From 63d674cfd45b354a4f7a1d655d871bfb01078d99 Mon Sep 17 00:00:00 2001 From: Rikko Date: Sat, 27 Aug 2022 18:03:36 +0530 Subject: [PATCH 0001/1464] Plugin must be installed before checking if it's enabled --- plugin_manager.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugin_manager.py b/plugin_manager.py index d057ba58..a64f2c42 100644 --- a/plugin_manager.py +++ b/plugin_manager.py @@ -143,7 +143,7 @@ async def update_plugins(self): all_plugins = await self.plugin_manager.categories["All"].get_plugins() plugins_to_update = [] for plugin in all_plugins: - if await plugin.get_local().is_enabled() and plugin.has_update(): + if plugin.is_installed and await plugin.get_local().is_enabled() and plugin.has_update(): plugins_to_update.append(plugin.update()) await asyncio.gather(*plugins_to_update) From 666fbadcb464bea299d8e2524a36e2cbac1319a2 Mon Sep 17 00:00:00 2001 From: Rikko Date: Sat, 27 Aug 2022 18:32:58 +0530 Subject: [PATCH 0002/1464] Update MD5 checksum for alliance elimination --- plugins/minigames.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/minigames.json b/plugins/minigames.json index e9aa2c09..22884035 100644 --- a/plugins/minigames.json +++ b/plugins/minigames.json @@ -19,7 +19,7 @@ "commit_sha": "cbdb3ead", "dependencies": [], "released_on": "08-08-2022", - "md5sum": "11dbb3c7e37e97bda028ea1251529ea0" + "md5sum": "f4f0bb91f5d10cf8f591ecf7d2848182" } } } From 71d8a4d8bc871dc71b3ad9be395d6e6f741f0cdb Mon Sep 17 00:00:00 2001 From: Rikko Date: Sat, 27 Aug 2022 18:39:43 +0530 Subject: [PATCH 0003/1464] Move MD5 checksum logic to sync fn --- plugin_manager.py | 64 ++++++++++++++++++++++++++++++++--------------- 1 file changed, 44 insertions(+), 20 deletions(-) diff --git a/plugin_manager.py b/plugin_manager.py index a64f2c42..38db806d 100644 --- a/plugin_manager.py +++ b/plugin_manager.py @@ -50,7 +50,7 @@ async def async_send_network_request(request): return response -def stream_network_response_to_file(request, file): +def stream_network_response_to_file(request, file, md5sum=None, retries=3): response = urllib.request.urlopen(request) chunk_size = 16 * 1024 content = b"" @@ -61,17 +61,11 @@ def stream_network_response_to_file(request, file): break fout.write(chunk) content += chunk - return content - - -async def async_stream_network_response_to_file(request, file, md5sum=None, retries=3): - loop = asyncio.get_event_loop() - content = await loop.run_in_executor(None, stream_network_response_to_file, request, file) if md5sum and hashlib.md5(content).hexdigest() != md5sum: if retries <= 0: # TODO: Raise a more fitting exception. - raise TypeError("md5sum match failed") - return await async_stream_network_response_to_file( + raise TypeError("MD5 checksum match failed. Please raise an issue on GitHub.") + return stream_network_response_to_file( request, file, md5sum=md5sum, @@ -80,6 +74,19 @@ async def async_stream_network_response_to_file(request, file, md5sum=None, retr return content +async def async_stream_network_response_to_file(request, file, md5sum=None, retries=3): + loop = asyncio.get_event_loop() + content = await loop.run_in_executor( + None, + stream_network_response_to_file, + request, + file, + md5sum, + retries, + ) + return content + + def play_sound(): ba.playsound(ba.getsound('swish')) @@ -453,12 +460,13 @@ async def set_content(self, content): self._content = content return self - async def set_content_from_network_response(self, request, md5sum=None): + async def set_content_from_network_response(self, request, md5sum=None, retries=3): if not self._content: self._content = await async_stream_network_response_to_file( request, self.install_path, md5sum=md5sum, + retries=retries, ) return self._content @@ -491,17 +499,29 @@ def __repr__(self): async def _download(self, retries=3): local_plugin = self.plugin.create_local() - await local_plugin.set_content_from_network_response(self.download_url, md5sum=self.md5sum) + await local_plugin.set_content_from_network_response( + self.download_url, + md5sum=self.md5sum, + retries=retries, + ) local_plugin.set_version(self.number) local_plugin.save() return local_plugin - async def install(self): - local_plugin = await self._download() - ba.screenmessage(f"{self.plugin.name} installed", color=(0, 1, 0)) - check = ba.app.config["Community Plugin Manager"]["Settings"] - if check["Auto Enable Plugins After Installation"]: - await local_plugin.enable() + async def install(self, suppress_screenmessage=False): + try: + local_plugin = await self._download() + except TypeError: + if not suppress_screenmessage: + ba.screenmessage(f"{self.plugin.name} failed MD5 checksum during installation", color=(1, 0, 0)) + return False + else: + if not suppress_screenmessage: + ba.screenmessage(f"{self.plugin.name} installed", color=(0, 1, 0)) + check = ba.app.config["Community Plugin Manager"]["Settings"] + if check["Auto Enable Plugins After Installation"]: + await local_plugin.enable() + return True class Plugin: @@ -588,9 +608,13 @@ def has_update(self): return self.get_local().version != self.latest_compatible_version.number async def update(self): - await self.latest_compatible_version.install() - ba.screenmessage(f"{self.name} updated to {self.latest_compatible_version.number}", - color=(0, 1, 0)) + if await self.latest_compatible_version.install(suppress_screenmessage=True): + ba.screenmessage(f"{self.name} updated to {self.latest_compatible_version.number}", + color=(0, 1, 0)) + else: + ba.screenmessage(f"{self.name} failed MD5 checksum while updating to " + f"{self.latest_compatible_version.number}", + color=(1, 0, 0)) class PluginWindow(popup.PopupWindow): From 0a57900035223693dbac13580c6f280fb82d6347 Mon Sep 17 00:00:00 2001 From: Rikko Date: Sat, 27 Aug 2022 19:30:21 +0530 Subject: [PATCH 0004/1464] Update exceptions and screenmessages --- plugin_manager.py | 48 +++++++++++++++++++++++++++++------------------ 1 file changed, 30 insertions(+), 18 deletions(-) diff --git a/plugin_manager.py b/plugin_manager.py index 38db806d..d706a92f 100644 --- a/plugin_manager.py +++ b/plugin_manager.py @@ -40,6 +40,18 @@ _CACHE = {} +class MD5CheckSumFailedError(Exception): + pass + + +class PluginNotInstalledError(Exception): + pass + + +class CategoryDoesNotExistError(Exception): + pass + + def send_network_request(request): return urllib.request.urlopen(request) @@ -63,8 +75,7 @@ def stream_network_response_to_file(request, file, md5sum=None, retries=3): content += chunk if md5sum and hashlib.md5(content).hexdigest() != md5sum: if retries <= 0: - # TODO: Raise a more fitting exception. - raise TypeError("MD5 checksum match failed. Please raise an issue on GitHub.") + raise MD5CheckSumFailedError("MD5 checksum match failed.") return stream_network_response_to_file( request, file, @@ -138,7 +149,7 @@ async def update_plugin_manager(self): update_details = await self.plugin_manager.get_update_details() if update_details: to_version, commit_sha = update_details - ba.screenmessage(f"Plugin Manager is being updated to version v{to_version}.") + ba.screenmessage(f"Plugin Manager is being updated to version v{to_version}") await self.plugin_manager.update(to_version, commit_sha) ba.screenmessage("Update successful. Restart game to reload changes.", color=(0, 1, 0)) @@ -333,8 +344,7 @@ def launch_settings(self): async def get_content(self): if self._content is None: if not self.is_installed: - # TODO: Raise a more fitting exception. - raise TypeError("Plugin is not available locally.") + raise PluginNotInstalledError("Plugin is not available locally.") loop = asyncio.get_event_loop() self._content = await loop.run_in_executor(None, self._get_content) return self._content @@ -511,7 +521,7 @@ async def _download(self, retries=3): async def install(self, suppress_screenmessage=False): try: local_plugin = await self._download() - except TypeError: + except MD5CheckSumFailedError: if not suppress_screenmessage: ba.screenmessage(f"{self.plugin.name} failed MD5 checksum during installation", color=(1, 0, 0)) return False @@ -589,7 +599,7 @@ def latest_compatible_version(self): def get_local(self): if not self.is_installed: - raise ValueError(f"{self.name} is not installed") + raise PluginNotInstalledError(f"{self.name} needs to be installed to get its local plugin.") if self._local_plugin is None: self._local_plugin = PluginLocal(self.name) return self._local_plugin @@ -934,7 +944,7 @@ async def update(self, to_version=None, commit_sha=None): response = await async_send_network_request(download_url) content = response.read() if hashlib.md5(content).hexdigest() != to_version_info["md5sum"]: - raise TypeError("md5sum check failed") + raise MD5CheckSumFailedError("MD5 checksum failed during plugin manager update.") with open(self.module_path, "wb") as fout: fout.write(content) return to_version_info @@ -1100,12 +1110,14 @@ async def add_source(self): def delete_selected_source(self): try: ba.app.config["Community Plugin Manager"]["Custom Sources"].remove(self.selected_source) + except ValueError: + # ba.screenmessage("No plugin source selected to delete.", color=(1, 0, 0)) + pass + else: ba.app.config.commit() ba.screenmessage("Plugin source deleted, refresh plugin list to see changes", color=(0, 1, 0)) self.draw_sources() - except Exception: - ba.screenmessage("No Plugin Selected to Delete", color=(1, 0, 0)) def _ok(self) -> None: play_sound() @@ -1354,9 +1366,7 @@ async def process_search_filter(self): continue try: await self.draw_plugin_names(self.selected_category, search_filter=filter_text) - except (KeyError, AttributeError): - # TODO: Raise a more fitting exception here. Selected category doesn't exist, such - # as the case where refresh button has been tapped on. + except CategoryDoesNotExistError: pass # XXX: This may be more efficient, but we need a way to get a plugin's textwidget # attributes like color, position and more. @@ -1431,7 +1441,10 @@ async def draw_plugin_names(self, category, search_filter=""): if not to_draw_plugin_names: return - category_plugins = await self.plugin_manager.categories[category].get_plugins() + try: + category_plugins = await self.plugin_manager.categories[category].get_plugins() + except (KeyError, AttributeError): + raise CategoryDoesNotExistError(f"{category} does not exist.") if search_filter: plugins = [] @@ -1688,11 +1701,10 @@ def save_settings_button(self): async def update(self, to_version=None, commit_sha=None): try: await self._plugin_manager.update(to_version, commit_sha) - except TypeError: - # TODO: Catch a more fitting exception here. - ba.screenmessage("md5sum check failed", color=(1, 0, 0)) + except MD5CheckSumFailedError: + ba.screenmessage("MD5 checksum failed during plugin manager update", color=(1, 0, 0)) else: - ba.screenmessage("Update successful.", color=(0, 1, 0)) + ba.screenmessage("Plugin manager update successful", color=(0, 1, 0)) ba.textwidget(edit=self._restart_to_reload_changes_text, text='Update Applied!\nRestart game to reload changes.') self._update_button.delete() From 5f94504e589c891ff24bd3f30bd064713d9945c1 Mon Sep 17 00:00:00 2001 From: Rikko Date: Sat, 27 Aug 2022 19:47:59 +0530 Subject: [PATCH 0005/1464] Fix text higlight when Plugin Manager is selected in Settings --- plugin_manager.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugin_manager.py b/plugin_manager.py index d706a92f..2af40c9a 100644 --- a/plugin_manager.py +++ b/plugin_manager.py @@ -1884,7 +1884,7 @@ def _b_title(x: float, y: float, button: ba.Widget, button_type="square", label="", on_activate_call=self._do_modmanager) - _b_title(x_offs6, v, avb, ba.Lstr(value="Plugin Manager")) + _b_title(x_offs6, v, mmb, ba.Lstr(value="Plugin Manager")) imgw = imgh = 120 ba.imagewidget(parent=self._root_widget, position=(x_offs6 + basew * 0.49 - imgw * 0.5 + 5, From cf2f5ee067297002f2cc66e5b0d092c1cbe723d1 Mon Sep 17 00:00:00 2001 From: Rikko Date: Sun, 28 Aug 2022 21:34:18 +0530 Subject: [PATCH 0006/1464] Bump to v0.1.2 --- plugin_manager.py | 5 ++--- plugins/minigames.json | 1 - plugins/utilities.json | 3 --- 3 files changed, 2 insertions(+), 7 deletions(-) diff --git a/plugin_manager.py b/plugin_manager.py index 2af40c9a..1ed0aa6f 100644 --- a/plugin_manager.py +++ b/plugin_manager.py @@ -20,7 +20,7 @@ _uiscale = ba.app.ui.uiscale -PLUGIN_MANAGER_VERSION = "0.1.1" +PLUGIN_MANAGER_VERSION = "0.1.2" REPOSITORY_URL = "http://github.com/bombsquad-community/plugin-manager" CURRENT_TAG = "main" # XXX: Using https with `ba.open_url` seems to trigger a pop-up dialog box on @@ -491,7 +491,6 @@ def __init__(self, plugin, version, tag=None): self.plugin = plugin self.api_version = info["api_version"] self.commit_sha = info["commit_sha"] - self.dependencies = info["dependencies"] self.md5sum = info["md5sum"] if tag is None: @@ -1891,7 +1890,7 @@ def _b_title(x: float, y: float, button: ba.Widget, v + 35), size=(imgw, imgh), color=(0.8, 0.95, 1), - texture=ba.gettexture("heart"), + texture=ba.gettexture("storeIcon"), draw_controller=mmb) self._restore_state() diff --git a/plugins/minigames.json b/plugins/minigames.json index 22884035..4d69b676 100644 --- a/plugins/minigames.json +++ b/plugins/minigames.json @@ -17,7 +17,6 @@ "1.1.0": { "api_version": 7, "commit_sha": "cbdb3ead", - "dependencies": [], "released_on": "08-08-2022", "md5sum": "f4f0bb91f5d10cf8f591ecf7d2848182" } diff --git a/plugins/utilities.json b/plugins/utilities.json index b98c05db..0015730a 100644 --- a/plugins/utilities.json +++ b/plugins/utilities.json @@ -22,14 +22,12 @@ "1.2.0": { "api_version": 7, "commit_sha": "a98dacd", - "dependencies": [], "released_on": "12-08-2022", "md5sum": "41084bfec41119ca9df8e6d899cd3cc0" }, "1.1.0": { "api_version": 7, "commit_sha": "13a9d128", - "dependencies": [], "released_on": "03-06-2022", "md5sum": "4b6bbb99037ebda4664da7c510b3717c" } @@ -49,7 +47,6 @@ "1.0.0": { "api_version": 7, "commit_sha": "2aa6df31", - "dependencies": [], "released_on": "06-08-2022", "md5sum": "233dfaa7f0e9394d21454f4ffa7d0205" } From 5057f65ca19c211d8bd11324f465d6d35c3267e1 Mon Sep 17 00:00:00 2001 From: Rikko Date: Sun, 28 Aug 2022 21:35:14 +0530 Subject: [PATCH 0007/1464] Bump to v0.1.2 --- index.json | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/index.json b/index.json index 43e3affe..2561e90e 100644 --- a/index.json +++ b/index.json @@ -1,17 +1,15 @@ { "plugin_manager_url": "http://github.com/bombsquad-community/plugin-manager/{content_type}/{tag}/plugin_manager.py", "versions": { - "0.1.1": { + "0.1.2": { "api_version": 7, - "commit_sha": "123abcd", - "dependencies": [], - "released_on": "someday-2022", - "md5sum": "implementme" + "commit_sha": "cf2f5ee0", + "released_on": "28-08-2022", + "md5sum": "18ab952ae92866850e2a7d87722ccf23" }, "0.1.0": { "api_version": 7, "commit_sha": "a02fe8e", - "dependencies": [], "released_on": "13-08-2022", "md5sum": "9038aeffc5836586ec8d61c51ec5ed5d" } From c400f49ce2a439726bb46570ef9dda9106570491 Mon Sep 17 00:00:00 2001 From: Rikko Date: Sun, 28 Aug 2022 21:50:05 +0530 Subject: [PATCH 0008/1464] Update screen message, bump to v0.1.3 --- plugin_manager.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/plugin_manager.py b/plugin_manager.py index 1ed0aa6f..0eeb4fb8 100644 --- a/plugin_manager.py +++ b/plugin_manager.py @@ -20,7 +20,7 @@ _uiscale = ba.app.ui.uiscale -PLUGIN_MANAGER_VERSION = "0.1.2" +PLUGIN_MANAGER_VERSION = "0.1.3" REPOSITORY_URL = "http://github.com/bombsquad-community/plugin-manager" CURRENT_TAG = "main" # XXX: Using https with `ba.open_url` seems to trigger a pop-up dialog box on @@ -149,7 +149,7 @@ async def update_plugin_manager(self): update_details = await self.plugin_manager.get_update_details() if update_details: to_version, commit_sha = update_details - ba.screenmessage(f"Plugin Manager is being updated to version v{to_version}") + ba.screenmessage(f"Plugin Manager is being updated to v{to_version}") await self.plugin_manager.update(to_version, commit_sha) ba.screenmessage("Update successful. Restart game to reload changes.", color=(0, 1, 0)) From 2e21e7d0ea4eb1c3bbda5943f65749f40abd98b0 Mon Sep 17 00:00:00 2001 From: Rikko Date: Sun, 28 Aug 2022 21:51:06 +0530 Subject: [PATCH 0009/1464] Bump to v0.1.3 --- index.json | 12 +++--------- 1 file changed, 3 insertions(+), 9 deletions(-) diff --git a/index.json b/index.json index 2561e90e..c56dd8f8 100644 --- a/index.json +++ b/index.json @@ -1,17 +1,11 @@ { "plugin_manager_url": "http://github.com/bombsquad-community/plugin-manager/{content_type}/{tag}/plugin_manager.py", "versions": { - "0.1.2": { + "0.1.3": { "api_version": 7, - "commit_sha": "cf2f5ee0", + "commit_sha": "c400f49c", "released_on": "28-08-2022", - "md5sum": "18ab952ae92866850e2a7d87722ccf23" - }, - "0.1.0": { - "api_version": 7, - "commit_sha": "a02fe8e", - "released_on": "13-08-2022", - "md5sum": "9038aeffc5836586ec8d61c51ec5ed5d" + "md5sum": "1ea165a3a248969b74c5ba21fa0bfcff" } }, "categories": [ From da5032a7e08284794d02faa78909efe409ffa2d3 Mon Sep 17 00:00:00 2001 From: Rikko Date: Sun, 28 Aug 2022 23:04:53 +0530 Subject: [PATCH 0010/1464] Add colorscheme v1.0.0 --- plugins/utilities/colorscheme.py | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/plugins/utilities/colorscheme.py b/plugins/utilities/colorscheme.py index b339d045..7c38aee9 100644 --- a/plugins/utilities/colorscheme.py +++ b/plugins/utilities/colorscheme.py @@ -6,7 +6,7 @@ # Settings -> Advanced -> Enter Code # to bring up the colorscheme UI. -# ba_meta require api 7 +# ba_meta require api 6 import _ba import ba @@ -139,7 +139,7 @@ def __init__(self, default_colors=((0.41, 0.39, 0.5), (0.5, 0.7, 0.25))): # A hack to let players select any RGB color value through the UI, # otherwise this is limited only to pro accounts. - ba.app.accounts_v1.have_pro = lambda: True + ba.app.accounts.have_pro = lambda: True self.draw_ui() @@ -291,7 +291,7 @@ def _cancel(self): colorscheme = ColorScheme(self._last_color, self._last_highlight) colorscheme.apply() # Good idea to revert this back now so we do not break anything else. - ba.app.accounts_v1.have_pro = original_have_pro + ba.app.accounts.have_pro = original_have_pro ba.containerwidget(edit=self._root_widget, transition="out_right") def reset(self, transition_out=True): @@ -299,7 +299,7 @@ def reset(self, transition_out=True): ba.playsound(ba.getsound("gunCocking")) ba.app.config["ColorScheme"] = (None, None) # Good idea to revert this back now so we do not break anything else. - ba.app.accounts_v1.have_pro = original_have_pro + ba.app.accounts.have_pro = original_have_pro ba.app.config.commit() ba.containerwidget(edit=self._root_widget, transition="out_right") @@ -312,7 +312,7 @@ def save(self, transition_out=True): ) colorscheme.apply() # Good idea to revert this back now so we do not break anything else. - ba.app.accounts_v1.have_pro = original_have_pro + ba.app.accounts.have_pro = original_have_pro ba.app.config["ColorScheme"] = ( self._color or self._default_colors[0], self._highlight or self._default_colors[1], @@ -381,7 +381,7 @@ def launch_colorscheme_selection_window(): # has pro-unlocked or not if our plugin runs before the dedicated # pro-unlocker plugin has been applied. global original_have_pro - original_have_pro = ba.app.accounts_v1.have_pro + original_have_pro = ba.app.accounts.have_pro ColorSchemeWindow() From 963a173797ee97e709831eb094b17d10146034ff Mon Sep 17 00:00:00 2001 From: Rikko Date: Sun, 28 Aug 2022 23:07:05 +0530 Subject: [PATCH 0011/1464] Revert "Add colorscheme v1.0.0" This reverts commit da5032a7e08284794d02faa78909efe409ffa2d3. --- plugins/utilities/colorscheme.py | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/plugins/utilities/colorscheme.py b/plugins/utilities/colorscheme.py index 7c38aee9..b339d045 100644 --- a/plugins/utilities/colorscheme.py +++ b/plugins/utilities/colorscheme.py @@ -6,7 +6,7 @@ # Settings -> Advanced -> Enter Code # to bring up the colorscheme UI. -# ba_meta require api 6 +# ba_meta require api 7 import _ba import ba @@ -139,7 +139,7 @@ def __init__(self, default_colors=((0.41, 0.39, 0.5), (0.5, 0.7, 0.25))): # A hack to let players select any RGB color value through the UI, # otherwise this is limited only to pro accounts. - ba.app.accounts.have_pro = lambda: True + ba.app.accounts_v1.have_pro = lambda: True self.draw_ui() @@ -291,7 +291,7 @@ def _cancel(self): colorscheme = ColorScheme(self._last_color, self._last_highlight) colorscheme.apply() # Good idea to revert this back now so we do not break anything else. - ba.app.accounts.have_pro = original_have_pro + ba.app.accounts_v1.have_pro = original_have_pro ba.containerwidget(edit=self._root_widget, transition="out_right") def reset(self, transition_out=True): @@ -299,7 +299,7 @@ def reset(self, transition_out=True): ba.playsound(ba.getsound("gunCocking")) ba.app.config["ColorScheme"] = (None, None) # Good idea to revert this back now so we do not break anything else. - ba.app.accounts.have_pro = original_have_pro + ba.app.accounts_v1.have_pro = original_have_pro ba.app.config.commit() ba.containerwidget(edit=self._root_widget, transition="out_right") @@ -312,7 +312,7 @@ def save(self, transition_out=True): ) colorscheme.apply() # Good idea to revert this back now so we do not break anything else. - ba.app.accounts.have_pro = original_have_pro + ba.app.accounts_v1.have_pro = original_have_pro ba.app.config["ColorScheme"] = ( self._color or self._default_colors[0], self._highlight or self._default_colors[1], @@ -381,7 +381,7 @@ def launch_colorscheme_selection_window(): # has pro-unlocked or not if our plugin runs before the dedicated # pro-unlocker plugin has been applied. global original_have_pro - original_have_pro = ba.app.accounts.have_pro + original_have_pro = ba.app.accounts_v1.have_pro ColorSchemeWindow() From 6c5c26105dcae57b0a70773aa6d1b546d437ef15 Mon Sep 17 00:00:00 2001 From: Rikko Date: Sun, 28 Aug 2022 23:08:07 +0530 Subject: [PATCH 0012/1464] Add colorscheme v1.0.0 --- plugins/utilities.json | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/plugins/utilities.json b/plugins/utilities.json index 0015730a..4be2b649 100644 --- a/plugins/utilities.json +++ b/plugins/utilities.json @@ -21,7 +21,7 @@ "versions": { "1.2.0": { "api_version": 7, - "commit_sha": "a98dacd", + "commit_sha": "963a17379", "released_on": "12-08-2022", "md5sum": "41084bfec41119ca9df8e6d899cd3cc0" }, @@ -30,6 +30,12 @@ "commit_sha": "13a9d128", "released_on": "03-06-2022", "md5sum": "4b6bbb99037ebda4664da7c510b3717c" + }, + "1.0.0": { + "api_version": 6, + "commit_sha": "da5032a7", + "released_on": "28-05-2021", + "md5sum": "527acfec13a2d0a6115a52df7abca920" } } }, From 06a21d2c784a20e89570d7929791cf97477025b2 Mon Sep 17 00:00:00 2001 From: Rikko Date: Sun, 28 Aug 2022 23:09:09 +0530 Subject: [PATCH 0013/1464] Hide plugins with no compatible API --- plugin_manager.py | 23 +++++++++++++++++++++-- 1 file changed, 21 insertions(+), 2 deletions(-) diff --git a/plugin_manager.py b/plugin_manager.py index 0eeb4fb8..ef12d75a 100644 --- a/plugin_manager.py +++ b/plugin_manager.py @@ -52,6 +52,10 @@ class CategoryDoesNotExistError(Exception): pass +class NoCompatibleVersionError(Exception): + pass + + def send_network_request(request): return urllib.request.urlopen(request) @@ -594,6 +598,10 @@ def latest_compatible_version(self): CURRENT_TAG if self.latest_version.number == number else None ) break + if self._latest_compatible_version is None: + raise NoCompatibleVersionError( + f"{self.name} has no version compatible with API {ba.app.api_version}." + ) return self._latest_compatible_version def get_local(self): @@ -614,7 +622,12 @@ async def uninstall(self): ba.screenmessage(f"{self.name} uninstalled", color=(0, 1, 0)) def has_update(self): - return self.get_local().version != self.latest_compatible_version.number + try: + latest_compatible_version = self.latest_compatible_version + except NoCompatibleVersionError: + return False + else: + return self.get_local().version != latest_compatible_version.number async def update(self): if await self.latest_compatible_version.install(suppress_screenmessage=True): @@ -1467,12 +1480,18 @@ async def draw_plugin_names(self, category, search_filter=""): await asyncio.gather(*plugin_names_to_draw) async def draw_plugin_name(self, plugin): + try: + latest_compatible_version = plugin.latest_compatible_version + except NoCompatibleVersionError: + # We currently don't show plugins that have no compatible versions. + return + if plugin.is_installed: local_plugin = plugin.get_local() if await local_plugin.is_enabled(): if not local_plugin.is_installed_via_plugin_manager: color = (0.8, 0.2, 0.2) - elif local_plugin.version == plugin.latest_compatible_version.number: + elif local_plugin.version == latest_compatible_version.number: color = (0, 1, 0) else: color = (1, 0.6, 0) From f725ec06e38f6759a2105ed283682869d02e8dd0 Mon Sep 17 00:00:00 2001 From: Rikko Date: Sun, 28 Aug 2022 23:20:33 +0530 Subject: [PATCH 0014/1464] Show API version in settings --- plugin_manager.py | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/plugin_manager.py b/plugin_manager.py index ef12d75a..d8d028ac 100644 --- a/plugin_manager.py +++ b/plugin_manager.py @@ -1640,7 +1640,17 @@ async def draw_ui(self): color=color, maxwidth=width * 0.95) - pos -= 70 + pos -= 45 + ba.textwidget(parent=self._root_widget, + position=(width * 0.22, pos-5), + size=(0, 0), + h_align='center', + v_align='center', + text=f'API Version: {ba.app.api_version}', + scale=text_scale * 0.7, + color=(0.4, 0.8, 1), + maxwidth=width * 0.95) + pos -= 25 ba.buttonwidget(parent=self._root_widget, position=((width * 0.49) - button_size[0] / 2, pos), size=button_size, From 99efaeb293efe733f2262fb62ce4254ca8adff35 Mon Sep 17 00:00:00 2001 From: Rikko Date: Sun, 28 Aug 2022 23:31:46 +0530 Subject: [PATCH 0015/1464] Set the view_url to the current latest compatible version --- plugin_manager.py | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/plugin_manager.py b/plugin_manager.py index d8d028ac..084a612f 100644 --- a/plugin_manager.py +++ b/plugin_manager.py @@ -552,7 +552,6 @@ def __init__(self, plugin, url, is_3rd_party=False): tag = CURRENT_TAG self.url = url self.download_url = url.format(content_type="raw", tag=tag) - self.view_url = url.format(content_type="blob", tag=tag) self._local_plugin = None self._versions = None @@ -562,6 +561,14 @@ def __init__(self, plugin, url, is_3rd_party=False): def __repr__(self): return f"" + @property + def view_url(self): + if self.latest_compatible_version == self.latest_version: + tag = CURRENT_TAG + else: + tag = self.latest_compatible_version.commit_sha + return self.url.format(content_type="blob", tag=tag) + @property def is_installed(self): return os.path.isfile(self.install_path) From 529756b5ce8e5f07bd38306c7d2cb7e0979bce7a Mon Sep 17 00:00:00 2001 From: Rikko Date: Mon, 29 Aug 2022 01:35:20 +0530 Subject: [PATCH 0016/1464] Update MD5 hash --- index.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/index.json b/index.json index c56dd8f8..7998e10a 100644 --- a/index.json +++ b/index.json @@ -5,7 +5,7 @@ "api_version": 7, "commit_sha": "c400f49c", "released_on": "28-08-2022", - "md5sum": "1ea165a3a248969b74c5ba21fa0bfcff" + "md5sum": "ea87ab649dfd7eeada22cebd61f3bf2a" } }, "categories": [ From 24ec71990b7b68e50d3e4171d4e4b5c130821b8d Mon Sep 17 00:00:00 2001 From: Rikko Date: Mon, 29 Aug 2022 18:41:17 +0530 Subject: [PATCH 0017/1464] Fine tune UI --- plugin_manager.py | 171 ++++++++++++++++++++++++++++------------------ 1 file changed, 103 insertions(+), 68 deletions(-) diff --git a/plugin_manager.py b/plugin_manager.py index 084a612f..782db124 100644 --- a/plugin_manager.py +++ b/plugin_manager.py @@ -20,7 +20,7 @@ _uiscale = ba.app.ui.uiscale -PLUGIN_MANAGER_VERSION = "0.1.3" +PLUGIN_MANAGER_VERSION = "0.1.4" REPOSITORY_URL = "http://github.com/bombsquad-community/plugin-manager" CURRENT_TAG = "main" # XXX: Using https with `ba.open_url` seems to trigger a pop-up dialog box on @@ -154,9 +154,14 @@ async def update_plugin_manager(self): if update_details: to_version, commit_sha = update_details ba.screenmessage(f"Plugin Manager is being updated to v{to_version}") - await self.plugin_manager.update(to_version, commit_sha) - ba.screenmessage("Update successful. Restart game to reload changes.", - color=(0, 1, 0)) + try: + await self.plugin_manager.update(to_version, commit_sha) + except MD5CheckSumFailedError: + ba.playsound(ba.getsound('error')) + else: + ba.screenmessage("Update successful. Restart game to reload changes.", + color=(0, 1, 0)) + ba.playsound(ba.getsound('shieldUp')) async def update_plugins(self): if not ba.app.config["Community Plugin Manager"]["Settings"]["Auto Update Plugins"]: @@ -200,7 +205,10 @@ async def fetch_metadata(self): return self async def is_valid(self): - await self.fetch_metadata() + try: + await self.fetch_metadata() + except urllib.error.HTTPError: + return False try: await asyncio.gather( self.get_name(), @@ -384,7 +392,7 @@ def load_minigames(self): scanned_results = set(ba.app.meta.scanresults.exports["ba.GameActivity"]) for game in scanner.results.exports["ba.GameActivity"]: if game not in scanned_results: - ba.screenmessage(f"{game} minigame loaded", color=(0, 1, 0)) + ba.screenmessage(f"{game} minigame loaded") ba.app.meta.scanresults.exports["ba.GameActivity"].append(game) def unload_minigames(self): @@ -397,7 +405,7 @@ def unload_minigames(self): new_scanned_results_games = [] for game in ba.app.meta.scanresults.exports["ba.GameActivity"]: if game in scanner.results.exports["ba.GameActivity"]: - ba.screenmessage(f"{game} minigame unloaded", color=(0, 1, 0)) + ba.screenmessage(f"{game} minigame unloaded") else: new_scanned_results_games.append(game) ba.app.meta.scanresults.exports["ba.GameActivity"] = new_scanned_results_games @@ -431,7 +439,7 @@ async def enable(self): ba.app.config["Plugins"][entry_point]["enabled"] = True if entry_point not in ba.app.plugins.active_plugins: self.load_plugin(entry_point) - ba.screenmessage(f"{entry_point} loaded", color=(0, 1, 0)) + ba.screenmessage(f"{entry_point} loaded") if await self.has_minigames(): self.load_minigames() # await self._set_status(to_enable=True) @@ -626,7 +634,7 @@ def create_local(self): async def uninstall(self): await self.get_local().uninstall() - ba.screenmessage(f"{self.name} uninstalled", color=(0, 1, 0)) + ba.screenmessage(f"{self.name} uninstalled", color=(0.9, 1, 0)) def has_update(self): try: @@ -640,10 +648,12 @@ async def update(self): if await self.latest_compatible_version.install(suppress_screenmessage=True): ba.screenmessage(f"{self.name} updated to {self.latest_compatible_version.number}", color=(0, 1, 0)) + ba.playsound(ba.getsound('shieldUp')) else: ba.screenmessage(f"{self.name} failed MD5 checksum while updating to " f"{self.latest_compatible_version.number}", color=(1, 0, 0)) + ba.playsound(ba.getsound('error')) class PluginWindow(popup.PopupWindow): @@ -706,7 +716,7 @@ async def draw_ui(self): text=self.plugin.info["description"], scale=text_scale * 0.6, color=color, maxwidth=width * 0.95) - b1_color = (0.6, 0.53, 0.63) + b1_color = None b2_color = (0.8, 0.15, 0.35) b3_color = (0.2, 0.8, 0.3) pos = height * 0.1 @@ -721,6 +731,7 @@ async def draw_ui(self): else: if await self.local_plugin.is_enabled(): button1_label = "Disable" + b1_color = (0.6, 0.53, 0.63) button1_action = self.disable if self.local_plugin.has_settings(): to_draw_button4 = True @@ -780,10 +791,12 @@ async def draw_ui(self): 110 if _uiscale is ba.UIScale.MEDIUM else 120) open_button = ba.buttonwidget(parent=self._root_widget, autoselect=True, - position=(open_pos_x-7.5, open_pos_y-15), - size=(55, 55), + 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.view_url)) ba.imagewidget(parent=self._root_widget, position=(open_pos_x, open_pos_y), @@ -792,13 +805,16 @@ async def draw_ui(self): texture=ba.gettexture("file"), draw_controller=open_button) ba.textwidget(parent=self._root_widget, - position=(open_pos_x, open_pos_y-6), + position=(open_pos_x-3, open_pos_y+12), text="Source", size=(10, 10), - scale=0.5) + draw_controller=open_button, + color=(1, 1, 1, 1), + rotate=25, + scale=0.45) if to_draw_button4: - settings_pos_x = (0 if _uiscale is ba.UIScale.SMALL else + settings_pos_x = (60 if _uiscale is ba.UIScale.SMALL else 60 if _uiscale is ba.UIScale.MEDIUM else 60) settings_pos_y = (100 if _uiscale is ba.UIScale.SMALL else 110 if _uiscale is ba.UIScale.MEDIUM else 120) @@ -853,14 +869,17 @@ async def enable(self) -> None: @button async def install(self): await self.plugin.latest_compatible_version.install() + ba.playsound(ba.getsound('cashRegister2')) @button async def uninstall(self): await self.plugin.uninstall() + ba.playsound(ba.getsound('shieldDown')) @button async def update(self): await self.plugin.update() + ba.playsound(ba.getsound('shieldUp')) class PluginManager: @@ -914,7 +933,8 @@ async def setup_plugin_categories(self, plugin_index): def cleanup(self): for category in self.categories.values(): - category.cleanup() + if category is not None: + category.cleanup() self.categories.clear() self._index.clear() self.unset_index_global_cache() @@ -975,6 +995,7 @@ async def soft_refresh(self): class PluginSourcesWindow(popup.PopupWindow): def __init__(self, origin_widget): play_sound() + self.selected_source = None self.scale_origin = origin_widget.get_screen_space_center() @@ -1042,9 +1063,13 @@ def __init__(self, origin_widget): color=(5, 2, 2), texture=ba.gettexture("crossOut"), draw_controller=delete_source_button) + + warning_pos_x = (43 if _uiscale is ba.UIScale.SMALL else + 35 if _uiscale is ba.UIScale.MEDIUM else + 48) ba.textwidget( parent=self._root_widget, - position=(48, 74), + position=(warning_pos_x, 74), size=(50, 22), text=("Warning: 3rd party plugin sources are not moderated\n" " by the community and may be dangerous!"), @@ -1056,7 +1081,7 @@ def __init__(self, origin_widget): ) self._add_source_widget = ba.textwidget(parent=self._root_widget, - text="rikkolovescats/sahilp-plugins", + # text="rikkolovescats/sahilp-plugins", size=(335, 50), position=(21, 22), h_align='left', @@ -1116,27 +1141,28 @@ async def add_source(self): category = Category(meta_url, is_3rd_party=True) if not await category.is_valid(): ba.screenmessage("Enter a valid plugin source", color=(1, 0, 0)) + ba.playsound(ba.getsound('error')) return if source in ba.app.config["Community Plugin Manager"]["Custom Sources"]: ba.screenmessage("Plugin source already exists") + ba.playsound(ba.getsound('error')) return ba.app.config["Community Plugin Manager"]["Custom Sources"].append(source) ba.app.config.commit() - ba.screenmessage("Plugin source added, refresh plugin list to see changes", + ba.screenmessage("Plugin source added; Refresh plugin list to see changes", color=(0, 1, 0)) + ba.playsound(ba.getsound('cashRegister2')) self.draw_sources() def delete_selected_source(self): - try: - ba.app.config["Community Plugin Manager"]["Custom Sources"].remove(self.selected_source) - except ValueError: - # ba.screenmessage("No plugin source selected to delete.", color=(1, 0, 0)) - pass - else: - ba.app.config.commit() - ba.screenmessage("Plugin source deleted, refresh plugin list to see changes", - color=(0, 1, 0)) - self.draw_sources() + if self.selected_source is None: + return + ba.app.config["Community Plugin Manager"]["Custom Sources"].remove(self.selected_source) + ba.app.config.commit() + ba.screenmessage("Plugin source deleted; Refresh plugin list to see changes", + color=(0.9, 1, 0)) + ba.playsound(ba.getsound('shieldDown')) + self.draw_sources() def _ok(self) -> None: play_sound() @@ -1188,9 +1214,11 @@ def __init__(self, transition: str = "in_right", origin_widget: ba.Widget = None loop = asyncio.get_event_loop() loop.create_task(self.draw_index()) - self._width = (490 if _uiscale is ba.UIScale.MEDIUM else 570) + self._width = (700 if _uiscale is ba.UIScale.SMALL + else 550 if _uiscale is ba.UIScale.MEDIUM + else 570) self._height = (500 if _uiscale is ba.UIScale.SMALL - else 380 if _uiscale is ba.UIScale.MEDIUM + else 422 if _uiscale is ba.UIScale.MEDIUM else 500) top_extra = 20 if _uiscale is ba.UIScale.SMALL else 0 @@ -1210,9 +1238,9 @@ def __init__(self, transition: str = "in_right", origin_widget: ba.Widget = None stack_offset=(0, -25) if _uiscale is ba.UIScale.SMALL else (0, 0) )) - back_pos_x = 5 + (10 if _uiscale is ba.UIScale.SMALL else + back_pos_x = 5 + (37 if _uiscale is ba.UIScale.SMALL else 27 if _uiscale is ba.UIScale.MEDIUM else 68) - back_pos_y = self._height - (115 if _uiscale is ba.UIScale.SMALL else + back_pos_y = self._height - (95 if _uiscale is ba.UIScale.SMALL else 65 if _uiscale is ba.UIScale.MEDIUM else 50) self._back_button = back_button = ba.buttonwidget( parent=self._root_widget, @@ -1226,7 +1254,7 @@ def __init__(self, transition: str = "in_right", origin_widget: ba.Widget = None ba.containerwidget(edit=self._root_widget, cancel_button=back_button) - title_pos = self._height - (100 if _uiscale is ba.UIScale.SMALL else + title_pos = self._height - (83 if _uiscale is ba.UIScale.SMALL else 50 if _uiscale is ba.UIScale.MEDIUM else 50) ba.textwidget( parent=self._root_widget, @@ -1240,8 +1268,8 @@ def __init__(self, transition: str = "in_right", origin_widget: ba.Widget = None maxwidth=270, ) - loading_pos_y = self._height - (235 if _uiscale is ba.UIScale.SMALL else - 220 if _uiscale is ba.UIScale.MEDIUM else 250) + loading_pos_y = self._height - (275 if _uiscale is ba.UIScale.SMALL else + 235 if _uiscale is ba.UIScale.MEDIUM else 270) self._plugin_manager_status_text = ba.textwidget( parent=self._root_widget, @@ -1287,14 +1315,14 @@ async def draw_index(self): await self.select_category("All") def draw_plugins_scroll_bar(self): - scroll_size_x = (400 if _uiscale is ba.UIScale.SMALL else - 380 if _uiscale is ba.UIScale.MEDIUM else 420) - scroll_size_y = (225 if _uiscale is ba.UIScale.SMALL else - 235 if _uiscale is ba.UIScale.MEDIUM else 335) + scroll_size_x = (515 if _uiscale is ba.UIScale.SMALL else + 430 if _uiscale is ba.UIScale.MEDIUM else 420) + scroll_size_y = (245 if _uiscale is ba.UIScale.SMALL else + 265 if _uiscale is ba.UIScale.MEDIUM else 335) scroll_pos_x = (70 if _uiscale is ba.UIScale.SMALL else - 40 if _uiscale is ba.UIScale.MEDIUM else 70) - scroll_pos_y = (125 if _uiscale is ba.UIScale.SMALL else - 30 if _uiscale is ba.UIScale.MEDIUM else 40) + 50 if _uiscale is ba.UIScale.MEDIUM else 70) + scroll_pos_y = (100 if _uiscale is ba.UIScale.SMALL else + 35 if _uiscale is ba.UIScale.MEDIUM else 40) self._scrollwidget = ba.scrollwidget(parent=self._root_widget, size=(scroll_size_x, scroll_size_y), position=(scroll_pos_x, scroll_pos_y)) @@ -1303,13 +1331,14 @@ def draw_plugins_scroll_bar(self): margin=0) def draw_category_selection_button(self, post_label): - category_pos_x = (330 if _uiscale is ba.UIScale.SMALL else - 285 if _uiscale is ba.UIScale.MEDIUM else 350) - category_pos_y = self._height - (145 if _uiscale is ba.UIScale.SMALL else + category_pos_x = (440 if _uiscale is ba.UIScale.SMALL else + 340 if _uiscale is ba.UIScale.MEDIUM else 350) + category_pos_y = self._height - (141 if _uiscale is ba.UIScale.SMALL else 110 if _uiscale is ba.UIScale.MEDIUM else 110) b_size = (140, 30) - b_textcolor = (0.75, 0.7, 0.8) - b_color = (0.6, 0.53, 0.63) + # b_textcolor = (0.75, 0.7, 0.8) + b_textcolor = (0.8, 0.8, 0.85) + # b_color = (0.6, 0.53, 0.63) label = f"Category: {post_label}" @@ -1322,7 +1351,7 @@ def draw_category_selection_button(self, post_label): self.show_categories_window), label=label, button_type="square", - color=b_color, + # color=b_color, textcolor=b_textcolor, # autoselect=True, text_scale=0.6) @@ -1332,12 +1361,12 @@ def draw_category_selection_button(self, post_label): def draw_search_bar(self): search_bar_pos_x = (85 if _uiscale is ba.UIScale.SMALL else - 65 if _uiscale is ba.UIScale.MEDIUM else 90) + 68 if _uiscale is ba.UIScale.MEDIUM else 90) search_bar_pos_y = self._height - ( 145 if _uiscale is ba.UIScale.SMALL else 110 if _uiscale is ba.UIScale.MEDIUM else 116) - search_bar_size_x = (250 if _uiscale is ba.UIScale.SMALL else + search_bar_size_x = (320 if _uiscale is ba.UIScale.SMALL else 230 if _uiscale is ba.UIScale.MEDIUM else 260) search_bar_size_y = ( 35 if _uiscale is ba.UIScale.SMALL else @@ -1345,7 +1374,7 @@ def draw_search_bar(self): filter_txt_pos_x = (60 if _uiscale is ba.UIScale.SMALL else 40 if _uiscale is ba.UIScale.MEDIUM else 60) - filter_txt_pos_y = search_bar_pos_y + (5 if _uiscale is ba.UIScale.SMALL else + filter_txt_pos_y = search_bar_pos_y + (3 if _uiscale is ba.UIScale.SMALL else 4 if _uiscale is ba.UIScale.MEDIUM else 8) ba.textwidget(parent=self._root_widget, @@ -1358,6 +1387,9 @@ def draw_search_bar(self): scale=0.5) filter_txt = ba.Lstr(resource='filterText') + search_bar_maxwidth = search_bar_size_x - (95 if _uiscale is ba.UIScale.SMALL else + 77 if _uiscale is ba.UIScale.MEDIUM else + 85) self._filter_widget = ba.textwidget(parent=self._root_widget, text="", size=(search_bar_size_x, search_bar_size_y), @@ -1367,6 +1399,7 @@ def draw_search_bar(self): editable=True, scale=0.8, autoselect=True, + maxwidth=search_bar_maxwidth, description=filter_txt) self._last_filter_text = None self._last_filter_plugins = [] @@ -1404,8 +1437,8 @@ async def process_search_filter(self): # ba.textwidget(edit=widget, position=None) def draw_settings_icon(self): - settings_pos_x = (500 if _uiscale is ba.UIScale.SMALL else - 440 if _uiscale is ba.UIScale.MEDIUM else 510) + settings_pos_x = (610 if _uiscale is ba.UIScale.SMALL else + 500 if _uiscale is ba.UIScale.MEDIUM else 510) settings_pos_y = (130 if _uiscale is ba.UIScale.SMALL else 60 if _uiscale is ba.UIScale.MEDIUM else 70) controller_button = ba.buttonwidget(parent=self._root_widget, @@ -1425,21 +1458,21 @@ def draw_settings_icon(self): draw_controller=controller_button) def draw_refresh_icon(self): - settings_pos_x = (500 if _uiscale is ba.UIScale.SMALL else - 440 if _uiscale is ba.UIScale.MEDIUM else 510) - settings_pos_y = (180 if _uiscale is ba.UIScale.SMALL else - 105 if _uiscale is ba.UIScale.MEDIUM else 120) + refresh_pos_x = (610 if _uiscale is ba.UIScale.SMALL else + 500 if _uiscale is ba.UIScale.MEDIUM else 510) + refresh_pos_y = (180 if _uiscale is ba.UIScale.SMALL else + 108 if _uiscale is ba.UIScale.MEDIUM else 120) loop = asyncio.get_event_loop() controller_button = ba.buttonwidget(parent=self._root_widget, # autoselect=True, - position=(settings_pos_x, settings_pos_y), + position=(refresh_pos_x, refresh_pos_y), size=(30, 30), button_type="square", label="", on_activate_call=lambda: loop.create_task(self.refresh())) ba.imagewidget(parent=self._root_widget, - position=(settings_pos_x, settings_pos_y), + position=(refresh_pos_x, refresh_pos_y), size=(30, 30), color=(0.8, 0.95, 1), texture=ba.gettexture("replayIcon"), @@ -1499,7 +1532,7 @@ async def draw_plugin_name(self, plugin): if not local_plugin.is_installed_via_plugin_manager: color = (0.8, 0.2, 0.2) elif local_plugin.version == latest_compatible_version.number: - color = (0, 1, 0) + color = (0, 0.95, 0.2) else: color = (1, 0.6, 0) else: @@ -1555,7 +1588,6 @@ def cleanup(self): self._last_filter_plugins = [] async def refresh(self): - play_sound() self.cleanup() ba.textwidget(edit=self._plugin_manager_status_text, text="Refreshing...") @@ -1581,8 +1613,8 @@ def __init__(self, plugin_manager, origin_widget): loop.create_task(self.draw_ui()) async def draw_ui(self): - 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 + b_text_color = (0.8, 0.8, 0.85) + s = 1.25 if _uiscale is ba.UIScale.SMALL else 1.27 if _uiscale is ba.UIScale.MEDIUM else 1.3 width = 380 * s height = 150 + 150 * s color = (0.9, 0.9, 0.9) @@ -1633,10 +1665,10 @@ async def draw_ui(self): on_value_change_call=ba.Call(self.toggle_setting, setting), maxwidth=500, textcolor=(0.9, 0.9, 0.9), - scale=0.75) - pos -= 32 + scale=text_scale * 0.8) + pos -= 34 * text_scale - pos -= 20 + pos = height - 220 ba.textwidget(parent=self._root_widget, position=(width * 0.49, pos-5), size=(0, 0), @@ -1732,14 +1764,17 @@ def save_settings_button(self): ba.app.config["Community Plugin Manager"]["Settings"] = self.settings.copy() ba.app.config.commit() self._ok() + ba.playsound(ba.getsound('shieldUp')) async def update(self, to_version=None, commit_sha=None): try: await self._plugin_manager.update(to_version, commit_sha) except MD5CheckSumFailedError: ba.screenmessage("MD5 checksum failed during plugin manager update", color=(1, 0, 0)) + ba.playsound(ba.getsound('error')) else: ba.screenmessage("Plugin manager update successful", color=(0, 1, 0)) + ba.playsound(ba.getsound('shieldUp')) ba.textwidget(edit=self._restart_to_reload_changes_text, text='Update Applied!\nRestart game to reload changes.') self._update_button.delete() @@ -1920,7 +1955,7 @@ def _b_title(x: float, y: float, button: ba.Widget, label="", on_activate_call=self._do_modmanager) _b_title(x_offs6, v, mmb, ba.Lstr(value="Plugin Manager")) - imgw = imgh = 120 + imgw = imgh = 112 ba.imagewidget(parent=self._root_widget, position=(x_offs6 + basew * 0.49 - imgw * 0.5 + 5, v + 35), From 1a3353f26b88106141382d5a5b031b572727d3c5 Mon Sep 17 00:00:00 2001 From: Rikko Date: Mon, 29 Aug 2022 18:42:00 +0530 Subject: [PATCH 0018/1464] Bump to v0.1.4 --- index.json | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/index.json b/index.json index 7998e10a..68a81fbc 100644 --- a/index.json +++ b/index.json @@ -1,11 +1,11 @@ { "plugin_manager_url": "http://github.com/bombsquad-community/plugin-manager/{content_type}/{tag}/plugin_manager.py", "versions": { - "0.1.3": { + "0.1.4": { "api_version": 7, - "commit_sha": "c400f49c", + "commit_sha": "24ec7199", "released_on": "28-08-2022", - "md5sum": "ea87ab649dfd7eeada22cebd61f3bf2a" + "md5sum": "2b2753efe6d0db5c098e7e41eb5b8c91" } }, "categories": [ From 109e61c5a304d55ba1b89fb980381cf54f4fb2d6 Mon Sep 17 00:00:00 2001 From: Rikko Date: Mon, 29 Aug 2022 18:47:45 +0530 Subject: [PATCH 0019/1464] Cancel colorscheme window on outside tap --- plugins/utilities/colorscheme.py | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/plugins/utilities/colorscheme.py b/plugins/utilities/colorscheme.py index b339d045..416b0733 100644 --- a/plugins/utilities/colorscheme.py +++ b/plugins/utilities/colorscheme.py @@ -165,11 +165,12 @@ def draw_ui(self): if uiscale is ba.UIScale.MEDIUM else 1.0 ) - top_extra = 15 if uiscale is ba.UIScale.SMALL else 15 + top_extra = 15 super().__init__( root_widget=ba.containerwidget( size=(width, height + top_extra), + on_outside_click_call=self.cancel_on_outside_click, transition="in_right", scale=self._base_scale, stack_offset=(0, 15) if uiscale is ba.UIScale.SMALL else (0, 0), @@ -286,6 +287,10 @@ def _pick_color(self, tag): tag=tag, ) + def cancel_on_outside_click(self): + ba.playsound(ba.getsound("swish")) + self._cancel() + def _cancel(self): if self._last_color and self._last_highlight: colorscheme = ColorScheme(self._last_color, self._last_highlight) From fa363fb251ae8581ebac0a0a030dab56049fedef Mon Sep 17 00:00:00 2001 From: Rikko Date: Mon, 29 Aug 2022 18:49:36 +0530 Subject: [PATCH 0020/1464] colorscheme v1.2.1 --- plugins/utilities.json | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/plugins/utilities.json b/plugins/utilities.json index 4be2b649..c347d34d 100644 --- a/plugins/utilities.json +++ b/plugins/utilities.json @@ -19,6 +19,12 @@ } ], "versions": { + "1.2.1": { + "api_version": 7, + "commit_sha": "109e61c5a", + "released_on": "29-08-2022", + "md5sum": "970360789f4605132eb5091e30a64642" + }, "1.2.0": { "api_version": 7, "commit_sha": "963a17379", From 41a8fe4855672fedda0cc77d41186ae82aceb69b Mon Sep 17 00:00:00 2001 From: Rikko Date: Mon, 29 Aug 2022 18:59:16 +0530 Subject: [PATCH 0021/1464] Add sound on plugin enable --- plugin_manager.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/plugin_manager.py b/plugin_manager.py index 782db124..846d74bb 100644 --- a/plugin_manager.py +++ b/plugin_manager.py @@ -865,6 +865,7 @@ def disable(self) -> None: @button async def enable(self) -> None: await self.local_plugin.enable() + ba.playsound(ba.getsound('gunCocking')) @button async def install(self): @@ -1764,7 +1765,7 @@ def save_settings_button(self): ba.app.config["Community Plugin Manager"]["Settings"] = self.settings.copy() ba.app.config.commit() self._ok() - ba.playsound(ba.getsound('shieldUp')) + ba.playsound(ba.getsound('gunCocking')) async def update(self, to_version=None, commit_sha=None): try: From dc30f6b774d472899c512c6b75ac095648c1f46f Mon Sep 17 00:00:00 2001 From: Rikko Date: Mon, 29 Aug 2022 19:00:14 +0530 Subject: [PATCH 0022/1464] Add sound on plugin enable --- index.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/index.json b/index.json index 68a81fbc..06c80bc0 100644 --- a/index.json +++ b/index.json @@ -3,9 +3,9 @@ "versions": { "0.1.4": { "api_version": 7, - "commit_sha": "24ec7199", + "commit_sha": "41a8fe485", "released_on": "28-08-2022", - "md5sum": "2b2753efe6d0db5c098e7e41eb5b8c91" + "md5sum": "e813cffc24b175fa350b6c0b257ceeab" } }, "categories": [ From 3f177bd27ed58e93a21ab58e5b619a0bc072dbd8 Mon Sep 17 00:00:00 2001 From: Rikko Date: Mon, 29 Aug 2022 22:31:28 +0530 Subject: [PATCH 0023/1464] Add tests --- .github/workflows/test.yml | 25 +++++++++++++ .gitignore | 2 + test/__init__.py | 0 test/pip_reqs.txt | 1 + test/test_checks.py | 77 ++++++++++++++++++++++++++++++++++++++ 5 files changed, 105 insertions(+) create mode 100644 .github/workflows/test.yml create mode 100644 test/__init__.py create mode 100644 test/pip_reqs.txt create mode 100644 test/test_checks.py diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml new file mode 100644 index 00000000..5d97e017 --- /dev/null +++ b/.github/workflows/test.yml @@ -0,0 +1,25 @@ +name: Tests + +on: [push] + +jobs: + build: + runs-on: ubuntu-latest + strategy: + matrix: + python-version: ["3.10"] + steps: + - uses: actions/checkout@v3 + - name: Set up Python ${{ matrix.python-version }} + uses: actions/setup-python@v3 + with: + python-version: ${{ matrix.python-version }} + - name: Code Style + run: | + python -m pip install --upgrade pip + pip install flake8 + flake8 + - name: Tests + run: | + pip install -r test/pip_reqs.txt + python -m unittest discover diff --git a/.gitignore b/.gitignore index 536edab4..44e23e1b 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1,3 @@ reference.py +__pycache__ +*.pyc diff --git a/test/__init__.py b/test/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/test/pip_reqs.txt b/test/pip_reqs.txt new file mode 100644 index 00000000..ee4ba4f3 --- /dev/null +++ b/test/pip_reqs.txt @@ -0,0 +1 @@ +aiohttp diff --git a/test/test_checks.py b/test/test_checks.py new file mode 100644 index 00000000..8b1f1970 --- /dev/null +++ b/test/test_checks.py @@ -0,0 +1,77 @@ +import hashlib +import os +import json +import re + +import asyncio +import aiohttp + +import unittest + + +async def assert_for_md5sum(url, md5sum, aiohttp_session): + async with aiohttp_session.get(url) as response: + expected_response_status = 200 + assert response.status == expected_response_status, ( + f'Request to "{url}" returned status code {response.status} (expected {expected_response_status}.' + ) + content = await response.read() + caclulated_md5sum = hashlib.md5(content).hexdigest() + assert caclulated_md5sum == md5sum, ( + f'"{url}" failed MD5 checksum:\nGot {caclulated_md5sum} (expected {md5sum}).' + ) + + +async def assert_for_commit_sha_and_md5sum_from_versions(base_url, versions, aiohttp_session): + tasks = tuple( + assert_for_md5sum( + base_url.format(content_type="raw", tag=version["commit_sha"]), + version["md5sum"], + aiohttp_session, + ) for number, version in versions.items() + ) + await asyncio.gather(*tasks) + + +class TestPluginManagerMetadata(unittest.IsolatedAsyncioTestCase): + async def asyncSetUp(self): + with open("index.json", "rb") as fin: + self.content = json.load(fin) + self.version_regexp = re.compile(b"PLUGIN_MANAGER_VERSION = .+") + + async def asyncTearDown(self): + pass + + def test_keys(self): + assert isinstance(self.content["plugin_manager_url"], str) + assert isinstance(self.content["versions"], dict) + assert isinstance(self.content["categories"], list) + assert isinstance(self.content["external_source_url"], str) + + def test_versions_order(self): + versions = list(self.content["versions"].items()) + sorted_versions = sorted(versions, key=lambda version: version[0]) + assert sorted_versions == versions + + async def test_versions_metadata(self): + versions = tuple(self.content["versions"].items()) + latest_number, latest_version = versions[0] + async with aiohttp.ClientSession() as session: + await asyncio.gather( + assert_for_commit_sha_and_md5sum_from_versions( + self.content["plugin_manager_url"], + self.content["versions"], + session, + ), + # Additionally assert for the latest version with tag as "main". + assert_for_md5sum( + self.content["plugin_manager_url"].format(content_type="raw", tag="main"), + latest_version["md5sum"], + session, + ), + ) + + +# class TestPluginsMetadata(unittest.IsolatedAsyncioTestCase): + +# class TestExternalSourceMetadata(unittest.IsolatedAsyncioTestCase): From 74ca172fe648c2579eec6a11c15ae32c53495736 Mon Sep 17 00:00:00 2001 From: Rikko Date: Mon, 29 Aug 2022 22:39:09 +0530 Subject: [PATCH 0024/1464] Have a separate GH action for tests --- .github/workflows/test.yml | 8 +++----- test/test_checks.py | 16 ++++++++++++---- 2 files changed, 15 insertions(+), 9 deletions(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 5d97e017..c3effedc 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -14,12 +14,10 @@ jobs: uses: actions/setup-python@v3 with: python-version: ${{ matrix.python-version }} - - name: Code Style + - name: Install Dependencies run: | python -m pip install --upgrade pip - pip install flake8 - flake8 - - name: Tests - run: | pip install -r test/pip_reqs.txt + - name: Execute Tests + run: | python -m unittest discover diff --git a/test/test_checks.py b/test/test_checks.py index 8b1f1970..900897c1 100644 --- a/test/test_checks.py +++ b/test/test_checks.py @@ -13,19 +13,24 @@ async def assert_for_md5sum(url, md5sum, aiohttp_session): async with aiohttp_session.get(url) as response: expected_response_status = 200 assert response.status == expected_response_status, ( - f'Request to "{url}" returned status code {response.status} (expected {expected_response_status}.' + f'Request to "{url}" returned status code {response.status} ' + f'(expected {expected_response_status}).' ) content = await response.read() caclulated_md5sum = hashlib.md5(content).hexdigest() assert caclulated_md5sum == md5sum, ( - f'"{url}" failed MD5 checksum:\nGot {caclulated_md5sum} (expected {md5sum}).' + f'"{url}" failed MD5 checksum:\nGot {caclulated_md5sum} ' + f'(expected {md5sum}).' ) async def assert_for_commit_sha_and_md5sum_from_versions(base_url, versions, aiohttp_session): tasks = tuple( assert_for_md5sum( - base_url.format(content_type="raw", tag=version["commit_sha"]), + base_url.format( + content_type="raw", + tag=version["commit_sha"], + ), version["md5sum"], aiohttp_session, ) for number, version in versions.items() @@ -65,7 +70,10 @@ async def test_versions_metadata(self): ), # Additionally assert for the latest version with tag as "main". assert_for_md5sum( - self.content["plugin_manager_url"].format(content_type="raw", tag="main"), + self.content["plugin_manager_url"].format( + content_type="raw", + tag="main", + ), latest_version["md5sum"], session, ), From ed5a5853d9a10aa0e014946a7aa2c77e4fd87dc2 Mon Sep 17 00:00:00 2001 From: Rikko Date: Mon, 29 Aug 2022 22:48:39 +0530 Subject: [PATCH 0025/1464] Add instructions on executing tests --- README.md | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/README.md b/README.md index 9b118a2d..88a378da 100644 --- a/README.md +++ b/README.md @@ -54,6 +54,14 @@ A plugin manager for the game - [Bombsquad](https://www.froemling.net/apps/bombs selection popup window in-game. +## Tests + +Metadata tests are automatically executed whenever a pull request is opened and a commit is pushed. You can also run them +locally by executing the following in the project's root directory: +```bash +$ python -m unittest discover +``` + ## License - [Plugin manager's source code](plugin_manager.py) is licensed under the MIT license. See [LICENSE](LICENSE) for more From e2e281694869bce806e656c4f7ca7f9c8411f6a2 Mon Sep 17 00:00:00 2001 From: Rikko Date: Mon, 29 Aug 2022 22:57:28 +0530 Subject: [PATCH 0026/1464] Add instructions to install test dependencies --- README.md | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 88a378da..f1f2445e 100644 --- a/README.md +++ b/README.md @@ -57,7 +57,14 @@ A plugin manager for the game - [Bombsquad](https://www.froemling.net/apps/bombs ## Tests Metadata tests are automatically executed whenever a pull request is opened and a commit is pushed. You can also run them -locally by executing the following in the project's root directory: +locally by installing test dependencies with: + +```bash +$ pip install -r test/pip_reqs.txt +``` + +and then executing the following in the project's root directory: + ```bash $ python -m unittest discover ``` From 43f5d80a00c71352a58002cf0ffce8724aa64aa8 Mon Sep 17 00:00:00 2001 From: Freaku17 <92618708+Freaku17@users.noreply.github.com> Date: Tue, 30 Aug 2022 16:32:34 +0530 Subject: [PATCH 0027/1464] Adding TowerD-unlocked --- plugins/utilities/TowerD-Unlocked.py | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) create mode 100644 plugins/utilities/TowerD-Unlocked.py diff --git a/plugins/utilities/TowerD-Unlocked.py b/plugins/utilities/TowerD-Unlocked.py new file mode 100644 index 00000000..19e24b4e --- /dev/null +++ b/plugins/utilities/TowerD-Unlocked.py @@ -0,0 +1,18 @@ +#By Freaku / @[Just] Freak#4999 + + +import ba +from bastd.maps import TowerD + + +@classmethod +def new_play_types(cls): + """return valid play types for this map.""" + return ['melee', 'keep_away', 'team_flag', 'king_of_the_hill'] + + +# ba_meta require api 7 +# ba_meta export plugin +class byFreaku(ba.Plugin): + def on_app_running(self): + TowerD.get_play_types = new_play_types From c3c3778f5e561d33613534470105fd0336b289c0 Mon Sep 17 00:00:00 2001 From: Freaku17 <92618708+Freaku17@users.noreply.github.com> Date: Tue, 30 Aug 2022 16:47:06 +0530 Subject: [PATCH 0028/1464] Adding plugin info to utilities.json --- plugins/utilities.json | 21 ++++++++++++++++++++- 1 file changed, 20 insertions(+), 1 deletion(-) diff --git a/plugins/utilities.json b/plugins/utilities.json index c347d34d..a3bc61ea 100644 --- a/plugins/utilities.json +++ b/plugins/utilities.json @@ -63,6 +63,25 @@ "md5sum": "233dfaa7f0e9394d21454f4ffa7d0205" } } + }, + "TowerD-Unlocked": { + "description": "Ability to play Tower-D map in ffa/team games!", + "external_url": "", + "authors": [ + { + "name": "Freaku", + "email": "", + "discord": "[Just] Freak#4999" + } + ], + "versions": { + "1.0.0": { + "api_version": 7, + "commit_sha": "43f5d80", + "released_on": "30-08-2022", + "md5sum": "6bf54255b323013bc3aaa571682e8a67" + } + } } } -} +} \ No newline at end of file From 5981bef63c9f04086176e1d301319b79eff0574d Mon Sep 17 00:00:00 2001 From: Vishal Date: Tue, 30 Aug 2022 18:29:00 +0530 Subject: [PATCH 0029/1464] Now checks will work when someone creates a Pull Request --- .github/workflows/flake8.yml | 4 +++- .github/workflows/mod-analyze.yml | 6 ++++-- .github/workflows/test.yml | 4 +++- 3 files changed, 10 insertions(+), 4 deletions(-) diff --git a/.github/workflows/flake8.yml b/.github/workflows/flake8.yml index 6e4fef06..13e470d2 100644 --- a/.github/workflows/flake8.yml +++ b/.github/workflows/flake8.yml @@ -1,6 +1,8 @@ name: Flake8 -on: [push] +on: + push: + pull_request: jobs: build: diff --git a/.github/workflows/mod-analyze.yml b/.github/workflows/mod-analyze.yml index 0d400b24..8e2d595d 100644 --- a/.github/workflows/mod-analyze.yml +++ b/.github/workflows/mod-analyze.yml @@ -1,7 +1,9 @@ name: PluginCheck -on: [push] - +on: + push: + pull_request: + jobs: build: runs-on: ubuntu-latest diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index c3effedc..2c01d00e 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -1,6 +1,8 @@ name: Tests -on: [push] +on: + push: + pull_request: jobs: build: From ece4b806c2f61ec8aedbe6890c76971db7bbc96f Mon Sep 17 00:00:00 2001 From: Freaku17 <92618708+Freaku17@users.noreply.github.com> Date: Tue, 30 Aug 2022 20:29:57 +0530 Subject: [PATCH 0030/1464] Fixing flake8 error --- plugins/utilities/TowerD-Unlocked.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/utilities/TowerD-Unlocked.py b/plugins/utilities/TowerD-Unlocked.py index 19e24b4e..e6d29b49 100644 --- a/plugins/utilities/TowerD-Unlocked.py +++ b/plugins/utilities/TowerD-Unlocked.py @@ -1,4 +1,4 @@ -#By Freaku / @[Just] Freak#4999 +# By Freaku / @[Just] Freak#4999 import ba From fede0c4d6b1f92e21c07cae12f46126505f8cbac Mon Sep 17 00:00:00 2001 From: Freaku17 <92618708+Freaku17@users.noreply.github.com> Date: Tue, 30 Aug 2022 23:39:21 +0530 Subject: [PATCH 0031/1464] Update utilities.json --- plugins/utilities.json | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/plugins/utilities.json b/plugins/utilities.json index a3bc61ea..a5b30a9c 100644 --- a/plugins/utilities.json +++ b/plugins/utilities.json @@ -77,11 +77,11 @@ "versions": { "1.0.0": { "api_version": 7, - "commit_sha": "43f5d80", + "commit_sha": "ece4b806", "released_on": "30-08-2022", - "md5sum": "6bf54255b323013bc3aaa571682e8a67" + "md5sum": "aac4edfcaeca1dc2910f97e739d67482" } } } } -} \ No newline at end of file +} From 6beb8ddf2984a5adfa35e611c68f097cefb5269b Mon Sep 17 00:00:00 2001 From: Rikko Date: Tue, 30 Aug 2022 23:54:59 +0530 Subject: [PATCH 0032/1464] Rename TowerD-Unlocked.py to unlock_TowerD.py --- plugins/utilities/{TowerD-Unlocked.py => unlock_TowerD.py} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename plugins/utilities/{TowerD-Unlocked.py => unlock_TowerD.py} (100%) diff --git a/plugins/utilities/TowerD-Unlocked.py b/plugins/utilities/unlock_TowerD.py similarity index 100% rename from plugins/utilities/TowerD-Unlocked.py rename to plugins/utilities/unlock_TowerD.py From 40b70fe4a78f53c02b39ae068e72203e3c4f182d Mon Sep 17 00:00:00 2001 From: Rikko Date: Tue, 30 Aug 2022 23:55:38 +0530 Subject: [PATCH 0033/1464] Rename TowerD-Unlocked.py to unlock_TowerD.py --- plugins/utilities.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/plugins/utilities.json b/plugins/utilities.json index a5b30a9c..51a73974 100644 --- a/plugins/utilities.json +++ b/plugins/utilities.json @@ -64,7 +64,7 @@ } } }, - "TowerD-Unlocked": { + "unlock_TowerD": { "description": "Ability to play Tower-D map in ffa/team games!", "external_url": "", "authors": [ @@ -77,7 +77,7 @@ "versions": { "1.0.0": { "api_version": 7, - "commit_sha": "ece4b806", + "commit_sha": "6beb8ddf", "released_on": "30-08-2022", "md5sum": "aac4edfcaeca1dc2910f97e739d67482" } From 21c62f72f99ade78c607c715bd607a8f670d7139 Mon Sep 17 00:00:00 2001 From: Rikko Date: Wed, 31 Aug 2022 06:18:24 +0530 Subject: [PATCH 0034/1464] Add plugin meta tests --- plugins/minigames.json | 2 +- plugins/utilities.json | 8 +- test/pip_reqs.txt | 2 +- test/test_checks.py | 210 ++++++++++++++++++++++++++++------------- 4 files changed, 147 insertions(+), 75 deletions(-) diff --git a/plugins/minigames.json b/plugins/minigames.json index 4d69b676..6ed54d62 100644 --- a/plugins/minigames.json +++ b/plugins/minigames.json @@ -16,7 +16,7 @@ "versions": { "1.1.0": { "api_version": 7, - "commit_sha": "cbdb3ead", + "commit_sha": "40b70fe", "released_on": "08-08-2022", "md5sum": "f4f0bb91f5d10cf8f591ecf7d2848182" } diff --git a/plugins/utilities.json b/plugins/utilities.json index 51a73974..928a86db 100644 --- a/plugins/utilities.json +++ b/plugins/utilities.json @@ -30,12 +30,6 @@ "commit_sha": "963a17379", "released_on": "12-08-2022", "md5sum": "41084bfec41119ca9df8e6d899cd3cc0" - }, - "1.1.0": { - "api_version": 7, - "commit_sha": "13a9d128", - "released_on": "03-06-2022", - "md5sum": "4b6bbb99037ebda4664da7c510b3717c" }, "1.0.0": { "api_version": 6, @@ -58,7 +52,7 @@ "versions": { "1.0.0": { "api_version": 7, - "commit_sha": "2aa6df31", + "commit_sha": "63d674cf", "released_on": "06-08-2022", "md5sum": "233dfaa7f0e9394d21454f4ffa7d0205" } diff --git a/test/pip_reqs.txt b/test/pip_reqs.txt index ee4ba4f3..64b1adae 100644 --- a/test/pip_reqs.txt +++ b/test/pip_reqs.txt @@ -1 +1 @@ -aiohttp +GitPython diff --git a/test/test_checks.py b/test/test_checks.py index 900897c1..db8e5099 100644 --- a/test/test_checks.py +++ b/test/test_checks.py @@ -1,85 +1,163 @@ +import git + import hashlib -import os import json import re - -import asyncio -import aiohttp +import io +import os +import pathlib import unittest -async def assert_for_md5sum(url, md5sum, aiohttp_session): - async with aiohttp_session.get(url) as response: - expected_response_status = 200 - assert response.status == expected_response_status, ( - f'Request to "{url}" returned status code {response.status} ' - f'(expected {expected_response_status}).' - ) - content = await response.read() - caclulated_md5sum = hashlib.md5(content).hexdigest() - assert caclulated_md5sum == md5sum, ( - f'"{url}" failed MD5 checksum:\nGot {caclulated_md5sum} ' - f'(expected {md5sum}).' - ) - - -async def assert_for_commit_sha_and_md5sum_from_versions(base_url, versions, aiohttp_session): - tasks = tuple( - assert_for_md5sum( - base_url.format( - content_type="raw", - tag=version["commit_sha"], - ), - version["md5sum"], - aiohttp_session, - ) for number, version in versions.items() - ) - await asyncio.gather(*tasks) - - -class TestPluginManagerMetadata(unittest.IsolatedAsyncioTestCase): - async def asyncSetUp(self): +class TestPluginManagerMetadata(unittest.TestCase): + def setUp(self): with open("index.json", "rb") as fin: self.content = json.load(fin) - self.version_regexp = re.compile(b"PLUGIN_MANAGER_VERSION = .+") + self.plugin_manager = "plugin_manager.py" + self.api_version_regexp = re.compile(b"(?<=ba_meta require api )(.*)") + self.plugin_manager_version_regexp = re.compile(b"(?<=PLUGIN_MANAGER_VERSION = )(.*)") - async def asyncTearDown(self): - pass + self.current_path = pathlib.Path() + self.repository = git.Repo() def test_keys(self): - assert isinstance(self.content["plugin_manager_url"], str) - assert isinstance(self.content["versions"], dict) - assert isinstance(self.content["categories"], list) - assert isinstance(self.content["external_source_url"], str) + self.assertTrue(isinstance(self.content["plugin_manager_url"], str)) + self.assertTrue(isinstance(self.content["versions"], dict)) + self.assertTrue(isinstance(self.content["categories"], list)) + self.assertTrue(isinstance(self.content["external_source_url"], str)) def test_versions_order(self): versions = list(self.content["versions"].items()) sorted_versions = sorted(versions, key=lambda version: version[0]) assert sorted_versions == versions - async def test_versions_metadata(self): + def test_versions(self): + for version_name, version_metadata in self.content["versions"].items(): + commit = self.repository.commit(version_metadata["commit_sha"]) + plugin_manager = commit.tree / self.plugin_manager + with io.BytesIO(plugin_manager.data_stream.read()) as fin: + content = fin.read() + + md5sum = hashlib.md5(content).hexdigest() + api_version = self.api_version_regexp.search(content).group() + plugin_manager_version = self.plugin_manager_version_regexp.search(content).group() + + self.assertEqual(md5sum, version_metadata["md5sum"]) + self.assertEqual(int(api_version.decode("utf-8")), version_metadata["api_version"]) + self.assertEqual(plugin_manager_version.decode("utf-8"), f'"{version_name}"') + + def test_latest_version(self): versions = tuple(self.content["versions"].items()) - latest_number, latest_version = versions[0] - async with aiohttp.ClientSession() as session: - await asyncio.gather( - assert_for_commit_sha_and_md5sum_from_versions( - self.content["plugin_manager_url"], - self.content["versions"], - session, - ), - # Additionally assert for the latest version with tag as "main". - assert_for_md5sum( - self.content["plugin_manager_url"].format( - content_type="raw", - tag="main", - ), - latest_version["md5sum"], - session, - ), - ) - - -# class TestPluginsMetadata(unittest.IsolatedAsyncioTestCase): - -# class TestExternalSourceMetadata(unittest.IsolatedAsyncioTestCase): + latest_version_name, latest_version_metadata = versions[0] + plugin_manager = self.current_path / self.plugin_manager + with open(plugin_manager, "rb") as fin: + content = fin.read() + + md5sum = hashlib.md5(content).hexdigest() + api_version = self.api_version_regexp.search(content).group() + plugin_manager_version = self.plugin_manager_version_regexp.search(content).group() + + self.assertEqual(md5sum, latest_version_metadata["md5sum"]) + self.assertEqual(int(api_version.decode("utf-8")), latest_version_metadata["api_version"]) + self.assertEqual(plugin_manager_version.decode("utf-8"), f'"{latest_version_name}"') + + +class TestPluginMetadata(unittest.TestCase): + def setUp(self): + self.category_directories = tuple( + f'{os.path.join("plugins", path)}' + for path in os.listdir("plugins") if os.path.isdir(path) + ) + + def test_no_duplicates(self): + unique_plugins = set() + total_plugin_count = 0 + for category in self.category_directories: + plugins = os.listdir(category) + total_plugin_count += len(plugins) + unique_plugins.update(plugins) + self.assertEqual(len(unique_plugins), total_plugin_count) + + +class BaseCategoryMetadataTestCases: + class BaseTest(unittest.TestCase): + def setUp(self): + self.api_version_regexp = re.compile(b"(?<=ba_meta require api )(.*)") + + self.current_path = pathlib.Path() + self.repository = git.Repo() + + def test_keys(self): + self.assertEqual(self.content["name"], self.name) + self.assertTrue(isinstance(self.content["description"], str)) + self.assertTrue(self.content["plugins_base_url"].startswith("http")) + self.assertTrue(isinstance(self.content["plugins"], dict)) + + def test_versions_order(self): + for plugin_metadata in self.content["plugins"].values(): + versions = list(plugin_metadata["versions"].items()) + sorted_versions = sorted( + versions, + key=lambda version: version[0], + reverse=True, + ) + self.assertEqual(sorted_versions, versions) + + def test_plugin_keys(self): + for plugin_metadata in self.content["plugins"].values(): + self.assertTrue(isinstance(plugin_metadata["description"], str)) + self.assertTrue(isinstance(plugin_metadata["external_url"], str)) + self.assertTrue(isinstance(plugin_metadata["authors"], list)) + self.assertTrue(len(plugin_metadata["authors"]) > 0) + for author in plugin_metadata["authors"]: + self.assertTrue(isinstance(author["name"], str)) + self.assertTrue(isinstance(author["email"], str)) + self.assertTrue(isinstance(author["discord"], str)) + self.assertTrue(isinstance(plugin_metadata["versions"], dict)) + self.assertTrue(len(plugin_metadata["versions"]) > 0) + + def test_versions(self): + for plugin_name, plugin_metadata in self.content["plugins"].items(): + for version_name, version_metadata in plugin_metadata["versions"].items(): + commit = self.repository.commit(version_metadata["commit_sha"]) + plugin = commit.tree / self.category / f"{plugin_name}.py" + with io.BytesIO(plugin.data_stream.read()) as fin: + content = fin.read() + + md5sum = hashlib.md5(content).hexdigest() + api_version = self.api_version_regexp.search(content).group() + + self.assertEqual(md5sum, version_metadata["md5sum"]) + self.assertEqual(int(api_version.decode("utf-8")), version_metadata["api_version"]) + + def test_latest_version(self): + for plugin_name, plugin_metadata in self.content["plugins"].items(): + latest_version_name, latest_version_metadata = tuple(plugin_metadata["versions"].items())[0] + plugin = self.current_path / self.category / f"{plugin_name}.py" + with open(plugin, "rb") as fin: + content = fin.read() + + md5sum = hashlib.md5(content).hexdigest() + api_version = self.api_version_regexp.search(content).group() + + self.assertEqual(md5sum, latest_version_metadata["md5sum"]) + self.assertEqual(int(api_version.decode("utf-8")), latest_version_metadata["api_version"]) + + +class TestUtilitiesCategoryMetadata(BaseCategoryMetadataTestCases.BaseTest): + def setUp(self): + super().setUp() + self.name = "Utilities" + self.category = os.path.join("plugins", "utilities") + with open(f"{self.category}.json", "rb") as fin: + self.content = json.load(fin) + + +class TestMinigamesCategoryMetadata(BaseCategoryMetadataTestCases.BaseTest): + def setUp(self): + super().setUp() + self.name = "Minigames" + self.category = os.path.join("plugins", "minigames") + with open(f"{self.category}.json", "rb") as fin: + self.content = json.load(fin) From 4110d2bd1520cd2430938db6c815bf0c136d3bec Mon Sep 17 00:00:00 2001 From: Rikko Date: Wed, 31 Aug 2022 06:30:07 +0530 Subject: [PATCH 0035/1464] verbose CI, fetch entire git history --- .github/workflows/test.yml | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 2c01d00e..d04e2fbc 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -12,6 +12,8 @@ jobs: python-version: ["3.10"] steps: - uses: actions/checkout@v3 + with: + fetch-depth: 0 - name: Set up Python ${{ matrix.python-version }} uses: actions/setup-python@v3 with: @@ -22,4 +24,4 @@ jobs: pip install -r test/pip_reqs.txt - name: Execute Tests run: | - python -m unittest discover + python -m unittest discover -v From 0fc1c8a274e22a60560b7facb00cc81b484e0622 Mon Sep 17 00:00:00 2001 From: Rikko Date: Wed, 31 Aug 2022 06:32:58 +0530 Subject: [PATCH 0036/1464] Remove redundant ci actions --- .github/workflows/MetaData.yml | 25 ----------------- .../workflows/{flake8.yml => code_style.yml} | 4 +-- .github/workflows/mod-analyze.yml | 27 ------------------- 3 files changed, 2 insertions(+), 54 deletions(-) delete mode 100644 .github/workflows/MetaData.yml rename .github/workflows/{flake8.yml => code_style.yml} (96%) delete mode 100644 .github/workflows/mod-analyze.yml diff --git a/.github/workflows/MetaData.yml b/.github/workflows/MetaData.yml deleted file mode 100644 index 78d8980b..00000000 --- a/.github/workflows/MetaData.yml +++ /dev/null @@ -1,25 +0,0 @@ -name: MetaDataCheck - -on: - push: - pull_request: - -jobs: - build: - runs-on: ubuntu-latest - strategy: - matrix: - python-version: ["3.10"] - steps: - - uses: actions/checkout@v3 - - name: Set up Python ${{ matrix.python-version }} - uses: actions/setup-python@v3 - with: - python-version: ${{ matrix.python-version }} - - name: Check MetaData - run: | - echo "Analyzing All Py Files" - for pyfile in $(git ls-files '*.py'); do - cat $pyfile | grep "# ba_meta require api 7" > /dev/null || (echo "$pyfile doesn't have the MetaData present in it." && exit 1) - done - echo "All Py Files have MetaData present in them." diff --git a/.github/workflows/flake8.yml b/.github/workflows/code_style.yml similarity index 96% rename from .github/workflows/flake8.yml rename to .github/workflows/code_style.yml index 13e470d2..d68a9064 100644 --- a/.github/workflows/flake8.yml +++ b/.github/workflows/code_style.yml @@ -1,6 +1,6 @@ -name: Flake8 +name: Code Style -on: +on: push: pull_request: diff --git a/.github/workflows/mod-analyze.yml b/.github/workflows/mod-analyze.yml deleted file mode 100644 index 8e2d595d..00000000 --- a/.github/workflows/mod-analyze.yml +++ /dev/null @@ -1,27 +0,0 @@ -name: PluginCheck - -on: - push: - pull_request: - -jobs: - build: - runs-on: ubuntu-latest - strategy: - matrix: - python-version: ["3.10"] - steps: - - uses: actions/checkout@v3 - - name: Set up Python ${{ matrix.python-version }} - uses: actions/setup-python@v3 - with: - python-version: ${{ matrix.python-version }} - - name: Install dependencies - run: | - sudo apt install jq - - name: Analysing mods - run: | - for jsonfile in $(git ls-files '*.json'); do - echo "Analyzing $jsonfile" - jq -e < $jsonfile > /dev/null || exit 1; - done From f29008acdbf54988f3622ae4baa8735d83338bb5 Mon Sep 17 00:00:00 2001 From: Rikko Date: Wed, 31 Aug 2022 15:58:19 +0530 Subject: [PATCH 0037/1464] Auto apply version metadata --- .../workflows/auto_apply_version_metadata.yml | 25 ++++ .github/workflows/test.yml | 2 +- plugins/minigames.json | 10 +- plugins/utilities.json | 52 ++++---- test/auto_apply_version_metadata.py | 124 ++++++++++++++++++ 5 files changed, 181 insertions(+), 32 deletions(-) create mode 100644 .github/workflows/auto_apply_version_metadata.yml create mode 100644 test/auto_apply_version_metadata.py diff --git a/.github/workflows/auto_apply_version_metadata.yml b/.github/workflows/auto_apply_version_metadata.yml new file mode 100644 index 00000000..268c38a7 --- /dev/null +++ b/.github/workflows/auto_apply_version_metadata.yml @@ -0,0 +1,25 @@ +name: Apply Version Metadata + +on: + pull_request: + +jobs: + build: + runs-on: ubuntu-latest + strategy: + matrix: + python-version: ["3.10"] + steps: + - uses: actions/checkout@v3 + with: + fetch-depth: 0 + - name: Set up Python ${{ matrix.python-version }} + uses: actions/setup-python@v3 + with: + python-version: ${{ matrix.python-version }} + - name: Auto Apply Version Metadata + uses: stefanzweifel/git-auto-commit-action@v4 + with: + commit_message: Apply version metadata + run: | + python test/auto_apply_version_metadata.py diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index d04e2fbc..d96fffa2 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -1,6 +1,6 @@ name: Tests -on: +on: push: pull_request: diff --git a/plugins/minigames.json b/plugins/minigames.json index 6ed54d62..19608e3a 100644 --- a/plugins/minigames.json +++ b/plugins/minigames.json @@ -14,11 +14,11 @@ } ], "versions": { - "1.1.0": { - "api_version": 7, - "commit_sha": "40b70fe", - "released_on": "08-08-2022", - "md5sum": "f4f0bb91f5d10cf8f591ecf7d2848182" + "1.1.0": { + "api_version": 7, + "commit_sha": "40b70fe", + "released_on": "08-08-2022", + "md5sum": "f4f0bb91f5d10cf8f591ecf7d2848182" } } } diff --git a/plugins/utilities.json b/plugins/utilities.json index 928a86db..41eda5e1 100644 --- a/plugins/utilities.json +++ b/plugins/utilities.json @@ -19,23 +19,23 @@ } ], "versions": { - "1.2.1": { - "api_version": 7, - "commit_sha": "109e61c5a", - "released_on": "29-08-2022", - "md5sum": "970360789f4605132eb5091e30a64642" + "1.2.1": { + "api_version": 7, + "commit_sha": "109e61c5a", + "released_on": "29-08-2022", + "md5sum": "970360789f4605132eb5091e30a64642" }, - "1.2.0": { - "api_version": 7, - "commit_sha": "963a17379", - "released_on": "12-08-2022", - "md5sum": "41084bfec41119ca9df8e6d899cd3cc0" + "1.2.0": { + "api_version": 7, + "commit_sha": "963a17379", + "released_on": "12-08-2022", + "md5sum": "41084bfec41119ca9df8e6d899cd3cc0" }, - "1.0.0": { - "api_version": 6, - "commit_sha": "da5032a7", - "released_on": "28-05-2021", - "md5sum": "527acfec13a2d0a6115a52df7abca920" + "1.0.0": { + "api_version": 6, + "commit_sha": "da5032a7", + "released_on": "28-05-2021", + "md5sum": "527acfec13a2d0a6115a52df7abca920" } } }, @@ -50,11 +50,11 @@ } ], "versions": { - "1.0.0": { - "api_version": 7, - "commit_sha": "63d674cf", - "released_on": "06-08-2022", - "md5sum": "233dfaa7f0e9394d21454f4ffa7d0205" + "1.0.0": { + "api_version": 7, + "commit_sha": "63d674cf", + "released_on": "06-08-2022", + "md5sum": "233dfaa7f0e9394d21454f4ffa7d0205" } } }, @@ -69,13 +69,13 @@ } ], "versions": { - "1.0.0": { - "api_version": 7, - "commit_sha": "6beb8ddf", - "released_on": "30-08-2022", - "md5sum": "aac4edfcaeca1dc2910f97e739d67482" + "1.0.0": { + "api_version": 7, + "commit_sha": "6beb8ddf", + "released_on": "30-08-2022", + "md5sum": "aac4edfcaeca1dc2910f97e739d67482" } } } } -} +} \ No newline at end of file diff --git a/test/auto_apply_version_metadata.py b/test/auto_apply_version_metadata.py new file mode 100644 index 00000000..467c6897 --- /dev/null +++ b/test/auto_apply_version_metadata.py @@ -0,0 +1,124 @@ +import hashlib +import json +import os +import sys +import re +import datetime + + +class NullVersionedPlugin: + def __init__(self, plugin_name, version_name, plugin_path, from_json={}): + self.plugin_name = plugin_name + self.version_name = version_name + self.plugin_path = plugin_path + self.json = from_json + self.api_version_regexp = re.compile(b"(?<=ba_meta require api )(.*)") + self._content = None + + def set_json(self, json): + self.json = json + return self + + def set_api_version(self): + if self._content is None: + with open(self.plugin_path, "rb") as fin: + self._content = fin.read() + + versions = self.json["plugins"][self.plugin_name]["versions"] + if versions[self.version_name] is None: + versions[self.version_name] = {} + + api_version = self.api_version_regexp.search(self._content).group() + versions[self.version_name]["api_version"] = int(api_version) + return self + + def set_commit_sha(self, commit_sha): + versions = self.json["plugins"][self.plugin_name]["versions"] + if versions[self.version_name] is None: + versions[self.version_name] = {} + + versions[self.version_name]["commit_sha"] = commit_sha[:8] + return self + + def set_released_on(self, date): + versions = self.json["plugins"][self.plugin_name]["versions"] + if versions[self.version_name] is None: + versions[self.version_name] = {} + + versions[self.version_name]["released_on"] = date + return self + + def set_md5sum(self): + if self._content is None: + with open(self.plugin_path, "rb") as fin: + self._content = fin.read() + + versions = self.json["plugins"][self.plugin_name]["versions"] + if versions[self.version_name] is None: + versions[self.version_name] = {} + + md5sum = hashlib.md5(self._content).hexdigest() + versions[self.version_name]["md5sum"] = md5sum + return self + + +class CategoryVersionMetadata: + def __init__(self, category_metadata_base): + self.category_metadata_base = category_metadata_base + self.category_metadata_file = f"{self.category_metadata_base}.json" + with open(self.category_metadata_file, "r") as fin: + self.category_metadata = json.load(fin) + + def get_plugins_having_null_version_values(self): + for plugin_name, plugin_metadata in self.category_metadata["plugins"].items(): + latest_version_name, latest_version_metadata = tuple(plugin_metadata["versions"].items())[0] + if latest_version_metadata is None: + plugin_path = f"{os.path.join(self.category_metadata_base, f'{plugin_name}.py')}" + yield NullVersionedPlugin( + plugin_name, + latest_version_name, + plugin_path, + ) + + def apply_version_metadata_to_null_version_values(self, commit_sha): + null_versioned_plugins = self.get_plugins_having_null_version_values() + today = datetime.date.today().strftime("%d-%m-%Y") + category_json = self.category_metadata + for plugin in null_versioned_plugins: + category_json = ( + plugin.set_json(category_json) + .set_api_version() + .set_commit_sha(commit_sha) + .set_released_on(today) + .set_md5sum() + .json + ) + return category_json + + def save(self, category_json): + with open(self.category_metadata_file, "w") as fout: + json.dump( + category_json, + fout, + indent=2, + ensure_ascii=False, + ) + + +def auto_apply_version_metadata(last_commit_sha): + utilities = CategoryVersionMetadata(os.path.join("plugins", "utilities")) + category_json = utilities.apply_version_metadata_to_null_version_values(last_commit_sha) + utilities.save(category_json) + + minigames = CategoryVersionMetadata(os.path.join("plugins", "minigames")) + category_json = minigames.apply_version_metadata_to_null_version_values(last_commit_sha) + minigames.save(category_json) + + +if __name__ == "__main__": + try: + last_commit_sha = sys.argv[1] + except KeyError: + raise ValueError("Last commit SHA not provided.") + else: + auto_apply_version_metadata(last_commit_sha) From ec9f1e1b718cab5e413789fe9bf1af4beefa62d6 Mon Sep 17 00:00:00 2001 From: Rikko Date: Wed, 31 Aug 2022 19:23:20 +0530 Subject: [PATCH 0038/1464] Auto apply version metadata fixes --- .../workflows/auto_apply_version_metadata.yml | 25 ----------- .github/workflows/checks.yml | 41 +++++++++++++++++++ .github/workflows/code_style.yml | 25 ----------- .github/workflows/test.yml | 27 ------------ 4 files changed, 41 insertions(+), 77 deletions(-) delete mode 100644 .github/workflows/auto_apply_version_metadata.yml create mode 100644 .github/workflows/checks.yml delete mode 100644 .github/workflows/code_style.yml delete mode 100644 .github/workflows/test.yml diff --git a/.github/workflows/auto_apply_version_metadata.yml b/.github/workflows/auto_apply_version_metadata.yml deleted file mode 100644 index 268c38a7..00000000 --- a/.github/workflows/auto_apply_version_metadata.yml +++ /dev/null @@ -1,25 +0,0 @@ -name: Apply Version Metadata - -on: - pull_request: - -jobs: - build: - runs-on: ubuntu-latest - strategy: - matrix: - python-version: ["3.10"] - steps: - - uses: actions/checkout@v3 - with: - fetch-depth: 0 - - name: Set up Python ${{ matrix.python-version }} - uses: actions/setup-python@v3 - with: - python-version: ${{ matrix.python-version }} - - name: Auto Apply Version Metadata - uses: stefanzweifel/git-auto-commit-action@v4 - with: - commit_message: Apply version metadata - run: | - python test/auto_apply_version_metadata.py diff --git a/.github/workflows/checks.yml b/.github/workflows/checks.yml new file mode 100644 index 00000000..fc088f6d --- /dev/null +++ b/.github/workflows/checks.yml @@ -0,0 +1,41 @@ +name: Apply PEP8, Metadata, and Run Tests + +on: + pull_request_target: + +jobs: + build: + runs-on: ubuntu-latest + strategy: + matrix: + python-version: ["3.10"] + steps: + - uses: actions/checkout@v3 + with: + token: ${{ secrets.GITHUB_TOKEN }} + repository: ${{ github.event.pull_request.head.repo.full_name }} + ref: ${{ github.head_ref }} + fetch-depth: 0 + - name: Set up Python ${{ matrix.python-version }} + uses: actions/setup-python@v3 + with: + python-version: ${{ matrix.python-version }} + - name: Install Dependencies + run: | + python -m pip install --upgrade pip + pip install autopep8 + pip install -r test/pip_reqs.txt + - name: Apply PEP8 + run: | + autopep8 --in-place --recursive . + - name: Apply Version Metadata + run: | + python test/auto_apply_version_metadata.py $(git log --pretty=format:'%h' -n 1) + - name: Apply Commit + uses: stefanzweifel/git-auto-commit-action@v4 + with: + commit_message: "[ci] auto-format" + branch: ${{ github.head_ref }} + - name: Execute Tests + run: | + python -m unittest discover -v diff --git a/.github/workflows/code_style.yml b/.github/workflows/code_style.yml deleted file mode 100644 index d68a9064..00000000 --- a/.github/workflows/code_style.yml +++ /dev/null @@ -1,25 +0,0 @@ -name: Code Style - -on: - push: - pull_request: - -jobs: - build: - runs-on: ubuntu-latest - strategy: - matrix: - python-version: ["3.10"] - steps: - - uses: actions/checkout@v3 - - name: Set up Python ${{ matrix.python-version }} - uses: actions/setup-python@v3 - with: - python-version: ${{ matrix.python-version }} - - name: Install dependencies - run: | - python -m pip install --upgrade pip - pip install flake8 - - name: Execute Flake8 - run: | - flake8 $(git ls-files '*.py') diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml deleted file mode 100644 index d96fffa2..00000000 --- a/.github/workflows/test.yml +++ /dev/null @@ -1,27 +0,0 @@ -name: Tests - -on: - push: - pull_request: - -jobs: - build: - runs-on: ubuntu-latest - strategy: - matrix: - python-version: ["3.10"] - steps: - - uses: actions/checkout@v3 - with: - fetch-depth: 0 - - name: Set up Python ${{ matrix.python-version }} - uses: actions/setup-python@v3 - with: - python-version: ${{ matrix.python-version }} - - name: Install Dependencies - run: | - python -m pip install --upgrade pip - pip install -r test/pip_reqs.txt - - name: Execute Tests - run: | - python -m unittest discover -v From 29f531e5158ddf924248528ad4ff2e37ec581245 Mon Sep 17 00:00:00 2001 From: Rikko Date: Wed, 31 Aug 2022 19:26:52 +0530 Subject: [PATCH 0039/1464] autopep8 --- plugin_manager.py | 32 +++++++++++++++-------------- setup.cfg | 2 -- test/auto_apply_version_metadata.py | 3 ++- test/test_checks.py | 9 +++++--- 4 files changed, 25 insertions(+), 21 deletions(-) delete mode 100644 setup.cfg diff --git a/plugin_manager.py b/plugin_manager.py index 846d74bb..0c165aa8 100644 --- a/plugin_manager.py +++ b/plugin_manager.py @@ -119,7 +119,7 @@ def __init__(self): def setup_config(self): # is_config_updated = False existing_plugin_manager_config = copy.deepcopy( - ba.app.config.get("Community Plugin Manager")) + ba.app.config.get("Community Plugin Manager")) plugin_manager_config = ba.app.config.setdefault("Community Plugin Manager", {}) plugin_manager_config.setdefault("Custom Sources", []) @@ -534,7 +534,8 @@ async def install(self, suppress_screenmessage=False): local_plugin = await self._download() except MD5CheckSumFailedError: if not suppress_screenmessage: - ba.screenmessage(f"{self.plugin.name} failed MD5 checksum during installation", color=(1, 0, 0)) + ba.screenmessage( + f"{self.plugin.name} failed MD5 checksum during installation", color=(1, 0, 0)) return False else: if not suppress_screenmessage: @@ -621,7 +622,8 @@ def latest_compatible_version(self): def get_local(self): if not self.is_installed: - raise PluginNotInstalledError(f"{self.name} needs to be installed to get its local plugin.") + raise PluginNotInstalledError( + f"{self.name} needs to be installed to get its local plugin.") if self._local_plugin is None: self._local_plugin = PluginLocal(self.name) return self._local_plugin @@ -1244,14 +1246,14 @@ def __init__(self, transition: str = "in_right", origin_widget: ba.Widget = None back_pos_y = self._height - (95 if _uiscale is ba.UIScale.SMALL else 65 if _uiscale is ba.UIScale.MEDIUM else 50) self._back_button = back_button = ba.buttonwidget( - parent=self._root_widget, - position=(back_pos_x, back_pos_y), - size=(60, 60), - scale=0.8, - label=ba.charstr(ba.SpecialChar.BACK), - # autoselect=True, - button_type='backSmall', - on_activate_call=self._back) + parent=self._root_widget, + position=(back_pos_x, back_pos_y), + size=(60, 60), + scale=0.8, + label=ba.charstr(ba.SpecialChar.BACK), + # autoselect=True, + button_type='backSmall', + on_activate_call=self._back) ba.containerwidget(edit=self._root_widget, cancel_button=back_button) @@ -1460,9 +1462,9 @@ def draw_settings_icon(self): def draw_refresh_icon(self): refresh_pos_x = (610 if _uiscale is ba.UIScale.SMALL else - 500 if _uiscale is ba.UIScale.MEDIUM else 510) + 500 if _uiscale is ba.UIScale.MEDIUM else 510) refresh_pos_y = (180 if _uiscale is ba.UIScale.SMALL else - 108 if _uiscale is ba.UIScale.MEDIUM else 120) + 108 if _uiscale is ba.UIScale.MEDIUM else 120) loop = asyncio.get_event_loop() controller_button = ba.buttonwidget(parent=self._root_widget, # autoselect=True, @@ -1719,8 +1721,8 @@ async def draw_ui(self): loop.create_task( self.update( *plugin_manager_update_available - ) - ), + ) + ), textcolor=b_text_color, button_type='square', text_scale=1, diff --git a/setup.cfg b/setup.cfg deleted file mode 100644 index 7da1f960..00000000 --- a/setup.cfg +++ /dev/null @@ -1,2 +0,0 @@ -[flake8] -max-line-length = 100 diff --git a/test/auto_apply_version_metadata.py b/test/auto_apply_version_metadata.py index 467c6897..1ace1ce7 100644 --- a/test/auto_apply_version_metadata.py +++ b/test/auto_apply_version_metadata.py @@ -71,7 +71,8 @@ def __init__(self, category_metadata_base): def get_plugins_having_null_version_values(self): for plugin_name, plugin_metadata in self.category_metadata["plugins"].items(): - latest_version_name, latest_version_metadata = tuple(plugin_metadata["versions"].items())[0] + latest_version_name, latest_version_metadata = tuple( + plugin_metadata["versions"].items())[0] if latest_version_metadata is None: plugin_path = f"{os.path.join(self.category_metadata_base, f'{plugin_name}.py')}" yield NullVersionedPlugin( diff --git a/test/test_checks.py b/test/test_checks.py index db8e5099..12f755b3 100644 --- a/test/test_checks.py +++ b/test/test_checks.py @@ -129,11 +129,13 @@ def test_versions(self): api_version = self.api_version_regexp.search(content).group() self.assertEqual(md5sum, version_metadata["md5sum"]) - self.assertEqual(int(api_version.decode("utf-8")), version_metadata["api_version"]) + self.assertEqual(int(api_version.decode("utf-8")), + version_metadata["api_version"]) def test_latest_version(self): for plugin_name, plugin_metadata in self.content["plugins"].items(): - latest_version_name, latest_version_metadata = tuple(plugin_metadata["versions"].items())[0] + latest_version_name, latest_version_metadata = tuple( + plugin_metadata["versions"].items())[0] plugin = self.current_path / self.category / f"{plugin_name}.py" with open(plugin, "rb") as fin: content = fin.read() @@ -142,7 +144,8 @@ def test_latest_version(self): api_version = self.api_version_regexp.search(content).group() self.assertEqual(md5sum, latest_version_metadata["md5sum"]) - self.assertEqual(int(api_version.decode("utf-8")), latest_version_metadata["api_version"]) + self.assertEqual(int(api_version.decode("utf-8")), + latest_version_metadata["api_version"]) class TestUtilitiesCategoryMetadata(BaseCategoryMetadataTestCases.BaseTest): From a131a209c7935d1f1ca3090b1b47cc8e6362082a Mon Sep 17 00:00:00 2001 From: Rikko Date: Wed, 31 Aug 2022 19:49:46 +0530 Subject: [PATCH 0040/1464] Update hashes --- .github/workflows/checks.yml | 3 ++- index.json | 4 ++-- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/.github/workflows/checks.yml b/.github/workflows/checks.yml index fc088f6d..606202fa 100644 --- a/.github/workflows/checks.yml +++ b/.github/workflows/checks.yml @@ -1,6 +1,7 @@ name: Apply PEP8, Metadata, and Run Tests on: + push: pull_request_target: jobs: @@ -27,7 +28,7 @@ jobs: pip install -r test/pip_reqs.txt - name: Apply PEP8 run: | - autopep8 --in-place --recursive . + autopep8 --in-place --recursive --max-line-length=100 . - name: Apply Version Metadata run: | python test/auto_apply_version_metadata.py $(git log --pretty=format:'%h' -n 1) diff --git a/index.json b/index.json index 06c80bc0..651e49e7 100644 --- a/index.json +++ b/index.json @@ -3,9 +3,9 @@ "versions": { "0.1.4": { "api_version": 7, - "commit_sha": "41a8fe485", + "commit_sha": "29f531e5", "released_on": "28-08-2022", - "md5sum": "e813cffc24b175fa350b6c0b257ceeab" + "md5sum": "5b3b8b36316ba2ab46aea38416301169" } }, "categories": [ From 21c0d983f74d1a96ecf2e19444f7ee27ffe64ccb Mon Sep 17 00:00:00 2001 From: rikkolovescats Date: Wed, 31 Aug 2022 14:20:11 +0000 Subject: [PATCH 0041/1464] [ci] auto-format --- plugins/minigames.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/minigames.json b/plugins/minigames.json index 19608e3a..c0e19a89 100644 --- a/plugins/minigames.json +++ b/plugins/minigames.json @@ -23,4 +23,4 @@ } } } -} +} \ No newline at end of file From 793cf9b40ca56f623aca39062f67ed6138745d8e Mon Sep 17 00:00:00 2001 From: Rikko Date: Wed, 31 Aug 2022 20:48:22 +0530 Subject: [PATCH 0042/1464] Apply diff commits for formatting and versioning --- .github/workflows/checks.yml | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/.github/workflows/checks.yml b/.github/workflows/checks.yml index 606202fa..5b8f9216 100644 --- a/.github/workflows/checks.yml +++ b/.github/workflows/checks.yml @@ -26,16 +26,21 @@ jobs: python -m pip install --upgrade pip pip install autopep8 pip install -r test/pip_reqs.txt - - name: Apply PEP8 + - name: Apply AutoPEP8 run: | autopep8 --in-place --recursive --max-line-length=100 . + - name: Apply Auto-Formatting Commit + uses: stefanzweifel/git-auto-commit-action@v4 + with: + commit_message: "[ci] auto-format" + branch: ${{ github.head_ref }} - name: Apply Version Metadata run: | python test/auto_apply_version_metadata.py $(git log --pretty=format:'%h' -n 1) - - name: Apply Commit + - name: Apply Version Metadata Commit uses: stefanzweifel/git-auto-commit-action@v4 with: - commit_message: "[ci] auto-format" + commit_message: "[ci] apply-version-metadata" branch: ${{ github.head_ref }} - name: Execute Tests run: | From fb054b023764a255de38b7779e07037e5733ad28 Mon Sep 17 00:00:00 2001 From: Freaku17 <92618708+Freaku17@users.noreply.github.com> Date: Wed, 31 Aug 2022 20:20:53 +0530 Subject: [PATCH 0043/1464] Adding VolleyBall --- plugins/minigames/VolleyBall.py | 781 ++++++++++++++++++++++++++++++++ 1 file changed, 781 insertions(+) create mode 100644 plugins/minigames/VolleyBall.py diff --git a/plugins/minigames/VolleyBall.py b/plugins/minigames/VolleyBall.py new file mode 100644 index 00000000..7606d451 --- /dev/null +++ b/plugins/minigames/VolleyBall.py @@ -0,0 +1,781 @@ +# Volley Ball (final) + +# Made by your friend: Freaku / @[Just] Freak#4999 + + + + +# Join BCS: +# https://discord.gg/ucyaesh + + + + +# My GitHub: +# https://github.com/Freaku17/BombSquad-Mods-byFreaku + + + + +# CHANGELOG: +""" +## 2021 +- Fixed Puck's mass/size/positions/texture/effects +- Fixed Goal positions +- Better center wall +- Added 1 more map +- Added more customisable options +- Map lights locators are now looped (thus reducing the size of the file and lengthy work...) +- Merged map & minigame in one file +- Puck spawns according to scored team +- Also puck now spawns in airrr +- Server support added :) +- Fixed **LOTS** of errors/bugs + +## 2022 +- Code cleanup +- No longer requires a plugin +- More accurate Goal positions +""" + + + + + + + + + + +# ba_meta require api 7 + +from __future__ import annotations + +from typing import TYPE_CHECKING + +import _ba, ba, random +from bastd.actor.playerspaz import PlayerSpaz +from bastd.actor.scoreboard import Scoreboard +from bastd.actor.powerupbox import PowerupBoxFactory +from bastd.actor.bomb import BombFactory +from bastd.gameutils import SharedObjects + +if TYPE_CHECKING: + from typing import Any, Sequence, Dict, Type, List, Optional, Union + + + +class PuckDiedMessage: + """Inform something that a puck has died.""" + + def __init__(self, puck: Puck): + self.puck = puck + + +class Puck(ba.Actor): + def __init__(self, position: Sequence[float] = (0.0, 1.0, 0.0)): + super().__init__() + shared = SharedObjects.get() + activity = self.getactivity() + + # Spawn just above the provided point. + self._spawn_pos = (position[0], position[1] + 1.05, position[2]) + self.last_players_to_touch: Dict[int, Player] = {} + self.scored = False + assert activity is not None + assert isinstance(activity, VolleyBallGame) + pmats = [shared.object_material, activity.puck_material] + self.node = ba.newnode('prop', + delegate=self, + attrs={ + 'model': activity.puck_model, + 'color_texture': activity.puck_tex, + 'body': 'sphere', + 'reflection': 'soft', + 'reflection_scale': [0.2], + 'shadow_size': 0.6, + 'model_scale': 0.4, + 'body_scale': 1.07, + 'is_area_of_interest': True, + 'position': self._spawn_pos, + 'materials': pmats + }) + + # Since it rolls on spawn, lets make gravity + # to 0, and when another node (bomb/spaz) + # touches it. It'll act back as our normie puck! + ba.animate(self.node, 'gravity_scale', {0:-0.1, 0.2:1}, False) + # When other node touches, it realises its new gravity_scale + + + def handlemessage(self, msg: Any) -> Any: + if isinstance(msg, ba.DieMessage): + assert self.node + self.node.delete() + activity = self._activity() + if activity and not msg.immediate: + activity.handlemessage(PuckDiedMessage(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.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 + else: + 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 + + +# ba_meta export game +class VolleyBallGame(ba.TeamGameActivity[Player, Team]): + name = 'Volley Ball' + description = 'Score some goals.\nby \ue048Freaku' + available_settings = [ + ba.IntSetting( + 'Score to Win', + min_value=1, + default=1, + 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', 4.0), + ], + default=1.0, + ), + ba.BoolSetting('Epic Mode', True), + ba.BoolSetting('Night Mode', False), + ba.BoolSetting('Icy Floor', True), + ba.BoolSetting('Disable Punch', False), + ba.BoolSetting('Disable Bombs', False), + ba.BoolSetting('Enable Bottom Credits', True), + ] + 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 ['Open Field', 'Closed Arena'] + + def __init__(self, settings: dict): + super().__init__(settings) + 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.puck_model = ba.getmodel('shield') + self.puck_tex = ba.gettexture('gameCircleIcon') + self._puck_sound = ba.getsound('metalHit') + self.puck_material = ba.Material() + self.puck_material.add_actions(actions=(('modify_part_collision', + 'friction', 0.5))) + self.puck_material.add_actions(conditions=('they_have_material', + shared.pickup_material), + actions=('modify_part_collision', + 'collide', True)) + self.puck_material.add_actions( + conditions=( + ('we_are_younger_than', 100), + 'and', + ('they_have_material', shared.object_material), + ), + actions=('modify_node_collision', 'collide', False), + ) + self.puck_material.add_actions(conditions=('they_have_material', + shared.footing_material), + actions=('impact_sound', + self._puck_sound, 0.2, 5)) + + # Keep track of which player last touched the puck + self.puck_material.add_actions( + conditions=('they_have_material', shared.player_material), + actions=(('call', 'at_connect', + self._handle_puck_player_collide), )) + + # We want the puck to kill powerups; not get stopped by them + self.puck_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.puck_material), + actions=(('modify_part_collision', 'collide', + True), ('modify_part_collision', 'physical', False), + ('call', 'at_connect', self._handle_score))) + + + self._wall_material=ba.Material() + self._fake_wall_material=ba.Material() + self._wall_material.add_actions( + + actions=( + ('modify_part_collision', 'friction', 100000), + )) + self._wall_material.add_actions( + conditions=('they_have_material', shared.pickup_material), + actions=( + ('modify_part_collision', 'collide', False), + )) + + self._wall_material.add_actions( + conditions=(('we_are_younger_than', 100), + 'and', + ('they_have_material',shared.object_material)), + actions=( + ('modify_part_collision', 'collide', False), + )) + self._wall_material.add_actions( + conditions=('they_have_material',shared.footing_material), + actions=( + ('modify_part_collision', 'friction', 9999.5), + )) + self._wall_material.add_actions( + conditions=('they_have_material', BombFactory.get().blast_material), + actions=( + ('modify_part_collision', 'collide', False), + ('modify_part_collision', 'physical', False) + + )) + self._fake_wall_material.add_actions( + conditions=('they_have_material', shared.player_material), + actions=( + ('modify_part_collision', 'collide', True), + ('modify_part_collision', 'physical', True) + + )) + self.blocks=[] + + + self._net_wall_material=ba.Material() + self._net_wall_material.add_actions( + conditions=('they_have_material', shared.player_material), + actions=( + ('modify_part_collision', 'collide', True), + ('modify_part_collision', 'physical', True) + + )) + + self._net_wall_material.add_actions( + conditions=('they_have_material', shared.object_material), + actions=( + ('modify_part_collision', 'collide', True), + )) + self._net_wall_material.add_actions( + conditions=('they_have_material', self.puck_material), + actions=( + ('modify_part_collision', 'collide', True), + )) + self._net_wall_material.add_actions( + conditions=('we_are_older_than', 1), + actions=( + ('modify_part_collision', 'collide', True), + )) + self.net_blocc=[] + + + self._puck_spawn_pos: Optional[Sequence[float]] = None + self._score_regions: Optional[List[ba.NodeActor]] = None + self._puck: Optional[Puck] = None + self._score_to_win = int(settings['Score to Win']) + self._punchie_ = bool(settings['Disable Punch']) + self._night_mode = bool(settings['Night Mode']) + self._bombies_ = bool(settings['Disable Bombs']) + self._time_limit = float(settings['Time Limit']) + self._icy_flooor = bool(settings['Icy Floor']) + self.credit_text = bool(settings['Enable Bottom Credits']) + self._epic_mode = bool(settings['Epic Mode']) + # Base class overrides. + self.slow_motion = self._epic_mode + self.default_music = (ba.MusicType.EPIC if self._epic_mode else + ba.MusicType.TO_THE_DEATH) + + def get_instance_description(self) -> Union[str, Sequence]: + if self._score_to_win == 1: + return 'Score a goal.' + return 'Score ${ARG1} goals.', self._score_to_win + + def get_instance_description_short(self) -> Union[str, Sequence]: + if self._score_to_win == 1: + return 'score a goal' + return 'score ${ARG1} goals', self._score_to_win + + def on_begin(self) -> None: + super().on_begin() + + self.setup_standard_time_limit(self._time_limit) + if self._night_mode: + ba.getactivity().globalsnode.tint = (0.5, 0.7, 1) + self._puck_spawn_pos = self.map.get_flag_position(None) + self._spawn_puck() + + # Set up the two score regions. + self._score_regions = [] + self._score_regions.append( + ba.NodeActor( + ba.newnode('region', + attrs={ + 'position':(5.7, 0, -0.065), + 'scale': (10.7, 0.001, 8), + 'type': 'box', + 'materials': [self._score_region_material] + }))) + self._score_regions.append( + ba.NodeActor( + ba.newnode('region', + attrs={ + 'position':(-5.7, 0, -0.065), + 'scale': (10.7, 0.001, 8), + 'type': 'box', + 'materials': [self._score_region_material] + }))) + self._update_scoreboard() + ba.playsound(self._chant_sound) + import base64 + exec(base64.b64decode("aWYgc2VsZi5jcmVkaXRfdGV4dDoKICAgICMjIFBlb3BsZSBzdGVhbGVkIGNyZWRpdHMgc28gdGhhdHMgd2h5IEkgZW5jb2RlZCB0aGlzLi4uCiAgICAjIyBFdmVuIHRobyB0aGVyZSBpcyBhIG9wdGlvbiwgdGhleSBjaGFuZ2VkIGNyZWF0ZWQgYnkKICAgICMjIGxpa2Ugd3RmIGlzIHRoaWVyIHByb2JsZW0/PwogICAgCiAgICAjIyBBbnl3YXlzIGhhdmUgYSBnb29kIGRheSEKICAgIHQgPSBiYS5uZXdub2RlKCd0ZXh0JywKICAgICAgICAgICAgICAgYXR0cnM9eyAndGV4dCc6IkNyZWF0ZWQgYnkg7oGIRnJlYWt1XG5Wb2xsZXlCYWxsIiwgIyMgRGlzYWJsZSAnRW5hYmxlIEJvdHRvbSBDcmVkaXRzJyB3aGVuIG1ha2luZyBwbGF5bGlzdCwgTm8gbmVlZCB0byBlZGl0IHRoaXMgbG92ZWx5Li4uCiAgICAgICAgJ3NjYWxlJzowLjcsCiAgICAgICAgJ3Bvc2l0aW9uJzooMCwwKSwgI0xldHMgaG9wZSBoZSB1c2VzIFRWIGJvcmRlciBvZiBzZXR0aW5ncz5HcmFwaGljcwogICAgICAgICdzaGFkb3cnOjAuNSwKICAgICAgICAnZmxhdG5lc3MnOjEuMiwKICAgICAgICAnY29sb3InOigxLCAxLCAxKSwKICAgICAgICAnaF9hbGlnbic6J2NlbnRlcicsCiAgICAgICAgJ3ZfYXR0YWNoJzonYm90dG9tJ30p").decode('UTF-8')) + shared = SharedObjects.get() + self.blocks.append(ba.NodeActor(ba.newnode('region',attrs={'position': (0,2.4,0),'scale': (0.8,6,20),'type': 'box','materials': (self._fake_wall_material, )}))) + + self.net_blocc.append(ba.NodeActor(ba.newnode('region',attrs={'position': (0,0,0),'scale': (0.6,2.4,20),'type': 'box','materials': (self._net_wall_material, )}))) + + def on_team_join(self, team: Team) -> None: + self._update_scoreboard() + + def _handle_puck_player_collide(self) -> None: + collision = ba.getcollision() + try: + puck = collision.sourcenode.getdelegate(Puck, True) + player = collision.opposingnode.getdelegate(PlayerSpaz, + True).getplayer( + Player, True) + except ba.NotFoundError: + return + + puck.last_players_to_touch[player.team.id] = player + + def _kill_puck(self) -> None: + self._puck = None + + def _handle_score(self) -> None: + assert self._puck is not None + assert self._score_regions is not None + + # Our puck might stick around for a second or two + # we don't want it to be able to score again. + if self._puck.scored: + return + + region = ba.getcollision().sourcenode + index = 0 + for index in range(len(self._score_regions)): + if region == self._score_regions[index].node: + break + + for team in self.teams: + if team.id == index: + scoring_team = team + team.score += 1 + + + + # Change puck Spawn + if team.id == 0: # left side scored + self._puck_spawn_pos= (5, 0.42, 0) + elif team.id == 1: # right side scored + self._puck_spawn_pos= (-5, 0.42, 0) + else: # normally shouldn't occur + self._puck_spawn_pos= (0, 0.42, 0) + # Easy pizzy + + + 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._puck.last_players_to_touch + and self._puck.last_players_to_touch[scoring_team.id]): + self.stats.player_scored( + self._puck.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() + + ba.playsound(self._foghorn_sound) + ba.playsound(self._cheer_sound) + + self._puck.scored = True + + # Kill the puck (it'll respawn itself shortly). + ba.emitfx(position= ba.getcollision().position, count=int(6.0 + 7.0 * 12), scale=3, spread=0.5, chunk_type='spark') + ba.timer(0.7, self._kill_puck) + + + ba.cameraflash(duration=7.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 on_transition_in(self) -> None: + super().on_transition_in() + activity = ba.getactivity() + if self._icy_flooor: + activity.map.is_hockey = True + + def _update_scoreboard(self) -> None: + winscore = self._score_to_win + for team in self.teams: + self._scoreboard.set_team_value(team, team.score, winscore) + + # overriding the default character spawning.. + def spawn_player(self, player: Player) -> ba.Actor: + spaz = self.spawn_player_spaz(player) + + if self._bombies_: + # We want the button to work, just no bombs... + spaz.bomb_count = 0 + # Imagine not being able to swipe those colorful buttons ;( + + + if self._punchie_: + spaz.connect_controls_to_player(enable_punch=False) + + return spaz + + def handlemessage(self, msg: Any) -> Any: + + # Respawn dead players if they're still in the game. + if isinstance(msg, ba.PlayerDiedMessage): + # Augment standard behavior... + super().handlemessage(msg) + self.respawn_player(msg.getplayer(Player)) + + # Respawn dead pucks. + elif isinstance(msg, PuckDiedMessage): + if not self.has_ended(): + ba.timer(2.2, self._spawn_puck) + else: + super().handlemessage(msg) + + def _flash_puck_spawn(self) -> None: + # Effect >>>>>> Flashly + ba.emitfx(position= self._puck_spawn_pos, count=int(6.0 + 7.0 * 12), scale=1.7, spread=0.4, chunk_type='spark') + + def _spawn_puck(self) -> None: + ba.playsound(self._swipsound) + ba.playsound(self._whistle_sound) + self._flash_puck_spawn() + assert self._puck_spawn_pos is not None + self._puck = Puck(position=self._puck_spawn_pos) + + + + + + + + + + + + + + + + + + + + + + + +class Pointzz: + points, boxes = {}, {} + points['spawn1'] = (-8.03866, 0.02275, 0.0) + (0.5, 0.05, 4.0) + points['spawn2'] = (8.82311, 0.01092, 0.0) + (0.5, 0.05, 4.0) + boxes['area_of_interest_bounds'] = (0.0, 1.18575, 0.43262) + (0, 0, 0) + (29.81803, 11.57249, 18.89134) + boxes['map_bounds'] = (0.0, 1.185751251, 0.4326226188) + (0.0, 0.0, 0.0) + ( + 42.09506485, 22.81173179, 29.76723155) + +class PointzzforH: + points, boxes = {}, {} + boxes['area_of_interest_bounds'] = (0.0, 0.7956858119, 0.0) + (0.0, 0.0, 0.0) + (30.80223883, 0.5961646365, 13.88431707) + boxes['map_bounds'] = (0.0, 0.7956858119, -0.4689020853) + (0.0, 0.0, 0.0) + ( + 35.16182389, 12.18696164, 21.52869693) + points['spawn1'] = (-6.835352227, 0.02305323209, 0.0) + (1.0, 1.0, 3.0) + points['spawn2'] = (6.857415055, 0.03938567998, 0.0) + (1.0, 1.0, 3.0) + + + +class VolleyBallMap(ba.Map): + defs = Pointzz() + name = "Open Field" + + @classmethod + def get_play_types(cls) -> List[str]: + return [] + + @classmethod + def get_preview_texture_name(cls) -> str: + return 'footballStadiumPreview' + + @classmethod + def on_preload(cls) -> Any: + data: Dict[str, Any] = { + 'model': ba.getmodel('footballStadium'), + 'vr_fill_model': ba.getmodel('footballStadiumVRFill'), + 'collide_model': ba.getcollidemodel('footballStadiumCollide'), + 'tex': ba.gettexture('footballStadium') + } + return data + + def __init__(self): + super().__init__() + shared = SharedObjects.get() + x = -5 + while x<5: + self.zone = ba.newnode('locator',attrs={'shape':'circle','position':(0,0,x), + 'color':(1,1,0),'opacity':1,'draw_beauty':True,'additive':False,'size':[0.40]}) + self.zone = ba.newnode('locator',attrs={'shape':'circle','position':(0,.25,x), + 'color':(1,1,0),'opacity':1,'draw_beauty':True,'additive':False,'size':[0.40]}) + self.zone = ba.newnode('locator',attrs={'shape':'circle','position':(0,.5,x), + 'color':(1,1,0),'opacity':1,'draw_beauty':True,'additive':False,'size':[0.40]}) + self.zone = ba.newnode('locator',attrs={'shape':'circle','position':(0,.75,x), + 'color':(1,1,0),'opacity':1,'draw_beauty':True,'additive':False,'size':[0.40]}) + self.zone = ba.newnode('locator',attrs={'shape':'circle','position':(0,1,x), + 'color':(1,1,0),'opacity':1,'draw_beauty':True,'additive':False,'size':[0.40]}) + x = x + 0.5 + + y = -1 + while y>-11: + self.zone = ba.newnode('locator',attrs={'shape':'circle','position':(y,0.01,4), + 'color':(0,0,1),'opacity':1,'draw_beauty':True,'additive':False,'size':[0.40]}) + self.zone = ba.newnode('locator',attrs={'shape':'circle','position':(y,0.01,-4), + 'color':(0,0,1),'opacity':1,'draw_beauty':True,'additive':False,'size':[0.40]}) + self.zone = ba.newnode('locator',attrs={'shape':'circle','position':(-y,0.01,4), + 'color':(1,0,0),'opacity':1,'draw_beauty':True,'additive':False,'size':[0.40]}) + self.zone = ba.newnode('locator',attrs={'shape':'circle','position':(-y,0.01,-4), + 'color':(1,0,0),'opacity':1,'draw_beauty':True,'additive':False,'size':[0.40]}) + y-=1 + + z = 0 + while z<5: + self.zone = ba.newnode('locator',attrs={'shape':'circle','position':(11,0.01,z), + 'color':(1,0,0),'opacity':1,'draw_beauty':True,'additive':False,'size':[0.40]}) + self.zone = ba.newnode('locator',attrs={'shape':'circle','position':(11,0.01,-z), + 'color':(1,0,0),'opacity':1,'draw_beauty':True,'additive':False,'size':[0.40]}) + self.zone = ba.newnode('locator',attrs={'shape':'circle','position':(-11,0.01,z), + 'color':(0,0,1),'opacity':1,'draw_beauty':True,'additive':False,'size':[0.40]}) + self.zone = ba.newnode('locator',attrs={'shape':'circle','position':(-11,0.01,-z), + 'color':(0,0,1),'opacity':1,'draw_beauty':True,'additive':False,'size':[0.40]}) + z+=1 + + self.node = ba.newnode( + 'terrain', + delegate=self, + attrs={ + 'model': self.preloaddata['model'], + 'collide_model': self.preloaddata['collide_model'], + 'color_texture': self.preloaddata['tex'], + 'materials': [shared.footing_material] + }) + ba.newnode('terrain', + attrs={ + 'model': self.preloaddata['vr_fill_model'], + 'lighting': False, + 'vr_only': True, + 'background': True, + 'color_texture': self.preloaddata['tex'] + }) + gnode = ba.getactivity().globalsnode + gnode.tint = (1.3, 1.2, 1.0) + gnode.ambient_color = (1.3, 1.2, 1.0) + gnode.vignette_outer = (0.57, 0.57, 0.57) + gnode.vignette_inner = (0.9, 0.9, 0.9) + gnode.vr_camera_offset = (0, -0.8, -1.1) + gnode.vr_near_clip = 0.5 + + + +class VolleyBallMapH(ba.Map): + defs = PointzzforH() + name = 'Closed Arena' + + @classmethod + def get_play_types(cls) -> List[str]: + return [] + + @classmethod + def get_preview_texture_name(cls) -> str: + return 'hockeyStadiumPreview' + + @classmethod + def on_preload(cls) -> Any: + data: Dict[str, Any] = { + 'models': (ba.getmodel('hockeyStadiumOuter'), + ba.getmodel('hockeyStadiumInner')), + 'vr_fill_model': ba.getmodel('footballStadiumVRFill'), + 'collide_model': ba.getcollidemodel('hockeyStadiumCollide'), + 'tex': ba.gettexture('hockeyStadium'), + } + mat = ba.Material() + mat.add_actions(actions=('modify_part_collision', 'friction', 0.01)) + data['ice_material'] = mat + return data + + def __init__(self) -> None: + super().__init__() + shared = SharedObjects.get() + x = -5 + while x<5: + self.zone = ba.newnode('locator',attrs={'shape':'circle','position':(0,0,x), + 'color':(1,1,0),'opacity':1,'draw_beauty':True,'additive':False,'size':[0.40]}) + self.zone = ba.newnode('locator',attrs={'shape':'circle','position':(0,.25,x), + 'color':(1,1,0),'opacity':1,'draw_beauty':True,'additive':False,'size':[0.40]}) + self.zone = ba.newnode('locator',attrs={'shape':'circle','position':(0,.5,x), + 'color':(1,1,0),'opacity':1,'draw_beauty':True,'additive':False,'size':[0.40]}) + self.zone = ba.newnode('locator',attrs={'shape':'circle','position':(0,.75,x), + 'color':(1,1,0),'opacity':1,'draw_beauty':True,'additive':False,'size':[0.40]}) + self.zone = ba.newnode('locator',attrs={'shape':'circle','position':(0,1,x), + 'color':(1,1,0),'opacity':1,'draw_beauty':True,'additive':False,'size':[0.40]}) + x = x + 0.5 + + y = -1 + while y>-11: + self.zone = ba.newnode('locator',attrs={'shape':'circle','position':(y,0.01,4), + 'color':(0,0,1),'opacity':1,'draw_beauty':True,'additive':False,'size':[0.40]}) + self.zone = ba.newnode('locator',attrs={'shape':'circle','position':(y,0.01,-4), + 'color':(0,0,1),'opacity':1,'draw_beauty':True,'additive':False,'size':[0.40]}) + self.zone = ba.newnode('locator',attrs={'shape':'circle','position':(-y,0.01,4), + 'color':(1,0,0),'opacity':1,'draw_beauty':True,'additive':False,'size':[0.40]}) + self.zone = ba.newnode('locator',attrs={'shape':'circle','position':(-y,0.01,-4), + 'color':(1,0,0),'opacity':1,'draw_beauty':True,'additive':False,'size':[0.40]}) + y-=1 + + z = 0 + while z<5: + self.zone = ba.newnode('locator',attrs={'shape':'circle','position':(11,0.01,z), + 'color':(1,0,0),'opacity':1,'draw_beauty':True,'additive':False,'size':[0.40]}) + self.zone = ba.newnode('locator',attrs={'shape':'circle','position':(11,0.01,-z), + 'color':(1,0,0),'opacity':1,'draw_beauty':True,'additive':False,'size':[0.40]}) + self.zone = ba.newnode('locator',attrs={'shape':'circle','position':(-11,0.01,z), + 'color':(0,0,1),'opacity':1,'draw_beauty':True,'additive':False,'size':[0.40]}) + self.zone = ba.newnode('locator',attrs={'shape':'circle','position':(-11,0.01,-z), + 'color':(0,0,1),'opacity':1,'draw_beauty':True,'additive':False,'size':[0.40]}) + z+=1 + + self.node = ba.newnode('terrain', + delegate=self, + attrs={ + 'model': + None, + 'collide_model': + ba.getcollidemodel('footballStadiumCollide'), # we dont want Goalposts... + 'color_texture': + self.preloaddata['tex'], + 'materials': [ + shared.footing_material] + }) + ba.newnode('terrain', + attrs={ + 'model': self.preloaddata['vr_fill_model'], + 'vr_only': True, + 'lighting': False, + 'background': True, + }) + mats = [shared.footing_material] + self.floor = ba.newnode('terrain', + attrs={ + 'model': self.preloaddata['models'][1], + 'color_texture': self.preloaddata['tex'], + 'opacity': 0.92, + 'opacity_in_low_or_medium_quality': 1.0, + 'materials': mats, + 'color': (0.4,0.9,0) + }) + + self.background = ba.newnode( + 'terrain', + attrs={ + 'model': ba.getmodel('natureBackground'), + 'lighting': False, + 'background': True, + 'color': (0.5,0.30,0.4) + }) + + gnode = ba.getactivity().globalsnode + gnode.floor_reflection = True + gnode.debris_friction = 0.3 + gnode.debris_kill_height = -0.3 + gnode.tint = (1.2, 1.3, 1.33) + gnode.ambient_color = (1.15, 1.25, 1.6) + gnode.vignette_outer = (0.66, 0.67, 0.73) + gnode.vignette_inner = (0.93, 0.93, 0.95) + gnode.vr_camera_offset = (0, -0.8, -1.1) + gnode.vr_near_clip = 0.5 + #self.is_hockey = True + + + + +ba._map.register_map(VolleyBallMap) +ba._map.register_map(VolleyBallMapH) From 263f39c0102fa1e363adc7c1d6fbc77d77e500f5 Mon Sep 17 00:00:00 2001 From: Freaku17 <92618708+Freaku17@users.noreply.github.com> Date: Wed, 31 Aug 2022 20:29:15 +0530 Subject: [PATCH 0044/1464] Updating minigames.json --- plugins/minigames.json | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/plugins/minigames.json b/plugins/minigames.json index c0e19a89..6714c8f1 100644 --- a/plugins/minigames.json +++ b/plugins/minigames.json @@ -21,6 +21,21 @@ "md5sum": "f4f0bb91f5d10cf8f591ecf7d2848182" } } + }, + "VolleyBall": { + "description": "Play VolleyBall in teams of two", + "external_url": "", + "authors": [ + { + "name": "Freaku", + "email": "", + "discord": "[Just] Freak#4999" + } + ], + "versions": { + "1.1.0": null + } + } } } } \ No newline at end of file From 4662ab49723879e12cc1e58f4a104b0b6ab7fdd9 Mon Sep 17 00:00:00 2001 From: Freaku17 <92618708+Freaku17@users.noreply.github.com> Date: Wed, 31 Aug 2022 20:36:48 +0530 Subject: [PATCH 0045/1464] Fixing json error --- plugins/minigames.json | 1 - 1 file changed, 1 deletion(-) diff --git a/plugins/minigames.json b/plugins/minigames.json index 6714c8f1..303c1471 100644 --- a/plugins/minigames.json +++ b/plugins/minigames.json @@ -34,7 +34,6 @@ ], "versions": { "1.1.0": null - } } } } From 423502b140cccd7d74a537c8e1707b3d8d3c6e56 Mon Sep 17 00:00:00 2001 From: Rikko Date: Wed, 31 Aug 2022 21:05:53 +0530 Subject: [PATCH 0046/1464] Prefer snake_case naming --- plugins/minigames.json | 6 +++--- plugins/minigames/{VolleyBall.py => volleyball.py} | 0 2 files changed, 3 insertions(+), 3 deletions(-) rename plugins/minigames/{VolleyBall.py => volleyball.py} (100%) diff --git a/plugins/minigames.json b/plugins/minigames.json index 303c1471..d6537d39 100644 --- a/plugins/minigames.json +++ b/plugins/minigames.json @@ -22,8 +22,8 @@ } } }, - "VolleyBall": { - "description": "Play VolleyBall in teams of two", + "volleyball": { + "description": "Play Volleyball in teams of two", "external_url": "", "authors": [ { @@ -37,4 +37,4 @@ } } } -} \ No newline at end of file +} diff --git a/plugins/minigames/VolleyBall.py b/plugins/minigames/volleyball.py similarity index 100% rename from plugins/minigames/VolleyBall.py rename to plugins/minigames/volleyball.py From 0553bb9ecf37fc62c631c0f1b7ec9458748b7534 Mon Sep 17 00:00:00 2001 From: rikkolovescats Date: Wed, 31 Aug 2022 15:36:27 +0000 Subject: [PATCH 0047/1464] [ci] auto-format --- plugins/minigames/volleyball.py | 262 ++++++++++++++------------------ 1 file changed, 112 insertions(+), 150 deletions(-) diff --git a/plugins/minigames/volleyball.py b/plugins/minigames/volleyball.py index 7606d451..5d8907a4 100644 --- a/plugins/minigames/volleyball.py +++ b/plugins/minigames/volleyball.py @@ -3,20 +3,14 @@ # Made by your friend: Freaku / @[Just] Freak#4999 - - # Join BCS: # https://discord.gg/ucyaesh - - # My GitHub: # https://github.com/Freaku17/BombSquad-Mods-byFreaku - - # CHANGELOG: """ ## 2021 @@ -39,21 +33,15 @@ """ - - - - - - - - # ba_meta require api 7 from __future__ import annotations from typing import TYPE_CHECKING -import _ba, ba, random +import _ba +import ba +import random from bastd.actor.playerspaz import PlayerSpaz from bastd.actor.scoreboard import Scoreboard from bastd.actor.powerupbox import PowerupBoxFactory @@ -64,7 +52,6 @@ from typing import Any, Sequence, Dict, Type, List, Optional, Union - class PuckDiedMessage: """Inform something that a puck has died.""" @@ -100,14 +87,13 @@ def __init__(self, position: Sequence[float] = (0.0, 1.0, 0.0)): 'position': self._spawn_pos, 'materials': pmats }) - + # Since it rolls on spawn, lets make gravity # to 0, and when another node (bomb/spaz) # touches it. It'll act back as our normie puck! - ba.animate(self.node, 'gravity_scale', {0:-0.1, 0.2:1}, False) + ba.animate(self.node, 'gravity_scale', {0: -0.1, 0.2: 1}, False) # When other node touches, it realises its new gravity_scale - def handlemessage(self, msg: Any) -> Any: if isinstance(msg, ba.DieMessage): assert self.node @@ -148,6 +134,7 @@ class Player(ba.Player['Team']): class Team(ba.Team[Player]): """Our team type for this game.""" + def __init__(self) -> None: self.score = 0 @@ -253,15 +240,14 @@ def __init__(self, settings: dict): actions=(('modify_part_collision', 'collide', True), ('modify_part_collision', 'physical', False), ('call', 'at_connect', self._handle_score))) - - - self._wall_material=ba.Material() - self._fake_wall_material=ba.Material() + + self._wall_material = ba.Material() + self._fake_wall_material = ba.Material() self._wall_material.add_actions( - + actions=( ('modify_part_collision', 'friction', 100000), - )) + )) self._wall_material.add_actions( conditions=('they_have_material', shared.pickup_material), actions=( @@ -270,13 +256,13 @@ def __init__(self, settings: dict): self._wall_material.add_actions( conditions=(('we_are_younger_than', 100), - 'and', - ('they_have_material',shared.object_material)), + 'and', + ('they_have_material', shared.object_material)), actions=( ('modify_part_collision', 'collide', False), )) self._wall_material.add_actions( - conditions=('they_have_material',shared.footing_material), + conditions=('they_have_material', shared.footing_material), actions=( ('modify_part_collision', 'friction', 9999.5), )) @@ -285,25 +271,24 @@ def __init__(self, settings: dict): actions=( ('modify_part_collision', 'collide', False), ('modify_part_collision', 'physical', False) - + )) self._fake_wall_material.add_actions( conditions=('they_have_material', shared.player_material), actions=( ('modify_part_collision', 'collide', True), ('modify_part_collision', 'physical', True) - - )) - self.blocks=[] + )) + self.blocks = [] - self._net_wall_material=ba.Material() + self._net_wall_material = ba.Material() self._net_wall_material.add_actions( conditions=('they_have_material', shared.player_material), actions=( ('modify_part_collision', 'collide', True), ('modify_part_collision', 'physical', True) - + )) self._net_wall_material.add_actions( @@ -321,8 +306,7 @@ def __init__(self, settings: dict): actions=( ('modify_part_collision', 'collide', True), )) - self.net_blocc=[] - + self.net_blocc = [] self._puck_spawn_pos: Optional[Sequence[float]] = None self._score_regions: Optional[List[ba.NodeActor]] = None @@ -365,7 +349,7 @@ def on_begin(self) -> None: ba.NodeActor( ba.newnode('region', attrs={ - 'position':(5.7, 0, -0.065), + 'position': (5.7, 0, -0.065), 'scale': (10.7, 0.001, 8), 'type': 'box', 'materials': [self._score_region_material] @@ -374,7 +358,7 @@ def on_begin(self) -> None: ba.NodeActor( ba.newnode('region', attrs={ - 'position':(-5.7, 0, -0.065), + 'position': (-5.7, 0, -0.065), 'scale': (10.7, 0.001, 8), 'type': 'box', 'materials': [self._score_region_material] @@ -384,9 +368,11 @@ def on_begin(self) -> None: import base64 exec(base64.b64decode("aWYgc2VsZi5jcmVkaXRfdGV4dDoKICAgICMjIFBlb3BsZSBzdGVhbGVkIGNyZWRpdHMgc28gdGhhdHMgd2h5IEkgZW5jb2RlZCB0aGlzLi4uCiAgICAjIyBFdmVuIHRobyB0aGVyZSBpcyBhIG9wdGlvbiwgdGhleSBjaGFuZ2VkIGNyZWF0ZWQgYnkKICAgICMjIGxpa2Ugd3RmIGlzIHRoaWVyIHByb2JsZW0/PwogICAgCiAgICAjIyBBbnl3YXlzIGhhdmUgYSBnb29kIGRheSEKICAgIHQgPSBiYS5uZXdub2RlKCd0ZXh0JywKICAgICAgICAgICAgICAgYXR0cnM9eyAndGV4dCc6IkNyZWF0ZWQgYnkg7oGIRnJlYWt1XG5Wb2xsZXlCYWxsIiwgIyMgRGlzYWJsZSAnRW5hYmxlIEJvdHRvbSBDcmVkaXRzJyB3aGVuIG1ha2luZyBwbGF5bGlzdCwgTm8gbmVlZCB0byBlZGl0IHRoaXMgbG92ZWx5Li4uCiAgICAgICAgJ3NjYWxlJzowLjcsCiAgICAgICAgJ3Bvc2l0aW9uJzooMCwwKSwgI0xldHMgaG9wZSBoZSB1c2VzIFRWIGJvcmRlciBvZiBzZXR0aW5ncz5HcmFwaGljcwogICAgICAgICdzaGFkb3cnOjAuNSwKICAgICAgICAnZmxhdG5lc3MnOjEuMiwKICAgICAgICAnY29sb3InOigxLCAxLCAxKSwKICAgICAgICAnaF9hbGlnbic6J2NlbnRlcicsCiAgICAgICAgJ3ZfYXR0YWNoJzonYm90dG9tJ30p").decode('UTF-8')) shared = SharedObjects.get() - self.blocks.append(ba.NodeActor(ba.newnode('region',attrs={'position': (0,2.4,0),'scale': (0.8,6,20),'type': 'box','materials': (self._fake_wall_material, )}))) - - self.net_blocc.append(ba.NodeActor(ba.newnode('region',attrs={'position': (0,0,0),'scale': (0.6,2.4,20),'type': 'box','materials': (self._net_wall_material, )}))) + self.blocks.append(ba.NodeActor(ba.newnode('region', attrs={'position': (0, 2.4, 0), 'scale': ( + 0.8, 6, 20), 'type': 'box', 'materials': (self._fake_wall_material, )}))) + + self.net_blocc.append(ba.NodeActor(ba.newnode('region', attrs={'position': (0, 0, 0), 'scale': ( + 0.6, 2.4, 20), 'type': 'box', 'materials': (self._net_wall_material, )}))) def on_team_join(self, team: Team) -> None: self._update_scoreboard() @@ -426,18 +412,15 @@ def _handle_score(self) -> None: scoring_team = team team.score += 1 - - # Change puck Spawn - if team.id == 0: # left side scored - self._puck_spawn_pos= (5, 0.42, 0) - elif team.id == 1: # right side scored - self._puck_spawn_pos= (-5, 0.42, 0) - else: # normally shouldn't occur - self._puck_spawn_pos= (0, 0.42, 0) + if team.id == 0: # left side scored + self._puck_spawn_pos = (5, 0.42, 0) + elif team.id == 1: # right side scored + self._puck_spawn_pos = (-5, 0.42, 0) + else: # normally shouldn't occur + self._puck_spawn_pos = (0, 0.42, 0) # Easy pizzy - - + for player in team.players: if player.actor: player.actor.handlemessage(ba.CelebrateMessage(2.0)) @@ -461,10 +444,10 @@ def _handle_score(self) -> None: self._puck.scored = True # Kill the puck (it'll respawn itself shortly). - ba.emitfx(position= ba.getcollision().position, count=int(6.0 + 7.0 * 12), scale=3, spread=0.5, chunk_type='spark') + ba.emitfx(position=ba.getcollision().position, count=int( + 6.0 + 7.0 * 12), scale=3, spread=0.5, chunk_type='spark') ba.timer(0.7, self._kill_puck) - ba.cameraflash(duration=7.0) self._update_scoreboard() @@ -494,7 +477,6 @@ def spawn_player(self, player: Player) -> ba.Actor: spaz.bomb_count = 0 # Imagine not being able to swipe those colorful buttons ;( - if self._punchie_: spaz.connect_controls_to_player(enable_punch=False) @@ -517,7 +499,8 @@ def handlemessage(self, msg: Any) -> Any: def _flash_puck_spawn(self) -> None: # Effect >>>>>> Flashly - ba.emitfx(position= self._puck_spawn_pos, count=int(6.0 + 7.0 * 12), scale=1.7, spread=0.4, chunk_type='spark') + ba.emitfx(position=self._puck_spawn_pos, count=int( + 6.0 + 7.0 * 12), scale=1.7, spread=0.4, chunk_type='spark') def _spawn_puck(self) -> None: ba.playsound(self._swipsound) @@ -527,45 +510,26 @@ def _spawn_puck(self) -> None: self._puck = Puck(position=self._puck_spawn_pos) - - - - - - - - - - - - - - - - - - - - - class Pointzz: points, boxes = {}, {} points['spawn1'] = (-8.03866, 0.02275, 0.0) + (0.5, 0.05, 4.0) points['spawn2'] = (8.82311, 0.01092, 0.0) + (0.5, 0.05, 4.0) - boxes['area_of_interest_bounds'] = (0.0, 1.18575, 0.43262) + (0, 0, 0) + (29.81803, 11.57249, 18.89134) + boxes['area_of_interest_bounds'] = (0.0, 1.18575, 0.43262) + \ + (0, 0, 0) + (29.81803, 11.57249, 18.89134) boxes['map_bounds'] = (0.0, 1.185751251, 0.4326226188) + (0.0, 0.0, 0.0) + ( - 42.09506485, 22.81173179, 29.76723155) + 42.09506485, 22.81173179, 29.76723155) + class PointzzforH: points, boxes = {}, {} - boxes['area_of_interest_bounds'] = (0.0, 0.7956858119, 0.0) + (0.0, 0.0, 0.0) + (30.80223883, 0.5961646365, 13.88431707) + boxes['area_of_interest_bounds'] = (0.0, 0.7956858119, 0.0) + \ + (0.0, 0.0, 0.0) + (30.80223883, 0.5961646365, 13.88431707) boxes['map_bounds'] = (0.0, 0.7956858119, -0.4689020853) + (0.0, 0.0, 0.0) + ( - 35.16182389, 12.18696164, 21.52869693) + 35.16182389, 12.18696164, 21.52869693) points['spawn1'] = (-6.835352227, 0.02305323209, 0.0) + (1.0, 1.0, 3.0) points['spawn2'] = (6.857415055, 0.03938567998, 0.0) + (1.0, 1.0, 3.0) - class VolleyBallMap(ba.Map): defs = Pointzz() name = "Open Field" @@ -587,47 +551,47 @@ def on_preload(cls) -> Any: 'tex': ba.gettexture('footballStadium') } return data - + def __init__(self): super().__init__() shared = SharedObjects.get() x = -5 - while x<5: - self.zone = ba.newnode('locator',attrs={'shape':'circle','position':(0,0,x), - 'color':(1,1,0),'opacity':1,'draw_beauty':True,'additive':False,'size':[0.40]}) - self.zone = ba.newnode('locator',attrs={'shape':'circle','position':(0,.25,x), - 'color':(1,1,0),'opacity':1,'draw_beauty':True,'additive':False,'size':[0.40]}) - self.zone = ba.newnode('locator',attrs={'shape':'circle','position':(0,.5,x), - 'color':(1,1,0),'opacity':1,'draw_beauty':True,'additive':False,'size':[0.40]}) - self.zone = ba.newnode('locator',attrs={'shape':'circle','position':(0,.75,x), - 'color':(1,1,0),'opacity':1,'draw_beauty':True,'additive':False,'size':[0.40]}) - self.zone = ba.newnode('locator',attrs={'shape':'circle','position':(0,1,x), - 'color':(1,1,0),'opacity':1,'draw_beauty':True,'additive':False,'size':[0.40]}) + while x < 5: + self.zone = ba.newnode('locator', attrs={'shape': 'circle', 'position': (0, 0, x), + 'color': (1, 1, 0), 'opacity': 1, 'draw_beauty': True, 'additive': False, 'size': [0.40]}) + self.zone = ba.newnode('locator', attrs={'shape': 'circle', 'position': (0, .25, x), + 'color': (1, 1, 0), 'opacity': 1, 'draw_beauty': True, 'additive': False, 'size': [0.40]}) + self.zone = ba.newnode('locator', attrs={'shape': 'circle', 'position': (0, .5, x), + 'color': (1, 1, 0), 'opacity': 1, 'draw_beauty': True, 'additive': False, 'size': [0.40]}) + self.zone = ba.newnode('locator', attrs={'shape': 'circle', 'position': (0, .75, x), + 'color': (1, 1, 0), 'opacity': 1, 'draw_beauty': True, 'additive': False, 'size': [0.40]}) + self.zone = ba.newnode('locator', attrs={'shape': 'circle', 'position': (0, 1, x), + 'color': (1, 1, 0), 'opacity': 1, 'draw_beauty': True, 'additive': False, 'size': [0.40]}) x = x + 0.5 y = -1 - while y>-11: - self.zone = ba.newnode('locator',attrs={'shape':'circle','position':(y,0.01,4), - 'color':(0,0,1),'opacity':1,'draw_beauty':True,'additive':False,'size':[0.40]}) - self.zone = ba.newnode('locator',attrs={'shape':'circle','position':(y,0.01,-4), - 'color':(0,0,1),'opacity':1,'draw_beauty':True,'additive':False,'size':[0.40]}) - self.zone = ba.newnode('locator',attrs={'shape':'circle','position':(-y,0.01,4), - 'color':(1,0,0),'opacity':1,'draw_beauty':True,'additive':False,'size':[0.40]}) - self.zone = ba.newnode('locator',attrs={'shape':'circle','position':(-y,0.01,-4), - 'color':(1,0,0),'opacity':1,'draw_beauty':True,'additive':False,'size':[0.40]}) - y-=1 + while y > -11: + self.zone = ba.newnode('locator', attrs={'shape': 'circle', 'position': (y, 0.01, 4), + 'color': (0, 0, 1), 'opacity': 1, 'draw_beauty': True, 'additive': False, 'size': [0.40]}) + self.zone = ba.newnode('locator', attrs={'shape': 'circle', 'position': (y, 0.01, -4), + 'color': (0, 0, 1), 'opacity': 1, 'draw_beauty': True, 'additive': False, 'size': [0.40]}) + self.zone = ba.newnode('locator', attrs={'shape': 'circle', 'position': (-y, 0.01, 4), + 'color': (1, 0, 0), 'opacity': 1, 'draw_beauty': True, 'additive': False, 'size': [0.40]}) + self.zone = ba.newnode('locator', attrs={'shape': 'circle', 'position': (-y, 0.01, -4), + 'color': (1, 0, 0), 'opacity': 1, 'draw_beauty': True, 'additive': False, 'size': [0.40]}) + y -= 1 z = 0 - while z<5: - self.zone = ba.newnode('locator',attrs={'shape':'circle','position':(11,0.01,z), - 'color':(1,0,0),'opacity':1,'draw_beauty':True,'additive':False,'size':[0.40]}) - self.zone = ba.newnode('locator',attrs={'shape':'circle','position':(11,0.01,-z), - 'color':(1,0,0),'opacity':1,'draw_beauty':True,'additive':False,'size':[0.40]}) - self.zone = ba.newnode('locator',attrs={'shape':'circle','position':(-11,0.01,z), - 'color':(0,0,1),'opacity':1,'draw_beauty':True,'additive':False,'size':[0.40]}) - self.zone = ba.newnode('locator',attrs={'shape':'circle','position':(-11,0.01,-z), - 'color':(0,0,1),'opacity':1,'draw_beauty':True,'additive':False,'size':[0.40]}) - z+=1 + while z < 5: + self.zone = ba.newnode('locator', attrs={'shape': 'circle', 'position': (11, 0.01, z), + 'color': (1, 0, 0), 'opacity': 1, 'draw_beauty': True, 'additive': False, 'size': [0.40]}) + self.zone = ba.newnode('locator', attrs={'shape': 'circle', 'position': (11, 0.01, -z), + 'color': (1, 0, 0), 'opacity': 1, 'draw_beauty': True, 'additive': False, 'size': [0.40]}) + self.zone = ba.newnode('locator', attrs={'shape': 'circle', 'position': (-11, 0.01, z), + 'color': (0, 0, 1), 'opacity': 1, 'draw_beauty': True, 'additive': False, 'size': [0.40]}) + self.zone = ba.newnode('locator', attrs={'shape': 'circle', 'position': (-11, 0.01, -z), + 'color': (0, 0, 1), 'opacity': 1, 'draw_beauty': True, 'additive': False, 'size': [0.40]}) + z += 1 self.node = ba.newnode( 'terrain', @@ -655,7 +619,6 @@ def __init__(self): gnode.vr_near_clip = 0.5 - class VolleyBallMapH(ba.Map): defs = PointzzforH() name = 'Closed Arena' @@ -686,42 +649,42 @@ def __init__(self) -> None: super().__init__() shared = SharedObjects.get() x = -5 - while x<5: - self.zone = ba.newnode('locator',attrs={'shape':'circle','position':(0,0,x), - 'color':(1,1,0),'opacity':1,'draw_beauty':True,'additive':False,'size':[0.40]}) - self.zone = ba.newnode('locator',attrs={'shape':'circle','position':(0,.25,x), - 'color':(1,1,0),'opacity':1,'draw_beauty':True,'additive':False,'size':[0.40]}) - self.zone = ba.newnode('locator',attrs={'shape':'circle','position':(0,.5,x), - 'color':(1,1,0),'opacity':1,'draw_beauty':True,'additive':False,'size':[0.40]}) - self.zone = ba.newnode('locator',attrs={'shape':'circle','position':(0,.75,x), - 'color':(1,1,0),'opacity':1,'draw_beauty':True,'additive':False,'size':[0.40]}) - self.zone = ba.newnode('locator',attrs={'shape':'circle','position':(0,1,x), - 'color':(1,1,0),'opacity':1,'draw_beauty':True,'additive':False,'size':[0.40]}) + while x < 5: + self.zone = ba.newnode('locator', attrs={'shape': 'circle', 'position': (0, 0, x), + 'color': (1, 1, 0), 'opacity': 1, 'draw_beauty': True, 'additive': False, 'size': [0.40]}) + self.zone = ba.newnode('locator', attrs={'shape': 'circle', 'position': (0, .25, x), + 'color': (1, 1, 0), 'opacity': 1, 'draw_beauty': True, 'additive': False, 'size': [0.40]}) + self.zone = ba.newnode('locator', attrs={'shape': 'circle', 'position': (0, .5, x), + 'color': (1, 1, 0), 'opacity': 1, 'draw_beauty': True, 'additive': False, 'size': [0.40]}) + self.zone = ba.newnode('locator', attrs={'shape': 'circle', 'position': (0, .75, x), + 'color': (1, 1, 0), 'opacity': 1, 'draw_beauty': True, 'additive': False, 'size': [0.40]}) + self.zone = ba.newnode('locator', attrs={'shape': 'circle', 'position': (0, 1, x), + 'color': (1, 1, 0), 'opacity': 1, 'draw_beauty': True, 'additive': False, 'size': [0.40]}) x = x + 0.5 y = -1 - while y>-11: - self.zone = ba.newnode('locator',attrs={'shape':'circle','position':(y,0.01,4), - 'color':(0,0,1),'opacity':1,'draw_beauty':True,'additive':False,'size':[0.40]}) - self.zone = ba.newnode('locator',attrs={'shape':'circle','position':(y,0.01,-4), - 'color':(0,0,1),'opacity':1,'draw_beauty':True,'additive':False,'size':[0.40]}) - self.zone = ba.newnode('locator',attrs={'shape':'circle','position':(-y,0.01,4), - 'color':(1,0,0),'opacity':1,'draw_beauty':True,'additive':False,'size':[0.40]}) - self.zone = ba.newnode('locator',attrs={'shape':'circle','position':(-y,0.01,-4), - 'color':(1,0,0),'opacity':1,'draw_beauty':True,'additive':False,'size':[0.40]}) - y-=1 + while y > -11: + self.zone = ba.newnode('locator', attrs={'shape': 'circle', 'position': (y, 0.01, 4), + 'color': (0, 0, 1), 'opacity': 1, 'draw_beauty': True, 'additive': False, 'size': [0.40]}) + self.zone = ba.newnode('locator', attrs={'shape': 'circle', 'position': (y, 0.01, -4), + 'color': (0, 0, 1), 'opacity': 1, 'draw_beauty': True, 'additive': False, 'size': [0.40]}) + self.zone = ba.newnode('locator', attrs={'shape': 'circle', 'position': (-y, 0.01, 4), + 'color': (1, 0, 0), 'opacity': 1, 'draw_beauty': True, 'additive': False, 'size': [0.40]}) + self.zone = ba.newnode('locator', attrs={'shape': 'circle', 'position': (-y, 0.01, -4), + 'color': (1, 0, 0), 'opacity': 1, 'draw_beauty': True, 'additive': False, 'size': [0.40]}) + y -= 1 z = 0 - while z<5: - self.zone = ba.newnode('locator',attrs={'shape':'circle','position':(11,0.01,z), - 'color':(1,0,0),'opacity':1,'draw_beauty':True,'additive':False,'size':[0.40]}) - self.zone = ba.newnode('locator',attrs={'shape':'circle','position':(11,0.01,-z), - 'color':(1,0,0),'opacity':1,'draw_beauty':True,'additive':False,'size':[0.40]}) - self.zone = ba.newnode('locator',attrs={'shape':'circle','position':(-11,0.01,z), - 'color':(0,0,1),'opacity':1,'draw_beauty':True,'additive':False,'size':[0.40]}) - self.zone = ba.newnode('locator',attrs={'shape':'circle','position':(-11,0.01,-z), - 'color':(0,0,1),'opacity':1,'draw_beauty':True,'additive':False,'size':[0.40]}) - z+=1 + while z < 5: + self.zone = ba.newnode('locator', attrs={'shape': 'circle', 'position': (11, 0.01, z), + 'color': (1, 0, 0), 'opacity': 1, 'draw_beauty': True, 'additive': False, 'size': [0.40]}) + self.zone = ba.newnode('locator', attrs={'shape': 'circle', 'position': (11, 0.01, -z), + 'color': (1, 0, 0), 'opacity': 1, 'draw_beauty': True, 'additive': False, 'size': [0.40]}) + self.zone = ba.newnode('locator', attrs={'shape': 'circle', 'position': (-11, 0.01, z), + 'color': (0, 0, 1), 'opacity': 1, 'draw_beauty': True, 'additive': False, 'size': [0.40]}) + self.zone = ba.newnode('locator', attrs={'shape': 'circle', 'position': (-11, 0.01, -z), + 'color': (0, 0, 1), 'opacity': 1, 'draw_beauty': True, 'additive': False, 'size': [0.40]}) + z += 1 self.node = ba.newnode('terrain', delegate=self, @@ -729,7 +692,8 @@ def __init__(self) -> None: 'model': None, 'collide_model': - ba.getcollidemodel('footballStadiumCollide'), # we dont want Goalposts... + # we dont want Goalposts... + ba.getcollidemodel('footballStadiumCollide'), 'color_texture': self.preloaddata['tex'], 'materials': [ @@ -750,7 +714,7 @@ def __init__(self) -> None: 'opacity': 0.92, 'opacity_in_low_or_medium_quality': 1.0, 'materials': mats, - 'color': (0.4,0.9,0) + 'color': (0.4, 0.9, 0) }) self.background = ba.newnode( @@ -759,7 +723,7 @@ def __init__(self) -> None: 'model': ba.getmodel('natureBackground'), 'lighting': False, 'background': True, - 'color': (0.5,0.30,0.4) + 'color': (0.5, 0.30, 0.4) }) gnode = ba.getactivity().globalsnode @@ -775,7 +739,5 @@ def __init__(self) -> None: #self.is_hockey = True - - ba._map.register_map(VolleyBallMap) ba._map.register_map(VolleyBallMapH) From c3d07bfad850f4e1cc3ce4a6721b3ed45162f1e8 Mon Sep 17 00:00:00 2001 From: rikkolovescats Date: Wed, 31 Aug 2022 15:36:28 +0000 Subject: [PATCH 0048/1464] [ci] apply-version-metadata --- plugins/minigames.json | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/plugins/minigames.json b/plugins/minigames.json index d6537d39..8cf72882 100644 --- a/plugins/minigames.json +++ b/plugins/minigames.json @@ -33,8 +33,13 @@ } ], "versions": { - "1.1.0": null + "1.1.0": { + "api_version": 7, + "commit_sha": "0553bb9", + "released_on": "31-08-2022", + "md5sum": "9cd1416e086597684ceb17a5712791b1" + } } } } -} +} \ No newline at end of file From d4b248b0cc16dfdc302085dcd2093fa7e6a021c8 Mon Sep 17 00:00:00 2001 From: Rikko Date: Wed, 31 Aug 2022 21:21:50 +0530 Subject: [PATCH 0049/1464] checks.yml -> ci.yml --- .github/workflows/{checks.yml => ci.yml} | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) rename .github/workflows/{checks.yml => ci.yml} (97%) diff --git a/.github/workflows/checks.yml b/.github/workflows/ci.yml similarity index 97% rename from .github/workflows/checks.yml rename to .github/workflows/ci.yml index 5b8f9216..6c2f7c47 100644 --- a/.github/workflows/checks.yml +++ b/.github/workflows/ci.yml @@ -1,4 +1,4 @@ -name: Apply PEP8, Metadata, and Run Tests +name: CI on: push: From ff2c586e7db40b1f8740fbce10a0973b16044110 Mon Sep 17 00:00:00 2001 From: Rikko Date: Wed, 31 Aug 2022 21:23:10 +0530 Subject: [PATCH 0050/1464] Update CI badge for current workflow --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index f1f2445e..d26a107e 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -[![GitHub Workflow Status](https://img.shields.io/github/workflow/status/bombsquad-community/plugin-manager/Flake8)](https://github.com/bombsquad-community/plugin-manager/actions) +[![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 From 4178c28edf7212bd69820d682db4cd50ffd9b4f9 Mon Sep 17 00:00:00 2001 From: Rikko Date: Wed, 31 Aug 2022 21:24:09 +0530 Subject: [PATCH 0051/1464] Run tests in verbose mode --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index d26a107e..95e07725 100644 --- a/README.md +++ b/README.md @@ -66,7 +66,7 @@ $ pip install -r test/pip_reqs.txt and then executing the following in the project's root directory: ```bash -$ python -m unittest discover +$ python -m unittest discover -v ``` ## License From ccdc259a03fbe2be9d2f5fed12705f8cdf8a510e Mon Sep 17 00:00:00 2001 From: Rikko Date: Wed, 31 Aug 2022 21:26:12 +0530 Subject: [PATCH 0052/1464] Rename a workflow step --- .github/workflows/ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 6c2f7c47..776889ec 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -29,7 +29,7 @@ jobs: - name: Apply AutoPEP8 run: | autopep8 --in-place --recursive --max-line-length=100 . - - name: Apply Auto-Formatting Commit + - name: Apply AutoPEP8 Commit uses: stefanzweifel/git-auto-commit-action@v4 with: commit_message: "[ci] auto-format" From 18faa2274be24fbd066294bc3cf8555acf7326ca Mon Sep 17 00:00:00 2001 From: Rikko Date: Wed, 31 Aug 2022 22:05:56 +0530 Subject: [PATCH 0053/1464] Add examples for submitting and updating plugins --- README.md | 103 ++++++++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 101 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 95e07725..6f9e1c86 100644 --- a/README.md +++ b/README.md @@ -29,6 +29,7 @@ A plugin manager for the game - [Bombsquad](https://www.froemling.net/apps/bombs ## Contributing ### Submitting a Plugin + - In order for a plugin to get accepted to this official repository, it must target the general game audience and be completely open and readable, not be encoded or encrypted in any form. - If your plugin doesn't target the general game audience, you can put your plugins in a GitHub repository and then @@ -36,17 +37,115 @@ A plugin manager for the game - [Bombsquad](https://www.froemling.net/apps/bombs See [3rd party plugin sources](#3rd-party-plugin-sources) for more information. - New plugins are accepted through a [pull request](../../compare). Add your plugin in the minigames, utilities, or the category directory you feel is the most relevant to the type of plugin you're submitting, [here](plugins). - Then add an entry to the category's JSON metadata file (check out existing entries to know what all fields are required). - Plugin manager will also show and execute the settings icon if your `ba.Plugin` export class has a method named + Then add an entry to the category's JSON metadata file. +- Plugin manager will also show and execute the settings icon if your `ba.Plugin` export class has a method named `on_plugin_manager_prompt`; check out the [colorscheme](https://github.com/bombsquad-community/plugin-manager/blob/f24f0ca5ded427f6041795021f1af2e6a08b6ce9/plugins/utilities/colorscheme.py#L419-L420) plugin for an example and it's behaviour when the settings icon is tapped on via the plugin manager in-game. +#### Example: + +Let's say you wanna submit this new utility-type plugin named as `sample_plugin.py`: +```python +# ba_meta require api 7 +import ba + +# ba_meta export plugin +class Main(ba.Plugin): + def on_app_running(self): + ba.screenmessage("Hi! I am a sample plugin!") + + def on_plugin_manager_prompt(self): + ba.screenmessage("You tapped my settings from the Plugin Manager Window!") +``` + +You'll have to fork this repository and add your `sample_plugin.py` plugin file into the appropriate directory, which for +utility plugins is [plugins/utilities](plugins/utilities). Now you'll have to add an entry for your plugin +in [plugins/utilities.json](plugins/utilities.json) so that it gets picked up by the Plugin Manager in-game. + +To do this, you'll have to edit the file and add something like this: +```json +{ + "name": "Utilities", + ... + "plugins": { + ... + "sample_plugin": { + "description": "Shows screenmessages!", + "external_url": "", + "authors": [ + { + "name": "Alex", + "email": "alex@example.com", + "discord": null + } + ], + "versions": { + "1.0.0": null + } + }, + ... + } + ... +} +``` +You can add whatever you wanna add to these fields. However, leave the value for your version key `null`: +```json +"1.0.0": null +``` +Version values will automatically be populated through github-actions (along with formatting your code as per PEP8 style +guide) once you open a pull request. + +Save `utilities.json` with your modified changes and now you can make us a [pull request](../../compare) with the +plugin you've added and the modified JSON metadata file! + ### Updating a Plugin + - Make a [pull request](../../compare) with whatever changes you'd like to make to an existing plugin, and add a new version entry in your plugin category's JSON metadata file. +#### Example + +Continuing the example from [Submitting a Plugin](#submitting-a-plugin) section, say you also wanna add a new screenmessage +to the `sample.py` plugin after it was submitted. Edit `sample.py` with whatever changes you'd like: +```diff +diff --git a/bla.py b/bla.py +index ebb7dcc..da2b312 100644 +--- a/plugins/utilities/sample.py ++++ b/plugins/utilities/sample.py +@@ -5,6 +5,7 @@ import ba + class Main(ba.Plugin): + def on_app_running(self): + ba.screenmessage("Hi! I am a sample plugin!") ++ ba.screenmessage("Hey! This is my new screenmessage!") + + def on_plugin_manager_prompt(self): + ba.screenmessage("You tapped my settings from the Plugin Manager Window!") +``` + +To name this new version as `1.1.0`, add `"1.1.0": null,` just above the previous plugin version in `utilities.json`: +```diff +diff --git a/bla.json b/bla.json +index d3fd5bc..34ce9ad 100644 +--- a/plugins/utilities.json ++++ b/plugins/utilities.json +@@ -14,7 +14,10 @@ + } + ], + "versions": { +- "1.0.0": null ++ "1.1.0": null, ++ "1.0.0": { ++ ... ++ } + } + }, + ... +``` +That's it! Now you can make a [pull request](../../compare) with both the updated `sample.py` and `utilities.json` files. + ## 3rd Party Plugin Sources + - In case your plugin doesn't sit well with our guidelines or you wouldn't want your plugin to be here for some reason, you can create your own GitHub repository and put all your plugins in there. - Check out https://github.com/rikkolovescats/sahilp-plugins for an example. You can choose to show up plugins from this From 3cf044a097a0a10244ca0a71ce6ccc114c90dee7 Mon Sep 17 00:00:00 2001 From: Rikko Date: Wed, 31 Aug 2022 22:07:59 +0530 Subject: [PATCH 0054/1464] Update diff examples headers --- README.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 6f9e1c86..81e97b18 100644 --- a/README.md +++ b/README.md @@ -89,7 +89,7 @@ To do this, you'll have to edit the file and add something like this: ... } ``` -You can add whatever you wanna add to these fields. However, leave the value for your version key `null`: +You can add whatever you wanna add to these fields. However, leave the value for your version key as `null`: ```json "1.0.0": null ``` @@ -109,7 +109,7 @@ plugin you've added and the modified JSON metadata file! Continuing the example from [Submitting a Plugin](#submitting-a-plugin) section, say you also wanna add a new screenmessage to the `sample.py` plugin after it was submitted. Edit `sample.py` with whatever changes you'd like: ```diff -diff --git a/bla.py b/bla.py +diff --git a/plugins/utilities/sample.py b/plugins/utilities/sample.py index ebb7dcc..da2b312 100644 --- a/plugins/utilities/sample.py +++ b/plugins/utilities/sample.py @@ -125,7 +125,7 @@ index ebb7dcc..da2b312 100644 To name this new version as `1.1.0`, add `"1.1.0": null,` just above the previous plugin version in `utilities.json`: ```diff -diff --git a/bla.json b/bla.json +diff --git a/plugins/utilities.json b/plugins/utilities.json index d3fd5bc..34ce9ad 100644 --- a/plugins/utilities.json +++ b/plugins/utilities.json From f1b484af8762ac4d38fd9d8457bdfac145d73686 Mon Sep 17 00:00:00 2001 From: Rikko Date: Wed, 31 Aug 2022 22:16:54 +0530 Subject: [PATCH 0055/1464] Make sample_plugin.py consistent everywhere --- README.md | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index 81e97b18..994509f5 100644 --- a/README.md +++ b/README.md @@ -107,12 +107,12 @@ plugin you've added and the modified JSON metadata file! #### Example Continuing the example from [Submitting a Plugin](#submitting-a-plugin) section, say you also wanna add a new screenmessage -to the `sample.py` plugin after it was submitted. Edit `sample.py` with whatever changes you'd like: +to the `sample_plugin.py` plugin after it was submitted. Edit `sample_plugin.py` with whatever changes you'd like: ```diff -diff --git a/plugins/utilities/sample.py b/plugins/utilities/sample.py +diff --git a/plugins/utilities/sample_plugin.py b/plugins/utilities/sample_plugin.py index ebb7dcc..da2b312 100644 ---- a/plugins/utilities/sample.py -+++ b/plugins/utilities/sample.py +--- a/plugins/utilities/sample_plugin.py ++++ b/plugins/utilities/sample_plugin.py @@ -5,6 +5,7 @@ import ba class Main(ba.Plugin): def on_app_running(self): @@ -142,7 +142,7 @@ index d3fd5bc..34ce9ad 100644 }, ... ``` -That's it! Now you can make a [pull request](../../compare) with both the updated `sample.py` and `utilities.json` files. +That's it! Now you can make a [pull request](../../compare) with both the updated `sample_plugin.py` and `utilities.json` files. ## 3rd Party Plugin Sources From 0fb45f5e657f760bafe8c7fe9242dce5340ed75f Mon Sep 17 00:00:00 2001 From: Freaku17 <92618708+Freaku17@users.noreply.github.com> Date: Wed, 31 Aug 2022 22:51:42 +0530 Subject: [PATCH 0056/1464] Removing encrypted credits in volleyball --- plugins/minigames/volleyball.py | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/plugins/minigames/volleyball.py b/plugins/minigames/volleyball.py index 5d8907a4..c4bae456 100644 --- a/plugins/minigames/volleyball.py +++ b/plugins/minigames/volleyball.py @@ -365,8 +365,16 @@ def on_begin(self) -> None: }))) self._update_scoreboard() ba.playsound(self._chant_sound) - import base64 - exec(base64.b64decode("aWYgc2VsZi5jcmVkaXRfdGV4dDoKICAgICMjIFBlb3BsZSBzdGVhbGVkIGNyZWRpdHMgc28gdGhhdHMgd2h5IEkgZW5jb2RlZCB0aGlzLi4uCiAgICAjIyBFdmVuIHRobyB0aGVyZSBpcyBhIG9wdGlvbiwgdGhleSBjaGFuZ2VkIGNyZWF0ZWQgYnkKICAgICMjIGxpa2Ugd3RmIGlzIHRoaWVyIHByb2JsZW0/PwogICAgCiAgICAjIyBBbnl3YXlzIGhhdmUgYSBnb29kIGRheSEKICAgIHQgPSBiYS5uZXdub2RlKCd0ZXh0JywKICAgICAgICAgICAgICAgYXR0cnM9eyAndGV4dCc6IkNyZWF0ZWQgYnkg7oGIRnJlYWt1XG5Wb2xsZXlCYWxsIiwgIyMgRGlzYWJsZSAnRW5hYmxlIEJvdHRvbSBDcmVkaXRzJyB3aGVuIG1ha2luZyBwbGF5bGlzdCwgTm8gbmVlZCB0byBlZGl0IHRoaXMgbG92ZWx5Li4uCiAgICAgICAgJ3NjYWxlJzowLjcsCiAgICAgICAgJ3Bvc2l0aW9uJzooMCwwKSwgI0xldHMgaG9wZSBoZSB1c2VzIFRWIGJvcmRlciBvZiBzZXR0aW5ncz5HcmFwaGljcwogICAgICAgICdzaGFkb3cnOjAuNSwKICAgICAgICAnZmxhdG5lc3MnOjEuMiwKICAgICAgICAnY29sb3InOigxLCAxLCAxKSwKICAgICAgICAnaF9hbGlnbic6J2NlbnRlcicsCiAgICAgICAgJ3ZfYXR0YWNoJzonYm90dG9tJ30p").decode('UTF-8')) + if self.credit_text: + t = ba.newnode('text', + attrs={ 'text':"Created by Freaku\nVolleyBall", ## Disable 'Enable Bottom Credits' when making playlist, No need to edit this lovely... + 'scale':0.7, + 'position':(0,0), + 'shadow':0.5, + 'flatness':1.2, + 'color':(1, 1, 1), + 'h_align':'center', + 'v_attach':'bottom'}) shared = SharedObjects.get() self.blocks.append(ba.NodeActor(ba.newnode('region', attrs={'position': (0, 2.4, 0), 'scale': ( 0.8, 6, 20), 'type': 'box', 'materials': (self._fake_wall_material, )}))) From 5d2b2bc9dd75db9cd4a8b454f19b3c3e69e771f8 Mon Sep 17 00:00:00 2001 From: Freaku17 Date: Wed, 31 Aug 2022 17:22:04 +0000 Subject: [PATCH 0057/1464] [ci] auto-format --- plugins/minigames/volleyball.py | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/plugins/minigames/volleyball.py b/plugins/minigames/volleyball.py index c4bae456..d4aeacc1 100644 --- a/plugins/minigames/volleyball.py +++ b/plugins/minigames/volleyball.py @@ -367,14 +367,14 @@ def on_begin(self) -> None: ba.playsound(self._chant_sound) if self.credit_text: t = ba.newnode('text', - attrs={ 'text':"Created by Freaku\nVolleyBall", ## Disable 'Enable Bottom Credits' when making playlist, No need to edit this lovely... - 'scale':0.7, - 'position':(0,0), - 'shadow':0.5, - 'flatness':1.2, - 'color':(1, 1, 1), - 'h_align':'center', - 'v_attach':'bottom'}) + attrs={'text': "Created by Freaku\nVolleyBall", # Disable 'Enable Bottom Credits' when making playlist, No need to edit this lovely... + 'scale': 0.7, + 'position': (0, 0), + 'shadow': 0.5, + 'flatness': 1.2, + 'color': (1, 1, 1), + 'h_align': 'center', + 'v_attach': 'bottom'}) shared = SharedObjects.get() self.blocks.append(ba.NodeActor(ba.newnode('region', attrs={'position': (0, 2.4, 0), 'scale': ( 0.8, 6, 20), 'type': 'box', 'materials': (self._fake_wall_material, )}))) From 0bc952246bdbf2f7f245767a9dfe86163067f332 Mon Sep 17 00:00:00 2001 From: Freaku17 <92618708+Freaku17@users.noreply.github.com> Date: Wed, 31 Aug 2022 22:57:04 +0530 Subject: [PATCH 0058/1464] Update minigames.json --- plugins/minigames.json | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/plugins/minigames.json b/plugins/minigames.json index 8cf72882..d6537d39 100644 --- a/plugins/minigames.json +++ b/plugins/minigames.json @@ -33,13 +33,8 @@ } ], "versions": { - "1.1.0": { - "api_version": 7, - "commit_sha": "0553bb9", - "released_on": "31-08-2022", - "md5sum": "9cd1416e086597684ceb17a5712791b1" - } + "1.1.0": null } } } -} \ No newline at end of file +} From efc1bda88754f04473b31f7cbaf5bd686284ffca Mon Sep 17 00:00:00 2001 From: Freaku17 Date: Wed, 31 Aug 2022 17:27:21 +0000 Subject: [PATCH 0059/1464] [ci] apply-version-metadata --- plugins/minigames.json | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/plugins/minigames.json b/plugins/minigames.json index d6537d39..b262ccb6 100644 --- a/plugins/minigames.json +++ b/plugins/minigames.json @@ -33,8 +33,13 @@ } ], "versions": { - "1.1.0": null + "1.1.0": { + "api_version": 7, + "commit_sha": "0bc9522", + "released_on": "31-08-2022", + "md5sum": "a7ad7f1ac908fd871bcbcf665d49828c" + } } } } -} +} \ No newline at end of file From 890fdc03f54c5cea40797e995fe50025f5fa5fef Mon Sep 17 00:00:00 2001 From: Rikko Date: Wed, 31 Aug 2022 23:03:20 +0530 Subject: [PATCH 0060/1464] Try CI without pull request target --- .github/workflows/ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 776889ec..df1b7ba8 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -2,7 +2,7 @@ name: CI on: push: - pull_request_target: + # pull_request_target: jobs: build: From e4c8db44400b5038cfbc15a1f6d493c9ca354760 Mon Sep 17 00:00:00 2001 From: Rikko Date: Wed, 31 Aug 2022 23:11:52 +0530 Subject: [PATCH 0061/1464] Applying updates when installed from workspace --- README.md | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 994509f5..d64d25b0 100644 --- a/README.md +++ b/README.md @@ -21,10 +21,17 @@ A plugin manager for the game - [Bombsquad](https://www.froemling.net/apps/bombs ## Installation -- Either download [plugin_manager.py](https://raw.githubusercontent.com/bombsquad-community/plugin-manager/main/plugin_manager.py) - to your mods directory (check it out by going into your game's Settings -> Advanced -> Show Mods Folder) or directly add - it to your workspace! +There are two different ways the plugin manager can be installed through: +1. Download [plugin_manager.py](https://raw.githubusercontent.com/bombsquad-community/plugin-manager/main/plugin_manager.py) + to your mods directory (check it out by going into your game's Settings -> Advanced -> Show Mods Folder). This is the + recommended way (see below). + +2. A not recommended method is to add + [plugin_manager.py](https://raw.githubusercontent.com/bombsquad-community/plugin-manager/main/plugin_manager.py) + to your workspace. However, plugin manager self-updates will fail when installed it's get installed from workspace + since the game will overrwrite the update with the older version that's on workspace on the next sync up. However, you can + manually apply updates by copying the latest plugin manager's source code again to your workspace when this method. ## Contributing From ac09e8dc6c2abc7d2817bef853e10873bde0c2e7 Mon Sep 17 00:00:00 2001 From: Rikko Date: Thu, 1 Sep 2022 02:07:32 +0530 Subject: [PATCH 0062/1464] Fix some typos --- README.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index d64d25b0..44c02453 100644 --- a/README.md +++ b/README.md @@ -27,11 +27,11 @@ There are two different ways the plugin manager can be installed through: to your mods directory (check it out by going into your game's Settings -> Advanced -> Show Mods Folder). This is the recommended way (see below). -2. A not recommended method is to add +2. Another way is to add [plugin_manager.py](https://raw.githubusercontent.com/bombsquad-community/plugin-manager/main/plugin_manager.py) - to your workspace. However, plugin manager self-updates will fail when installed it's get installed from workspace - since the game will overrwrite the update with the older version that's on workspace on the next sync up. However, you can - manually apply updates by copying the latest plugin manager's source code again to your workspace when this method. + to your workspace. However, plugin manager self-updates will fail when installed using this way since the game + will overrwrite the updated plugin manager, with the older version from workspace on the next sync. However, you can + manually apply updates by copying the latest plugin manager's source code again to your workspace when using this method. ## Contributing From 4a81d280e6957096459ecbf77b63ed32194c39b0 Mon Sep 17 00:00:00 2001 From: Freaku17 <92618708+Freaku17@users.noreply.github.com> Date: Thu, 1 Sep 2022 15:58:50 +0530 Subject: [PATCH 0063/1464] Adding MemoryGame --- plugins/minigames/memory_game.py | 1005 ++++++++++++++++++++++++++++++ 1 file changed, 1005 insertions(+) create mode 100644 plugins/minigames/memory_game.py diff --git a/plugins/minigames/memory_game.py b/plugins/minigames/memory_game.py new file mode 100644 index 00000000..db2297e3 --- /dev/null +++ b/plugins/minigames/memory_game.py @@ -0,0 +1,1005 @@ +from __future__ import annotations + + +## Original creator: byANG3L ## +## Made by: Freaku / @[Just] Freak#4999 ## + +## From: BSWorld Modpack (https://youtu.be/1TN56NLlShE) ## + + +# Used in-game boxes and textures instead of external +# So it will run on server and randoms can play init ._. +# (& some improvements) + + + + + + +# incase someone is wondering how is map floating. Check out +# def spawnAllMap(self) + + + +# ba_meta require api 7 +from typing import TYPE_CHECKING, overload +import _ba,ba,random +from bastd.gameutils import SharedObjects +if TYPE_CHECKING: + from typing import Any, Sequence, Optional, List, Dict, Type, Union, Any, Literal + + + + +class OnTimer(ba.Actor): + """Timer which counts but doesn't show on-screen""" + def __init__(self) -> None: + super().__init__() + self._starttime_ms: Optional[int] = None + self.node = ba.newnode('text', attrs={ 'v_attach': 'top', 'h_attach': 'center', 'h_align': 'center', 'color': (1, 1, 0.5, 1), 'flatness': 0.5, 'shadow': 0.5, 'position': (0, -70), 'scale': 0, 'text': ''}) + self.inputnode = ba.newnode('timedisplay', attrs={ 'timemin': 0, 'showsubseconds': True }) + self.inputnode.connectattr('output', self.node, 'text') + def start(self) -> None: + tval = ba.time(timeformat=ba.TimeFormat.MILLISECONDS) + assert isinstance(tval, int) + self._starttime_ms = tval + self.inputnode.time1 = self._starttime_ms + ba.getactivity().globalsnode.connectattr('time', self.inputnode, 'time2') + def has_started(self) -> bool: + return self._starttime_ms is not None + def stop(self, + endtime: Union[int, float] = None, + timeformat: ba.TimeFormat = ba.TimeFormat.SECONDS) -> None: + if endtime is None: + endtime = ba.time(timeformat=ba.TimeFormat.MILLISECONDS) + timeformat = ba.TimeFormat.MILLISECONDS + if self._starttime_ms is None: + print('Warning: OnTimer.stop() called without start() first') + else: + endtime_ms: int + if timeformat is ba.TimeFormat.SECONDS: + endtime_ms = int(endtime * 1000) + elif timeformat is ba.TimeFormat.MILLISECONDS: + assert isinstance(endtime, int) + endtime_ms = endtime + else: + raise ValueError(f'invalid timeformat: {timeformat}') + + self.inputnode.timemax = endtime_ms - self._starttime_ms + # Overloads so type checker knows our exact return type based in args. + @overload + def getstarttime(self, timeformat: Literal[ba.TimeFormat.SECONDS] = ba.TimeFormat.SECONDS) -> float: + ... + @overload + def getstarttime(self, + timeformat: Literal[ba.TimeFormat.MILLISECONDS]) -> int: + ... + def getstarttime( + self, + timeformat: ba.TimeFormat = ba.TimeFormat.SECONDS + ) -> Union[int, float]: + """Return the sim-time when start() was called. + + Time will be returned in seconds if timeformat is SECONDS or + milliseconds if it is MILLISECONDS. + """ + val_ms: Any + if self._starttime_ms is None: + print('WARNING: getstarttime() called on un-started timer') + val_ms = ba.time(timeformat=ba.TimeFormat.MILLISECONDS) + else: + val_ms = self._starttime_ms + assert isinstance(val_ms, int) + if timeformat is ba.TimeFormat.SECONDS: + return 0.001 * val_ms + if timeformat is ba.TimeFormat.MILLISECONDS: + return val_ms + raise ValueError(f'invalid timeformat: {timeformat}') + + @property + def starttime(self) -> float: + """Shortcut for start time in seconds.""" + return self.getstarttime() + + def handlemessage(self, msg: Any) -> Any: + # if we're asked to die, just kill our node/timer + if isinstance(msg, ba.DieMessage): + if self.node: + self.node.delete() + + + + +class Player(ba.Player['Team']): + """Our player type for this game.""" + + def __init__(self) -> None: + super().__init__() + self.death_time: Optional[float] = None + + +class Team(ba.Team[Player]): + """Our team type for this game.""" + + +# ba_meta export game +class MGgame(ba.TeamGameActivity[Player, Team]): + + name = 'Memory Game' + description = 'Memories tiles and survive till the end!' + available_settings = [ba.BoolSetting('Epic Mode', default=False), ba.BoolSetting('Enable Bottom Credits', True)] + scoreconfig = ba.ScoreConfig(label='Survived', scoretype=ba.ScoreType.MILLISECONDS, version='B') + + # Print messages when players die (since its meaningful in this game). + announce_player_deaths = True + + # we're currently hard-coded for one map.. + @classmethod + def get_supported_maps(cls, sessiontype: Type[ba.Session]) -> List[str]: + return ['Sky Tiles'] + + # We support teams, free-for-all, and co-op sessions. + @classmethod + def supports_session_type(cls, sessiontype: Type[ba.Session]) -> bool: + return (issubclass(sessiontype, ba.DualTeamSession) + or issubclass(sessiontype, ba.FreeForAllSession) + or issubclass(sessiontype, ba.CoopSession)) + + def __init__(self, settings: dict): + super().__init__(settings) + + self._epic_mode = settings.get('Epic Mode', False) + self._last_player_death_time: Optional[float] = None + self._timer: Optional[OnTimer] = None + self.credit_text = bool(settings['Enable Bottom Credits']) + + # Some base class overrides: + self.default_music = (ba.MusicType.EPIC + if self._epic_mode else ba.MusicType.SURVIVAL) + if self._epic_mode: + self.slow_motion = True + shared = SharedObjects.get() + self._collide_with_player=ba.Material() + self._collide_with_player.add_actions(actions=(('modify_part_collision', 'collide', True))) + self.dont_collide=ba.Material() + self.dont_collide.add_actions(actions=(('modify_part_collision', 'collide', False))) + self._levelStage = 0 + + self.announcePlayerDeaths = True + self._lastPlayerDeathTime = None + self._spawnCenter = (-3.17358, 2.75764, -2.99124) + + self._mapFGPModel = ba.getmodel('buttonSquareOpaque') + self._mapFGPDefaultTex = ba.gettexture('achievementOffYouGo') + + self._mapFGCurseTex = ba.gettexture('powerupCurse') + self._mapFGHealthTex = ba.gettexture('powerupHealth') + self._mapFGIceTex = ba.gettexture('powerupIceBombs') + self._mapFGImpactTex = ba.gettexture('powerupImpactBombs') + self._mapFGMinesTex = ba.gettexture('powerupLandMines') + self._mapFGPunchTex = ba.gettexture('powerupPunch') + self._mapFGShieldTex = ba.gettexture('powerupShield') + self._mapFGStickyTex = ba.gettexture('powerupStickyBombs') + + self._mapFGSpaz = ba.gettexture('neoSpazIcon') + self._mapFGZoe = ba.gettexture('zoeIcon') + self._mapFGSnake = ba.gettexture('ninjaIcon') + self._mapFGKronk= ba.gettexture('kronkIcon') + self._mapFGMel = ba.gettexture('melIcon') + self._mapFGJack = ba.gettexture('jackIcon') + self._mapFGSanta = ba.gettexture('santaIcon') + self._mapFGFrosty = ba.gettexture('frostyIcon') + self._mapFGBones = ba.gettexture('bonesIcon') + self._mapFGBernard = ba.gettexture('bearIcon') + self._mapFGPascal = ba.gettexture('penguinIcon') + self._mapFGAli = ba.gettexture('aliIcon') + self._mapFGRobot = ba.gettexture('cyborgIcon') + self._mapFGAgent = ba.gettexture('agentIcon') + self._mapFGGrumbledorf = ba.gettexture('wizardIcon') + self._mapFGPixel = ba.gettexture('pixieIcon') + + self._imageTextDefault = ba.gettexture('bg') + self._circleTex = ba.gettexture('circleShadow') + + self._image = ba.newnode('image', + attrs={'texture': self._imageTextDefault, + 'position':(0,-100), + 'scale':(100,100), + 'opacity': 0.0, + 'attach':'topCenter'}) + + self._textCounter = ba.newnode('text', + attrs={'text': '10', + 'position': (0, -100), + 'scale': 2.3, + 'shadow': 1.0, + 'flatness': 1.0, + 'opacity': 0.0, + 'v_attach': 'top', + 'h_attach': 'center', + 'h_align': 'center', + 'v_align': 'center'}) + + self._textLevel = ba.newnode('text', + attrs={'text': 'Level ' + str(self._levelStage), + 'position': (0, -28), + 'scale': 1.3, + 'shadow': 1.0, + 'flatness': 1.0, + 'color': (1.0, 0.0, 1.0), + 'opacity': 0.0, + 'v_attach': 'top', + 'h_attach': 'center', + 'h_align': 'center', + 'v_align': 'center'}) + + self._imageCircle = ba.newnode('image', + attrs={'texture': self._circleTex, + 'position': (75, -75), + 'scale': (20,20), + 'color': (0.2, 0.2, 0.2), + 'opacity': 0.0, + 'attach': 'topCenter'}) + self._imageCircle2 = ba.newnode('image', + attrs={'texture': self._circleTex, + 'position': (75, -100), + 'scale': (20,20), + 'color': (0.2, 0.2, 0.2), + 'opacity': 0.0, + 'attach': 'topCenter'}) + self._imageCircle3 = ba.newnode('image', + attrs={'texture': self._circleTex, + 'position': (75, -125), + 'scale': (20,20), + 'color': (0.2, 0.2, 0.2), + 'opacity': 0.0, + 'attach': 'topCenter'}) + + + def on_transition_in(self) -> None: + super().on_transition_in() + self._bellLow = ba.getsound('bellLow') + self._bellMed = ba.getsound('bellMed') + self._bellHigh = ba.getsound('bellHigh') + self._tickSound = ba.getsound('tick') + self._tickFinal = ba.getsound('powerup01') + self._scoreSound = ba.getsound('score') + + self._image.opacity = 1 + self._textCounter.opacity = 1 + self._textLevel.opacity = 1 + self._imageCircle.opacity = 0.7 + self._imageCircle2.opacity = 0.7 + self._imageCircle3.opacity = 0.7 + + self._levelStage += 1 + + self._textLevel.text = 'Level ' + str(self._levelStage) + + self._image.texture = self._imageTextDefault + + if self._levelStage == 1: + timeStart = 6 + ba.timer(timeStart, self._randomPlatform) + ba.timer(timeStart, self.startCounter) + + def on_begin(self) -> None: + super().on_begin() + + self._timer = OnTimer() + self._timer.start() + + self.coldel = True + self.coldel2 = True + self.coldel3 = True + self.coldel4 = True + self.coldel5 = True + self.coldel6 = True + self.coldel7 = True + self.coldel8 = True + self.coldel9 = True + self.coldel10 = True + self.coldel11 = True + self.coldel12 = True + self.coldel13 = True + self.coldel14 = True + self.coldel15 = True + self.coldel16 = True + if self.credit_text: + t = ba.newnode('text', + attrs={ 'text':"Made by Freaku\nOriginally for 1.4: byANG3L", ## Disable 'Enable Bottom Credits' when making playlist, No need to edit this lovely... + 'scale':0.7, + 'position':(0,0), + 'shadow':0.5, + 'flatness':1.2, + 'color':(1, 1, 1), + 'h_align':'center', + 'v_attach':'bottom'}) + self.spawnAllMap() + self.flashHide() + + # Check for immediate end (if we've only got 1 player, etc). + ba.timer(5, self._check_end_game) + self._dingSound = ba.getsound('dingSmall') + self._dingSoundHigh = ba.getsound('dingSmallHigh') + + def startCounter(self): + self._textCounter.text = '10' + def count9(): + def count8(): + def count7(): + def count6(): + def count5(): + def count4(): + def count3(): + def count2(): + def count1(): + def countFinal(): + self._textCounter.text = '' + ba.playsound(self._tickFinal) + self._stop() + self._textCounter.text = '1' + ba.playsound(self._tickSound) + ba.timer(1, countFinal) + self._textCounter.text = '2' + ba.playsound(self._tickSound) + ba.timer(1, count1) + self._textCounter.text = '3' + ba.playsound(self._tickSound) + ba.timer(1, count2) + self._textCounter.text = '4' + ba.playsound(self._tickSound) + ba.timer(1, count3) + self._textCounter.text = '5' + ba.playsound(self._tickSound) + ba.timer(1, count4) + self._textCounter.text = '6' + ba.playsound(self._tickSound) + ba.timer(1, count5) + self._textCounter.text = '7' + ba.playsound(self._tickSound) + ba.timer(1, count6) + self._textCounter.text = '8' + ba.playsound(self._tickSound) + ba.timer(1, count7) + self._textCounter.text = '9' + ba.playsound(self._tickSound) + ba.timer(1, count8) + ba.timer(1, count9) + + def on_player_join(self, player: Player) -> None: + # Don't allow joining after we start + # (would enable leave/rejoin tomfoolery). + if self.has_begun(): + ba.screenmessage( + ba.Lstr(resource='playerDelayedJoinText', + subs=[('${PLAYER}', player.getname(full=True))]), + color=(0, 1, 0),transient=True,clients=[player.sessionplayer.inputdevice.client_id]) + # For score purposes, mark them as having died right as the + # game started. + assert self._timer is not None + player.death_time = self._timer.getstarttime() + return + self.spawn_player(player) + + def on_player_leave(self, player: Player) -> None: + # Augment default behavior. + super().on_player_leave(player) + + # A departing player may trigger game-over. + self._check_end_game() + + # overriding the default character spawning.. + def spawn_player(self, player: Player) -> ba.Actor: + spaz = self.spawn_player_spaz(player) + pos = (self._spawnCenter[0] + random.uniform(-1.5, 2.5), self._spawnCenter[1], self._spawnCenter[2] + random.uniform(-2.5, 1.5)) + spaz.connect_controls_to_player(enable_punch=False, enable_bomb=False, enable_pickup=False) + spaz.handlemessage(ba.StandMessage(pos)) + return spaz + + def _randomSelect(self): + if self._levelStage == 1: + self._textureSelected = random.choice([self._mapFGMinesTex, + self._mapFGStickyTex]) + self._image.texture = self._textureSelected + elif self._levelStage == 2: + self._textureSelected = random.choice([self._mapFGIceTex, + self._mapFGShieldTex]) + self._image.texture = self._textureSelected + elif self._levelStage in [3,4,5]: + self._textureSelected = random.choice([self._mapFGStickyTex, + self._mapFGIceTex, + self._mapFGImpactTex, + self._mapFGMinesTex]) + self._image.texture = self._textureSelected + elif self._levelStage in [6,7,8,9]: + self._textureSelected = random.choice([self._mapFGCurseTex, + self._mapFGHealthTex, + self._mapFGIceTex, + self._mapFGImpactTex, + self._mapFGMinesTex, + self._mapFGPunchTex, + self._mapFGShieldTex]) + self._image.texture = self._textureSelected + elif self._levelStage >= 10: + self._textureSelected = random.choice([self._mapFGSpaz, + self._mapFGZoe, + self._mapFGSnake, + self._mapFGKronk, + self._mapFGMel, + self._mapFGJack, + self._mapFGSanta, + self._mapFGFrosty, + self._mapFGBones, + self._mapFGBernard, + self._mapFGPascal, + self._mapFGAli, + self._mapFGRobot, + self._mapFGAgent, + self._mapFGGrumbledorf, + self._mapFGPixel]) + self._image.texture = self._textureSelected + return self._textureSelected + + def _stop(self): + self._textureSelected = self._randomSelect() + def circle(): + def circle2(): + def circle3(): + self._imageCircle3.color = (0.0, 1.0, 0.0) + self._imageCircle3.opacity = 1.0 + ba.playsound(self._bellHigh) + ba.timer(0.2, self._doDelete) + self._imageCircle2.color = (1.0, 1.0, 0.0) + self._imageCircle2.opacity = 1.0 + ba.playsound(self._bellMed) + ba.timer(1, circle3) + self._imageCircle.color = (1.0, 0.0, 0.0) + self._imageCircle.opacity = 1.0 + ba.playsound(self._bellLow) + ba.timer(1, circle2) + ba.timer(1, circle) + + def _randomPlatform(self): + if self._levelStage == 1: + randomTexture=[self._mapFGMinesTex, + self._mapFGMinesTex, + self._mapFGMinesTex, + self._mapFGMinesTex, + self._mapFGMinesTex, + self._mapFGMinesTex, + self._mapFGMinesTex, + self._mapFGMinesTex, + self._mapFGStickyTex, + self._mapFGStickyTex, + self._mapFGStickyTex, + self._mapFGStickyTex, + self._mapFGStickyTex, + self._mapFGStickyTex, + self._mapFGStickyTex, + self._mapFGStickyTex] + elif self._levelStage == 2: + randomTexture=[self._mapFGIceTex, + self._mapFGIceTex, + self._mapFGIceTex, + self._mapFGIceTex, + self._mapFGIceTex, + self._mapFGIceTex, + self._mapFGIceTex, + self._mapFGIceTex, + self._mapFGShieldTex, + self._mapFGShieldTex, + self._mapFGShieldTex, + self._mapFGShieldTex, + self._mapFGShieldTex, + self._mapFGShieldTex, + self._mapFGShieldTex, + self._mapFGShieldTex] + elif self._levelStage in [3,4,5]: + randomTexture=[self._mapFGStickyTex, + self._mapFGStickyTex, + self._mapFGStickyTex, + self._mapFGStickyTex, + self._mapFGIceTex, + self._mapFGIceTex, + self._mapFGIceTex, + self._mapFGIceTex, + self._mapFGImpactTex, + self._mapFGImpactTex, + self._mapFGImpactTex, + self._mapFGImpactTex, + self._mapFGMinesTex, + self._mapFGMinesTex, + self._mapFGMinesTex, + self._mapFGMinesTex] + elif self._levelStage in [6,7,8,9]: + randomTexture=[self._mapFGHealthTex, + self._mapFGShieldTex, + self._mapFGCurseTex, + self._mapFGCurseTex, + self._mapFGHealthTex, + self._mapFGHealthTex, + self._mapFGIceTex, + self._mapFGIceTex, + self._mapFGImpactTex, + self._mapFGImpactTex, + self._mapFGMinesTex, + self._mapFGMinesTex, + self._mapFGPunchTex, + self._mapFGPunchTex, + self._mapFGShieldTex, + self._mapFGShieldTex] + elif self._levelStage >= 10: + randomTexture=[self._mapFGSpaz, + self._mapFGZoe, + self._mapFGSnake, + self._mapFGKronk, + self._mapFGMel, + self._mapFGJack, + self._mapFGSanta, + self._mapFGFrosty, + self._mapFGBones, + self._mapFGBernard, + self._mapFGPascal, + self._mapFGAli, + self._mapFGRobot, + self._mapFGAgent, + self._mapFGGrumbledorf, + self._mapFGPixel] + + (self.mapFGPTex, self.mapFGP2Tex, + self.mapFGP3Tex, self.mapFGP4Tex, + self.mapFGP5Tex, self.mapFGP6Tex, + self.mapFGP7Tex, self.mapFGP8Tex, + self.mapFGP9Tex,self.mapFGP10Tex, + self.mapFGP11Tex, self.mapFGP12Tex, + self.mapFGP13Tex, self.mapFGP14Tex, + self.mapFGP15Tex, self.mapFGP16Tex) = ( + random.sample(randomTexture, 16)) + self._mixPlatform() + + def _mixPlatform(self): + ba.timer(1, self.flashShow) + ba.timer(3, self.flashHide) + ba.timer(4, self.flashShow) + ba.timer(6, self.flashHide) + ba.timer(7, self.flashShow) + ba.timer(9, self.flashHide) + ba.timer(13.2, self.flashShow) + + def flashHide(self): + self.mapFGP.color_texture = self._mapFGPDefaultTex + self.mapFGP2.color_texture = self._mapFGPDefaultTex + self.mapFGP3.color_texture = self._mapFGPDefaultTex + self.mapFGP4.color_texture = self._mapFGPDefaultTex + self.mapFGP5.color_texture = self._mapFGPDefaultTex + self.mapFGP6.color_texture = self._mapFGPDefaultTex + self.mapFGP7.color_texture = self._mapFGPDefaultTex + self.mapFGP8.color_texture = self._mapFGPDefaultTex + self.mapFGP9.color_texture = self._mapFGPDefaultTex + self.mapFGP10.color_texture = self._mapFGPDefaultTex + self.mapFGP11.color_texture = self._mapFGPDefaultTex + self.mapFGP12.color_texture = self._mapFGPDefaultTex + self.mapFGP13.color_texture = self._mapFGPDefaultTex + self.mapFGP14.color_texture = self._mapFGPDefaultTex + self.mapFGP15.color_texture = self._mapFGPDefaultTex + self.mapFGP16.color_texture = self._mapFGPDefaultTex + + def flashShow(self): + self.mapFGP.color_texture = self.mapFGPTex + self.mapFGP2.color_texture = self.mapFGP2Tex + self.mapFGP3.color_texture = self.mapFGP3Tex + self.mapFGP4.color_texture = self.mapFGP4Tex + self.mapFGP5.color_texture = self.mapFGP5Tex + self.mapFGP6.color_texture = self.mapFGP6Tex + self.mapFGP7.color_texture = self.mapFGP7Tex + self.mapFGP8.color_texture = self.mapFGP8Tex + self.mapFGP9.color_texture = self.mapFGP9Tex + self.mapFGP10.color_texture = self.mapFGP10Tex + self.mapFGP11.color_texture = self.mapFGP11Tex + self.mapFGP12.color_texture = self.mapFGP12Tex + self.mapFGP13.color_texture = self.mapFGP13Tex + self.mapFGP14.color_texture = self.mapFGP14Tex + self.mapFGP15.color_texture = self.mapFGP15Tex + self.mapFGP16.color_texture = self.mapFGP16Tex + + def _doDelete(self): + if not self.mapFGPTex == self._textureSelected: + self.mapFGP.delete() + self.mapFGPcol.delete() + self.coldel = True + if not self.mapFGP2Tex == self._textureSelected: + self.mapFGP2.delete() + self.mapFGP2col.delete() + self.coldel2 = True + if not self.mapFGP3Tex == self._textureSelected: + self.mapFGP3.delete() + self.mapFGP3col.delete() + self.coldel3 = True + if not self.mapFGP4Tex == self._textureSelected: + self.mapFGP4.delete() + self.mapFGP4col.delete() + self.coldel4 = True + if not self.mapFGP5Tex == self._textureSelected: + self.mapFGP5.delete() + self.mapFGP5col.delete() + self.coldel5 = True + if not self.mapFGP6Tex == self._textureSelected: + self.mapFGP6.delete() + self.mapFGP6col.delete() + self.coldel6 = True + if not self.mapFGP7Tex == self._textureSelected: + self.mapFGP7.delete() + self.mapFGP7col.delete() + self.coldel7 = True + if not self.mapFGP8Tex == self._textureSelected: + self.mapFGP8.delete() + self.mapFGP8col.delete() + self.coldel8 = True + if not self.mapFGP9Tex == self._textureSelected: + self.mapFGP9.delete() + self.mapFGP9col.delete() + self.coldel9 = True + if not self.mapFGP10Tex == self._textureSelected: + self.mapFGP10.delete() + self.mapFGP10col.delete() + self.coldel10 = True + if not self.mapFGP11Tex == self._textureSelected: + self.mapFGP11.delete() + self.mapFGP11col.delete() + self.coldel11 = True + if not self.mapFGP12Tex == self._textureSelected: + self.mapFGP12.delete() + self.mapFGP12col.delete() + self.coldel12 = True + if not self.mapFGP13Tex == self._textureSelected: + self.mapFGP13.delete() + self.mapFGP13col.delete() + self.coldel13 = True + if not self.mapFGP14Tex == self._textureSelected: + self.mapFGP14.delete() + self.mapFGP14col.delete() + self.coldel14 = True + if not self.mapFGP15Tex == self._textureSelected: + self.mapFGP15.delete() + self.mapFGP15col.delete() + self.coldel15 = True + if not self.mapFGP16Tex == self._textureSelected: + self.mapFGP16.delete() + self.mapFGP16col.delete() + self.coldel16 = True + + ba.timer(3.3, self._platformTexDefault) + + def spawnAllMap(self): + """ + # Here's how it works: + # First, create prop with a gravity scale of 0 + # Then use a in-game model which will suit it (For this one I didn't chose box, since it will look kinda weird) Right? + # Instead I used a 2d model (which is nothing but a button in menu) + # This prop SHOULD NOT collide with anything, since it has gravity_scale of 0 if it'll get weight it will fall down :(( + # These are where we change those color-textures and is seen in-game + + # Now lets talk about the actual node on which we stand (sadly no-one realises it exists) + # A moment of silence for this node... + + # Alright, so this is a region node (the one used in hockey/football for scoring) + # Thanksfully these are just thicc boxes positioned on the map (so they are not moved neither they have gravity_scale) + # So we create this region node and place it to the same position of our prop node + # and give it collide_with_player and footing materials + # Thats it, now you have your own floating platforms :D + """ + shared = SharedObjects.get() + if self.coldel: + self.mapFGP = ba.newnode('prop', + attrs={'body': 'puck', 'position': (3,2,-9), 'model': self._mapFGPModel, 'model_scale': 3.8, 'body_scale': 3.8, 'shadow_size': 0.5, 'gravity_scale':0.0, 'color_texture': self._mapFGPDefaultTex, 'reflection': 'soft', 'reflection_scale': [1.0], 'is_area_of_interest': True, 'materials': [self.dont_collide]}) + self.mapFGPTex = None + self.mapFGPcol = ba.newnode('region',attrs={'position': (3,2,-9),'scale': (3.5,0.1,3.5),'type': 'box','materials': (self._collide_with_player, shared.footing_material)}) + self.coldel = False + + if self.coldel2: + self.mapFGP2 = ba.newnode('prop', + attrs={'body': 'puck', 'position': (3,2,-6), 'model': self._mapFGPModel, 'model_scale': 3.8, 'body_scale': 3.8, 'shadow_size': 0.5, 'gravity_scale':0.0, 'color_texture': self._mapFGPDefaultTex, 'reflection': 'soft', 'reflection_scale': [1.0], 'is_area_of_interest': True, 'materials': [self.dont_collide]}) + self.mapFGP2Tex = None + self.mapFGP2col = ba.newnode('region',attrs={'position': (3,2,-6),'scale': (3.5,0.1,3.5),'type': 'box','materials': (self._collide_with_player, shared.footing_material)}) + self.coldel2 = False + + if self.coldel3: + self.mapFGP3 = ba.newnode('prop', + attrs={'body': 'puck', 'position': (3,2,-3), 'model': self._mapFGPModel, 'model_scale': 3.8, 'body_scale': 3.8, 'shadow_size': 0.5, 'gravity_scale':0.0, 'color_texture': self._mapFGPDefaultTex, 'reflection': 'soft', 'reflection_scale': [1.0], 'is_area_of_interest': True, 'materials': [self.dont_collide]}) + self.mapFGP3Tex = None + self.mapFGP3col = ba.newnode('region',attrs={'position': (3,2,-3),'scale': (3.5,0.1,3.5),'type': 'box','materials': (self._collide_with_player, shared.footing_material)}) + self.coldel3 = False + + if self.coldel4: + self.mapFGP4 = ba.newnode('prop', + attrs={'body': 'puck', 'position': (3,2,0), 'model': self._mapFGPModel, 'model_scale': 3.8, 'body_scale': 3.8, 'shadow_size': 0.5, 'gravity_scale':0.0, 'color_texture': self._mapFGPDefaultTex, 'reflection': 'soft', 'reflection_scale': [1.0], 'is_area_of_interest': True, 'materials': [self.dont_collide]}) + self.mapFGP4Tex = None + self.mapFGP4col = ba.newnode('region',attrs={'position': (3,2,0),'scale': (3.5,0.1,3.5),'type': 'box','materials': (self._collide_with_player, shared.footing_material)}) + self.coldel4 = False + + if self.coldel5: + self.mapFGP5 = ba.newnode('prop', + attrs={'body': 'puck', 'position': (0,2,-9), 'model': self._mapFGPModel, 'model_scale': 3.8, 'body_scale': 3.8, 'shadow_size': 0.5, 'gravity_scale':0.0, 'color_texture': self._mapFGPDefaultTex, 'reflection': 'soft', 'reflection_scale': [1.0], 'is_area_of_interest': True, 'materials': [self.dont_collide]}) + self.mapFGP5Tex = None + self.mapFGP5col = ba.newnode('region',attrs={'position': (0,2,-9),'scale': (3.5,0.1,3.5),'type': 'box','materials': (self._collide_with_player, shared.footing_material)}) + self.coldel5 = False + + if self.coldel6: + self.mapFGP6 = ba.newnode('prop', + attrs={'body': 'puck', 'position': (0,2,-6), 'model': self._mapFGPModel, 'model_scale': 3.8, 'body_scale': 3.8, 'shadow_size': 0.5, 'gravity_scale':0.0, 'color_texture': self._mapFGPDefaultTex, 'reflection': 'soft', 'reflection_scale': [1.0], 'is_area_of_interest': True, 'materials': [self.dont_collide]}) + self.mapFGP6Tex = None + self.mapFGP6col = ba.newnode('region',attrs={'position': (0,2,-6),'scale': (3.5,0.1,3.5),'type': 'box','materials': (self._collide_with_player, shared.footing_material)}) + self.coldel6 = False + + if self.coldel7: + self.mapFGP7 = ba.newnode('prop', + attrs={'body': 'puck', 'position': (0,2,-3), 'model': self._mapFGPModel, 'model_scale': 3.8, 'body_scale': 3.8, 'shadow_size': 0.5, 'gravity_scale':0.0, 'color_texture': self._mapFGPDefaultTex, 'reflection': 'soft', 'reflection_scale': [1.0], 'is_area_of_interest': True, 'materials': [self.dont_collide]}) + self.mapFGP7Tex = None + self.mapFGP7col = ba.newnode('region',attrs={'position': (0,2,-3),'scale': (3.5,0.1,3.5),'type': 'box','materials': (self._collide_with_player, shared.footing_material)}) + self.coldel7 = False + + if self.coldel8: + self.mapFGP8 = ba.newnode('prop', + attrs={'body': 'puck', 'position': (0,2,0), 'model': self._mapFGPModel, 'model_scale': 3.8, 'body_scale': 3.8, 'shadow_size': 0.5, 'gravity_scale':0.0, 'color_texture': self._mapFGPDefaultTex, 'reflection': 'soft', 'reflection_scale': [1.0], 'is_area_of_interest': True, 'materials': [self.dont_collide]}) + self.mapFGP8Tex = None + self.mapFGP8col = ba.newnode('region',attrs={'position': (0,2,0),'scale': (3.5,0.1,3.5),'type': 'box','materials': (self._collide_with_player, shared.footing_material)}) + self.coldel8 = False + + if self.coldel9: + self.mapFGP9 = ba.newnode('prop', + attrs={'body': 'puck', 'position': (-3,2,-9), 'model': self._mapFGPModel, 'model_scale': 3.8, 'body_scale': 3.8, 'shadow_size': 0.5, 'gravity_scale':0.0, 'color_texture': self._mapFGPDefaultTex, 'reflection': 'soft', 'reflection_scale': [1.0], 'is_area_of_interest': True, 'materials': [self.dont_collide]}) + self.mapFGP9Tex = None + self.mapFGP9col = ba.newnode('region',attrs={'position': (-3,2,-9),'scale': (3.5,0.1,3.5),'type': 'box','materials': (self._collide_with_player, shared.footing_material)}) + self.coldel9 = False + + if self.coldel10: + self.mapFGP10 = ba.newnode('prop', + attrs={'body': 'puck', 'position': (-3,2,-6), 'model': self._mapFGPModel, 'model_scale': 3.8, 'body_scale': 3.8, 'shadow_size': 0.5, 'gravity_scale':0.0, 'color_texture': self._mapFGPDefaultTex, 'reflection': 'soft', 'reflection_scale': [1.0], 'is_area_of_interest': True, 'materials': [self.dont_collide]}) + self.mapFGP10Tex = None + self.mapFGP10col = ba.newnode('region',attrs={'position': (-3,2,-6),'scale': (3.5,0.1,3.5),'type': 'box','materials': (self._collide_with_player, shared.footing_material)}) + self.coldel10 = False + + if self.coldel11: + self.mapFGP11 = ba.newnode('prop', + attrs={'body': 'puck', 'position': (-3,2,-3), 'model': self._mapFGPModel, 'model_scale': 3.8, 'body_scale': 3.8, 'shadow_size': 0.5, 'gravity_scale':0.0, 'color_texture': self._mapFGPDefaultTex, 'reflection': 'soft', 'reflection_scale': [1.0], 'is_area_of_interest': True, 'materials': [self.dont_collide]}) + self.mapFGP11Tex = None + self.mapFGP11col = ba.newnode('region',attrs={'position': (-3,2,-3),'scale': (3.5,0.1,3.5),'type': 'box','materials': (self._collide_with_player, shared.footing_material)}) + self.coldel11 = False + + if self.coldel12: + self.mapFGP12 = ba.newnode('prop', + attrs={'body': 'puck', 'position': (-3,2,0), 'model': self._mapFGPModel, 'model_scale': 3.8, 'body_scale': 3.8, 'shadow_size': 0.5, 'gravity_scale':0.0, 'color_texture': self._mapFGPDefaultTex, 'reflection': 'soft', 'reflection_scale': [1.0], 'is_area_of_interest': True, 'materials': [self.dont_collide]}) + self.mapFGP12Tex = None + self.mapFGP12col = ba.newnode('region',attrs={'position': (-3,2,0),'scale': (3.5,0.1,3.5),'type': 'box','materials': (self._collide_with_player, shared.footing_material)}) + self.coldel12 = False + + if self.coldel13: + self.mapFGP13 = ba.newnode('prop', + attrs={'body': 'puck', 'position': (-6,2,-9), 'model': self._mapFGPModel, 'model_scale': 3.8, 'body_scale': 3.8, 'shadow_size': 0.5, 'gravity_scale':0.0, 'color_texture': self._mapFGPDefaultTex, 'reflection': 'soft', 'reflection_scale': [1.0], 'is_area_of_interest': True, 'materials': [self.dont_collide]}) + self.mapFGP13Tex = None + self.mapFGP13col = ba.newnode('region',attrs={'position': (-6,2,-9),'scale': (3.5,0.1,3.5),'type': 'box','materials': (self._collide_with_player, shared.footing_material)}) + self.coldel13 = False + + if self.coldel14: + self.mapFGP14 = ba.newnode('prop', + attrs={'body': 'puck', 'position': (-6,2,-6), 'model': self._mapFGPModel, 'model_scale': 3.8, 'body_scale': 3.8, 'shadow_size': 0.5, 'gravity_scale':0.0, 'color_texture': self._mapFGPDefaultTex, 'reflection': 'soft', 'reflection_scale': [1.0], 'is_area_of_interest': True, 'materials': [self.dont_collide]}) + self.mapFGP14Tex = None + self.mapFGP14col = ba.newnode('region',attrs={'position': (-6,2,-6),'scale': (3.5,0.1,3.5),'type': 'box','materials': (self._collide_with_player, shared.footing_material)}) + self.coldel14 = False + + if self.coldel15: + self.mapFGP15 = ba.newnode('prop', + attrs={'body': 'puck', 'position': (-6,2,-3), 'model': self._mapFGPModel, 'model_scale': 3.8, 'body_scale': 3.8, 'shadow_size': 0.5, 'gravity_scale':0.0, 'color_texture': self._mapFGPDefaultTex, 'reflection': 'soft', 'reflection_scale': [1.0], 'is_area_of_interest': True, 'materials': [self.dont_collide]}) + self.mapFGP15Tex = None + self.mapFGP15col = ba.newnode('region',attrs={'position': (-6,2,-3),'scale': (3.5,0.1,3.5),'type': 'box','materials': (self._collide_with_player, shared.footing_material)}) + self.coldel15 = False + + if self.coldel16: + self.mapFGP16 = ba.newnode('prop', + attrs={'body': 'puck', 'position': (-6,2,0), 'model': self._mapFGPModel, 'model_scale': 3.8, 'body_scale': 3.8, 'shadow_size': 0.5, 'gravity_scale':0.0, 'color_texture': self._mapFGPDefaultTex, 'reflection': 'soft', 'reflection_scale': [1.0], 'is_area_of_interest': True, 'materials': [self.dont_collide]}) + self.mapFGP16Tex = None + self.mapFGP16col = ba.newnode('region',attrs={'position': (-6,2,0),'scale': (3.5,0.1,3.5),'type': 'box','materials': (self._collide_with_player, shared.footing_material)}) + self.coldel16 = False + + def _platformTexDefault(self): + self._textureSelected = None + + self._imageCircle.color = (0.2, 0.2, 0.2) + self._imageCircle.opacity = 0.7 + self._imageCircle2.color = (0.2, 0.2, 0.2) + self._imageCircle2.opacity = 0.7 + self._imageCircle3.color = (0.2, 0.2, 0.2) + self._imageCircle3.opacity = 0.7 + + self._levelStage += 1 + + self._textLevel.text = 'Level ' + str(self._levelStage) + + self._image.texture = self._imageTextDefault + + if self._levelStage == 1: + timeStart = 6 + else: + timeStart = 2 + ba.playsound(self._scoreSound) + activity = _ba.get_foreground_host_activity() + for i in activity.players: + try: + i.actor.node.handlemessage(ba.CelebrateMessage(2.0)) + except: + pass + ba.timer(timeStart, self._randomPlatform) + ba.timer(timeStart, self.startCounter) + + self.spawnAllMap() + self.flashHide() + + # Various high-level game events come through this method. + def handlemessage(self, msg: Any) -> Any: + if isinstance(msg, ba.PlayerDiedMessage): + + # Augment standard behavior. + super().handlemessage(msg) + + curtime = ba.time() + + # Record the player's moment of death. + # assert isinstance(msg.spaz.player + msg.getplayer(Player).death_time = curtime + + # In co-op mode, end the game the instant everyone dies + # (more accurate looking). + # In teams/ffa, allow a one-second fudge-factor so we can + # get more draws if players die basically at the same time. + if isinstance(self.session, ba.CoopSession): + # Teams will still show up if we check now.. check in + # the next cycle. + ba.pushcall(self._check_end_game) + + # Also record this for a final setting of the clock. + self._last_player_death_time = curtime + else: + ba.timer(1.0, self._check_end_game) + else: + # Default handler: + return super().handlemessage(msg) + return None + + def _check_end_game(self) -> None: + living_team_count = 0 + for team in self.teams: + for player in team.players: + if player.is_alive(): + living_team_count += 1 + break + + # In co-op, we go till everyone is dead.. otherwise we go + # until one team remains. + if isinstance(self.session, ba.CoopSession): + if living_team_count <= 0: + self.end_game() + else: + if living_team_count <= 1: + self.end_game() + + + def end_game(self) -> None: + cur_time = ba.time() + assert self._timer is not None + start_time = self._timer.getstarttime() + + # Mark death-time as now for any still-living players + # and award players points for how long they lasted. + # (these per-player scores are only meaningful in team-games) + for team in self.teams: + for player in team.players: + survived = False + + # Throw an extra fudge factor in so teams that + # didn't die come out ahead of teams that did. + if player.death_time is None: + survived = True + player.death_time = cur_time + 1 + + # Award a per-player score depending on how many seconds + # they lasted (per-player scores only affect teams mode; + # everywhere else just looks at the per-team score). + score = int(player.death_time - self._timer.getstarttime()) + if survived: + score += 50 # A bit extra for survivors. + self.stats.player_scored(player, score, screenmessage=False) + + # Stop updating our time text, and set the final time to match + # exactly when our last guy died. + self._timer.stop(endtime=self._last_player_death_time) + + # Ok now calc game results: set a score for each team and then tell + # the game to end. + results = ba.GameResults() + + # Remember that 'free-for-all' mode is simply a special form + # of 'teams' mode where each player gets their own team, so we can + # just always deal in teams and have all cases covered. + for team in self.teams: + + # Set the team score to the max time survived by any player on + # that team. + longest_life = 0.0 + for player in team.players: + assert player.death_time is not None + longest_life = max(longest_life, player.death_time - start_time) + + # Submit the score value in milliseconds. + results.set_team_score(team, int(1000.0 * longest_life)) + + self.end(results=results) + + + + + + + + + +class MGdefs(): + points = {} + boxes = {} + boxes['area_of_interest_bounds'] = (0.3544110667, 4.493562578, -2.518391331) + (0.0, 0.0, 0.0) + (16.64754831, 8.06138989, 18.5029888) + boxes['map_bounds'] = (0.2608783669, 4.899663734, -3.543675157) + (0.0, 0.0, 0.0) + (29.23565494, 14.19991443, 29.92689344) + +class MGmap(ba.Map): + defs = MGdefs() + name = 'Sky Tiles' + + @classmethod + def get_play_types(cls) -> List[str]: + """Return valid play types for this map.""" + return [] + + @classmethod + def get_preview_texture_name(cls) -> str: + return 'achievementOffYouGo' + + @classmethod + def on_preload(cls) -> Any: + data: Dict[str, Any] = { + 'bgtex': ba.gettexture('menuBG'), + 'bgmodel': ba.getmodel('thePadBG') + } + return data + + def __init__(self) -> None: + super().__init__() + shared = SharedObjects.get() + self.node = ba.newnode( + 'terrain', + attrs={ + 'model': self.preloaddata['bgmodel'], + 'lighting': False, + 'background': True, + 'color_texture': self.preloaddata['bgtex'] + }) + gnode = ba.getactivity().globalsnode + gnode.tint = (1.3, 1.2, 1.0) + gnode.ambient_color = (1.3, 1.2, 1.0) + gnode.vignette_outer = (0.57, 0.57, 0.57) + gnode.vignette_inner = (0.9, 0.9, 0.9) + gnode.vr_camera_offset = (0, -0.8, -1.1) + gnode.vr_near_clip = 0.5 + + + + + +ba._map.register_map(MGmap) + + + + +# ba_meta export plugin +class byFreaku(ba.Plugin): + def __init__(self): + ## Campaign support ## + ba.app.add_coop_practice_level(ba.Level(name='Memory Game', displayname='${GAME}', gametype=MGgame, settings={}, preview_texture_name='achievementOffYouGo')) \ No newline at end of file From 93e3111d56175940426fd10f295bf519e9d4492c Mon Sep 17 00:00:00 2001 From: Freaku17 <92618708+Freaku17@users.noreply.github.com> Date: Thu, 1 Sep 2022 16:02:29 +0530 Subject: [PATCH 0064/1464] Adding MusicalFlags --- plugins/minigames/musical_flags.py | 241 +++++++++++++++++++++++++++++ 1 file changed, 241 insertions(+) create mode 100644 plugins/minigames/musical_flags.py diff --git a/plugins/minigames/musical_flags.py b/plugins/minigames/musical_flags.py new file mode 100644 index 00000000..ab5e04e6 --- /dev/null +++ b/plugins/minigames/musical_flags.py @@ -0,0 +1,241 @@ +## Made by MattZ45986 on GitHub +## Ported by: Freaku / @[Just] Freak#4999 + + +#Bug Fixes & Improvements as well... + +#Join BCS: +# https://discord.gg/ucyaesh + + + + +from __future__ import annotations +from typing import TYPE_CHECKING +import _ba,ba,random,math +from bastd.actor.flag import Flag,FlagPickedUpMessage +from bastd.actor.playerspaz import PlayerSpaz +if TYPE_CHECKING: + from typing import Any, Type, List, Dict, Tuple, Union, Sequence, Optional + + + +class Player(ba.Player['Team']): + def __init__(self) -> None: + self.done: bool = False + self.survived: bool = True + +class Team(ba.Team[Player]): + def __init__(self) -> None: + self.score = 0 + + +# ba_meta require api 7 +# ba_meta export game +class MFGame(ba.TeamGameActivity[Player, Team]): + name = 'Musical Flags' + description = "Don't be the one stuck without a flag!" + + @classmethod + def get_available_settings( + cls, sessiontype: Type[ba.Session]) -> List[ba.Setting]: + settings = [ + 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.BoolSetting('Epic Mode', default=False), + ba.BoolSetting('Enable Running', default=True), + ba.BoolSetting('Enable Punching', default=False), + ba.BoolSetting('Enable Bottom Credit', True) + ] + return settings + + @classmethod + def supports_session_type(cls, sessiontype: Type[ba.Session]) -> bool: + return (issubclass(sessiontype, ba.DualTeamSession) + or issubclass(sessiontype, ba.FreeForAllSession)) + + @classmethod + def get_supported_maps(cls, sessiontype: Type[ba.Session]) -> List[str]: + return ['Doom Shroom'] + + def __init__(self, settings: dict): + super().__init__(settings) + self.nodes = [] + self._dingsound = ba.getsound('dingSmall') + self._epic_mode = bool(settings['Epic Mode']) + self.credit_text = bool(settings['Enable Bottom Credit']) + self._time_limit = float(settings['Time Limit']) + self.is_punch = bool(settings['Enable Punching']) + self.is_run = bool(settings['Enable Running']) + + self._textRound = ba.newnode('text', + attrs={'text': '', + 'position': (0, -38), + 'scale': 1, + 'shadow': 1.0, + 'flatness': 1.0, + 'color': (1.0, 0.0, 1.0), + 'opacity': 1, + 'v_attach': 'top', + 'h_attach': 'center', + 'h_align': 'center', + 'v_align': 'center'}) + + self.slow_motion = self._epic_mode + # A cool music, matching our gamemode theme + self.default_music = ba.MusicType.FLAG_CATCHER + + def get_instance_description(self) -> Union[str, Sequence]: + return 'Catch Flag for yourself' + + def get_instance_description_short(self) -> Union[str, Sequence]: + return 'Catch Flag for yourself' + + def on_player_join(self, player: Player) -> None: + if self.has_begun(): + ba.screenmessage( + ba.Lstr(resource='playerDelayedJoinText', + subs=[('${PLAYER}', player.getname(full=True))]), + color=(0, 1, 0),transient=True) + player.survived = False + return + self.spawn_player(player) + + def on_player_leave(self, player: Player) -> None: + super().on_player_leave(player) + # A departing player may trigger game-over. + self.checkEnd() + + def on_begin(self) -> None: + super().on_begin() + self.roundNum = 0 + self.numPickedUp = 0 + self.nodes = [] + self.flags = [] + self.spawned = [] + self.setup_standard_time_limit(self._time_limit) + if self.credit_text: + t = ba.newnode('text', + attrs={ 'text':"Ported by Freaku\nMade by MattZ45986", ## Disable 'Enable Bottom Credits' when making playlist, No need to edit this lovely... + 'scale':0.7, + 'position':(0,0), + 'shadow':0.5, + 'flatness':1.2, + 'color':(1, 1, 1), + 'h_align':'center', + 'v_attach':'bottom'}) + self.makeRound() + self._textRound.text = 'Round ' + str(self.roundNum) + ba.timer(5, self.checkEnd) + + def makeRound(self): + for player in self.players: + if player.survived: player.team.score += 1 + self.roundNum += 1 + self._textRound.text = 'Round ' + str(self.roundNum) + self.flags = [] + self.spawned = [] + angle = random.randint(0,359) + c=0 + for player in self.players: + if player.survived: c+=1 + spacing = 10 + for player in self.players: + player.done = False + if player.survived: + if not player.is_alive(): + self.spawn_player(player,(.5,5,-4)) + self.spawned.append(player) + try: spacing = 360 // (c) + except: self.checkEnd() + colors = [(1,0,0),(0,1,0),(0,0,1),(1,1,0),(1,0,1),(0,1,1),(0,0,0),(0.5,0.8,0),(0,0.8,0.5),(0.8,0.25,0.7),(0,0.27,0.55),(2,2,0.6),(0.4,3,0.85)] + # Smart Mathematics: + # All Flags spawn same distance from the players + for i in range(c-1): + angle += spacing + angle %= 360 + x=6 * math.sin(math.degrees(angle)) + z=6 * math.cos(math.degrees(angle)) + flag = Flag(position=(x+.5,5,z-4), color=colors[i]).autoretain() + self.flags.append(flag) + + def killRound(self): + self.numPickedUp = 0 + for player in self.players: + if player.is_alive(): player.actor.handlemessage(ba.DieMessage()) + for flag in self.flags: flag.node.delete() + for light in self.nodes: light.delete() + + def spawn_player(self, player: Player, pos: tuple = (0,0,0)) -> ba.Actor: + spaz = self.spawn_player_spaz(player) + if pos == (0,0,0): + pos = (-.5+random.random()*2,3+random.random()*2,-5+random.random()*2) + spaz.connect_controls_to_player(enable_punch=self.is_punch, enable_bomb=False, enable_run=self.is_run) + spaz.handlemessage(ba.StandMessage(pos)) + return spaz + + def check_respawn(self, player): + if not player.done and player.survived: + self.respawn_player(player, 2.5) + + def handlemessage(self, msg: Any) -> Any: + + if isinstance(msg, ba.PlayerDiedMessage): + super().handlemessage(msg) + player = msg.getplayer(Player) + ba.timer(0.1, ba.Call(self.check_respawn, player)) + ba.timer(0.5, self.checkEnd) + elif isinstance(msg, FlagPickedUpMessage): + self.numPickedUp += 1 + msg.node.getdelegate(PlayerSpaz, True).getplayer(Player, True).done = True + l = ba.newnode('light', + owner=None, + attrs={'color':msg.node.color, + 'position':(msg.node.position_center), + 'intensity':1}) + self.nodes.append(l) + msg.flag.handlemessage(ba.DieMessage()) + msg.node.handlemessage(ba.DieMessage()) + msg.node.delete() + if self.numPickedUp == len(self.flags): + for player in self.spawned: + if not player.done: + try: + player.survived = False + ba.screenmessage("No Flag? "+player.getname()) + player.actor.handlemessage(ba.StandMessage((0,3,-2))) + ba.timer(0.5,ba.Call(player.actor.handlemessage, ba.FreezeMessage())) + ba.timer(3,ba.Call(player.actor.handlemessage, ba.ShouldShatterMessage())) + except: pass + ba.timer(3.5,self.killRound) + ba.timer(3.55,self.makeRound) + else: + return super().handlemessage(msg) + return None + + def checkEnd(self): + i = 0 + for player in self.players: + if player.survived: + i+=1 + if i <= 1: + for player in self.players: + if player.survived: + player.team.score += 10 + ba.timer(2.5, self.end_game) + + def end_game(self) -> None: + results = ba.GameResults() + for team in self.teams: + results.set_team_score(team, team.score) + self.end(results=results) From 845adbaf1ef35a7fee6a874231883a74e6b5084d Mon Sep 17 00:00:00 2001 From: Freaku17 <92618708+Freaku17@users.noreply.github.com> Date: Thu, 1 Sep 2022 16:06:01 +0530 Subject: [PATCH 0065/1464] Adding Floater --- plugins/utilities/floater.py | 266 +++++++++++++++++++++++++++++++++++ 1 file changed, 266 insertions(+) create mode 100644 plugins/utilities/floater.py diff --git a/plugins/utilities/floater.py b/plugins/utilities/floater.py new file mode 100644 index 00000000..3ac19c1d --- /dev/null +++ b/plugins/utilities/floater.py @@ -0,0 +1,266 @@ +#Ported by: Freaku / @[Just] Freak#4999 + +#Join BCS: +# https://discord.gg/ucyaesh + + +#My GitHub: +# https://github.com/Freaku17/BombSquad-Mods-byFreaku + + + +# ba_meta require api 7 +from __future__ import annotations +from typing import TYPE_CHECKING +import _ba,ba,random,math +from bastd.gameutils import SharedObjects +from bastd.actor.bomb import Bomb +from bastd.actor.popuptext import PopupText +if TYPE_CHECKING: + from typing import Optional + + +class Floater(ba.Actor): + def __init__(self, bounds): + super().__init__() + shared = SharedObjects.get() + self.controlled = False + self.source_player = None + self.floaterMaterial = ba.Material() + self.floaterMaterial.add_actions( + conditions=('they_have_material', + shared.player_material), + actions=(('modify_node_collision', 'collide', True), + ('modify_part_collision', 'physical', True))) + self.floaterMaterial.add_actions( + conditions=(('they_have_material', + shared.object_material), 'or', + ('they_have_material', + shared.footing_material), 'or', + ('they_have_material', + self.floaterMaterial)), + actions=('modify_part_collision', 'physical', False)) + + self.pos = bounds + self.px = "random.uniform(self.pos[0],self.pos[3])" + self.py = "random.uniform(self.pos[1],self.pos[4])" + self.pz = "random.uniform(self.pos[2],self.pos[5])" + + self.node = ba.newnode( + 'prop', + delegate=self, + owner=None, + attrs={ + 'position': (eval(self.px), eval(self.py), eval(self.pz)), + 'model': + ba.getmodel('landMine'), + 'light_model': + ba.getmodel('landMine'), + 'body': + 'landMine', + 'body_scale': + 3, + 'model_scale': + 3.1, + 'shadow_size': + 0.25, + 'density': + 999999, + 'gravity_scale': + 0.0, + 'color_texture': + ba.gettexture('achievementFlawlessVictory'), + 'reflection': + 'soft', + 'reflection_scale': [0.25], + 'materials': + [shared.footing_material, self.floaterMaterial] + }) + self.node2 = ba.newnode( + 'prop', + owner=self.node, + attrs={ + 'position': (0, 0, 0), + 'body': + 'sphere', + 'model': + None, + 'color_texture': + None, + 'body_scale': + 1.0, + 'reflection': + 'powerup', + 'density': + 999999, + 'reflection_scale': [1.0], + 'model_scale': + 1.0, + 'gravity_scale': + 0, + 'shadow_size': + 0.1, + 'is_area_of_interest': + True, + 'materials': + [shared.object_material, self.floaterMaterial] + }) + self.node.connectattr('position', self.node2, 'position') + + def pop(self): PopupText(text="Ported by \ue048Freaku", scale=1.3, position=(self.node.position[0],self.node.position[1]-1,self.node.position[2]), color=(0,1,1)).autoretain() #Edit = YouNoob... + + def checkCanControl(self): + if not self.node.exists(): + return False + if not self.source_player.is_alive(): + self.dis() + return False + return True + + def con(self): + self.controlled = True + self.checkPlayerDie() + + def up(self): + if not self.checkCanControl(): + return + v = self.node.velocity + self.node.velocity = (v[0], 5, v[2]) + + def upR(self): + if not self.checkCanControl(): + return + v = self.node.velocity + self.node.velocity = (v[0], 0, v[2]) + + def down(self): + if not self.checkCanControl(): + return + v = self.node.velocity + self.node.velocity = (v[0], -5, v[2]) + + def downR(self): + if not self.checkCanControl(): + return + v = self.node.velocity + self.node.velocity = (v[0], 0, v[2]) + + def leftright(self, value): + if not self.checkCanControl(): + return + v = self.node.velocity + self.node.velocity = (5 * value, v[1], v[2]) + + def updown(self, value): + if not self.checkCanControl(): + return + v = self.node.velocity + self.node.velocity = (v[0], v[1], -5 * value) + + def dis(self): + if self.node.exists(): + self.controlled = False + self.node.velocity = (0, 0, 0) + self.move() + + def checkPlayerDie(self): + if not self.controlled: + return + if self.source_player is None: + return + if self.source_player.is_alive(): + ba.timer(1, self.checkPlayerDie) + return + else: + self.dis() + + def distance(self, x1, y1, z1, x2, y2, z2): + d = math.sqrt(math.pow(x2 - x1, 2) + math.pow(y2 - y1, 2) + math.pow(z2 - z1, 2)) + return d + + def drop(self): + try: + np = self.node.position + except: + np = (0, 0, 0) + self.b = Bomb(bomb_type=random.choice(['normal', 'ice', 'sticky', 'impact', 'land_mine', 'tnt']), source_player=self.source_player, position=(np[0], np[1] - 1, np[2]), velocity=(0, -1, 0)).autoretain() + if self.b.bomb_type in ['impact', 'land_mine']: + self.b.arm() + + def move(self): + px = eval(self.px) + py = eval(self.py) + pz = eval(self.pz) + if self.node.exists() and not self.controlled: + pn = self.node.position + dist = self.distance(pn[0], pn[1], pn[2], px, py, pz) + self.node.velocity = ((px - pn[0]) / dist, (py - pn[1]) / dist, (pz - pn[2]) / dist) + ba.timer(dist-1, ba.WeakCall(self.move), suppress_format_warning=True) + + def handlemessage(self, msg): + if isinstance(msg, ba.DieMessage): + self.node.delete() + self.node2.delete() + self.controlled = False + elif isinstance(msg, ba.OutOfBoundsMessage): + self.handlemessage(ba.DieMessage()) + else: + super().handlemessage(msg) + + + + + + +def assignFloInputs(clientID: int): + with ba.Context(_ba.get_foreground_host_activity()): + activity = ba.getactivity() + if not hasattr(activity, 'flo') or not activity.flo.node.exists(): + try: activity.flo = Floater(activity.map.get_def_bound_box('map_bounds')) + except: return #Perhaps using in main-menu/score-screen + floater = activity.flo + if floater.controlled: + ba.screenmessage('Floater is already being controlled', color=(1, 0, 0), transient=True, clients=[clientID]) + return + ba.screenmessage('You Gained Control Over The Floater!\n Press Bomb to Throw Bombs and Punch to leave!', clients=[clientID], transient=True, color=(0, 1, 1)) + + for i in _ba.get_foreground_host_activity().players: + if i.sessionplayer.inputdevice.client_id == clientID: + def dis(i, floater): + i.actor.node.invincible = False + i.resetinput() + i.actor.connect_controls_to_player() + floater.dis() + ps = i.actor.node.position + i.actor.node.invincible = True + floater.node.position = (ps[0], ps[1] + 1.0, ps[2]) + ba.timer(1, floater.pop) + i.actor.node.hold_node = ba.Node(None) + i.actor.node.hold_node = floater.node2 + i.actor.connect_controls_to_player() + i.actor.disconnect_controls_from_player() + i.resetinput() + floater.source_player = i + floater.con() + i.assigninput(ba.InputType.PICK_UP_PRESS, floater.up) + i.assigninput(ba.InputType.PICK_UP_RELEASE, floater.upR) + i.assigninput(ba.InputType.JUMP_PRESS, floater.down) + i.assigninput(ba.InputType.BOMB_PRESS, floater.drop) + i.assigninput(ba.InputType.PUNCH_PRESS, ba.Call(dis, i, floater)) + i.assigninput(ba.InputType.UP_DOWN, floater.updown) + i.assigninput(ba.InputType.LEFT_RIGHT, floater.leftright) + + + + +old_fcm = _ba.chatmessage +def new_chat_message(msg: Union[str, ba.Lstr], clients: Sequence[int] = None, sender_override: str = None): + old_fcm(msg, clients, sender_override) + if msg == '/floater': + try: assignFloInputs(-1) + except: pass +_ba.chatmessage = new_chat_message + +# ba_meta export plugin +class byFreaku(ba.Plugin): + def __init__(self): pass \ No newline at end of file From f935050a819c4d567fc71ef34d02a64d731c9ef0 Mon Sep 17 00:00:00 2001 From: Freaku17 <92618708+Freaku17@users.noreply.github.com> Date: Thu, 1 Sep 2022 16:22:05 +0530 Subject: [PATCH 0066/1464] Updating json files for new plugins --- plugins/minigames.json | 28 ++++++++++++++++++++++++++++ plugins/utilities.json | 14 ++++++++++++++ 2 files changed, 42 insertions(+) diff --git a/plugins/minigames.json b/plugins/minigames.json index b262ccb6..9f24e87b 100644 --- a/plugins/minigames.json +++ b/plugins/minigames.json @@ -40,6 +40,34 @@ "md5sum": "a7ad7f1ac908fd871bcbcf665d49828c" } } + }, + "memory_game": { + "description": "Memorise tiles to surive! Playable in teams/ffa/co-op", + "external_url": "", + "authors": [ + { + "name": "Freaku", + "email": "", + "discord": "[Just] Freak#4999" + } + ], + "versions": { + "1.0.0": null + } + }, + "musical_flags": { + "description": "Musical chairs... but for bombsquad!?!! Playable in ffa/teams", + "external_url": "", + "authors": [ + { + "name": "Freaku", + "email": "", + "discord": "[Just] Freak#4999" + } + ], + "versions": { + "1.0.0": null + } } } } \ No newline at end of file diff --git a/plugins/utilities.json b/plugins/utilities.json index 41eda5e1..4b1f32ce 100644 --- a/plugins/utilities.json +++ b/plugins/utilities.json @@ -76,6 +76,20 @@ "md5sum": "aac4edfcaeca1dc2910f97e739d67482" } } + }, + "floater": { + "description": "Calls a overpowered floater in any gamemode. Chat /floater to activate!", + "external_url": "", + "authors": [ + { + "name": "Freaku", + "email": "", + "discord": "[Just] Freak#4999" + } + ], + "versions": { + "1.0.0": null + } } } } \ No newline at end of file From 805b99a86ff5f09d77f59a0ccf457bc573ceca69 Mon Sep 17 00:00:00 2001 From: Rikko Date: Thu, 1 Sep 2022 16:42:42 +0530 Subject: [PATCH 0067/1464] Enable pull request target, pushes on only main branch --- .github/workflows/ci.yml | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index df1b7ba8..18be8ddf 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -2,7 +2,9 @@ name: CI on: push: - # pull_request_target: + branches: + - main + pull_request_target: jobs: build: From 858030b8522e4cf15d1c25a7de61990c05f8498a Mon Sep 17 00:00:00 2001 From: Freaku17 Date: Thu, 1 Sep 2022 12:56:24 +0000 Subject: [PATCH 0068/1464] [ci] auto-format --- plugins/minigames/memory_game.py | 514 +++++++++++++++-------------- plugins/minigames/musical_flags.py | 129 ++++---- plugins/utilities/floater.py | 48 +-- 3 files changed, 362 insertions(+), 329 deletions(-) diff --git a/plugins/minigames/memory_game.py b/plugins/minigames/memory_game.py index db2297e3..c5c0204a 100644 --- a/plugins/minigames/memory_game.py +++ b/plugins/minigames/memory_game.py @@ -12,41 +12,42 @@ # (& some improvements) - - - - # incase someone is wondering how is map floating. Check out # def spawnAllMap(self) - # ba_meta require api 7 from typing import TYPE_CHECKING, overload -import _ba,ba,random +import _ba +import ba +import random from bastd.gameutils import SharedObjects if TYPE_CHECKING: from typing import Any, Sequence, Optional, List, Dict, Type, Union, Any, Literal - - class OnTimer(ba.Actor): """Timer which counts but doesn't show on-screen""" + def __init__(self) -> None: super().__init__() self._starttime_ms: Optional[int] = None - self.node = ba.newnode('text', attrs={ 'v_attach': 'top', 'h_attach': 'center', 'h_align': 'center', 'color': (1, 1, 0.5, 1), 'flatness': 0.5, 'shadow': 0.5, 'position': (0, -70), 'scale': 0, 'text': ''}) - self.inputnode = ba.newnode('timedisplay', attrs={ 'timemin': 0, 'showsubseconds': True }) + self.node = ba.newnode('text', attrs={'v_attach': 'top', 'h_attach': 'center', 'h_align': 'center', 'color': ( + 1, 1, 0.5, 1), 'flatness': 0.5, 'shadow': 0.5, 'position': (0, -70), 'scale': 0, 'text': ''}) + self.inputnode = ba.newnode('timedisplay', attrs={ + 'timemin': 0, 'showsubseconds': True}) self.inputnode.connectattr('output', self.node, 'text') + def start(self) -> None: tval = ba.time(timeformat=ba.TimeFormat.MILLISECONDS) assert isinstance(tval, int) self._starttime_ms = tval self.inputnode.time1 = self._starttime_ms ba.getactivity().globalsnode.connectattr('time', self.inputnode, 'time2') + def has_started(self) -> bool: return self._starttime_ms is not None + def stop(self, endtime: Union[int, float] = None, timeformat: ba.TimeFormat = ba.TimeFormat.SECONDS) -> None: @@ -67,13 +68,16 @@ def stop(self, self.inputnode.timemax = endtime_ms - self._starttime_ms # Overloads so type checker knows our exact return type based in args. + @overload def getstarttime(self, timeformat: Literal[ba.TimeFormat.SECONDS] = ba.TimeFormat.SECONDS) -> float: ... + @overload def getstarttime(self, timeformat: Literal[ba.TimeFormat.MILLISECONDS]) -> int: ... + def getstarttime( self, timeformat: ba.TimeFormat = ba.TimeFormat.SECONDS @@ -108,8 +112,6 @@ def handlemessage(self, msg: Any) -> Any: self.node.delete() - - class Player(ba.Player['Team']): """Our player type for this game.""" @@ -127,7 +129,8 @@ class MGgame(ba.TeamGameActivity[Player, Team]): name = 'Memory Game' description = 'Memories tiles and survive till the end!' - available_settings = [ba.BoolSetting('Epic Mode', default=False), ba.BoolSetting('Enable Bottom Credits', True)] + available_settings = [ba.BoolSetting( + 'Epic Mode', default=False), ba.BoolSetting('Enable Bottom Credits', True)] scoreconfig = ba.ScoreConfig(label='Survived', scoretype=ba.ScoreType.MILLISECONDS, version='B') # Print messages when players die (since its meaningful in this game). @@ -159,9 +162,9 @@ def __init__(self, settings: dict): if self._epic_mode: self.slow_motion = True shared = SharedObjects.get() - self._collide_with_player=ba.Material() + self._collide_with_player = ba.Material() self._collide_with_player.add_actions(actions=(('modify_part_collision', 'collide', True))) - self.dont_collide=ba.Material() + self.dont_collide = ba.Material() self.dont_collide.add_actions(actions=(('modify_part_collision', 'collide', False))) self._levelStage = 0 @@ -184,7 +187,7 @@ def __init__(self, settings: dict): self._mapFGSpaz = ba.gettexture('neoSpazIcon') self._mapFGZoe = ba.gettexture('zoeIcon') self._mapFGSnake = ba.gettexture('ninjaIcon') - self._mapFGKronk= ba.gettexture('kronkIcon') + self._mapFGKronk = ba.gettexture('kronkIcon') self._mapFGMel = ba.gettexture('melIcon') self._mapFGJack = ba.gettexture('jackIcon') self._mapFGSanta = ba.gettexture('santaIcon') @@ -202,59 +205,58 @@ def __init__(self, settings: dict): self._circleTex = ba.gettexture('circleShadow') self._image = ba.newnode('image', - attrs={'texture': self._imageTextDefault, - 'position':(0,-100), - 'scale':(100,100), - 'opacity': 0.0, - 'attach':'topCenter'}) + attrs={'texture': self._imageTextDefault, + 'position': (0, -100), + 'scale': (100, 100), + 'opacity': 0.0, + 'attach': 'topCenter'}) self._textCounter = ba.newnode('text', - attrs={'text': '10', - 'position': (0, -100), - 'scale': 2.3, - 'shadow': 1.0, - 'flatness': 1.0, - 'opacity': 0.0, - 'v_attach': 'top', - 'h_attach': 'center', - 'h_align': 'center', - 'v_align': 'center'}) + attrs={'text': '10', + 'position': (0, -100), + 'scale': 2.3, + 'shadow': 1.0, + 'flatness': 1.0, + 'opacity': 0.0, + 'v_attach': 'top', + 'h_attach': 'center', + 'h_align': 'center', + 'v_align': 'center'}) self._textLevel = ba.newnode('text', - attrs={'text': 'Level ' + str(self._levelStage), - 'position': (0, -28), - 'scale': 1.3, - 'shadow': 1.0, - 'flatness': 1.0, - 'color': (1.0, 0.0, 1.0), - 'opacity': 0.0, - 'v_attach': 'top', - 'h_attach': 'center', - 'h_align': 'center', - 'v_align': 'center'}) + attrs={'text': 'Level ' + str(self._levelStage), + 'position': (0, -28), + 'scale': 1.3, + 'shadow': 1.0, + 'flatness': 1.0, + 'color': (1.0, 0.0, 1.0), + 'opacity': 0.0, + 'v_attach': 'top', + 'h_attach': 'center', + 'h_align': 'center', + 'v_align': 'center'}) self._imageCircle = ba.newnode('image', - attrs={'texture': self._circleTex, - 'position': (75, -75), - 'scale': (20,20), - 'color': (0.2, 0.2, 0.2), - 'opacity': 0.0, - 'attach': 'topCenter'}) + attrs={'texture': self._circleTex, + 'position': (75, -75), + 'scale': (20, 20), + 'color': (0.2, 0.2, 0.2), + 'opacity': 0.0, + 'attach': 'topCenter'}) self._imageCircle2 = ba.newnode('image', - attrs={'texture': self._circleTex, - 'position': (75, -100), - 'scale': (20,20), - 'color': (0.2, 0.2, 0.2), - 'opacity': 0.0, - 'attach': 'topCenter'}) + attrs={'texture': self._circleTex, + 'position': (75, -100), + 'scale': (20, 20), + 'color': (0.2, 0.2, 0.2), + 'opacity': 0.0, + 'attach': 'topCenter'}) self._imageCircle3 = ba.newnode('image', - attrs={'texture': self._circleTex, - 'position': (75, -125), - 'scale': (20,20), - 'color': (0.2, 0.2, 0.2), - 'opacity': 0.0, - 'attach': 'topCenter'}) - + attrs={'texture': self._circleTex, + 'position': (75, -125), + 'scale': (20, 20), + 'color': (0.2, 0.2, 0.2), + 'opacity': 0.0, + 'attach': 'topCenter'}) def on_transition_in(self) -> None: super().on_transition_in() @@ -307,14 +309,14 @@ def on_begin(self) -> None: self.coldel16 = True if self.credit_text: t = ba.newnode('text', - attrs={ 'text':"Made by Freaku\nOriginally for 1.4: byANG3L", ## Disable 'Enable Bottom Credits' when making playlist, No need to edit this lovely... - 'scale':0.7, - 'position':(0,0), - 'shadow':0.5, - 'flatness':1.2, - 'color':(1, 1, 1), - 'h_align':'center', - 'v_attach':'bottom'}) + attrs={'text': "Made by Freaku\nOriginally for 1.4: byANG3L", # Disable 'Enable Bottom Credits' when making playlist, No need to edit this lovely... + 'scale': 0.7, + 'position': (0, 0), + 'shadow': 0.5, + 'flatness': 1.2, + 'color': (1, 1, 1), + 'h_align': 'center', + 'v_attach': 'bottom'}) self.spawnAllMap() self.flashHide() @@ -325,6 +327,7 @@ def on_begin(self) -> None: def startCounter(self): self._textCounter.text = '10' + def count9(): def count8(): def count7(): @@ -374,7 +377,7 @@ def on_player_join(self, player: Player) -> None: ba.screenmessage( ba.Lstr(resource='playerDelayedJoinText', subs=[('${PLAYER}', player.getname(full=True))]), - color=(0, 1, 0),transient=True,clients=[player.sessionplayer.inputdevice.client_id]) + color=(0, 1, 0), transient=True, clients=[player.sessionplayer.inputdevice.client_id]) # For score purposes, mark them as having died right as the # game started. assert self._timer is not None @@ -392,7 +395,8 @@ def on_player_leave(self, player: Player) -> None: # overriding the default character spawning.. def spawn_player(self, player: Player) -> ba.Actor: spaz = self.spawn_player_spaz(player) - pos = (self._spawnCenter[0] + random.uniform(-1.5, 2.5), self._spawnCenter[1], self._spawnCenter[2] + random.uniform(-2.5, 1.5)) + pos = (self._spawnCenter[0] + random.uniform(-1.5, 2.5), + self._spawnCenter[1], self._spawnCenter[2] + random.uniform(-2.5, 1.5)) spaz.connect_controls_to_player(enable_punch=False, enable_bomb=False, enable_pickup=False) spaz.handlemessage(ba.StandMessage(pos)) return spaz @@ -400,49 +404,50 @@ def spawn_player(self, player: Player) -> ba.Actor: def _randomSelect(self): if self._levelStage == 1: self._textureSelected = random.choice([self._mapFGMinesTex, - self._mapFGStickyTex]) + self._mapFGStickyTex]) self._image.texture = self._textureSelected elif self._levelStage == 2: self._textureSelected = random.choice([self._mapFGIceTex, - self._mapFGShieldTex]) + self._mapFGShieldTex]) self._image.texture = self._textureSelected - elif self._levelStage in [3,4,5]: + elif self._levelStage in [3, 4, 5]: self._textureSelected = random.choice([self._mapFGStickyTex, - self._mapFGIceTex, - self._mapFGImpactTex, - self._mapFGMinesTex]) + self._mapFGIceTex, + self._mapFGImpactTex, + self._mapFGMinesTex]) self._image.texture = self._textureSelected - elif self._levelStage in [6,7,8,9]: + elif self._levelStage in [6, 7, 8, 9]: self._textureSelected = random.choice([self._mapFGCurseTex, - self._mapFGHealthTex, - self._mapFGIceTex, - self._mapFGImpactTex, - self._mapFGMinesTex, - self._mapFGPunchTex, - self._mapFGShieldTex]) + self._mapFGHealthTex, + self._mapFGIceTex, + self._mapFGImpactTex, + self._mapFGMinesTex, + self._mapFGPunchTex, + self._mapFGShieldTex]) self._image.texture = self._textureSelected elif self._levelStage >= 10: self._textureSelected = random.choice([self._mapFGSpaz, - self._mapFGZoe, - self._mapFGSnake, - self._mapFGKronk, - self._mapFGMel, - self._mapFGJack, - self._mapFGSanta, - self._mapFGFrosty, - self._mapFGBones, - self._mapFGBernard, - self._mapFGPascal, - self._mapFGAli, - self._mapFGRobot, - self._mapFGAgent, - self._mapFGGrumbledorf, - self._mapFGPixel]) + self._mapFGZoe, + self._mapFGSnake, + self._mapFGKronk, + self._mapFGMel, + self._mapFGJack, + self._mapFGSanta, + self._mapFGFrosty, + self._mapFGBones, + self._mapFGBernard, + self._mapFGPascal, + self._mapFGAli, + self._mapFGRobot, + self._mapFGAgent, + self._mapFGGrumbledorf, + self._mapFGPixel]) self._image.texture = self._textureSelected return self._textureSelected def _stop(self): self._textureSelected = self._randomSelect() + def circle(): def circle2(): def circle3(): @@ -462,100 +467,100 @@ def circle3(): def _randomPlatform(self): if self._levelStage == 1: - randomTexture=[self._mapFGMinesTex, - self._mapFGMinesTex, - self._mapFGMinesTex, - self._mapFGMinesTex, - self._mapFGMinesTex, - self._mapFGMinesTex, - self._mapFGMinesTex, - self._mapFGMinesTex, - self._mapFGStickyTex, - self._mapFGStickyTex, - self._mapFGStickyTex, - self._mapFGStickyTex, - self._mapFGStickyTex, - self._mapFGStickyTex, - self._mapFGStickyTex, - self._mapFGStickyTex] + randomTexture = [self._mapFGMinesTex, + self._mapFGMinesTex, + self._mapFGMinesTex, + self._mapFGMinesTex, + self._mapFGMinesTex, + self._mapFGMinesTex, + self._mapFGMinesTex, + self._mapFGMinesTex, + self._mapFGStickyTex, + self._mapFGStickyTex, + self._mapFGStickyTex, + self._mapFGStickyTex, + self._mapFGStickyTex, + self._mapFGStickyTex, + self._mapFGStickyTex, + self._mapFGStickyTex] elif self._levelStage == 2: - randomTexture=[self._mapFGIceTex, - self._mapFGIceTex, - self._mapFGIceTex, - self._mapFGIceTex, - self._mapFGIceTex, - self._mapFGIceTex, - self._mapFGIceTex, - self._mapFGIceTex, - self._mapFGShieldTex, - self._mapFGShieldTex, - self._mapFGShieldTex, - self._mapFGShieldTex, - self._mapFGShieldTex, - self._mapFGShieldTex, - self._mapFGShieldTex, - self._mapFGShieldTex] - elif self._levelStage in [3,4,5]: - randomTexture=[self._mapFGStickyTex, - self._mapFGStickyTex, - self._mapFGStickyTex, - self._mapFGStickyTex, - self._mapFGIceTex, - self._mapFGIceTex, - self._mapFGIceTex, - self._mapFGIceTex, - self._mapFGImpactTex, - self._mapFGImpactTex, - self._mapFGImpactTex, - self._mapFGImpactTex, - self._mapFGMinesTex, - self._mapFGMinesTex, - self._mapFGMinesTex, - self._mapFGMinesTex] - elif self._levelStage in [6,7,8,9]: - randomTexture=[self._mapFGHealthTex, - self._mapFGShieldTex, - self._mapFGCurseTex, - self._mapFGCurseTex, - self._mapFGHealthTex, - self._mapFGHealthTex, - self._mapFGIceTex, - self._mapFGIceTex, - self._mapFGImpactTex, - self._mapFGImpactTex, - self._mapFGMinesTex, - self._mapFGMinesTex, - self._mapFGPunchTex, - self._mapFGPunchTex, - self._mapFGShieldTex, - self._mapFGShieldTex] + randomTexture = [self._mapFGIceTex, + self._mapFGIceTex, + self._mapFGIceTex, + self._mapFGIceTex, + self._mapFGIceTex, + self._mapFGIceTex, + self._mapFGIceTex, + self._mapFGIceTex, + self._mapFGShieldTex, + self._mapFGShieldTex, + self._mapFGShieldTex, + self._mapFGShieldTex, + self._mapFGShieldTex, + self._mapFGShieldTex, + self._mapFGShieldTex, + self._mapFGShieldTex] + elif self._levelStage in [3, 4, 5]: + randomTexture = [self._mapFGStickyTex, + self._mapFGStickyTex, + self._mapFGStickyTex, + self._mapFGStickyTex, + self._mapFGIceTex, + self._mapFGIceTex, + self._mapFGIceTex, + self._mapFGIceTex, + self._mapFGImpactTex, + self._mapFGImpactTex, + self._mapFGImpactTex, + self._mapFGImpactTex, + self._mapFGMinesTex, + self._mapFGMinesTex, + self._mapFGMinesTex, + self._mapFGMinesTex] + elif self._levelStage in [6, 7, 8, 9]: + randomTexture = [self._mapFGHealthTex, + self._mapFGShieldTex, + self._mapFGCurseTex, + self._mapFGCurseTex, + self._mapFGHealthTex, + self._mapFGHealthTex, + self._mapFGIceTex, + self._mapFGIceTex, + self._mapFGImpactTex, + self._mapFGImpactTex, + self._mapFGMinesTex, + self._mapFGMinesTex, + self._mapFGPunchTex, + self._mapFGPunchTex, + self._mapFGShieldTex, + self._mapFGShieldTex] elif self._levelStage >= 10: - randomTexture=[self._mapFGSpaz, - self._mapFGZoe, - self._mapFGSnake, - self._mapFGKronk, - self._mapFGMel, - self._mapFGJack, - self._mapFGSanta, - self._mapFGFrosty, - self._mapFGBones, - self._mapFGBernard, - self._mapFGPascal, - self._mapFGAli, - self._mapFGRobot, - self._mapFGAgent, - self._mapFGGrumbledorf, - self._mapFGPixel] + randomTexture = [self._mapFGSpaz, + self._mapFGZoe, + self._mapFGSnake, + self._mapFGKronk, + self._mapFGMel, + self._mapFGJack, + self._mapFGSanta, + self._mapFGFrosty, + self._mapFGBones, + self._mapFGBernard, + self._mapFGPascal, + self._mapFGAli, + self._mapFGRobot, + self._mapFGAgent, + self._mapFGGrumbledorf, + self._mapFGPixel] (self.mapFGPTex, self.mapFGP2Tex, self.mapFGP3Tex, self.mapFGP4Tex, - self.mapFGP5Tex, self.mapFGP6Tex, - self.mapFGP7Tex, self.mapFGP8Tex, - self.mapFGP9Tex,self.mapFGP10Tex, - self.mapFGP11Tex, self.mapFGP12Tex, - self.mapFGP13Tex, self.mapFGP14Tex, - self.mapFGP15Tex, self.mapFGP16Tex) = ( - random.sample(randomTexture, 16)) + self.mapFGP5Tex, self.mapFGP6Tex, + self.mapFGP7Tex, self.mapFGP8Tex, + self.mapFGP9Tex, self.mapFGP10Tex, + self.mapFGP11Tex, self.mapFGP12Tex, + self.mapFGP13Tex, self.mapFGP14Tex, + self.mapFGP15Tex, self.mapFGP16Tex) = ( + random.sample(randomTexture, 16)) self._mixPlatform() def _mixPlatform(self): @@ -692,114 +697,130 @@ def spawnAllMap(self): shared = SharedObjects.get() if self.coldel: self.mapFGP = ba.newnode('prop', - attrs={'body': 'puck', 'position': (3,2,-9), 'model': self._mapFGPModel, 'model_scale': 3.8, 'body_scale': 3.8, 'shadow_size': 0.5, 'gravity_scale':0.0, 'color_texture': self._mapFGPDefaultTex, 'reflection': 'soft', 'reflection_scale': [1.0], 'is_area_of_interest': True, 'materials': [self.dont_collide]}) + attrs={'body': 'puck', 'position': (3, 2, -9), 'model': self._mapFGPModel, 'model_scale': 3.8, 'body_scale': 3.8, 'shadow_size': 0.5, 'gravity_scale': 0.0, 'color_texture': self._mapFGPDefaultTex, 'reflection': 'soft', 'reflection_scale': [1.0], 'is_area_of_interest': True, 'materials': [self.dont_collide]}) self.mapFGPTex = None - self.mapFGPcol = ba.newnode('region',attrs={'position': (3,2,-9),'scale': (3.5,0.1,3.5),'type': 'box','materials': (self._collide_with_player, shared.footing_material)}) + self.mapFGPcol = ba.newnode('region', attrs={'position': (3, 2, -9), 'scale': ( + 3.5, 0.1, 3.5), 'type': 'box', 'materials': (self._collide_with_player, shared.footing_material)}) self.coldel = False if self.coldel2: - self.mapFGP2 = ba.newnode('prop', - attrs={'body': 'puck', 'position': (3,2,-6), 'model': self._mapFGPModel, 'model_scale': 3.8, 'body_scale': 3.8, 'shadow_size': 0.5, 'gravity_scale':0.0, 'color_texture': self._mapFGPDefaultTex, 'reflection': 'soft', 'reflection_scale': [1.0], 'is_area_of_interest': True, 'materials': [self.dont_collide]}) + self.mapFGP2 = ba.newnode('prop', + attrs={'body': 'puck', 'position': (3, 2, -6), 'model': self._mapFGPModel, 'model_scale': 3.8, 'body_scale': 3.8, 'shadow_size': 0.5, 'gravity_scale': 0.0, 'color_texture': self._mapFGPDefaultTex, 'reflection': 'soft', 'reflection_scale': [1.0], 'is_area_of_interest': True, 'materials': [self.dont_collide]}) self.mapFGP2Tex = None - self.mapFGP2col = ba.newnode('region',attrs={'position': (3,2,-6),'scale': (3.5,0.1,3.5),'type': 'box','materials': (self._collide_with_player, shared.footing_material)}) + self.mapFGP2col = ba.newnode('region', attrs={'position': (3, 2, -6), 'scale': ( + 3.5, 0.1, 3.5), 'type': 'box', 'materials': (self._collide_with_player, shared.footing_material)}) self.coldel2 = False if self.coldel3: - self.mapFGP3 = ba.newnode('prop', - attrs={'body': 'puck', 'position': (3,2,-3), 'model': self._mapFGPModel, 'model_scale': 3.8, 'body_scale': 3.8, 'shadow_size': 0.5, 'gravity_scale':0.0, 'color_texture': self._mapFGPDefaultTex, 'reflection': 'soft', 'reflection_scale': [1.0], 'is_area_of_interest': True, 'materials': [self.dont_collide]}) + self.mapFGP3 = ba.newnode('prop', + attrs={'body': 'puck', 'position': (3, 2, -3), 'model': self._mapFGPModel, 'model_scale': 3.8, 'body_scale': 3.8, 'shadow_size': 0.5, 'gravity_scale': 0.0, 'color_texture': self._mapFGPDefaultTex, 'reflection': 'soft', 'reflection_scale': [1.0], 'is_area_of_interest': True, 'materials': [self.dont_collide]}) self.mapFGP3Tex = None - self.mapFGP3col = ba.newnode('region',attrs={'position': (3,2,-3),'scale': (3.5,0.1,3.5),'type': 'box','materials': (self._collide_with_player, shared.footing_material)}) + self.mapFGP3col = ba.newnode('region', attrs={'position': (3, 2, -3), 'scale': ( + 3.5, 0.1, 3.5), 'type': 'box', 'materials': (self._collide_with_player, shared.footing_material)}) self.coldel3 = False if self.coldel4: - self.mapFGP4 = ba.newnode('prop', - attrs={'body': 'puck', 'position': (3,2,0), 'model': self._mapFGPModel, 'model_scale': 3.8, 'body_scale': 3.8, 'shadow_size': 0.5, 'gravity_scale':0.0, 'color_texture': self._mapFGPDefaultTex, 'reflection': 'soft', 'reflection_scale': [1.0], 'is_area_of_interest': True, 'materials': [self.dont_collide]}) + self.mapFGP4 = ba.newnode('prop', + attrs={'body': 'puck', 'position': (3, 2, 0), 'model': self._mapFGPModel, 'model_scale': 3.8, 'body_scale': 3.8, 'shadow_size': 0.5, 'gravity_scale': 0.0, 'color_texture': self._mapFGPDefaultTex, 'reflection': 'soft', 'reflection_scale': [1.0], 'is_area_of_interest': True, 'materials': [self.dont_collide]}) self.mapFGP4Tex = None - self.mapFGP4col = ba.newnode('region',attrs={'position': (3,2,0),'scale': (3.5,0.1,3.5),'type': 'box','materials': (self._collide_with_player, shared.footing_material)}) + self.mapFGP4col = ba.newnode('region', attrs={'position': (3, 2, 0), 'scale': ( + 3.5, 0.1, 3.5), 'type': 'box', 'materials': (self._collide_with_player, shared.footing_material)}) self.coldel4 = False if self.coldel5: - self.mapFGP5 = ba.newnode('prop', - attrs={'body': 'puck', 'position': (0,2,-9), 'model': self._mapFGPModel, 'model_scale': 3.8, 'body_scale': 3.8, 'shadow_size': 0.5, 'gravity_scale':0.0, 'color_texture': self._mapFGPDefaultTex, 'reflection': 'soft', 'reflection_scale': [1.0], 'is_area_of_interest': True, 'materials': [self.dont_collide]}) + self.mapFGP5 = ba.newnode('prop', + attrs={'body': 'puck', 'position': (0, 2, -9), 'model': self._mapFGPModel, 'model_scale': 3.8, 'body_scale': 3.8, 'shadow_size': 0.5, 'gravity_scale': 0.0, 'color_texture': self._mapFGPDefaultTex, 'reflection': 'soft', 'reflection_scale': [1.0], 'is_area_of_interest': True, 'materials': [self.dont_collide]}) self.mapFGP5Tex = None - self.mapFGP5col = ba.newnode('region',attrs={'position': (0,2,-9),'scale': (3.5,0.1,3.5),'type': 'box','materials': (self._collide_with_player, shared.footing_material)}) + self.mapFGP5col = ba.newnode('region', attrs={'position': (0, 2, -9), 'scale': ( + 3.5, 0.1, 3.5), 'type': 'box', 'materials': (self._collide_with_player, shared.footing_material)}) self.coldel5 = False if self.coldel6: - self.mapFGP6 = ba.newnode('prop', - attrs={'body': 'puck', 'position': (0,2,-6), 'model': self._mapFGPModel, 'model_scale': 3.8, 'body_scale': 3.8, 'shadow_size': 0.5, 'gravity_scale':0.0, 'color_texture': self._mapFGPDefaultTex, 'reflection': 'soft', 'reflection_scale': [1.0], 'is_area_of_interest': True, 'materials': [self.dont_collide]}) + self.mapFGP6 = ba.newnode('prop', + attrs={'body': 'puck', 'position': (0, 2, -6), 'model': self._mapFGPModel, 'model_scale': 3.8, 'body_scale': 3.8, 'shadow_size': 0.5, 'gravity_scale': 0.0, 'color_texture': self._mapFGPDefaultTex, 'reflection': 'soft', 'reflection_scale': [1.0], 'is_area_of_interest': True, 'materials': [self.dont_collide]}) self.mapFGP6Tex = None - self.mapFGP6col = ba.newnode('region',attrs={'position': (0,2,-6),'scale': (3.5,0.1,3.5),'type': 'box','materials': (self._collide_with_player, shared.footing_material)}) + self.mapFGP6col = ba.newnode('region', attrs={'position': (0, 2, -6), 'scale': ( + 3.5, 0.1, 3.5), 'type': 'box', 'materials': (self._collide_with_player, shared.footing_material)}) self.coldel6 = False if self.coldel7: - self.mapFGP7 = ba.newnode('prop', - attrs={'body': 'puck', 'position': (0,2,-3), 'model': self._mapFGPModel, 'model_scale': 3.8, 'body_scale': 3.8, 'shadow_size': 0.5, 'gravity_scale':0.0, 'color_texture': self._mapFGPDefaultTex, 'reflection': 'soft', 'reflection_scale': [1.0], 'is_area_of_interest': True, 'materials': [self.dont_collide]}) + self.mapFGP7 = ba.newnode('prop', + attrs={'body': 'puck', 'position': (0, 2, -3), 'model': self._mapFGPModel, 'model_scale': 3.8, 'body_scale': 3.8, 'shadow_size': 0.5, 'gravity_scale': 0.0, 'color_texture': self._mapFGPDefaultTex, 'reflection': 'soft', 'reflection_scale': [1.0], 'is_area_of_interest': True, 'materials': [self.dont_collide]}) self.mapFGP7Tex = None - self.mapFGP7col = ba.newnode('region',attrs={'position': (0,2,-3),'scale': (3.5,0.1,3.5),'type': 'box','materials': (self._collide_with_player, shared.footing_material)}) + self.mapFGP7col = ba.newnode('region', attrs={'position': (0, 2, -3), 'scale': ( + 3.5, 0.1, 3.5), 'type': 'box', 'materials': (self._collide_with_player, shared.footing_material)}) self.coldel7 = False if self.coldel8: - self.mapFGP8 = ba.newnode('prop', - attrs={'body': 'puck', 'position': (0,2,0), 'model': self._mapFGPModel, 'model_scale': 3.8, 'body_scale': 3.8, 'shadow_size': 0.5, 'gravity_scale':0.0, 'color_texture': self._mapFGPDefaultTex, 'reflection': 'soft', 'reflection_scale': [1.0], 'is_area_of_interest': True, 'materials': [self.dont_collide]}) + self.mapFGP8 = ba.newnode('prop', + attrs={'body': 'puck', 'position': (0, 2, 0), 'model': self._mapFGPModel, 'model_scale': 3.8, 'body_scale': 3.8, 'shadow_size': 0.5, 'gravity_scale': 0.0, 'color_texture': self._mapFGPDefaultTex, 'reflection': 'soft', 'reflection_scale': [1.0], 'is_area_of_interest': True, 'materials': [self.dont_collide]}) self.mapFGP8Tex = None - self.mapFGP8col = ba.newnode('region',attrs={'position': (0,2,0),'scale': (3.5,0.1,3.5),'type': 'box','materials': (self._collide_with_player, shared.footing_material)}) + self.mapFGP8col = ba.newnode('region', attrs={'position': (0, 2, 0), 'scale': ( + 3.5, 0.1, 3.5), 'type': 'box', 'materials': (self._collide_with_player, shared.footing_material)}) self.coldel8 = False if self.coldel9: - self.mapFGP9 = ba.newnode('prop', - attrs={'body': 'puck', 'position': (-3,2,-9), 'model': self._mapFGPModel, 'model_scale': 3.8, 'body_scale': 3.8, 'shadow_size': 0.5, 'gravity_scale':0.0, 'color_texture': self._mapFGPDefaultTex, 'reflection': 'soft', 'reflection_scale': [1.0], 'is_area_of_interest': True, 'materials': [self.dont_collide]}) + self.mapFGP9 = ba.newnode('prop', + attrs={'body': 'puck', 'position': (-3, 2, -9), 'model': self._mapFGPModel, 'model_scale': 3.8, 'body_scale': 3.8, 'shadow_size': 0.5, 'gravity_scale': 0.0, 'color_texture': self._mapFGPDefaultTex, 'reflection': 'soft', 'reflection_scale': [1.0], 'is_area_of_interest': True, 'materials': [self.dont_collide]}) self.mapFGP9Tex = None - self.mapFGP9col = ba.newnode('region',attrs={'position': (-3,2,-9),'scale': (3.5,0.1,3.5),'type': 'box','materials': (self._collide_with_player, shared.footing_material)}) + self.mapFGP9col = ba.newnode('region', attrs={'position': (-3, 2, -9), 'scale': ( + 3.5, 0.1, 3.5), 'type': 'box', 'materials': (self._collide_with_player, shared.footing_material)}) self.coldel9 = False if self.coldel10: - self.mapFGP10 = ba.newnode('prop', - attrs={'body': 'puck', 'position': (-3,2,-6), 'model': self._mapFGPModel, 'model_scale': 3.8, 'body_scale': 3.8, 'shadow_size': 0.5, 'gravity_scale':0.0, 'color_texture': self._mapFGPDefaultTex, 'reflection': 'soft', 'reflection_scale': [1.0], 'is_area_of_interest': True, 'materials': [self.dont_collide]}) + self.mapFGP10 = ba.newnode('prop', + attrs={'body': 'puck', 'position': (-3, 2, -6), 'model': self._mapFGPModel, 'model_scale': 3.8, 'body_scale': 3.8, 'shadow_size': 0.5, 'gravity_scale': 0.0, 'color_texture': self._mapFGPDefaultTex, 'reflection': 'soft', 'reflection_scale': [1.0], 'is_area_of_interest': True, 'materials': [self.dont_collide]}) self.mapFGP10Tex = None - self.mapFGP10col = ba.newnode('region',attrs={'position': (-3,2,-6),'scale': (3.5,0.1,3.5),'type': 'box','materials': (self._collide_with_player, shared.footing_material)}) + self.mapFGP10col = ba.newnode('region', attrs={'position': (-3, 2, -6), 'scale': ( + 3.5, 0.1, 3.5), 'type': 'box', 'materials': (self._collide_with_player, shared.footing_material)}) self.coldel10 = False if self.coldel11: - self.mapFGP11 = ba.newnode('prop', - attrs={'body': 'puck', 'position': (-3,2,-3), 'model': self._mapFGPModel, 'model_scale': 3.8, 'body_scale': 3.8, 'shadow_size': 0.5, 'gravity_scale':0.0, 'color_texture': self._mapFGPDefaultTex, 'reflection': 'soft', 'reflection_scale': [1.0], 'is_area_of_interest': True, 'materials': [self.dont_collide]}) + self.mapFGP11 = ba.newnode('prop', + attrs={'body': 'puck', 'position': (-3, 2, -3), 'model': self._mapFGPModel, 'model_scale': 3.8, 'body_scale': 3.8, 'shadow_size': 0.5, 'gravity_scale': 0.0, 'color_texture': self._mapFGPDefaultTex, 'reflection': 'soft', 'reflection_scale': [1.0], 'is_area_of_interest': True, 'materials': [self.dont_collide]}) self.mapFGP11Tex = None - self.mapFGP11col = ba.newnode('region',attrs={'position': (-3,2,-3),'scale': (3.5,0.1,3.5),'type': 'box','materials': (self._collide_with_player, shared.footing_material)}) + self.mapFGP11col = ba.newnode('region', attrs={'position': (-3, 2, -3), 'scale': ( + 3.5, 0.1, 3.5), 'type': 'box', 'materials': (self._collide_with_player, shared.footing_material)}) self.coldel11 = False if self.coldel12: - self.mapFGP12 = ba.newnode('prop', - attrs={'body': 'puck', 'position': (-3,2,0), 'model': self._mapFGPModel, 'model_scale': 3.8, 'body_scale': 3.8, 'shadow_size': 0.5, 'gravity_scale':0.0, 'color_texture': self._mapFGPDefaultTex, 'reflection': 'soft', 'reflection_scale': [1.0], 'is_area_of_interest': True, 'materials': [self.dont_collide]}) + self.mapFGP12 = ba.newnode('prop', + attrs={'body': 'puck', 'position': (-3, 2, 0), 'model': self._mapFGPModel, 'model_scale': 3.8, 'body_scale': 3.8, 'shadow_size': 0.5, 'gravity_scale': 0.0, 'color_texture': self._mapFGPDefaultTex, 'reflection': 'soft', 'reflection_scale': [1.0], 'is_area_of_interest': True, 'materials': [self.dont_collide]}) self.mapFGP12Tex = None - self.mapFGP12col = ba.newnode('region',attrs={'position': (-3,2,0),'scale': (3.5,0.1,3.5),'type': 'box','materials': (self._collide_with_player, shared.footing_material)}) + self.mapFGP12col = ba.newnode('region', attrs={'position': (-3, 2, 0), 'scale': ( + 3.5, 0.1, 3.5), 'type': 'box', 'materials': (self._collide_with_player, shared.footing_material)}) self.coldel12 = False if self.coldel13: - self.mapFGP13 = ba.newnode('prop', - attrs={'body': 'puck', 'position': (-6,2,-9), 'model': self._mapFGPModel, 'model_scale': 3.8, 'body_scale': 3.8, 'shadow_size': 0.5, 'gravity_scale':0.0, 'color_texture': self._mapFGPDefaultTex, 'reflection': 'soft', 'reflection_scale': [1.0], 'is_area_of_interest': True, 'materials': [self.dont_collide]}) + self.mapFGP13 = ba.newnode('prop', + attrs={'body': 'puck', 'position': (-6, 2, -9), 'model': self._mapFGPModel, 'model_scale': 3.8, 'body_scale': 3.8, 'shadow_size': 0.5, 'gravity_scale': 0.0, 'color_texture': self._mapFGPDefaultTex, 'reflection': 'soft', 'reflection_scale': [1.0], 'is_area_of_interest': True, 'materials': [self.dont_collide]}) self.mapFGP13Tex = None - self.mapFGP13col = ba.newnode('region',attrs={'position': (-6,2,-9),'scale': (3.5,0.1,3.5),'type': 'box','materials': (self._collide_with_player, shared.footing_material)}) + self.mapFGP13col = ba.newnode('region', attrs={'position': (-6, 2, -9), 'scale': ( + 3.5, 0.1, 3.5), 'type': 'box', 'materials': (self._collide_with_player, shared.footing_material)}) self.coldel13 = False if self.coldel14: - self.mapFGP14 = ba.newnode('prop', - attrs={'body': 'puck', 'position': (-6,2,-6), 'model': self._mapFGPModel, 'model_scale': 3.8, 'body_scale': 3.8, 'shadow_size': 0.5, 'gravity_scale':0.0, 'color_texture': self._mapFGPDefaultTex, 'reflection': 'soft', 'reflection_scale': [1.0], 'is_area_of_interest': True, 'materials': [self.dont_collide]}) + self.mapFGP14 = ba.newnode('prop', + attrs={'body': 'puck', 'position': (-6, 2, -6), 'model': self._mapFGPModel, 'model_scale': 3.8, 'body_scale': 3.8, 'shadow_size': 0.5, 'gravity_scale': 0.0, 'color_texture': self._mapFGPDefaultTex, 'reflection': 'soft', 'reflection_scale': [1.0], 'is_area_of_interest': True, 'materials': [self.dont_collide]}) self.mapFGP14Tex = None - self.mapFGP14col = ba.newnode('region',attrs={'position': (-6,2,-6),'scale': (3.5,0.1,3.5),'type': 'box','materials': (self._collide_with_player, shared.footing_material)}) + self.mapFGP14col = ba.newnode('region', attrs={'position': (-6, 2, -6), 'scale': ( + 3.5, 0.1, 3.5), 'type': 'box', 'materials': (self._collide_with_player, shared.footing_material)}) self.coldel14 = False if self.coldel15: - self.mapFGP15 = ba.newnode('prop', - attrs={'body': 'puck', 'position': (-6,2,-3), 'model': self._mapFGPModel, 'model_scale': 3.8, 'body_scale': 3.8, 'shadow_size': 0.5, 'gravity_scale':0.0, 'color_texture': self._mapFGPDefaultTex, 'reflection': 'soft', 'reflection_scale': [1.0], 'is_area_of_interest': True, 'materials': [self.dont_collide]}) + self.mapFGP15 = ba.newnode('prop', + attrs={'body': 'puck', 'position': (-6, 2, -3), 'model': self._mapFGPModel, 'model_scale': 3.8, 'body_scale': 3.8, 'shadow_size': 0.5, 'gravity_scale': 0.0, 'color_texture': self._mapFGPDefaultTex, 'reflection': 'soft', 'reflection_scale': [1.0], 'is_area_of_interest': True, 'materials': [self.dont_collide]}) self.mapFGP15Tex = None - self.mapFGP15col = ba.newnode('region',attrs={'position': (-6,2,-3),'scale': (3.5,0.1,3.5),'type': 'box','materials': (self._collide_with_player, shared.footing_material)}) + self.mapFGP15col = ba.newnode('region', attrs={'position': (-6, 2, -3), 'scale': ( + 3.5, 0.1, 3.5), 'type': 'box', 'materials': (self._collide_with_player, shared.footing_material)}) self.coldel15 = False if self.coldel16: - self.mapFGP16 = ba.newnode('prop', - attrs={'body': 'puck', 'position': (-6,2,0), 'model': self._mapFGPModel, 'model_scale': 3.8, 'body_scale': 3.8, 'shadow_size': 0.5, 'gravity_scale':0.0, 'color_texture': self._mapFGPDefaultTex, 'reflection': 'soft', 'reflection_scale': [1.0], 'is_area_of_interest': True, 'materials': [self.dont_collide]}) + self.mapFGP16 = ba.newnode('prop', + attrs={'body': 'puck', 'position': (-6, 2, 0), 'model': self._mapFGPModel, 'model_scale': 3.8, 'body_scale': 3.8, 'shadow_size': 0.5, 'gravity_scale': 0.0, 'color_texture': self._mapFGPDefaultTex, 'reflection': 'soft', 'reflection_scale': [1.0], 'is_area_of_interest': True, 'materials': [self.dont_collide]}) self.mapFGP16Tex = None - self.mapFGP16col = ba.newnode('region',attrs={'position': (-6,2,0),'scale': (3.5,0.1,3.5),'type': 'box','materials': (self._collide_with_player, shared.footing_material)}) + self.mapFGP16col = ba.newnode('region', attrs={'position': (-6, 2, 0), 'scale': ( + 3.5, 0.1, 3.5), 'type': 'box', 'materials': (self._collide_with_player, shared.footing_material)}) self.coldel16 = False def _platformTexDefault(self): @@ -883,7 +904,6 @@ def _check_end_game(self) -> None: if living_team_count <= 1: self.end_game() - def end_game(self) -> None: cur_time = ba.time() assert self._timer is not None @@ -936,18 +956,14 @@ def end_game(self) -> None: self.end(results=results) - - - - - - - class MGdefs(): points = {} boxes = {} - boxes['area_of_interest_bounds'] = (0.3544110667, 4.493562578, -2.518391331) + (0.0, 0.0, 0.0) + (16.64754831, 8.06138989, 18.5029888) - boxes['map_bounds'] = (0.2608783669, 4.899663734, -3.543675157) + (0.0, 0.0, 0.0) + (29.23565494, 14.19991443, 29.92689344) + boxes['area_of_interest_bounds'] = ( + 0.3544110667, 4.493562578, -2.518391331) + (0.0, 0.0, 0.0) + (16.64754831, 8.06138989, 18.5029888) + boxes['map_bounds'] = (0.2608783669, 4.899663734, -3.543675157) + \ + (0.0, 0.0, 0.0) + (29.23565494, 14.19991443, 29.92689344) + class MGmap(ba.Map): defs = MGdefs() @@ -990,16 +1006,12 @@ def __init__(self) -> None: gnode.vr_near_clip = 0.5 - - - ba._map.register_map(MGmap) - - # ba_meta export plugin class byFreaku(ba.Plugin): def __init__(self): ## Campaign support ## - ba.app.add_coop_practice_level(ba.Level(name='Memory Game', displayname='${GAME}', gametype=MGgame, settings={}, preview_texture_name='achievementOffYouGo')) \ No newline at end of file + ba.app.add_coop_practice_level(ba.Level(name='Memory Game', displayname='${GAME}', gametype=MGgame, settings={ + }, preview_texture_name='achievementOffYouGo')) diff --git a/plugins/minigames/musical_flags.py b/plugins/minigames/musical_flags.py index ab5e04e6..fbe9d2e6 100644 --- a/plugins/minigames/musical_flags.py +++ b/plugins/minigames/musical_flags.py @@ -1,30 +1,31 @@ -## Made by MattZ45986 on GitHub -## Ported by: Freaku / @[Just] Freak#4999 +# Made by MattZ45986 on GitHub +# Ported by: Freaku / @[Just] Freak#4999 -#Bug Fixes & Improvements as well... +# Bug Fixes & Improvements as well... -#Join BCS: +# Join BCS: # https://discord.gg/ucyaesh - - from __future__ import annotations from typing import TYPE_CHECKING -import _ba,ba,random,math -from bastd.actor.flag import Flag,FlagPickedUpMessage +import _ba +import ba +import random +import math +from bastd.actor.flag import Flag, FlagPickedUpMessage from bastd.actor.playerspaz import PlayerSpaz if TYPE_CHECKING: from typing import Any, Type, List, Dict, Tuple, Union, Sequence, Optional - class Player(ba.Player['Team']): def __init__(self) -> None: self.done: bool = False self.survived: bool = True + class Team(ba.Team[Player]): def __init__(self) -> None: self.score = 0 @@ -79,17 +80,17 @@ def __init__(self, settings: dict): self.is_run = bool(settings['Enable Running']) self._textRound = ba.newnode('text', - attrs={'text': '', - 'position': (0, -38), - 'scale': 1, - 'shadow': 1.0, - 'flatness': 1.0, - 'color': (1.0, 0.0, 1.0), - 'opacity': 1, - 'v_attach': 'top', - 'h_attach': 'center', - 'h_align': 'center', - 'v_align': 'center'}) + attrs={'text': '', + 'position': (0, -38), + 'scale': 1, + 'shadow': 1.0, + 'flatness': 1.0, + 'color': (1.0, 0.0, 1.0), + 'opacity': 1, + 'v_attach': 'top', + 'h_attach': 'center', + 'h_align': 'center', + 'v_align': 'center'}) self.slow_motion = self._epic_mode # A cool music, matching our gamemode theme @@ -106,7 +107,7 @@ def on_player_join(self, player: Player) -> None: ba.screenmessage( ba.Lstr(resource='playerDelayedJoinText', subs=[('${PLAYER}', player.getname(full=True))]), - color=(0, 1, 0),transient=True) + color=(0, 1, 0), transient=True) player.survived = False return self.spawn_player(player) @@ -126,61 +127,70 @@ def on_begin(self) -> None: self.setup_standard_time_limit(self._time_limit) if self.credit_text: t = ba.newnode('text', - attrs={ 'text':"Ported by Freaku\nMade by MattZ45986", ## Disable 'Enable Bottom Credits' when making playlist, No need to edit this lovely... - 'scale':0.7, - 'position':(0,0), - 'shadow':0.5, - 'flatness':1.2, - 'color':(1, 1, 1), - 'h_align':'center', - 'v_attach':'bottom'}) + attrs={'text': "Ported by Freaku\nMade by MattZ45986", # Disable 'Enable Bottom Credits' when making playlist, No need to edit this lovely... + 'scale': 0.7, + 'position': (0, 0), + 'shadow': 0.5, + 'flatness': 1.2, + 'color': (1, 1, 1), + 'h_align': 'center', + 'v_attach': 'bottom'}) self.makeRound() self._textRound.text = 'Round ' + str(self.roundNum) ba.timer(5, self.checkEnd) def makeRound(self): for player in self.players: - if player.survived: player.team.score += 1 + if player.survived: + player.team.score += 1 self.roundNum += 1 self._textRound.text = 'Round ' + str(self.roundNum) self.flags = [] self.spawned = [] - angle = random.randint(0,359) - c=0 + angle = random.randint(0, 359) + c = 0 for player in self.players: - if player.survived: c+=1 + if player.survived: + c += 1 spacing = 10 for player in self.players: player.done = False if player.survived: if not player.is_alive(): - self.spawn_player(player,(.5,5,-4)) + self.spawn_player(player, (.5, 5, -4)) self.spawned.append(player) - try: spacing = 360 // (c) - except: self.checkEnd() - colors = [(1,0,0),(0,1,0),(0,0,1),(1,1,0),(1,0,1),(0,1,1),(0,0,0),(0.5,0.8,0),(0,0.8,0.5),(0.8,0.25,0.7),(0,0.27,0.55),(2,2,0.6),(0.4,3,0.85)] + try: + spacing = 360 // (c) + except: + self.checkEnd() + colors = [(1, 0, 0), (0, 1, 0), (0, 0, 1), (1, 1, 0), (1, 0, 1), (0, 1, 1), (0, 0, 0), + (0.5, 0.8, 0), (0, 0.8, 0.5), (0.8, 0.25, 0.7), (0, 0.27, 0.55), (2, 2, 0.6), (0.4, 3, 0.85)] # Smart Mathematics: # All Flags spawn same distance from the players for i in range(c-1): angle += spacing angle %= 360 - x=6 * math.sin(math.degrees(angle)) - z=6 * math.cos(math.degrees(angle)) - flag = Flag(position=(x+.5,5,z-4), color=colors[i]).autoretain() + x = 6 * math.sin(math.degrees(angle)) + z = 6 * math.cos(math.degrees(angle)) + flag = Flag(position=(x+.5, 5, z-4), color=colors[i]).autoretain() self.flags.append(flag) def killRound(self): self.numPickedUp = 0 for player in self.players: - if player.is_alive(): player.actor.handlemessage(ba.DieMessage()) - for flag in self.flags: flag.node.delete() - for light in self.nodes: light.delete() - - def spawn_player(self, player: Player, pos: tuple = (0,0,0)) -> ba.Actor: + if player.is_alive(): + player.actor.handlemessage(ba.DieMessage()) + for flag in self.flags: + flag.node.delete() + for light in self.nodes: + light.delete() + + def spawn_player(self, player: Player, pos: tuple = (0, 0, 0)) -> ba.Actor: spaz = self.spawn_player_spaz(player) - if pos == (0,0,0): - pos = (-.5+random.random()*2,3+random.random()*2,-5+random.random()*2) - spaz.connect_controls_to_player(enable_punch=self.is_punch, enable_bomb=False, enable_run=self.is_run) + if pos == (0, 0, 0): + pos = (-.5+random.random()*2, 3+random.random()*2, -5+random.random()*2) + spaz.connect_controls_to_player(enable_punch=self.is_punch, + enable_bomb=False, enable_run=self.is_run) spaz.handlemessage(ba.StandMessage(pos)) return spaz @@ -199,10 +209,10 @@ def handlemessage(self, msg: Any) -> Any: self.numPickedUp += 1 msg.node.getdelegate(PlayerSpaz, True).getplayer(Player, True).done = True l = ba.newnode('light', - owner=None, - attrs={'color':msg.node.color, - 'position':(msg.node.position_center), - 'intensity':1}) + owner=None, + attrs={'color': msg.node.color, + 'position': (msg.node.position_center), + 'intensity': 1}) self.nodes.append(l) msg.flag.handlemessage(ba.DieMessage()) msg.node.handlemessage(ba.DieMessage()) @@ -213,12 +223,13 @@ def handlemessage(self, msg: Any) -> Any: try: player.survived = False ba.screenmessage("No Flag? "+player.getname()) - player.actor.handlemessage(ba.StandMessage((0,3,-2))) - ba.timer(0.5,ba.Call(player.actor.handlemessage, ba.FreezeMessage())) - ba.timer(3,ba.Call(player.actor.handlemessage, ba.ShouldShatterMessage())) - except: pass - ba.timer(3.5,self.killRound) - ba.timer(3.55,self.makeRound) + player.actor.handlemessage(ba.StandMessage((0, 3, -2))) + ba.timer(0.5, ba.Call(player.actor.handlemessage, ba.FreezeMessage())) + ba.timer(3, ba.Call(player.actor.handlemessage, ba.ShouldShatterMessage())) + except: + pass + ba.timer(3.5, self.killRound) + ba.timer(3.55, self.makeRound) else: return super().handlemessage(msg) return None @@ -227,7 +238,7 @@ def checkEnd(self): i = 0 for player in self.players: if player.survived: - i+=1 + i += 1 if i <= 1: for player in self.players: if player.survived: diff --git a/plugins/utilities/floater.py b/plugins/utilities/floater.py index 3ac19c1d..91061176 100644 --- a/plugins/utilities/floater.py +++ b/plugins/utilities/floater.py @@ -1,18 +1,20 @@ -#Ported by: Freaku / @[Just] Freak#4999 +# Ported by: Freaku / @[Just] Freak#4999 -#Join BCS: +# Join BCS: # https://discord.gg/ucyaesh -#My GitHub: +# My GitHub: # https://github.com/Freaku17/BombSquad-Mods-byFreaku - # ba_meta require api 7 from __future__ import annotations from typing import TYPE_CHECKING -import _ba,ba,random,math +import _ba +import ba +import random +import math from bastd.gameutils import SharedObjects from bastd.actor.bomb import Bomb from bastd.actor.popuptext import PopupText @@ -107,7 +109,8 @@ def __init__(self, bounds): }) self.node.connectattr('position', self.node2, 'position') - def pop(self): PopupText(text="Ported by \ue048Freaku", scale=1.3, position=(self.node.position[0],self.node.position[1]-1,self.node.position[2]), color=(0,1,1)).autoretain() #Edit = YouNoob... + def pop(self): PopupText(text="Ported by \ue048Freaku", scale=1.3, position=( + self.node.position[0], self.node.position[1]-1, self.node.position[2]), color=(0, 1, 1)).autoretain() # Edit = YouNoob... def checkCanControl(self): if not self.node.exists(): @@ -183,7 +186,8 @@ def drop(self): np = self.node.position except: np = (0, 0, 0) - self.b = Bomb(bomb_type=random.choice(['normal', 'ice', 'sticky', 'impact', 'land_mine', 'tnt']), source_player=self.source_player, position=(np[0], np[1] - 1, np[2]), velocity=(0, -1, 0)).autoretain() + self.b = Bomb(bomb_type=random.choice(['normal', 'ice', 'sticky', 'impact', 'land_mine', 'tnt']), + source_player=self.source_player, position=(np[0], np[1] - 1, np[2]), velocity=(0, -1, 0)).autoretain() if self.b.bomb_type in ['impact', 'land_mine']: self.b.arm() @@ -208,21 +212,21 @@ def handlemessage(self, msg): super().handlemessage(msg) - - - - def assignFloInputs(clientID: int): with ba.Context(_ba.get_foreground_host_activity()): activity = ba.getactivity() if not hasattr(activity, 'flo') or not activity.flo.node.exists(): - try: activity.flo = Floater(activity.map.get_def_bound_box('map_bounds')) - except: return #Perhaps using in main-menu/score-screen + try: + activity.flo = Floater(activity.map.get_def_bound_box('map_bounds')) + except: + return # Perhaps using in main-menu/score-screen floater = activity.flo if floater.controlled: - ba.screenmessage('Floater is already being controlled', color=(1, 0, 0), transient=True, clients=[clientID]) + ba.screenmessage('Floater is already being controlled', + color=(1, 0, 0), transient=True, clients=[clientID]) return - ba.screenmessage('You Gained Control Over The Floater!\n Press Bomb to Throw Bombs and Punch to leave!', clients=[clientID], transient=True, color=(0, 1, 1)) + ba.screenmessage('You Gained Control Over The Floater!\n Press Bomb to Throw Bombs and Punch to leave!', clients=[ + clientID], transient=True, color=(0, 1, 1)) for i in _ba.get_foreground_host_activity().players: if i.sessionplayer.inputdevice.client_id == clientID: @@ -251,16 +255,22 @@ def dis(i, floater): i.assigninput(ba.InputType.LEFT_RIGHT, floater.leftright) +old_fcm = _ba.chatmessage -old_fcm = _ba.chatmessage def new_chat_message(msg: Union[str, ba.Lstr], clients: Sequence[int] = None, sender_override: str = None): old_fcm(msg, clients, sender_override) if msg == '/floater': - try: assignFloInputs(-1) - except: pass + try: + assignFloInputs(-1) + except: + pass + + _ba.chatmessage = new_chat_message # ba_meta export plugin + + class byFreaku(ba.Plugin): - def __init__(self): pass \ No newline at end of file + def __init__(self): pass From 8b89226b824800ebac61451391cf704d58344b0d Mon Sep 17 00:00:00 2001 From: Freaku17 Date: Thu, 1 Sep 2022 12:56:27 +0000 Subject: [PATCH 0069/1464] [ci] apply-version-metadata --- plugins/minigames.json | 14 ++++++++++++-- plugins/utilities.json | 7 ++++++- 2 files changed, 18 insertions(+), 3 deletions(-) diff --git a/plugins/minigames.json b/plugins/minigames.json index 9f24e87b..68702d78 100644 --- a/plugins/minigames.json +++ b/plugins/minigames.json @@ -52,7 +52,12 @@ } ], "versions": { - "1.0.0": null + "1.0.0": { + "api_version": 7, + "commit_sha": "858030b", + "released_on": "01-09-2022", + "md5sum": "27de4d6a66f41367977812c2df307c24" + } } }, "musical_flags": { @@ -66,7 +71,12 @@ } ], "versions": { - "1.0.0": null + "1.0.0": { + "api_version": 7, + "commit_sha": "858030b", + "released_on": "01-09-2022", + "md5sum": "c84b7f415de5d3e9189ee73fc0e3ce93" + } } } } diff --git a/plugins/utilities.json b/plugins/utilities.json index 4b1f32ce..59914c4d 100644 --- a/plugins/utilities.json +++ b/plugins/utilities.json @@ -88,7 +88,12 @@ } ], "versions": { - "1.0.0": null + "1.0.0": { + "api_version": 7, + "commit_sha": "858030b", + "released_on": "01-09-2022", + "md5sum": "c024a0774f2e960dad7f633efdc3feb5" + } } } } From a1bffefee5cadccecbaa9850f38c78c230db247d Mon Sep 17 00:00:00 2001 From: Rikko Date: Thu, 1 Sep 2022 19:47:32 +0530 Subject: [PATCH 0070/1464] strip an additional space char --- plugins/utilities.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/plugins/utilities.json b/plugins/utilities.json index 59914c4d..4712db4f 100644 --- a/plugins/utilities.json +++ b/plugins/utilities.json @@ -78,7 +78,7 @@ } }, "floater": { - "description": "Calls a overpowered floater in any gamemode. Chat /floater to activate!", + "description": "Calls a overpowered floater in any gamemode. Chat /floater to activate!", "external_url": "", "authors": [ { @@ -97,4 +97,4 @@ } } } -} \ No newline at end of file +} From f0a03f9c8ed4a49522fc3a82689aa986676fb28a Mon Sep 17 00:00:00 2001 From: rikkolovescats Date: Thu, 1 Sep 2022 14:17:51 +0000 Subject: [PATCH 0071/1464] [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 4712db4f..fb1503e2 100644 --- a/plugins/utilities.json +++ b/plugins/utilities.json @@ -97,4 +97,4 @@ } } } -} +} \ No newline at end of file From 86f0ad25192dc02099d56e36b1ec64354c821d0b Mon Sep 17 00:00:00 2001 From: Rikko Date: Thu, 1 Sep 2022 19:50:32 +0530 Subject: [PATCH 0072/1464] Strip off extra space char --- plugins/utilities.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/plugins/utilities.json b/plugins/utilities.json index fb1503e2..cdecb7b1 100644 --- a/plugins/utilities.json +++ b/plugins/utilities.json @@ -78,7 +78,7 @@ } }, "floater": { - "description": "Calls a overpowered floater in any gamemode. Chat /floater to activate!", + "description": "Calls a overpowered floater in any gamemode. Chat /floater to activate!", "external_url": "", "authors": [ { @@ -97,4 +97,4 @@ } } } -} \ No newline at end of file +} From b4b9401892cea4d23e97577336cdb87cb8d8c706 Mon Sep 17 00:00:00 2001 From: rikkolovescats Date: Thu, 1 Sep 2022 14:20:52 +0000 Subject: [PATCH 0073/1464] [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 cdecb7b1..8fd9c1d6 100644 --- a/plugins/utilities.json +++ b/plugins/utilities.json @@ -97,4 +97,4 @@ } } } -} +} \ No newline at end of file From f36703c68d54ac1c9f8ed7c42bbb5abeba454d4d Mon Sep 17 00:00:00 2001 From: Freaku17 <92618708+Freaku17@users.noreply.github.com> Date: Fri, 2 Sep 2022 17:09:35 +0530 Subject: [PATCH 0074/1464] Adding IconsKeyboard --- plugins/utilities/icons_keyboard.py | 63 +++++++++++++++++++++++++++++ 1 file changed, 63 insertions(+) create mode 100644 plugins/utilities/icons_keyboard.py diff --git a/plugins/utilities/icons_keyboard.py b/plugins/utilities/icons_keyboard.py new file mode 100644 index 00000000..84c4a5d4 --- /dev/null +++ b/plugins/utilities/icons_keyboard.py @@ -0,0 +1,63 @@ +#Made by: Freaku / @[Just] Freak#4999 + +# • Icon Keyboard • +# Make your chats look even more cooler! +# Make sure "Always Use Internal Keyboard" is ON +# Double tap the space to change between keyboards... + + + + +# ba_meta require api 7 + +from __future__ import annotations + +from typing import TYPE_CHECKING + +import ba +from _ba import charstr as uwu + +if TYPE_CHECKING: + from typing import Any, Optional, Dict, List, Tuple,Type, Iterable + + + + + + + +# ba_meta export keyboard +class IconKeyboard_byFreaku(ba.Keyboard): + """Keyboard go brrrrrrr""" + name = 'Icons by \ue048Freaku' + chars = [(uwu(ba.SpecialChar.TICKET), + uwu(ba.SpecialChar.CROWN), + uwu(ba.SpecialChar.DRAGON), + uwu(ba.SpecialChar.SKULL), + uwu(ba.SpecialChar.HEART), + uwu(ba.SpecialChar.FEDORA), + uwu(ba.SpecialChar.HAL), + uwu(ba.SpecialChar.YIN_YANG), + uwu(ba.SpecialChar.EYE_BALL), + uwu(ba.SpecialChar.HELMET), + uwu(ba.SpecialChar.OUYA_BUTTON_U)), + (uwu(ba.SpecialChar.MUSHROOM), + uwu(ba.SpecialChar.NINJA_STAR), + uwu(ba.SpecialChar.VIKING_HELMET), + uwu(ba.SpecialChar.MOON), + uwu(ba.SpecialChar.SPIDER), + uwu(ba.SpecialChar.FIREBALL), + uwu(ba.SpecialChar.MIKIROG), + uwu(ba.SpecialChar.OUYA_BUTTON_O), + uwu(ba.SpecialChar.LOCAL_ACCOUNT), + uwu(ba.SpecialChar.LOGO)), + (uwu(ba.SpecialChar.TICKET), + uwu(ba.SpecialChar.FLAG_INDIA), + uwu(ba.SpecialChar.OCULUS_LOGO), + uwu(ba.SpecialChar.STEAM_LOGO), + uwu(ba.SpecialChar.NVIDIA_LOGO), + uwu(ba.SpecialChar.GAME_CENTER_LOGO), + uwu(ba.SpecialChar.GOOGLE_PLAY_GAMES_LOGO), + uwu(ba.SpecialChar.ALIBABA_LOGO))] + nums = [] + pages: Dict[str, Tuple[str, ...]] = {} From 64293e2c55f00877a15c34846bb5564a86fcd10a Mon Sep 17 00:00:00 2001 From: Freaku17 <92618708+Freaku17@users.noreply.github.com> Date: Fri, 2 Sep 2022 17:14:34 +0530 Subject: [PATCH 0075/1464] Update json files --- plugins/utilities.json | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/plugins/utilities.json b/plugins/utilities.json index 8fd9c1d6..32019bf6 100644 --- a/plugins/utilities.json +++ b/plugins/utilities.json @@ -95,6 +95,20 @@ "md5sum": "c024a0774f2e960dad7f633efdc3feb5" } } + }, + "icons_keyboard": { + "description": "Enable 'Always Use Internal Keyboard' in Settings>Advanced. Double tap space-bar to change keyboards", + "external_url": "", + "authors": [ + { + "name": "Freaku", + "email": "", + "discord": "[Just] Freak#4999" + } + ], + "versions": { + "1.0.0": null + } } } } \ No newline at end of file From b581d9018b458d1163ce7c64857e1c43cf8e1b1d Mon Sep 17 00:00:00 2001 From: Freaku17 Date: Fri, 2 Sep 2022 11:45:44 +0000 Subject: [PATCH 0076/1464] [ci] auto-format --- plugins/utilities/icons_keyboard.py | 67 +++++++++++++---------------- 1 file changed, 30 insertions(+), 37 deletions(-) diff --git a/plugins/utilities/icons_keyboard.py b/plugins/utilities/icons_keyboard.py index 84c4a5d4..3033bd49 100644 --- a/plugins/utilities/icons_keyboard.py +++ b/plugins/utilities/icons_keyboard.py @@ -1,4 +1,4 @@ -#Made by: Freaku / @[Just] Freak#4999 +# Made by: Freaku / @[Just] Freak#4999 # • Icon Keyboard • # Make your chats look even more cooler! @@ -6,8 +6,6 @@ # Double tap the space to change between keyboards... - - # ba_meta require api 7 from __future__ import annotations @@ -18,12 +16,7 @@ from _ba import charstr as uwu if TYPE_CHECKING: - from typing import Any, Optional, Dict, List, Tuple,Type, Iterable - - - - - + from typing import Any, Optional, Dict, List, Tuple, Type, Iterable # ba_meta export keyboard @@ -31,33 +24,33 @@ class IconKeyboard_byFreaku(ba.Keyboard): """Keyboard go brrrrrrr""" name = 'Icons by \ue048Freaku' chars = [(uwu(ba.SpecialChar.TICKET), - uwu(ba.SpecialChar.CROWN), - uwu(ba.SpecialChar.DRAGON), - uwu(ba.SpecialChar.SKULL), - uwu(ba.SpecialChar.HEART), - uwu(ba.SpecialChar.FEDORA), - uwu(ba.SpecialChar.HAL), - uwu(ba.SpecialChar.YIN_YANG), - uwu(ba.SpecialChar.EYE_BALL), - uwu(ba.SpecialChar.HELMET), - uwu(ba.SpecialChar.OUYA_BUTTON_U)), - (uwu(ba.SpecialChar.MUSHROOM), - uwu(ba.SpecialChar.NINJA_STAR), - uwu(ba.SpecialChar.VIKING_HELMET), - uwu(ba.SpecialChar.MOON), - uwu(ba.SpecialChar.SPIDER), - uwu(ba.SpecialChar.FIREBALL), - uwu(ba.SpecialChar.MIKIROG), - uwu(ba.SpecialChar.OUYA_BUTTON_O), - uwu(ba.SpecialChar.LOCAL_ACCOUNT), - uwu(ba.SpecialChar.LOGO)), - (uwu(ba.SpecialChar.TICKET), - uwu(ba.SpecialChar.FLAG_INDIA), - uwu(ba.SpecialChar.OCULUS_LOGO), - uwu(ba.SpecialChar.STEAM_LOGO), - uwu(ba.SpecialChar.NVIDIA_LOGO), - uwu(ba.SpecialChar.GAME_CENTER_LOGO), - uwu(ba.SpecialChar.GOOGLE_PLAY_GAMES_LOGO), - uwu(ba.SpecialChar.ALIBABA_LOGO))] + uwu(ba.SpecialChar.CROWN), + uwu(ba.SpecialChar.DRAGON), + uwu(ba.SpecialChar.SKULL), + uwu(ba.SpecialChar.HEART), + uwu(ba.SpecialChar.FEDORA), + uwu(ba.SpecialChar.HAL), + uwu(ba.SpecialChar.YIN_YANG), + uwu(ba.SpecialChar.EYE_BALL), + uwu(ba.SpecialChar.HELMET), + uwu(ba.SpecialChar.OUYA_BUTTON_U)), + (uwu(ba.SpecialChar.MUSHROOM), + uwu(ba.SpecialChar.NINJA_STAR), + uwu(ba.SpecialChar.VIKING_HELMET), + uwu(ba.SpecialChar.MOON), + uwu(ba.SpecialChar.SPIDER), + uwu(ba.SpecialChar.FIREBALL), + uwu(ba.SpecialChar.MIKIROG), + uwu(ba.SpecialChar.OUYA_BUTTON_O), + uwu(ba.SpecialChar.LOCAL_ACCOUNT), + uwu(ba.SpecialChar.LOGO)), + (uwu(ba.SpecialChar.TICKET), + uwu(ba.SpecialChar.FLAG_INDIA), + uwu(ba.SpecialChar.OCULUS_LOGO), + uwu(ba.SpecialChar.STEAM_LOGO), + uwu(ba.SpecialChar.NVIDIA_LOGO), + uwu(ba.SpecialChar.GAME_CENTER_LOGO), + uwu(ba.SpecialChar.GOOGLE_PLAY_GAMES_LOGO), + uwu(ba.SpecialChar.ALIBABA_LOGO))] nums = [] pages: Dict[str, Tuple[str, ...]] = {} From b5ee1f09781ce63d3695beac27451beafba7d642 Mon Sep 17 00:00:00 2001 From: Freaku17 Date: Fri, 2 Sep 2022 11:45:46 +0000 Subject: [PATCH 0077/1464] [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 32019bf6..51231617 100644 --- a/plugins/utilities.json +++ b/plugins/utilities.json @@ -107,7 +107,12 @@ } ], "versions": { - "1.0.0": null + "1.0.0": { + "api_version": 7, + "commit_sha": "b581d90", + "released_on": "02-09-2022", + "md5sum": "94f67a98a9faed0ece63674c84d40061" + } } } } From 7c4504cc1eb08670c9164ea6e1d29c60bd8b85b8 Mon Sep 17 00:00:00 2001 From: Rikko Date: Mon, 5 Sep 2022 00:27:45 +0530 Subject: [PATCH 0078/1464] Work with all kinds of exports --- plugin_manager.py | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/plugin_manager.py b/plugin_manager.py index 0c165aa8..2a5facca 100644 --- a/plugin_manager.py +++ b/plugin_manager.py @@ -382,6 +382,10 @@ async def has_minigames(self): self._has_minigames = REGEXP["minigames"].search(content) is not None return self._has_minigames + async def has_plugins(self): + entry_points = await self.get_entry_points() + return len(entry_points) > 0 + def load_minigames(self): scanner = ba._meta.DirectoryScan(paths="") directory, module = self.install_path.rsplit(os.path.sep, 1) @@ -414,6 +418,8 @@ async def is_enabled(self): """ Return True even if a single entry point is enabled or contains minigames. """ + if not await self.has_plugins(): + return True for entry_point, plugin_info in ba.app.config["Plugins"].items(): if entry_point.startswith(self._entry_point_initials) and plugin_info["enabled"]: return True @@ -422,7 +428,7 @@ async def is_enabled(self): # for entry_point in await self.get_entry_points(): # if ba.app.config["Plugins"][entry_point]["enabled"]: # return True - return await self.has_minigames() + return False # XXX: Commenting this out for now, since `enable` and `disable` currently have their # own separate logic. @@ -728,7 +734,7 @@ async def draw_ui(self): to_draw_button4 = False if self.plugin.is_installed: self.local_plugin = self.plugin.get_local() - if await self.local_plugin.has_minigames(): + if not await self.local_plugin.has_plugins(): to_draw_button1 = False else: if await self.local_plugin.is_enabled(): From 1efff85162c5b4de3b3f05e58f7591d65bcccdcb Mon Sep 17 00:00:00 2001 From: Rikko Date: Mon, 5 Sep 2022 11:26:57 +0530 Subject: [PATCH 0079/1464] Prep for v0.1.5 --- index.json | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/index.json b/index.json index 651e49e7..64b326c6 100644 --- a/index.json +++ b/index.json @@ -1,12 +1,7 @@ { "plugin_manager_url": "http://github.com/bombsquad-community/plugin-manager/{content_type}/{tag}/plugin_manager.py", "versions": { - "0.1.4": { - "api_version": 7, - "commit_sha": "29f531e5", - "released_on": "28-08-2022", - "md5sum": "5b3b8b36316ba2ab46aea38416301169" - } + "0.1.5": null }, "categories": [ "http://github.com/bombsquad-community/plugin-manager/{content_type}/{tag}/plugins/utilities.json", From ed52b4b1d1d0c9823c386d7a995ebaa21d157e3f Mon Sep 17 00:00:00 2001 From: Rikko Date: Mon, 5 Sep 2022 11:36:34 +0530 Subject: [PATCH 0080/1464] Prep for v0.1.5 --- index.json | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/index.json b/index.json index 64b326c6..3201b663 100644 --- a/index.json +++ b/index.json @@ -1,7 +1,12 @@ { "plugin_manager_url": "http://github.com/bombsquad-community/plugin-manager/{content_type}/{tag}/plugin_manager.py", "versions": { - "0.1.5": null + "0.1.5": { + "api_version": 7, + "commit_sha": "7c4504cc1eb08670c9164ea6e1d29c60bd8b85b8", + "released_on": "05-09-2022", + "md5sum": "5b3b8b36316ba2ab46aea38416301169" + } }, "categories": [ "http://github.com/bombsquad-community/plugin-manager/{content_type}/{tag}/plugins/utilities.json", From 5f57d4cca0faca3a24e754eca5b2025e73ac8040 Mon Sep 17 00:00:00 2001 From: Rikko Date: Mon, 5 Sep 2022 11:37:46 +0530 Subject: [PATCH 0081/1464] Update md5sum --- index.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/index.json b/index.json index 3201b663..63944ce2 100644 --- a/index.json +++ b/index.json @@ -5,7 +5,7 @@ "api_version": 7, "commit_sha": "7c4504cc1eb08670c9164ea6e1d29c60bd8b85b8", "released_on": "05-09-2022", - "md5sum": "5b3b8b36316ba2ab46aea38416301169" + "md5sum": "52e03d303e55738d3653f86fb5abe2de" } }, "categories": [ From c34599609fa35fc8a6886e2f0f1fe4bc1c9a0901 Mon Sep 17 00:00:00 2001 From: Rikko Date: Mon, 5 Sep 2022 11:39:31 +0530 Subject: [PATCH 0082/1464] Update index.json --- index.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/index.json b/index.json index 63944ce2..e4520699 100644 --- a/index.json +++ b/index.json @@ -1,7 +1,7 @@ { "plugin_manager_url": "http://github.com/bombsquad-community/plugin-manager/{content_type}/{tag}/plugin_manager.py", "versions": { - "0.1.5": { + "0.1.4": { "api_version": 7, "commit_sha": "7c4504cc1eb08670c9164ea6e1d29c60bd8b85b8", "released_on": "05-09-2022", From 1c2915afc1515a37e8428903a4c827531a32d08c Mon Sep 17 00:00:00 2001 From: Vishal Date: Wed, 31 Aug 2022 22:41:32 +0530 Subject: [PATCH 0083/1464] New Plugin --- plugins/utilities/easy_connect.py | 592 ++++++++++++++++++++++++++++++ 1 file changed, 592 insertions(+) create mode 100644 plugins/utilities/easy_connect.py diff --git a/plugins/utilities/easy_connect.py b/plugins/utilities/easy_connect.py new file mode 100644 index 00000000..0c9d6e08 --- /dev/null +++ b/plugins/utilities/easy_connect.py @@ -0,0 +1,592 @@ +# -*- coding: utf-8 -*- +# ba_meta require api 7 + +# =============================================== +# EasyConnect by Mr.Smoothy | +# verion 1.2 | +# https://discord.gg/ucyaesh | +# Serverconnector X IPPORTRevealer | +# for bombsquad v1.7 + | +# =============================================== + + +# .................___________________________________________ +# WATCH IN ACTION https://www.youtube.com/watch?v=jwi2wKwZblQ +# .................___________________________________________ + +# Have any idea/suggestion/bug report > send message on discord mr.smoothy#5824 + +# Discord:- +# mr.smoothy#5824 + + +# DONT EDIT ANYTHING WITHOUT PERMISSION + +# join Bombspot - bombsquad biggest modding community .... open for everyone https://discord.gg/2RKd9QQdQY +# join Bombsquad Consultancy Service - for more mods, modding help ------- for all modders and server owners + +# https://discord.gg/2RKd9QQdQY +# https://discord.gg/ucyaesh + +# REQUIREMENTS +# built for bs 1.7 and above + +# by Mr.Smoothy for Bombsquad version 1.7 + +import _ba +import ba +import bastd +import threading +from bastd.ui.gather import manualtab, publictab +from bastd.ui import popup +from dataclasses import dataclass +import random +from enum import Enum +from bastd.ui.popup import PopupMenuWindow, PopupWindow +from typing import Any, Optional, Dict, List, Tuple, Type, Union, Callable +from bastd.ui.gather.publictab import PublicGatherTab + + +class _HostLookupThread(threading.Thread): + """Thread to fetch an addr.""" + + def __init__(self, name: str, port: int, + call: Callable[[Optional[str], int], Any]): + super().__init__() + self._name = name + self._port = port + self._call = call + + def run(self) -> None: + result: Optional[str] + try: + import socket + result = socket.gethostbyname(self._name) + except Exception: + result = None + ba.pushcall(lambda: self._call(result, self._port), + from_other_thread=True) + + +def new_build_favorites_tab(self, region_height: float) -> None: + c_height = region_height - 20 + v = c_height - 35 - 25 - 30 + self.retry_inter = 0.0 + uiscale = ba.app.ui.uiscale + self._width = 1240 if uiscale is ba.UIScale.SMALL else 1040 + x_inset = 100 if uiscale is ba.UIScale.SMALL else 0 + self._height = (578 if uiscale is ba.UIScale.SMALL else + 670 if uiscale is ba.UIScale.MEDIUM else 800) + + self._scroll_width = self._width - 130 + 2 * x_inset + self._scroll_height = self._height - 180 + x_inset = 100 if uiscale is ba.UIScale.SMALL else 0 + + c_height = self._scroll_height - 20 + sub_scroll_height = c_height - 63 + self._favorites_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 = (90 if uiscale is ba.UIScale.SMALL else + 142 if uiscale is ba.UIScale.MEDIUM else 130) + b_space_extra = (0 if uiscale is ba.UIScale.SMALL else + -2 if uiscale is ba.UIScale.MEDIUM else -5) + + btnv = (c_height - (48 if uiscale is ba.UIScale.SMALL else + 45 if uiscale is ba.UIScale.MEDIUM else 40) - + b_height) + # ================= smoothy ============= + + ba.textwidget(parent=self._container, + position=(90 if uiscale is ba.UIScale.SMALL else 120, btnv + + 120 if uiscale is ba.UIScale.SMALL else btnv+90), + size=(0, 0), + h_align='center', + color=(0.8, 0.8, 0.8), + v_align='top', + text="Auto") + btnv += 50 if uiscale is ba.UIScale.SMALL else 0 + + ba.buttonwidget(parent=self._container, + size=(30, 30), + position=(25 if uiscale is ba.UIScale.SMALL else 40, + btnv+10), + + color=(0.6, 0.53, 0.63), + textcolor=(0.75, 0.7, 0.8), + on_activate_call=self.auto_retry_dec, + text_scale=1.3 if uiscale is ba.UIScale.SMALL else 1.2, + label="-", + autoselect=True) + self.retry_inter_text = ba.textwidget(parent=self._container, + position=( + 90 if uiscale is ba.UIScale.SMALL else 120, btnv+25), + size=(0, 0), + h_align='center', + color=(0.8, 0.8, 0.8), + v_align='center', + text=str(self.retry_inter) if self.retry_inter > 0.0 else 'off') + ba.buttonwidget(parent=self._container, + size=(30, 30), + position=(125 if uiscale is ba.UIScale.SMALL else 155, + btnv+10), + + color=(0.6, 0.53, 0.63), + textcolor=(0.75, 0.7, 0.8), + on_activate_call=self.auto_retry_inc, + text_scale=1.3 if uiscale is ba.UIScale.SMALL else 1.2, + label="+", + autoselect=True) + + btnv -= b_height + b_space_extra + + self._favorites_connect_button = btn1 = ba.buttonwidget( + parent=self._container, + size=(b_width, b_height), + position=(25 if uiscale is ba.UIScale.SMALL else 40, btnv), + button_type='square', + color=(0.6, 0.53, 0.63), + textcolor=(0.75, 0.7, 0.8), + on_activate_call=self._on_favorites_connect_press, + text_scale=1.0 if uiscale is ba.UIScale.SMALL else 1.2, + label=ba.Lstr(resource='gatherWindow.manualConnectText'), + autoselect=True) + if uiscale is ba.UIScale.SMALL and ba.app.ui.use_toolbars: + ba.widget(edit=btn1, + left_widget=_ba.get_special_widget('back_button')) + btnv -= b_height + b_space_extra + ba.buttonwidget(parent=self._container, + size=(b_width, b_height), + position=(25 if uiscale is ba.UIScale.SMALL else 40, + btnv), + button_type='square', + color=(0.6, 0.53, 0.63), + textcolor=(0.75, 0.7, 0.8), + on_activate_call=self._on_favorites_edit_press, + text_scale=1.0 if uiscale is ba.UIScale.SMALL else 1.2, + label=ba.Lstr(resource='editText'), + autoselect=True) + btnv -= b_height + b_space_extra + ba.buttonwidget(parent=self._container, + size=(b_width, b_height), + position=(25 if uiscale is ba.UIScale.SMALL else 40, + btnv), + button_type='square', + color=(0.6, 0.53, 0.63), + textcolor=(0.75, 0.7, 0.8), + on_activate_call=self._on_favorite_delete_press, + text_scale=1.0 if uiscale is ba.UIScale.SMALL else 1.2, + label=ba.Lstr(resource='deleteText'), + autoselect=True) + + v -= sub_scroll_height + 23 + self._scrollwidget = scrlw = ba.scrollwidget( + parent=self._container, + position=(190 if uiscale is ba.UIScale.SMALL else 225, v), + size=(sub_scroll_width, sub_scroll_height), + claims_left_right=True) + ba.widget(edit=self._favorites_connect_button, + right_widget=self._scrollwidget) + self._columnwidget = ba.columnwidget(parent=scrlw, + left_border=10, + border=2, + margin=0, + claims_left_right=True) + + self._favorite_selected = None + self._refresh_favorites() + + +def new_on_favorites_connect_press(self) -> None: + if self._favorite_selected is None: + self._no_favorite_selected_error() + + else: + config = ba.app.config['Saved Servers'][self._favorite_selected] + _HostLookupThread(name=config['addr'], + port=config['port'], + call=ba.WeakCall( + self._host_lookup_result)).start() + + if self.retry_inter > 0 and (_ba.get_connection_to_host_info() == {} or _ba.get_connection_to_host_info()['build_number'] == 0): + ba.screenmessage("Server full or unreachable, Retrying....") + self._retry_timer = ba.Timer(self.retry_inter, ba.Call( + self._on_favorites_connect_press), timetype=ba.TimeType.REAL) + + +def auto_retry_inc(self): + + self.retry_inter += 0.5 + ba.textwidget(edit=self.retry_inter_text, text='%.1f' % self.retry_inter) + + +def auto_retry_dec(self): + if self.retry_inter > 0.0: + self.retry_inter -= 0.5 + + if self.retry_inter == 0.0: + ba.textwidget(edit=self.retry_inter_text, text='off') + else: + ba.textwidget(edit=self.retry_inter_text, text='%.1f' % self.retry_inter) + + +@dataclass +class PartyEntry: + """Info about a public party.""" + address: str + index: int + queue: Optional[str] = None + port: int = -1 + name: str = '' + size: int = -1 + size_max: int = -1 + claimed: bool = False + ping: Optional[float] = None + ping_interval: float = -1.0 + next_ping_time: float = -1.0 + ping_attempts: int = 0 + ping_responses: int = 0 + stats_addr: Optional[str] = None + clean_display_index: Optional[int] = None + + def get_key(self) -> str: + """Return the key used to store this party.""" + return f'{self.address}_{self.port}' + + +class SelectionComponent(Enum): + """Describes what part of an entry is selected.""" + NAME = 'name' + STATS_BUTTON = 'stats_button' + + +@dataclass +class Selection: + """Describes the currently selected list element.""" + entry_key: str + component: SelectionComponent + + +def _clear(self) -> None: + for widget in [ + self._name_widget, self._size_widget, self._ping_widget, + self._stats_button + ]: + if widget: + try: + widget.delete() + except: + pass + + +def update(self, index: int, party: PartyEntry, sub_scroll_width: float, + sub_scroll_height: float, lineheight: float, + columnwidget: ba.Widget, join_text: ba.Widget, + filter_text: ba.Widget, existing_selection: Optional[Selection], + tab: PublicGatherTab) -> None: + """Update for the given data.""" + # pylint: disable=too-many-locals + + # Quick-out: if we've been marked clean for a certain index and + # we're still at that index, we're done. + if party.clean_display_index == index: + return + + ping_good = _ba.get_v1_account_misc_read_val('pingGood', 100) + ping_med = _ba.get_v1_account_misc_read_val('pingMed', 500) + + self._clear() + hpos = 20 + vpos = sub_scroll_height - lineheight * index - 50 + self._name_widget = ba.textwidget( + text=ba.Lstr(value=party.name), + parent=columnwidget, + size=(sub_scroll_width * 0.63, 20), + position=(0 + hpos, 4 + vpos), + selectable=True, + on_select_call=ba.WeakCall( + tab.set_public_party_selection, + Selection(party.get_key(), SelectionComponent.NAME)), + on_activate_call=ba.WeakCall(tab.on_public_party_activate, party), + click_activate=True, + maxwidth=sub_scroll_width * 0.45, + corner_scale=1.4, + autoselect=True, + color=(1, 1, 1, 0.3 if party.ping is None else 1.0), + h_align='left', + v_align='center') + ba.widget(edit=self._name_widget, + left_widget=join_text, + show_buffer_top=64.0, + show_buffer_bottom=64.0) + if existing_selection == Selection(party.get_key(), + SelectionComponent.NAME): + ba.containerwidget(edit=columnwidget, + selected_child=self._name_widget) + if party.stats_addr or True: + url = party.stats_addr.replace( + '${ACCOUNT}', + _ba.get_v1_account_misc_read_val_2('resolvedAccountID', + 'UNKNOWN')) + self._stats_button = ba.buttonwidget( + color=(0.5, 0.8, 0.8), + textcolor=(1.0, 1.0, 1.0), + label='....', + parent=columnwidget, + autoselect=True, + + on_select_call=ba.WeakCall( + tab.set_public_party_selection, + Selection(party.get_key(), + SelectionComponent.STATS_BUTTON)), + size=(100, 40), + position=(sub_scroll_width * 0.66 + hpos, 1 + vpos), + scale=0.9) + ba.buttonwidget(edit=self._stats_button, on_activate_call=ba.Call( + self.on_stats_click, self._stats_button, party)) + if existing_selection == Selection( + party.get_key(), SelectionComponent.STATS_BUTTON): + ba.containerwidget(edit=columnwidget, + selected_child=self._stats_button) + + self._size_widget = ba.textwidget( + text=str(party.size) + '/' + str(party.size_max), + parent=columnwidget, + size=(0, 0), + position=(sub_scroll_width * 0.86 + hpos, 20 + vpos), + scale=0.7, + color=(0.8, 0.8, 0.8), + h_align='right', + v_align='center') + + if index == 0: + ba.widget(edit=self._name_widget, up_widget=filter_text) + if self._stats_button: + ba.widget(edit=self._stats_button, up_widget=filter_text) + + self._ping_widget = ba.textwidget(parent=columnwidget, + size=(0, 0), + position=(sub_scroll_width * 0.94 + + hpos, 20 + vpos), + scale=0.7, + h_align='right', + v_align='center') + if party.ping is None: + ba.textwidget(edit=self._ping_widget, + text='-', + color=(0.5, 0.5, 0.5)) + else: + ba.textwidget(edit=self._ping_widget, + text=str(int(party.ping)), + color=(0, 1, 0) if party.ping <= ping_good else + (1, 1, 0) if party.ping <= ping_med else (1, 0, 0)) + + party.clean_display_index = index + + +def _get_popup_window_scale() -> float: + uiscale = ba.app.ui.uiscale + return (2.3 if uiscale is ba.UIScale.SMALL else + 1.65 if uiscale is ba.UIScale.MEDIUM else 1.23) + + +_party = None + + +def on_stats_click(self, widget, party): + global _party + _party = party + choices = ['connect', 'copyqueue', "save"] + DisChoices = [ba.Lstr(resource="ipp", fallback_value="Connect by IP"), ba.Lstr( + resource="copy id", fallback_value="Copy Queue ID"), ba.Lstr(value="Save")] + if party.stats_addr: + choices.append('stats') + if 'discord' in party.stats_addr: + txt = "Discord" + elif 'yout' in party.stats_addr: + txt = "Youtube" + else: + txt = party.stats_addr[0:13] + DisChoices.append(ba.Lstr(value=txt)) + PopupMenuWindow( + position=widget.get_screen_space_center(), + scale=_get_popup_window_scale(), + choices=choices, + choices_display=DisChoices, + current_choice="stats", + delegate=self) + + +def popup_menu_closing(self, popup_window: popup.PopupWindow) -> None: + pass + + +def popup_menu_selected_choice(self, window: popup.PopupMenu, + choice: str) -> None: + """Called when a menu entry is selected.""" + # Unused arg. + + if choice == 'stats': + url = _party.stats_addr.replace( + '${ACCOUNT}', + _ba.get_v1_account_misc_read_val_2('resolvedAccountID', + 'UNKNOWN')) + ba.open_url(url) + elif choice == 'connect': + + PartyQuickConnect(_party.address, _party.port) + elif choice == 'save': + config = ba.app.config + ip_add = _party.address + p_port = _party.port + title = _party.name + if not isinstance(config.get('Saved Servers'), dict): + config['Saved Servers'] = {} + config['Saved Servers'][f'{ip_add}@{p_port}'] = { + 'addr': ip_add, + 'port': p_port, + 'name': title + } + config.commit() + ba.screenmessage("Server saved to manual") + ba.playsound(ba.getsound('gunCocking')) + elif choice == "copyqueue": + ba.clipboard_set_text(_party.queue) + ba.playsound(ba.getsound('gunCocking')) + + +def replace(): + manualtab.ManualGatherTab._build_favorites_tab = new_build_favorites_tab + manualtab.ManualGatherTab._on_favorites_connect_press = new_on_favorites_connect_press + manualtab.ManualGatherTab.auto_retry_dec = auto_retry_dec + manualtab.ManualGatherTab.auto_retry_inc = auto_retry_inc + publictab.UIRow.update = update + publictab.UIRow._clear = _clear + publictab.UIRow.on_stats_click = on_stats_click + publictab.UIRow.popup_menu_closing = popup_menu_closing + publictab.UIRow.popup_menu_selected_choice = popup_menu_selected_choice + + +class PartyQuickConnect(ba.Window): + def __init__(self, address: str, port: int): + self._width = 800 + self._height = 400 + self._white_tex = ba.gettexture('white') + self.lineup_tex = ba.gettexture('playerLineup') + self.lineup_1_transparent_model = ba.getmodel( + 'playerLineup1Transparent') + self.eyes_model = ba.getmodel('plasticEyesTransparent') + uiscale = ba.app.ui.uiscale + super().__init__(root_widget=ba.containerwidget( + size=(self._width, self._height), + color=(0.45, 0.63, 0.15), + transition='in_scale', + scale=(1.4 if uiscale is ba.UIScale.SMALL else + 1.2 if uiscale is ba.UIScale.MEDIUM else 1.0))) + self._cancel_button = ba.buttonwidget(parent=self._root_widget, + scale=1.0, + position=(60, self._height - 80), + size=(50, 50), + label='', + on_activate_call=self.close, + autoselect=True, + color=(0.45, 0.63, 0.15), + icon=ba.gettexture('crossOut'), + iconscale=1.2) + ba.containerwidget(edit=self._root_widget, + cancel_button=self._cancel_button) + + self.IP = ba.textwidget( + parent=self._root_widget, + position=(self._width * 0.5, self._height * 0.55 + 60), + size=(0, 0), + color=(1.0, 3.0, 1.0), + scale=1.3, + h_align='center', + v_align='center', + text="IP: "+address + " PORT: "+str(port), + maxwidth=self._width * 0.65) + self._title_text = ba.textwidget( + parent=self._root_widget, + position=(self._width * 0.5, self._height * 0.55), + size=(0, 0), + color=(1.0, 3.0, 1.0), + scale=1.3, + h_align='center', + v_align='center', + text="Retrying....", + maxwidth=self._width * 0.65) + self._line_image = ba.imagewidget( + parent=self._root_widget, + color=(0.0, 0.0, 0.0), + opacity=0.2, + position=(40.0, 120), + size=(800-190+80, 4.0), + texture=self._white_tex) + self.dude_x = 60 + self._body_image_target = ba.buttonwidget( + parent=self._root_widget, + size=(1 * 60, 1 * 80), + color=(random.random(), random.random(), random.random()), + label='', + texture=self.lineup_tex, + position=(40, 110), + model_transparent=self.lineup_1_transparent_model) + self._eyes_image = ba.imagewidget( + parent=self._root_widget, + size=(1 * 36, 1 * 18), + texture=self.lineup_tex, + color=(1, 1, 1), + position=(40, 165), + model_transparent=self.eyes_model) + # self._body_image_target2 = ba.imagewidget( + # parent=self._root_widget, + # size=(1* 60, 1 * 80), + # color=(1,0.3,0.4), + # texture=self.lineup_tex, + # position=(700,130), + # model_transparent=self.lineup_1_transparent_model) + self.closed = False + self.retry_count = 1 + self.direction = "right" + self.connect(address, port) + self.move_R = ba.Timer(0.01, ba.Call(self.move_right), + timetype=ba.TimeType.REAL, repeat=True) + + def move_right(self): + if self._body_image_target and self._eyes_image: + ba.buttonwidget(edit=self._body_image_target, position=(self.dude_x, 110)) + ba.imagewidget(edit=self._eyes_image, position=(self.dude_x+10, 165)) + else: + self.move_R = None + if self.direction == "right": + self.dude_x += 2 + if self.dude_x >= 650: + self.direction = "left" + else: + self.dude_x -= 2 + if self.dude_x <= 50: + self.direction = "right" + + def connect(self, address, port): + if not self.closed and (_ba.get_connection_to_host_info() == {} or _ba.get_connection_to_host_info()['build_number'] == 0): + ba.textwidget(edit=self._title_text, text="Retrying....("+str(self.retry_count)+")") + self.retry_count += 1 + _ba.connect_to_party(address, port=port) + self._retry_timer = ba.Timer(1.5, ba.Call( + self.connect, address, port), timetype=ba.TimeType.REAL) + + def close(self) -> None: + """Close the ui.""" + self.closed = True + ba.containerwidget(edit=self._root_widget, transition='out_scale') + +# ba_meta export plugin + + +class InitalRun(ba.Plugin): + def __init__(self): + replace() From 7c1c275695aa745b655ca7afcfa662057f06f856 Mon Sep 17 00:00:00 2001 From: Vishal Date: Wed, 31 Aug 2022 22:55:08 +0530 Subject: [PATCH 0084/1464] Update utilities.json --- plugins/utilities.json | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/plugins/utilities.json b/plugins/utilities.json index 51231617..a8b4e3e7 100644 --- a/plugins/utilities.json +++ b/plugins/utilities.json @@ -93,7 +93,19 @@ "commit_sha": "858030b", "released_on": "01-09-2022", "md5sum": "c024a0774f2e960dad7f633efdc3feb5" + }, + "easy_connect": { + "description": "Can connect easily to servers by retrying automatically till you join the server.", + "external_url": "", + "authors": [ + { + "name": "Mr.Smoothy", + "email": "", + "discord": "mr.smoothy#5824" } + ], + "versions": { + "1.0.0": null } }, "icons_keyboard": { @@ -116,4 +128,4 @@ } } } -} \ No newline at end of file +} From c0d4c6f09ec414ceed75b7c380899992208213f2 Mon Sep 17 00:00:00 2001 From: vishal332008 Date: Wed, 31 Aug 2022 17:25:34 +0000 Subject: [PATCH 0085/1464] [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 a8b4e3e7..b42718ac 100644 --- a/plugins/utilities.json +++ b/plugins/utilities.json @@ -105,7 +105,12 @@ } ], "versions": { - "1.0.0": null + "1.0.0": { + "api_version": 7, + "commit_sha": "f01323d", + "released_on": "31-08-2022", + "md5sum": "eb93f3df040261f73963621cb66565d3" + } } }, "icons_keyboard": { @@ -128,4 +133,4 @@ } } } -} +} \ No newline at end of file From 7b9c9ae4bfb757ac0babe525ad2efd70091efb40 Mon Sep 17 00:00:00 2001 From: Rikko Date: Thu, 1 Sep 2022 20:37:31 +0530 Subject: [PATCH 0086/1464] Null plugin metadata for CI to correct it --- plugins/utilities.json | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/plugins/utilities.json b/plugins/utilities.json index b42718ac..a8b4e3e7 100644 --- a/plugins/utilities.json +++ b/plugins/utilities.json @@ -105,12 +105,7 @@ } ], "versions": { - "1.0.0": { - "api_version": 7, - "commit_sha": "f01323d", - "released_on": "31-08-2022", - "md5sum": "eb93f3df040261f73963621cb66565d3" - } + "1.0.0": null } }, "icons_keyboard": { @@ -133,4 +128,4 @@ } } } -} \ No newline at end of file +} From 8e68c6147d7bee42fc32d2865f106d998237c196 Mon Sep 17 00:00:00 2001 From: Rikko Date: Thu, 1 Sep 2022 20:40:21 +0530 Subject: [PATCH 0087/1464] Correct JSON --- plugins/utilities.json | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/plugins/utilities.json b/plugins/utilities.json index a8b4e3e7..8583fd83 100644 --- a/plugins/utilities.json +++ b/plugins/utilities.json @@ -93,7 +93,9 @@ "commit_sha": "858030b", "released_on": "01-09-2022", "md5sum": "c024a0774f2e960dad7f633efdc3feb5" - }, + } + } + }, "easy_connect": { "description": "Can connect easily to servers by retrying automatically till you join the server.", "external_url": "", From 6eb5390a5177a705807cac95dde9e7dd648b94bf Mon Sep 17 00:00:00 2001 From: rikkolovescats Date: Thu, 1 Sep 2022 15:11:13 +0000 Subject: [PATCH 0088/1464] [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 8583fd83..b3001643 100644 --- a/plugins/utilities.json +++ b/plugins/utilities.json @@ -107,7 +107,12 @@ } ], "versions": { - "1.0.0": null + "1.0.0": { + "api_version": 7, + "commit_sha": "770a2f3", + "released_on": "01-09-2022", + "md5sum": "eb93f3df040261f73963621cb66565d3" + } } }, "icons_keyboard": { @@ -130,4 +135,4 @@ } } } -} +} \ No newline at end of file From 3a8ba07e00a2c280a4f0ce5ffa4bff46fd815307 Mon Sep 17 00:00:00 2001 From: Rikko Date: Tue, 6 Sep 2022 20:14:38 +0530 Subject: [PATCH 0089/1464] Null plugin metadata for CI to correct it --- plugins/utilities.json | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/plugins/utilities.json b/plugins/utilities.json index b3001643..8583fd83 100644 --- a/plugins/utilities.json +++ b/plugins/utilities.json @@ -107,12 +107,7 @@ } ], "versions": { - "1.0.0": { - "api_version": 7, - "commit_sha": "770a2f3", - "released_on": "01-09-2022", - "md5sum": "eb93f3df040261f73963621cb66565d3" - } + "1.0.0": null } }, "icons_keyboard": { @@ -135,4 +130,4 @@ } } } -} \ No newline at end of file +} From 2c2edee325566f19df25d69b3704252b96067309 Mon Sep 17 00:00:00 2001 From: rikkolovescats Date: Tue, 6 Sep 2022 14:45:35 +0000 Subject: [PATCH 0090/1464] [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 8583fd83..6785927c 100644 --- a/plugins/utilities.json +++ b/plugins/utilities.json @@ -107,7 +107,12 @@ } ], "versions": { - "1.0.0": null + "1.0.0": { + "api_version": 7, + "commit_sha": "3a8ba07", + "released_on": "06-09-2022", + "md5sum": "eb93f3df040261f73963621cb66565d3" + } } }, "icons_keyboard": { @@ -130,4 +135,4 @@ } } } -} +} \ No newline at end of file From 6998dedead019c33818b54c2121d9027695acbb7 Mon Sep 17 00:00:00 2001 From: Rikko Date: Thu, 8 Sep 2022 01:27:21 +0530 Subject: [PATCH 0091/1464] Release v0.1.5 --- .github/workflows/ci.yml | 4 +- CHANGELOG.md | 5 ++ plugin_manager.py | 2 +- test/auto_apply_version_metadata.py | 84 +++++++++++++++++++++++++++-- test/test_checks.py | 6 ++- 5 files changed, 93 insertions(+), 8 deletions(-) create mode 100644 CHANGELOG.md diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 18be8ddf..2feffb79 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -31,7 +31,7 @@ jobs: - name: Apply AutoPEP8 run: | autopep8 --in-place --recursive --max-line-length=100 . - - name: Apply AutoPEP8 Commit + - name: Commit AutoPEP8 uses: stefanzweifel/git-auto-commit-action@v4 with: commit_message: "[ci] auto-format" @@ -39,7 +39,7 @@ jobs: - name: Apply Version Metadata run: | python test/auto_apply_version_metadata.py $(git log --pretty=format:'%h' -n 1) - - name: Apply Version Metadata Commit + - name: Commit Version Metadata uses: stefanzweifel/git-auto-commit-action@v4 with: commit_message: "[ci] apply-version-metadata" diff --git a/CHANGELOG.md b/CHANGELOG.md new file mode 100644 index 00000000..200ad879 --- /dev/null +++ b/CHANGELOG.md @@ -0,0 +1,5 @@ +## Plugin Manager (dd-mm-yyyy) + +### 0.5.0 (08-09-2022) + +- Plugin files that export classes besides plugin or game, now work. diff --git a/plugin_manager.py b/plugin_manager.py index 2a5facca..a6b18b8d 100644 --- a/plugin_manager.py +++ b/plugin_manager.py @@ -20,7 +20,7 @@ _uiscale = ba.app.ui.uiscale -PLUGIN_MANAGER_VERSION = "0.1.4" +PLUGIN_MANAGER_VERSION = "0.1.5" REPOSITORY_URL = "http://github.com/bombsquad-community/plugin-manager" CURRENT_TAG = "main" # XXX: Using https with `ba.open_url` seems to trigger a pop-up dialog box on diff --git a/test/auto_apply_version_metadata.py b/test/auto_apply_version_metadata.py index 1ace1ce7..317c3bcf 100644 --- a/test/auto_apply_version_metadata.py +++ b/test/auto_apply_version_metadata.py @@ -6,7 +6,7 @@ import datetime -class NullVersionedPlugin: +class PluginVersionMetadata: def __init__(self, plugin_name, version_name, plugin_path, from_json={}): self.plugin_name = plugin_name self.version_name = version_name @@ -57,10 +57,18 @@ def set_md5sum(self): if versions[self.version_name] is None: versions[self.version_name] = {} - md5sum = hashlib.md5(self._content).hexdigest() + md5sum = self.calculate_md5sum() versions[self.version_name]["md5sum"] = md5sum return self + def calculate_md5sum(self): + if self._content is None: + with open(self.plugin_path, "rb") as fin: + self._content = fin.read() + + md5sum = hashlib.md5(self._content).hexdigest() + return md5sum + class CategoryVersionMetadata: def __init__(self, category_metadata_base): @@ -75,17 +83,38 @@ def get_plugins_having_null_version_values(self): plugin_metadata["versions"].items())[0] if latest_version_metadata is None: plugin_path = f"{os.path.join(self.category_metadata_base, f'{plugin_name}.py')}" - yield NullVersionedPlugin( + yield PluginVersionMetadata( plugin_name, latest_version_name, plugin_path, ) + def get_plugins_having_diff_last_md5sum_version_values(self): + for plugin_name, plugin_metadata in self.category_metadata["plugins"].items(): + latest_version_name, latest_version_metadata = tuple( + plugin_metadata["versions"].items())[0] + + plugin_path = f"{os.path.join(self.category_metadata_base, f'{plugin_name}.py')}" + plugin_version_metadata = PluginVersionMetadata( + plugin_name, + latest_version_name, + plugin_path, + ) + if plugin_version_metadata.calculate_md5sum() != latest_version_metadata["md5sum"]: + yield plugin_version_metadata + def apply_version_metadata_to_null_version_values(self, commit_sha): null_versioned_plugins = self.get_plugins_having_null_version_values() + return self.apply_metadata_to_plugins(commit_sha, null_versioned_plugins) + + def apply_version_metadata_to_last_version_values(self, commit_sha): + diff_md5sum_plugins = self.get_plugins_having_diff_last_md5sum_version_values() + return self.apply_metadata_to_plugins(commit_sha, diff_md5sum_plugins) + + def apply_metadata_to_plugins(self, commit_sha, plugins): today = datetime.date.today().strftime("%d-%m-%Y") category_json = self.category_metadata - for plugin in null_versioned_plugins: + for plugin in plugins: category_json = ( plugin.set_json(category_json) .set_api_version() @@ -106,7 +135,54 @@ def save(self, category_json): ) +class PluginManagerVersionMetadata: + def __init__(self): + with open("plugin_manager.py", "rb") as fin: + self._content = fin.read() + self.metadata_path = "index.json" + with open(self.metadata_path, "rb") as fin: + self.json = json.load(fin) + self.api_version_regexp = re.compile(b"(?<=ba_meta require api )(.*)") + + def set_api_version(self, version_name): + version = self.json["versions"][version_name] + api_version = self.api_version_regexp.search(self._content).group() + version["api_version"] = int(api_version) + + def calculate_md5sum(self): + md5sum = hashlib.md5(self._content).hexdigest() + return md5sum + + def apply_version_metadata_to_null_version_value(self, commit_sha): + today = datetime.date.today().strftime("%d-%m-%Y") + latest_version_name, latest_version_metadata = tuple( + self.json["versions"].items())[0] + + if self.json["versions"][latest_version_name] is None: + self.json["versions"][latest_version_name] = {} + version = self.json["versions"][latest_version_name] + self.set_api_version(latest_version_name) + version["commit_sha"] = commit_sha[:8] + version["released_on"] = today + version["md5sum"] = self.calculate_md5sum() + + return self.json + + def save(self, metadata): + with open(self.metadata_path, "w") as fout: + json.dump( + metadata, + fout, + indent=2, + ensure_ascii=False, + ) + + def auto_apply_version_metadata(last_commit_sha): + plugin_manager = PluginManagerVersionMetadata() + metadata = plugin_manager.apply_version_metadata_to_null_version_value(last_commit_sha) + plugin_manager.save(metadata) + utilities = CategoryVersionMetadata(os.path.join("plugins", "utilities")) category_json = utilities.apply_version_metadata_to_null_version_values(last_commit_sha) utilities.save(category_json) diff --git a/test/test_checks.py b/test/test_checks.py index 12f755b3..cddc1be1 100644 --- a/test/test_checks.py +++ b/test/test_checks.py @@ -29,7 +29,11 @@ def test_keys(self): def test_versions_order(self): versions = list(self.content["versions"].items()) - sorted_versions = sorted(versions, key=lambda version: version[0]) + sorted_versions = sorted( + versions, + key=lambda version: version[0], + reverse=True, + ) assert sorted_versions == versions def test_versions(self): From 9306bd0764caec9e78f1a6500bf0c03acececfd1 Mon Sep 17 00:00:00 2001 From: Rikko Date: Thu, 8 Sep 2022 01:28:08 +0530 Subject: [PATCH 0092/1464] Bump index.json to v0.1.5 --- index.json | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/index.json b/index.json index e4520699..75a82b64 100644 --- a/index.json +++ b/index.json @@ -1,11 +1,17 @@ { "plugin_manager_url": "http://github.com/bombsquad-community/plugin-manager/{content_type}/{tag}/plugin_manager.py", "versions": { + "0.1.5": { + "api_version": 7, + "commit_sha": "6998ded", + "released_on": "08-09-2022", + "md5sum": "d88925069a3ee73c2ea5141539b0a286" + }, "0.1.4": { - "api_version": 7, - "commit_sha": "7c4504cc1eb08670c9164ea6e1d29c60bd8b85b8", - "released_on": "05-09-2022", - "md5sum": "52e03d303e55738d3653f86fb5abe2de" + "api_version": 7, + "commit_sha": "7c4504c", + "released_on": "05-09-2022", + "md5sum": "52e03d303e55738d3653f86fb5abe2de" } }, "categories": [ @@ -14,4 +20,4 @@ "http://github.com/bombsquad-community/plugin-manager/{content_type}/{tag}/plugins/maps.json" ], "external_source_url": "http://github.com/{repository}/{content_type}/{tag}/category.json" -} +} \ No newline at end of file From 2a70e273e1e932fc83456067f55f24e10b7e938c Mon Sep 17 00:00:00 2001 From: Rikko Date: Wed, 14 Sep 2022 00:34:21 +0530 Subject: [PATCH 0093/1464] Make plugin settings to cyan color --- plugin_manager.py | 1 + 1 file changed, 1 insertion(+) diff --git a/plugin_manager.py b/plugin_manager.py index a6b18b8d..8721d388 100644 --- a/plugin_manager.py +++ b/plugin_manager.py @@ -832,6 +832,7 @@ async def draw_ui(self): size=(40, 40), button_type="square", label="", + color=(0, 0.75, 0.75), on_activate_call=self.settings) ba.imagewidget(parent=self._root_widget, position=(settings_pos_x, settings_pos_y), From abc65c4d186bfdcb36e5ef496dbbad126b485149 Mon Sep 17 00:00:00 2001 From: Rikko Date: Fri, 16 Sep 2022 02:41:58 +0530 Subject: [PATCH 0094/1464] Update README.md --- README.md | 38 +++++++++++++++++++++++++++++--------- 1 file changed, 29 insertions(+), 9 deletions(-) diff --git a/README.md b/README.md index 44c02453..57640c8e 100644 --- a/README.md +++ b/README.md @@ -2,19 +2,22 @@ # plugin-manager -A plugin manager for the game - [Bombsquad](https://www.froemling.net/apps/bombsquad). +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. +![Plugin Manager GIF](https://user-images.githubusercontent.com/106954762/190505304-519c4b91-2461-42b1-be57-655a3fb0cbe8.gif) ## Features -- [x] Fully open-source plugin manager, as well as all the plugins you'll find in this repository. -- [x] Ability to add 3rd party plugin sources (use them at your own risk, since they may not be audited!). -- [x] Only deal with plugins and plugin updates targetting your game's current API version. -- [x] Search installable plugins from this repository, as well as 3rd party sources. -- [x] Setting to enable or disable auto-updates for plugin manager as well plugins. -- [x] Setting to immediately enable installed plugins/minigames without having to restart game. -- [x] Ability to launch a plugin's settings directly from the plugin manager window. -- [x] Check out a plugin's source code before you even install it. +- [x] Completely open-source - both the plugin-manager and all the plugins in this repository. +- [x] Works on all platforms. +- [x] Only deal with plugins and updates targetting your game's current API version. +- [x] Search for plugins. +- [x] Add 3rd party plugin sources (use them at your own risk, since they may not be audited!). +- [x] Enable or disable auto-updates for plugin manager and plugins. +- [x] Immediately enable installed plugins/minigames without having to restart game. +- [x] Launch a plugin's settings directly from the plugin manager window. +- [x] Check out a plugin's source code before installing it. - [ ] Sync installed plugins with workspaces. - [ ] Sort plugins by popularity, downloads, rating or some other metric. @@ -33,6 +36,15 @@ There are two different ways the plugin manager can be installed through: will overrwrite the updated plugin manager, with the older version from workspace on the next sync. However, you can manually apply updates by copying the latest plugin manager's source code again to your workspace when using this method. + +## Usage + +- If installed correctly, you'll see the plugin manager button in your game's settings. + + + +- That's it, you now have access to a variety of community created content waiting for you to install! + ## Contributing ### Submitting a Plugin @@ -175,6 +187,14 @@ and then executing the following in the project's root directory: $ python -m unittest discover -v ``` +## Shout out! + +If you've been with the community for long enough, you may have known about the amazing +[Mrmaxmeier's mod manager](https://github.com/Mrmaxmeier/BombSquad-Community-Mod-Manager), which unfortunately wasn't +maintained and failed to keep up with the game's latest versions and API changes. Well, this is another attempt to +create something similar, with a hope we as a community can continue to keep it up-to-date with the original game. + + ## License - [Plugin manager's source code](plugin_manager.py) is licensed under the MIT license. See [LICENSE](LICENSE) for more From c48ad15ca537f4df59e28a89b6d4c54abc07f14f Mon Sep 17 00:00:00 2001 From: Rikko Date: Fri, 16 Sep 2022 03:59:44 +0530 Subject: [PATCH 0095/1464] Remove some debug prints --- plugin_manager.py | 21 --------------------- 1 file changed, 21 deletions(-) diff --git a/plugin_manager.py b/plugin_manager.py index 8721d388..85a43798 100644 --- a/plugin_manager.py +++ b/plugin_manager.py @@ -2089,24 +2089,3 @@ def on_app_running(self) -> None: startup_tasks = StartupTasks() loop = asyncio.get_event_loop() loop.create_task(startup_tasks.execute()) - # loop = asyncio.get_event_loop() - # loop.create_task(do()) - # pm = PluginManager() - # pm.plugin_index() - - def on_app_pause(self) -> None: - """Called after pausing game activity.""" - print("pause") - - def on_app_resume(self) -> None: - """Called after the game continues.""" - print("resume") - - def on_app_shutdown(self) -> None: - """Called before closing the application.""" - print("shutdown") - # print(ba.app.config["Community Plugin Manager"]) - # with open(_env["config_file_path"], "r") as fin: - # c = fin.read() - # import json - # print(json.loads(c)["Community Plugin Manager"]) From eee2047add3ba8e17e534499bc89a32515b65a0d Mon Sep 17 00:00:00 2001 From: Rikko Date: Fri, 16 Sep 2022 04:00:20 +0530 Subject: [PATCH 0096/1464] Release v0.1.6 --- index.json | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/index.json b/index.json index 75a82b64..8cac22bf 100644 --- a/index.json +++ b/index.json @@ -1,6 +1,7 @@ { "plugin_manager_url": "http://github.com/bombsquad-community/plugin-manager/{content_type}/{tag}/plugin_manager.py", "versions": { + "0.1.6": null, "0.1.5": { "api_version": 7, "commit_sha": "6998ded", @@ -20,4 +21,4 @@ "http://github.com/bombsquad-community/plugin-manager/{content_type}/{tag}/plugins/maps.json" ], "external_source_url": "http://github.com/{repository}/{content_type}/{tag}/category.json" -} \ No newline at end of file +} From 56e0f23282eacdc9ed4e327817bf6288f496431d Mon Sep 17 00:00:00 2001 From: rikkolovescats Date: Thu, 15 Sep 2022 22:31:18 +0000 Subject: [PATCH 0097/1464] [ci] apply-version-metadata --- index.json | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/index.json b/index.json index 8cac22bf..dfb0eef0 100644 --- a/index.json +++ b/index.json @@ -1,7 +1,12 @@ { "plugin_manager_url": "http://github.com/bombsquad-community/plugin-manager/{content_type}/{tag}/plugin_manager.py", "versions": { - "0.1.6": null, + "0.1.6": { + "api_version": 7, + "commit_sha": "eee2047", + "released_on": "15-09-2022", + "md5sum": "5b4ffdc55edae0d53f71ae8b723be731" + }, "0.1.5": { "api_version": 7, "commit_sha": "6998ded", @@ -21,4 +26,4 @@ "http://github.com/bombsquad-community/plugin-manager/{content_type}/{tag}/plugins/maps.json" ], "external_source_url": "http://github.com/{repository}/{content_type}/{tag}/category.json" -} +} \ No newline at end of file From 2a7ad8e49728da7bec57c0a01654a8750b3a1605 Mon Sep 17 00:00:00 2001 From: Rikko Date: Fri, 16 Sep 2022 04:03:59 +0530 Subject: [PATCH 0098/1464] Bump to v0.1.6 --- index.json | 9 ++------- plugin_manager.py | 2 +- 2 files changed, 3 insertions(+), 8 deletions(-) diff --git a/index.json b/index.json index dfb0eef0..8cac22bf 100644 --- a/index.json +++ b/index.json @@ -1,12 +1,7 @@ { "plugin_manager_url": "http://github.com/bombsquad-community/plugin-manager/{content_type}/{tag}/plugin_manager.py", "versions": { - "0.1.6": { - "api_version": 7, - "commit_sha": "eee2047", - "released_on": "15-09-2022", - "md5sum": "5b4ffdc55edae0d53f71ae8b723be731" - }, + "0.1.6": null, "0.1.5": { "api_version": 7, "commit_sha": "6998ded", @@ -26,4 +21,4 @@ "http://github.com/bombsquad-community/plugin-manager/{content_type}/{tag}/plugins/maps.json" ], "external_source_url": "http://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 85a43798..399482c6 100644 --- a/plugin_manager.py +++ b/plugin_manager.py @@ -20,7 +20,7 @@ _uiscale = ba.app.ui.uiscale -PLUGIN_MANAGER_VERSION = "0.1.5" +PLUGIN_MANAGER_VERSION = "0.1.6" REPOSITORY_URL = "http://github.com/bombsquad-community/plugin-manager" CURRENT_TAG = "main" # XXX: Using https with `ba.open_url` seems to trigger a pop-up dialog box on From 6238803a536bbb290f5bbe816bdc8410ffbecc11 Mon Sep 17 00:00:00 2001 From: rikkolovescats Date: Thu, 15 Sep 2022 22:34:24 +0000 Subject: [PATCH 0099/1464] [ci] apply-version-metadata --- index.json | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/index.json b/index.json index 8cac22bf..363be828 100644 --- a/index.json +++ b/index.json @@ -1,7 +1,12 @@ { "plugin_manager_url": "http://github.com/bombsquad-community/plugin-manager/{content_type}/{tag}/plugin_manager.py", "versions": { - "0.1.6": null, + "0.1.6": { + "api_version": 7, + "commit_sha": "2a7ad8e", + "released_on": "15-09-2022", + "md5sum": "56950f6455606f7705eebd3e9a38c78f" + }, "0.1.5": { "api_version": 7, "commit_sha": "6998ded", @@ -21,4 +26,4 @@ "http://github.com/bombsquad-community/plugin-manager/{content_type}/{tag}/plugins/maps.json" ], "external_source_url": "http://github.com/{repository}/{content_type}/{tag}/category.json" -} +} \ No newline at end of file From a3c0de2a2aa40152f6da0080863ffb9dfc1d6bf3 Mon Sep 17 00:00:00 2001 From: itsre3 <105688454+itsre3@users.noreply.github.com> Date: Thu, 15 Sep 2022 23:46:11 +0100 Subject: [PATCH 0100/1464] Update README.md --- README.md | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/README.md b/README.md index 57640c8e..f7ddb9cc 100644 --- a/README.md +++ b/README.md @@ -24,7 +24,7 @@ which makes further modding of your game more convenient by providing easier acc ## Installation -There are two different ways the plugin manager can be installed through: +There are two different ways the plugin manager can be installed: 1. Download [plugin_manager.py](https://raw.githubusercontent.com/bombsquad-community/plugin-manager/main/plugin_manager.py) to your mods directory (check it out by going into your game's Settings -> Advanced -> Show Mods Folder). This is the @@ -51,8 +51,8 @@ There are two different ways the plugin manager can be installed through: - In order for a plugin to get accepted to this official repository, it must target the general game audience and be completely open and readable, not be encoded or encrypted in any form. -- If your plugin doesn't target the general game audience, you can put your plugins in a GitHub repository and then - your plugins can be installed through the custom source option in-game. +- If your plugin doesn't target the general game audience, you can put your plugin(s) in a GitHub repository and then + your plugin(s) can be installed through the custom source option in-game. See [3rd party plugin sources](#3rd-party-plugin-sources) for more information. - New plugins are accepted through a [pull request](../../compare). Add your plugin in the minigames, utilities, or the category directory you feel is the most relevant to the type of plugin you're submitting, [here](plugins). @@ -60,7 +60,7 @@ There are two different ways the plugin manager can be installed through: - Plugin manager will also show and execute the settings icon if your `ba.Plugin` export class has a method named `on_plugin_manager_prompt`; check out the [colorscheme](https://github.com/bombsquad-community/plugin-manager/blob/f24f0ca5ded427f6041795021f1af2e6a08b6ce9/plugins/utilities/colorscheme.py#L419-L420) - plugin for an example and it's behaviour when the settings icon is tapped on via the plugin manager in-game. + plugin as an example and it's behaviour when the settings icon is tapped via the plugin manager in-game. #### Example: @@ -79,7 +79,7 @@ class Main(ba.Plugin): ``` You'll have to fork this repository and add your `sample_plugin.py` plugin file into the appropriate directory, which for -utility plugins is [plugins/utilities](plugins/utilities). Now you'll have to add an entry for your plugin +utility plugin is [plugins/utilities](plugins/utilities). After that, you'll have to add an entry for your plugin in [plugins/utilities.json](plugins/utilities.json) so that it gets picked up by the Plugin Manager in-game. To do this, you'll have to edit the file and add something like this: @@ -115,7 +115,7 @@ You can add whatever you wanna add to these fields. However, leave the value for Version values will automatically be populated through github-actions (along with formatting your code as per PEP8 style guide) once you open a pull request. -Save `utilities.json` with your modified changes and now you can make us a [pull request](../../compare) with the +Save `utilities.json` with your modified changes and now you can create a [pull request](../../compare) with the plugin you've added and the modified JSON metadata file! ### Updating a Plugin @@ -125,8 +125,8 @@ plugin you've added and the modified JSON metadata file! #### Example -Continuing the example from [Submitting a Plugin](#submitting-a-plugin) section, say you also wanna add a new screenmessage -to the `sample_plugin.py` plugin after it was submitted. Edit `sample_plugin.py` with whatever changes you'd like: +Continuing the example from [Submitting a Plugin](#submitting-a-plugin) section, if you also want to add a new screenmessage +to the `sample_plugin.py` plugin after it has been submitted, edit `sample_plugin.py` with whatever changes you'd like: ```diff diff --git a/plugins/utilities/sample_plugin.py b/plugins/utilities/sample_plugin.py index ebb7dcc..da2b312 100644 @@ -167,7 +167,7 @@ That's it! Now you can make a [pull request](../../compare) with both the update - In case your plugin doesn't sit well with our guidelines or you wouldn't want your plugin to be here for some reason, you can create your own GitHub repository and put all your plugins in there. -- Check out https://github.com/rikkolovescats/sahilp-plugins for an example. You can choose to show up plugins from this +- Check out https://github.com/rikkolovescats/sahilp-plugins as an example. You can choose to show up plugins from this repository in your plugin manager by adding `rikkolovescats/sahilp-plugins` as a custom source through the category selection popup window in-game. @@ -189,7 +189,7 @@ $ python -m unittest discover -v ## Shout out! -If you've been with the community for long enough, you may have known about the amazing +If you've been with the community long enough, you may have known about the amazing [Mrmaxmeier's mod manager](https://github.com/Mrmaxmeier/BombSquad-Community-Mod-Manager), which unfortunately wasn't maintained and failed to keep up with the game's latest versions and API changes. Well, this is another attempt to create something similar, with a hope we as a community can continue to keep it up-to-date with the original game. From d2f30febbbd30620d50ba2635a4e1f60261bc9e4 Mon Sep 17 00:00:00 2001 From: itsre3 <105688454+itsre3@users.noreply.github.com> Date: Thu, 15 Sep 2022 23:54:09 +0100 Subject: [PATCH 0101/1464] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index f7ddb9cc..bae5dfd5 100644 --- a/README.md +++ b/README.md @@ -60,7 +60,7 @@ There are two different ways the plugin manager can be installed: - Plugin manager will also show and execute the settings icon if your `ba.Plugin` export class has a method named `on_plugin_manager_prompt`; check out the [colorscheme](https://github.com/bombsquad-community/plugin-manager/blob/f24f0ca5ded427f6041795021f1af2e6a08b6ce9/plugins/utilities/colorscheme.py#L419-L420) - plugin as an example and it's behaviour when the settings icon is tapped via the plugin manager in-game. + plugin as an example and its behaviour when the settings icon is tapped via the plugin manager in-game. #### Example: From 723579c9696cf6d111e15c5456c8e3e1d5c30335 Mon Sep 17 00:00:00 2001 From: Ayush Saini <36878972+imayushsaini@users.noreply.github.com> Date: Sat, 17 Sep 2022 22:06:42 +0530 Subject: [PATCH 0102/1464] added partyWindow, serverSwitch plugins --- plugins/utilities/advanced_party_window.py | 2051 ++++++++++++++++++++ plugins/utilities/server_switch.py | 561 ++++++ 2 files changed, 2612 insertions(+) create mode 100644 plugins/utilities/advanced_party_window.py create mode 100644 plugins/utilities/server_switch.py diff --git a/plugins/utilities/advanced_party_window.py b/plugins/utilities/advanced_party_window.py new file mode 100644 index 00000000..889cfd47 --- /dev/null +++ b/plugins/utilities/advanced_party_window.py @@ -0,0 +1,2051 @@ +# -*- coding: utf-8 -*- +# ba_meta require api 7 + +# AdvancedPartyWindow by Mr.Smoothy + +# build on base of plasma's modifypartywindow + +# added many features + +# discord mr.smoothy#5824 + +# https://discord.gg/ucyaesh Join BCS +# Youtube : Hey Smoothy + +# added advanced ID revealer +# live ping support for bcs + +#Made by Mr.Smoothy - Plasma Boson +version_str = "7" + +import os,urllib +import os,sys,re,json,codecs,traceback,base64 +import threading +import time,copy,datetime,shutil + +from _thread import start_new_thread + +import urllib.request + +from typing import TYPE_CHECKING, cast + +import _ba +import ba +import time +import math +import threading + +from dataclasses import dataclass +from bastd.ui.popup import PopupMenuWindow,PopupWindow +from bastd.ui.confirm import ConfirmWindow +from bastd.ui.colorpicker import ColorPickerExact + +from typing import List, Sequence, Optional, Dict, Any, Union + +import bastd.ui.party as bastd_party +cache_chat=[] +connect=_ba.connect_to_party +disconnect=_ba.disconnect_from_host +unmuted_names=[] +smo_mode=3 +f_chat=False +chatlogger=False +screenmsg=True +ip_add="127.0.0.1" +p_port=43210 +p_name="local" +current_ping = 0.0 +enable_typing = False # this will prevent auto ping to update textwidget when user actually typing chat message +import ssl +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() + + ip_add=address + p_port=port + connect(address,port,print_progress) + else: + ip_add=address + p_port=port + # print(ip_add,p_port) + connect(ip_add,port,print_progress) + + +DEBUG_SERVER_COMMUNICATION = False +DEBUG_PROCESSING = False +class PingThread(threading.Thread): + """Thread for sending out game pings.""" + + def __init__(self): + super().__init__() + + def run(self) -> None: + # pylint: disable=too-many-branches + # pylint: disable=too-many-statements + ba.app.ping_thread_count += 1 + sock: Optional[socket.socket] = None + try: + import socket + from ba.internal import get_ip_address_type + socket_type = get_ip_address_type(ip_add) + sock = socket.socket(socket_type, socket.SOCK_DGRAM) + sock.connect((ip_add,p_port)) + + accessible = False + starttime = time.time() + + # Send a few pings and wait a second for + # a response. + sock.settimeout(1) + for _i in range(3): + sock.send(b'\x0b') + result: Optional[bytes] + try: + # 11: BA_PACKET_SIMPLE_PING + result = sock.recv(10) + except Exception: + result = None + if result == b'\x0c': + # 12: BA_PACKET_SIMPLE_PONG + accessible = True + break + time.sleep(1) + ping = (time.time() - starttime) * 1000.0 + global current_ping + current_ping = round(ping,2) + except ConnectionRefusedError: + # Fine, server; sorry we pinged you. Hmph. + pass + except OSError as exc: + import errno + + # Ignore harmless errors. + if exc.errno in { + errno.EHOSTUNREACH, errno.ENETUNREACH, errno.EINVAL, + errno.EPERM, errno.EACCES + }: + pass + elif exc.errno == 10022: + # Windows 'invalid argument' error. + pass + elif exc.errno == 10051: + # Windows 'a socket operation was attempted + # to an unreachable network' error. + pass + elif exc.errno == errno.EADDRNOTAVAIL: + if self._port == 0: + # This has happened. Ignore. + pass + elif ba.do_once(): + print(f'Got EADDRNOTAVAIL on gather ping' + f' for addr {self._address}' + f' port {self._port}.') + else: + ba.print_exception( + f'Error on gather ping ' + f'(errno={exc.errno})', once=True) + except Exception: + ba.print_exception('Error on gather ping', once=True) + finally: + try: + if sock is not None: + sock.close() + except Exception: + ba.print_exception('Error on gather ping cleanup', once=True) + + ba.app.ping_thread_count -= 1 + _ba.pushcall(update_ping, from_other_thread=True) + time.sleep(4) + self.run() + + +try: + import OnlineTranslator + tranTypes = [item for item in dir(OnlineTranslator) if item.startswith("Translator_")] + if "item" in globals():del item +except:tranTypes = []#;ba.print_exception() + +RecordFilesDir = os.path.join(_ba.env()["python_directory_user"],"Configs" + os.sep) +if not os.path.exists(RecordFilesDir):os.makedirs(RecordFilesDir) + +version_str = "3.0.1" + +Current_Lang = None + +SystemEncode = sys.getfilesystemencoding() +if not isinstance(SystemEncode,str): + SystemEncode = "utf-8" + +def update_ping(): + try: + _ba.set_ping_widget_value(current_ping) + except: + with _ba.Context('ui'): + if hasattr(_ba,"ping_widget") and _ba.ping_widget.exists(): + ba.textwidget(edit=_ba.ping_widget,text="Ping:"+str(current_ping)+" ms") + +PingThread().start() + +import datetime +try: + from ba._generated.enums import TimeType +except: + from ba._enums import TimeType +class chatloggThread(): + """Thread for sending out game pings.""" + def __init__(self): + super().__init__() + self.saved_msg=[] + def run(self) -> None: + # pylint: disable=too-many-branches + # pylint: disable=too-many-statements + global chatlogger + self.timerr=ba.Timer(5.0,self.chatlogg,repeat=True,timetype=TimeType.REAL) + def chatlogg(self): + global chatlogger + chats=_ba.get_chat_messages() + for msg in chats: + if msg in self.saved_msg: + pass + else: + self.save(msg) + self.saved_msg.append(msg) + if len(self.saved_msg) > 45: + self.saved_msg.pop(0) + if chatlogger: + pass + else: + self.timerr=None + def save(self,msg): + x=str(datetime.datetime.now()) + t=open(os.path.join(_ba.env()["python_directory_user"],"Chat logged.txt"),"a+") + t.write(x+" : "+ msg +"\n") + t.close() +class mututalServerThread(): + def run(self): + self.timer=ba.Timer(10,self.checkPlayers,repeat=True,timetype=TimeType.REAL) + def checkPlayers(self): + if _ba.get_connection_to_host_info()!={}: + server_name=_ba.get_connection_to_host_info()["name"] + players=[] + for ros in _ba.get_game_roster(): + players.append(ros["display_string"]) + start_new_thread(dump_mutual_servers,(players,server_name,)) + +def dump_mutual_servers(players,server_name): + filePath = os.path.join(RecordFilesDir, "players.json") + data={} + if os.path.isfile(filePath): + f=open(filePath,"r") + data=json.load(f) + for player in players: + if player in data: + if server_name not in data[player]: + data[player].insert(0,server_name) + data[player]=data[player][:3] + else: + data[player]=[server_name] + f=open(filePath,"w") + json.dump(data,f) +mututalServerThread().run() + + +class customchatThread(): + """.""" + + def __init__(self): + super().__init__() + global cache_chat + self.saved_msg=[] + chats=_ba.get_chat_messages() + for msg in chats: #fill up old chat , to avoid old msg popup + cache_chat.append(msg) + def run(self) -> None: + # pylint: disable=too-many-branches + # pylint: disable=too-many-statements + global chatlogger + self.timerr=ba.Timer(5.0,self.chatcheck,repeat=True,timetype=TimeType.REAL) + + def chatcheck(self): + global unmuted_names + global cache_chat + chats=_ba.get_chat_messages() + for msg in chats: + if msg in cache_chat: + pass + else: + if msg.split(":")[0] in unmuted_names: + ba.screenmessage(msg,color=(0.6,0.9,0.6)) + cache_chat.append(msg) + if len(self.saved_msg) > 45: + cache_chat.pop(0) + if ba.app.config.resolve('Chat Muted'): + pass + else: + self.timerr=None + +def chatloggerstatus(): + global chatlogger + if chatlogger: + return "Turn off Chat Logger" + else: + return "Turn on chat logger" + +def _getTransText(text , isBaLstr = False , same_fb = False): + global Current_Lang + global chatlogger + if Current_Lang != 'English': + Current_Lang = 'English' + global Language_Texts + Language_Texts = { + "Chinese": { + + }, + "English": { + "Add_a_Quick_Reply": "Add a Quick Reply", + "Admin_Command_Kick_Confirm": "Are you sure to use admin\ +command to kick %s?", + "Ban_For_%d_Seconds": "Ban for %d second(s).", + "Ban_Time_Post": "Enter the time you want to ban(Seconds).", + "Credits_for_This": "Credits for This", + "Custom_Action": "Custom Action", + "Debug_for_Host_Info": "Host Info Debug", + "Game_Record_Saved": "Game replay %s is saved.", + "Kick_ID": "Kick ID:%d", + "Mention_this_guy": "Mention this guy", + "Modify_Main_Color": "Modify Main Color", + "No_valid_player_found": "Can't find a valid player.", + "No_valid_player_id_found": "Can't find a valid player ID.", + "Normal_kick_confirm": "Are you sure to kick %s?", + "Remove_a_Quick_Reply": "Remove a Quick Reply", + "Restart_Game_Record": "Save Recording", + "Restart_Game_Record_Confirm": "Are you sure to restart recording game stream?", + "Send_%d_times": "Send for %d times", + "Something_is_added": "'%s' is added.", + "Something_is_removed": "'%s' is removed.", + "Times": "Times", + "Translator": "Translator", + "chatloggeroff":"Turn off Chat Logger", + "chatloggeron":"Turn on Chat Logger", + "screenmsgoff":"Hide ScreenMessage", + "screenmsgon":"Show ScreenMessage", + "unmutethisguy":"unmute this guy", + "mutethisguy":"mute this guy", + "muteall":"Mute all", + "unmuteall":"Unmute all" + + } + } + + Language_Texts = Language_Texts.get(Current_Lang) + try: + from Language_Packs import ModifiedPartyWindow_LanguagePack as ext_lan_pack + if isinstance(ext_lan_pack,dict) and isinstance(ext_lan_pack.get(Current_Lang),dict): + complete_Pack = ext_lan_pack.get(Current_Lang) + for key,item in complete_Pack.items(): + Language_Texts[key] = item + except: + pass + + return(Language_Texts.get(text,"#Unknown Text#" if not same_fb else text) if not isBaLstr else + ba.Lstr(resource = "??Unknown??",fallback_value = Language_Texts.get(text,"#Unknown Text#" if not same_fb else text))) + +def _get_popup_window_scale() -> float: + uiscale = ba.app.ui.uiscale + return(2.3 if uiscale is ba.UIScale.SMALL else + 1.65 if uiscale is ba.UIScale.MEDIUM else 1.23) + +def _creat_Lstr_list(string_list : list = []) -> list: + return([ba.Lstr(resource = "??Unknown??",fallback_value = item) for item in string_list]) + + + + +customchatThread().run() + +class ModifiedPartyWindow(bastd_party.PartyWindow): + def __init__(self, origin: Sequence[float] = (0, 0)): + _ba.set_party_window_open(True) + self._r = 'partyWindow' + self.msg_user_selected='' + self._popup_type: Optional[str] = None + self._popup_party_member_client_id: Optional[int] = None + self._popup_party_member_is_host: Optional[bool] = None + self._width = 500 + + + uiscale = ba.app.ui.uiscale + self._height = (365 if uiscale is ba.UIScale.SMALL else + 480 if uiscale is ba.UIScale.MEDIUM else 600) + + #Custom color here + self._bg_color = ba.app.config.get("PartyWindow_Main_Color",(0.40, 0.55, 0.20)) if not isinstance(self._getCustomSets().get("Color"),(list,tuple)) else self._getCustomSets().get("Color") + if not isinstance(self._bg_color,(list,tuple)) or not len(self._bg_color) == 3:self._bg_color = (0.40, 0.55, 0.20) + + + + + ba.Window.__init__(self,root_widget=ba.containerwidget( + size=(self._width, self._height), + transition='in_scale', + color=self._bg_color, + parent=_ba.get_special_widget('overlay_stack'), + on_outside_click_call=self.close_with_sound, + scale_origin_stack_offset=origin, + scale=(2.0 if uiscale is ba.UIScale.SMALL else + 1.35 if uiscale is ba.UIScale.MEDIUM else 1.0), + stack_offset=(0, -10) if uiscale is ba.UIScale.SMALL else ( + 240, 0) if uiscale is ba.UIScale.MEDIUM else (330, 20))) + + self._cancel_button = ba.buttonwidget(parent=self._root_widget, + scale=0.7, + position=(30, self._height - 47), + size=(50, 50), + label='', + on_activate_call=self.close, + autoselect=True, + color=(0.45, 0.63, 0.15), + icon=ba.gettexture('crossOut'), + iconscale=1.2) + self._smoothy_button = ba.buttonwidget(parent=self._root_widget, + scale=0.6, + position=(5, self._height - 47 -40), + size=(50, 50), + label='69', + on_activate_call=self.smoothy_roster_changer, + autoselect=True, + color=(0.45, 0.63, 0.15), + icon=ba.gettexture('replayIcon'), + iconscale=1.2) + ba.containerwidget(edit=self._root_widget, + cancel_button=self._cancel_button) + + self._menu_button = ba.buttonwidget( + parent=self._root_widget, + scale=0.7, + position=(self._width - 60, self._height - 47), + size=(50, 50), + label="\xee\x80\x90", + autoselect=True, + button_type='square', + on_activate_call=ba.WeakCall(self._on_menu_button_press), + color=(0.55, 0.73, 0.25), + icon=ba.gettexture('menuButton'), + iconscale=1.2) + + info = _ba.get_connection_to_host_info() + if info.get('name', '') != '': + title = info['name'] + else: + title = ba.Lstr(resource=self._r + '.titleText') + + self._title_text = ba.textwidget(parent=self._root_widget, + scale=0.9, + color=(0.5, 0.7, 0.5), + text=title, + size=(120, 20), + position=(self._width * 0.5-60, + self._height - 29), + on_select_call=self.title_selected, + selectable=True, + maxwidth=self._width * 0.7, + h_align='center', + v_align='center') + + self._empty_str = ba.textwidget(parent=self._root_widget, + scale=0.75, + size=(0, 0), + position=(self._width * 0.5, + self._height - 65), + maxwidth=self._width * 0.85, + text="no one", + h_align='center', + v_align='center') + + self._scroll_width = self._width - 50 + self._scrollwidget = ba.scrollwidget(parent=self._root_widget, + size=(self._scroll_width, + self._height - 200), + position=(30, 80), + color=(0.4, 0.6, 0.3)) + self._columnwidget = ba.columnwidget(parent=self._scrollwidget, + border=2, + margin=0) + ba.widget(edit=self._menu_button, down_widget=self._columnwidget) + + self._muted_text = ba.textwidget( + parent=self._root_widget, + position=(self._width * 0.5, self._height * 0.5), + size=(0, 0), + h_align='center', + v_align='center', + text="") + self._chat_texts: List[ba.Widget] = [] + self._chat_texts_haxx: List[ba.Widget] = [] + + # add all existing messages if chat is not muted + # print("updates") + if True: #smoothy - always show chat in partywindow + msgs = _ba.get_chat_messages() + for msg in msgs: + self._add_msg(msg) + # print(msg) + # else: + # msgs=_ba.get_chat_messages() + # for msg in msgs: + # print(msg); + # txt = ba.textwidget(parent=self._columnwidget, + # text=msg, + # h_align='left', + # v_align='center', + # size=(0, 13), + # scale=0.55, + # maxwidth=self._scroll_width * 0.94, + # shadow=0.3, + # flatness=1.0) + # self._chat_texts.append(txt) + # if len(self._chat_texts) > 40: + # first = self._chat_texts.pop(0) + # first.delete() + # ba.containerwidget(edit=self._columnwidget, visible_child=txt) + self.ping_widget = txt = ba.textwidget( + parent=self._root_widget, + scale = 0.6, + size=(20, 5), + color=(0.45, 0.63, 0.15), + position=(self._width/2 -20, 50), + text='', + selectable=True, + autoselect=False, + v_align='center') + _ba.ping_widget = self.ping_widget + + def enable_chat_mode(): + pass + + self._text_field = txt = ba.textwidget( + parent=self._root_widget, + editable=True, + size=(530-80, 40), + position=(44+60, 39), + text='', + maxwidth=494, + shadow=0.3, + flatness=1.0, + description=ba.Lstr(resource=self._r + '.chatMessageText'), + autoselect=True, + v_align='center', + corner_scale=0.7) + + + # for m in _ba.get_chat_messages(): + # if m: + # ttchat=ba.textwidget( + # parent=self._columnwidget, + # size=(10,10), + # h_align='left', + # v_align='center', + # text=str(m), + # scale=0.6, + # flatness=0, + # color=(2,2,2), + # shadow=0, + # always_highlight=True + + # ) + ba.widget(edit=self._scrollwidget, + autoselect=True, + left_widget=self._cancel_button, + up_widget=self._cancel_button, + down_widget=self._text_field) + ba.widget(edit=self._columnwidget, + autoselect=True, + up_widget=self._cancel_button, + down_widget=self._text_field) + ba.containerwidget(edit=self._root_widget, selected_child=txt) + btn = ba.buttonwidget(parent=self._root_widget, + size=(50, 35), + label=ba.Lstr(resource=self._r + '.sendText'), + button_type='square', + autoselect=True, + position=(self._width - 70, 35), + on_activate_call=self._send_chat_message) + + + + def _times_button_on_click(): + # self._popup_type = "send_Times_Press" + # allow_range = 100 if _ba.get_foreground_host_session() is not None else 4 + # PopupMenuWindow(position=self._times_button.get_screen_space_center(), + # scale=_get_popup_window_scale(), + # choices=[str(index) for index in range(1,allow_range + 1)], + # choices_display=_creat_Lstr_list([_getTransText("Send_%d_times")%int(index) for index in range(1,allow_range + 1)]), + # current_choice="Share_Server_Info", + # delegate=self) + Quickreply = self._get_quick_responds() + if len(Quickreply) > 0: + PopupMenuWindow(position=self._times_button.get_screen_space_center(), + scale=_get_popup_window_scale(), + choices=Quickreply, + choices_display=_creat_Lstr_list(Quickreply), + current_choice=Quickreply[0], + delegate=self) + self._popup_type = "QuickMessageSelect" + + self._send_msg_times = 1 + + self._times_button = ba.buttonwidget(parent=self._root_widget, + size=(50, 35), + label="Quick", + button_type='square', + autoselect=True, + position=(30, 35), + on_activate_call=_times_button_on_click) + + ba.textwidget(edit=txt, on_return_press_call=btn.activate) + self._name_widgets: List[ba.Widget] = [] + self._roster: Optional[List[Dict[str, Any]]] = None + + self.smoothy_mode=1 + self.full_chat_mode=False + self._update_timer = ba.Timer(1.0, + ba.WeakCall(self._update), + repeat=True, + timetype=ba.TimeType.REAL) + + self._update() + def title_selected(self): + + self.full_chat_mode= self.full_chat_mode ==False + self._update() + def smoothy_roster_changer(self): + + self.smoothy_mode=(self.smoothy_mode+1)%3 + + + + self._update() + + def on_chat_message(self, msg: str) -> None: + """Called when a new chat message comes through.""" + # print("on_chat"+msg) + if True: + self._add_msg(msg) + def _on_chat_press(self,msg,widget): + global unmuted_names + if msg.split(":")[0] in unmuted_names: + + choices=['mute'] + choices_display=[_getTransText("mutethisguy",isBaLstr = True)] + else: + choices=['unmute'] + choices_display=[_getTransText("unmutethisguy",isBaLstr = True)] + PopupMenuWindow(position=widget.get_screen_space_center(), + scale=_get_popup_window_scale(), + choices=choices, + choices_display=choices_display, + current_choice="@ this guy", + delegate=self) + self.msg_user_selected=msg.split(":")[0] + self._popup_type = "chatmessagepress" + + # _ba.chatmessage("pressed") + + + def _add_msg(self, msg: str) -> None: + try: + if ba.app.config.resolve('Chat Muted'): + + + txt = ba.textwidget(parent=self._columnwidget, + text=msg, + h_align='left', + v_align='center', + size=(130, 13), + scale=0.55, + position=(-0.6,0), + selectable=True, + click_activate=True, + maxwidth=self._scroll_width * 0.94, + shadow=0.3, + flatness=1.0) + ba.textwidget(edit=txt, + on_activate_call=ba.Call( + self._on_chat_press, + msg,txt)) + else: + txt = ba.textwidget(parent=self._columnwidget, + text=msg, + h_align='left', + v_align='center', + size=(0, 13), + scale=0.55, + + + + maxwidth=self._scroll_width * 0.94, + shadow=0.3, + flatness=1.0) + + # btn = ba.buttonwidget(parent=self._columnwidget, + # scale=0.7, + # size=(100,20), + # label="smoothy buttin", + # icon=ba.gettexture('replayIcon'), + # texture=None, + # ) + self._chat_texts_haxx.append(txt) + if len(self._chat_texts_haxx) > 40: + first = self._chat_texts_haxx.pop(0) + first.delete() + ba.containerwidget(edit=self._columnwidget, visible_child=txt) + except Exception: + pass + + def _add_msg_when_muted(self, msg: str) -> None: + + txt = ba.textwidget(parent=self._columnwidget, + text=msg, + h_align='left', + v_align='center', + size=(0, 13), + scale=0.55, + maxwidth=self._scroll_width * 0.94, + shadow=0.3, + flatness=1.0) + self._chat_texts.append(txt) + if len(self._chat_texts) > 40: + first = self._chat_texts.pop(0) + first.delete() + ba.containerwidget(edit=self._columnwidget, visible_child=txt) + def color_picker_closing(self, picker) -> None: + ba._appconfig.commit_app_config() + def color_picker_selected_color(self, picker, color) -> None: + #bs.animateArray(self._root_widget,"color",3,{0:self._bg_color,1500:color}) + ba.containerwidget(edit=self._root_widget,color=color) + self._bg_color = color + ba.app.config["PartyWindow_Main_Color"] = color + def _on_nick_rename_press(self,arg) -> None: + + ba.containerwidget(edit=self._root_widget, transition='out_scale') + c_width = 600 + c_height = 250 + uiscale = ba.app.ui.uiscale + self._nick_rename_window = cnt = ba.containerwidget( + + scale=(1.8 if uiscale is ba.UIScale.SMALL else + 1.55 if uiscale is ba.UIScale.MEDIUM else 1.0), + size=(c_width, c_height), + transition='in_scale') + + ba.textwidget(parent=cnt, + size=(0, 0), + h_align='center', + v_align='center', + text='Enter nickname', + maxwidth=c_width * 0.8, + position=(c_width * 0.5, c_height - 60)) + id=self._get_nick(arg) + self._player_nick_text = txt89 = ba.textwidget( + parent=cnt, + size=(c_width * 0.8, 40), + h_align='left', + v_align='center', + text=id, + editable=True, + description='Players nick name', + position=(c_width * 0.1, c_height - 140), + autoselect=True, + maxwidth=c_width * 0.7, + max_chars=200) + cbtn = ba.buttonwidget( + parent=cnt, + label=ba.Lstr(resource='cancelText'), + on_activate_call=ba.Call( + lambda c: ba.containerwidget(edit=c, transition='out_scale'), + cnt), + size=(180, 60), + position=(30, 30), + autoselect=True) + okb = ba.buttonwidget(parent=cnt, + label='Rename', + size=(180, 60), + position=(c_width - 230, 30), + on_activate_call=ba.Call( + self._add_nick,arg), + autoselect=True) + ba.widget(edit=cbtn, right_widget=okb) + ba.widget(edit=okb, left_widget=cbtn) + ba.textwidget(edit=txt89, on_return_press_call=okb.activate) + ba.containerwidget(edit=cnt, cancel_button=cbtn, start_button=okb) + def _add_nick(self,arg): + config = ba.app.config + new_name_raw = cast(str, ba.textwidget(query=self._player_nick_text)) + if arg: + if not isinstance(config.get('players nick'), dict): + config['players nick'] = {} + config['players nick'][arg] = new_name_raw + config.commit() + ba.containerwidget(edit=self._nick_rename_window, + transition='out_scale') + # ba.containerwidget(edit=self._root_widget,transition='in_scale') + def _get_nick(self,id): + config=ba.app.config + if not isinstance(config.get('players nick'), dict): + return "add nick" + elif id in config['players nick']: + return config['players nick'][id] + else: + return "add nick" + + def _reset_game_record(self) -> None: + try: + dir_path = _ba.get_replays_dir();curFilePath = os.path.join(dir_path+os.sep,"__lastReplay.brp").encode(SystemEncode) + newFileName = str(ba.Lstr(resource="replayNameDefaultText").evaluate()+" (%s)"%(datetime.datetime.strftime(datetime.datetime.now(),"%Y_%m_%d_%H_%M_%S"))+".brp") + newFilePath = os.path.join(dir_path+os.sep,newFileName).encode(SystemEncode) + #print(curFilePath, newFilePath) + #os.rename(curFilePath,newFilePath) + shutil.copyfile(curFilePath, newFilePath) + _ba.reset_game_activity_tracking() + ba.screenmessage(_getTransText("Game_Record_Saved")%newFileName,color = (1,1,1)) + except:ba.print_exception();ba.screenmessage(ba.Lstr(resource="replayWriteErrorText").evaluate()+"\ +"+traceback.format_exc(),color = (1,0,0)) + def _on_menu_button_press(self) -> None: + is_muted = ba.app.config.resolve('Chat Muted') + global chatlogger + choices = ["unmute" if is_muted else "mute","screenmsg","addQuickReply","removeQuickReply","chatlogger","credits"] + DisChoices = [_getTransText("unmuteall",isBaLstr = True) if is_muted else _getTransText("muteall",isBaLstr = True), + _getTransText("screenmsgoff",isBaLstr = True) if screenmsg else _getTransText("screenmsgon",isBaLstr = True), + + _getTransText("Add_a_Quick_Reply",isBaLstr = True), + _getTransText("Remove_a_Quick_Reply",isBaLstr = True), + _getTransText("chatloggeroff",isBaLstr = True) if chatlogger else _getTransText("chatloggeron",isBaLstr = True), + _getTransText("Credits_for_This",isBaLstr = True) + ] + + if len(tranTypes) > 0 : + choices.append("translator");DisChoices.append(_getTransText("Translator",isBaLstr = True)) + + choices.append("resetGameRecord") + DisChoices.append(_getTransText("Restart_Game_Record",isBaLstr = True)) + if self._getCustomSets().get("Enable_HostInfo_Debug",False): + choices.append("hostInfo_Debug");DisChoices.append(_getTransText("Debug_for_Host_Info",isBaLstr = True)) + + PopupMenuWindow( + position=self._menu_button.get_screen_space_center(), + scale=_get_popup_window_scale(), + choices=choices, + choices_display=DisChoices, + current_choice="unmute" if is_muted else "mute", delegate=self) + self._popup_type = "menu" + def _on_party_member_press(self, client_id: int, is_host: bool, + widget: ba.Widget) -> None: + # if we"re the host, pop up "kick" options for all non-host members + if _ba.get_foreground_host_session() is not None: + kick_str = ba.Lstr(resource="kickText") + else:kick_str = ba.Lstr(resource="kickVoteText") + choices = ["kick","@ this guy","info","adminkick"] + + choices_display = [kick_str,_getTransText("Mention_this_guy",isBaLstr = True),ba.Lstr(resource="??Unknown??",fallback_value="Info"), + ba.Lstr(resource = "??Unknown??",fallback_value = _getTransText("Kick_ID")%client_id)] + + try: + if len(self._getCustomSets().get("partyMemberPress_Custom") if isinstance(self._getCustomSets().get("partyMemberPress_Custom"),dict) else {}) > 0: + choices.append("customAction");choices_display.append(_getTransText("Custom_Action",isBaLstr = True)) + except:ba.print_exception() + + + + PopupMenuWindow(position=widget.get_screen_space_center(), + scale=_get_popup_window_scale(), + choices=choices, + choices_display=choices_display, + current_choice="@ this guy", + delegate=self) + self._popup_party_member_client_id = client_id + self._popup_party_member_is_host = is_host + self._popup_type = "partyMemberPress" + + def _send_chat_message(self) -> None: + sendtext = ba.textwidget(query=self._text_field) + if sendtext==".ip": + _ba.chatmessage("IP "+ip_add+" PORT "+str(p_port)) + + ba.textwidget(edit=self._text_field,text="") + return + elif sendtext==".info": + if _ba.get_connection_to_host_info() == {}: + s_build=0 + else: + s_build = _ba.get_connection_to_host_info()['build_number'] + s_v="0" + if s_build <=14365: + s_v=" 1.4.148 or below" + elif s_build <=14377: + s_v="1.4.148 < x < = 1.4.155 " + elif s_build>=20001 and s_build < 20308: + s_v ="1.5" + elif s_build >= 20308 and s_build < 20591: + s_v="1.6 " + else: + s_v ="1.7 and above " + _ba.chatmessage("script version "+s_v+"- build "+str(s_build)) + ba.textwidget(edit=self._text_field,text="") + return + elif sendtext==".ping disabled": + PingThread(ip_add, p_port).start() + ba.textwidget(edit=self._text_field,text="") + return + elif sendtext==".save": + info = _ba.get_connection_to_host_info() + config = ba.app.config + if info.get('name', '') != '': + title = info['name'] + if not isinstance(config.get('Saved Servers'), dict): + config['Saved Servers'] = {} + config['Saved Servers'][f'{ip_add}@{p_port}'] = { + 'addr': ip_add, + 'port': p_port, + 'name': title + } + config.commit() + ba.screenmessage("Server saved to manual") + ba.playsound(ba.getsound('gunCocking')) + ba.textwidget(edit=self._text_field,text="") + return + # elif sendtext != "": + # for index in range(getattr(self,"_send_msg_times",1)): + if '\\' in sendtext: + sendtext = sendtext.replace('\\d', ('\ue048')) + sendtext = sendtext.replace('\\c', ('\ue043')) + sendtext = sendtext.replace('\\h', ('\ue049')) + sendtext = sendtext.replace('\\s', ('\ue046')) + sendtext = sendtext.replace('\\n', ('\ue04b')) + sendtext = sendtext.replace('\\f', ('\ue04f')) + sendtext = sendtext.replace('\\g', ('\ue027')) + sendtext = sendtext.replace('\\i', ('\ue03a')) + sendtext = sendtext.replace('\\m', ('\ue04d')) + sendtext = sendtext.replace('\\t', ('\ue01f')) + sendtext = sendtext.replace('\\bs', ('\ue01e')) + sendtext = sendtext.replace('\\j', ('\ue010')) + sendtext = sendtext.replace('\\e', ('\ue045')) + sendtext = sendtext.replace('\\l', ('\ue047')) + sendtext = sendtext.replace('\\a', ('\ue020')) + sendtext = sendtext.replace('\\b', ('\ue00c')) + if sendtext=="": + sendtext=" " + msg=sendtext + msg1=msg.split(" ") + ms2="" + if(len(msg1)>11): + hp=int(len(msg1)/2) + + for m in range (0,hp): + ms2=ms2+" "+msg1[m] + + _ba.chatmessage(ms2) + + ms2="" + for m in range (hp,len(msg1)): + ms2=ms2+" "+msg1[m] + _ba.chatmessage(ms2) + else: + _ba.chatmessage(msg) + + ba.textwidget(edit=self._text_field,text="") + # else: + # Quickreply = self._get_quick_responds() + # if len(Quickreply) > 0: + # PopupMenuWindow(position=self._text_field.get_screen_space_center(), + # scale=_get_popup_window_scale(), + # choices=Quickreply, + # choices_display=_creat_Lstr_list(Quickreply), + # current_choice=Quickreply[0], + # delegate=self) + # self._popup_type = "QuickMessageSelect" + # else: + # _ba.chatmessage(sendtext) + # ba.textwidget(edit=self._text_field,text="") + def _get_quick_responds(self): + if not hasattr(self,"_caches") or not isinstance(self._caches,dict):self._caches = {} + try: + filePath = os.path.join(RecordFilesDir,"Quickmessage.txt") + + if os.path.exists(RecordFilesDir) is not True: + os.makedirs(RecordFilesDir) + + if not os.path.isfile(filePath): + with open(filePath,"wb") as writer: + writer.write(({"Chinese":u"\xe5\x8e\x89\xe5\xae\xb3\xef\xbc\x8c\xe8\xbf\x98\xe6\x9c\x89\xe8\xbf\x99\xe7\xa7\x8d\xe9\xaa\x9a\xe6\x93\x8d\xe4\xbd\x9c!\ +\xe4\xbd\xa0\xe2\x84\xa2\xe8\x83\xbd\xe5\x88\xab\xe6\x89\x93\xe9\x98\x9f\xe5\x8f\x8b\xe5\x90\x97\xef\xbc\x9f\ +\xe5\x8f\xaf\xe4\xbb\xa5\xe5\x95\x8a\xe5\xb1\x85\xe7\x84\xb6\xe8\x83\xbd\xe8\xbf\x99\xe4\xb9\x88\xe7\x8e\xa9\xef\xbc\x9f"}.get(Current_Lang,"What the hell?\nDude that's amazing!")).encode("UTF-8")) + if os.path.getmtime(filePath) != self._caches.get("Vertify_Quickresponse_Text"): + with open(filePath,"rU", encoding = "UTF-8-sig") as Reader: + Text = Reader.read() + if Text.startswith(str(codecs.BOM_UTF8)): + Text = Text[3:] + self._caches["quickReplys"] = (Text).split("\\n") + self._caches["Vertify_Quickresponse_Text"] = os.path.getmtime(filePath) + return(self._caches.get("quickReplys",[])) + except:ba.print_exception();ba.screenmessage(ba.Lstr(resource="errorText"),(1,0,0));ba.playsound(ba.getsound("error")) + def _write_quick_responds(self,data): + try: + with open(os.path.join(RecordFilesDir,"Quickmessage.txt"),"wb") as writer: + writer.write("\\n".join(data).encode("utf-8")) + except:ba.print_exception();ba.screenmessage(ba.Lstr(resource="errorText"),(1,0,0));ba.playsound(ba.getsound("error")) + def _getCustomSets(self): + try: + if not hasattr(self,"_caches") or not isinstance(self._caches,dict):self._caches = {} + try: + from VirtualHost import MainSettings + if MainSettings.get("Custom_PartyWindow_Sets",{}) != self._caches.get("PartyWindow_Sets",{}): + self._caches["PartyWindow_Sets"] = MainSettings.get("Custom_PartyWindow_Sets",{}) + except: + try: + filePath = os.path.join(RecordFilesDir,"Settings.json") + if os.path.isfile(filePath): + if os.path.getmtime(filePath) != self._caches.get("Vertify_MainSettings.json_Text"): + with open(filePath,"rU", encoding = "UTF-8-sig") as Reader: + Text = Reader.read() + if Text.startswith(str(codecs.BOM_UTF8)): + Text = Text[3:] + self._caches["PartyWindow_Sets"] = json.loads(Text.decode("utf-8")).get("Custom_PartyWindow_Sets",{}) + self._caches["Vertify_MainSettings.json_Text"] = os.path.getmtime(filePath) + except:ba.print_exception() + return(self._caches.get("PartyWindow_Sets") if isinstance(self._caches.get("PartyWindow_Sets"),dict) else {}) + + except:ba.print_exception() + def _getObjectByID(self,type = "playerName",ID = None): + if ID is None:ID = self._popup_party_member_client_id + type = type.lower();output = [] + for roster in self._roster: + if type.startswith("all"): + if type in ("roster","fullrecord"):output += [roster] + elif type.find("player") != -1 and roster["players"] != []: + if type.find("namefull") != -1:output += [(i["name_full"]) for i in roster["players"]] + elif type.find("name") != -1:output += [(i["name"]) for i in roster["players"]] + elif type.find("playerid") != -1:output += [i["id"] for i in roster["players"]] + elif type.lower() in ("account","displaystring"):output += [(roster["display_string"])] + elif roster["client_id"] == ID and not type.startswith("all"): + try: + if type in ("roster","fullrecord"):return(roster) + elif type.find("player") != -1 and roster["players"] != []: + if len(roster["players"]) == 1 or type.find("singleplayer") != -1: + if type.find("namefull") != -1:return((roster["players"][0]["name_full"])) + elif type.find("name") != -1:return((roster["players"][0]["name"])) + elif type.find("playerid") != -1:return(roster["players"][0]["id"]) + else: + if type.find("namefull") != -1:return([(i["name_full"]) for i in roster["players"]]) + elif type.find("name") != -1:return([(i["name"]) for i in roster["players"]]) + elif type.find("playerid") != -1:return([i["id"] for i in roster["players"]]) + elif type.lower() in ("account","displaystring"):return((roster["display_string"])) + except:ba.print_exception() + + return(None if len(output) == 0 else output) + def _edit_text_msg_box(self,text,type = "rewrite"): + if not isinstance(type,str) or not isinstance(text,str):return + type = type.lower();text = (text) + if type.find("add") != -1:ba.textwidget(edit=self._text_field,text=ba.textwidget(query=self._text_field)+text) + else:ba.textwidget(edit=self._text_field,text=text) + def _send_admin_kick_command(self):_ba.chatmessage("/kick " + str(self._popup_party_member_client_id)) + def new_input_window_callback(self,got_text, flag, code): + if got_text: + if flag.startswith("Host_Kick_Player:"): + try: + result = _ba.disconnect_client(self._popup_party_member_client_id, ban_time=int(code)) + if not result: + ba.playsound(ba.getsound('error')) + ba.screenmessage( + ba.Lstr(resource='getTicketsWindow.unavailableText'), + color=(1, 0, 0)) + except: + ba.playsound(ba.getsound('error')) + print(traceback.format_exc()) + + + def _kick_selected_player(self): + """ + result = _ba._disconnectClient(self._popup_party_member_client_id,banTime) + if not result: + ba.playsound(ba.getsound("error")) + ba.screenmessage(ba.Lstr(resource="getTicketsWindow.unavailableText"),color=(1,0,0)) + """ + if self._popup_party_member_client_id != -1: + if _ba.get_foreground_host_session() is not None: + self._popup_type = "banTimePress" + choices = [0,30,60,120,300,600,900,1800,3600,7200,99999999] if not (isinstance(self._getCustomSets().get("Ban_Time_List"),list) + and all([isinstance(item,int) for item in self._getCustomSets().get("Ban_Time_List")])) else self._getCustomSets().get("Ban_Time_List") + PopupMenuWindow(position=self.get_root_widget().get_screen_space_center(), + scale=_get_popup_window_scale(), + choices=[str(item) for item in choices], + choices_display=_creat_Lstr_list([_getTransText("Ban_For_%d_Seconds")%item for item in choices]), + current_choice="Share_Server_Info", + delegate=self) + """ + NewInputWindow(origin_widget = self.get_root_widget(), + delegate = self,post_text = _getTransText("Ban_Time_Post"), + default_code = "300",flag = "Host_Kick_Player:"+str(self._popup_party_member_client_id)) + """ + else: + # kick-votes appeared in build 14248 + if (_ba.get_connection_to_host_info().get('build_number', 0) < + 14248): + ba.playsound(ba.getsound('error')) + ba.screenmessage( + ba.Lstr(resource='getTicketsWindow.unavailableText'), + color=(1, 0, 0)) + else: + + # Ban for 5 minutes. + result = _ba.disconnect_client(self._popup_party_member_client_id, ban_time=5 * 60) + if not result: + ba.playsound(ba.getsound('error')) + ba.screenmessage( + ba.Lstr(resource='getTicketsWindow.unavailableText'), + color=(1, 0, 0)) + else: + ba.playsound(ba.getsound('error')) + ba.screenmessage( + ba.Lstr(resource='internal.cantKickHostError'), + color=(1, 0, 0)) + + #NewShareCodeWindow(origin_widget=self.get_root_widget(), delegate=None,code = "300",execText = u"_ba._disconnectClient(%d,{Value})"%self._popup_party_member_client_id) + def joinbombspot(self): + import random + url=['https://discord.gg/CbxhJTrRta','https://discord.gg/ucyaesh'] + ba.open_url(url[random.randint(0,1)]) + def _update(self) -> None: + # pylint: disable=too-many-locals + # pylint: disable=too-many-branches + # pylint: disable=too-many-statements + # pylint: disable=too-many-nested-blocks + + # # update muted state + # if ba.app.config.resolve('Chat Muted'): + # ba.textwidget(edit=self._muted_text, color=(1, 1, 1, 0.3)) + # # clear any chat texts we're showing + # if self._chat_texts: + # while self._chat_texts: + # first = self._chat_texts.pop() + # first.delete() + # else: + # ba.textwidget(edit=self._muted_text, color=(1, 1, 1, 0.0)) + + # update roster section + + roster = _ba.get_game_roster() + global f_chat + global smo_mode + if roster != self._roster or smo_mode!=self.smoothy_mode or f_chat!=self.full_chat_mode: + self._roster = roster + smo_mode=self.smoothy_mode + f_chat=self.full_chat_mode + # clear out old + for widget in self._name_widgets: + widget.delete() + self._name_widgets = [] + + if not self._roster : + top_section_height = 60 + ba.textwidget(edit=self._empty_str, + text=ba.Lstr(resource=self._r + '.emptyText')) + ba.scrollwidget(edit=self._scrollwidget, + size=(self._width - 50, + self._height - top_section_height - 110), + position=(30, 80)) + elif self.full_chat_mode: + top_section_height = 60 + ba.scrollwidget(edit=self._scrollwidget, + size=(self._width - 50, + self._height - top_section_height - 75), + position=(30, 80)) + + else: + columns = 1 if len( + self._roster) == 1 else 2 if len(self._roster) == 2 else 3 + rows = int(math.ceil(float(len(self._roster)) / columns)) + c_width = (self._width * 0.9) / max(3, columns) + c_width_total = c_width * columns + c_height = 24 + c_height_total = c_height * rows + for y in range(rows): + for x in range(columns): + index = y * columns + x + if index < len(self._roster): + t_scale = 0.65 + pos = (self._width * 0.53 - c_width_total * 0.5 + + c_width * x - 23, + self._height - 65 - c_height * y - 15) + + # if there are players present for this client, use + # their names as a display string instead of the + # client spec-string + try: + if self.smoothy_mode ==1 and self._roster[index]['players']: + # if there's just one, use the full name; + # otherwise combine short names + if len(self._roster[index] + ['players']) == 1: + p_str = self._roster[index]['players'][ + 0]['name_full'] + else: + p_str = ('/'.join([ + entry['name'] for entry in + self._roster[index]['players'] + ])) + if len(p_str) > 25: + p_str = p_str[:25] + '...' + elif self.smoothy_mode==0 : + p_str = self._roster[index][ + 'display_string'] + p_str= self._get_nick(p_str) + + else: + p_str = self._roster[index][ + 'display_string'] + + + except Exception: + ba.print_exception( + 'Error calcing client name str.') + p_str = '???' + try: + widget = ba.textwidget(parent=self._root_widget, + position=(pos[0], pos[1]), + scale=t_scale, + size=(c_width * 0.85, 30), + maxwidth=c_width * 0.85, + color=(1, 1, + 1) if index == 0 else + (1, 1, 1), + selectable=True, + autoselect=True, + click_activate=True, + text=ba.Lstr(value=p_str), + h_align='left', + v_align='center') + self._name_widgets.append(widget) + except Exception: + pass + # in newer versions client_id will be present and + # we can use that to determine who the host is. + # in older versions we assume the first client is + # host + if self._roster[index]['client_id'] is not None: + is_host = self._roster[index][ + 'client_id'] == -1 + else: + is_host = (index == 0) + + # FIXME: Should pass client_id to these sort of + # calls; not spec-string (perhaps should wait till + # client_id is more readily available though). + try: + ba.textwidget(edit=widget, + on_activate_call=ba.Call( + self._on_party_member_press, + self._roster[index]['client_id'], + is_host, widget)) + except Exception: + pass + pos = (self._width * 0.53 - c_width_total * 0.5 + + c_width * x, + self._height - 65 - c_height * y) + + # Make the assumption that the first roster + # entry is the server. + # FIXME: Shouldn't do this. + if is_host: + twd = min( + c_width * 0.85, + _ba.get_string_width( + p_str, suppress_warning=True) * + t_scale) + try: + self._name_widgets.append( + ba.textwidget( + parent=self._root_widget, + position=(pos[0] + twd + 1, + pos[1] - 0.5), + size=(0, 0), + h_align='left', + v_align='center', + maxwidth=c_width * 0.96 - twd, + color=(0.1, 1, 0.1, 0.5), + text=ba.Lstr(resource=self._r + + '.hostText'), + scale=0.4, + shadow=0.1, + flatness=1.0)) + except Exception: + pass + try: + ba.textwidget(edit=self._empty_str, text='') + ba.scrollwidget(edit=self._scrollwidget, + size=(self._width - 50, + max(100, self._height - 139 - + c_height_total)), + position=(30, 80)) + except Exception: + pass + def hide_screen_msg(self): + file=open('ba_data/data/languages/english.json') + eng=json.loads(file.read()) + file.close() + eng['internal']['playerJoinedPartyText']='' + eng['internal']['playerLeftPartyText']='' + eng['internal']['chatBlockedText']='' + eng['kickVoteStartedText']='' + # eng['kickVoteText']='' + eng['kickWithChatText']='' + eng['kickOccurredText']='' + eng['kickVoteFailedText']='' + eng['votesNeededText']='' + eng['playerDelayedJoinText']='' + eng['playerLeftText']='' + eng['kickQuestionText']='' + file=open('ba_data/data/languages/english.json',"w") + json.dump(eng,file) + file.close() + ba.app.lang.setlanguage(None) + + def restore_screen_msg(self): + file=open('ba_data/data/languages/english.json') + eng=json.loads(file.read()) + file.close() + eng['internal']['playerJoinedPartyText']="${NAME} joined the pawri!" + eng['internal']['playerLeftPartyText']="${NAME} left the pawri." + eng['internal']['chatBlockedText']="${NAME} is chat-blocked for ${TIME} seconds." + eng['kickVoteStartedText']="A kick vote has been started for ${NAME}." + # eng['kickVoteText']='' + eng['kickWithChatText']="Type ${YES} in chat for yes and ${NO} for no." + eng['kickOccurredText']="${NAME} was kicked." + eng['kickVoteFailedText']="Kick-vote failed." + eng['votesNeededText']="${NUMBER} votes needed" + eng['playerDelayedJoinText']="${PLAYER} will enter at the start of the next round." + eng['playerLeftText']="${PLAYER} left the game." + eng['kickQuestionText']="Kick ${NAME}?" + file=open('ba_data/data/languages/english.json',"w") + json.dump(eng,file) + file.close() + ba.app.lang.setlanguage(None) + def popup_menu_selected_choice(self, popup_window: PopupMenuWindow, + choice: str) -> None: + """Called when a choice is selected in the popup.""" + global unmuted_names + if self._popup_type == "banTimePress": + result = _ba.disconnect_client(self._popup_party_member_client_id, ban_time=int(choice)) + if not result: + ba.playsound(ba.getsound('error')) + ba.screenmessage( + ba.Lstr(resource='getTicketsWindow.unavailableText'), + color=(1, 0, 0)) + elif self._popup_type == "send_Times_Press": + self._send_msg_times = int(choice) + ba.buttonwidget(edit = self._times_button,label="%s:%d"%(_getTransText("Times"),getattr(self,"_send_msg_times",1))) + + elif self._popup_type == "chatmessagepress": + if choice=="mute": + + unmuted_names.remove(self.msg_user_selected) + if choice=="unmute": + unmuted_names.append(self.msg_user_selected) + + + elif self._popup_type == "partyMemberPress": + if choice == "kick": + ConfirmWindow(text=_getTransText("Normal_kick_confirm")%self._getObjectByID("account"), + action=self._kick_selected_player, cancel_button=True, cancel_is_selected=True, + color=self._bg_color, text_scale=1.0, + origin_widget=self.get_root_widget()) + elif choice=="info": + account=self._getObjectByID("account") + + self.loading_widget= ConfirmWindow(text="Searching .....", + color=self._bg_color, text_scale=1.0,cancel_button=False, + origin_widget=self.get_root_widget()) + start_new_thread(fetchAccountInfo,(account,self.loading_widget,)) + + elif choice == "adminkick": + ConfirmWindow(text=_getTransText("Admin_Command_Kick_Confirm")%self._getObjectByID("account"), + action=self._send_admin_kick_command, cancel_button=True, cancel_is_selected=True, + color=self._bg_color, text_scale=1.0, + origin_widget=self.get_root_widget()) + + elif choice == "@ this guy": + ChoiceDis = [];NewChoices = [] + account=self._getObjectByID("account") + ChoiceDis.append(account) + temp = self._getObjectByID("playerNameFull") + if temp is not None: + if isinstance(temp,str) and temp not in ChoiceDis:ChoiceDis.append(temp) + elif isinstance(temp,(list,tuple)): + for item in temp: + if isinstance(item,str) and item not in ChoiceDis:ChoiceDis.append(item) + #print("r\\"" + + for item in ChoiceDis: + NewChoices.append(u"self._edit_text_msg_box('%s','add')"%(item.replace("'",r"'").replace('"',r'\\"'))) + + else: + nick=self._get_nick(account) + ChoiceDis.append(nick) + NewChoices.append(u"self._on_nick_rename_press('%s')"%(account)) + p = PopupMenuWindow(position=popup_window.root_widget.get_screen_space_center(), + scale=_get_popup_window_scale(), + choices=NewChoices, + choices_display=_creat_Lstr_list(ChoiceDis), + current_choice=NewChoices[0], + delegate=self) + self._popup_type = "Custom_Exec_Choice" + elif choice == "customAction": + customActionSets = self._getCustomSets() + customActionSets = customActionSets.get("partyMemberPress_Custom") if isinstance(customActionSets.get("partyMemberPress_Custom"),dict) else {} + ChoiceDis = [];NewChoices = [] + for key,item in customActionSets.items(): + ChoiceDis.append(key);NewChoices.append(item) + if len(ChoiceDis) > 0: + p = PopupMenuWindow(position=popup_window.root_widget.get_screen_space_center(), + scale=_get_popup_window_scale(), + choices=NewChoices, + choices_display=_creat_Lstr_list(ChoiceDis), + current_choice=NewChoices[0], + delegate=self) + self._popup_type = "customAction_partyMemberPress" + else:ba.playsound(ba.getsound("error"));ba.screenmessage(ba.Lstr(resource="getTicketsWindow.unavailableText"),color=(1,0,0)) + elif self._popup_type == "menu": + if choice in ("mute", "unmute"): + cfg = ba.app.config + cfg['Chat Muted'] = (choice == 'mute') + cfg.apply_and_commit() + if cfg['Chat Muted']: + customchatThread().run() + self._update() + elif choice in ("credits",): + ConfirmWindow(text="AdvancePartyWindow by Mr.Smoothy \n extended version of ModifyPartyWindow(Plasma Boson) \n Version 5.3 \n Dont modify or release the source code \n Discord : \n mr.smoothy#5824 Plasma Boson#4104", + action=self.joinbombspot, width=420,height=200, + cancel_button=False, cancel_is_selected=False, + color=self._bg_color, text_scale=1.0, ok_text="More mods >", cancel_text=None, + origin_widget=self.get_root_widget()) + elif choice =="chatlogger": + # ColorPickerExact(parent=self.get_root_widget(), position=self.get_root_widget().get_screen_space_center(), + # initial_color=self._bg_color, delegate=self, tag='') + global chatlogger + if chatlogger: + chatlogger=False + ba.screenmessage("Chat logger turned OFF") + else: + chatlogger=True + chatloggThread().run() + ba.screenmessage("Chat logger turned ON") + elif choice=='screenmsg': + global screenmsg + if screenmsg: + screenmsg=False + self.hide_screen_msg() + else: + screenmsg=True + self.restore_screen_msg() + elif choice == "addQuickReply": + try: + newReply = ba.textwidget(query=self._text_field) + data = self._get_quick_responds() + data.append(newReply) + self._write_quick_responds(data) + ba.screenmessage(_getTransText("Something_is_added")%newReply,color=(0,1,0)) + ba.playsound(ba.getsound("dingSmallHigh")) + except:ba.print_exception() + elif choice == "removeQuickReply": + Quickreply = self._get_quick_responds() + PopupMenuWindow(position=self._text_field.get_screen_space_center(), + scale=_get_popup_window_scale(), + choices=Quickreply, + choices_display=_creat_Lstr_list(Quickreply), + current_choice=Quickreply[0], + delegate=self) + self._popup_type = "removeQuickReplySelect" + elif choice in ("hostInfo_Debug",) and isinstance(_ba.get_connection_to_host_info(),dict): + if len(_ba.get_connection_to_host_info()) > 0: + #print(_ba.get_connection_to_host_info(),type(_ba.get_connection_to_host_info())) + + ChoiceDis = list(_ba.get_connection_to_host_info().keys()) + NewChoices = ["ba.screenmessage(str(_ba.get_connection_to_host_info().get('%s')))"%((str(i)).replace("'",r"'").replace('"',r'\\"')) for i in ChoiceDis] + PopupMenuWindow(position=popup_window.root_widget.get_screen_space_center(), + scale=_get_popup_window_scale(), + choices=NewChoices, + choices_display=_creat_Lstr_list(ChoiceDis), + current_choice=NewChoices[0], + delegate=self) + + self._popup_type = "Custom_Exec_Choice" + else:ba.playsound(ba.getsound("error"));ba.screenmessage(ba.Lstr(resource="getTicketsWindow.unavailableText"),color=(1,0,0)) + elif choice == "translator": + chats = _ba._getChatMessages() + if len(chats) > 0: + choices = [(item) for item in chats[::-1]] + PopupMenuWindow(position=popup_window.root_widget.get_screen_space_center(), + scale=_get_popup_window_scale(), + choices=choices, + choices_display=_creat_Lstr_list(choices), + current_choice=choices[0], + delegate=self) + self._popup_type = "translator_Press" + else:ba.playsound(ba.getsound("error"));ba.screenmessage(ba.Lstr(resource="getTicketsWindow.unavailableText"),color=(1,0,0)) + elif choice == "resetGameRecord": + ConfirmWindow(text=_getTransText("Restart_Game_Record_Confirm"), + action=self._reset_game_record, cancel_button=True, cancel_is_selected=True, + color=self._bg_color, text_scale=1.0, + origin_widget=self.get_root_widget()) + elif self._popup_type == "translator_Press": + + if len(tranTypes) == 1: + exec("start_new_thread(OnlineTranslator.%s,(u'%s',))"%(tranTypes[0],choice.replace("'",r"'").replace('"',r'\\"'))) + elif len(tranTypes) > 1: + choices = ["start_new_thread(OnlineTranslator.%s,(u'%s',))"%(item,choice.replace("'",r"'").replace('"',r'\\"')) for item in tranTypes] + + PopupMenuWindow(position=popup_window.root_widget.get_screen_space_center(), + scale=_get_popup_window_scale(), + choices=choices, + choices_display=_creat_Lstr_list(tranTypes), + current_choice=choices[0], + delegate=self) + self._popup_type = "Custom_Exec_Choice" + else:ba.playsound(ba.getsound("error"));ba.screenmessage(ba.Lstr(resource="getTicketsWindow.unavailableText"),color=(1,0,0)) + elif self._popup_type == "customAction_partyMemberPress": + + try: + keyReplaceValue = (r"{$PlayerNameFull}",r"{$PlayerName}",r"{$PlayerID}",r"{$AccountInfo}",r"{$AllPlayerName}",r"{$AllPlayerNameFull}") + pos = None;curKeyWord = None + for keyWord in keyReplaceValue: + CurPos = choice.find(keyWord) + if CurPos != -1 and (pos is None or CurPos < pos): + pos = CurPos;curKeyWord = keyWord + if isinstance(pos,int) and isinstance(curKeyWord,str): + if curKeyWord in (r"{$PlayerNameFull}",r"{$PlayerName}",r"{$AllPlayerName}",r"{$AllPlayerNameFull}"): + #if choice.count(curKeyWord) != 0: + playerName = self._getObjectByID(curKeyWord.replace("{$","").replace("}","")) + if isinstance(playerName,(list,tuple)): + ChoiceDis = [];NewChoices = [] + for i in playerName: + ChoiceDis.append(i) + NewChoices.append(choice.replace(curKeyWord,(i.replace("'",r"'").replace('"',r'\\"')),1)) + p = PopupMenuWindow(position=popup_window.root_widget.get_screen_space_center(), + scale=_get_popup_window_scale(), + choices=NewChoices, + choices_display=_creat_Lstr_list(ChoiceDis), + current_choice=NewChoices[0], + delegate=self) + self._popup_type = "customAction_partyMemberPress" + elif isinstance(playerName,str): + self.popup_menu_selected_choice(popup_window,choice.replace(curKeyWord,(playerName.replace("'",r"'").replace('"',r'\\"')),1)) + else:ba.screenmessage(_getTransText("No_valid_player_found"),(1,0,0));ba.playsound(ba.getsound("error")) + elif curKeyWord in (r"{$PlayerID}",) != 0: + playerID = self._getObjectByID("PlayerID") + playerName = self._getObjectByID("PlayerName") + #print(playerID,playerName) + if isinstance(playerID,(list,tuple)) and isinstance(playerName,(list,tuple)) and len(playerName) == len(playerID): + ChoiceDis = [];NewChoices = [] + for i1,i2 in playerName,playerID: + ChoiceDis.append(i1);NewChoices.append(choice.replace(r"{$PlayerID}",str(i2).replace("'",r"'").replace('"',r'\\"')),1) + p = PopupMenuWindow(position=popup_window.root_widget.get_screen_space_center(), + scale=_get_popup_window_scale(), + choices=NewChoices, + choices_display=_creat_Lstr_list(ChoiceDis), + current_choice=NewChoices[0], + delegate=self) + self._popup_type = "customAction_partyMemberPress" + elif isinstance(playerID,int): + self.popup_menu_selected_choice(popup_window,choice.replace(r"{$PlayerID}",str(playerID).replace("'",r"'").replace('"',r'\\"'))) + else:ba.screenmessage(_getTransText("No_valid_player_id_found"),(1,0,0));ba.playsound(ba.getsound("error")) + elif curKeyWord in (r"{$AccountInfo}",) != 0: + self.popup_menu_selected_choice(popup_window,choice.replace(r"{$AccountInfo}",(str(self._getObjectByID("roster"))).replace("'",r"'").replace('"',r'\\"'),1)) + else:exec(choice) + except Exception as e:ba.screenmessage(repr(e),(1,0,0)) + elif self._popup_type == "QuickMessageSelect": + #ba.textwidget(edit=self._text_field,text=self._get_quick_responds()[index]) + self._edit_text_msg_box(choice,"add") + elif self._popup_type == "removeQuickReplySelect": + data = self._get_quick_responds() + if len(data) > 0 and choice in data: + data.remove(choice) + self._write_quick_responds(data) + ba.screenmessage(_getTransText("Something_is_removed")%choice,(1,0,0)) + ba.playsound(ba.getsound("shieldDown")) + else:ba.screenmessage(ba.Lstr(resource="errorText"),(1,0,0));ba.playsound(ba.getsound("error")) + elif choice.startswith("custom_Exec_Choice_") or self._popup_type == "Custom_Exec_Choice": + exec(choice[len("custom_Exec_Choice_"):] if choice.startswith("custom_Exec_Choice_") else choice) + else: + print("unhandled popup type: "+str(self._popup_type)) + + +import base64 +from ba._general import Call +def fetchAccountInfo(account,loading_widget): + pbid="" + account_data=[] + servers=[] + try: + filePath = os.path.join(RecordFilesDir, "players.json") + fdata = {} + if os.path.isfile(filePath): + f = open(filePath, "r") + fdata = json.load(f) + if account in fdata: + servers=fdata[account] + data = urllib.request.urlopen(f'https://api.bombsquad.ga/player?key={base64.b64encode(account.encode("utf-8")).decode("utf-8")}&base64=true') + account_data=json.loads(data.read().decode('utf-8'))[0] + pbid=account_data["pbid"] + + except: + pass + # _ba.pushcall(Call(updateAccountWindow,loading_widget,accounts[0]),from_other_thread=True) + _ba.pushcall(Call(CustomAccountViewerWindow,pbid,account_data,servers,loading_widget),from_other_thread =True) + +from bastd.ui.account import viewer + +class CustomAccountViewerWindow(viewer.AccountViewerWindow): + def __init__(self,account_id,custom_data,servers,loading_widget): + super().__init__(account_id) + try: + loading_widget._cancel() + except: + pass + self.custom_data=custom_data + self.pb_id=account_id + self.servers=servers + def _copy_pb(self): + ba.clipboard_set_text(self.pb_id) + ba.screenmessage(ba.Lstr(resource='gatherWindow.copyCodeConfirmText')) + def _on_query_response(self,data): + + if data is None: + ba.textwidget(edit=self._loading_text,text="") + ba.textwidget(parent=self._scrollwidget, + size=(0, 0), + position=(170, 200), + flatness=1.0, + h_align='center', + v_align='center', + scale=0.5, + color=ba.app.ui.infotextcolor, + text="Mutual servers", + maxwidth=300) + v=200-21 + for server in self.servers: + ba.textwidget(parent=self._scrollwidget, + size=(0, 0), + position=(170, v), + h_align='center', + v_align='center', + scale=0.55, + text=server, + maxwidth=300) + v-=23 + else: + for account in self.custom_data["accounts"]: + if account not in data["accountDisplayStrings"]: + data["accountDisplayStrings"].append(account) + try: + self._loading_text.delete() + trophystr = '' + try: + trophystr = data['trophies'] + num = 10 + chunks = [ + trophystr[i:i + num] + for i in range(0, len(trophystr), num) + ] + trophystr = ('\n\n'.join(chunks)) + if trophystr == '': + trophystr = '-' + except Exception: + ba.print_exception('Error displaying trophies.') + account_name_spacing = 15 + tscale = 0.65 + ts_height = _ba.get_string_height(trophystr, + suppress_warning=True) + sub_width = self._width - 80 + sub_height = 500 + ts_height * tscale + \ + account_name_spacing * len(data['accountDisplayStrings']) + self._subcontainer = ba.containerwidget( + parent=self._scrollwidget, + size=(sub_width, sub_height), + background=False) + v = sub_height - 20 + + title_scale = 0.37 + center = 0.3 + maxwidth_scale = 0.45 + showing_character = False + if data['profileDisplayString'] is not None: + tint_color = (1, 1, 1) + try: + if data['profile'] is not None: + profile = data['profile'] + character = ba.app.spaz_appearances.get( + profile['character'], None) + if character is not None: + tint_color = (profile['color'] if 'color' + in profile else (1, 1, 1)) + tint2_color = (profile['highlight'] + if 'highlight' in profile else + (1, 1, 1)) + icon_tex = character.icon_texture + tint_tex = character.icon_mask_texture + mask_texture = ba.gettexture( + 'characterIconMask') + ba.imagewidget( + parent=self._subcontainer, + position=(sub_width * center - 40, v - 80), + size=(80, 80), + color=(1, 1, 1), + mask_texture=mask_texture, + texture=ba.gettexture(icon_tex), + tint_texture=ba.gettexture(tint_tex), + tint_color=tint_color, + tint2_color=tint2_color) + v -= 95 + except Exception: + ba.print_exception('Error displaying character.') + ba.textwidget( + parent=self._subcontainer, + size=(0, 0), + position=(sub_width * center, v), + h_align='center', + v_align='center', + scale=0.9, + color=ba.safecolor(tint_color, 0.7), + shadow=1.0, + text=ba.Lstr(value=data['profileDisplayString']), + maxwidth=sub_width * maxwidth_scale * 0.75) + showing_character = True + v -= 33 + + center = 0.75 if showing_character else 0.5 + maxwidth_scale = 0.45 if showing_character else 0.9 + + v = sub_height - 20 + if len(data['accountDisplayStrings']) <= 1: + account_title = ba.Lstr( + resource='settingsWindow.accountText') + else: + account_title = ba.Lstr( + resource='accountSettingsWindow.accountsText', + fallback_resource='settingsWindow.accountText') + ba.textwidget(parent=self._subcontainer, + size=(0, 0), + position=(sub_width * center, v), + flatness=1.0, + h_align='center', + v_align='center', + scale=title_scale, + color=ba.app.ui.infotextcolor, + text=account_title, + maxwidth=sub_width * maxwidth_scale) + draw_small = (showing_character + or len(data['accountDisplayStrings']) > 1) + v -= 14 if draw_small else 20 + for account_string in data['accountDisplayStrings']: + ba.textwidget(parent=self._subcontainer, + size=(0, 0), + position=(sub_width * center, v), + h_align='center', + v_align='center', + scale=0.55 if draw_small else 0.8, + text=account_string, + maxwidth=sub_width * maxwidth_scale) + v -= account_name_spacing + + v += account_name_spacing + v -= 25 if showing_character else 29 + # ======================================================================= + ba.textwidget(parent=self._subcontainer, + size=(0, 0), + position=(sub_width * center, v), + flatness=1.0, + h_align='center', + v_align='center', + scale=title_scale, + color=ba.app.ui.infotextcolor, + text=str(self.pb_id), + maxwidth=sub_width * maxwidth_scale) + self._copy_btn = ba.buttonwidget( + parent=self._subcontainer, + position=(sub_width * center -120, v -9), + size=(60, 30), + scale=0.5, + label='copy', + color=(0.6, 0.5, 0.6), + on_activate_call=self._copy_pb, + autoselect=True) + + v-=24 + ba.textwidget(parent=self._subcontainer, + size=(0, 0), + position=(sub_width * center, v), + flatness=1.0, + h_align='center', + v_align='center', + scale=title_scale, + color=ba.app.ui.infotextcolor, + text="Name", + maxwidth=sub_width * maxwidth_scale) + v-=26 + for name in self.custom_data["names"]: + ba.textwidget(parent=self._subcontainer, + size=(0, 0), + position=(sub_width * center, v), + h_align='center', + v_align='center', + scale=0.51, + text=name, + maxwidth=sub_width * maxwidth_scale) + v-=13 + v-=8 + ba.textwidget(parent=self._subcontainer, + size=(0, 0), + position=(sub_width * center, v), + flatness=1.0, + h_align='center', + v_align='center', + scale=title_scale, + color=ba.app.ui.infotextcolor, + text="Created On", + maxwidth=sub_width * maxwidth_scale) + v-=19 + d=self.custom_data["createdOn"] + + ba.textwidget(parent=self._subcontainer, + size=(0, 0), + position=(sub_width * center, v), + h_align='center', + v_align='center', + scale=0.55, + text=d[:d.index("T")], + maxwidth=sub_width * maxwidth_scale) + v-=29 + ba.textwidget(parent=self._subcontainer, + size=(0, 0), + position=(sub_width * center, v), + flatness=1.0, + h_align='center', + v_align='center', + scale=title_scale, + color=ba.app.ui.infotextcolor, + text="Discord", + maxwidth=sub_width * maxwidth_scale) + v -= 19 + if len(self.custom_data["discord"]) >0: + ba.textwidget(parent=self._subcontainer, + size=(0, 0), + position=(sub_width * center, v), + h_align='center', + v_align='center', + scale=0.55, + text=self.custom_data["discord"][0]["username"]+ ","+self.custom_data["discord"][0]["id"], + maxwidth=sub_width * maxwidth_scale) + v -= 26 + ba.textwidget(parent=self._subcontainer, + size=(0, 0), + position=(sub_width * center, v), + flatness=1.0, + h_align='center', + v_align='center', + scale=title_scale, + color=ba.app.ui.infotextcolor, + text="Mutual servers", + maxwidth=sub_width * maxwidth_scale) + v=-19 + v=270 + for server in self.servers: + ba.textwidget(parent=self._subcontainer, + size=(0, 0), + position=(sub_width * center, v), + h_align='center', + v_align='center', + scale=0.55, + text=server, + maxwidth=sub_width * maxwidth_scale) + v-=13 + + v-=16 + #================================================================== + ba.textwidget(parent=self._subcontainer, + size=(0, 0), + position=(sub_width * center, v), + flatness=1.0, + h_align='center', + v_align='center', + scale=title_scale, + color=ba.app.ui.infotextcolor, + text=ba.Lstr(resource='rankText'), + maxwidth=sub_width * maxwidth_scale) + v -= 14 + if data['rank'] is None: + rank_str = '-' + suffix_offset = None + else: + str_raw = ba.Lstr( + resource='league.rankInLeagueText').evaluate() + # FIXME: Would be nice to not have to eval this. + rank_str = ba.Lstr( + resource='league.rankInLeagueText', + subs=[('${RANK}', str(data['rank'][2])), + ('${NAME}', + ba.Lstr(translate=('leagueNames', + data['rank'][0]))), + ('${SUFFIX}', '')]).evaluate() + rank_str_width = min( + sub_width * maxwidth_scale, + _ba.get_string_width(rank_str, suppress_warning=True) * + 0.55) + + # Only tack our suffix on if its at the end and only for + # non-diamond leagues. + if (str_raw.endswith('${SUFFIX}') + and data['rank'][0] != 'Diamond'): + suffix_offset = rank_str_width * 0.5 + 2 + else: + suffix_offset = None + + ba.textwidget(parent=self._subcontainer, + size=(0, 0), + position=(sub_width * center, v), + h_align='center', + v_align='center', + scale=0.55, + text=rank_str, + maxwidth=sub_width * maxwidth_scale) + if suffix_offset is not None: + assert data['rank'] is not None + ba.textwidget(parent=self._subcontainer, + size=(0, 0), + position=(sub_width * center + suffix_offset, + v + 3), + h_align='left', + v_align='center', + scale=0.29, + flatness=1.0, + text='[' + str(data['rank'][1]) + ']') + v -= 14 + + str_raw = ba.Lstr( + resource='league.rankInLeagueText').evaluate() + old_offs = -50 + prev_ranks_shown = 0 + for prev_rank in data['prevRanks']: + rank_str = ba.Lstr( + value='${S}: ${I}', + subs=[ + ('${S}', + ba.Lstr(resource='league.seasonText', + subs=[('${NUMBER}', str(prev_rank[0]))])), + ('${I}', + ba.Lstr(resource='league.rankInLeagueText', + subs=[('${RANK}', str(prev_rank[3])), + ('${NAME}', + ba.Lstr(translate=('leagueNames', + prev_rank[1]))), + ('${SUFFIX}', '')])) + ]).evaluate() + rank_str_width = min( + sub_width * maxwidth_scale, + _ba.get_string_width(rank_str, suppress_warning=True) * + 0.3) + + # Only tack our suffix on if its at the end and only for + # non-diamond leagues. + if (str_raw.endswith('${SUFFIX}') + and prev_rank[1] != 'Diamond'): + suffix_offset = rank_str_width + 2 + else: + suffix_offset = None + ba.textwidget(parent=self._subcontainer, + size=(0, 0), + position=(sub_width * center + old_offs, v), + h_align='left', + v_align='center', + scale=0.3, + text=rank_str, + flatness=1.0, + maxwidth=sub_width * maxwidth_scale) + if suffix_offset is not None: + ba.textwidget(parent=self._subcontainer, + size=(0, 0), + position=(sub_width * center + old_offs + + suffix_offset, v + 1), + h_align='left', + v_align='center', + scale=0.20, + flatness=1.0, + text='[' + str(prev_rank[2]) + ']') + prev_ranks_shown += 1 + v -= 10 + + v -= 13 + + ba.textwidget(parent=self._subcontainer, + size=(0, 0), + position=(sub_width * center, v), + flatness=1.0, + h_align='center', + v_align='center', + scale=title_scale, + color=ba.app.ui.infotextcolor, + text=ba.Lstr(resource='achievementsText'), + maxwidth=sub_width * maxwidth_scale) + v -= 14 + ba.textwidget(parent=self._subcontainer, + size=(0, 0), + position=(sub_width * center, v), + h_align='center', + v_align='center', + scale=0.55, + text=str(data['achievementsCompleted']) + ' / ' + + str(len(ba.app.ach.achievements)), + maxwidth=sub_width * maxwidth_scale) + v -= 25 + + if prev_ranks_shown == 0 and showing_character: + v -= 20 + elif prev_ranks_shown == 1 and showing_character: + v -= 10 + + center = 0.5 + maxwidth_scale = 0.9 + + ba.textwidget(parent=self._subcontainer, + size=(0, 0), + position=(sub_width * center, v), + h_align='center', + v_align='center', + scale=title_scale, + color=ba.app.ui.infotextcolor, + flatness=1.0, + text=ba.Lstr(resource='trophiesThisSeasonText', + fallback_resource='trophiesText'), + maxwidth=sub_width * maxwidth_scale) + v -= 19 + ba.textwidget(parent=self._subcontainer, + size=(0, ts_height), + position=(sub_width * 0.5, + v - ts_height * tscale), + h_align='center', + v_align='top', + corner_scale=tscale, + text=trophystr) + + except Exception: + 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: + _ba.connect_to_party=newconnect_to_party + bastd_party.PartyWindow = ModifiedPartyWindow + else:print("AdvancePartyWindow only runs with BombSquad version equal or higher than 1.7") diff --git a/plugins/utilities/server_switch.py b/plugins/utilities/server_switch.py new file mode 100644 index 00000000..6047f299 --- /dev/null +++ b/plugins/utilities/server_switch.py @@ -0,0 +1,561 @@ + +# ba_meta require api 7 + +from __future__ import annotations +import copy +import time +from typing import TYPE_CHECKING + +import _ba +import ba +import time +import threading +from enum import Enum +from dataclasses import dataclass +if TYPE_CHECKING: + from typing import Any, Optional, Dict, List, Tuple,Type + import ba + from bastd.ui.gather import GatherWindow + +from bastd.ui.confirm import ConfirmWindow +# discord @mr.smoothy#5824 + +import bastd.ui.mainmenu as bastd_ui_mainmenu + +connect=_ba.connect_to_party +disconnect=_ba.disconnect_from_host + +server=[] + + +ip_add="private" +p_port=44444 +p_name="nothing here" +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() + + ip_add=address + p_port=port + connect(address,port,print_progress) + else: + + + ip_add=address + p_port=port + # print(ip_add,p_port) + connect(ip_add,port,print_progress) +def newdisconnect_from_host(): + try: + name=_ba.get_connection_to_host_info()['name'] + global server + global ip_add + global p_port + pojo = {"name":name,"ip":ip_add,"port":p_port} + if pojo not in server: + server.insert(0,pojo) + server = server[:3] + except: + pass + disconnect() + +def printip(): + ba.screenmessage("ip address is"+ip_add) +def new_refresh_in_game( + self, positions: List[Tuple[float, float, + float]]) -> Tuple[float, float, float]: + # pylint: disable=too-many-branches + # pylint: disable=too-many-locals + # pylint: disable=too-many-statements + custom_menu_entries: List[Dict[str, Any]] = [] + session = _ba.get_foreground_host_session() + if session is not None: + try: + custom_menu_entries = session.get_custom_menu_entries() + for cme in custom_menu_entries: + if (not isinstance(cme, dict) or 'label' not in cme + or not isinstance(cme['label'], (str, ba.Lstr)) + or 'call' not in cme or not callable(cme['call'])): + raise ValueError('invalid custom menu entry: ' + + str(cme)) + except Exception: + custom_menu_entries = [] + ba.print_exception( + f'Error getting custom menu entries for {session}') + self._width = 250.0 + self._height = 250.0 if self._input_player else 180.0 + if (self._is_demo or self._is_arcade) and self._input_player: + self._height -= 40 + if not self._have_settings_button: + self._height -= 50 + if self._connected_to_remote_player: + # In this case we have a leave *and* a disconnect button. + self._height += 50 + self._height += 50 * (len(custom_menu_entries)) + uiscale = ba.app.ui.uiscale + ba.containerwidget( + edit=self._root_widget, + size=(self._width*2, self._height), + scale=(2.15 if uiscale is ba.UIScale.SMALL else + 1.6 if uiscale is ba.UIScale.MEDIUM else 1.0)) + h = 125.0 + v = (self._height - 80.0 if self._input_player else self._height - 60) + h_offset = 0 + d_h_offset = 0 + v_offset = -50 + for _i in range(6 + len(custom_menu_entries)): + positions.append((h, v, 1.0)) + v += v_offset + h += h_offset + h_offset += d_h_offset + self._start_button = None + ba.app.pause() + h, v, scale = positions[self._p_index] + ba.textwidget( + parent=self._root_widget, + draw_controller=None, + text="IP: "+ip_add+" PORT: "+str(p_port), + position=(h+self._button_width-80,v+60), + h_align='center', + v_align='center', + size=(20, 60), + scale=0.6) + v_h=v + + global server + def con(address,port): + global ip_add + global p_port + if(address==ip_add and port==p_port): + self._resume() + else: + _ba.disconnect_from_host() + _ba.connect_to_party(address,port) + if len(server) ==0: + ba.textwidget( + parent=self._root_widget, + draw_controller=None, + text="Nothing in \n recents", + position=(h +self._button_width *scale ,v-30), + h_align='center', + v_align='center', + size=(20, 60), + scale=1) + for ser in server: + self._server_button = ba.buttonwidget( + color=(0.8, 0, 1), + parent=self._root_widget, + position=(h +self._button_width *scale - 80, v_h), + size=(self._button_width, self._button_height), + scale=scale, + autoselect=self._use_autoselect, + label=ser["name"][0:22], + + on_activate_call=ba.Call(con,ser["ip"],ser["port"])) + v_h=v_h-50 + + # Player name if applicable. + if self._input_player: + player_name = self._input_player.getname() + h, v, scale = positions[self._p_index] + v += 35 + ba.textwidget(parent=self._root_widget, + position=(h - self._button_width / 2, v), + size=(self._button_width, self._button_height), + color=(1, 1, 1, 0.5), + scale=0.7, + h_align='center', + text=ba.Lstr(value=player_name)) + else: + player_name = '' + h, v, scale = positions[self._p_index] + self._p_index += 1 + btn = ba.buttonwidget(parent=self._root_widget, + position=(h - self._button_width / 2, v), + size=(self._button_width, self._button_height), + scale=scale, + label=ba.Lstr(resource=self._r + '.resumeText'), + autoselect=self._use_autoselect, + on_activate_call=self._resume) + ba.containerwidget(edit=self._root_widget, cancel_button=btn) + + # Add any custom options defined by the current game. + for entry in custom_menu_entries: + h, v, scale = positions[self._p_index] + self._p_index += 1 + + # Ask the entry whether we should resume when we call + # it (defaults to true). + resume = bool(entry.get('resume_on_call', True)) + + if resume: + call = ba.Call(self._resume_and_call, entry['call']) + else: + call = ba.Call(entry['call'], ba.WeakCall(self._resume)) + + ba.buttonwidget(parent=self._root_widget, + position=(h - self._button_width / 2, v), + size=(self._button_width, self._button_height), + scale=scale, + on_activate_call=call, + label=entry['label'], + autoselect=self._use_autoselect) + # Add a 'leave' button if the menu-owner has a player. + if ((self._input_player or self._connected_to_remote_player) + and not (self._is_demo or self._is_arcade)): + h, v, scale = positions[self._p_index] + self._p_index += 1 + btn = ba.buttonwidget(parent=self._root_widget, + position=(h - self._button_width / 2, v), + size=(self._button_width, + self._button_height), + scale=scale, + on_activate_call=self._leave, + label='', + autoselect=self._use_autoselect) + + if (player_name != '' and player_name[0] != '<' + and player_name[-1] != '>'): + txt = ba.Lstr(resource=self._r + '.justPlayerText', + subs=[('${NAME}', player_name)]) + else: + txt = ba.Lstr(value=player_name) + ba.textwidget(parent=self._root_widget, + position=(h, v + self._button_height * + (0.64 if player_name != '' else 0.5)), + size=(0, 0), + text=ba.Lstr(resource=self._r + '.leaveGameText'), + scale=(0.83 if player_name != '' else 1.0), + color=(0.75, 1.0, 0.7), + h_align='center', + v_align='center', + draw_controller=btn, + maxwidth=self._button_width * 0.9) + ba.textwidget(parent=self._root_widget, + position=(h, v + self._button_height * 0.27), + size=(0, 0), + text=txt, + color=(0.75, 1.0, 0.7), + h_align='center', + v_align='center', + draw_controller=btn, + scale=0.45, + maxwidth=self._button_width * 0.9) + return h, v, scale +def new_refresh(self) -> None: + # pylint: disable=too-many-branches + # pylint: disable=too-many-locals + # pylint: disable=too-many-statements + global server + print(server) + from bastd.ui.confirm import QuitWindow + from bastd.ui.store.button import StoreButton + import ba + # Clear everything that was there. + children = self._root_widget.get_children() + for child in children: + child.delete() + + self._tdelay = 0.0 + self._t_delay_inc = 0.0 + self._t_delay_play = 0.0 + self._button_width = 200.0 + self._button_height = 45.0 + + self._r = 'mainMenu' + + app = ba.app + self._have_quit_button = (app.ui.uiscale is ba.UIScale.LARGE + or (app.platform == 'windows' + and app.subplatform == 'oculus')) + + self._have_store_button = not self._in_game + + self._have_settings_button = ( + (not self._in_game or not app.toolbar_test) + and not (self._is_demo or self._is_arcade or self._is_iircade)) + + self._input_device = input_device = _ba.get_ui_input_device() + self._input_player = input_device.player if input_device else None + self._connected_to_remote_player = ( + input_device.is_connected_to_remote_player() + if input_device else False) + + + positions: List[Tuple[float, float, float]] = [] + self._p_index = 0 + + if self._in_game: + h, v, scale = self._refresh_in_game(positions) + print("refreshing in GAME",ip_add) + # btn = ba.buttonwidget(parent=self._root_widget, + # position=(80,270), + # size=(100, 90), + # scale=1.2, + # label=ip_add, + # autoselect=None, + # on_activate_call=printip) + ba.textwidget( + parent=self._root_widget, + draw_controller=None, + text="IP: "+ip_add+" PORT: "+str(p_port), + position=(150,270), + h_align='center', + v_align='center', + size=(20, 60), + scale=1) + self._server_button = ba.buttonwidget( + parent=self._root_widget, + position=(h * 3.2 +20 - self._button_width * scale, v), + size=(self._button_width, self._button_height), + scale=scale, + autoselect=self._use_autoselect, + label=ba.Lstr(resource=self._r + '.settingsText'), + transition_delay=self._tdelay, + on_activate_call=self._settings) + self._server_button2 = ba.buttonwidget( + parent=self._root_widget, + position=(h * 3.2 +20 - self._button_width * scale, v-50), + size=(self._button_width, self._button_height), + scale=scale, + autoselect=self._use_autoselect, + label=ba.Lstr(resource=self._r + '.settingsText'), + transition_delay=self._tdelay, + on_activate_call=self._settings) + self._server_button3 = ba.buttonwidget( + parent=self._root_widget, + position=(h * 3.2 +20 - self._button_width * scale, v-100), + size=(self._button_width, self._button_height), + scale=scale, + autoselect=self._use_autoselect, + label=ba.Lstr(resource=self._r + '.settingsText'), + transition_delay=self._tdelay, + on_activate_call=self._settings) + + else: + h, v, scale = self._refresh_not_in_game(positions) + + if self._have_settings_button: + h, v, scale = positions[self._p_index] + self._p_index += 1 + self._settings_button = ba.buttonwidget( + parent=self._root_widget, + position=(h - self._button_width * 0.5 * scale, v), + size=(self._button_width, self._button_height), + scale=scale, + autoselect=self._use_autoselect, + label=ba.Lstr(resource=self._r + '.settingsText'), + transition_delay=self._tdelay, + on_activate_call=self._settings) + + # Scattered eggs on easter. + if _ba.get_account_misc_read_val('easter', + False) and not self._in_game: + icon_size = 34 + ba.imagewidget(parent=self._root_widget, + position=(h - icon_size * 0.5 - 15, + v + self._button_height * scale - + icon_size * 0.24 + 1.5), + transition_delay=self._tdelay, + size=(icon_size, icon_size), + texture=ba.gettexture('egg3'), + tilt_scale=0.0) + + self._tdelay += self._t_delay_inc + + if self._in_game: + h, v, scale = positions[self._p_index] + self._p_index += 1 + + # If we're in a replay, we have a 'Leave Replay' button. + if _ba.is_in_replay(): + ba.buttonwidget(parent=self._root_widget, + position=(h - self._button_width * 0.5 * scale, + v), + scale=scale, + size=(self._button_width, self._button_height), + autoselect=self._use_autoselect, + label=ba.Lstr(resource='replayEndText'), + on_activate_call=self._confirm_end_replay) + elif _ba.get_foreground_host_session() is not None: + ba.buttonwidget( + parent=self._root_widget, + position=(h - self._button_width * 0.5 * scale, v), + scale=scale, + size=(self._button_width, self._button_height), + autoselect=self._use_autoselect, + label=ba.Lstr(resource=self._r + '.endGameText'), + on_activate_call=self._confirm_end_game) + # Assume we're in a client-session. + else: + ba.buttonwidget( + parent=self._root_widget, + position=(h - self._button_width * 0.5 * scale, v), + scale=scale, + size=(self._button_width, self._button_height), + autoselect=self._use_autoselect, + label=ba.Lstr(resource=self._r + '.leavePartyText'), + on_activate_call=self._confirm_leave_party) + + self._store_button: Optional[ba.Widget] + if self._have_store_button: + this_b_width = self._button_width + h, v, scale = positions[self._p_index] + self._p_index += 1 + + sbtn = self._store_button_instance = StoreButton( + parent=self._root_widget, + position=(h - this_b_width * 0.5 * scale, v), + size=(this_b_width, self._button_height), + scale=scale, + on_activate_call=ba.WeakCall(self._on_store_pressed), + sale_scale=1.3, + transition_delay=self._tdelay) + self._store_button = store_button = sbtn.get_button() + uiscale = ba.app.ui.uiscale + icon_size = (55 if uiscale is ba.UIScale.SMALL else + 55 if uiscale is ba.UIScale.MEDIUM else 70) + ba.imagewidget( + parent=self._root_widget, + position=(h - icon_size * 0.5, + v + self._button_height * scale - icon_size * 0.23), + transition_delay=self._tdelay, + size=(icon_size, icon_size), + texture=ba.gettexture(self._store_char_tex), + tilt_scale=0.0, + draw_controller=store_button) + + self._tdelay += self._t_delay_inc + else: + self._store_button = None + + self._quit_button: Optional[ba.Widget] + if not self._in_game and self._have_quit_button: + h, v, scale = positions[self._p_index] + self._p_index += 1 + self._quit_button = quit_button = ba.buttonwidget( + parent=self._root_widget, + autoselect=self._use_autoselect, + position=(h - self._button_width * 0.5 * scale, v), + size=(self._button_width, self._button_height), + scale=scale, + label=ba.Lstr(resource=self._r + + ('.quitText' if 'Mac' in + ba.app.user_agent_string else '.exitGameText')), + on_activate_call=self._quit, + transition_delay=self._tdelay) + + # Scattered eggs on easter. + if _ba.get_account_misc_read_val('easter', False): + icon_size = 30 + ba.imagewidget(parent=self._root_widget, + position=(h - icon_size * 0.5 + 25, + v + self._button_height * scale - + icon_size * 0.24 + 1.5), + transition_delay=self._tdelay, + size=(icon_size, icon_size), + texture=ba.gettexture('egg1'), + tilt_scale=0.0) + + ba.containerwidget(edit=self._root_widget, + cancel_button=quit_button) + self._tdelay += self._t_delay_inc + else: + self._quit_button = None + + # If we're not in-game, have no quit button, and this is android, + # we want back presses to quit our activity. + if (not self._in_game and not self._have_quit_button + and ba.app.platform == 'android'): + + def _do_quit() -> None: + QuitWindow(swish=True, back=True) + + ba.containerwidget(edit=self._root_widget, + on_cancel_call=_do_quit) + + # Add speed-up/slow-down buttons for replays. + # (ideally this should be part of a fading-out playback bar like most + # media players but this works for now). + if _ba.is_in_replay(): + b_size = 50.0 + b_buffer = 10.0 + t_scale = 0.75 + uiscale = ba.app.ui.uiscale + if uiscale is ba.UIScale.SMALL: + b_size *= 0.6 + b_buffer *= 1.0 + v_offs = -40 + t_scale = 0.5 + elif uiscale is ba.UIScale.MEDIUM: + v_offs = -70 + else: + v_offs = -100 + self._replay_speed_text = ba.textwidget( + parent=self._root_widget, + text=ba.Lstr(resource='watchWindow.playbackSpeedText', + subs=[('${SPEED}', str(1.23))]), + position=(h, v + v_offs + 7 * t_scale), + h_align='center', + v_align='center', + size=(0, 0), + scale=t_scale) + + # Update to current value. + self._change_replay_speed(0) + + # Keep updating in a timer in case it gets changed elsewhere. + self._change_replay_speed_timer = ba.Timer( + 0.25, + ba.WeakCall(self._change_replay_speed, 0), + timetype=ba.TimeType.REAL, + repeat=True) + btn = ba.buttonwidget(parent=self._root_widget, + position=(h - b_size - b_buffer, + v - b_size - b_buffer + v_offs), + button_type='square', + size=(b_size, b_size), + label='', + autoselect=True, + on_activate_call=ba.Call( + self._change_replay_speed, -1)) + ba.textwidget( + parent=self._root_widget, + draw_controller=btn, + text='-', + position=(h - b_size * 0.5 - b_buffer, + v - b_size * 0.5 - b_buffer + 5 * t_scale + v_offs), + h_align='center', + v_align='center', + size=(0, 0), + scale=3.0 * t_scale) + btn = ba.buttonwidget( + parent=self._root_widget, + position=(h + b_buffer, v - b_size - b_buffer + v_offs), + button_type='square', + size=(b_size, b_size), + label='', + autoselect=True, + on_activate_call=ba.Call(self._change_replay_speed, 1)) + ba.textwidget( + parent=self._root_widget, + draw_controller=btn, + text='+', + position=(h + b_size * 0.5 + b_buffer, + v - b_size * 0.5 - b_buffer + 5 * t_scale + v_offs), + h_align='center', + v_align='center', + size=(0, 0), + scale=3.0 * t_scale) + +# ba_meta export plugin +class bySmoothy(ba.Plugin): + def __init__(self): + if _ba.env().get("build_number",0) >= 20577: + bastd_ui_mainmenu.MainMenuWindow._refresh_in_game= new_refresh_in_game + _ba.connect_to_party=newconnect_to_party + _ba.disconnect_from_host=newdisconnect_from_host + else:print("Server Switch only works on bs 1.7 and above") From 7337368ad78c2a4ce2a9e0fd6fac7dfd936a313d Mon Sep 17 00:00:00 2001 From: imayushsaini Date: Sat, 17 Sep 2022 16:39:03 +0000 Subject: [PATCH 0103/1464] [ci] auto-format --- plugins/utilities/advanced_party_window.py | 1548 +++++++++++--------- plugins/utilities/server_switch.py | 947 ++++++------ 2 files changed, 1319 insertions(+), 1176 deletions(-) diff --git a/plugins/utilities/advanced_party_window.py b/plugins/utilities/advanced_party_window.py index 889cfd47..d3496428 100644 --- a/plugins/utilities/advanced_party_window.py +++ b/plugins/utilities/advanced_party_window.py @@ -15,68 +15,75 @@ # added advanced ID revealer # live ping support for bcs -#Made by Mr.Smoothy - Plasma Boson -version_str = "7" - -import os,urllib -import os,sys,re,json,codecs,traceback,base64 -import threading -import time,copy,datetime,shutil - -from _thread import start_new_thread - -import urllib.request - -from typing import TYPE_CHECKING, cast - -import _ba -import ba -import time +# Made by Mr.Smoothy - Plasma Boson +import traceback +import codecs +import json +import re +import sys +import shutil +import copy +import urllib +import os +from bastd.ui.account import viewer +from bastd.ui.popup import PopupMenuWindow, PopupWindow +from ba._general import Call +import base64 +import datetime +import ssl +import bastd.ui.party as bastd_party +from typing import List, Sequence, Optional, Dict, Any, Union +from bastd.ui.colorpicker import ColorPickerExact +from bastd.ui.confirm import ConfirmWindow +from dataclasses import dataclass import math +import time +import ba +import _ba +from typing import TYPE_CHECKING, cast +import urllib.request +from _thread import start_new_thread import threading +version_str = "7" -from dataclasses import dataclass -from bastd.ui.popup import PopupMenuWindow,PopupWindow -from bastd.ui.confirm import ConfirmWindow -from bastd.ui.colorpicker import ColorPickerExact - -from typing import List, Sequence, Optional, Dict, Any, Union -import bastd.ui.party as bastd_party -cache_chat=[] -connect=_ba.connect_to_party -disconnect=_ba.disconnect_from_host -unmuted_names=[] -smo_mode=3 -f_chat=False -chatlogger=False -screenmsg=True -ip_add="127.0.0.1" -p_port=43210 -p_name="local" +cache_chat = [] +connect = _ba.connect_to_party +disconnect = _ba.disconnect_from_host +unmuted_names = [] +smo_mode = 3 +f_chat = False +chatlogger = False +screenmsg = True +ip_add = "127.0.0.1" +p_port = 43210 +p_name = "local" current_ping = 0.0 enable_typing = False # this will prevent auto ping to update textwidget when user actually typing chat message -import ssl ssl._create_default_https_context = ssl._create_unverified_context -def newconnect_to_party(address,port=43210,print_progress=False): + + +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!={} ): + dd = _ba.get_connection_to_host_info() + if (dd != {}): _ba.disconnect_from_host() - ip_add=address - p_port=port - connect(address,port,print_progress) + ip_add = address + p_port = port + connect(address, port, print_progress) else: - ip_add=address - p_port=port + ip_add = address + p_port = port # print(ip_add,p_port) - connect(ip_add,port,print_progress) + connect(ip_add, port, print_progress) DEBUG_SERVER_COMMUNICATION = False DEBUG_PROCESSING = False + + class PingThread(threading.Thread): """Thread for sending out game pings.""" @@ -93,7 +100,7 @@ def run(self) -> None: from ba.internal import get_ip_address_type socket_type = get_ip_address_type(ip_add) sock = socket.socket(socket_type, socket.SOCK_DGRAM) - sock.connect((ip_add,p_port)) + sock.connect((ip_add, p_port)) accessible = False starttime = time.time() @@ -116,7 +123,7 @@ def run(self) -> None: time.sleep(1) ping = (time.time() - starttime) * 1000.0 global current_ping - current_ping = round(ping,2) + current_ping = round(ping, 2) except ConnectionRefusedError: # Fine, server; sorry we pinged you. Hmph. pass @@ -166,91 +173,107 @@ def run(self) -> None: try: import OnlineTranslator tranTypes = [item for item in dir(OnlineTranslator) if item.startswith("Translator_")] - if "item" in globals():del item -except:tranTypes = []#;ba.print_exception() + if "item" in globals(): + del item +except: + tranTypes = [] # ;ba.print_exception() -RecordFilesDir = os.path.join(_ba.env()["python_directory_user"],"Configs" + os.sep) -if not os.path.exists(RecordFilesDir):os.makedirs(RecordFilesDir) +RecordFilesDir = os.path.join(_ba.env()["python_directory_user"], "Configs" + os.sep) +if not os.path.exists(RecordFilesDir): + os.makedirs(RecordFilesDir) version_str = "3.0.1" Current_Lang = None SystemEncode = sys.getfilesystemencoding() -if not isinstance(SystemEncode,str): +if not isinstance(SystemEncode, str): SystemEncode = "utf-8" + def update_ping(): try: _ba.set_ping_widget_value(current_ping) except: with _ba.Context('ui'): - if hasattr(_ba,"ping_widget") and _ba.ping_widget.exists(): - ba.textwidget(edit=_ba.ping_widget,text="Ping:"+str(current_ping)+" ms") + if hasattr(_ba, "ping_widget") and _ba.ping_widget.exists(): + ba.textwidget(edit=_ba.ping_widget, text="Ping:"+str(current_ping)+" ms") + PingThread().start() -import datetime try: from ba._generated.enums import TimeType except: from ba._enums import TimeType + + class chatloggThread(): """Thread for sending out game pings.""" + def __init__(self): super().__init__() - self.saved_msg=[] + self.saved_msg = [] + def run(self) -> None: # pylint: disable=too-many-branches # pylint: disable=too-many-statements global chatlogger - self.timerr=ba.Timer(5.0,self.chatlogg,repeat=True,timetype=TimeType.REAL) + self.timerr = ba.Timer(5.0, self.chatlogg, repeat=True, timetype=TimeType.REAL) + def chatlogg(self): - global chatlogger - chats=_ba.get_chat_messages() - for msg in chats: - if msg in self.saved_msg: - pass + global chatlogger + chats = _ba.get_chat_messages() + for msg in chats: + if msg in self.saved_msg: + pass + else: + self.save(msg) + self.saved_msg.append(msg) + if len(self.saved_msg) > 45: + self.saved_msg.pop(0) + if chatlogger: + pass else: - self.save(msg) - self.saved_msg.append(msg) - if len(self.saved_msg) > 45: - self.saved_msg.pop(0) - if chatlogger: - pass - else: - self.timerr=None - def save(self,msg): - x=str(datetime.datetime.now()) - t=open(os.path.join(_ba.env()["python_directory_user"],"Chat logged.txt"),"a+") - t.write(x+" : "+ msg +"\n") - t.close() + self.timerr = None + + def save(self, msg): + x = str(datetime.datetime.now()) + t = open(os.path.join(_ba.env()["python_directory_user"], "Chat logged.txt"), "a+") + t.write(x+" : " + msg + "\n") + t.close() + + class mututalServerThread(): def run(self): - self.timer=ba.Timer(10,self.checkPlayers,repeat=True,timetype=TimeType.REAL) + self.timer = ba.Timer(10, self.checkPlayers, repeat=True, timetype=TimeType.REAL) + def checkPlayers(self): - if _ba.get_connection_to_host_info()!={}: - server_name=_ba.get_connection_to_host_info()["name"] - players=[] + if _ba.get_connection_to_host_info() != {}: + server_name = _ba.get_connection_to_host_info()["name"] + players = [] for ros in _ba.get_game_roster(): players.append(ros["display_string"]) - start_new_thread(dump_mutual_servers,(players,server_name,)) + start_new_thread(dump_mutual_servers, (players, server_name,)) + -def dump_mutual_servers(players,server_name): +def dump_mutual_servers(players, server_name): filePath = os.path.join(RecordFilesDir, "players.json") - data={} + data = {} if os.path.isfile(filePath): - f=open(filePath,"r") - data=json.load(f) + f = open(filePath, "r") + data = json.load(f) for player in players: if player in data: if server_name not in data[player]: - data[player].insert(0,server_name) - data[player]=data[player][:3] + data[player].insert(0, server_name) + data[player] = data[player][:3] else: - data[player]=[server_name] - f=open(filePath,"w") - json.dump(data,f) + data[player] = [server_name] + f = open(filePath, "w") + json.dump(data, f) + + mututalServerThread().run() @@ -260,58 +283,61 @@ class customchatThread(): def __init__(self): super().__init__() global cache_chat - self.saved_msg=[] - chats=_ba.get_chat_messages() - for msg in chats: #fill up old chat , to avoid old msg popup + self.saved_msg = [] + chats = _ba.get_chat_messages() + for msg in chats: # fill up old chat , to avoid old msg popup cache_chat.append(msg) + def run(self) -> None: # pylint: disable=too-many-branches # pylint: disable=too-many-statements global chatlogger - self.timerr=ba.Timer(5.0,self.chatcheck,repeat=True,timetype=TimeType.REAL) + self.timerr = ba.Timer(5.0, self.chatcheck, repeat=True, timetype=TimeType.REAL) def chatcheck(self): - global unmuted_names - global cache_chat - chats=_ba.get_chat_messages() - for msg in chats: - if msg in cache_chat: - pass - else: - if msg.split(":")[0] in unmuted_names: - ba.screenmessage(msg,color=(0.6,0.9,0.6)) - cache_chat.append(msg) - if len(self.saved_msg) > 45: - cache_chat.pop(0) - if ba.app.config.resolve('Chat Muted'): - pass - else: - self.timerr=None + global unmuted_names + global cache_chat + chats = _ba.get_chat_messages() + for msg in chats: + if msg in cache_chat: + pass + else: + if msg.split(":")[0] in unmuted_names: + ba.screenmessage(msg, color=(0.6, 0.9, 0.6)) + cache_chat.append(msg) + if len(self.saved_msg) > 45: + cache_chat.pop(0) + if ba.app.config.resolve('Chat Muted'): + pass + else: + self.timerr = None + def chatloggerstatus(): - global chatlogger - if chatlogger: - return "Turn off Chat Logger" - else: - return "Turn on chat logger" + global chatlogger + if chatlogger: + return "Turn off Chat Logger" + else: + return "Turn on chat logger" + -def _getTransText(text , isBaLstr = False , same_fb = False): +def _getTransText(text, isBaLstr=False, same_fb=False): global Current_Lang global chatlogger if Current_Lang != 'English': Current_Lang = 'English' global Language_Texts Language_Texts = { - "Chinese": { + "Chinese": { - }, - "English": { - "Add_a_Quick_Reply": "Add a Quick Reply", - "Admin_Command_Kick_Confirm": "Are you sure to use admin\ + }, + "English": { + "Add_a_Quick_Reply": "Add a Quick Reply", + "Admin_Command_Kick_Confirm": "Are you sure to use admin\ command to kick %s?", - "Ban_For_%d_Seconds": "Ban for %d second(s).", - "Ban_Time_Post": "Enter the time you want to ban(Seconds).", - "Credits_for_This": "Credits for This", + "Ban_For_%d_Seconds": "Ban for %d second(s).", + "Ban_Time_Post": "Enter the time you want to ban(Seconds).", + "Credits_for_This": "Credits for This", "Custom_Action": "Custom Action", "Debug_for_Host_Info": "Host Info Debug", "Game_Record_Saved": "Game replay %s is saved.", @@ -329,67 +355,66 @@ def _getTransText(text , isBaLstr = False , same_fb = False): "Something_is_removed": "'%s' is removed.", "Times": "Times", "Translator": "Translator", - "chatloggeroff":"Turn off Chat Logger", - "chatloggeron":"Turn on Chat Logger", - "screenmsgoff":"Hide ScreenMessage", - "screenmsgon":"Show ScreenMessage", - "unmutethisguy":"unmute this guy", - "mutethisguy":"mute this guy", - "muteall":"Mute all", - "unmuteall":"Unmute all" - - } - } + "chatloggeroff": "Turn off Chat Logger", + "chatloggeron": "Turn on Chat Logger", + "screenmsgoff": "Hide ScreenMessage", + "screenmsgon": "Show ScreenMessage", + "unmutethisguy": "unmute this guy", + "mutethisguy": "mute this guy", + "muteall": "Mute all", + "unmuteall": "Unmute all" + + } + } Language_Texts = Language_Texts.get(Current_Lang) try: from Language_Packs import ModifiedPartyWindow_LanguagePack as ext_lan_pack - if isinstance(ext_lan_pack,dict) and isinstance(ext_lan_pack.get(Current_Lang),dict): + if isinstance(ext_lan_pack, dict) and isinstance(ext_lan_pack.get(Current_Lang), dict): complete_Pack = ext_lan_pack.get(Current_Lang) - for key,item in complete_Pack.items(): + for key, item in complete_Pack.items(): Language_Texts[key] = item except: pass - return(Language_Texts.get(text,"#Unknown Text#" if not same_fb else text) if not isBaLstr else - ba.Lstr(resource = "??Unknown??",fallback_value = Language_Texts.get(text,"#Unknown Text#" if not same_fb else text))) + return (Language_Texts.get(text, "#Unknown Text#" if not same_fb else text) if not isBaLstr else + ba.Lstr(resource="??Unknown??", fallback_value=Language_Texts.get(text, "#Unknown Text#" if not same_fb else text))) + def _get_popup_window_scale() -> float: uiscale = ba.app.ui.uiscale - return(2.3 if uiscale is ba.UIScale.SMALL else - 1.65 if uiscale is ba.UIScale.MEDIUM else 1.23) - -def _creat_Lstr_list(string_list : list = []) -> list: - return([ba.Lstr(resource = "??Unknown??",fallback_value = item) for item in string_list]) + return (2.3 if uiscale is ba.UIScale.SMALL else + 1.65 if uiscale is ba.UIScale.MEDIUM else 1.23) +def _creat_Lstr_list(string_list: list = []) -> list: + return ([ba.Lstr(resource="??Unknown??", fallback_value=item) for item in string_list]) customchatThread().run() + class ModifiedPartyWindow(bastd_party.PartyWindow): def __init__(self, origin: Sequence[float] = (0, 0)): _ba.set_party_window_open(True) self._r = 'partyWindow' - self.msg_user_selected='' + self.msg_user_selected = '' self._popup_type: Optional[str] = None self._popup_party_member_client_id: Optional[int] = None self._popup_party_member_is_host: Optional[bool] = None self._width = 500 - uiscale = ba.app.ui.uiscale self._height = (365 if uiscale is ba.UIScale.SMALL else 480 if uiscale is ba.UIScale.MEDIUM else 600) - #Custom color here - self._bg_color = ba.app.config.get("PartyWindow_Main_Color",(0.40, 0.55, 0.20)) if not isinstance(self._getCustomSets().get("Color"),(list,tuple)) else self._getCustomSets().get("Color") - if not isinstance(self._bg_color,(list,tuple)) or not len(self._bg_color) == 3:self._bg_color = (0.40, 0.55, 0.20) - + # Custom color here + self._bg_color = ba.app.config.get("PartyWindow_Main_Color", (0.40, 0.55, 0.20)) if not isinstance( + self._getCustomSets().get("Color"), (list, tuple)) else self._getCustomSets().get("Color") + if not isinstance(self._bg_color, (list, tuple)) or not len(self._bg_color) == 3: + self._bg_color = (0.40, 0.55, 0.20) - - - ba.Window.__init__(self,root_widget=ba.containerwidget( + ba.Window.__init__(self, root_widget=ba.containerwidget( size=(self._width, self._height), transition='in_scale', color=self._bg_color, @@ -412,15 +437,15 @@ def __init__(self, origin: Sequence[float] = (0, 0)): icon=ba.gettexture('crossOut'), iconscale=1.2) self._smoothy_button = ba.buttonwidget(parent=self._root_widget, - scale=0.6, - position=(5, self._height - 47 -40), - size=(50, 50), - label='69', - on_activate_call=self.smoothy_roster_changer, - autoselect=True, - color=(0.45, 0.63, 0.15), - icon=ba.gettexture('replayIcon'), - iconscale=1.2) + scale=0.6, + position=(5, self._height - 47 - 40), + size=(50, 50), + label='69', + on_activate_call=self.smoothy_roster_changer, + autoselect=True, + color=(0.45, 0.63, 0.15), + icon=ba.gettexture('replayIcon'), + iconscale=1.2) ba.containerwidget(edit=self._root_widget, cancel_button=self._cancel_button) @@ -489,7 +514,7 @@ def __init__(self, origin: Sequence[float] = (0, 0)): # add all existing messages if chat is not muted # print("updates") - if True: #smoothy - always show chat in partywindow + if True: # smoothy - always show chat in partywindow msgs = _ba.get_chat_messages() for msg in msgs: self._add_msg(msg) @@ -514,10 +539,10 @@ def __init__(self, origin: Sequence[float] = (0, 0)): # ba.containerwidget(edit=self._columnwidget, visible_child=txt) self.ping_widget = txt = ba.textwidget( parent=self._root_widget, - scale = 0.6, + scale=0.6, size=(20, 5), color=(0.45, 0.63, 0.15), - position=(self._width/2 -20, 50), + position=(self._width/2 - 20, 50), text='', selectable=True, autoselect=False, @@ -541,7 +566,6 @@ def enable_chat_mode(): v_align='center', corner_scale=0.7) - # for m in _ba.get_chat_messages(): # if m: # ttchat=ba.textwidget( @@ -575,8 +599,6 @@ def enable_chat_mode(): position=(self._width - 70, 35), on_activate_call=self._send_chat_message) - - def _times_button_on_click(): # self._popup_type = "send_Times_Press" # allow_range = 100 if _ba.get_foreground_host_session() is not None else 4 @@ -589,147 +611,149 @@ def _times_button_on_click(): Quickreply = self._get_quick_responds() if len(Quickreply) > 0: PopupMenuWindow(position=self._times_button.get_screen_space_center(), - scale=_get_popup_window_scale(), - choices=Quickreply, - choices_display=_creat_Lstr_list(Quickreply), - current_choice=Quickreply[0], - delegate=self) + scale=_get_popup_window_scale(), + choices=Quickreply, + choices_display=_creat_Lstr_list(Quickreply), + current_choice=Quickreply[0], + delegate=self) self._popup_type = "QuickMessageSelect" self._send_msg_times = 1 self._times_button = ba.buttonwidget(parent=self._root_widget, - size=(50, 35), - label="Quick", - button_type='square', - autoselect=True, - position=(30, 35), - on_activate_call=_times_button_on_click) + size=(50, 35), + label="Quick", + button_type='square', + autoselect=True, + position=(30, 35), + on_activate_call=_times_button_on_click) ba.textwidget(edit=txt, on_return_press_call=btn.activate) self._name_widgets: List[ba.Widget] = [] self._roster: Optional[List[Dict[str, Any]]] = None - self.smoothy_mode=1 - self.full_chat_mode=False + self.smoothy_mode = 1 + self.full_chat_mode = False self._update_timer = ba.Timer(1.0, ba.WeakCall(self._update), repeat=True, timetype=ba.TimeType.REAL) self._update() + def title_selected(self): - self.full_chat_mode= self.full_chat_mode ==False + self.full_chat_mode = self.full_chat_mode == False self._update() - def smoothy_roster_changer(self): - - self.smoothy_mode=(self.smoothy_mode+1)%3 + def smoothy_roster_changer(self): + self.smoothy_mode = (self.smoothy_mode+1) % 3 - self._update() + self._update() def on_chat_message(self, msg: str) -> None: - """Called when a new chat message comes through.""" - # print("on_chat"+msg) - if True: - self._add_msg(msg) - def _on_chat_press(self,msg,widget): + """Called when a new chat message comes through.""" + # print("on_chat"+msg) + if True: + self._add_msg(msg) + + def _on_chat_press(self, msg, widget): global unmuted_names if msg.split(":")[0] in unmuted_names: - choices=['mute'] - choices_display=[_getTransText("mutethisguy",isBaLstr = True)] + choices = ['mute'] + choices_display = [_getTransText("mutethisguy", isBaLstr=True)] else: - choices=['unmute'] - choices_display=[_getTransText("unmutethisguy",isBaLstr = True)] + choices = ['unmute'] + choices_display = [_getTransText("unmutethisguy", isBaLstr=True)] PopupMenuWindow(position=widget.get_screen_space_center(), - scale=_get_popup_window_scale(), - choices=choices, - choices_display=choices_display, - current_choice="@ this guy", - delegate=self) - self.msg_user_selected=msg.split(":")[0] + scale=_get_popup_window_scale(), + choices=choices, + choices_display=choices_display, + current_choice="@ this guy", + delegate=self) + self.msg_user_selected = msg.split(":")[0] self._popup_type = "chatmessagepress" # _ba.chatmessage("pressed") - def _add_msg(self, msg: str) -> None: - try: - if ba.app.config.resolve('Chat Muted'): - - - txt = ba.textwidget(parent=self._columnwidget, - text=msg, - h_align='left', - v_align='center', - size=(130, 13), - scale=0.55, - position=(-0.6,0), - selectable=True, - click_activate=True, - maxwidth=self._scroll_width * 0.94, - shadow=0.3, - flatness=1.0) - ba.textwidget(edit=txt, - on_activate_call=ba.Call( - self._on_chat_press, - msg,txt)) - else: - txt = ba.textwidget(parent=self._columnwidget, - text=msg, - h_align='left', - v_align='center', - size=(0, 13), - scale=0.55, - - - - maxwidth=self._scroll_width * 0.94, - shadow=0.3, - flatness=1.0) - - # btn = ba.buttonwidget(parent=self._columnwidget, - # scale=0.7, - # size=(100,20), - # label="smoothy buttin", - # icon=ba.gettexture('replayIcon'), - # texture=None, - # ) - self._chat_texts_haxx.append(txt) - if len(self._chat_texts_haxx) > 40: - first = self._chat_texts_haxx.pop(0) - first.delete() - ba.containerwidget(edit=self._columnwidget, visible_child=txt) - except Exception: - pass + try: + if ba.app.config.resolve('Chat Muted'): + + txt = ba.textwidget(parent=self._columnwidget, + text=msg, + h_align='left', + v_align='center', + size=(130, 13), + scale=0.55, + position=(-0.6, 0), + selectable=True, + click_activate=True, + maxwidth=self._scroll_width * 0.94, + shadow=0.3, + flatness=1.0) + ba.textwidget(edit=txt, + on_activate_call=ba.Call( + self._on_chat_press, + msg, txt)) + else: + txt = ba.textwidget(parent=self._columnwidget, + text=msg, + h_align='left', + v_align='center', + size=(0, 13), + scale=0.55, + + + + maxwidth=self._scroll_width * 0.94, + shadow=0.3, + flatness=1.0) + + # btn = ba.buttonwidget(parent=self._columnwidget, + # scale=0.7, + # size=(100,20), + # label="smoothy buttin", + # icon=ba.gettexture('replayIcon'), + # texture=None, + # ) + self._chat_texts_haxx.append(txt) + if len(self._chat_texts_haxx) > 40: + first = self._chat_texts_haxx.pop(0) + first.delete() + ba.containerwidget(edit=self._columnwidget, visible_child=txt) + except Exception: + pass def _add_msg_when_muted(self, msg: str) -> None: - txt = ba.textwidget(parent=self._columnwidget, - text=msg, - h_align='left', - v_align='center', - size=(0, 13), - scale=0.55, - maxwidth=self._scroll_width * 0.94, - shadow=0.3, - flatness=1.0) - self._chat_texts.append(txt) - if len(self._chat_texts) > 40: - first = self._chat_texts.pop(0) - first.delete() - ba.containerwidget(edit=self._columnwidget, visible_child=txt) + txt = ba.textwidget(parent=self._columnwidget, + text=msg, + h_align='left', + v_align='center', + size=(0, 13), + scale=0.55, + maxwidth=self._scroll_width * 0.94, + shadow=0.3, + flatness=1.0) + self._chat_texts.append(txt) + if len(self._chat_texts) > 40: + first = self._chat_texts.pop(0) + first.delete() + ba.containerwidget(edit=self._columnwidget, visible_child=txt) + def color_picker_closing(self, picker) -> None: ba._appconfig.commit_app_config() + def color_picker_selected_color(self, picker, color) -> None: - #bs.animateArray(self._root_widget,"color",3,{0:self._bg_color,1500:color}) - ba.containerwidget(edit=self._root_widget,color=color) + # bs.animateArray(self._root_widget,"color",3,{0:self._bg_color,1500:color}) + ba.containerwidget(edit=self._root_widget, color=color) self._bg_color = color ba.app.config["PartyWindow_Main_Color"] = color - def _on_nick_rename_press(self,arg) -> None: + + def _on_nick_rename_press(self, arg) -> None: ba.containerwidget(edit=self._root_widget, transition='out_scale') c_width = 600 @@ -749,7 +773,7 @@ def _on_nick_rename_press(self,arg) -> None: text='Enter nickname', maxwidth=c_width * 0.8, position=(c_width * 0.5, c_height - 60)) - id=self._get_nick(arg) + id = self._get_nick(arg) self._player_nick_text = txt89 = ba.textwidget( parent=cnt, size=(c_width * 0.8, 40), @@ -776,64 +800,76 @@ def _on_nick_rename_press(self,arg) -> None: size=(180, 60), position=(c_width - 230, 30), on_activate_call=ba.Call( - self._add_nick,arg), + self._add_nick, arg), autoselect=True) ba.widget(edit=cbtn, right_widget=okb) ba.widget(edit=okb, left_widget=cbtn) ba.textwidget(edit=txt89, on_return_press_call=okb.activate) ba.containerwidget(edit=cnt, cancel_button=cbtn, start_button=okb) - def _add_nick(self,arg): - config = ba.app.config - new_name_raw = cast(str, ba.textwidget(query=self._player_nick_text)) - if arg: - if not isinstance(config.get('players nick'), dict): - config['players nick'] = {} - config['players nick'][arg] = new_name_raw - config.commit() - ba.containerwidget(edit=self._nick_rename_window, + + def _add_nick(self, arg): + config = ba.app.config + new_name_raw = cast(str, ba.textwidget(query=self._player_nick_text)) + if arg: + if not isinstance(config.get('players nick'), dict): + config['players nick'] = {} + config['players nick'][arg] = new_name_raw + config.commit() + ba.containerwidget(edit=self._nick_rename_window, transition='out_scale') - # ba.containerwidget(edit=self._root_widget,transition='in_scale') - def _get_nick(self,id): - config=ba.app.config - if not isinstance(config.get('players nick'), dict): + # ba.containerwidget(edit=self._root_widget,transition='in_scale') + + def _get_nick(self, id): + config = ba.app.config + if not isinstance(config.get('players nick'), dict): + return "add nick" + elif id in config['players nick']: + return config['players nick'][id] + else: return "add nick" - elif id in config['players nick']: - return config['players nick'][id] - else: - return "add nick" def _reset_game_record(self) -> None: try: - dir_path = _ba.get_replays_dir();curFilePath = os.path.join(dir_path+os.sep,"__lastReplay.brp").encode(SystemEncode) - newFileName = str(ba.Lstr(resource="replayNameDefaultText").evaluate()+" (%s)"%(datetime.datetime.strftime(datetime.datetime.now(),"%Y_%m_%d_%H_%M_%S"))+".brp") - newFilePath = os.path.join(dir_path+os.sep,newFileName).encode(SystemEncode) + dir_path = _ba.get_replays_dir() + curFilePath = os.path.join(dir_path+os.sep, "__lastReplay.brp").encode(SystemEncode) + newFileName = str(ba.Lstr(resource="replayNameDefaultText").evaluate( + )+" (%s)" % (datetime.datetime.strftime(datetime.datetime.now(), "%Y_%m_%d_%H_%M_%S"))+".brp") + newFilePath = os.path.join(dir_path+os.sep, newFileName).encode(SystemEncode) #print(curFilePath, newFilePath) - #os.rename(curFilePath,newFilePath) + # os.rename(curFilePath,newFilePath) shutil.copyfile(curFilePath, newFilePath) _ba.reset_game_activity_tracking() - ba.screenmessage(_getTransText("Game_Record_Saved")%newFileName,color = (1,1,1)) - except:ba.print_exception();ba.screenmessage(ba.Lstr(resource="replayWriteErrorText").evaluate()+"\ -"+traceback.format_exc(),color = (1,0,0)) + ba.screenmessage(_getTransText("Game_Record_Saved") % newFileName, color=(1, 1, 1)) + except: + ba.print_exception() + ba.screenmessage(ba.Lstr(resource="replayWriteErrorText").evaluate() + + ""+traceback.format_exc(), color=(1, 0, 0)) + def _on_menu_button_press(self) -> None: is_muted = ba.app.config.resolve('Chat Muted') global chatlogger - choices = ["unmute" if is_muted else "mute","screenmsg","addQuickReply","removeQuickReply","chatlogger","credits"] - DisChoices = [_getTransText("unmuteall",isBaLstr = True) if is_muted else _getTransText("muteall",isBaLstr = True), - _getTransText("screenmsgoff",isBaLstr = True) if screenmsg else _getTransText("screenmsgon",isBaLstr = True), - - _getTransText("Add_a_Quick_Reply",isBaLstr = True), - _getTransText("Remove_a_Quick_Reply",isBaLstr = True), - _getTransText("chatloggeroff",isBaLstr = True) if chatlogger else _getTransText("chatloggeron",isBaLstr = True), - _getTransText("Credits_for_This",isBaLstr = True) - ] - - if len(tranTypes) > 0 : - choices.append("translator");DisChoices.append(_getTransText("Translator",isBaLstr = True)) + choices = ["unmute" if is_muted else "mute", "screenmsg", + "addQuickReply", "removeQuickReply", "chatlogger", "credits"] + DisChoices = [_getTransText("unmuteall", isBaLstr=True) if is_muted else _getTransText("muteall", isBaLstr=True), + _getTransText("screenmsgoff", isBaLstr=True) if screenmsg else _getTransText( + "screenmsgon", isBaLstr=True), + + _getTransText("Add_a_Quick_Reply", isBaLstr=True), + _getTransText("Remove_a_Quick_Reply", isBaLstr=True), + _getTransText("chatloggeroff", isBaLstr=True) if chatlogger else _getTransText( + "chatloggeron", isBaLstr=True), + _getTransText("Credits_for_This", isBaLstr=True) + ] + + if len(tranTypes) > 0: + choices.append("translator") + DisChoices.append(_getTransText("Translator", isBaLstr=True)) choices.append("resetGameRecord") - DisChoices.append(_getTransText("Restart_Game_Record",isBaLstr = True)) - if self._getCustomSets().get("Enable_HostInfo_Debug",False): - choices.append("hostInfo_Debug");DisChoices.append(_getTransText("Debug_for_Host_Info",isBaLstr = True)) + DisChoices.append(_getTransText("Restart_Game_Record", isBaLstr=True)) + if self._getCustomSets().get("Enable_HostInfo_Debug", False): + choices.append("hostInfo_Debug") + DisChoices.append(_getTransText("Debug_for_Host_Info", isBaLstr=True)) PopupMenuWindow( position=self._menu_button.get_screen_space_center(), @@ -842,121 +878,123 @@ def _on_menu_button_press(self) -> None: choices_display=DisChoices, current_choice="unmute" if is_muted else "mute", delegate=self) self._popup_type = "menu" + def _on_party_member_press(self, client_id: int, is_host: bool, widget: ba.Widget) -> None: # if we"re the host, pop up "kick" options for all non-host members if _ba.get_foreground_host_session() is not None: kick_str = ba.Lstr(resource="kickText") - else:kick_str = ba.Lstr(resource="kickVoteText") - choices = ["kick","@ this guy","info","adminkick"] + else: + kick_str = ba.Lstr(resource="kickVoteText") + choices = ["kick", "@ this guy", "info", "adminkick"] - choices_display = [kick_str,_getTransText("Mention_this_guy",isBaLstr = True),ba.Lstr(resource="??Unknown??",fallback_value="Info"), - ba.Lstr(resource = "??Unknown??",fallback_value = _getTransText("Kick_ID")%client_id)] + choices_display = [kick_str, _getTransText("Mention_this_guy", isBaLstr=True), ba.Lstr(resource="??Unknown??", fallback_value="Info"), + ba.Lstr(resource="??Unknown??", fallback_value=_getTransText("Kick_ID") % client_id)] try: - if len(self._getCustomSets().get("partyMemberPress_Custom") if isinstance(self._getCustomSets().get("partyMemberPress_Custom"),dict) else {}) > 0: - choices.append("customAction");choices_display.append(_getTransText("Custom_Action",isBaLstr = True)) - except:ba.print_exception() - - + if len(self._getCustomSets().get("partyMemberPress_Custom") if isinstance(self._getCustomSets().get("partyMemberPress_Custom"), dict) else {}) > 0: + choices.append("customAction") + choices_display.append(_getTransText("Custom_Action", isBaLstr=True)) + except: + ba.print_exception() PopupMenuWindow(position=widget.get_screen_space_center(), - scale=_get_popup_window_scale(), - choices=choices, - choices_display=choices_display, - current_choice="@ this guy", - delegate=self) + scale=_get_popup_window_scale(), + choices=choices, + choices_display=choices_display, + current_choice="@ this guy", + delegate=self) self._popup_party_member_client_id = client_id self._popup_party_member_is_host = is_host self._popup_type = "partyMemberPress" def _send_chat_message(self) -> None: sendtext = ba.textwidget(query=self._text_field) - if sendtext==".ip": - _ba.chatmessage("IP "+ip_add+" PORT "+str(p_port)) - - ba.textwidget(edit=self._text_field,text="") - return - elif sendtext==".info": - if _ba.get_connection_to_host_info() == {}: - s_build=0 - else: - s_build = _ba.get_connection_to_host_info()['build_number'] - s_v="0" - if s_build <=14365: - s_v=" 1.4.148 or below" - elif s_build <=14377: - s_v="1.4.148 < x < = 1.4.155 " - elif s_build>=20001 and s_build < 20308: - s_v ="1.5" - elif s_build >= 20308 and s_build < 20591: - s_v="1.6 " - else: - s_v ="1.7 and above " - _ba.chatmessage("script version "+s_v+"- build "+str(s_build)) - ba.textwidget(edit=self._text_field,text="") - return - elif sendtext==".ping disabled": - PingThread(ip_add, p_port).start() - ba.textwidget(edit=self._text_field,text="") - return - elif sendtext==".save": - info = _ba.get_connection_to_host_info() - config = ba.app.config - if info.get('name', '') != '': - title = info['name'] - if not isinstance(config.get('Saved Servers'), dict): - config['Saved Servers'] = {} - config['Saved Servers'][f'{ip_add}@{p_port}'] = { - 'addr': ip_add, - 'port': p_port, - 'name': title - } - config.commit() - ba.screenmessage("Server saved to manual") - ba.playsound(ba.getsound('gunCocking')) - ba.textwidget(edit=self._text_field,text="") + if sendtext == ".ip": + _ba.chatmessage("IP "+ip_add+" PORT "+str(p_port)) + + ba.textwidget(edit=self._text_field, text="") return + elif sendtext == ".info": + if _ba.get_connection_to_host_info() == {}: + s_build = 0 + else: + s_build = _ba.get_connection_to_host_info()['build_number'] + s_v = "0" + if s_build <= 14365: + s_v = " 1.4.148 or below" + elif s_build <= 14377: + s_v = "1.4.148 < x < = 1.4.155 " + elif s_build >= 20001 and s_build < 20308: + s_v = "1.5" + elif s_build >= 20308 and s_build < 20591: + s_v = "1.6 " + else: + s_v = "1.7 and above " + _ba.chatmessage("script version "+s_v+"- build "+str(s_build)) + ba.textwidget(edit=self._text_field, text="") + return + elif sendtext == ".ping disabled": + PingThread(ip_add, p_port).start() + ba.textwidget(edit=self._text_field, text="") + return + elif sendtext == ".save": + info = _ba.get_connection_to_host_info() + config = ba.app.config + if info.get('name', '') != '': + title = info['name'] + if not isinstance(config.get('Saved Servers'), dict): + config['Saved Servers'] = {} + config['Saved Servers'][f'{ip_add}@{p_port}'] = { + 'addr': ip_add, + 'port': p_port, + 'name': title + } + config.commit() + ba.screenmessage("Server saved to manual") + ba.playsound(ba.getsound('gunCocking')) + ba.textwidget(edit=self._text_field, text="") + return # elif sendtext != "": # for index in range(getattr(self,"_send_msg_times",1)): if '\\' in sendtext: - sendtext = sendtext.replace('\\d', ('\ue048')) - sendtext = sendtext.replace('\\c', ('\ue043')) - sendtext = sendtext.replace('\\h', ('\ue049')) - sendtext = sendtext.replace('\\s', ('\ue046')) - sendtext = sendtext.replace('\\n', ('\ue04b')) - sendtext = sendtext.replace('\\f', ('\ue04f')) - sendtext = sendtext.replace('\\g', ('\ue027')) - sendtext = sendtext.replace('\\i', ('\ue03a')) - sendtext = sendtext.replace('\\m', ('\ue04d')) - sendtext = sendtext.replace('\\t', ('\ue01f')) - sendtext = sendtext.replace('\\bs', ('\ue01e')) - sendtext = sendtext.replace('\\j', ('\ue010')) - sendtext = sendtext.replace('\\e', ('\ue045')) - sendtext = sendtext.replace('\\l', ('\ue047')) - sendtext = sendtext.replace('\\a', ('\ue020')) - sendtext = sendtext.replace('\\b', ('\ue00c')) - if sendtext=="": - sendtext=" " - msg=sendtext - msg1=msg.split(" ") - ms2="" - if(len(msg1)>11): - hp=int(len(msg1)/2) - - for m in range (0,hp): - ms2=ms2+" "+msg1[m] + sendtext = sendtext.replace('\\d', ('\ue048')) + sendtext = sendtext.replace('\\c', ('\ue043')) + sendtext = sendtext.replace('\\h', ('\ue049')) + sendtext = sendtext.replace('\\s', ('\ue046')) + sendtext = sendtext.replace('\\n', ('\ue04b')) + sendtext = sendtext.replace('\\f', ('\ue04f')) + sendtext = sendtext.replace('\\g', ('\ue027')) + sendtext = sendtext.replace('\\i', ('\ue03a')) + sendtext = sendtext.replace('\\m', ('\ue04d')) + sendtext = sendtext.replace('\\t', ('\ue01f')) + sendtext = sendtext.replace('\\bs', ('\ue01e')) + sendtext = sendtext.replace('\\j', ('\ue010')) + sendtext = sendtext.replace('\\e', ('\ue045')) + sendtext = sendtext.replace('\\l', ('\ue047')) + sendtext = sendtext.replace('\\a', ('\ue020')) + sendtext = sendtext.replace('\\b', ('\ue00c')) + if sendtext == "": + sendtext = " " + msg = sendtext + msg1 = msg.split(" ") + ms2 = "" + if (len(msg1) > 11): + hp = int(len(msg1)/2) + + for m in range(0, hp): + ms2 = ms2+" "+msg1[m] _ba.chatmessage(ms2) - ms2="" - for m in range (hp,len(msg1)): - ms2=ms2+" "+msg1[m] + ms2 = "" + for m in range(hp, len(msg1)): + ms2 = ms2+" "+msg1[m] _ba.chatmessage(ms2) else: _ba.chatmessage(msg) - ba.textwidget(edit=self._text_field,text="") + ba.textwidget(edit=self._text_field, text="") # else: # Quickreply = self._get_quick_responds() # if len(Quickreply) > 0: @@ -970,93 +1008,135 @@ def _send_chat_message(self) -> None: # else: # _ba.chatmessage(sendtext) # ba.textwidget(edit=self._text_field,text="") + def _get_quick_responds(self): - if not hasattr(self,"_caches") or not isinstance(self._caches,dict):self._caches = {} + if not hasattr(self, "_caches") or not isinstance(self._caches, dict): + self._caches = {} try: - filePath = os.path.join(RecordFilesDir,"Quickmessage.txt") + filePath = os.path.join(RecordFilesDir, "Quickmessage.txt") if os.path.exists(RecordFilesDir) is not True: os.makedirs(RecordFilesDir) if not os.path.isfile(filePath): - with open(filePath,"wb") as writer: - writer.write(({"Chinese":u"\xe5\x8e\x89\xe5\xae\xb3\xef\xbc\x8c\xe8\xbf\x98\xe6\x9c\x89\xe8\xbf\x99\xe7\xa7\x8d\xe9\xaa\x9a\xe6\x93\x8d\xe4\xbd\x9c!\ + with open(filePath, "wb") as writer: + writer.write(({"Chinese": u"\xe5\x8e\x89\xe5\xae\xb3\xef\xbc\x8c\xe8\xbf\x98\xe6\x9c\x89\xe8\xbf\x99\xe7\xa7\x8d\xe9\xaa\x9a\xe6\x93\x8d\xe4\xbd\x9c!\ \xe4\xbd\xa0\xe2\x84\xa2\xe8\x83\xbd\xe5\x88\xab\xe6\x89\x93\xe9\x98\x9f\xe5\x8f\x8b\xe5\x90\x97\xef\xbc\x9f\ -\xe5\x8f\xaf\xe4\xbb\xa5\xe5\x95\x8a\xe5\xb1\x85\xe7\x84\xb6\xe8\x83\xbd\xe8\xbf\x99\xe4\xb9\x88\xe7\x8e\xa9\xef\xbc\x9f"}.get(Current_Lang,"What the hell?\nDude that's amazing!")).encode("UTF-8")) +\xe5\x8f\xaf\xe4\xbb\xa5\xe5\x95\x8a\xe5\xb1\x85\xe7\x84\xb6\xe8\x83\xbd\xe8\xbf\x99\xe4\xb9\x88\xe7\x8e\xa9\xef\xbc\x9f"}.get(Current_Lang, "What the hell?\nDude that's amazing!")).encode("UTF-8")) if os.path.getmtime(filePath) != self._caches.get("Vertify_Quickresponse_Text"): - with open(filePath,"rU", encoding = "UTF-8-sig") as Reader: + with open(filePath, "rU", encoding="UTF-8-sig") as Reader: Text = Reader.read() if Text.startswith(str(codecs.BOM_UTF8)): Text = Text[3:] self._caches["quickReplys"] = (Text).split("\\n") self._caches["Vertify_Quickresponse_Text"] = os.path.getmtime(filePath) - return(self._caches.get("quickReplys",[])) - except:ba.print_exception();ba.screenmessage(ba.Lstr(resource="errorText"),(1,0,0));ba.playsound(ba.getsound("error")) - def _write_quick_responds(self,data): + return (self._caches.get("quickReplys", [])) + except: + ba.print_exception() + ba.screenmessage(ba.Lstr(resource="errorText"), (1, 0, 0)) + ba.playsound(ba.getsound("error")) + + def _write_quick_responds(self, data): try: - with open(os.path.join(RecordFilesDir,"Quickmessage.txt"),"wb") as writer: + with open(os.path.join(RecordFilesDir, "Quickmessage.txt"), "wb") as writer: writer.write("\\n".join(data).encode("utf-8")) - except:ba.print_exception();ba.screenmessage(ba.Lstr(resource="errorText"),(1,0,0));ba.playsound(ba.getsound("error")) + except: + ba.print_exception() + ba.screenmessage(ba.Lstr(resource="errorText"), (1, 0, 0)) + ba.playsound(ba.getsound("error")) + def _getCustomSets(self): try: - if not hasattr(self,"_caches") or not isinstance(self._caches,dict):self._caches = {} + if not hasattr(self, "_caches") or not isinstance(self._caches, dict): + self._caches = {} try: from VirtualHost import MainSettings - if MainSettings.get("Custom_PartyWindow_Sets",{}) != self._caches.get("PartyWindow_Sets",{}): - self._caches["PartyWindow_Sets"] = MainSettings.get("Custom_PartyWindow_Sets",{}) + if MainSettings.get("Custom_PartyWindow_Sets", {}) != self._caches.get("PartyWindow_Sets", {}): + self._caches["PartyWindow_Sets"] = MainSettings.get( + "Custom_PartyWindow_Sets", {}) except: try: - filePath = os.path.join(RecordFilesDir,"Settings.json") + filePath = os.path.join(RecordFilesDir, "Settings.json") if os.path.isfile(filePath): if os.path.getmtime(filePath) != self._caches.get("Vertify_MainSettings.json_Text"): - with open(filePath,"rU", encoding = "UTF-8-sig") as Reader: + with open(filePath, "rU", encoding="UTF-8-sig") as Reader: Text = Reader.read() if Text.startswith(str(codecs.BOM_UTF8)): Text = Text[3:] - self._caches["PartyWindow_Sets"] = json.loads(Text.decode("utf-8")).get("Custom_PartyWindow_Sets",{}) - self._caches["Vertify_MainSettings.json_Text"] = os.path.getmtime(filePath) - except:ba.print_exception() - return(self._caches.get("PartyWindow_Sets") if isinstance(self._caches.get("PartyWindow_Sets"),dict) else {}) - - except:ba.print_exception() - def _getObjectByID(self,type = "playerName",ID = None): - if ID is None:ID = self._popup_party_member_client_id - type = type.lower();output = [] + self._caches["PartyWindow_Sets"] = json.loads( + Text.decode("utf-8")).get("Custom_PartyWindow_Sets", {}) + self._caches["Vertify_MainSettings.json_Text"] = os.path.getmtime( + filePath) + except: + ba.print_exception() + return (self._caches.get("PartyWindow_Sets") if isinstance(self._caches.get("PartyWindow_Sets"), dict) else {}) + + except: + ba.print_exception() + + def _getObjectByID(self, type="playerName", ID=None): + if ID is None: + ID = self._popup_party_member_client_id + type = type.lower() + output = [] for roster in self._roster: if type.startswith("all"): - if type in ("roster","fullrecord"):output += [roster] + if type in ("roster", "fullrecord"): + output += [roster] elif type.find("player") != -1 and roster["players"] != []: - if type.find("namefull") != -1:output += [(i["name_full"]) for i in roster["players"]] - elif type.find("name") != -1:output += [(i["name"]) for i in roster["players"]] - elif type.find("playerid") != -1:output += [i["id"] for i in roster["players"]] - elif type.lower() in ("account","displaystring"):output += [(roster["display_string"])] + if type.find("namefull") != -1: + output += [(i["name_full"]) for i in roster["players"]] + elif type.find("name") != -1: + output += [(i["name"]) for i in roster["players"]] + elif type.find("playerid") != -1: + output += [i["id"] for i in roster["players"]] + elif type.lower() in ("account", "displaystring"): + output += [(roster["display_string"])] elif roster["client_id"] == ID and not type.startswith("all"): try: - if type in ("roster","fullrecord"):return(roster) + if type in ("roster", "fullrecord"): + return (roster) elif type.find("player") != -1 and roster["players"] != []: if len(roster["players"]) == 1 or type.find("singleplayer") != -1: - if type.find("namefull") != -1:return((roster["players"][0]["name_full"])) - elif type.find("name") != -1:return((roster["players"][0]["name"])) - elif type.find("playerid") != -1:return(roster["players"][0]["id"]) + if type.find("namefull") != -1: + return ((roster["players"][0]["name_full"])) + elif type.find("name") != -1: + return ((roster["players"][0]["name"])) + elif type.find("playerid") != -1: + return (roster["players"][0]["id"]) else: - if type.find("namefull") != -1:return([(i["name_full"]) for i in roster["players"]]) - elif type.find("name") != -1:return([(i["name"]) for i in roster["players"]]) - elif type.find("playerid") != -1:return([i["id"] for i in roster["players"]]) - elif type.lower() in ("account","displaystring"):return((roster["display_string"])) - except:ba.print_exception() - - return(None if len(output) == 0 else output) - def _edit_text_msg_box(self,text,type = "rewrite"): - if not isinstance(type,str) or not isinstance(text,str):return - type = type.lower();text = (text) - if type.find("add") != -1:ba.textwidget(edit=self._text_field,text=ba.textwidget(query=self._text_field)+text) - else:ba.textwidget(edit=self._text_field,text=text) - def _send_admin_kick_command(self):_ba.chatmessage("/kick " + str(self._popup_party_member_client_id)) - def new_input_window_callback(self,got_text, flag, code): + if type.find("namefull") != -1: + return ([(i["name_full"]) for i in roster["players"]]) + elif type.find("name") != -1: + return ([(i["name"]) for i in roster["players"]]) + elif type.find("playerid") != -1: + return ([i["id"] for i in roster["players"]]) + elif type.lower() in ("account", "displaystring"): + return ((roster["display_string"])) + except: + ba.print_exception() + + return (None if len(output) == 0 else output) + + def _edit_text_msg_box(self, text, type="rewrite"): + if not isinstance(type, str) or not isinstance(text, str): + return + type = type.lower() + text = (text) + if type.find("add") != -1: + ba.textwidget(edit=self._text_field, text=ba.textwidget(query=self._text_field)+text) + else: + ba.textwidget(edit=self._text_field, text=text) + + def _send_admin_kick_command(self): _ba.chatmessage( + "/kick " + str(self._popup_party_member_client_id)) + + def new_input_window_callback(self, got_text, flag, code): if got_text: if flag.startswith("Host_Kick_Player:"): try: - result = _ba.disconnect_client(self._popup_party_member_client_id, ban_time=int(code)) + result = _ba.disconnect_client( + self._popup_party_member_client_id, ban_time=int(code)) if not result: ba.playsound(ba.getsound('error')) ba.screenmessage( @@ -1066,7 +1146,6 @@ def new_input_window_callback(self,got_text, flag, code): ba.playsound(ba.getsound('error')) print(traceback.format_exc()) - def _kick_selected_player(self): """ result = _ba._disconnectClient(self._popup_party_member_client_id,banTime) @@ -1077,14 +1156,15 @@ def _kick_selected_player(self): if self._popup_party_member_client_id != -1: if _ba.get_foreground_host_session() is not None: self._popup_type = "banTimePress" - choices = [0,30,60,120,300,600,900,1800,3600,7200,99999999] if not (isinstance(self._getCustomSets().get("Ban_Time_List"),list) - and all([isinstance(item,int) for item in self._getCustomSets().get("Ban_Time_List")])) else self._getCustomSets().get("Ban_Time_List") + choices = [0, 30, 60, 120, 300, 600, 900, 1800, 3600, 7200, 99999999] if not (isinstance(self._getCustomSets().get("Ban_Time_List"), list) + and all([isinstance(item, int) for item in self._getCustomSets().get("Ban_Time_List")])) else self._getCustomSets().get("Ban_Time_List") PopupMenuWindow(position=self.get_root_widget().get_screen_space_center(), - scale=_get_popup_window_scale(), - choices=[str(item) for item in choices], - choices_display=_creat_Lstr_list([_getTransText("Ban_For_%d_Seconds")%item for item in choices]), - current_choice="Share_Server_Info", - delegate=self) + scale=_get_popup_window_scale(), + choices=[str(item) for item in choices], + choices_display=_creat_Lstr_list( + [_getTransText("Ban_For_%d_Seconds") % item for item in choices]), + current_choice="Share_Server_Info", + delegate=self) """ NewInputWindow(origin_widget = self.get_root_widget(), delegate = self,post_text = _getTransText("Ban_Time_Post"), @@ -1101,7 +1181,8 @@ def _kick_selected_player(self): else: # Ban for 5 minutes. - result = _ba.disconnect_client(self._popup_party_member_client_id, ban_time=5 * 60) + result = _ba.disconnect_client( + self._popup_party_member_client_id, ban_time=5 * 60) if not result: ba.playsound(ba.getsound('error')) ba.screenmessage( @@ -1116,8 +1197,9 @@ def _kick_selected_player(self): #NewShareCodeWindow(origin_widget=self.get_root_widget(), delegate=None,code = "300",execText = u"_ba._disconnectClient(%d,{Value})"%self._popup_party_member_client_id) def joinbombspot(self): import random - url=['https://discord.gg/CbxhJTrRta','https://discord.gg/ucyaesh'] - ba.open_url(url[random.randint(0,1)]) + url = ['https://discord.gg/CbxhJTrRta', 'https://discord.gg/ucyaesh'] + ba.open_url(url[random.randint(0, 1)]) + def _update(self) -> None: # pylint: disable=too-many-locals # pylint: disable=too-many-branches @@ -1140,16 +1222,16 @@ def _update(self) -> None: roster = _ba.get_game_roster() global f_chat global smo_mode - if roster != self._roster or smo_mode!=self.smoothy_mode or f_chat!=self.full_chat_mode: + if roster != self._roster or smo_mode != self.smoothy_mode or f_chat != self.full_chat_mode: self._roster = roster - smo_mode=self.smoothy_mode - f_chat=self.full_chat_mode + smo_mode = self.smoothy_mode + f_chat = self.full_chat_mode # clear out old for widget in self._name_widgets: widget.delete() self._name_widgets = [] - if not self._roster : + if not self._roster: top_section_height = 60 ba.textwidget(edit=self._empty_str, text=ba.Lstr(resource=self._r + '.emptyText')) @@ -1185,7 +1267,7 @@ def _update(self) -> None: # their names as a display string instead of the # client spec-string try: - if self.smoothy_mode ==1 and self._roster[index]['players']: + if self.smoothy_mode == 1 and self._roster[index]['players']: # if there's just one, use the full name; # otherwise combine short names if len(self._roster[index] @@ -1199,38 +1281,37 @@ def _update(self) -> None: ])) if len(p_str) > 25: p_str = p_str[:25] + '...' - elif self.smoothy_mode==0 : + elif self.smoothy_mode == 0: p_str = self._roster[index][ 'display_string'] - p_str= self._get_nick(p_str) + p_str = self._get_nick(p_str) else: - p_str = self._roster[index][ + p_str = self._roster[index][ 'display_string'] - except Exception: ba.print_exception( 'Error calcing client name str.') p_str = '???' try: - widget = ba.textwidget(parent=self._root_widget, - position=(pos[0], pos[1]), - scale=t_scale, - size=(c_width * 0.85, 30), - maxwidth=c_width * 0.85, - color=(1, 1, - 1) if index == 0 else - (1, 1, 1), - selectable=True, - autoselect=True, - click_activate=True, - text=ba.Lstr(value=p_str), - h_align='left', - v_align='center') - self._name_widgets.append(widget) + widget = ba.textwidget(parent=self._root_widget, + position=(pos[0], pos[1]), + scale=t_scale, + size=(c_width * 0.85, 30), + maxwidth=c_width * 0.85, + color=(1, 1, + 1) if index == 0 else + (1, 1, 1), + selectable=True, + autoselect=True, + click_activate=True, + text=ba.Lstr(value=p_str), + h_align='left', + v_align='center') + self._name_widgets.append(widget) except Exception: - pass + pass # in newer versions client_id will be present and # we can use that to determine who the host is. # in older versions we assume the first client is @@ -1245,13 +1326,13 @@ def _update(self) -> None: # calls; not spec-string (perhaps should wait till # client_id is more readily available though). try: - ba.textwidget(edit=widget, - on_activate_call=ba.Call( - self._on_party_member_press, - self._roster[index]['client_id'], - is_host, widget)) + ba.textwidget(edit=widget, + on_activate_call=ba.Call( + self._on_party_member_press, + self._roster[index]['client_id'], + is_host, widget)) except Exception: - pass + pass pos = (self._width * 0.53 - c_width_total * 0.5 + c_width * x, self._height - 65 - c_height * y) @@ -1266,71 +1347,72 @@ def _update(self) -> None: p_str, suppress_warning=True) * t_scale) try: - self._name_widgets.append( - ba.textwidget( - parent=self._root_widget, - position=(pos[0] + twd + 1, - pos[1] - 0.5), - size=(0, 0), - h_align='left', - v_align='center', - maxwidth=c_width * 0.96 - twd, - color=(0.1, 1, 0.1, 0.5), - text=ba.Lstr(resource=self._r + - '.hostText'), - scale=0.4, - shadow=0.1, - flatness=1.0)) + self._name_widgets.append( + ba.textwidget( + parent=self._root_widget, + position=(pos[0] + twd + 1, + pos[1] - 0.5), + size=(0, 0), + h_align='left', + v_align='center', + maxwidth=c_width * 0.96 - twd, + color=(0.1, 1, 0.1, 0.5), + text=ba.Lstr(resource=self._r + + '.hostText'), + scale=0.4, + shadow=0.1, + flatness=1.0)) except Exception: - pass + pass try: - ba.textwidget(edit=self._empty_str, text='') - ba.scrollwidget(edit=self._scrollwidget, - size=(self._width - 50, - max(100, self._height - 139 - - c_height_total)), - position=(30, 80)) + ba.textwidget(edit=self._empty_str, text='') + ba.scrollwidget(edit=self._scrollwidget, + size=(self._width - 50, + max(100, self._height - 139 - + c_height_total)), + position=(30, 80)) except Exception: - pass + pass + def hide_screen_msg(self): - file=open('ba_data/data/languages/english.json') - eng=json.loads(file.read()) + file = open('ba_data/data/languages/english.json') + eng = json.loads(file.read()) file.close() - eng['internal']['playerJoinedPartyText']='' - eng['internal']['playerLeftPartyText']='' - eng['internal']['chatBlockedText']='' - eng['kickVoteStartedText']='' + eng['internal']['playerJoinedPartyText'] = '' + eng['internal']['playerLeftPartyText'] = '' + eng['internal']['chatBlockedText'] = '' + eng['kickVoteStartedText'] = '' # eng['kickVoteText']='' - eng['kickWithChatText']='' - eng['kickOccurredText']='' - eng['kickVoteFailedText']='' - eng['votesNeededText']='' - eng['playerDelayedJoinText']='' - eng['playerLeftText']='' - eng['kickQuestionText']='' - file=open('ba_data/data/languages/english.json',"w") - json.dump(eng,file) + eng['kickWithChatText'] = '' + eng['kickOccurredText'] = '' + eng['kickVoteFailedText'] = '' + eng['votesNeededText'] = '' + eng['playerDelayedJoinText'] = '' + eng['playerLeftText'] = '' + eng['kickQuestionText'] = '' + file = open('ba_data/data/languages/english.json', "w") + json.dump(eng, file) file.close() ba.app.lang.setlanguage(None) def restore_screen_msg(self): - file=open('ba_data/data/languages/english.json') - eng=json.loads(file.read()) + file = open('ba_data/data/languages/english.json') + eng = json.loads(file.read()) file.close() - eng['internal']['playerJoinedPartyText']="${NAME} joined the pawri!" - eng['internal']['playerLeftPartyText']="${NAME} left the pawri." - eng['internal']['chatBlockedText']="${NAME} is chat-blocked for ${TIME} seconds." - eng['kickVoteStartedText']="A kick vote has been started for ${NAME}." + eng['internal']['playerJoinedPartyText'] = "${NAME} joined the pawri!" + eng['internal']['playerLeftPartyText'] = "${NAME} left the pawri." + eng['internal']['chatBlockedText'] = "${NAME} is chat-blocked for ${TIME} seconds." + eng['kickVoteStartedText'] = "A kick vote has been started for ${NAME}." # eng['kickVoteText']='' - eng['kickWithChatText']="Type ${YES} in chat for yes and ${NO} for no." - eng['kickOccurredText']="${NAME} was kicked." - eng['kickVoteFailedText']="Kick-vote failed." - eng['votesNeededText']="${NUMBER} votes needed" - eng['playerDelayedJoinText']="${PLAYER} will enter at the start of the next round." - eng['playerLeftText']="${PLAYER} left the game." - eng['kickQuestionText']="Kick ${NAME}?" - file=open('ba_data/data/languages/english.json',"w") - json.dump(eng,file) + eng['kickWithChatText'] = "Type ${YES} in chat for yes and ${NO} for no." + eng['kickOccurredText'] = "${NAME} was kicked." + eng['kickVoteFailedText'] = "Kick-vote failed." + eng['votesNeededText'] = "${NUMBER} votes needed" + eng['playerDelayedJoinText'] = "${PLAYER} will enter at the start of the next round." + eng['playerLeftText'] = "${PLAYER} left the game." + eng['kickQuestionText'] = "Kick ${NAME}?" + file = open('ba_data/data/languages/english.json', "w") + json.dump(eng, file) file.close() ba.app.lang.setlanguage(None) def popup_menu_selected_choice(self, popup_window: PopupMenuWindow, @@ -1346,109 +1428,119 @@ def popup_menu_selected_choice(self, popup_window: PopupMenuWindow, color=(1, 0, 0)) elif self._popup_type == "send_Times_Press": self._send_msg_times = int(choice) - ba.buttonwidget(edit = self._times_button,label="%s:%d"%(_getTransText("Times"),getattr(self,"_send_msg_times",1))) + ba.buttonwidget(edit=self._times_button, label="%s:%d" % + (_getTransText("Times"), getattr(self, "_send_msg_times", 1))) elif self._popup_type == "chatmessagepress": - if choice=="mute": + if choice == "mute": unmuted_names.remove(self.msg_user_selected) - if choice=="unmute": + if choice == "unmute": unmuted_names.append(self.msg_user_selected) - elif self._popup_type == "partyMemberPress": if choice == "kick": - ConfirmWindow(text=_getTransText("Normal_kick_confirm")%self._getObjectByID("account"), - action=self._kick_selected_player, cancel_button=True, cancel_is_selected=True, - color=self._bg_color, text_scale=1.0, - origin_widget=self.get_root_widget()) - elif choice=="info": - account=self._getObjectByID("account") - - self.loading_widget= ConfirmWindow(text="Searching .....", - color=self._bg_color, text_scale=1.0,cancel_button=False, + ConfirmWindow(text=_getTransText("Normal_kick_confirm") % self._getObjectByID("account"), + action=self._kick_selected_player, cancel_button=True, cancel_is_selected=True, + color=self._bg_color, text_scale=1.0, origin_widget=self.get_root_widget()) - start_new_thread(fetchAccountInfo,(account,self.loading_widget,)) + elif choice == "info": + account = self._getObjectByID("account") + + self.loading_widget = ConfirmWindow(text="Searching .....", + color=self._bg_color, text_scale=1.0, cancel_button=False, + origin_widget=self.get_root_widget()) + start_new_thread(fetchAccountInfo, (account, self.loading_widget,)) elif choice == "adminkick": - ConfirmWindow(text=_getTransText("Admin_Command_Kick_Confirm")%self._getObjectByID("account"), - action=self._send_admin_kick_command, cancel_button=True, cancel_is_selected=True, - color=self._bg_color, text_scale=1.0, - origin_widget=self.get_root_widget()) + ConfirmWindow(text=_getTransText("Admin_Command_Kick_Confirm") % self._getObjectByID("account"), + action=self._send_admin_kick_command, cancel_button=True, cancel_is_selected=True, + color=self._bg_color, text_scale=1.0, + origin_widget=self.get_root_widget()) elif choice == "@ this guy": - ChoiceDis = [];NewChoices = [] - account=self._getObjectByID("account") + ChoiceDis = [] + NewChoices = [] + account = self._getObjectByID("account") ChoiceDis.append(account) temp = self._getObjectByID("playerNameFull") if temp is not None: - if isinstance(temp,str) and temp not in ChoiceDis:ChoiceDis.append(temp) - elif isinstance(temp,(list,tuple)): + if isinstance(temp, str) and temp not in ChoiceDis: + ChoiceDis.append(temp) + elif isinstance(temp, (list, tuple)): for item in temp: - if isinstance(item,str) and item not in ChoiceDis:ChoiceDis.append(item) - #print("r\\"" + if isinstance(item, str) and item not in ChoiceDis: + ChoiceDis.append(item) + # print("r\\"" for item in ChoiceDis: - NewChoices.append(u"self._edit_text_msg_box('%s','add')"%(item.replace("'",r"'").replace('"',r'\\"'))) + NewChoices.append(u"self._edit_text_msg_box('%s','add')" % + (item.replace("'", r"'").replace('"', r'\\"'))) else: - nick=self._get_nick(account) - ChoiceDis.append(nick) - NewChoices.append(u"self._on_nick_rename_press('%s')"%(account)) + nick = self._get_nick(account) + ChoiceDis.append(nick) + NewChoices.append(u"self._on_nick_rename_press('%s')" % (account)) p = PopupMenuWindow(position=popup_window.root_widget.get_screen_space_center(), - scale=_get_popup_window_scale(), - choices=NewChoices, - choices_display=_creat_Lstr_list(ChoiceDis), - current_choice=NewChoices[0], - delegate=self) + scale=_get_popup_window_scale(), + choices=NewChoices, + choices_display=_creat_Lstr_list(ChoiceDis), + current_choice=NewChoices[0], + delegate=self) self._popup_type = "Custom_Exec_Choice" elif choice == "customAction": customActionSets = self._getCustomSets() - customActionSets = customActionSets.get("partyMemberPress_Custom") if isinstance(customActionSets.get("partyMemberPress_Custom"),dict) else {} - ChoiceDis = [];NewChoices = [] - for key,item in customActionSets.items(): - ChoiceDis.append(key);NewChoices.append(item) + customActionSets = customActionSets.get("partyMemberPress_Custom") if isinstance( + customActionSets.get("partyMemberPress_Custom"), dict) else {} + ChoiceDis = [] + NewChoices = [] + for key, item in customActionSets.items(): + ChoiceDis.append(key) + NewChoices.append(item) if len(ChoiceDis) > 0: p = PopupMenuWindow(position=popup_window.root_widget.get_screen_space_center(), - scale=_get_popup_window_scale(), - choices=NewChoices, - choices_display=_creat_Lstr_list(ChoiceDis), - current_choice=NewChoices[0], - delegate=self) + scale=_get_popup_window_scale(), + choices=NewChoices, + choices_display=_creat_Lstr_list(ChoiceDis), + current_choice=NewChoices[0], + delegate=self) self._popup_type = "customAction_partyMemberPress" - else:ba.playsound(ba.getsound("error"));ba.screenmessage(ba.Lstr(resource="getTicketsWindow.unavailableText"),color=(1,0,0)) + else: + ba.playsound(ba.getsound("error")) + ba.screenmessage( + ba.Lstr(resource="getTicketsWindow.unavailableText"), color=(1, 0, 0)) elif self._popup_type == "menu": if choice in ("mute", "unmute"): cfg = ba.app.config cfg['Chat Muted'] = (choice == 'mute') cfg.apply_and_commit() if cfg['Chat Muted']: - customchatThread().run() + customchatThread().run() self._update() elif choice in ("credits",): ConfirmWindow(text="AdvancePartyWindow by Mr.Smoothy \n extended version of ModifyPartyWindow(Plasma Boson) \n Version 5.3 \n Dont modify or release the source code \n Discord : \n mr.smoothy#5824 Plasma Boson#4104", - action=self.joinbombspot, width=420,height=200, - cancel_button=False, cancel_is_selected=False, - color=self._bg_color, text_scale=1.0, ok_text="More mods >", cancel_text=None, - origin_widget=self.get_root_widget()) - elif choice =="chatlogger": + action=self.joinbombspot, width=420, height=200, + cancel_button=False, cancel_is_selected=False, + color=self._bg_color, text_scale=1.0, ok_text="More mods >", cancel_text=None, + origin_widget=self.get_root_widget()) + elif choice == "chatlogger": # ColorPickerExact(parent=self.get_root_widget(), position=self.get_root_widget().get_screen_space_center(), # initial_color=self._bg_color, delegate=self, tag='') global chatlogger if chatlogger: - chatlogger=False - ba.screenmessage("Chat logger turned OFF") + chatlogger = False + ba.screenmessage("Chat logger turned OFF") else: - chatlogger=True - chatloggThread().run() - ba.screenmessage("Chat logger turned ON") - elif choice=='screenmsg': + chatlogger = True + chatloggThread().run() + ba.screenmessage("Chat logger turned ON") + elif choice == 'screenmsg': global screenmsg if screenmsg: - screenmsg=False + screenmsg = False self.hide_screen_msg() else: - screenmsg=True + screenmsg = True self.restore_screen_msg() elif choice == "addQuickReply": try: @@ -1456,138 +1548,171 @@ def popup_menu_selected_choice(self, popup_window: PopupMenuWindow, data = self._get_quick_responds() data.append(newReply) self._write_quick_responds(data) - ba.screenmessage(_getTransText("Something_is_added")%newReply,color=(0,1,0)) + ba.screenmessage(_getTransText("Something_is_added") % + newReply, color=(0, 1, 0)) ba.playsound(ba.getsound("dingSmallHigh")) - except:ba.print_exception() + except: + ba.print_exception() elif choice == "removeQuickReply": Quickreply = self._get_quick_responds() PopupMenuWindow(position=self._text_field.get_screen_space_center(), - scale=_get_popup_window_scale(), - choices=Quickreply, - choices_display=_creat_Lstr_list(Quickreply), - current_choice=Quickreply[0], - delegate=self) + scale=_get_popup_window_scale(), + choices=Quickreply, + choices_display=_creat_Lstr_list(Quickreply), + current_choice=Quickreply[0], + delegate=self) self._popup_type = "removeQuickReplySelect" - elif choice in ("hostInfo_Debug",) and isinstance(_ba.get_connection_to_host_info(),dict): + elif choice in ("hostInfo_Debug",) and isinstance(_ba.get_connection_to_host_info(), dict): if len(_ba.get_connection_to_host_info()) > 0: - #print(_ba.get_connection_to_host_info(),type(_ba.get_connection_to_host_info())) + # print(_ba.get_connection_to_host_info(),type(_ba.get_connection_to_host_info())) ChoiceDis = list(_ba.get_connection_to_host_info().keys()) - NewChoices = ["ba.screenmessage(str(_ba.get_connection_to_host_info().get('%s')))"%((str(i)).replace("'",r"'").replace('"',r'\\"')) for i in ChoiceDis] + NewChoices = ["ba.screenmessage(str(_ba.get_connection_to_host_info().get('%s')))" % ( + (str(i)).replace("'", r"'").replace('"', r'\\"')) for i in ChoiceDis] PopupMenuWindow(position=popup_window.root_widget.get_screen_space_center(), - scale=_get_popup_window_scale(), - choices=NewChoices, - choices_display=_creat_Lstr_list(ChoiceDis), - current_choice=NewChoices[0], - delegate=self) + scale=_get_popup_window_scale(), + choices=NewChoices, + choices_display=_creat_Lstr_list(ChoiceDis), + current_choice=NewChoices[0], + delegate=self) self._popup_type = "Custom_Exec_Choice" - else:ba.playsound(ba.getsound("error"));ba.screenmessage(ba.Lstr(resource="getTicketsWindow.unavailableText"),color=(1,0,0)) + else: + ba.playsound(ba.getsound("error")) + ba.screenmessage( + ba.Lstr(resource="getTicketsWindow.unavailableText"), color=(1, 0, 0)) elif choice == "translator": chats = _ba._getChatMessages() if len(chats) > 0: choices = [(item) for item in chats[::-1]] PopupMenuWindow(position=popup_window.root_widget.get_screen_space_center(), - scale=_get_popup_window_scale(), - choices=choices, - choices_display=_creat_Lstr_list(choices), - current_choice=choices[0], - delegate=self) + scale=_get_popup_window_scale(), + choices=choices, + choices_display=_creat_Lstr_list(choices), + current_choice=choices[0], + delegate=self) self._popup_type = "translator_Press" - else:ba.playsound(ba.getsound("error"));ba.screenmessage(ba.Lstr(resource="getTicketsWindow.unavailableText"),color=(1,0,0)) + else: + ba.playsound(ba.getsound("error")) + ba.screenmessage( + ba.Lstr(resource="getTicketsWindow.unavailableText"), color=(1, 0, 0)) elif choice == "resetGameRecord": ConfirmWindow(text=_getTransText("Restart_Game_Record_Confirm"), - action=self._reset_game_record, cancel_button=True, cancel_is_selected=True, - color=self._bg_color, text_scale=1.0, - origin_widget=self.get_root_widget()) + action=self._reset_game_record, cancel_button=True, cancel_is_selected=True, + color=self._bg_color, text_scale=1.0, + origin_widget=self.get_root_widget()) elif self._popup_type == "translator_Press": if len(tranTypes) == 1: - exec("start_new_thread(OnlineTranslator.%s,(u'%s',))"%(tranTypes[0],choice.replace("'",r"'").replace('"',r'\\"'))) + exec("start_new_thread(OnlineTranslator.%s,(u'%s',))" % + (tranTypes[0], choice.replace("'", r"'").replace('"', r'\\"'))) elif len(tranTypes) > 1: - choices = ["start_new_thread(OnlineTranslator.%s,(u'%s',))"%(item,choice.replace("'",r"'").replace('"',r'\\"')) for item in tranTypes] + choices = ["start_new_thread(OnlineTranslator.%s,(u'%s',))" % ( + item, choice.replace("'", r"'").replace('"', r'\\"')) for item in tranTypes] PopupMenuWindow(position=popup_window.root_widget.get_screen_space_center(), - scale=_get_popup_window_scale(), - choices=choices, - choices_display=_creat_Lstr_list(tranTypes), - current_choice=choices[0], - delegate=self) + scale=_get_popup_window_scale(), + choices=choices, + choices_display=_creat_Lstr_list(tranTypes), + current_choice=choices[0], + delegate=self) self._popup_type = "Custom_Exec_Choice" - else:ba.playsound(ba.getsound("error"));ba.screenmessage(ba.Lstr(resource="getTicketsWindow.unavailableText"),color=(1,0,0)) + else: + ba.playsound(ba.getsound("error")) + ba.screenmessage( + ba.Lstr(resource="getTicketsWindow.unavailableText"), color=(1, 0, 0)) elif self._popup_type == "customAction_partyMemberPress": try: - keyReplaceValue = (r"{$PlayerNameFull}",r"{$PlayerName}",r"{$PlayerID}",r"{$AccountInfo}",r"{$AllPlayerName}",r"{$AllPlayerNameFull}") - pos = None;curKeyWord = None + keyReplaceValue = (r"{$PlayerNameFull}", r"{$PlayerName}", r"{$PlayerID}", + r"{$AccountInfo}", r"{$AllPlayerName}", r"{$AllPlayerNameFull}") + pos = None + curKeyWord = None for keyWord in keyReplaceValue: CurPos = choice.find(keyWord) if CurPos != -1 and (pos is None or CurPos < pos): - pos = CurPos;curKeyWord = keyWord - if isinstance(pos,int) and isinstance(curKeyWord,str): - if curKeyWord in (r"{$PlayerNameFull}",r"{$PlayerName}",r"{$AllPlayerName}",r"{$AllPlayerNameFull}"): - #if choice.count(curKeyWord) != 0: - playerName = self._getObjectByID(curKeyWord.replace("{$","").replace("}","")) - if isinstance(playerName,(list,tuple)): - ChoiceDis = [];NewChoices = [] + pos = CurPos + curKeyWord = keyWord + if isinstance(pos, int) and isinstance(curKeyWord, str): + if curKeyWord in (r"{$PlayerNameFull}", r"{$PlayerName}", r"{$AllPlayerName}", r"{$AllPlayerNameFull}"): + # if choice.count(curKeyWord) != 0: + playerName = self._getObjectByID( + curKeyWord.replace("{$", "").replace("}", "")) + if isinstance(playerName, (list, tuple)): + ChoiceDis = [] + NewChoices = [] for i in playerName: ChoiceDis.append(i) - NewChoices.append(choice.replace(curKeyWord,(i.replace("'",r"'").replace('"',r'\\"')),1)) + NewChoices.append(choice.replace( + curKeyWord, (i.replace("'", r"'").replace('"', r'\\"')), 1)) p = PopupMenuWindow(position=popup_window.root_widget.get_screen_space_center(), - scale=_get_popup_window_scale(), - choices=NewChoices, - choices_display=_creat_Lstr_list(ChoiceDis), - current_choice=NewChoices[0], - delegate=self) + scale=_get_popup_window_scale(), + choices=NewChoices, + choices_display=_creat_Lstr_list(ChoiceDis), + current_choice=NewChoices[0], + delegate=self) self._popup_type = "customAction_partyMemberPress" - elif isinstance(playerName,str): - self.popup_menu_selected_choice(popup_window,choice.replace(curKeyWord,(playerName.replace("'",r"'").replace('"',r'\\"')),1)) - else:ba.screenmessage(_getTransText("No_valid_player_found"),(1,0,0));ba.playsound(ba.getsound("error")) + elif isinstance(playerName, str): + self.popup_menu_selected_choice(popup_window, choice.replace( + curKeyWord, (playerName.replace("'", r"'").replace('"', r'\\"')), 1)) + else: + ba.screenmessage(_getTransText("No_valid_player_found"), (1, 0, 0)) + ba.playsound(ba.getsound("error")) elif curKeyWord in (r"{$PlayerID}",) != 0: playerID = self._getObjectByID("PlayerID") playerName = self._getObjectByID("PlayerName") - #print(playerID,playerName) - if isinstance(playerID,(list,tuple)) and isinstance(playerName,(list,tuple)) and len(playerName) == len(playerID): - ChoiceDis = [];NewChoices = [] - for i1,i2 in playerName,playerID: - ChoiceDis.append(i1);NewChoices.append(choice.replace(r"{$PlayerID}",str(i2).replace("'",r"'").replace('"',r'\\"')),1) + # print(playerID,playerName) + if isinstance(playerID, (list, tuple)) and isinstance(playerName, (list, tuple)) and len(playerName) == len(playerID): + ChoiceDis = [] + NewChoices = [] + for i1, i2 in playerName, playerID: + ChoiceDis.append(i1) + NewChoices.append(choice.replace(r"{$PlayerID}", str( + i2).replace("'", r"'").replace('"', r'\\"')), 1) p = PopupMenuWindow(position=popup_window.root_widget.get_screen_space_center(), - scale=_get_popup_window_scale(), - choices=NewChoices, - choices_display=_creat_Lstr_list(ChoiceDis), - current_choice=NewChoices[0], - delegate=self) + scale=_get_popup_window_scale(), + choices=NewChoices, + choices_display=_creat_Lstr_list(ChoiceDis), + current_choice=NewChoices[0], + delegate=self) self._popup_type = "customAction_partyMemberPress" - elif isinstance(playerID,int): - self.popup_menu_selected_choice(popup_window,choice.replace(r"{$PlayerID}",str(playerID).replace("'",r"'").replace('"',r'\\"'))) - else:ba.screenmessage(_getTransText("No_valid_player_id_found"),(1,0,0));ba.playsound(ba.getsound("error")) + elif isinstance(playerID, int): + self.popup_menu_selected_choice(popup_window, choice.replace( + r"{$PlayerID}", str(playerID).replace("'", r"'").replace('"', r'\\"'))) + else: + ba.screenmessage(_getTransText("No_valid_player_id_found"), (1, 0, 0)) + ba.playsound(ba.getsound("error")) elif curKeyWord in (r"{$AccountInfo}",) != 0: - self.popup_menu_selected_choice(popup_window,choice.replace(r"{$AccountInfo}",(str(self._getObjectByID("roster"))).replace("'",r"'").replace('"',r'\\"'),1)) - else:exec(choice) - except Exception as e:ba.screenmessage(repr(e),(1,0,0)) + self.popup_menu_selected_choice(popup_window, choice.replace( + r"{$AccountInfo}", (str(self._getObjectByID("roster"))).replace("'", r"'").replace('"', r'\\"'), 1)) + else: + exec(choice) + except Exception as e: + ba.screenmessage(repr(e), (1, 0, 0)) elif self._popup_type == "QuickMessageSelect": - #ba.textwidget(edit=self._text_field,text=self._get_quick_responds()[index]) - self._edit_text_msg_box(choice,"add") + # ba.textwidget(edit=self._text_field,text=self._get_quick_responds()[index]) + self._edit_text_msg_box(choice, "add") elif self._popup_type == "removeQuickReplySelect": data = self._get_quick_responds() if len(data) > 0 and choice in data: data.remove(choice) self._write_quick_responds(data) - ba.screenmessage(_getTransText("Something_is_removed")%choice,(1,0,0)) + ba.screenmessage(_getTransText("Something_is_removed") % choice, (1, 0, 0)) ba.playsound(ba.getsound("shieldDown")) - else:ba.screenmessage(ba.Lstr(resource="errorText"),(1,0,0));ba.playsound(ba.getsound("error")) + else: + ba.screenmessage(ba.Lstr(resource="errorText"), (1, 0, 0)) + ba.playsound(ba.getsound("error")) elif choice.startswith("custom_Exec_Choice_") or self._popup_type == "Custom_Exec_Choice": - exec(choice[len("custom_Exec_Choice_"):] if choice.startswith("custom_Exec_Choice_") else choice) + exec(choice[len("custom_Exec_Choice_"):] + if choice.startswith("custom_Exec_Choice_") else choice) else: print("unhandled popup type: "+str(self._popup_type)) -import base64 -from ba._general import Call -def fetchAccountInfo(account,loading_widget): - pbid="" - account_data=[] - servers=[] +def fetchAccountInfo(account, loading_widget): + pbid = "" + account_data = [] + servers = [] try: filePath = os.path.join(RecordFilesDir, "players.json") fdata = {} @@ -1595,35 +1720,38 @@ def fetchAccountInfo(account,loading_widget): f = open(filePath, "r") fdata = json.load(f) if account in fdata: - servers=fdata[account] - data = urllib.request.urlopen(f'https://api.bombsquad.ga/player?key={base64.b64encode(account.encode("utf-8")).decode("utf-8")}&base64=true') - account_data=json.loads(data.read().decode('utf-8'))[0] - pbid=account_data["pbid"] + servers = fdata[account] + data = urllib.request.urlopen( + f'https://api.bombsquad.ga/player?key={base64.b64encode(account.encode("utf-8")).decode("utf-8")}&base64=true') + account_data = json.loads(data.read().decode('utf-8'))[0] + pbid = account_data["pbid"] except: pass # _ba.pushcall(Call(updateAccountWindow,loading_widget,accounts[0]),from_other_thread=True) - _ba.pushcall(Call(CustomAccountViewerWindow,pbid,account_data,servers,loading_widget),from_other_thread =True) + _ba.pushcall(Call(CustomAccountViewerWindow, pbid, account_data, + servers, loading_widget), from_other_thread=True) -from bastd.ui.account import viewer class CustomAccountViewerWindow(viewer.AccountViewerWindow): - def __init__(self,account_id,custom_data,servers,loading_widget): + def __init__(self, account_id, custom_data, servers, loading_widget): super().__init__(account_id) try: loading_widget._cancel() except: pass - self.custom_data=custom_data - self.pb_id=account_id - self.servers=servers + self.custom_data = custom_data + self.pb_id = account_id + self.servers = servers + def _copy_pb(self): ba.clipboard_set_text(self.pb_id) ba.screenmessage(ba.Lstr(resource='gatherWindow.copyCodeConfirmText')) - def _on_query_response(self,data): + + def _on_query_response(self, data): if data is None: - ba.textwidget(edit=self._loading_text,text="") + ba.textwidget(edit=self._loading_text, text="") ba.textwidget(parent=self._scrollwidget, size=(0, 0), position=(170, 200), @@ -1634,7 +1762,7 @@ def _on_query_response(self,data): color=ba.app.ui.infotextcolor, text="Mutual servers", maxwidth=300) - v=200-21 + v = 200-21 for server in self.servers: ba.textwidget(parent=self._scrollwidget, size=(0, 0), @@ -1644,7 +1772,7 @@ def _on_query_response(self,data): scale=0.55, text=server, maxwidth=300) - v-=23 + v -= 23 else: for account in self.custom_data["accounts"]: if account not in data["accountDisplayStrings"]: @@ -1670,7 +1798,7 @@ def _on_query_response(self,data): suppress_warning=True) sub_width = self._width - 80 sub_height = 500 + ts_height * tscale + \ - account_name_spacing * len(data['accountDisplayStrings']) + account_name_spacing * len(data['accountDisplayStrings']) self._subcontainer = ba.containerwidget( parent=self._scrollwidget, size=(sub_width, sub_height), @@ -1775,7 +1903,7 @@ def _on_query_response(self,data): maxwidth=sub_width * maxwidth_scale) self._copy_btn = ba.buttonwidget( parent=self._subcontainer, - position=(sub_width * center -120, v -9), + position=(sub_width * center - 120, v - 9), size=(60, 30), scale=0.5, label='copy', @@ -1783,7 +1911,7 @@ def _on_query_response(self,data): on_activate_call=self._copy_pb, autoselect=True) - v-=24 + v -= 24 ba.textwidget(parent=self._subcontainer, size=(0, 0), position=(sub_width * center, v), @@ -1794,7 +1922,7 @@ def _on_query_response(self,data): color=ba.app.ui.infotextcolor, text="Name", maxwidth=sub_width * maxwidth_scale) - v-=26 + v -= 26 for name in self.custom_data["names"]: ba.textwidget(parent=self._subcontainer, size=(0, 0), @@ -1804,8 +1932,8 @@ def _on_query_response(self,data): scale=0.51, text=name, maxwidth=sub_width * maxwidth_scale) - v-=13 - v-=8 + v -= 13 + v -= 8 ba.textwidget(parent=self._subcontainer, size=(0, 0), position=(sub_width * center, v), @@ -1816,8 +1944,8 @@ def _on_query_response(self,data): color=ba.app.ui.infotextcolor, text="Created On", maxwidth=sub_width * maxwidth_scale) - v-=19 - d=self.custom_data["createdOn"] + v -= 19 + d = self.custom_data["createdOn"] ba.textwidget(parent=self._subcontainer, size=(0, 0), @@ -1827,7 +1955,7 @@ def _on_query_response(self,data): scale=0.55, text=d[:d.index("T")], maxwidth=sub_width * maxwidth_scale) - v-=29 + v -= 29 ba.textwidget(parent=self._subcontainer, size=(0, 0), position=(sub_width * center, v), @@ -1839,14 +1967,15 @@ def _on_query_response(self,data): text="Discord", maxwidth=sub_width * maxwidth_scale) v -= 19 - if len(self.custom_data["discord"]) >0: + if len(self.custom_data["discord"]) > 0: ba.textwidget(parent=self._subcontainer, size=(0, 0), position=(sub_width * center, v), h_align='center', v_align='center', scale=0.55, - text=self.custom_data["discord"][0]["username"]+ ","+self.custom_data["discord"][0]["id"], + text=self.custom_data["discord"][0]["username"] + + ","+self.custom_data["discord"][0]["id"], maxwidth=sub_width * maxwidth_scale) v -= 26 ba.textwidget(parent=self._subcontainer, @@ -1859,8 +1988,8 @@ def _on_query_response(self,data): color=ba.app.ui.infotextcolor, text="Mutual servers", maxwidth=sub_width * maxwidth_scale) - v=-19 - v=270 + v = -19 + v = 270 for server in self.servers: ba.textwidget(parent=self._subcontainer, size=(0, 0), @@ -1870,10 +1999,10 @@ def _on_query_response(self,data): scale=0.55, text=server, maxwidth=sub_width * maxwidth_scale) - v-=13 + v -= 13 - v-=16 - #================================================================== + v -= 16 + # ================================================================== ba.textwidget(parent=self._subcontainer, size=(0, 0), position=(sub_width * center, v), @@ -2006,7 +2135,7 @@ def _on_query_response(self,data): v_align='center', scale=0.55, text=str(data['achievementsCompleted']) + ' / ' + - str(len(ba.app.ach.achievements)), + str(len(ba.app.ach.achievements)), maxwidth=sub_width * maxwidth_scale) v -= 25 @@ -2043,9 +2172,12 @@ def _on_query_response(self,data): 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: - _ba.connect_to_party=newconnect_to_party + if _ba.env().get("build_number", 0) >= 20577: + _ba.connect_to_party = newconnect_to_party bastd_party.PartyWindow = ModifiedPartyWindow - else:print("AdvancePartyWindow only runs with BombSquad version equal or higher than 1.7") + else: + print("AdvancePartyWindow only runs with BombSquad version equal or higher than 1.7") diff --git a/plugins/utilities/server_switch.py b/plugins/utilities/server_switch.py index 6047f299..66b90bd2 100644 --- a/plugins/utilities/server_switch.py +++ b/plugins/utilities/server_switch.py @@ -13,7 +13,7 @@ from enum import Enum from dataclasses import dataclass if TYPE_CHECKING: - from typing import Any, Optional, Dict, List, Tuple,Type + from typing import Any, Optional, Dict, List, Tuple, Type import ba from bastd.ui.gather import GatherWindow @@ -22,540 +22,551 @@ import bastd.ui.mainmenu as bastd_ui_mainmenu -connect=_ba.connect_to_party -disconnect=_ba.disconnect_from_host +connect = _ba.connect_to_party +disconnect = _ba.disconnect_from_host -server=[] +server = [] -ip_add="private" -p_port=44444 -p_name="nothing here" -def newconnect_to_party(address,port=43210,print_progress=False): +ip_add = "private" +p_port = 44444 +p_name = "nothing here" + + +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!={} ): + dd = _ba.get_connection_to_host_info() + if (dd != {}): _ba.disconnect_from_host() - ip_add=address - p_port=port - connect(address,port,print_progress) + ip_add = address + p_port = port + connect(address, port, print_progress) else: - - ip_add=address - p_port=port + ip_add = address + p_port = port # print(ip_add,p_port) - connect(ip_add,port,print_progress) + connect(ip_add, port, print_progress) + + def newdisconnect_from_host(): try: - name=_ba.get_connection_to_host_info()['name'] + name = _ba.get_connection_to_host_info()['name'] global server global ip_add global p_port - pojo = {"name":name,"ip":ip_add,"port":p_port} + pojo = {"name": name, "ip": ip_add, "port": p_port} if pojo not in server: - server.insert(0,pojo) + server.insert(0, pojo) server = server[:3] except: pass disconnect() + def printip(): ba.screenmessage("ip address is"+ip_add) + + def new_refresh_in_game( self, positions: List[Tuple[float, float, float]]) -> Tuple[float, float, float]: - # pylint: disable=too-many-branches - # pylint: disable=too-many-locals - # pylint: disable=too-many-statements - custom_menu_entries: List[Dict[str, Any]] = [] - session = _ba.get_foreground_host_session() - if session is not None: - try: - custom_menu_entries = session.get_custom_menu_entries() - for cme in custom_menu_entries: - if (not isinstance(cme, dict) or 'label' not in cme - or not isinstance(cme['label'], (str, ba.Lstr)) - or 'call' not in cme or not callable(cme['call'])): - raise ValueError('invalid custom menu entry: ' + - str(cme)) - except Exception: - custom_menu_entries = [] - ba.print_exception( - f'Error getting custom menu entries for {session}') - self._width = 250.0 - self._height = 250.0 if self._input_player else 180.0 - if (self._is_demo or self._is_arcade) and self._input_player: - self._height -= 40 - if not self._have_settings_button: - self._height -= 50 - if self._connected_to_remote_player: - # In this case we have a leave *and* a disconnect button. - self._height += 50 - self._height += 50 * (len(custom_menu_entries)) - uiscale = ba.app.ui.uiscale - ba.containerwidget( - edit=self._root_widget, - size=(self._width*2, self._height), - scale=(2.15 if uiscale is ba.UIScale.SMALL else - 1.6 if uiscale is ba.UIScale.MEDIUM else 1.0)) - h = 125.0 - v = (self._height - 80.0 if self._input_player else self._height - 60) - h_offset = 0 - d_h_offset = 0 - v_offset = -50 - for _i in range(6 + len(custom_menu_entries)): - positions.append((h, v, 1.0)) - v += v_offset - h += h_offset - h_offset += d_h_offset - self._start_button = None - ba.app.pause() - h, v, scale = positions[self._p_index] + # pylint: disable=too-many-branches + # pylint: disable=too-many-locals + # pylint: disable=too-many-statements + custom_menu_entries: List[Dict[str, Any]] = [] + session = _ba.get_foreground_host_session() + if session is not None: + try: + custom_menu_entries = session.get_custom_menu_entries() + for cme in custom_menu_entries: + if (not isinstance(cme, dict) or 'label' not in cme + or not isinstance(cme['label'], (str, ba.Lstr)) + or 'call' not in cme or not callable(cme['call'])): + raise ValueError('invalid custom menu entry: ' + + str(cme)) + except Exception: + custom_menu_entries = [] + ba.print_exception( + f'Error getting custom menu entries for {session}') + self._width = 250.0 + self._height = 250.0 if self._input_player else 180.0 + if (self._is_demo or self._is_arcade) and self._input_player: + self._height -= 40 + if not self._have_settings_button: + self._height -= 50 + if self._connected_to_remote_player: + # In this case we have a leave *and* a disconnect button. + self._height += 50 + self._height += 50 * (len(custom_menu_entries)) + uiscale = ba.app.ui.uiscale + ba.containerwidget( + edit=self._root_widget, + size=(self._width*2, self._height), + scale=(2.15 if uiscale is ba.UIScale.SMALL else + 1.6 if uiscale is ba.UIScale.MEDIUM else 1.0)) + h = 125.0 + v = (self._height - 80.0 if self._input_player else self._height - 60) + h_offset = 0 + d_h_offset = 0 + v_offset = -50 + for _i in range(6 + len(custom_menu_entries)): + positions.append((h, v, 1.0)) + v += v_offset + h += h_offset + h_offset += d_h_offset + self._start_button = None + ba.app.pause() + h, v, scale = positions[self._p_index] + ba.textwidget( + parent=self._root_widget, + draw_controller=None, + text="IP: "+ip_add+" PORT: "+str(p_port), + position=(h+self._button_width-80, v+60), + h_align='center', + v_align='center', + size=(20, 60), + scale=0.6) + v_h = v + + global server + + def con(address, port): + global ip_add + global p_port + if (address == ip_add and port == p_port): + self._resume() + else: + _ba.disconnect_from_host() + _ba.connect_to_party(address, port) + if len(server) == 0: ba.textwidget( - parent=self._root_widget, - draw_controller=None, - text="IP: "+ip_add+" PORT: "+str(p_port), - position=(h+self._button_width-80,v+60), - h_align='center', - v_align='center', - size=(20, 60), - scale=0.6) - v_h=v - - global server - def con(address,port): - global ip_add - global p_port - if(address==ip_add and port==p_port): - self._resume() - else: - _ba.disconnect_from_host() - _ba.connect_to_party(address,port) - if len(server) ==0: - ba.textwidget( - parent=self._root_widget, - draw_controller=None, - text="Nothing in \n recents", - position=(h +self._button_width *scale ,v-30), - h_align='center', - v_align='center', - size=(20, 60), - scale=1) - for ser in server: - self._server_button = ba.buttonwidget( - color=(0.8, 0, 1), - parent=self._root_widget, - position=(h +self._button_width *scale - 80, v_h), - size=(self._button_width, self._button_height), - scale=scale, - autoselect=self._use_autoselect, - label=ser["name"][0:22], - - on_activate_call=ba.Call(con,ser["ip"],ser["port"])) - v_h=v_h-50 - - # Player name if applicable. - if self._input_player: - player_name = self._input_player.getname() - h, v, scale = positions[self._p_index] - v += 35 - ba.textwidget(parent=self._root_widget, + parent=self._root_widget, + draw_controller=None, + text="Nothing in \n recents", + position=(h + self._button_width * scale, v-30), + h_align='center', + v_align='center', + size=(20, 60), + scale=1) + for ser in server: + self._server_button = ba.buttonwidget( + color=(0.8, 0, 1), + parent=self._root_widget, + position=(h + self._button_width * scale - 80, v_h), + size=(self._button_width, self._button_height), + scale=scale, + autoselect=self._use_autoselect, + label=ser["name"][0:22], + + on_activate_call=ba.Call(con, ser["ip"], ser["port"])) + v_h = v_h-50 + + # Player name if applicable. + if self._input_player: + player_name = self._input_player.getname() + h, v, scale = positions[self._p_index] + v += 35 + ba.textwidget(parent=self._root_widget, + position=(h - self._button_width / 2, v), + size=(self._button_width, self._button_height), + color=(1, 1, 1, 0.5), + scale=0.7, + h_align='center', + text=ba.Lstr(value=player_name)) + else: + player_name = '' + h, v, scale = positions[self._p_index] + self._p_index += 1 + btn = ba.buttonwidget(parent=self._root_widget, position=(h - self._button_width / 2, v), size=(self._button_width, self._button_height), - color=(1, 1, 1, 0.5), - scale=0.7, - h_align='center', - text=ba.Lstr(value=player_name)) + scale=scale, + label=ba.Lstr(resource=self._r + '.resumeText'), + autoselect=self._use_autoselect, + on_activate_call=self._resume) + ba.containerwidget(edit=self._root_widget, cancel_button=btn) + + # Add any custom options defined by the current game. + for entry in custom_menu_entries: + h, v, scale = positions[self._p_index] + self._p_index += 1 + + # Ask the entry whether we should resume when we call + # it (defaults to true). + resume = bool(entry.get('resume_on_call', True)) + + if resume: + call = ba.Call(self._resume_and_call, entry['call']) else: - player_name = '' + call = ba.Call(entry['call'], ba.WeakCall(self._resume)) + + ba.buttonwidget(parent=self._root_widget, + position=(h - self._button_width / 2, v), + size=(self._button_width, self._button_height), + scale=scale, + on_activate_call=call, + label=entry['label'], + autoselect=self._use_autoselect) + # Add a 'leave' button if the menu-owner has a player. + if ((self._input_player or self._connected_to_remote_player) + and not (self._is_demo or self._is_arcade)): h, v, scale = positions[self._p_index] self._p_index += 1 btn = ba.buttonwidget(parent=self._root_widget, position=(h - self._button_width / 2, v), - size=(self._button_width, self._button_height), + size=(self._button_width, + self._button_height), scale=scale, - label=ba.Lstr(resource=self._r + '.resumeText'), - autoselect=self._use_autoselect, - on_activate_call=self._resume) - ba.containerwidget(edit=self._root_widget, cancel_button=btn) + on_activate_call=self._leave, + label='', + autoselect=self._use_autoselect) + + if (player_name != '' and player_name[0] != '<' + and player_name[-1] != '>'): + txt = ba.Lstr(resource=self._r + '.justPlayerText', + subs=[('${NAME}', player_name)]) + else: + txt = ba.Lstr(value=player_name) + ba.textwidget(parent=self._root_widget, + position=(h, v + self._button_height * + (0.64 if player_name != '' else 0.5)), + size=(0, 0), + text=ba.Lstr(resource=self._r + '.leaveGameText'), + scale=(0.83 if player_name != '' else 1.0), + color=(0.75, 1.0, 0.7), + h_align='center', + v_align='center', + draw_controller=btn, + maxwidth=self._button_width * 0.9) + ba.textwidget(parent=self._root_widget, + position=(h, v + self._button_height * 0.27), + size=(0, 0), + text=txt, + color=(0.75, 1.0, 0.7), + h_align='center', + v_align='center', + draw_controller=btn, + scale=0.45, + maxwidth=self._button_width * 0.9) + return h, v, scale - # Add any custom options defined by the current game. - for entry in custom_menu_entries: - h, v, scale = positions[self._p_index] - self._p_index += 1 - # Ask the entry whether we should resume when we call - # it (defaults to true). - resume = bool(entry.get('resume_on_call', True)) +def new_refresh(self) -> None: + # pylint: disable=too-many-branches + # pylint: disable=too-many-locals + # pylint: disable=too-many-statements + global server + print(server) + from bastd.ui.confirm import QuitWindow + from bastd.ui.store.button import StoreButton + import ba + # Clear everything that was there. + children = self._root_widget.get_children() + for child in children: + child.delete() + + self._tdelay = 0.0 + self._t_delay_inc = 0.0 + self._t_delay_play = 0.0 + self._button_width = 200.0 + self._button_height = 45.0 + + self._r = 'mainMenu' + + app = ba.app + self._have_quit_button = (app.ui.uiscale is ba.UIScale.LARGE + or (app.platform == 'windows' + and app.subplatform == 'oculus')) + + self._have_store_button = not self._in_game + + self._have_settings_button = ( + (not self._in_game or not app.toolbar_test) + and not (self._is_demo or self._is_arcade or self._is_iircade)) + + self._input_device = input_device = _ba.get_ui_input_device() + self._input_player = input_device.player if input_device else None + self._connected_to_remote_player = ( + input_device.is_connected_to_remote_player() + if input_device else False) + + positions: List[Tuple[float, float, float]] = [] + self._p_index = 0 + + if self._in_game: + h, v, scale = self._refresh_in_game(positions) + print("refreshing in GAME", ip_add) + # btn = ba.buttonwidget(parent=self._root_widget, + # position=(80,270), + # size=(100, 90), + # scale=1.2, + # label=ip_add, + # autoselect=None, + # on_activate_call=printip) + ba.textwidget( + parent=self._root_widget, + draw_controller=None, + text="IP: "+ip_add+" PORT: "+str(p_port), + position=(150, 270), + h_align='center', + v_align='center', + size=(20, 60), + scale=1) + self._server_button = ba.buttonwidget( + parent=self._root_widget, + position=(h * 3.2 + 20 - self._button_width * scale, v), + size=(self._button_width, self._button_height), + scale=scale, + autoselect=self._use_autoselect, + label=ba.Lstr(resource=self._r + '.settingsText'), + transition_delay=self._tdelay, + on_activate_call=self._settings) + self._server_button2 = ba.buttonwidget( + parent=self._root_widget, + position=(h * 3.2 + 20 - self._button_width * scale, v-50), + size=(self._button_width, self._button_height), + scale=scale, + autoselect=self._use_autoselect, + label=ba.Lstr(resource=self._r + '.settingsText'), + transition_delay=self._tdelay, + on_activate_call=self._settings) + self._server_button3 = ba.buttonwidget( + parent=self._root_widget, + position=(h * 3.2 + 20 - self._button_width * scale, v-100), + size=(self._button_width, self._button_height), + scale=scale, + autoselect=self._use_autoselect, + label=ba.Lstr(resource=self._r + '.settingsText'), + transition_delay=self._tdelay, + on_activate_call=self._settings) - if resume: - call = ba.Call(self._resume_and_call, entry['call']) - else: - call = ba.Call(entry['call'], ba.WeakCall(self._resume)) + else: + h, v, scale = self._refresh_not_in_game(positions) + + if self._have_settings_button: + h, v, scale = positions[self._p_index] + self._p_index += 1 + self._settings_button = ba.buttonwidget( + parent=self._root_widget, + position=(h - self._button_width * 0.5 * scale, v), + size=(self._button_width, self._button_height), + scale=scale, + autoselect=self._use_autoselect, + label=ba.Lstr(resource=self._r + '.settingsText'), + transition_delay=self._tdelay, + on_activate_call=self._settings) + + # Scattered eggs on easter. + if _ba.get_account_misc_read_val('easter', + False) and not self._in_game: + icon_size = 34 + ba.imagewidget(parent=self._root_widget, + position=(h - icon_size * 0.5 - 15, + v + self._button_height * scale - + icon_size * 0.24 + 1.5), + transition_delay=self._tdelay, + size=(icon_size, icon_size), + texture=ba.gettexture('egg3'), + tilt_scale=0.0) + + self._tdelay += self._t_delay_inc + + if self._in_game: + h, v, scale = positions[self._p_index] + self._p_index += 1 + # If we're in a replay, we have a 'Leave Replay' button. + if _ba.is_in_replay(): ba.buttonwidget(parent=self._root_widget, - position=(h - self._button_width / 2, v), - size=(self._button_width, self._button_height), + position=(h - self._button_width * 0.5 * scale, + v), scale=scale, - on_activate_call=call, - label=entry['label'], - autoselect=self._use_autoselect) - # Add a 'leave' button if the menu-owner has a player. - if ((self._input_player or self._connected_to_remote_player) - and not (self._is_demo or self._is_arcade)): - h, v, scale = positions[self._p_index] - self._p_index += 1 - btn = ba.buttonwidget(parent=self._root_widget, - position=(h - self._button_width / 2, v), - size=(self._button_width, - self._button_height), - scale=scale, - on_activate_call=self._leave, - label='', - autoselect=self._use_autoselect) - - if (player_name != '' and player_name[0] != '<' - and player_name[-1] != '>'): - txt = ba.Lstr(resource=self._r + '.justPlayerText', - subs=[('${NAME}', player_name)]) - else: - txt = ba.Lstr(value=player_name) - ba.textwidget(parent=self._root_widget, - position=(h, v + self._button_height * - (0.64 if player_name != '' else 0.5)), - size=(0, 0), - text=ba.Lstr(resource=self._r + '.leaveGameText'), - scale=(0.83 if player_name != '' else 1.0), - color=(0.75, 1.0, 0.7), - h_align='center', - v_align='center', - draw_controller=btn, - maxwidth=self._button_width * 0.9) - ba.textwidget(parent=self._root_widget, - position=(h, v + self._button_height * 0.27), - size=(0, 0), - text=txt, - color=(0.75, 1.0, 0.7), - h_align='center', - v_align='center', - draw_controller=btn, - scale=0.45, - maxwidth=self._button_width * 0.9) - return h, v, scale -def new_refresh(self) -> None: - # pylint: disable=too-many-branches - # pylint: disable=too-many-locals - # pylint: disable=too-many-statements - global server - print(server) - from bastd.ui.confirm import QuitWindow - from bastd.ui.store.button import StoreButton - import ba - # Clear everything that was there. - children = self._root_widget.get_children() - for child in children: - child.delete() - - self._tdelay = 0.0 - self._t_delay_inc = 0.0 - self._t_delay_play = 0.0 - self._button_width = 200.0 - self._button_height = 45.0 - - self._r = 'mainMenu' - - app = ba.app - self._have_quit_button = (app.ui.uiscale is ba.UIScale.LARGE - or (app.platform == 'windows' - and app.subplatform == 'oculus')) - - self._have_store_button = not self._in_game - - self._have_settings_button = ( - (not self._in_game or not app.toolbar_test) - and not (self._is_demo or self._is_arcade or self._is_iircade)) - - self._input_device = input_device = _ba.get_ui_input_device() - self._input_player = input_device.player if input_device else None - self._connected_to_remote_player = ( - input_device.is_connected_to_remote_player() - if input_device else False) - - - positions: List[Tuple[float, float, float]] = [] - self._p_index = 0 - - if self._in_game: - h, v, scale = self._refresh_in_game(positions) - print("refreshing in GAME",ip_add) - # btn = ba.buttonwidget(parent=self._root_widget, - # position=(80,270), - # size=(100, 90), - # scale=1.2, - # label=ip_add, - # autoselect=None, - # on_activate_call=printip) - ba.textwidget( - parent=self._root_widget, - draw_controller=None, - text="IP: "+ip_add+" PORT: "+str(p_port), - position=(150,270), - h_align='center', - v_align='center', - size=(20, 60), - scale=1) - self._server_button = ba.buttonwidget( - parent=self._root_widget, - position=(h * 3.2 +20 - self._button_width * scale, v), - size=(self._button_width, self._button_height), - scale=scale, - autoselect=self._use_autoselect, - label=ba.Lstr(resource=self._r + '.settingsText'), - transition_delay=self._tdelay, - on_activate_call=self._settings) - self._server_button2 = ba.buttonwidget( + size=(self._button_width, self._button_height), + autoselect=self._use_autoselect, + label=ba.Lstr(resource='replayEndText'), + on_activate_call=self._confirm_end_replay) + elif _ba.get_foreground_host_session() is not None: + ba.buttonwidget( parent=self._root_widget, - position=(h * 3.2 +20 - self._button_width * scale, v-50), - size=(self._button_width, self._button_height), + position=(h - self._button_width * 0.5 * scale, v), scale=scale, - autoselect=self._use_autoselect, - label=ba.Lstr(resource=self._r + '.settingsText'), - transition_delay=self._tdelay, - on_activate_call=self._settings) - self._server_button3 = ba.buttonwidget( - parent=self._root_widget, - position=(h * 3.2 +20 - self._button_width * scale, v-100), size=(self._button_width, self._button_height), - scale=scale, autoselect=self._use_autoselect, - label=ba.Lstr(resource=self._r + '.settingsText'), - transition_delay=self._tdelay, - on_activate_call=self._settings) - + label=ba.Lstr(resource=self._r + '.endGameText'), + on_activate_call=self._confirm_end_game) + # Assume we're in a client-session. else: - h, v, scale = self._refresh_not_in_game(positions) - - if self._have_settings_button: - h, v, scale = positions[self._p_index] - self._p_index += 1 - self._settings_button = ba.buttonwidget( + ba.buttonwidget( parent=self._root_widget, position=(h - self._button_width * 0.5 * scale, v), - size=(self._button_width, self._button_height), scale=scale, + size=(self._button_width, self._button_height), autoselect=self._use_autoselect, - label=ba.Lstr(resource=self._r + '.settingsText'), - transition_delay=self._tdelay, - on_activate_call=self._settings) + label=ba.Lstr(resource=self._r + '.leavePartyText'), + on_activate_call=self._confirm_leave_party) + + self._store_button: Optional[ba.Widget] + if self._have_store_button: + this_b_width = self._button_width + h, v, scale = positions[self._p_index] + self._p_index += 1 + + sbtn = self._store_button_instance = StoreButton( + parent=self._root_widget, + position=(h - this_b_width * 0.5 * scale, v), + size=(this_b_width, self._button_height), + scale=scale, + on_activate_call=ba.WeakCall(self._on_store_pressed), + sale_scale=1.3, + transition_delay=self._tdelay) + self._store_button = store_button = sbtn.get_button() + uiscale = ba.app.ui.uiscale + icon_size = (55 if uiscale is ba.UIScale.SMALL else + 55 if uiscale is ba.UIScale.MEDIUM else 70) + ba.imagewidget( + parent=self._root_widget, + position=(h - icon_size * 0.5, + v + self._button_height * scale - icon_size * 0.23), + transition_delay=self._tdelay, + size=(icon_size, icon_size), + texture=ba.gettexture(self._store_char_tex), + tilt_scale=0.0, + draw_controller=store_button) + + self._tdelay += self._t_delay_inc + else: + self._store_button = None + + self._quit_button: Optional[ba.Widget] + if not self._in_game and self._have_quit_button: + h, v, scale = positions[self._p_index] + self._p_index += 1 + self._quit_button = quit_button = ba.buttonwidget( + parent=self._root_widget, + autoselect=self._use_autoselect, + position=(h - self._button_width * 0.5 * scale, v), + size=(self._button_width, self._button_height), + scale=scale, + label=ba.Lstr(resource=self._r + + ('.quitText' if 'Mac' in + ba.app.user_agent_string else '.exitGameText')), + on_activate_call=self._quit, + transition_delay=self._tdelay) # Scattered eggs on easter. - if _ba.get_account_misc_read_val('easter', - False) and not self._in_game: - icon_size = 34 + if _ba.get_account_misc_read_val('easter', False): + icon_size = 30 ba.imagewidget(parent=self._root_widget, - position=(h - icon_size * 0.5 - 15, + position=(h - icon_size * 0.5 + 25, v + self._button_height * scale - icon_size * 0.24 + 1.5), transition_delay=self._tdelay, size=(icon_size, icon_size), - texture=ba.gettexture('egg3'), + texture=ba.gettexture('egg1'), tilt_scale=0.0) + ba.containerwidget(edit=self._root_widget, + cancel_button=quit_button) self._tdelay += self._t_delay_inc + else: + self._quit_button = None - if self._in_game: - h, v, scale = positions[self._p_index] - self._p_index += 1 - - # If we're in a replay, we have a 'Leave Replay' button. - if _ba.is_in_replay(): - ba.buttonwidget(parent=self._root_widget, - position=(h - self._button_width * 0.5 * scale, - v), - scale=scale, - size=(self._button_width, self._button_height), - autoselect=self._use_autoselect, - label=ba.Lstr(resource='replayEndText'), - on_activate_call=self._confirm_end_replay) - elif _ba.get_foreground_host_session() is not None: - ba.buttonwidget( - parent=self._root_widget, - position=(h - self._button_width * 0.5 * scale, v), - scale=scale, - size=(self._button_width, self._button_height), - autoselect=self._use_autoselect, - label=ba.Lstr(resource=self._r + '.endGameText'), - on_activate_call=self._confirm_end_game) - # Assume we're in a client-session. - else: - ba.buttonwidget( - parent=self._root_widget, - position=(h - self._button_width * 0.5 * scale, v), - scale=scale, - size=(self._button_width, self._button_height), - autoselect=self._use_autoselect, - label=ba.Lstr(resource=self._r + '.leavePartyText'), - on_activate_call=self._confirm_leave_party) - - self._store_button: Optional[ba.Widget] - if self._have_store_button: - this_b_width = self._button_width - h, v, scale = positions[self._p_index] - self._p_index += 1 - - sbtn = self._store_button_instance = StoreButton( - parent=self._root_widget, - position=(h - this_b_width * 0.5 * scale, v), - size=(this_b_width, self._button_height), - scale=scale, - on_activate_call=ba.WeakCall(self._on_store_pressed), - sale_scale=1.3, - transition_delay=self._tdelay) - self._store_button = store_button = sbtn.get_button() - uiscale = ba.app.ui.uiscale - icon_size = (55 if uiscale is ba.UIScale.SMALL else - 55 if uiscale is ba.UIScale.MEDIUM else 70) - ba.imagewidget( - parent=self._root_widget, - position=(h - icon_size * 0.5, - v + self._button_height * scale - icon_size * 0.23), - transition_delay=self._tdelay, - size=(icon_size, icon_size), - texture=ba.gettexture(self._store_char_tex), - tilt_scale=0.0, - draw_controller=store_button) - - self._tdelay += self._t_delay_inc - else: - self._store_button = None + # If we're not in-game, have no quit button, and this is android, + # we want back presses to quit our activity. + if (not self._in_game and not self._have_quit_button + and ba.app.platform == 'android'): - self._quit_button: Optional[ba.Widget] - if not self._in_game and self._have_quit_button: - h, v, scale = positions[self._p_index] - self._p_index += 1 - self._quit_button = quit_button = ba.buttonwidget( - parent=self._root_widget, - autoselect=self._use_autoselect, - position=(h - self._button_width * 0.5 * scale, v), - size=(self._button_width, self._button_height), - scale=scale, - label=ba.Lstr(resource=self._r + - ('.quitText' if 'Mac' in - ba.app.user_agent_string else '.exitGameText')), - on_activate_call=self._quit, - transition_delay=self._tdelay) - - # Scattered eggs on easter. - if _ba.get_account_misc_read_val('easter', False): - icon_size = 30 - ba.imagewidget(parent=self._root_widget, - position=(h - icon_size * 0.5 + 25, - v + self._button_height * scale - - icon_size * 0.24 + 1.5), - transition_delay=self._tdelay, - size=(icon_size, icon_size), - texture=ba.gettexture('egg1'), - tilt_scale=0.0) + def _do_quit() -> None: + QuitWindow(swish=True, back=True) ba.containerwidget(edit=self._root_widget, - cancel_button=quit_button) - self._tdelay += self._t_delay_inc + on_cancel_call=_do_quit) + + # Add speed-up/slow-down buttons for replays. + # (ideally this should be part of a fading-out playback bar like most + # media players but this works for now). + if _ba.is_in_replay(): + b_size = 50.0 + b_buffer = 10.0 + t_scale = 0.75 + uiscale = ba.app.ui.uiscale + if uiscale is ba.UIScale.SMALL: + b_size *= 0.6 + b_buffer *= 1.0 + v_offs = -40 + t_scale = 0.5 + elif uiscale is ba.UIScale.MEDIUM: + v_offs = -70 else: - self._quit_button = None - - # If we're not in-game, have no quit button, and this is android, - # we want back presses to quit our activity. - if (not self._in_game and not self._have_quit_button - and ba.app.platform == 'android'): - - def _do_quit() -> None: - QuitWindow(swish=True, back=True) + v_offs = -100 + self._replay_speed_text = ba.textwidget( + parent=self._root_widget, + text=ba.Lstr(resource='watchWindow.playbackSpeedText', + subs=[('${SPEED}', str(1.23))]), + position=(h, v + v_offs + 7 * t_scale), + h_align='center', + v_align='center', + size=(0, 0), + scale=t_scale) + + # Update to current value. + self._change_replay_speed(0) + + # Keep updating in a timer in case it gets changed elsewhere. + self._change_replay_speed_timer = ba.Timer( + 0.25, + ba.WeakCall(self._change_replay_speed, 0), + timetype=ba.TimeType.REAL, + repeat=True) + btn = ba.buttonwidget(parent=self._root_widget, + position=(h - b_size - b_buffer, + v - b_size - b_buffer + v_offs), + button_type='square', + size=(b_size, b_size), + label='', + autoselect=True, + on_activate_call=ba.Call( + self._change_replay_speed, -1)) + ba.textwidget( + parent=self._root_widget, + draw_controller=btn, + text='-', + position=(h - b_size * 0.5 - b_buffer, + v - b_size * 0.5 - b_buffer + 5 * t_scale + v_offs), + h_align='center', + v_align='center', + size=(0, 0), + scale=3.0 * t_scale) + btn = ba.buttonwidget( + parent=self._root_widget, + position=(h + b_buffer, v - b_size - b_buffer + v_offs), + button_type='square', + size=(b_size, b_size), + label='', + autoselect=True, + on_activate_call=ba.Call(self._change_replay_speed, 1)) + ba.textwidget( + parent=self._root_widget, + draw_controller=btn, + text='+', + position=(h + b_size * 0.5 + b_buffer, + v - b_size * 0.5 - b_buffer + 5 * t_scale + v_offs), + h_align='center', + v_align='center', + size=(0, 0), + scale=3.0 * t_scale) - ba.containerwidget(edit=self._root_widget, - on_cancel_call=_do_quit) +# ba_meta export plugin - # Add speed-up/slow-down buttons for replays. - # (ideally this should be part of a fading-out playback bar like most - # media players but this works for now). - if _ba.is_in_replay(): - b_size = 50.0 - b_buffer = 10.0 - t_scale = 0.75 - uiscale = ba.app.ui.uiscale - if uiscale is ba.UIScale.SMALL: - b_size *= 0.6 - b_buffer *= 1.0 - v_offs = -40 - t_scale = 0.5 - elif uiscale is ba.UIScale.MEDIUM: - v_offs = -70 - else: - v_offs = -100 - self._replay_speed_text = ba.textwidget( - parent=self._root_widget, - text=ba.Lstr(resource='watchWindow.playbackSpeedText', - subs=[('${SPEED}', str(1.23))]), - position=(h, v + v_offs + 7 * t_scale), - h_align='center', - v_align='center', - size=(0, 0), - scale=t_scale) - - # Update to current value. - self._change_replay_speed(0) - - # Keep updating in a timer in case it gets changed elsewhere. - self._change_replay_speed_timer = ba.Timer( - 0.25, - ba.WeakCall(self._change_replay_speed, 0), - timetype=ba.TimeType.REAL, - repeat=True) - btn = ba.buttonwidget(parent=self._root_widget, - position=(h - b_size - b_buffer, - v - b_size - b_buffer + v_offs), - button_type='square', - size=(b_size, b_size), - label='', - autoselect=True, - on_activate_call=ba.Call( - self._change_replay_speed, -1)) - ba.textwidget( - parent=self._root_widget, - draw_controller=btn, - text='-', - position=(h - b_size * 0.5 - b_buffer, - v - b_size * 0.5 - b_buffer + 5 * t_scale + v_offs), - h_align='center', - v_align='center', - size=(0, 0), - scale=3.0 * t_scale) - btn = ba.buttonwidget( - parent=self._root_widget, - position=(h + b_buffer, v - b_size - b_buffer + v_offs), - button_type='square', - size=(b_size, b_size), - label='', - autoselect=True, - on_activate_call=ba.Call(self._change_replay_speed, 1)) - ba.textwidget( - parent=self._root_widget, - draw_controller=btn, - text='+', - position=(h + b_size * 0.5 + b_buffer, - v - b_size * 0.5 - b_buffer + 5 * t_scale + v_offs), - h_align='center', - v_align='center', - size=(0, 0), - scale=3.0 * t_scale) -# ba_meta export plugin class bySmoothy(ba.Plugin): def __init__(self): - if _ba.env().get("build_number",0) >= 20577: - bastd_ui_mainmenu.MainMenuWindow._refresh_in_game= new_refresh_in_game - _ba.connect_to_party=newconnect_to_party - _ba.disconnect_from_host=newdisconnect_from_host - else:print("Server Switch only works on bs 1.7 and above") + if _ba.env().get("build_number", 0) >= 20577: + bastd_ui_mainmenu.MainMenuWindow._refresh_in_game = new_refresh_in_game + _ba.connect_to_party = newconnect_to_party + _ba.disconnect_from_host = newdisconnect_from_host + else: + print("Server Switch only works on bs 1.7 and above") From 585e4698a22bb783938fdabba532d7c977a32394 Mon Sep 17 00:00:00 2001 From: Ayush Saini <36878972+imayushsaini@users.noreply.github.com> Date: Sat, 17 Sep 2022 22:17:55 +0530 Subject: [PATCH 0104/1464] added entry for new plugin --- plugins/utilities.json | 29 +++++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) diff --git a/plugins/utilities.json b/plugins/utilities.json index 6785927c..346a8e78 100644 --- a/plugins/utilities.json +++ b/plugins/utilities.json @@ -115,6 +115,35 @@ } } }, + "advanced_party_window": { + "description": "Advanced your party window with lots of feature", + "external_url": "https://www.youtube.com/watch?v=QrES1jQGXF0", + "authors": [ + { + "name": "Mr.Smoothy", + "email": "smoothyt@bombsquad.ga", + "discord": "mr.smoothy#5824" + } + ], + "versions": { + "1.0.0": null + } + } + , + "server_switch": { + "description": "Let you switch between recents servers", + "external_url": "https://www.youtube.com/watch?v=QrES1jQGXF0", + "authors": [ + { + "name": "Mr.Smoothy", + "email": "smoothyt@bombsquad.ga", + "discord": "mr.smoothy#5824" + } + ], + "versions": { + "1.0.0": null + } + }, "icons_keyboard": { "description": "Enable 'Always Use Internal Keyboard' in Settings>Advanced. Double tap space-bar to change keyboards", "external_url": "", From 2cff7021900c4e7cfd16f2e015bc88a9bf4acee3 Mon Sep 17 00:00:00 2001 From: imayushsaini Date: Sat, 17 Sep 2022 16:49:21 +0000 Subject: [PATCH 0105/1464] [ci] apply-version-metadata --- plugins/utilities.json | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) diff --git a/plugins/utilities.json b/plugins/utilities.json index 346a8e78..3548c74c 100644 --- a/plugins/utilities.json +++ b/plugins/utilities.json @@ -126,10 +126,14 @@ } ], "versions": { - "1.0.0": null + "1.0.0": { + "api_version": 7, + "commit_sha": "e994af5", + "released_on": "17-09-2022", + "md5sum": "efc4f07eb242d28fe08a7a707376bfc5" + } } - } - , + }, "server_switch": { "description": "Let you switch between recents servers", "external_url": "https://www.youtube.com/watch?v=QrES1jQGXF0", @@ -141,7 +145,12 @@ } ], "versions": { - "1.0.0": null + "1.0.0": { + "api_version": 7, + "commit_sha": "e994af5", + "released_on": "17-09-2022", + "md5sum": "5b90431822c8f6a8227266ab8d64686b" + } } }, "icons_keyboard": { From c94179aa303dc48addd19ad919339ce515ae27f3 Mon Sep 17 00:00:00 2001 From: Freaku17 <92618708+Freaku17@users.noreply.github.com> Date: Sat, 17 Sep 2022 22:43:48 +0530 Subject: [PATCH 0106/1464] Floater: Fixing no chat window in solo --- plugins/utilities/floater.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/plugins/utilities/floater.py b/plugins/utilities/floater.py index 91061176..b902b952 100644 --- a/plugins/utilities/floater.py +++ b/plugins/utilities/floater.py @@ -268,9 +268,9 @@ def new_chat_message(msg: Union[str, ba.Lstr], clients: Sequence[int] = None, se _ba.chatmessage = new_chat_message +if not _ba.is_party_icon_visible(): + _ba.set_party_icon_always_visible(True) # ba_meta export plugin - - class byFreaku(ba.Plugin): def __init__(self): pass From 9daa54a780ffb252dbd4df499bb34691c469bbda Mon Sep 17 00:00:00 2001 From: Freaku17 <92618708+Freaku17@users.noreply.github.com> Date: Sat, 17 Sep 2022 22:45:33 +0530 Subject: [PATCH 0107/1464] Update Floater --- plugins/utilities.json | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/plugins/utilities.json b/plugins/utilities.json index 3548c74c..5bf42a2e 100644 --- a/plugins/utilities.json +++ b/plugins/utilities.json @@ -93,7 +93,8 @@ "commit_sha": "858030b", "released_on": "01-09-2022", "md5sum": "c024a0774f2e960dad7f633efdc3feb5" - } + }, + "1.1.0": null } }, "easy_connect": { @@ -173,4 +174,4 @@ } } } -} \ No newline at end of file +} From 3f36f755918d381a66315355f7011ed48a907ee9 Mon Sep 17 00:00:00 2001 From: Freaku17 Date: Sat, 17 Sep 2022 17:16:46 +0000 Subject: [PATCH 0108/1464] [ci] auto-format --- plugins/utilities/floater.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/plugins/utilities/floater.py b/plugins/utilities/floater.py index b902b952..d57e5931 100644 --- a/plugins/utilities/floater.py +++ b/plugins/utilities/floater.py @@ -272,5 +272,7 @@ def new_chat_message(msg: Union[str, ba.Lstr], clients: Sequence[int] = None, se _ba.set_party_icon_always_visible(True) # ba_meta export plugin + + class byFreaku(ba.Plugin): def __init__(self): pass From a199b05124064e465655fff6fb0145ae303ce612 Mon Sep 17 00:00:00 2001 From: Freaku17 Date: Sat, 17 Sep 2022 17:16:47 +0000 Subject: [PATCH 0109/1464] [ci] apply-version-metadata --- plugins/utilities.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/plugins/utilities.json b/plugins/utilities.json index 5bf42a2e..3c1c2e12 100644 --- a/plugins/utilities.json +++ b/plugins/utilities.json @@ -94,7 +94,7 @@ "released_on": "01-09-2022", "md5sum": "c024a0774f2e960dad7f633efdc3feb5" }, - "1.1.0": null + "1.1.0": null } }, "easy_connect": { @@ -174,4 +174,4 @@ } } } -} +} \ No newline at end of file From 383f774111d438a6993704e57a90b6ed963193c2 Mon Sep 17 00:00:00 2001 From: Freaku17 <92618708+Freaku17@users.noreply.github.com> Date: Sat, 17 Sep 2022 22:52:55 +0530 Subject: [PATCH 0110/1464] Fixing build err --- plugins/utilities.json | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/plugins/utilities.json b/plugins/utilities.json index 3c1c2e12..c8c1e9ed 100644 --- a/plugins/utilities.json +++ b/plugins/utilities.json @@ -88,13 +88,13 @@ } ], "versions": { + "1.1.0": null, "1.0.0": { "api_version": 7, "commit_sha": "858030b", "released_on": "01-09-2022", "md5sum": "c024a0774f2e960dad7f633efdc3feb5" - }, - "1.1.0": null + } } }, "easy_connect": { @@ -174,4 +174,4 @@ } } } -} \ No newline at end of file +} From 5aefe97f069bb6ba2dbf18c65dbf9222b87e06b7 Mon Sep 17 00:00:00 2001 From: Freaku17 Date: Sat, 17 Sep 2022 17:23:14 +0000 Subject: [PATCH 0111/1464] [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 c8c1e9ed..d4fc35d8 100644 --- a/plugins/utilities.json +++ b/plugins/utilities.json @@ -88,7 +88,12 @@ } ], "versions": { - "1.1.0": null, + "1.1.0": { + "api_version": 7, + "commit_sha": "383f774", + "released_on": "17-09-2022", + "md5sum": "d20cdf514aeaf8f3db08eb8c5c7867e6" + }, "1.0.0": { "api_version": 7, "commit_sha": "858030b", @@ -174,4 +179,4 @@ } } } -} +} \ No newline at end of file From a6d1a435c9f87a9dbbb4c86a3df57a247b0a88ff Mon Sep 17 00:00:00 2001 From: Rikko Date: Sun, 18 Sep 2022 02:39:02 +0530 Subject: [PATCH 0112/1464] Update colorscheme to 1.2.2 --- plugins/utilities.json | 3 ++- plugins/utilities/colorscheme.py | 30 +++++++++++++++++++++++++++--- 2 files changed, 29 insertions(+), 4 deletions(-) diff --git a/plugins/utilities.json b/plugins/utilities.json index d4fc35d8..d2a40a01 100644 --- a/plugins/utilities.json +++ b/plugins/utilities.json @@ -19,6 +19,7 @@ } ], "versions": { + "1.2.2": null, "1.2.1": { "api_version": 7, "commit_sha": "109e61c5a", @@ -179,4 +180,4 @@ } } } -} \ No newline at end of file +} diff --git a/plugins/utilities/colorscheme.py b/plugins/utilities/colorscheme.py index 416b0733..6e427173 100644 --- a/plugins/utilities/colorscheme.py +++ b/plugins/utilities/colorscheme.py @@ -15,14 +15,32 @@ original_buttonwidget = ba.buttonwidget original_containerwidget = ba.containerwidget original_checkboxwidget = ba.checkboxwidget - -original_add_transaction = _ba.add_transaction # We set this later so we store the overridden method in case the # player is using pro-unlocker plugins that override the # `ba.app.accounts.have_pro` method. original_have_pro = None +def is_game_version_lower_than(version): + """ + Returns a boolean value indicating whether the current game + version is lower than the passed version. Useful for addressing + any breaking changes within game versions. + """ + game_version = tuple(map(int, ba.app.version.split("."))) + version = tuple(map(int, version.split("."))) + return game_version < version + + +# Adds backward compatibility for a breaking change released in +# game version 1.7.7, which moves `_ba.add_transaction` to +# `ba.internal.add_transaction`. +if is_game_version_lower_than("1.7.7"): + original_add_transaction = _ba.add_transaction +else: + original_add_transaction = ba.internal.add_transaction + + class ColorScheme: """ Apply a colorscheme to the game. Can also be invoked directly @@ -369,7 +387,13 @@ def add(self, transaction_code, transaction_fn): self.custom_transactions[transaction_code] = transaction_fn def enable(self): - _ba.add_transaction = self._handle + # Adds backward compatibility for a breaking change released in + # game version 1.7.7, which moves `_ba.add_transaction` to + # `ba.internal.add_transaction`. + if is_game_version_lower_than("1.7.7"): + _ba.add_transaction = self._handle + else: + ba.internal.add_transaction = self._handle def launch_colorscheme_selection_window(): From 6596a8167c027fe30f0c243ae50ff9aa075c0bdc Mon Sep 17 00:00:00 2001 From: rikkolovescats Date: Sat, 17 Sep 2022 21:10:28 +0000 Subject: [PATCH 0113/1464] [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 d2a40a01..422be0f3 100644 --- a/plugins/utilities.json +++ b/plugins/utilities.json @@ -19,7 +19,12 @@ } ], "versions": { - "1.2.2": null, + "1.2.2": { + "api_version": 7, + "commit_sha": "a6d1a43", + "released_on": "17-09-2022", + "md5sum": "6c06e45ad4e37e2208bc3e8e128f1b87" + }, "1.2.1": { "api_version": 7, "commit_sha": "109e61c5a", @@ -180,4 +185,4 @@ } } } -} +} \ No newline at end of file From 41e239c4bd0fab985738ce5824a62046edf87e24 Mon Sep 17 00:00:00 2001 From: Rikko Date: Sun, 18 Sep 2022 17:07:29 +0530 Subject: [PATCH 0114/1464] Add pro-unlocker --- plugins/utilities.json | 16 +++++++++++++- plugins/utilities/pro_unlocker.py | 36 +++++++++++++++++++++++++++++++ 2 files changed, 51 insertions(+), 1 deletion(-) create mode 100644 plugins/utilities/pro_unlocker.py diff --git a/plugins/utilities.json b/plugins/utilities.json index 422be0f3..f7b76d95 100644 --- a/plugins/utilities.json +++ b/plugins/utilities.json @@ -183,6 +183,20 @@ "md5sum": "94f67a98a9faed0ece63674c84d40061" } } + }, + "pro_unlocker": { + "description": "Unlocks some pro-only features - custom colors, playlist maker, etc.", + "external_url": "", + "authors": [ + { + "name": "Anonymous", + "email": "", + "discord": "" + } + ], + "versions": { + "1.0.0": null + } } } -} \ No newline at end of file +} diff --git a/plugins/utilities/pro_unlocker.py b/plugins/utilities/pro_unlocker.py new file mode 100644 index 00000000..5603072d --- /dev/null +++ b/plugins/utilities/pro_unlocker.py @@ -0,0 +1,36 @@ +# ba_meta require api 7 +import _ba +import ba + + +def is_game_version_lower_than(version): + """ + Returns a boolean value indicating whether the current game + version is lower than the passed version. Useful for addressing + any breaking changes within game versions. + """ + game_version = tuple(map(int, ba.app.version.split("."))) + version = tuple(map(int, version.split("."))) + return game_version < version + + +if is_game_version_lower_than("1.7.7"): + original_get_purchased = _ba.get_purchased +else: + original_get_purchased = ba.internal.get_purchased + + +def get_purchased(item): + if item.startswith('characters.') or item.startswith('icons.'): + return original_get_purchased(item) + return True + + +# ba_meta export plugin +class Unlock(ba.Plugin): + def on_app_running(self): + ba.app.accounts_v1.have_pro = lambda: True + if is_game_version_lower_than("1.7.7"): + _ba.get_purchased = get_purchased + else: + ba.internal.get_purchased = get_purchased From 2cc3115e42efa364c59b58ec7fddc8e776d24e90 Mon Sep 17 00:00:00 2001 From: rikkolovescats Date: Sun, 18 Sep 2022 11:37:59 +0000 Subject: [PATCH 0115/1464] [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 f7b76d95..7881a58f 100644 --- a/plugins/utilities.json +++ b/plugins/utilities.json @@ -195,8 +195,13 @@ } ], "versions": { - "1.0.0": null + "1.0.0": { + "api_version": 7, + "commit_sha": "41e239c", + "released_on": "18-09-2022", + "md5sum": "bbaee5f133b41d2eb53e3b726403a75e" + } } } } -} +} \ No newline at end of file From fa6fba9643bff8eb139539af7a33645a02f70a87 Mon Sep 17 00:00:00 2001 From: Rikko Date: Sun, 18 Sep 2022 17:36:08 +0530 Subject: [PATCH 0116/1464] Update description for pro-unlocker --- plugins/utilities.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/plugins/utilities.json b/plugins/utilities.json index 7881a58f..47800c14 100644 --- a/plugins/utilities.json +++ b/plugins/utilities.json @@ -185,7 +185,7 @@ } }, "pro_unlocker": { - "description": "Unlocks some pro-only features - custom colors, playlist maker, etc.", + "description": "Unlocks some pro-only features - custom colors, playlist maker, etc.\n(Please support the game developer if you can!)", "external_url": "", "authors": [ { @@ -204,4 +204,4 @@ } } } -} \ No newline at end of file +} From 503a45108f4a0a02fec193962d73bcb8bc48b212 Mon Sep 17 00:00:00 2001 From: Rikko Date: Sun, 18 Sep 2022 17:59:50 +0530 Subject: [PATCH 0117/1464] Correct CHANGELOG entries --- CHANGELOG.md | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 200ad879..779927ad 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,12 @@ ## Plugin Manager (dd-mm-yyyy) -### 0.5.0 (08-09-2022) + +### 0.1.6 (15-09-2022) + +- Distinguish the settings button with a cyan color (previously was green) in plugin manager window. +- Clean up some internal code. + + +### 0.1.5 (08-09-2022) - Plugin files that export classes besides plugin or game, now work. From 5f906e730e1db033fe67c8482d652c4540d0688b Mon Sep 17 00:00:00 2001 From: rikkolovescats Date: Sun, 18 Sep 2022 12:30:42 +0000 Subject: [PATCH 0118/1464] [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 47800c14..d9b415fd 100644 --- a/plugins/utilities.json +++ b/plugins/utilities.json @@ -204,4 +204,4 @@ } } } -} +} \ No newline at end of file From 51fda2e506d991fe1ff956c180c51a989c3fcf83 Mon Sep 17 00:00:00 2001 From: Loup <90267658+Loup-Garou911XD@users.noreply.github.com> Date: Wed, 21 Sep 2022 18:07:14 +0530 Subject: [PATCH 0119/1464] Added mood light to utilities.json --- plugins/utilities.json | 22 +++++++++++++++++++++- 1 file changed, 21 insertions(+), 1 deletion(-) diff --git a/plugins/utilities.json b/plugins/utilities.json index d9b415fd..c2b99bee 100644 --- a/plugins/utilities.json +++ b/plugins/utilities.json @@ -3,6 +3,26 @@ "description": "Utilities", "plugins_base_url": "http://github.com/bombsquad-community/plugin-manager/{content_type}/{tag}/plugins/utilities", "plugins": { + "mood_light": { + "description": "mood lighting in co-op games" + "external_url": "", + "authors": [ + { + "name": "Anonymous", + "email": "", + "discord": "" + } + ], + "versions": { + "1.0.0": { + "api_version": 7, + "commit_sha": "41e239c", + "released_on": "21-09-2022", + "md5sum": "bbaee5f133b41d2edjsjsk3b726403a75e" + } + } + }, + "colorscheme": { "description": "Create custom UI colorschemes!", "external_url": "http://www.youtube.com/watch?v=qatwWrBAvjc", @@ -204,4 +224,4 @@ } } } -} \ No newline at end of file +} From ed985bce794c8fa13ea2adaf015756d64c898488 Mon Sep 17 00:00:00 2001 From: Loup <90267658+Loup-Garou911XD@users.noreply.github.com> Date: Wed, 21 Sep 2022 18:09:19 +0530 Subject: [PATCH 0120/1464] Uploaded mood_light.py --- plugins/utilities/mood light.py | 213 ++++++++++++++++++++++++++++++++ 1 file changed, 213 insertions(+) create mode 100644 plugins/utilities/mood light.py diff --git a/plugins/utilities/mood light.py b/plugins/utilities/mood light.py new file mode 100644 index 00000000..bebcbdf2 --- /dev/null +++ b/plugins/utilities/mood light.py @@ -0,0 +1,213 @@ +#mood light plugin by ʟօʊքɢǟʀօʊ + +# ba_meta require api 7 +from __future__ import annotations +from typing import TYPE_CHECKING, cast + +import ba +import _ba +import random +from ba._map import Map +from bastd import mainmenu +from bastd.gameutils import SharedObjects +from time import sleep +if TYPE_CHECKING: + from typing import Any, Sequence, Callable, List, Dict, Tuple, Optional, Union + +# ba_meta export plugin + +class ColorSchemeWindow(ba.Window): + def __init__(self, default_colors=((0.41, 0.39, 0.5), (0.5, 0.7, 0.25))): + self._default_colors = default_colors + self._color, self._highlight = ba.app.config.get("ColorScheme", (None, None)) + + self._last_color = self._color + self._last_highlight = self._highlight + + # Let's set the game's default colorscheme before opening the Window. + # Otherwise the colors in the Window are tinted as per the already + # applied custom colorscheme thereby making it impossible to visually + # differentiate between different colors. + # A hack to let players select any RGB color value through the UI, + # otherwise this is limited only to pro accounts. + ba.app.accounts_v1.have_pro = lambda: True + + self.draw_ui() + + def draw_ui(self): + # Most of the stuff here for drawing the UI is referred from the + # game's bastd/ui/profile/edit.py, and so there could be some + # cruft here due to my oversight. + uiscale = ba.app.ui.uiscale + self._width = width = 480.0 if uiscale is ba.UIScale.SMALL else 380.0 + self._x_inset = x_inset = 40.0 if uiscale is ba.UIScale.SMALL else 0.0 + self._height = height = ( + 275.0 + if uiscale is ba.UIScale.SMALL + else 288.0 + if uiscale is ba.UIScale.MEDIUM + else 300.0 + ) + spacing = 40 + self._base_scale = ( + 2.05 + if uiscale is ba.UIScale.SMALL + else 1.5 + if uiscale is ba.UIScale.MEDIUM + else 1.0 + ) + top_extra = 15 + + super().__init__( + root_widget=ba.containerwidget( + size=(width, height + top_extra), + on_outside_click_call=self.cancel_on_outside_click, + transition="in_right", + scale=self._base_scale, + stack_offset=(0, 15) if uiscale is ba.UIScale.SMALL else (0, 0), + ) + ) + + cancel_button = ba.buttonwidget( + parent=self._root_widget, + position=(52 + x_inset, height - 60), + size=(155, 60), + scale=0.8, + autoselect=True, + label=ba.Lstr(resource="cancelText"), + on_activate_call=self._cancel, + ) + ba.containerwidget(edit=self._root_widget, cancel_button=cancel_button) + + save_button = ba.buttonwidget( + parent=self._root_widget, + position=(width - (177 + x_inset), height - 110), + size=(155, 60), + autoselect=True, + scale=0.8, + label=ba.Lstr(resource="saveText"), + ) + ba.widget(edit=save_button, left_widget=cancel_button) + ba.buttonwidget(edit=save_button, on_activate_call=self.save) + ba.widget(edit=cancel_button, right_widget=save_button) + ba.containerwidget(edit=self._root_widget, start_button=save_button) + + reset_button = ba.buttonwidget( + parent=self._root_widget, + position=(width - (177 + x_inset), height - 60), + size=(155, 60), + color=(0.2, 0.5, 0.6), + autoselect=True, + scale=0.8, + label=ba.Lstr(resource="settingsWindowAdvanced.resetText"), + ) + ba.widget(edit=reset_button, left_widget=reset_button) + ba.buttonwidget(edit=reset_button, on_activate_call=self.reset) + ba.widget(edit=cancel_button, right_widget=reset_button) + ba.containerwidget(edit=self._root_widget, start_button=reset_button) + + v = height - 65.0 + v -= spacing * 3.0 + b_size = 80 + b_offs = 75 + + + ba.textwidget( + parent=self._root_widget, + h_align="center", + v_align="center", + position=(self._width * 0.5 - b_offs, v - 65), + size=(0, 0), + draw_controller=self._color_button, + text=ba.Lstr(resource="editProfileWindow.colorText"), + scale=0.7, + color=ba.app.ui.title_color, + maxwidth=120, + ) + + self._highlight_button = ba.buttonwidget( + parent=self._root_widget, + autoselect=True, + position=(self._width * 0.5 + b_offs - b_size * 0.5, v - 50), + size=(b_size, b_size), + color=self._last_highlight or self._default_colors[1], + label="", + button_type="square", + ) + + ba.buttonwidget( + edit=self._highlight_button, + on_activate_call=ba.Call(self._pick_color, "highlight"), + ) + ba.textwidget( + parent=self._root_widget, + h_align="center", + v_align="center", + position=(self._width * 0.5 + b_offs, v - 65), + size=(0, 0), + draw_controller=self._highlight_button, + text=ba.Lstr(resource="editProfileWindow.highlightText"), + scale=0.7, + color=ba.app.ui.title_color, + maxwidth=120, + ) + + def cancel_on_outside_click(self): + ba.playsound(ba.getsound("swish")) + self._cancel() + + def _cancel(self): + if self._last_color and self._last_highlight: + colorscheme = ColorScheme(self._last_color, self._last_highlight) + colorscheme.apply() + # Good idea to revert this back now so we do not break anything else. + ba.app.accounts_v1.have_pro = original_have_pro + ba.containerwidget(edit=self._root_widget, transition="out_right") + + def reset(self, transition_out=True): + if transition_out: + ba.playsound(ba.getsound("gunCocking")) + ba.app.config["ColorScheme"] = (None, None) + # Good idea to revert this back now so we do not break anything else. + ba.app.accounts_v1.have_pro = original_have_pro + ba.app.config.commit() + ba.containerwidget(edit=self._root_widget, transition="out_right") + + def save(self, transition_out=True): + if transition_out: + ba.playsound(ba.getsound("gunCocking")) + colorscheme = ColorScheme( + self._color or self._default_colors[0], + self._highlight or self._default_colors[1], + ) + ba.containerwidget(edit=self._root_widget, transition="out_right") + + + + + + + +class UwUuser(ba.Plugin): + Map._old_init = Map.__init__ + def on_plugin_manager_prompt(self): + ColorSchemeWindow() + def _new_init(self, vr_overlay_offset: Optional[Sequence[float]] = None) -> None: + self._old_init(vr_overlay_offset) + in_game = not isinstance(_ba.get_foreground_host_session(), mainmenu.MainMenuSession) + if not in_game: return + + gnode = _ba.getactivity().globalsnode + + lowerlimit=5 + upperlimit=20 + + def changetint(): + ba.animate_array(gnode, 'tint', 3, { + 0.0: gnode.tint, + 1.0: (random.randrange(lowerlimit,upperlimit)/10, random.randrange(lowerlimit,upperlimit)/10, random.randrange(lowerlimit, upperlimit)/10) + }) + _ba.timer(0.3, changetint, repeat= True) + + + Map.__init__ = _new_init From cd59c1ad034e0cc0d56f6b62979d07fdfb9bfa7d Mon Sep 17 00:00:00 2001 From: Loup <90267658+Loup-Garou911XD@users.noreply.github.com> Date: Wed, 21 Sep 2022 18:10:22 +0530 Subject: [PATCH 0121/1464] Rename mood light.py to mood_light.py --- plugins/utilities/{mood light.py => mood_light.py} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename plugins/utilities/{mood light.py => mood_light.py} (100%) diff --git a/plugins/utilities/mood light.py b/plugins/utilities/mood_light.py similarity index 100% rename from plugins/utilities/mood light.py rename to plugins/utilities/mood_light.py From da219635790908e16bbbc0468acd0bcf28eecb21 Mon Sep 17 00:00:00 2001 From: Loup <90267658+Loup-Garou911XD@users.noreply.github.com> Date: Thu, 22 Sep 2022 04:12:19 +0530 Subject: [PATCH 0122/1464] Major progress on settings ui --- plugins/utilities/mood_light.py | 311 ++++++++++++++------------------ 1 file changed, 140 insertions(+), 171 deletions(-) diff --git a/plugins/utilities/mood_light.py b/plugins/utilities/mood_light.py index bebcbdf2..c7036a1c 100644 --- a/plugins/utilities/mood_light.py +++ b/plugins/utilities/mood_light.py @@ -14,184 +14,154 @@ if TYPE_CHECKING: from typing import Any, Sequence, Callable, List, Dict, Tuple, Optional, Union -# ba_meta export plugin - -class ColorSchemeWindow(ba.Window): - def __init__(self, default_colors=((0.41, 0.39, 0.5), (0.5, 0.7, 0.25))): - self._default_colors = default_colors - self._color, self._highlight = ba.app.config.get("ColorScheme", (None, None)) - - self._last_color = self._color - self._last_highlight = self._highlight - - # Let's set the game's default colorscheme before opening the Window. - # Otherwise the colors in the Window are tinted as per the already - # applied custom colorscheme thereby making it impossible to visually - # differentiate between different colors. - # A hack to let players select any RGB color value through the UI, - # otherwise this is limited only to pro accounts. - ba.app.accounts_v1.have_pro = lambda: True - - self.draw_ui() - - def draw_ui(self): - # Most of the stuff here for drawing the UI is referred from the - # game's bastd/ui/profile/edit.py, and so there could be some - # cruft here due to my oversight. - uiscale = ba.app.ui.uiscale - self._width = width = 480.0 if uiscale is ba.UIScale.SMALL else 380.0 - self._x_inset = x_inset = 40.0 if uiscale is ba.UIScale.SMALL else 0.0 - self._height = height = ( - 275.0 - if uiscale is ba.UIScale.SMALL - else 288.0 - if uiscale is ba.UIScale.MEDIUM - else 300.0 - ) - spacing = 40 - self._base_scale = ( - 2.05 - if uiscale is ba.UIScale.SMALL - else 1.5 - if uiscale is ba.UIScale.MEDIUM - else 1.0 - ) - top_extra = 15 - - super().__init__( - root_widget=ba.containerwidget( - size=(width, height + top_extra), - on_outside_click_call=self.cancel_on_outside_click, - transition="in_right", - scale=self._base_scale, - stack_offset=(0, 15) if uiscale is ba.UIScale.SMALL else (0, 0), - ) - ) - - cancel_button = ba.buttonwidget( - parent=self._root_widget, - position=(52 + x_inset, height - 60), - size=(155, 60), - scale=0.8, - autoselect=True, - label=ba.Lstr(resource="cancelText"), - on_activate_call=self._cancel, - ) - ba.containerwidget(edit=self._root_widget, cancel_button=cancel_button) - - save_button = ba.buttonwidget( - parent=self._root_widget, - position=(width - (177 + x_inset), height - 110), - size=(155, 60), - autoselect=True, - scale=0.8, - label=ba.Lstr(resource="saveText"), - ) - ba.widget(edit=save_button, left_widget=cancel_button) - ba.buttonwidget(edit=save_button, on_activate_call=self.save) - ba.widget(edit=cancel_button, right_widget=save_button) - ba.containerwidget(edit=self._root_widget, start_button=save_button) - - reset_button = ba.buttonwidget( - parent=self._root_widget, - position=(width - (177 + x_inset), height - 60), - size=(155, 60), - color=(0.2, 0.5, 0.6), - autoselect=True, - scale=0.8, - label=ba.Lstr(resource="settingsWindowAdvanced.resetText"), - ) - ba.widget(edit=reset_button, left_widget=reset_button) - ba.buttonwidget(edit=reset_button, on_activate_call=self.reset) - ba.widget(edit=cancel_button, right_widget=reset_button) - ba.containerwidget(edit=self._root_widget, start_button=reset_button) - - v = height - 65.0 - v -= spacing * 3.0 - b_size = 80 - b_offs = 75 - - - ba.textwidget( - parent=self._root_widget, - h_align="center", - v_align="center", - position=(self._width * 0.5 - b_offs, v - 65), - size=(0, 0), - draw_controller=self._color_button, - text=ba.Lstr(resource="editProfileWindow.colorText"), - scale=0.7, - color=ba.app.ui.title_color, - maxwidth=120, - ) - - self._highlight_button = ba.buttonwidget( - parent=self._root_widget, - autoselect=True, - position=(self._width * 0.5 + b_offs - b_size * 0.5, v - 50), - size=(b_size, b_size), - color=self._last_highlight or self._default_colors[1], - label="", - button_type="square", - ) - - ba.buttonwidget( - edit=self._highlight_button, - on_activate_call=ba.Call(self._pick_color, "highlight"), - ) - ba.textwidget( - parent=self._root_widget, - h_align="center", - v_align="center", - position=(self._width * 0.5 + b_offs, v - 65), - size=(0, 0), - draw_controller=self._highlight_button, - text=ba.Lstr(resource="editProfileWindow.highlightText"), - scale=0.7, - color=ba.app.ui.title_color, - maxwidth=120, - ) - - def cancel_on_outside_click(self): - ba.playsound(ba.getsound("swish")) - self._cancel() +class SettingWindow(ba.Window): + def __init__(self): + global Ldefault,Udefault + Ldefault=5 + Udefault=20 + + def increase_limit(self): + global Ldefault,Udefault + try: + if Udefault>=29 and self.selected=="upper": + ba.textwidget(edit=self.warn_text,text="Careful!You risk get blind beyond this point") + elif self.selected=="lower" and Ldefault>=-20: + ba.textwidget(edit=self.warn_text,text="") + + if self.selected=="lower": + Ldefault += 1 + ba.textwidget(edit=self.lower_text,text=str(Ldefault)) + elif self.selected=="upper": + Udefault+=1 + ba.textwidget(edit=self.upper_text,text=str(Udefault)) + except AttributeError: + ba.textwidget(edit=self.warn_text,text="Click on number to select it") + + def decrease_limit(self): + global Ldefault,Udefault + try: + if Ldefault<=-19 and self.selected == "lower": + ba.textwidget(edit=self.warn_text,text="DON'T BE AFRAID OF DARK,IT'S A PLACE WHERE YOU CAN HIDE") + elif (self.selected == "upper" and Udefault >=30) or (self.selected== "lower" and Ldefault>=-20): + ba.textwidget(edit=self.warn_text,text="") + + + if self.selected=="lower": + Ldefault -= 1 + ba.textwidget(edit=self.lower_text,text=str(Ldefault)) + elif self.selected=="upper": + Udefault -=1 + ba.textwidget(edit=self.upper_text,text=str(Udefault)) + except AttributeError: + ba.textwidget(edit=self.warn_text,text="Click on number to select it") + + def on_text_click(self,selected): + self.selected=selected + if selected=="upper": + ba.textwidget(edit=self.upper_text,color=(0,0,1)) + ba.textwidget(edit=self.lower_text,color=(1,1,1)) + elif selected=="lower": + ba.textwidget(edit=self.lower_text,color=(0,0,1)) + ba.textwidget(edit=self.upper_text,color=(1,1,1)) + else: + ba.screenmessage("this should't happen from on_text_click") + + def draw_ui(self): + self.uiscale=ba.app.ui.uiscale + + super().__init__( + root_widget=ba.containerwidget( + size=(800, 800), + on_outside_click_call=self.close, + transition="in_right",)) + + increase_button=ba.buttonwidget( + parent=self._root_widget, + position=(250,100), + size=(50,50), + label="+", + scale=2, + on_activate_call=self.increase_limit) + + decrease_button=ba.buttonwidget( + parent=self._root_widget, + position=(100,100), + size=(50,50), + scale=2, + label="-", + on_activate_call=self.decrease_limit) + + + self.lower_text=ba.textwidget( + parent=self._root_widget, + size=(200,100), + scale=2, + position=(100,300), + h_align="center", + v_align="center", + maxwidth=400.0, + text=str(Ldefault), + click_activate=True, + selectable=True) + + self.upper_text=ba.textwidget( + parent=self._root_widget, + size=(200,100), + scale=2, + position=(500,300), + h_align="center", + v_align="center", + maxwidth=400.0, + text=str(Udefault), + click_activate=True, + selectable=True) + + ba.textwidget(edit=self.upper_text,on_activate_call=ba.Call(self.on_text_click,"upper")) + ba.textwidget(edit=self.lower_text,on_activate_call=ba.Call(self.on_text_click,"lower")) + + + self.warn_text=ba.textwidget( + parent=self._root_widget, + text="", + size=(400,100), + position=(200,500), + h_align="center", + v_align="center", + maxwidth=600) + + close_button=ba.buttonwidget( + parent=self._root_widget, + position=(700,650), + size=(100,100), + label=ba.Lstr(resource="cancelText"), + on_activate_call=self.close, + color=(0.8,0.2,0.2)) + ba.containerwidget(edit=self._root_widget, cancel_button=close_button) + + def close(self): + ba.screenmessage("closed") + ba.containerwidget(edit=self._root_widget, transition="out_right") - def _cancel(self): - if self._last_color and self._last_highlight: - colorscheme = ColorScheme(self._last_color, self._last_highlight) - colorscheme.apply() - # Good idea to revert this back now so we do not break anything else. - ba.app.accounts_v1.have_pro = original_have_pro - ba.containerwidget(edit=self._root_widget, transition="out_right") - def reset(self, transition_out=True): - if transition_out: - ba.playsound(ba.getsound("gunCocking")) - ba.app.config["ColorScheme"] = (None, None) - # Good idea to revert this back now so we do not break anything else. - ba.app.accounts_v1.have_pro = original_have_pro - ba.app.config.commit() - ba.containerwidget(edit=self._root_widget, transition="out_right") - def save(self, transition_out=True): - if transition_out: - ba.playsound(ba.getsound("gunCocking")) - colorscheme = ColorScheme( - self._color or self._default_colors[0], - self._highlight or self._default_colors[1], - ) - ba.containerwidget(edit=self._root_widget, transition="out_right") - -class UwUuser(ba.Plugin): +# ba_meta export plugin +class moodlight(ba.Plugin): Map._old_init = Map.__init__ - def on_plugin_manager_prompt(self): - ColorSchemeWindow() + + def on_app_running(self): + try: + SettingWindow().draw_ui() + except Exception as err: + ba.screenmessage(str(err)) +# def on_plugin_manager_prompt(self): +# SettingWindow() + def _new_init(self, vr_overlay_offset: Optional[Sequence[float]] = None) -> None: self._old_init(vr_overlay_offset) in_game = not isinstance(_ba.get_foreground_host_session(), mainmenu.MainMenuSession) @@ -199,13 +169,12 @@ def _new_init(self, vr_overlay_offset: Optional[Sequence[float]] = None) -> None gnode = _ba.getactivity().globalsnode - lowerlimit=5 - upperlimit=20 + def changetint(): ba.animate_array(gnode, 'tint', 3, { 0.0: gnode.tint, - 1.0: (random.randrange(lowerlimit,upperlimit)/10, random.randrange(lowerlimit,upperlimit)/10, random.randrange(lowerlimit, upperlimit)/10) + 1.0: (random.randrange(Ldefault,Udefault)/10, random.randrange(Ldefault,Udefault)/10, random.randrange(Ldefault,Udefault)/10) }) _ba.timer(0.3, changetint, repeat= True) From ee29a3ba4ca8140531a572890ca4d5dc3125110d Mon Sep 17 00:00:00 2001 From: Loup <90267658+Loup-Garou911XD@users.noreply.github.com> Date: Thu, 22 Sep 2022 13:28:25 +0530 Subject: [PATCH 0123/1464] Chat command to launch setting window --- plugins/utilities/mood_light.py | 49 +++++++++++++++++---------------- 1 file changed, 26 insertions(+), 23 deletions(-) diff --git a/plugins/utilities/mood_light.py b/plugins/utilities/mood_light.py index c7036a1c..fb514c24 100644 --- a/plugins/utilities/mood_light.py +++ b/plugins/utilities/mood_light.py @@ -9,6 +9,7 @@ import random from ba._map import Map from bastd import mainmenu +from bastd.ui.party import PartyWindow from bastd.gameutils import SharedObjects from time import sleep if TYPE_CHECKING: @@ -19,13 +20,14 @@ def __init__(self): global Ldefault,Udefault Ldefault=5 Udefault=20 + self.draw_ui() def increase_limit(self): global Ldefault,Udefault try: if Udefault>=29 and self.selected=="upper": ba.textwidget(edit=self.warn_text,text="Careful!You risk get blind beyond this point") - elif self.selected=="lower" and Ldefault>=-20: + elif self.selected=="lower" and Ldefault>=-20 or self.selected=="upper" and Udefault<=30: ba.textwidget(edit=self.warn_text,text="") if self.selected=="lower": @@ -42,7 +44,7 @@ def decrease_limit(self): try: if Ldefault<=-19 and self.selected == "lower": ba.textwidget(edit=self.warn_text,text="DON'T BE AFRAID OF DARK,IT'S A PLACE WHERE YOU CAN HIDE") - elif (self.selected == "upper" and Udefault >=30) or (self.selected== "lower" and Ldefault>=-20): + elif (self.selected == "upper" and Udefault <=30) or (self.selected== "lower" and Ldefault>=-20): ba.textwidget(edit=self.warn_text,text="") @@ -115,11 +117,7 @@ def draw_ui(self): text=str(Udefault), click_activate=True, selectable=True) - - ba.textwidget(edit=self.upper_text,on_activate_call=ba.Call(self.on_text_click,"upper")) - ba.textwidget(edit=self.lower_text,on_activate_call=ba.Call(self.on_text_click,"lower")) - - + self.warn_text=ba.textwidget( parent=self._root_widget, text="", @@ -133,34 +131,41 @@ def draw_ui(self): parent=self._root_widget, position=(700,650), size=(100,100), - label=ba.Lstr(resource="cancelText"), + icon=ba.gettexture('crossOut'), on_activate_call=self.close, color=(0.8,0.2,0.2)) + ba.containerwidget(edit=self._root_widget, cancel_button=close_button) + ba.textwidget(edit=self.upper_text,on_activate_call=ba.Call(self.on_text_click,"upper")) + ba.textwidget(edit=self.lower_text,on_activate_call=ba.Call(self.on_text_click,"lower")) - def close(self): - ba.screenmessage("closed") + def close(self): ba.containerwidget(edit=self._root_widget, transition="out_right") - - - - - - - # ba_meta export plugin class moodlight(ba.Plugin): + def __init__(self): + pass Map._old_init = Map.__init__ def on_app_running(self): try: - SettingWindow().draw_ui() + SettingWindow() + _ba.timer(0.5, self.on_chat_message, True) except Exception as err: ba.screenmessage(str(err)) -# def on_plugin_manager_prompt(self): -# SettingWindow() + + def on_chat_message(self): + messages=_ba.get_chat_messages() + if len(messages)>0: + lastmessage=messages[-1].split(":")[-1].strip().lower() + if lastmessage in ("/mood light","/mood lighting","/mood_light","/mood_lighting","/moodlight","ml"): + _ba.chatmessage("Mood light settings opened") + SettingWindow() + + def on_plugin_manager_prompt(self): + SettingWindow() def _new_init(self, vr_overlay_offset: Optional[Sequence[float]] = None) -> None: self._old_init(vr_overlay_offset) @@ -169,9 +174,7 @@ def _new_init(self, vr_overlay_offset: Optional[Sequence[float]] = None) -> None gnode = _ba.getactivity().globalsnode - - - def changetint(): + def changetint(self): ba.animate_array(gnode, 'tint', 3, { 0.0: gnode.tint, 1.0: (random.randrange(Ldefault,Udefault)/10, random.randrange(Ldefault,Udefault)/10, random.randrange(Ldefault,Udefault)/10) From d32cf3556d38465e41fc4c0e0fef14c616460edd Mon Sep 17 00:00:00 2001 From: Cross Joy <87638792+CrossJoy@users.noreply.github.com> Date: Mon, 26 Sep 2022 18:46:16 +0800 Subject: [PATCH 0124/1464] fixed easy connect for 1.7.7 and above --- plugins/utilities/easy_connect.py | 30 ++++++++++++++++++++++-------- 1 file changed, 22 insertions(+), 8 deletions(-) diff --git a/plugins/utilities/easy_connect.py b/plugins/utilities/easy_connect.py index 0c9d6e08..ce566d06 100644 --- a/plugins/utilities/easy_connect.py +++ b/plugins/utilities/easy_connect.py @@ -156,7 +156,7 @@ def new_build_favorites_tab(self, region_height: float) -> None: autoselect=True) if uiscale is ba.UIScale.SMALL and ba.app.ui.use_toolbars: ba.widget(edit=btn1, - left_widget=_ba.get_special_widget('back_button')) + left_widget=ba_internal.get_special_widget('back_button')) btnv -= b_height + b_space_extra ba.buttonwidget(parent=self._container, size=(b_width, b_height), @@ -211,7 +211,7 @@ def new_on_favorites_connect_press(self) -> None: call=ba.WeakCall( self._host_lookup_result)).start() - if self.retry_inter > 0 and (_ba.get_connection_to_host_info() == {} or _ba.get_connection_to_host_info()['build_number'] == 0): + if self.retry_inter > 0 and (ba_internal.get_connection_to_host_info() == {} or ba_internal.get_connection_to_host_info()['build_number'] == 0): ba.screenmessage("Server full or unreachable, Retrying....") self._retry_timer = ba.Timer(self.retry_inter, ba.Call( self._on_favorites_connect_press), timetype=ba.TimeType.REAL) @@ -295,8 +295,8 @@ def update(self, index: int, party: PartyEntry, sub_scroll_width: float, if party.clean_display_index == index: return - ping_good = _ba.get_v1_account_misc_read_val('pingGood', 100) - ping_med = _ba.get_v1_account_misc_read_val('pingMed', 500) + ping_good = ba_internal.get_v1_account_misc_read_val('pingGood', 100) + ping_med = ba_internal.get_v1_account_misc_read_val('pingMed', 500) self._clear() hpos = 20 @@ -329,7 +329,7 @@ def update(self, index: int, party: PartyEntry, sub_scroll_width: float, if party.stats_addr or True: url = party.stats_addr.replace( '${ACCOUNT}', - _ba.get_v1_account_misc_read_val_2('resolvedAccountID', + ba_internal.get_v1_account_misc_read_val_2('resolvedAccountID', 'UNKNOWN')) self._stats_button = ba.buttonwidget( color=(0.5, 0.8, 0.8), @@ -432,7 +432,7 @@ def popup_menu_selected_choice(self, window: popup.PopupMenu, if choice == 'stats': url = _party.stats_addr.replace( '${ACCOUNT}', - _ba.get_v1_account_misc_read_val_2('resolvedAccountID', + ba_internal.get_v1_account_misc_read_val_2('resolvedAccountID', 'UNKNOWN')) ba.open_url(url) elif choice == 'connect': @@ -457,8 +457,22 @@ def popup_menu_selected_choice(self, window: popup.PopupMenu, ba.clipboard_set_text(_party.queue) ba.playsound(ba.getsound('gunCocking')) +def is_game_version_lower_than(version): + """ + Returns a boolean value indicating whether the current game + version is lower than the passed version. Useful for addressing + any breaking changes within game versions. + """ + game_version = tuple(map(int, ba.app.version.split("."))) + version = tuple(map(int, version.split("."))) + return game_version < version def replace(): + global ba_internal + if is_game_version_lower_than("1.7.7"): + ba_internal = _ba + else: + ba_internal = ba.internal manualtab.ManualGatherTab._build_favorites_tab = new_build_favorites_tab manualtab.ManualGatherTab._on_favorites_connect_press = new_on_favorites_connect_press manualtab.ManualGatherTab.auto_retry_dec = auto_retry_dec @@ -572,10 +586,10 @@ def move_right(self): self.direction = "right" def connect(self, address, port): - if not self.closed and (_ba.get_connection_to_host_info() == {} or _ba.get_connection_to_host_info()['build_number'] == 0): + if not self.closed and (ba_internal.get_connection_to_host_info() == {} or ba_internal.get_connection_to_host_info()['build_number'] == 0): ba.textwidget(edit=self._title_text, text="Retrying....("+str(self.retry_count)+")") self.retry_count += 1 - _ba.connect_to_party(address, port=port) + ba_internal.connect_to_party(address, port=port) self._retry_timer = ba.Timer(1.5, ba.Call( self.connect, address, port), timetype=ba.TimeType.REAL) From b3f01804634a376542423b9b4ea1cb3f6925c1db Mon Sep 17 00:00:00 2001 From: Cross Joy <87638792+CrossJoy@users.noreply.github.com> Date: Mon, 26 Sep 2022 19:05:24 +0800 Subject: [PATCH 0125/1464] Update easy_connect version --- plugins/utilities.json | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/plugins/utilities.json b/plugins/utilities.json index d9b415fd..25f628ba 100644 --- a/plugins/utilities.json +++ b/plugins/utilities.json @@ -119,6 +119,7 @@ } ], "versions": { + "1.2.0": null "1.0.0": { "api_version": 7, "commit_sha": "3a8ba07", @@ -204,4 +205,4 @@ } } } -} \ No newline at end of file +} From d61d420909a66cc4881bd0c73c87c77e56a08c47 Mon Sep 17 00:00:00 2001 From: CrossJoy Date: Mon, 26 Sep 2022 11:19:43 +0000 Subject: [PATCH 0126/1464] [ci] auto-format --- plugins/utilities/easy_connect.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/plugins/utilities/easy_connect.py b/plugins/utilities/easy_connect.py index ce566d06..8f5eb245 100644 --- a/plugins/utilities/easy_connect.py +++ b/plugins/utilities/easy_connect.py @@ -330,7 +330,7 @@ def update(self, index: int, party: PartyEntry, sub_scroll_width: float, url = party.stats_addr.replace( '${ACCOUNT}', ba_internal.get_v1_account_misc_read_val_2('resolvedAccountID', - 'UNKNOWN')) + 'UNKNOWN')) self._stats_button = ba.buttonwidget( color=(0.5, 0.8, 0.8), textcolor=(1.0, 1.0, 1.0), @@ -433,7 +433,7 @@ def popup_menu_selected_choice(self, window: popup.PopupMenu, url = _party.stats_addr.replace( '${ACCOUNT}', ba_internal.get_v1_account_misc_read_val_2('resolvedAccountID', - 'UNKNOWN')) + 'UNKNOWN')) ba.open_url(url) elif choice == 'connect': @@ -457,6 +457,7 @@ def popup_menu_selected_choice(self, window: popup.PopupMenu, ba.clipboard_set_text(_party.queue) ba.playsound(ba.getsound('gunCocking')) + def is_game_version_lower_than(version): """ Returns a boolean value indicating whether the current game @@ -467,6 +468,7 @@ def is_game_version_lower_than(version): version = tuple(map(int, version.split("."))) return game_version < version + def replace(): global ba_internal if is_game_version_lower_than("1.7.7"): From d8d29852875f4002952854ec66226abec9943d05 Mon Sep 17 00:00:00 2001 From: Cross Joy <87638792+CrossJoy@users.noreply.github.com> Date: Tue, 27 Sep 2022 07:22:44 +0800 Subject: [PATCH 0127/1464] added comma --- plugins/utilities.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/utilities.json b/plugins/utilities.json index 25f628ba..bfd11977 100644 --- a/plugins/utilities.json +++ b/plugins/utilities.json @@ -119,7 +119,7 @@ } ], "versions": { - "1.2.0": null + "1.2.0": null, "1.0.0": { "api_version": 7, "commit_sha": "3a8ba07", From a58e12c609be974028ba003b63b7e46012dc6cf1 Mon Sep 17 00:00:00 2001 From: CrossJoy Date: Mon, 26 Sep 2022 23:23:05 +0000 Subject: [PATCH 0128/1464] [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 bfd11977..f51a3b42 100644 --- a/plugins/utilities.json +++ b/plugins/utilities.json @@ -119,7 +119,12 @@ } ], "versions": { - "1.2.0": null, + "1.2.0": { + "api_version": 7, + "commit_sha": "d8d2985", + "released_on": "26-09-2022", + "md5sum": "1ef7d937e49a1aa954f56b3f9bf8a5fe" + }, "1.0.0": { "api_version": 7, "commit_sha": "3a8ba07", @@ -205,4 +210,4 @@ } } } -} +} \ No newline at end of file From cd25d292c8fc280a9500056598c05289c682fbff Mon Sep 17 00:00:00 2001 From: Cross Joy <87638792+CrossJoy@users.noreply.github.com> Date: Tue, 27 Sep 2022 22:29:10 +0800 Subject: [PATCH 0129/1464] Organize the version checker func Make it more readable on the top. --- plugins/utilities/easy_connect.py | 33 ++++++++++++++++--------------- 1 file changed, 17 insertions(+), 16 deletions(-) diff --git a/plugins/utilities/easy_connect.py b/plugins/utilities/easy_connect.py index 8f5eb245..e55f1012 100644 --- a/plugins/utilities/easy_connect.py +++ b/plugins/utilities/easy_connect.py @@ -47,6 +47,23 @@ from bastd.ui.gather.publictab import PublicGatherTab +def is_game_version_lower_than(version): + """ + Returns a boolean value indicating whether the current game + version is lower than the passed version. Useful for addressing + any breaking changes within game versions. + """ + game_version = tuple(map(int, ba.app.version.split("."))) + version = tuple(map(int, version.split("."))) + return game_version < version + + +if is_game_version_lower_than("1.7.7"): + ba_internal = _ba +else: + ba_internal = ba.internal + + class _HostLookupThread(threading.Thread): """Thread to fetch an addr.""" @@ -458,23 +475,7 @@ def popup_menu_selected_choice(self, window: popup.PopupMenu, ba.playsound(ba.getsound('gunCocking')) -def is_game_version_lower_than(version): - """ - Returns a boolean value indicating whether the current game - version is lower than the passed version. Useful for addressing - any breaking changes within game versions. - """ - game_version = tuple(map(int, ba.app.version.split("."))) - version = tuple(map(int, version.split("."))) - return game_version < version - - def replace(): - global ba_internal - if is_game_version_lower_than("1.7.7"): - ba_internal = _ba - else: - ba_internal = ba.internal manualtab.ManualGatherTab._build_favorites_tab = new_build_favorites_tab manualtab.ManualGatherTab._on_favorites_connect_press = new_on_favorites_connect_press manualtab.ManualGatherTab.auto_retry_dec = auto_retry_dec From b7036af184ada314dc40b04e76986355d9fc6951 Mon Sep 17 00:00:00 2001 From: Rikko Date: Tue, 27 Sep 2022 20:34:06 +0530 Subject: [PATCH 0130/1464] Set version to null for ci to autofill --- plugins/utilities.json | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/plugins/utilities.json b/plugins/utilities.json index f51a3b42..bfd11977 100644 --- a/plugins/utilities.json +++ b/plugins/utilities.json @@ -119,12 +119,7 @@ } ], "versions": { - "1.2.0": { - "api_version": 7, - "commit_sha": "d8d2985", - "released_on": "26-09-2022", - "md5sum": "1ef7d937e49a1aa954f56b3f9bf8a5fe" - }, + "1.2.0": null, "1.0.0": { "api_version": 7, "commit_sha": "3a8ba07", @@ -210,4 +205,4 @@ } } } -} \ No newline at end of file +} From 2355cbdbc38a6bf6126ece07436888244e0fbfeb Mon Sep 17 00:00:00 2001 From: rikkolovescats Date: Tue, 27 Sep 2022 15:05:10 +0000 Subject: [PATCH 0131/1464] [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 bfd11977..ae08b424 100644 --- a/plugins/utilities.json +++ b/plugins/utilities.json @@ -119,7 +119,12 @@ } ], "versions": { - "1.2.0": null, + "1.2.0": { + "api_version": 7, + "commit_sha": "b7036af", + "released_on": "27-09-2022", + "md5sum": "c9d694c1beafba7957da34014a38d278" + }, "1.0.0": { "api_version": 7, "commit_sha": "3a8ba07", @@ -205,4 +210,4 @@ } } } -} +} \ No newline at end of file From 7dd4c75b8b8020989684f229d42e7ace2b18ad21 Mon Sep 17 00:00:00 2001 From: Droopy <90500887+Drooopyyy@users.noreply.github.com> Date: Fri, 30 Sep 2022 15:18:39 +0530 Subject: [PATCH 0132/1464] Add files via upload Ultra Partywindow for 1.7.7+ --- .../utilities/Updated_Ultra_Partywindow.py | 2760 +++++++++++++++++ 1 file changed, 2760 insertions(+) create mode 100644 plugins/utilities/Updated_Ultra_Partywindow.py diff --git a/plugins/utilities/Updated_Ultra_Partywindow.py b/plugins/utilities/Updated_Ultra_Partywindow.py new file mode 100644 index 00000000..c82a8519 --- /dev/null +++ b/plugins/utilities/Updated_Ultra_Partywindow.py @@ -0,0 +1,2760 @@ +__author__ = 'Droopy' +__version__ = 4.0 + +# ba_meta require api 7 +import datetime +import json +import math +import os +import pickle +import random +import time +import urllib.request +import weakref +from threading import Thread +from typing import List, Tuple, Sequence, Optional, Dict, Any, cast +from hashlib import md5 + +import _ba +import ba +import bastd.ui.party +from bastd.ui.colorpicker import ColorPickerExact +from bastd.ui.confirm import ConfirmWindow +from bastd.ui.mainmenu import MainMenuWindow +from bastd.ui.popup import PopupMenuWindow, PopupWindow, PopupMenu + +_ip = '127.0.0.1' +_port = 43210 +_ping = '-' +url = 'http://bombsquadprivatechat.ml' +last_msg = None + +my_directory = _ba.env()['python_directory_user'] + '/UltraPartyWindowFiles/' +quick_msg_file = my_directory + 'QuickMessages.txt' +cookies_file = my_directory + 'cookies.txt' +saved_ids_file = my_directory + 'saved_ids.json' +my_location = my_directory + + +def initialize(): + config_defaults = {'Party Chat Muted': False, + 'Chat Muted': False, + 'ping button': True, + 'IP button': True, + 'copy button': True, + 'Direct Send': False, + 'Colorful Chat': True, + 'Custom Commands': [], + 'Message Notification': 'bottom', + 'Self Status': 'online', + 'Translate Source Language': '', + 'Translate Destination Language': 'en', + 'Pronunciation': True + } + config = ba.app.config + for key in config_defaults: + if key not in config: + config[key] = config_defaults[key] + + if not os.path.exists(my_directory): + os.makedirs(my_directory) + if not os.path.exists(cookies_file): + with open(cookies_file, 'wb') as f: + pickle.dump({}, f) + if not os.path.exists(saved_ids_file): + with open(saved_ids_file, 'w') as f: + data = {} + json.dump(data, f) + + +def display_error(msg=None): + if msg: + ba.screenmessage(msg, (1, 0, 0)) + else: + ba.screenmessage('Failed!', (1, 0, 0)) + ba.playsound(ba.getsound('error')) + + +def display_success(msg=None): + if msg: + ba.screenmessage(msg, (0, 1, 0)) + else: + ba.screenmessage('Successful!', (0, 1, 0)) + +class Translate(Thread): + def __init__(self, data, callback): + super().__init__() + self.data = data + self._callback = callback + def run(self): + _ba.pushcall(ba.Call(ba.screenmessage, 'Translating...'), from_other_thread=True) + response = messenger._send_request(f'{url}/translate', self.data) + if response: + _ba.pushcall(ba.Call(self._callback, response), from_other_thread=True) + +class ColorTracker: + def __init__(self): + self.saved = {} + + def _get_safe_color(self, sender): + while True: + color = (random.random(), random.random(), random.random()) + s = 0 + background = ba.app.config.get('PartyWindow Main Color', (0.5, 0.5, 0.5)) + for i, j in zip(color, background): + s += (i - j) ** 2 + if s > 0.1: + self.saved[sender] = color + if len(self.saved) > 20: + self.saved.pop(list(self.saved.keys())[0]) + break + time.sleep(0.1) + + def _get_sender_color(self, sender): + if sender not in self.saved: + self.thread = Thread(target=self._get_safe_color, args=(sender,)) + self.thread.start() + return (1, 1, 1) + else: + return self.saved[sender] + + +class PrivateChatHandler: + def __init__(self): + self.pvt_msgs = {} + self.login_id = None + self.last_msg_id = None + self.logged_in = False + self.cookieProcessor = urllib.request.HTTPCookieProcessor() + self.opener = urllib.request.build_opener(self.cookieProcessor) + self.filter = 'all' + self.pending_messages = [] + self.friends_status = {} + self.error = '' + Thread(target=self._ping).start() + + def _load_ids(self): + with open(saved_ids_file, 'r') as f: + saved = json.load(f) + if self.myid in saved: + self.saved_ids = saved[self.myid] + else: + self.saved_ids = {'all': ''} + + def _dump_ids(self): + with open(saved_ids_file, 'r') as f: + saved = json.load(f) + with open(saved_ids_file, 'w') as f: + saved[self.myid] = self.saved_ids + json.dump(saved, f) + + def _ping(self): + self.server_online = False + response = self._send_request(url=f'{url}') + if not response: + self.error = 'Server offline' + elif response: + try: + self.server_online = True + version = float(response.replace('v', '')) + if version > __version__: + self._update_version() + except: + self.error = 'Server offline' + + def _update_version(self): + new_file = self._send_request(url=f'{url}/updatepartywindow?get=file') + hash = self._send_request(url=f'{url}/updatepartywindow?get=md5') + if hash and new_file: + file_hash = md5(new_file.encode()).hexdigest() + if hash == file_hash: + with open(__file__, 'w') as f: + f.write(new_file) + _ba.pushcall(ba.Call(ba.screenmessage, 'Ultra party window updated\nNeeds restart.'), True) + + + def _signup(self, registration_key): + data = dict(pb_id=self.myid, registration_key=registration_key) + response = self._send_request(url=f'{url}/signup', data=data) + if response: + if response == 'successful': + display_success('Account Created Successfully') + self._login(registration_key=registration_key) + return True + display_error(response) + + def _save_cookie(self): + with open(cookies_file, 'rb') as f: + cookies = pickle.load(f) + with open(cookies_file, 'wb') as f: + for c in self.cookieProcessor.cookiejar: + cookie = pickle.dumps(c) + break + cookies[self.myid] = cookie + pickle.dump(cookies, f) + + def _cookie_login(self): + self.myid = ba.internal.get_v1_account_misc_read_val_2('resolvedAccountID', '') + try: + with open(cookies_file, 'rb') as f: + cookies = pickle.load(f) + except: + return False + if self.myid in cookies: + cookie = pickle.loads(cookies[self.myid]) + self.cookieProcessor.cookiejar.set_cookie(cookie) + self.opener = urllib.request.build_opener(self.cookieProcessor) + response = self._send_request(url=f'{url}/login') + if response.startswith('logged in as'): + self.logged_in = True + self._load_ids() + display_success(response) + return True + + def _login(self, registration_key): + self.myid = ba.internal.get_v1_account_misc_read_val_2('resolvedAccountID', '') + data = dict(pb_id=self.myid, registration_key=registration_key) + response = self._send_request(url=f'{url}/login', data=data) + if response == 'successful': + self.logged_in = True + self._load_ids() + self._save_cookie() + display_success('Account Logged in Successfully') + return True + else: + display_error(response) + + def _query(self, pb_id=None): + if not pb_id: + pb_id = self.myid + response = self._send_request(url=f'{url}/query/{pb_id}') + if response == 'exists': + return True + return False + + def _send_request(self, url, data=None): + try: + if not data: + response = self.opener.open(url) + else: + response = self.opener.open(url, data=json.dumps(data).encode()) + if response.getcode() != 200: + display_error(response.read().decode()) + return None + else: + return response.read().decode() + except: + return None + + def _save_id(self, account_id, nickname='', verify=True): + # display_success(f'Saving {account_id}. Please wait...') + if verify: + url = 'http://bombsquadgame.com/accountquery?id=' + account_id + response = json.loads(urllib.request.urlopen(url).read().decode()) + if 'error' in response: + display_error('Enter valid account id') + return False + self.saved_ids[account_id] = {} + name = None + if nickname == '': + name_html = response['name_html'] + name = name_html.split('>')[1] + nick = name if name else nickname + else: + nick = nickname + self.saved_ids[account_id] = nick + self._dump_ids() + display_success(f'Account added: {nick}({account_id})') + return True + + def _remove_id(self, account_id): + removed = self.saved_ids.pop(account_id) + self._dump_ids() + ba.screenmessage(f'Removed successfully: {removed}({account_id})', (0, 1, 0)) + ba.playsound(ba.getsound('shieldDown')) + + def _format_message(self, msg): + filter = msg['filter'] + if filter in self.saved_ids: + if self.filter == 'all': + message = '[' + self.saved_ids[filter] + ']' + msg['message'] + else: + message = msg['message'] + else: + message = '[' + msg['filter'] + ']: ' + 'Message from unsaved id. Save id to view message.' + return message + + def _get_status(self, id, type='status'): + info = self.friends_status.get(id, {}) + if not info: + return '-' + if type == 'status': + return info['status'] + else: + last_seen = info["last_seen"] + last_seen = _get_local_time(last_seen) + ba.screenmessage(f'Last seen on: {last_seen}') + + +def _get_local_time(utctime): + d = datetime.datetime.strptime(utctime, '%d-%m-%Y %H:%M:%S') + d = d.replace(tzinfo=datetime.timezone.utc) + d = d.astimezone() + return d.strftime('%B %d,\t\t%H:%M:%S') + + +def update_status(): + if messenger.logged_in: + if ba.app.config['Self Status'] == 'online': + host = _ba.get_connection_to_host_info().get('name', '') + if host: + my_status = f'Playing in {host}' + else: + my_status = 'in Lobby' + ids_to_check = [i for i in messenger.saved_ids if i != 'all'] + response = messenger._send_request(url=f'{url}/updatestatus', + data=dict(self_status=my_status, ids=ids_to_check)) + if response: + messenger.friends_status = json.loads(response) + else: + messenger.friends_status = {} + + +def messenger_thread(): + counter = 0 + while True: + counter += 1 + time.sleep(0.6) + check_new_message() + if counter > 5: + counter = 0 + update_status() + + +def check_new_message(): + if messenger.logged_in: + if messenger.login_id != messenger.myid: + response = messenger._send_request(f'{url}/first') + if response: + messenger.pvt_msgs = json.loads(response) + if messenger.pvt_msgs['all']: + messenger.last_msg_id = messenger.pvt_msgs['all'][-1]['id'] + messenger.login_id = messenger.myid + else: + response = messenger._send_request(f'{url}/new/{messenger.last_msg_id}') + if response: + new_msgs = json.loads(response) + if new_msgs: + for msg in new_msgs['messages']: + if msg['id'] > messenger.last_msg_id: + messenger.last_msg_id = msg['id'] + messenger.pvt_msgs['all'].append( + dict(id=msg['id'], filter=msg['filter'], message=msg['message'], sent=msg['sent'])) + if len(messenger.pvt_msgs['all']) > 40: + messenger.pvt_msgs['all'].pop(0) + if msg['filter'] not in messenger.pvt_msgs: + messenger.pvt_msgs[msg['filter']] = [ + dict(id=msg['id'], filter=msg['filter'], message=msg['message'], sent=msg['sent'])] + else: + messenger.pvt_msgs[msg['filter']].append( + dict(id=msg['id'], filter=msg['filter'], message=msg['message'], sent=msg['sent'])) + if len(messenger.pvt_msgs[msg['filter']]) > 20: + messenger.pvt_msgs[msg['filter']].pop(0) + messenger.pending_messages.append( + (messenger._format_message(msg), msg['filter'], msg['sent'])) + + +def display_message(msg, msg_type, filter=None, sent=None): + flag = None + notification = ba.app.config['Message Notification'] + if _ba.app.ui.party_window: + if _ba.app.ui.party_window(): + if _ba.app.ui.party_window()._private_chat: + flag = 1 + if msg_type == 'private': + if messenger.filter == filter or messenger.filter == 'all': + _ba.app.ui.party_window().on_chat_message(msg, sent) + else: + if notification == 'top': + ba.screenmessage(msg, (1, 1, 0), True, ba.gettexture('coin')) + else: + ba.screenmessage(msg, (1, 1, 0), False) + else: + ba.screenmessage(msg, (0.2, 1.0, 1.0), True, ba.gettexture('circleShadow')) + else: + flag = 1 + if msg_type == 'private': + if notification == 'top': + ba.screenmessage(msg, (1, 1, 0), True, ba.gettexture('coin')) + else: + ba.screenmessage(msg, (1, 1, 0), False) + if not flag: + if msg_type == 'private': + if notification == 'top': + ba.screenmessage(msg, (1, 1, 0), True, ba.gettexture('coin')) + else: + ba.screenmessage(msg, (1, 1, 0), False) + else: + ba.screenmessage(msg, (0.2, 1.0, 1.0), True, ba.gettexture('circleShadow')) + + +def msg_displayer(): + for msg in messenger.pending_messages: + display_message(msg[0], 'private', msg[1], msg[2]) + messenger.pending_messages.remove(msg) + if ba.app.config['Chat Muted'] and not ba.app.config['Party Chat Muted']: + global last_msg + last = _ba.get_chat_messages() + lm = last[-1] if last else None + if lm != last_msg: + last_msg = lm + display_message(lm, 'public') + + +class SortQuickMessages: + def __init__(self): + uiscale = ba.app.ui.uiscale + bg_color = ba.app.config.get('PartyWindow Main Color', (0.5, 0.5, 0.5)) + self._width = 750 if uiscale is ba.UIScale.SMALL else 600 + self._height = (300 if uiscale is ba.UIScale.SMALL else + 325 if uiscale is ba.UIScale.MEDIUM else 350) + self._root_widget = ba.containerwidget( + size=(self._width, self._height), + transition='in_right', + on_outside_click_call=self._save, + color=bg_color, + parent=_ba.get_special_widget('overlay_stack'), + scale=(2.0 if uiscale is ba.UIScale.SMALL else + 1.3 if uiscale is ba.UIScale.MEDIUM else 1.0), + stack_offset=(0, -16) if uiscale is ba.UIScale.SMALL else (0, 0)) + ba.textwidget(parent=self._root_widget, + position=(-10, self._height - 50), + size=(self._width, 25), + text='Sort Quick Messages', + color=ba.app.ui.title_color, + scale=1.05, + h_align='center', + v_align='center', + maxwidth=270) + b_textcolor = (0.4, 0.75, 0.5) + up_button = ba.buttonwidget(parent=self._root_widget, + position=(10, 170), + size=(75, 75), + on_activate_call=self._move_up, + label=ba.charstr(ba.SpecialChar.UP_ARROW), + button_type='square', + color=bg_color, + textcolor=b_textcolor, + autoselect=True, + repeat=True) + down_button = ba.buttonwidget(parent=self._root_widget, + position=(10, 75), + size=(75, 75), + on_activate_call=self._move_down, + label=ba.charstr(ba.SpecialChar.DOWN_ARROW), + button_type='square', + color=bg_color, + textcolor=b_textcolor, + autoselect=True, + repeat=True) + self._scroll_width = self._width - 150 + self._scroll_height = self._height - 110 + self._scrollwidget = ba.scrollwidget( + parent=self._root_widget, + size=(self._scroll_width, self._scroll_height), + color=bg_color, + position=(100, 40)) + self._columnwidget = ba.columnwidget( + parent=self._scrollwidget, + border=2, + margin=0) + with open(quick_msg_file, 'r') as f: + self.msgs = f.read().split('\n') + self._msg_selected = None + self._refresh() + ba.containerwidget(edit=self._root_widget, + on_cancel_call=self._save) + + def _refresh(self): + for child in self._columnwidget.get_children(): + child.delete() + for msg in enumerate(self.msgs): + txt = ba.textwidget( + parent=self._columnwidget, + size=(self._scroll_width - 10, 30), + selectable=True, + always_highlight=True, + on_select_call=ba.Call(self._on_msg_select, msg), + text=msg[1], + h_align='left', + v_align='center', + maxwidth=self._scroll_width) + if msg == self._msg_selected: + ba.columnwidget(edit=self._columnwidget, + selected_child=txt, + visible_child=txt) + + def _on_msg_select(self, msg): + self._msg_selected = msg + + def _move_up(self): + index = self._msg_selected[0] + msg = self._msg_selected[1] + if index: + self.msgs.insert((index - 1), self.msgs.pop(index)) + self._msg_selected = (index - 1, msg) + self._refresh() + + def _move_down(self): + index = self._msg_selected[0] + msg = self._msg_selected[1] + if index + 1 < len(self.msgs): + self.msgs.insert((index + 1), self.msgs.pop(index)) + self._msg_selected = (index + 1, msg) + self._refresh() + + def _save(self) -> None: + try: + with open(quick_msg_file, 'w') as f: + f.write('\n'.join(self.msgs)) + except: + ba.print_exception() + ba.screenmessage('Error!', (1, 0, 0)) + ba.containerwidget( + edit=self._root_widget, + transition='out_right') + + +class TranslationSettings: + def __init__(self): + uiscale = ba.app.ui.uiscale + height = (300 if uiscale is ba.UIScale.SMALL else + 350 if uiscale is ba.UIScale.MEDIUM else 400) + width = (500 if uiscale is ba.UIScale.SMALL else + 600 if uiscale is ba.UIScale.MEDIUM else 650) + self._transition_out: Optional[str] + scale_origin: Optional[Tuple[float, float]] + self._transition_out = 'out_scale' + scale_origin = 10 + transition = 'in_scale' + scale_origin = None + cancel_is_selected = False + cfg = ba.app.config + bg_color = cfg.get('PartyWindow Main Color', (0.5, 0.5, 0.5)) + + LANGUAGES = { + '': 'Auto-Detect', + 'af': 'afrikaans', + 'sq': 'albanian', + 'am': 'amharic', + 'ar': 'arabic', + 'hy': 'armenian', + 'az': 'azerbaijani', + 'eu': 'basque', + 'be': 'belarusian', + 'bn': 'bengali', + 'bs': 'bosnian', + 'bg': 'bulgarian', + 'ca': 'catalan', + 'ceb': 'cebuano', + 'ny': 'chichewa', + 'zh-cn': 'chinese (simplified)', + 'zh-tw': 'chinese (traditional)', + 'co': 'corsican', + 'hr': 'croatian', + 'cs': 'czech', + 'da': 'danish', + 'nl': 'dutch', + 'en': 'english', + 'eo': 'esperanto', + 'et': 'estonian', + 'tl': 'filipino', + 'fi': 'finnish', + 'fr': 'french', + 'fy': 'frisian', + 'gl': 'galician', + 'ka': 'georgian', + 'de': 'german', + 'el': 'greek', + 'gu': 'gujarati', + 'ht': 'haitian creole', + 'ha': 'hausa', + 'haw': 'hawaiian', + 'iw': 'hebrew', + 'he': 'hebrew', + 'hi': 'hindi', + 'hmn': 'hmong', + 'hu': 'hungarian', + 'is': 'icelandic', + 'ig': 'igbo', + 'id': 'indonesian', + 'ga': 'irish', + 'it': 'italian', + 'ja': 'japanese', + 'jw': 'javanese', + 'kn': 'kannada', + 'kk': 'kazakh', + 'km': 'khmer', + 'ko': 'korean', + 'ku': 'kurdish (kurmanji)', + 'ky': 'kyrgyz', + 'lo': 'lao', + 'la': 'latin', + 'lv': 'latvian', + 'lt': 'lithuanian', + 'lb': 'luxembourgish', + 'mk': 'macedonian', + 'mg': 'malagasy', + 'ms': 'malay', + 'ml': 'malayalam', + 'mt': 'maltese', + 'mi': 'maori', + 'mr': 'marathi', + 'mn': 'mongolian', + 'my': 'myanmar (burmese)', + 'ne': 'nepali', + 'no': 'norwegian', + 'or': 'odia', + 'ps': 'pashto', + 'fa': 'persian', + 'pl': 'polish', + 'pt': 'portuguese', + 'pa': 'punjabi', + 'ro': 'romanian', + 'ru': 'russian', + 'sm': 'samoan', + 'gd': 'scots gaelic', + 'sr': 'serbian', + 'st': 'sesotho', + 'sn': 'shona', + 'sd': 'sindhi', + 'si': 'sinhala', + 'sk': 'slovak', + 'sl': 'slovenian', + 'so': 'somali', + 'es': 'spanish', + 'su': 'sundanese', + 'sw': 'swahili', + 'sv': 'swedish', + 'tg': 'tajik', + 'ta': 'tamil', + 'te': 'telugu', + 'th': 'thai', + 'tr': 'turkish', + 'uk': 'ukrainian', + 'ur': 'urdu', + 'ug': 'uyghur', + 'uz': 'uzbek', + 'vi': 'vietnamese', + 'cy': 'welsh', + 'xh': 'xhosa', + 'yi': 'yiddish', + 'yo': 'yoruba', + 'zu': 'zulu'} + + self.root_widget = ba.containerwidget( + size=(width, height), + color=bg_color, + transition=transition, + toolbar_visibility='menu_minimal_no_back', + parent=_ba.get_special_widget('overlay_stack'), + on_outside_click_call=self._cancel, + scale=(2.1 if uiscale is ba.UIScale.SMALL else + 1.5 if uiscale is ba.UIScale.MEDIUM else 1.0), + scale_origin_stack_offset=scale_origin) + ba.textwidget(parent=self.root_widget, + position=(width * 0.5, height - 45), + size=(20, 20), + h_align='center', + v_align='center', + text="Text Translation", + scale=0.9, + color=(5, 5, 5)) + cbtn = btn = ba.buttonwidget(parent=self.root_widget, + autoselect=True, + position=(30, height - 60), + size=(30, 30), + label=ba.charstr(ba.SpecialChar.BACK), + button_type='backSmall', + on_activate_call=self._cancel) + + source_lang_text = ba.textwidget(parent=self.root_widget, + position=(40, height - 110), + size=(20, 20), + h_align='left', + v_align='center', + text="Source Language : ", + scale=0.9, + color=(1, 1, 1)) + + source_lang_menu = PopupMenu( + parent=self.root_widget, + position=(330 if uiscale is ba.UIScale.SMALL else 400, height - 115), + width=200, + scale=(2.8 if uiscale is ba.UIScale.SMALL else + 1.8 if uiscale is ba.UIScale.MEDIUM else 1.2), + current_choice=cfg['Translate Source Language'], + choices=LANGUAGES.keys(), + choices_display=(ba.Lstr(value=i) for i in LANGUAGES.values()), + button_size=(130, 35), + on_value_change_call=self._change_source) + + destination_lang_text = ba.textwidget(parent=self.root_widget, + position=(40, height - 165), + size=(20, 20), + h_align='left', + v_align='center', + text="Destination Language : ", + scale=0.9, + color=(1, 1, 1)) + + destination_lang_menu = PopupMenu( + parent=self.root_widget, + position=(330 if uiscale is ba.UIScale.SMALL else 400, height - 170), + width=200, + scale=(2.8 if uiscale is ba.UIScale.SMALL else + 1.8 if uiscale is ba.UIScale.MEDIUM else 1.2), + current_choice=cfg['Translate Destination Language'], + choices=list(LANGUAGES.keys())[1:], + choices_display=list(ba.Lstr(value=i) for i in LANGUAGES.values())[1:], + button_size=(130, 35), + on_value_change_call=self._change_destination) + + try: + + translation_mode_text = ba.textwidget(parent=self.root_widget, + position=(40, height - 215), + size=(20, 20), + h_align='left', + v_align='center', + text="Translate Mode", + scale=0.9, + color=(1, 1, 1)) + decoration = ba.textwidget(parent=self.root_widget, + position=(40, height - 225), + size=(20, 20), + h_align='left', + v_align='center', + text="________________", + scale=0.9, + color=(1, 1, 1)) + + language_char_text = ba.textwidget(parent=self.root_widget, + position=(85, height - 273), + size=(20, 20), + h_align='left', + v_align='center', + text='Normal Translation', + scale=0.6, + color=(1, 1, 1)) + + pronunciation_text = ba.textwidget(parent=self.root_widget, + position=(295, height - 273), + size=(20, 20), + h_align='left', + v_align='center', + text="Show Prononciation", + scale=0.6, + color=(1, 1, 1)) + + from bastd.ui.radiogroup import make_radio_group + cur_val = ba.app.config.get('Pronunciation', True) + cb1 = ba.checkboxwidget( + parent=self.root_widget, + position=(250, height - 275), + size=(20, 20), + maxwidth=300, + scale=1, + autoselect=True, + text="") + cb2 = ba.checkboxwidget( + parent=self.root_widget, + position=(40, height - 275), + size=(20, 20), + maxwidth=300, + scale=1, + autoselect=True, + text="") + make_radio_group((cb1, cb2), (True, False), cur_val, + self._actions_changed) + except Exception as e: + print(e) + pass + + ba.containerwidget(edit=self.root_widget, cancel_button=btn) + + + def _change_source(self, choice): + cfg = ba.app.config + cfg['Translate Source Language'] = choice + cfg.apply_and_commit() + + def _change_destination(self, choice): + cfg = ba.app.config + cfg['Translate Destination Language'] = choice + cfg.apply_and_commit() + + def _actions_changed(self, v: str) -> None: + cfg = ba.app.config + cfg['Pronunciation'] = v + cfg.apply_and_commit() + + def _cancel(self) -> None: + ba.containerwidget(edit=self.root_widget, transition='out_scale') + SettingsWindow() + + +class SettingsWindow: + + def __init__(self): + uiscale = ba.app.ui.uiscale + height = (300 if uiscale is ba.UIScale.SMALL else + 350 if uiscale is ba.UIScale.MEDIUM else 400) + width = (500 if uiscale is ba.UIScale.SMALL else + 600 if uiscale is ba.UIScale.MEDIUM else 650) + scroll_h = (200 if uiscale is ba.UIScale.SMALL else + 250 if uiscale is ba.UIScale.MEDIUM else 270) + scroll_w = (450 if uiscale is ba.UIScale.SMALL else + 550 if uiscale is ba.UIScale.MEDIUM else 600) + self._transition_out: Optional[str] + scale_origin: Optional[Tuple[float, float]] + self._transition_out = 'out_scale' + scale_origin = 10 + transition = 'in_scale' + scale_origin = None + cancel_is_selected = False + cfg = ba.app.config + bg_color = cfg.get('PartyWindow Main Color', (0.5, 0.5, 0.5)) + + self.root_widget = ba.containerwidget( + size=(width, height), + color=bg_color, + transition=transition, + toolbar_visibility='menu_minimal_no_back', + parent=_ba.get_special_widget('overlay_stack'), + on_outside_click_call=self._cancel, + scale=(2.1 if uiscale is ba.UIScale.SMALL else + 1.5 if uiscale is ba.UIScale.MEDIUM else 1.0), + scale_origin_stack_offset=scale_origin) + ba.textwidget(parent=self.root_widget, + position=(width * 0.5, height - 45), + size=(20, 20), + h_align='center', + v_align='center', + text="Custom Settings", + scale=0.9, + color=(5, 5, 5)) + cbtn = btn = ba.buttonwidget(parent=self.root_widget, + autoselect=True, + position=(30, height - 60), + size=(30, 30), + label=ba.charstr(ba.SpecialChar.BACK), + button_type='backSmall', + on_activate_call=self._cancel) + scroll_position = (30 if uiscale is ba.UIScale.SMALL else + 40 if uiscale is ba.UIScale.MEDIUM else 50) + self._scrollwidget = ba.scrollwidget(parent=self.root_widget, + position=(30, scroll_position), + simple_culling_v=20.0, + highlight=False, + size=(scroll_w, scroll_h), + selection_loops_to_parent=True) + ba.widget(edit=self._scrollwidget, right_widget=self._scrollwidget) + self._subcontainer = ba.columnwidget(parent=self._scrollwidget, + selection_loops_to_parent=True) + ip_button = ba.checkboxwidget( + parent=self._subcontainer, + size=(300, 30), + maxwidth=300, + textcolor=((0, 1, 0) if cfg['IP button'] else (0.95, 0.65, 0)), + scale=1, + value=cfg['IP button'], + autoselect=True, + text="IP Button", + on_value_change_call=self.ip_button) + ping_button = ba.checkboxwidget( + parent=self._subcontainer, + size=(300, 30), + maxwidth=300, + textcolor=((0, 1, 0) if cfg['ping button'] else (0.95, 0.65, 0)), + scale=1, + value=cfg['ping button'], + autoselect=True, + text="Ping Button", + on_value_change_call=self.ping_button) + copy_button = ba.checkboxwidget( + parent=self._subcontainer, + size=(300, 30), + maxwidth=300, + textcolor=((0, 1, 0) if cfg['copy button'] else (0.95, 0.65, 0)), + scale=1, + value=cfg['copy button'], + autoselect=True, + text="Copy Text Button", + on_value_change_call=self.copy_button) + direct_send = ba.checkboxwidget( + parent=self._subcontainer, + size=(300, 30), + maxwidth=300, + textcolor=((0, 1, 0) if cfg['Direct Send'] else (0.95, 0.65, 0)), + scale=1, + value=cfg['Direct Send'], + autoselect=True, + text="Directly Send Custom Commands", + on_value_change_call=self.direct_send) + colorfulchat = ba.checkboxwidget( + parent=self._subcontainer, + size=(300, 30), + maxwidth=300, + textcolor=((0, 1, 0) if cfg['Colorful Chat'] else (0.95, 0.65, 0)), + scale=1, + value=cfg['Colorful Chat'], + autoselect=True, + text="Colorful Chat", + on_value_change_call=self.colorful_chat) + msg_notification_text = ba.textwidget(parent=self._subcontainer, + scale=0.8, + color=(1, 1, 1), + text='Message Notifcation:', + size=(100, 30), + h_align='left', + v_align='center') + msg_notification_widget = PopupMenu( + parent=self._subcontainer, + position=(100, height - 1200), + width=200, + scale=(2.8 if uiscale is ba.UIScale.SMALL else + 1.8 if uiscale is ba.UIScale.MEDIUM else 1.2), + choices=['top', 'bottom'], + current_choice=ba.app.config['Message Notification'], + button_size=(80, 25), + on_value_change_call=self._change_notification) + self_status_text = ba.textwidget(parent=self._subcontainer, + scale=0.8, + color=(1, 1, 1), + text='Self Status:', + size=(100, 30), + h_align='left', + v_align='center') + self_status_widget = PopupMenu( + parent=self._subcontainer, + position=(50, height - 1000), + width=200, + scale=(2.8 if uiscale is ba.UIScale.SMALL else + 1.8 if uiscale is ba.UIScale.MEDIUM else 1.2), + choices=['online', 'offline'], + current_choice=ba.app.config['Self Status'], + button_size=(80, 25), + on_value_change_call=self._change_status) + ba.containerwidget(edit=self.root_widget, cancel_button=btn) + ba.containerwidget(edit=self.root_widget, + selected_child=(cbtn if cbtn is not None + and cancel_is_selected else None), + start_button=None) + + self._translation_btn = ba.buttonwidget(parent=self._subcontainer, + scale=1.2, + position=(100, 1200), + size=(150, 50), + label='Translate Settings', + on_activate_call=self._translaton_btn, + autoselect=True) + + def ip_button(self, value: bool): + cfg = ba.app.config + cfg['IP button'] = value + cfg.apply_and_commit() + if cfg['IP button']: + ba.screenmessage("IP Button is now enabled", color=(0, 1, 0)) + else: + ba.screenmessage("IP Button is now disabled", color=(1, 0.7, 0)) + + def ping_button(self, value: bool): + cfg = ba.app.config + cfg['ping button'] = value + cfg.apply_and_commit() + if cfg['ping button']: + ba.screenmessage("Ping Button is now enabled", color=(0, 1, 0)) + else: + ba.screenmessage("Ping Button is now disabled", color=(1, 0.7, 0)) + + def copy_button(self, value: bool): + cfg = ba.app.config + cfg['copy button'] = value + cfg.apply_and_commit() + if cfg['copy button']: + ba.screenmessage("Copy Text Button is now enabled", color=(0, 1, 0)) + else: + ba.screenmessage("Copy Text Button is now disabled", color=(1, 0.7, 0)) + + def direct_send(self, value: bool): + cfg = ba.app.config + cfg['Direct Send'] = value + cfg.apply_and_commit() + + def colorful_chat(self, value: bool): + cfg = ba.app.config + cfg['Colorful Chat'] = value + cfg.apply_and_commit() + + def _change_notification(self, choice): + cfg = ba.app.config + cfg['Message Notification'] = choice + cfg.apply_and_commit() + + def _change_status(self, choice): + cfg = ba.app.config + cfg['Self Status'] = choice + cfg.apply_and_commit() + + def _translaton_btn(self): + try: + ba.containerwidget(edit=self.root_widget, transition='out_scale') + TranslationSettings() + except Exception as e: + print(e) + pass + + def _cancel(self) -> None: + ba.containerwidget(edit=self.root_widget, transition='out_scale') + + + +class PartyWindow(ba.Window): + """Party list/chat window.""" + + def __del__(self) -> None: + _ba.set_party_window_open(False) + + def __init__(self, origin: Sequence[float] = (0, 0)): + self._private_chat = False + self._firstcall = True + self.ping_server() + _ba.set_party_window_open(True) + self._r = 'partyWindow' + self._popup_type: Optional[str] = None + self._popup_party_member_client_id: Optional[int] = None + self._popup_party_member_is_host: Optional[bool] = None + self._width = 500 + uiscale = ba.app.ui.uiscale + self._height = (365 if uiscale is ba.UIScale.SMALL else + 480 if uiscale is ba.UIScale.MEDIUM else 600) + self.bg_color = ba.app.config.get('PartyWindow Main Color', (0.5, 0.5, 0.5)) + self.ping_timer = ba.Timer(5, ba.WeakCall(self.ping_server), repeat=True) + + ba.Window.__init__(self, root_widget=ba.containerwidget( + size=(self._width, self._height), + transition='in_scale', + color=self.bg_color, + parent=_ba.get_special_widget('overlay_stack'), + on_outside_click_call=self.close_with_sound, + scale_origin_stack_offset=origin, + scale=(2.0 if uiscale is ba.UIScale.SMALL else + 1.35 if uiscale is ba.UIScale.MEDIUM else 1.0), + stack_offset=(0, -10) if uiscale is ba.UIScale.SMALL else ( + 240, 0) if uiscale is ba.UIScale.MEDIUM else (330, 20))) + + self._cancel_button = ba.buttonwidget(parent=self._root_widget, + scale=0.7, + position=(30, self._height - 47), + size=(50, 50), + label='', + on_activate_call=self.close, + autoselect=True, + color=self.bg_color, + icon=ba.gettexture('crossOut'), + iconscale=1.2) + ba.containerwidget(edit=self._root_widget, + cancel_button=self._cancel_button) + + self._menu_button = ba.buttonwidget( + parent=self._root_widget, + scale=0.7, + position=(self._width - 80, self._height - 47), + size=(50, 50), + label='...', + autoselect=True, + button_type='square', + on_activate_call=ba.WeakCall(self._on_menu_button_press), + color=self.bg_color, + iconscale=1.2) + + info = _ba.get_connection_to_host_info() + if info.get('name', '') != '': + self.title = ba.Lstr(value=info['name']) + else: + self.title = ba.Lstr(resource=self._r + '.titleText') + + self._title_text = ba.textwidget(parent=self._root_widget, + scale=0.9, + color=(0.5, 0.7, 0.5), + text=self.title, + size=(0, 0), + position=(self._width * 0.47, + self._height - 29), + maxwidth=self._width * 0.6, + h_align='center', + v_align='center') + self._empty_str = ba.textwidget(parent=self._root_widget, + scale=0.75, + size=(0, 0), + position=(self._width * 0.5, + self._height - 65), + maxwidth=self._width * 0.85, + h_align='center', + v_align='center') + + self._scroll_width = self._width - 50 + self._scrollwidget = ba.scrollwidget(parent=self._root_widget, + size=(self._scroll_width, + self._height - 200), + position=(30, 80), + color=self.bg_color) + self._columnwidget = ba.columnwidget(parent=self._scrollwidget, + border=2, + margin=0) + ba.widget(edit=self._menu_button, down_widget=self._columnwidget) + + self._muted_text = ba.textwidget( + parent=self._root_widget, + position=(self._width * 0.5, self._height * 0.5), + size=(0, 0), + h_align='center', + v_align='center', + text=ba.Lstr(resource='chatMutedText')) + + self._text_field = txt = ba.textwidget( + parent=self._root_widget, + editable=True, + size=(500, 40), + position=(54, 39), + text='', + maxwidth=494, + shadow=0.3, + flatness=1.0, + description=ba.Lstr(resource=self._r + '.chatMessageText'), + autoselect=True, + v_align='center', + corner_scale=0.7) + + ba.widget(edit=self._scrollwidget, + autoselect=True, + left_widget=self._cancel_button, + up_widget=self._cancel_button, + down_widget=self._text_field) + ba.widget(edit=self._columnwidget, + autoselect=True, + up_widget=self._cancel_button, + down_widget=self._text_field) + ba.containerwidget(edit=self._root_widget, selected_child=txt) + self._send_button = btn = ba.buttonwidget(parent=self._root_widget, + size=(50, 35), + label=ba.Lstr(resource=self._r + '.sendText'), + button_type='square', + autoselect=True, + color=self.bg_color, + position=(self._width - 90, 35), + on_activate_call=self._send_chat_message) + ba.textwidget(edit=txt, on_return_press_call=btn.activate) + self._previous_button = ba.buttonwidget(parent=self._root_widget, + size=(30, 30), + label=ba.charstr(ba.SpecialChar.UP_ARROW), + button_type='square', + autoselect=True, + position=(15, 57), + color=self.bg_color, + scale=0.75, + on_activate_call=self._previous_message) + self._next_button = ba.buttonwidget(parent=self._root_widget, + size=(30, 30), + label=ba.charstr(ba.SpecialChar.DOWN_ARROW), + button_type='square', + autoselect=True, + color=self.bg_color, + scale=0.75, + position=(15, 28), + on_activate_call=self._next_message) + self._translate_button = ba.buttonwidget(parent=self._root_widget, + size=(55, 47), + label="Trans", + button_type='square', + autoselect=True, + color=self.bg_color, + scale=0.75, + position=(self._width - 28, 35), + on_activate_call=self._translate) + if ba.app.config['copy button']: + self._copy_button = ba.buttonwidget(parent=self._root_widget, + size=(15, 15), + label='©', + button_type='backSmall', + autoselect=True, + color=self.bg_color, + position=(self._width - 40, 80), + on_activate_call=self._copy_to_clipboard) + self._ping_button = None + if info.get('name', '') != '': + if ba.app.config['ping button']: + self._ping_button = ba.buttonwidget( + parent=self._root_widget, + scale=0.7, + position=(self._width - 538, self._height - 57), + size=(75, 75), + autoselect=True, + button_type='square', + label=f'{_ping}', + on_activate_call=self._send_ping, + color=self.bg_color, + text_scale=2.3, + iconscale=1.2) + if ba.app.config['IP button']: + self._ip_port_button = ba.buttonwidget(parent=self._root_widget, + size=(30, 30), + label='IP', + button_type='square', + autoselect=True, + color=self.bg_color, + position=(self._width - 530, self._height - 100), + on_activate_call=self._ip_port_msg) + self._settings_button = ba.buttonwidget(parent=self._root_widget, + size=(50, 50), + scale=0.5, + button_type='square', + autoselect=True, + color=self.bg_color, + position=(self._width - 40, self._height - 47), + on_activate_call=self._on_setting_button_press, + icon=ba.gettexture('settingsIcon'), + iconscale=1.2) + self._privatechat_button = ba.buttonwidget(parent=self._root_widget, + size=(50, 50), + scale=0.5, + button_type='square', + autoselect=True, + color=self.bg_color, + position=(self._width - 40, self._height - 80), + on_activate_call=self._on_privatechat_button_press, + icon=ba.gettexture('ouyaOButton'), + iconscale=1.2) + self._name_widgets: List[ba.Widget] = [] + self._roster: Optional[List[Dict[str, Any]]] = None + self._update_timer = ba.Timer(1.0, + ba.WeakCall(self._update), + repeat=True, + timetype=ba.TimeType.REAL) + self._update() + + def on_chat_message(self, msg: str, sent=None) -> None: + """Called when a new chat message comes through.""" + if ba.app.config['Party Chat Muted'] and not _ba.app.ui.party_window()._private_chat: + return + if sent: + self._add_msg(msg, sent) + else: + self._add_msg(msg) + + def _add_msg(self, msg: str, sent=None) -> None: + if ba.app.config['Colorful Chat']: + sender = msg.split(': ')[0] + color = color_tracker._get_sender_color(sender) if sender else (1, 1, 1) + else: + color = (1, 1, 1) + maxwidth = self._scroll_width * 0.94 + txt = ba.textwidget(parent=self._columnwidget, + text=msg, + h_align='left', + v_align='center', + size=(0, 13), + scale=0.55, + color=color, + maxwidth=maxwidth, + shadow=0.3, + flatness=1.0) + if sent: + ba.textwidget(edit=txt, size=(100, 15), + selectable=True, + click_activate=True, + on_activate_call=ba.Call(ba.screenmessage, f'Message sent: {_get_local_time(sent)}')) + self._chat_texts.append(txt) + if len(self._chat_texts) > 40: + first = self._chat_texts.pop(0) + first.delete() + ba.containerwidget(edit=self._columnwidget, visible_child=txt) + + def _on_menu_button_press(self) -> None: + is_muted = ba.app.config['Party Chat Muted'] + uiscale = ba.app.ui.uiscale + + choices = ['muteOption', 'modifyColor', 'addQuickReply', 'removeQuickReply', 'credits'] + choices_display = ['Mute Option', 'Modify Main Color', 'Add as Quick Reply', 'Remove a Quick Reply', 'Credits'] + + if hasattr(_ba.get_foreground_host_activity(), '_map'): + choices.append('manualCamera') + choices_display.append('Manual Camera') + + PopupMenuWindow( + position=self._menu_button.get_screen_space_center(), + color=self.bg_color, + scale=(2.3 if uiscale is ba.UIScale.SMALL else + 1.65 if uiscale is ba.UIScale.MEDIUM else 1.23), + choices=choices, + choices_display=self._create_baLstr_list(choices_display), + current_choice='muteOption', + delegate=self) + self._popup_type = 'menu' + + def _update(self) -> None: + if not self._private_chat: + _ba.set_party_window_open(True) + ba.textwidget(edit=self._title_text, text=self.title) + if self._firstcall: + if hasattr(self, '_status_text'): + self._status_text.delete() + self._roster = [] + self._firstcall = False + self._chat_texts: List[ba.Widget] = [] + if not ba.app.config['Party Chat Muted']: + msgs = _ba.get_chat_messages() + for msg in msgs: + self._add_msg(msg) + # update muted state + if ba.app.config['Party Chat Muted']: + ba.textwidget(edit=self._muted_text, color=(1, 1, 1, 0.3)) + # clear any chat texts we're showing + if self._chat_texts: + while self._chat_texts: + first = self._chat_texts.pop() + first.delete() + else: + ba.textwidget(edit=self._muted_text, color=(1, 1, 1, 0.0)) + if self._ping_button: + ba.buttonwidget(edit=self._ping_button, + label=f'{_ping}', + textcolor=self._get_ping_color()) + + # update roster section + roster = _ba.get_game_roster() + if roster != self._roster or self._firstcall: + + self._roster = roster + + # clear out old + for widget in self._name_widgets: + widget.delete() + self._name_widgets = [] + if not self._roster: + top_section_height = 60 + ba.textwidget(edit=self._empty_str, + text=ba.Lstr(resource=self._r + '.emptyText')) + ba.scrollwidget(edit=self._scrollwidget, + size=(self._width - 50, + self._height - top_section_height - 110), + position=(30, 80)) + else: + columns = 1 if len( + self._roster) == 1 else 2 if len(self._roster) == 2 else 3 + rows = int(math.ceil(float(len(self._roster)) / columns)) + c_width = (self._width * 0.9) / max(3, columns) + c_width_total = c_width * columns + c_height = 24 + c_height_total = c_height * rows + for y in range(rows): + for x in range(columns): + index = y * columns + x + if index < len(self._roster): + t_scale = 0.65 + pos = (self._width * 0.53 - c_width_total * 0.5 + + c_width * x - 23, + self._height - 65 - c_height * y - 15) + + # if there are players present for this client, use + # their names as a display string instead of the + # client spec-string + try: + if self._roster[index]['players']: + # if there's just one, use the full name; + # otherwise combine short names + if len(self._roster[index] + ['players']) == 1: + p_str = self._roster[index]['players'][ + 0]['name_full'] + else: + p_str = ('/'.join([ + entry['name'] for entry in + self._roster[index]['players'] + ])) + if len(p_str) > 25: + p_str = p_str[:25] + '...' + else: + p_str = self._roster[index][ + 'display_string'] + except Exception: + ba.print_exception( + 'Error calcing client name str.') + p_str = '???' + widget = ba.textwidget(parent=self._root_widget, + position=(pos[0], pos[1]), + scale=t_scale, + size=(c_width * 0.85, 30), + maxwidth=c_width * 0.85, + color=(1, 1, + 1) if index == 0 else + (1, 1, 1), + selectable=True, + autoselect=True, + click_activate=True, + text=ba.Lstr(value=p_str), + h_align='left', + v_align='center') + self._name_widgets.append(widget) + + # in newer versions client_id will be present and + # we can use that to determine who the host is. + # in older versions we assume the first client is + # host + if self._roster[index]['client_id'] is not None: + is_host = self._roster[index][ + 'client_id'] == -1 + else: + is_host = (index == 0) + + # FIXME: Should pass client_id to these sort of + # calls; not spec-string (perhaps should wait till + # client_id is more readily available though). + ba.textwidget(edit=widget, + on_activate_call=ba.Call( + self._on_party_member_press, + self._roster[index]['client_id'], + is_host, widget)) + pos = (self._width * 0.53 - c_width_total * 0.5 + + c_width * x, + self._height - 65 - c_height * y) + + # Make the assumption that the first roster + # entry is the server. + # FIXME: Shouldn't do this. + if is_host: + twd = min( + c_width * 0.85, + _ba.get_string_width( + p_str, suppress_warning=True) * + t_scale) + self._name_widgets.append( + ba.textwidget( + parent=self._root_widget, + position=(pos[0] + twd + 1, + pos[1] - 0.5), + size=(0, 0), + h_align='left', + v_align='center', + maxwidth=c_width * 0.96 - twd, + color=(0.1, 1, 0.1, 0.5), + text=ba.Lstr(resource=self._r + + '.hostText'), + scale=0.4, + shadow=0.1, + flatness=1.0)) + ba.textwidget(edit=self._empty_str, text='') + ba.scrollwidget(edit=self._scrollwidget, + size=(self._width - 50, + max(100, self._height - 139 - + c_height_total)), + position=(30, 80)) + else: + _ba.set_party_window_open(False) + for widget in self._name_widgets: + widget.delete() + self._name_widgets = [] + ba.textwidget(edit=self._title_text, text='Private Chat') + ba.textwidget(edit=self._empty_str, text='') + if self._firstcall: + self._firstcall = False + if hasattr(self, '_status_text'): + self._status_text.delete() + try: + msgs = messenger.pvt_msgs[messenger.filter] + except: + msgs = [] + if self._chat_texts: + while self._chat_texts: + first = self._chat_texts.pop() + first.delete() + uiscale = ba.app.ui.uiscale + scroll_height = (165 if uiscale is ba.UIScale.SMALL else + 280 if uiscale is ba.UIScale.MEDIUM else 400) + ba.scrollwidget(edit=self._scrollwidget, + size=(self._width - 50, scroll_height)) + for msg in msgs: + message = messenger._format_message(msg) + self._add_msg(message, msg['sent']) + self._filter_text = ba.textwidget(parent=self._root_widget, + scale=0.6, + color=(0.9, 1.0, 0.9), + text='Filter: ', + size=(0, 0), + position=(self._width * 0.3, + self._height - 70), + h_align='center', + v_align='center') + choices = [i for i in messenger.saved_ids] + choices_display = [ba.Lstr(value=messenger.saved_ids[i]) for i in messenger.saved_ids] + choices.append('add') + choices_display.append(ba.Lstr(value='***Add New***')) + filter_widget = PopupMenu( + parent=self._root_widget, + position=(self._width * 0.4, + self._height - 80), + width=200, + scale=(2.8 if uiscale is ba.UIScale.SMALL else + 1.8 if uiscale is ba.UIScale.MEDIUM else 1.2), + choices=choices, + choices_display=choices_display, + current_choice=messenger.filter, + button_size=(120, 30), + on_value_change_call=self._change_filter) + self._popup_button = filter_widget.get_button() + if messenger.filter != 'all': + user_status = messenger._get_status(messenger.filter) + if user_status == 'Offline': + color = (1, 0, 0) + elif user_status.startswith(('Playing in', 'in Lobby')): + color = (0, 1, 0) + else: + color = (0.9, 1.0, 0.9) + self._status_text = ba.textwidget(parent=self._root_widget, + scale=0.5, + color=color, + text=f'Status:\t{user_status}', + size=(200, 30), + position=(self._width * 0.3, + self._height - 110), + h_align='center', + v_align='center', + autoselect=True, + selectable=True, + click_activate=True) + ba.textwidget(edit=self._status_text, + on_activate_call=ba.Call(messenger._get_status, messenger.filter, 'last_seen')) + + def _change_filter(self, choice): + if choice == 'add': + self.close() + AddNewIdWindow() + else: + messenger.filter = choice + self._firstcall = True + self._filter_text.delete() + self._popup_button.delete() + if self._chat_texts: + while self._chat_texts: + first = self._chat_texts.pop() + first.delete() + self._update() + + def popup_menu_selected_choice(self, popup_window: PopupMenuWindow, + choice: str) -> None: + """Called when a choice is selected in the popup.""" + if self._popup_type == 'partyMemberPress': + playerinfo = self._get_player_info(self._popup_party_member_client_id) + if choice == 'kick': + name = playerinfo['ds'] + ConfirmWindow(text=f'Are you sure to kick {name}?', + action=self._vote_kick_player, + cancel_button=True, + cancel_is_selected=True, + color=self.bg_color, + text_scale=1.0, + origin_widget=self.get_root_widget()) + elif choice == 'mention': + players = playerinfo['players'] + choices = [] + namelist = [playerinfo['ds']] + for player in players: + name = player['name_full'] + if name not in namelist: + namelist.append(name) + choices_display = self._create_baLstr_list(namelist) + for i in namelist: + i = i.replace('"', '\"') + i = i.replace("'", "\'") + choices.append(f'self._edit_text_msg_box("{i}")') + PopupMenuWindow(position=popup_window.root_widget.get_screen_space_center(), + color=self.bg_color, + scale=self._get_popup_window_scale(), + choices=choices, + choices_display=choices_display, + current_choice=choices[0], + delegate=self) + self._popup_type = "executeChoice" + elif choice == 'adminkick': + name = playerinfo['ds'] + ConfirmWindow(text=f'Are you sure to use admin\ncommand to kick {name}', + action=self._send_admin_kick_command, + cancel_button=True, + cancel_is_selected=True, + color=self.bg_color, + text_scale=1.0, + origin_widget=self.get_root_widget()) + elif choice == 'customCommands': + choices = [] + choices_display = [] + playerinfo = self._get_player_info(self._popup_party_member_client_id) + account = playerinfo['ds'] + try: + name = playerinfo['players'][0]['name_full'] + except: + name = account + for i in ba.app.config.get('Custom Commands'): + i = i.replace('$c', str(self._popup_party_member_client_id)) + i = i.replace('$a', str(account)) + i = i.replace('$n', str(name)) + if ba.app.config['Direct Send']: + choices.append(f'_ba.chatmessage("{i}")') + else: + choices.append(f'self._edit_text_msg_box("{i}")') + choices_display.append(ba.Lstr(value=i)) + choices.append('AddNewChoiceWindow()') + choices_display.append(ba.Lstr(value='***Add New***')) + PopupMenuWindow(position=popup_window.root_widget.get_screen_space_center(), + color=self.bg_color, + scale=self._get_popup_window_scale(), + choices=choices, + choices_display=choices_display, + current_choice=choices[0], + delegate=self) + self._popup_type = 'executeChoice' + + elif choice == 'addNew': + AddNewChoiceWindow() + + elif self._popup_type == 'menu': + if choice == 'muteOption': + current_choice = self._get_current_mute_type() + PopupMenuWindow( + position=(self._width - 60, self._height - 47), + color=self.bg_color, + scale=self._get_popup_window_scale(), + choices=['muteInGameOnly', 'mutePartyWindowOnly', 'muteAll', 'unmuteAll'], + choices_display=self._create_baLstr_list( + ['Mute In Game Messages Only', 'Mute Party Window Messages Only', 'Mute all', 'Unmute All']), + current_choice=current_choice, + delegate=self + ) + self._popup_type = 'muteType' + elif choice == 'modifyColor': + ColorPickerExact(parent=self.get_root_widget(), + position=self.get_root_widget().get_screen_space_center(), + initial_color=self.bg_color, + delegate=self, tag='') + elif choice == 'addQuickReply': + try: + newReply = ba.textwidget(query=self._text_field) + oldReplies = self._get_quick_responds() + oldReplies.append(newReply) + self._write_quick_responds(oldReplies) + ba.screenmessage(f'"{newReply}" is added.', (0, 1, 0)) + ba.playsound(ba.getsound('dingSmallHigh')) + except: + ba.print_exception() + elif choice == 'removeQuickReply': + quick_reply = self._get_quick_responds() + PopupMenuWindow(position=self._send_button.get_screen_space_center(), + color=self.bg_color, + scale=self._get_popup_window_scale(), + choices=quick_reply, + choices_display=self._create_baLstr_list(quick_reply), + current_choice=quick_reply[0], + delegate=self) + self._popup_type = 'removeQuickReplySelect' + elif choice == 'credits': + ConfirmWindow( + text=u'\ue043Party Window Reloaded V3\ue043\n\nCredits - Droopy#3730\nSpecial Thanks - BoTT-Vishah#4150', + action=self.join_discord, + width=420, + height=230, + color=self.bg_color, + text_scale=1.0, + ok_text="Join Discord", + origin_widget=self.get_root_widget()) + elif choice == 'manualCamera': + ba.containerwidget(edit=self._root_widget, transition='out_scale') + Manual_camera_window() + + elif self._popup_type == 'muteType': + self._change_mute_type(choice) + + elif self._popup_type == 'executeChoice': + exec(choice) + + elif self._popup_type == 'quickMessage': + if choice == '*** EDIT ORDER ***': + SortQuickMessages() + else: + self._edit_text_msg_box(choice) + + elif self._popup_type == 'removeQuickReplySelect': + data = self._get_quick_responds() + data.remove(choice) + self._write_quick_responds(data) + ba.screenmessage(f'"{choice}" is removed.', (1, 0, 0)) + ba.playsound(ba.getsound('shieldDown')) + + else: + print(f'unhandled popup type: {self._popup_type}') + del popup_window # unused + + def _vote_kick_player(self): + if self._popup_party_member_is_host: + ba.playsound(ba.getsound('error')) + ba.screenmessage( + ba.Lstr(resource='internal.cantKickHostError'), + color=(1, 0, 0)) + else: + assert self._popup_party_member_client_id is not None + + # Ban for 5 minutes. + result = _ba.disconnect_client( + self._popup_party_member_client_id, ban_time=5 * 60) + if not result: + ba.playsound(ba.getsound('error')) + ba.screenmessage( + ba.Lstr(resource='getTicketsWindow.unavailableText'), + color=(1, 0, 0)) + + def _send_admin_kick_command(self): + _ba.chatmessage('/kick ' + str(self._popup_party_member_client_id)) + + def _translate(self): + def _apply_translation(translated): + if self._text_field.exists(): + ba.textwidget(edit=self._text_field, text=translated) + msg = ba.textwidget(query=self._text_field) + cfg = ba.app.config + if msg == '': + ba.screenmessage('Nothing to translate.', (1, 0, 0)) + ba.playsound(ba.getsound('error')) + else: + data = dict(message=msg) + if cfg['Translate Source Language']: + data['src'] = cfg['Translate Source Language'] + if cfg['Translate Destination Language']: + data['dest'] = cfg['Translate Destination Language'] + if cfg['Pronunciation']: + data['type'] = 'pronunciation' + Translate(data, _apply_translation).start() + + + def _copy_to_clipboard(self): + msg = ba.textwidget(query=self._text_field) + if msg == '': + ba.screenmessage('Nothing to copy.', (1, 0, 0)) + ba.playsound(ba.getsound('error')) + else: + ba.clipboard_set_text(msg) + ba.screenmessage(f'"{msg}" is copied to clipboard.', (0, 1, 0)) + ba.playsound(ba.getsound('dingSmallHigh')) + + def _get_current_mute_type(self): + cfg = ba.app.config + if cfg['Chat Muted'] == True: + if cfg['Party Chat Muted'] == True: + return 'muteAll' + else: + return 'muteInGameOnly' + else: + if cfg['Party Chat Muted'] == True: + return 'mutePartyWindowOnly' + else: + return 'unmuteAll' + + def _change_mute_type(self, choice): + cfg = ba.app.config + if choice == 'muteInGameOnly': + cfg['Chat Muted'] = True + cfg['Party Chat Muted'] = False + elif choice == 'mutePartyWindowOnly': + cfg['Chat Muted'] = False + cfg['Party Chat Muted'] = True + elif choice == 'muteAll': + cfg['Chat Muted'] = True + cfg['Party Chat Muted'] = True + else: + cfg['Chat Muted'] = False + cfg['Party Chat Muted'] = False + cfg.apply_and_commit() + self._update() + + def popup_menu_closing(self, popup_window: PopupWindow) -> None: + """Called when the popup is closing.""" + + def _on_party_member_press(self, client_id: int, is_host: bool, + widget: ba.Widget) -> None: + # if we're the host, pop up 'kick' options for all non-host members + if _ba.get_foreground_host_session() is not None: + kick_str = ba.Lstr(resource='kickText') + else: + # kick-votes appeared in build 14248 + if (_ba.get_connection_to_host_info().get('build_number', 0) < + 14248): + return + kick_str = ba.Lstr(resource='kickVoteText') + uiscale = ba.app.ui.uiscale + choices = ['kick', 'mention', 'adminkick'] + choices_display = [kick_str] + list(self._create_baLstr_list(['Mention this guy', f'Kick ID: {client_id}'])) + choices.append('customCommands') + choices_display.append(ba.Lstr(value='Custom Commands')) + PopupMenuWindow( + position=widget.get_screen_space_center(), + color=self.bg_color, + scale=(2.3 if uiscale is ba.UIScale.SMALL else + 1.65 if uiscale is ba.UIScale.MEDIUM else 1.23), + choices=choices, + choices_display=choices_display, + current_choice='mention', + delegate=self) + self._popup_type = 'partyMemberPress' + self._popup_party_member_client_id = client_id + self._popup_party_member_is_host = is_host + + def _send_chat_message(self) -> None: + msg = ba.textwidget(query=self._text_field) + ba.textwidget(edit=self._text_field, text='') + if '\\' in msg: + msg = msg.replace('\\d', ('\ue048')) + msg = msg.replace('\\c', ('\ue043')) + msg = msg.replace('\\h', ('\ue049')) + msg = msg.replace('\\s', ('\ue046')) + msg = msg.replace('\\n', ('\ue04b')) + msg = msg.replace('\\f', ('\ue04f')) + msg = msg.replace('\\g', ('\ue027')) + msg = msg.replace('\\i', ('\ue03a')) + msg = msg.replace('\\m', ('\ue04d')) + msg = msg.replace('\\t', ('\ue01f')) + msg = msg.replace('\\bs', ('\ue01e')) + msg = msg.replace('\\j', ('\ue010')) + msg = msg.replace('\\e', ('\ue045')) + msg = msg.replace('\\l', ('\ue047')) + msg = msg.replace('\\a', ('\ue020')) + msg = msg.replace('\\b', ('\ue00c')) + if not msg: + choices = self._get_quick_responds() + choices.append('*** EDIT ORDER ***') + PopupMenuWindow(position=self._send_button.get_screen_space_center(), + scale=self._get_popup_window_scale(), + color=self.bg_color, + choices=choices, + current_choice=choices[0], + delegate=self) + self._popup_type = 'quickMessage' + return + elif msg.startswith('/info '): + account = msg.replace('/info ', '') + if account: + from bastd.ui.account import viewer + viewer.AccountViewerWindow( + account_id=account) + ba.textwidget(edit=self._text_field, text='') + return + if not self._private_chat: + if msg == '/id': + myid = ba.internal.get_v1_account_misc_read_val_2('resolvedAccountID', '') + _ba.chatmessage(f"My Unique ID : {myid}") + elif msg == '/save': + info = _ba.get_connection_to_host_info() + config = ba.app.config + if info.get('name', '') != '': + title = info['name'] + if not isinstance(config.get('Saved Servers'), dict): + config['Saved Servers'] = {} + config['Saved Servers'][f'{_ip}@{_port}'] = { + 'addr': _ip, + 'port': _port, + 'name': title + } + config.commit() + ba.screenmessage("Server Added To Manual", color=(0, 1, 0), transient=True) + ba.playsound(ba.getsound('gunCocking')) + elif msg != '': + _ba.chatmessage(cast(str, msg)) + else: + receiver = messenger.filter + name = ba.internal.get_v1_account_display_string() + if not receiver: + display_error('Choose a valid receiver id') + return + data = {'receiver': receiver, 'message': f'{name}: {msg}'} + if msg.startswith('/rename '): + if messenger.filter != 'all': + nickname = msg.replace('/rename ', '') + messenger._save_id(messenger.filter, nickname, verify=False) + self._change_filter(messenger.filter) + elif msg == '/remove': + if messenger.filter != 'all': + messenger._remove_id(messenger.filter) + self._change_filter('all') + else: + display_error('Cant delete this') + ba.textwidget(edit=self._text_field, text='') + return + ba.Call(messenger._send_request, url, data) + ba.Call(check_new_message) + Thread(target=messenger._send_request, args=(url, data)).start() + Thread(target=check_new_message).start() + ba.textwidget(edit=self._text_field, text='') + + + def _write_quick_responds(self, data): + try: + with open(quick_msg_file, 'w') as f: + f.write('\n'.join(data)) + except: + ba.print_exception() + ba.screenmessage('Error!', (1, 0, 0)) + ba.playsound(ba.getsound('error')) + + def _get_quick_responds(self): + if os.path.exists(quick_msg_file): + with open(quick_msg_file, 'r') as f: + return f.read().split('\n') + else: + default_replies = ['What the hell?', 'Dude that\'s amazing!'] + self._write_quick_responds(default_replies) + return default_replies + + def color_picker_selected_color(self, picker, color) -> None: + ba.containerwidget(edit=self._root_widget, color=color) + color = tuple(round(i, 2) for i in color) + self.bg_color = color + ba.app.config['PartyWindow Main Color'] = color + + def color_picker_closing(self, picker) -> None: + ba.app.config.apply_and_commit() + + def _remove_sender_from_message(self, msg=''): + msg_start = msg.find(": ") + 2 + return msg[msg_start:] + + def _previous_message(self): + msgs = self._chat_texts + if not hasattr(self, 'msg_index'): + self.msg_index = len(msgs) - 1 + else: + if self.msg_index > 0: + self.msg_index -= 1 + else: + del self.msg_index + try: + msg_widget = msgs[self.msg_index] + msg = ba.textwidget(query=msg_widget) + msg = self._remove_sender_from_message(msg) + if msg in ('', ' '): + self._previous_message() + return + except: + msg = '' + self._edit_text_msg_box(msg, 'replace') + + def _next_message(self): + msgs = self._chat_texts + if not hasattr(self, 'msg_index'): + self.msg_index = 0 + else: + if self.msg_index < len(msgs) - 1: + self.msg_index += 1 + else: + del self.msg_index + try: + msg_widget = msgs[self.msg_index] + msg = ba.textwidget(query=msg_widget) + msg = self._remove_sender_from_message(msg) + if msg in ('', ' '): + self._next_message() + return + except: + msg = '' + self._edit_text_msg_box(msg, 'replace') + + def _ip_port_msg(self): + try: + msg = f'IP : {_ip} PORT : {_port}' + except: + msg = '' + self._edit_text_msg_box(msg, 'replace') + + def ping_server(self): + info = _ba.get_connection_to_host_info() + if info.get('name', '') != '': + self.pingThread = PingThread(_ip, _port) + self.pingThread.start() + + def _get_ping_color(self): + try: + if _ping < 100: + return (0, 1, 0) + elif _ping < 500: + return (1, 1, 0) + else: + return (1, 0, 0) + except: + return (0.1, 0.1, 0.1) + + def _send_ping(self): + if isinstance(_ping, int): + _ba.chatmessage(f'My ping = {_ping}ms') + + def close(self) -> None: + """Close the window.""" + ba.containerwidget(edit=self._root_widget, transition='out_scale') + + def close_with_sound(self) -> None: + """Close the window and make a lovely sound.""" + ba.playsound(ba.getsound('swish')) + self.close() + + def _get_popup_window_scale(self) -> float: + uiscale = ba.app.ui.uiscale + return (2.4 if uiscale is ba.UIScale.SMALL else + 1.5 if uiscale is ba.UIScale.MEDIUM else 1.0) + + def _create_baLstr_list(self, list1): + return (ba.Lstr(value=i) for i in list1) + + def _get_player_info(self, clientID): + info = {} + for i in _ba.get_game_roster(): + if i['client_id'] == clientID: + info['ds'] = i['display_string'] + info['players'] = i['players'] + info['aid'] = i['account_id'] + break + return info + + def _edit_text_msg_box(self, text, action='add'): + if isinstance(text, str): + if action == 'add': + ba.textwidget(edit=self._text_field, text=ba.textwidget(query=self._text_field) + text) + elif action == 'replace': + ba.textwidget(edit=self._text_field, text=text) + + def _on_setting_button_press(self): + try: + SettingsWindow() + except Exception as e: + ba.print_exception() + pass + + def _on_privatechat_button_press(self): + try: + if messenger.logged_in: + self._firstcall = True + if self._chat_texts: + while self._chat_texts: + first = self._chat_texts.pop() + first.delete() + if not self._private_chat: + self._private_chat = True + else: + self._filter_text.delete() + self._popup_button.delete() + self._private_chat = False + self._update() + else: + if messenger.server_online: + if not messenger._cookie_login(): + if messenger._query(): + LoginWindow(wtype='login') + else: + LoginWindow(wtype='signup') + else: + display_error(messenger.error) + except Exception as e: + ba.print_exception() + pass + + def join_discord(self): + ba.open_url("https://discord.gg/KvYgpEg2JR") + + +class LoginWindow: + def __init__(self, wtype): + self.wtype = wtype + if self.wtype == 'signup': + title = 'Sign Up Window' + label = 'Sign Up' + else: + title = 'Login Window' + label = 'Log In' + uiscale = ba.app.ui.uiscale + bg_color = ba.app.config.get('PartyWindow Main Color', (0.5, 0.5, 0.5)) + self._root_widget = ba.containerwidget(size=(500, 250), + transition='in_scale', + color=bg_color, + toolbar_visibility='menu_minimal_no_back', + parent=_ba.get_special_widget('overlay_stack'), + on_outside_click_call=self._close, + scale=(2.1 if uiscale is ba.UIScale.SMALL else + 1.5 if uiscale is ba.UIScale.MEDIUM else 1.0), + stack_offset=(0, -10) if uiscale is ba.UIScale.SMALL else ( + 240, 0) if uiscale is ba.UIScale.MEDIUM else (330, 20)) + self._title_text = ba.textwidget(parent=self._root_widget, + scale=0.8, + color=(1, 1, 1), + text=title, + size=(0, 0), + position=(250, 200), + h_align='center', + v_align='center') + self._id = ba.textwidget(parent=self._root_widget, + scale=0.5, + color=(1, 1, 1), + text=f'Account: ' + ba.internal.get_v1_account_misc_read_val_2('resolvedAccountID', ''), + size=(0, 0), + position=(220, 170), + h_align='center', + v_align='center') + self._registrationkey_text = ba.textwidget(parent=self._root_widget, + scale=0.5, + color=(1, 1, 1), + text=f'Registration Key:', + size=(0, 0), + position=(100, 140), + h_align='center', + v_align='center') + self._text_field = ba.textwidget( + parent=self._root_widget, + editable=True, + size=(200, 40), + position=(175, 130), + text='', + maxwidth=410, + flatness=1.0, + autoselect=True, + v_align='center', + corner_scale=0.7) + self._connect_button = ba.buttonwidget(parent=self._root_widget, + size=(150, 30), + color=(0, 1, 0), + label='Get Registration Key', + button_type='square', + autoselect=True, + position=(150, 80), + on_activate_call=self._connect) + self._confirm_button = ba.buttonwidget(parent=self._root_widget, + size=(50, 30), + label=label, + button_type='square', + autoselect=True, + position=(200, 40), + on_activate_call=self._confirmcall) + ba.textwidget(edit=self._text_field, on_return_press_call=self._confirm_button.activate) + + def _close(self): + ba.containerwidget(edit=self._root_widget, + transition=('out_scale')) + + def _connect(self): + try: + host = url.split('http://')[1].split(':')[0] + import socket + address = socket.gethostbyname(host) + _ba.disconnect_from_host() + _ba.connect_to_party(address, port=11111) + except Exception: + display_error('Cant get ip from hostname') + + def _confirmcall(self): + if self.wtype == 'signup': + key = ba.textwidget(query=self._text_field) + answer = messenger._signup(registration_key=key) if key else None + if answer: + self._close() + else: + if messenger._login(registration_key=ba.textwidget(query=self._text_field)): + self._close() + + +class AddNewIdWindow: + def __init__(self): + uiscale = ba.app.ui.uiscale + bg_color = ba.app.config.get('PartyWindow Main Color', (0.5, 0.5, 0.5)) + self._root_widget = ba.containerwidget(size=(500, 250), + transition='in_scale', + color=bg_color, + toolbar_visibility='menu_minimal_no_back', + parent=_ba.get_special_widget('overlay_stack'), + on_outside_click_call=self._close, + scale=(2.1 if uiscale is ba.UIScale.SMALL else + 1.5 if uiscale is ba.UIScale.MEDIUM else 1.0)) + self._title_text = ba.textwidget(parent=self._root_widget, + scale=0.8, + color=(1, 1, 1), + text='Add New ID', + size=(0, 0), + position=(250, 200), + h_align='center', + v_align='center') + self._accountid_text = ba.textwidget(parent=self._root_widget, + scale=0.6, + color=(1, 1, 1), + text='pb-id: ', + size=(0, 0), + position=(50, 155), + h_align='center', + v_align='center') + self._accountid_field = ba.textwidget( + parent=self._root_widget, + editable=True, + size=(250, 40), + position=(100, 140), + text='', + maxwidth=410, + flatness=1.0, + autoselect=True, + v_align='center', + corner_scale=0.7) + self._nickname_text = ba.textwidget(parent=self._root_widget, + scale=0.5, + color=(1, 1, 1), + text='Nickname: ', + size=(0, 0), + position=(50, 115), + h_align='center', + v_align='center') + self._nickname_field = ba.textwidget( + parent=self._root_widget, + editable=True, + size=(250, 40), + position=(100, 100), + text='', + maxwidth=410, + flatness=1.0, + autoselect=True, + v_align='center', + corner_scale=0.7) + self._help_text = ba.textwidget(parent=self._root_widget, + scale=0.4, + color=(0.1, 0.9, 0.9), + text='Help:\nEnter pb-id of account you\n want to chat to\nEnter nickname of id to\n recognize id easily\nLeave nickname \n to use their default name', + size=(0, 0), + position=(325, 120), + h_align='left', + v_align='center') + self._add = ba.buttonwidget(parent=self._root_widget, + size=(50, 30), + label='Add', + button_type='square', + autoselect=True, + position=(100, 50), + on_activate_call=ba.Call(self._relay_function)) + ba.textwidget(edit=self._accountid_field, on_return_press_call=self._add.activate) + self._remove = ba.buttonwidget(parent=self._root_widget, + size=(75, 30), + label='Remove', + button_type='square', + autoselect=True, + position=(170, 50), + on_activate_call=self._remove_id) + ba.containerwidget(edit=self._root_widget, + on_cancel_call=self._close) + + def _relay_function(self): + account_id = ba.textwidget(query=self._accountid_field) + nickname = ba.textwidget(query=self._nickname_field) + try: + if messenger._save_id(account_id, nickname): + self._close() + except: + display_error('Enter valid pb-id') + + def _remove_id(self): + uiscale = ba.app.ui.uiscale + if len(messenger.saved_ids) > 1: + choices = [i for i in messenger.saved_ids] + choices.remove('all') + choices_display = [ba.Lstr(value=messenger.saved_ids[i]) for i in choices] + PopupMenuWindow(position=self._remove.get_screen_space_center(), + color=ba.app.config.get('PartyWindow Main Color', (0.5, 0.5, 0.5)), + scale=(2.4 if uiscale is ba.UIScale.SMALL else + 1.5 if uiscale is ba.UIScale.MEDIUM else 1.0), + choices=choices, + choices_display=choices_display, + current_choice=choices[0], + delegate=self) + self._popup_type = 'removeSelectedID' + + def popup_menu_selected_choice(self, popup_window: PopupMenuWindow, + choice: str) -> None: + """Called when a choice is selected in the popup.""" + if self._popup_type == 'removeSelectedID': + messenger._remove_id(choice) + self._close() + + def popup_menu_closing(self, popup_window: PopupWindow) -> None: + """Called when the popup is closing.""" + + def _close(self): + ba.containerwidget(edit=self._root_widget, + transition=('out_scale')) + + +class AddNewChoiceWindow: + def __init__(self): + uiscale = ba.app.ui.uiscale + bg_color = ba.app.config.get('PartyWindow Main Color', (0.5, 0.5, 0.5)) + self._root_widget = ba.containerwidget(size=(500, 250), + transition='in_scale', + color=bg_color, + toolbar_visibility='menu_minimal_no_back', + parent=_ba.get_special_widget('overlay_stack'), + on_outside_click_call=self._close, + scale=(2.1 if uiscale is ba.UIScale.SMALL else + 1.5 if uiscale is ba.UIScale.MEDIUM else 1.0), + stack_offset=(0, -10) if uiscale is ba.UIScale.SMALL else ( + 240, 0) if uiscale is ba.UIScale.MEDIUM else (330, 20)) + self._title_text = ba.textwidget(parent=self._root_widget, + scale=0.8, + color=(1, 1, 1), + text='Add Custom Command', + size=(0, 0), + position=(250, 200), + h_align='center', + v_align='center') + self._text_field = ba.textwidget( + parent=self._root_widget, + editable=True, + size=(500, 40), + position=(75, 140), + text='', + maxwidth=410, + flatness=1.0, + autoselect=True, + v_align='center', + corner_scale=0.7) + self._help_text = ba.textwidget(parent=self._root_widget, + scale=0.4, + color=(0.2, 0.2, 0.2), + text='Use\n$c = client id\n$a = account id\n$n = name', + size=(0, 0), + position=(70, 75), + h_align='left', + v_align='center') + self._add = ba.buttonwidget(parent=self._root_widget, + size=(50, 30), + label='Add', + button_type='square', + autoselect=True, + position=(150, 50), + on_activate_call=self._add_choice) + ba.textwidget(edit=self._text_field, on_return_press_call=self._add.activate) + self._remove = ba.buttonwidget(parent=self._root_widget, + size=(50, 30), + label='Remove', + button_type='square', + autoselect=True, + position=(350, 50), + on_activate_call=self._remove_custom_command) + ba.containerwidget(edit=self._root_widget, + on_cancel_call=self._close) + + def _add_choice(self): + newCommand = ba.textwidget(query=self._text_field) + cfg = ba.app.config + if any(i in newCommand for i in ('$c', '$a', '$n')): + cfg['Custom Commands'].append(newCommand) + cfg.apply_and_commit() + ba.screenmessage('Added successfully', (0, 1, 0)) + ba.playsound(ba.getsound('dingSmallHigh')) + self._close() + else: + ba.screenmessage('Use at least of these ($c, $a, $n)', (1, 0, 0)) + ba.playsound(ba.getsound('error')) + + def _remove_custom_command(self): + uiscale = ba.app.ui.uiscale + commands = ba.app.config['Custom Commands'] + PopupMenuWindow(position=self._remove.get_screen_space_center(), + color=ba.app.config.get('PartyWindow Main Color', (0.5, 0.5, 0.5)), + scale=(2.4 if uiscale is ba.UIScale.SMALL else + 1.5 if uiscale is ba.UIScale.MEDIUM else 1.0), + choices=commands, + current_choice=commands[0], + delegate=self) + self._popup_type = 'removeCustomCommandSelect' + + def popup_menu_selected_choice(self, popup_window: PopupMenuWindow, + choice: str) -> None: + """Called when a choice is selected in the popup.""" + if self._popup_type == 'removeCustomCommandSelect': + config = ba.app.config + config['Custom Commands'].remove(choice) + config.apply_and_commit() + ba.screenmessage('Removed successfully', (0, 1, 0)) + ba.playsound(ba.getsound('shieldDown')) + + def popup_menu_closing(self, popup_window: PopupWindow) -> None: + """Called when the popup is closing.""" + + def _close(self): + ba.containerwidget(edit=self._root_widget, + transition=('out_scale')) + + +class Manual_camera_window: + def __init__(self): + self._root_widget = ba.containerwidget( + on_outside_click_call=None, + size=(0, 0)) + button_size = (30, 30) + self._title_text = ba.textwidget(parent=self._root_widget, + scale=0.9, + color=(1, 1, 1), + text='Manual Camera Setup', + size=(0, 0), + position=(130, 153), + h_align='center', + v_align='center') + self._xminus = ba.buttonwidget(parent=self._root_widget, + size=button_size, + label=ba.charstr(ba.SpecialChar.LEFT_ARROW), + button_type='square', + autoselect=True, + position=(1, 60), + on_activate_call=ba.Call(self._change_camera_position, 'x-')) + self._xplus = ba.buttonwidget(parent=self._root_widget, + size=button_size, + label=ba.charstr(ba.SpecialChar.RIGHT_ARROW), + button_type='square', + autoselect=True, + position=(60, 60), + on_activate_call=ba.Call(self._change_camera_position, 'x')) + self._yplus = ba.buttonwidget(parent=self._root_widget, + size=button_size, + label=ba.charstr(ba.SpecialChar.UP_ARROW), + button_type='square', + autoselect=True, + position=(30, 100), + on_activate_call=ba.Call(self._change_camera_position, 'y')) + self._yminus = ba.buttonwidget(parent=self._root_widget, + size=button_size, + label=ba.charstr(ba.SpecialChar.DOWN_ARROW), + button_type='square', + autoselect=True, + position=(30, 20), + on_activate_call=ba.Call(self._change_camera_position, 'y-')) + self.inwards = ba.buttonwidget(parent=self._root_widget, + size=(100, 30), + label='INWARDS', + button_type='square', + autoselect=True, + position=(120, 90), + on_activate_call=ba.Call(self._change_camera_position, 'z-')) + self._outwards = ba.buttonwidget(parent=self._root_widget, + size=(100, 30), + label='OUTWARDS', + button_type='square', + autoselect=True, + position=(120, 50), + on_activate_call=ba.Call(self._change_camera_position, 'z')) + self._step_text = ba.textwidget(parent=self._root_widget, + scale=0.5, + color=(1, 1, 1), + text='Step:', + size=(0, 0), + position=(1, -20), + h_align='center', + v_align='center') + self._text_field = ba.textwidget( + parent=self._root_widget, + editable=True, + size=(100, 40), + position=(26, -35), + text='', + maxwidth=120, + flatness=1.0, + autoselect=True, + v_align='center', + corner_scale=0.7) + self._reset = ba.buttonwidget(parent=self._root_widget, + size=(50, 30), + label='Reset', + button_type='square', + autoselect=True, + position=(120, -35), + on_activate_call=ba.Call(self._change_camera_position, 'reset')) + self._done = ba.buttonwidget(parent=self._root_widget, + size=(50, 30), + label='Done', + button_type='square', + autoselect=True, + position=(180, -35), + on_activate_call=self._close) + ba.containerwidget(edit=self._root_widget, + cancel_button=self._done) + + def _close(self): + ba.containerwidget(edit=self._root_widget, + transition=('out_scale')) + + def _change_camera_position(self, direction): + activity = _ba.get_foreground_host_activity() + node = activity.globalsnode + aoi = list(node.area_of_interest_bounds) + center = [(aoi[0] + aoi[3]) / 2, + (aoi[1] + aoi[4]) / 2, + (aoi[2] + aoi[5]) / 2] + size = (aoi[3] - aoi[0], + aoi[4] - aoi[1], + aoi[5] - aoi[2]) + + try: + increment = float(ba.textwidget(query=self._text_field)) + except: + # ba.print_exception() + increment = 1 + + if direction == 'x': + center[0] += increment + elif direction == 'x-': + center[0] -= increment + elif direction == 'y': + center[1] += increment + elif direction == 'y-': + center[1] -= increment + elif direction == 'z': + center[2] += increment + elif direction == 'z-': + center[2] -= increment + elif direction == 'reset': + node.area_of_interest_bounds = activity._map.get_def_bound_box('area_of_interest_bounds') + return + + aoi = (center[0] - size[0] / 2, + center[1] - size[1] / 2, + center[2] - size[2] / 2, + center[0] + size[0] / 2, + center[1] + size[1] / 2, + center[2] + size[2] / 2) + node.area_of_interest_bounds = tuple(aoi) + + +def __popup_menu_window_init__(self, + position: Tuple[float, float], + choices: Sequence[str], + current_choice: str, + delegate: Any = None, + width: float = 230.0, + maxwidth: float = None, + scale: float = 1.0, + color: Tuple[float, float, float] = (0.35, 0.55, 0.15), + choices_disabled: Sequence[str] = None, + choices_display: Sequence[ba.Lstr] = None): + # FIXME: Clean up a bit. + # pylint: disable=too-many-branches + # pylint: disable=too-many-locals + # pylint: disable=too-many-statements + if choices_disabled is None: + choices_disabled = [] + if choices_display is None: + choices_display = [] + + # FIXME: For the moment we base our width on these strings so + # we need to flatten them. + choices_display_fin: List[str] = [] + for choice_display in choices_display: + choices_display_fin.append(choice_display.evaluate()) + + if maxwidth is None: + maxwidth = width * 1.5 + + self._transitioning_out = False + self._choices = list(choices) + self._choices_display = list(choices_display_fin) + self._current_choice = current_choice + self._color = color + self._choices_disabled = list(choices_disabled) + self._done_building = False + if not choices: + raise TypeError('Must pass at least one choice') + self._width = width + self._scale = scale + if len(choices) > 8: + self._height = 280 + self._use_scroll = True + else: + self._height = 20 + len(choices) * 33 + self._use_scroll = False + self._delegate = None # don't want this stuff called just yet.. + + # extend width to fit our longest string (or our max-width) + for index, choice in enumerate(choices): + if len(choices_display_fin) == len(choices): + choice_display_name = choices_display_fin[index] + else: + choice_display_name = choice + if self._use_scroll: + self._width = max( + self._width, + min( + maxwidth, + _ba.get_string_width(choice_display_name, + suppress_warning=True)) + 75) + else: + self._width = max( + self._width, + min( + maxwidth, + _ba.get_string_width(choice_display_name, + suppress_warning=True)) + 60) + + # init parent class - this will rescale and reposition things as + # needed and create our root widget + PopupWindow.__init__(self, + position, + size=(self._width, self._height), + bg_color=self._color, + scale=self._scale) + + if self._use_scroll: + self._scrollwidget = ba.scrollwidget(parent=self.root_widget, + position=(20, 20), + highlight=False, + color=(0.35, 0.55, 0.15), + size=(self._width - 40, + self._height - 40)) + self._columnwidget = ba.columnwidget(parent=self._scrollwidget, + border=2, + margin=0) + else: + self._offset_widget = ba.containerwidget(parent=self.root_widget, + position=(30, 15), + size=(self._width - 40, + self._height), + background=False) + self._columnwidget = ba.columnwidget(parent=self._offset_widget, + border=2, + margin=0) + for index, choice in enumerate(choices): + if len(choices_display_fin) == len(choices): + choice_display_name = choices_display_fin[index] + else: + choice_display_name = choice + inactive = (choice in self._choices_disabled) + wdg = ba.textwidget(parent=self._columnwidget, + size=(self._width - 40, 28), + on_select_call=ba.Call(self._select, index), + click_activate=True, + color=(0.5, 0.5, 0.5, 0.5) if inactive else + ((0.5, 1, 0.5, + 1) if choice == self._current_choice else + (0.8, 0.8, 0.8, 1.0)), + padding=0, + maxwidth=maxwidth, + text=choice_display_name, + on_activate_call=self._activate, + v_align='center', + selectable=(not inactive)) + if choice == self._current_choice: + ba.containerwidget(edit=self._columnwidget, + selected_child=wdg, + visible_child=wdg) + + # ok from now on our delegate can be called + self._delegate = weakref.ref(delegate) + self._done_building = True + + +original_connect_to_party = _ba.connect_to_party +original_sign_in = ba.internal.sign_in_v1 + + +def modify_connect_to_party(address: str, port: int = 43210, print_progress: bool = True) -> None: + global _ip, _port + _ip = address + _port = port + original_connect_to_party(_ip, _port, print_progress) + + +temptimer = None + + +def modify_sign_in(account_type: str) -> None: + original_sign_in(account_type) + if messenger.server_online: + messenger.logged_in = False + global temptimer + temptimer = ba.Timer(2, messenger._cookie_login) + + +class PingThread(Thread): + """Thread for sending out game pings.""" + + def __init__(self, address: str, port: int): + super().__init__() + self._address = address + self._port = port + + def run(self) -> None: + sock: Optional[socket.socket] = None + try: + import socket + from ba.internal import get_ip_address_type + socket_type = get_ip_address_type(self._address) + sock = socket.socket(socket_type, socket.SOCK_DGRAM) + sock.connect((self._address, self._port)) + + starttime = time.time() + + # Send a few pings and wait a second for + # a response. + sock.settimeout(1) + for _i in range(3): + sock.send(b'\x0b') + result: Optional[bytes] + try: + # 11: BA_PACKET_SIMPLE_PING + result = sock.recv(10) + except Exception: + result = None + if result == b'\x0c': + # 12: BA_PACKET_SIMPLE_PONG + accessible = True + break + time.sleep(1) + global _ping + _ping = int((time.time() - starttime) * 1000.0) + except Exception: + ba.print_exception('Error on gather ping', once=True) + finally: + try: + if sock is not None: + sock.close() + except Exception: + ba.print_exception('Error on gather ping cleanup', once=True) + + +def _get_store_char_tex(self) -> str: + _ba.set_party_icon_always_visible(True) + return ('storeCharacterXmas' if ba.internal.get_v1_account_misc_read_val( + 'xmas', False) else + 'storeCharacterEaster' if ba.internal.get_v1_account_misc_read_val( + 'easter', False) else 'storeCharacter') + + +# ba_meta export plugin +class InitalRun(ba.Plugin): + def __init__(self): + if _ba.env().get("build_number", 0) >= 20124: + global messenger, listener, displayer, color_tracker + initialize() + messenger = PrivateChatHandler() + listener = Thread(target=messenger_thread) + listener.start() + displayer = ba.Timer(0.4, msg_displayer, True) + color_tracker = ColorTracker() + bastd.ui.party.PartyWindow = PartyWindow + PopupMenuWindow.__init__ = __popup_menu_window_init__ + _ba.connect_to_party = modify_connect_to_party + ba.internal.sign_in_v1 = modify_sign_in + MainMenuWindow._get_store_char_tex = _get_store_char_tex + else: + display_error("This Party Window only runs with BombSquad version higer than 1.6.0.") From 4a1e7a559e8f36a025967db5cce9b0eec079eaa1 Mon Sep 17 00:00:00 2001 From: Drooopyyy Date: Fri, 30 Sep 2022 09:51:51 +0000 Subject: [PATCH 0133/1464] [ci] auto-format --- .../utilities/Updated_Ultra_Partywindow.py | 130 ++++++++++-------- 1 file changed, 69 insertions(+), 61 deletions(-) diff --git a/plugins/utilities/Updated_Ultra_Partywindow.py b/plugins/utilities/Updated_Ultra_Partywindow.py index c82a8519..ebe8896f 100644 --- a/plugins/utilities/Updated_Ultra_Partywindow.py +++ b/plugins/utilities/Updated_Ultra_Partywindow.py @@ -81,17 +81,20 @@ def display_success(msg=None): else: ba.screenmessage('Successful!', (0, 1, 0)) + class Translate(Thread): def __init__(self, data, callback): super().__init__() self.data = data self._callback = callback + def run(self): _ba.pushcall(ba.Call(ba.screenmessage, 'Translating...'), from_other_thread=True) response = messenger._send_request(f'{url}/translate', self.data) if response: _ba.pushcall(ba.Call(self._callback, response), from_other_thread=True) + class ColorTracker: def __init__(self): self.saved = {} @@ -170,8 +173,8 @@ def _update_version(self): if hash == file_hash: with open(__file__, 'w') as f: f.write(new_file) - _ba.pushcall(ba.Call(ba.screenmessage, 'Ultra party window updated\nNeeds restart.'), True) - + _ba.pushcall(ba.Call(ba.screenmessage, + 'Ultra party window updated\nNeeds restart.'), True) def _signup(self, registration_key): data = dict(pb_id=self.myid, registration_key=registration_key) @@ -281,7 +284,8 @@ def _format_message(self, msg): else: message = msg['message'] else: - message = '[' + msg['filter'] + ']: ' + 'Message from unsaved id. Save id to view message.' + message = '[' + msg['filter'] + ']: ' + \ + 'Message from unsaved id. Save id to view message.' return message def _get_status(self, id, type='status'): @@ -723,58 +727,58 @@ def __init__(self): try: translation_mode_text = ba.textwidget(parent=self.root_widget, - position=(40, height - 215), - size=(20, 20), - h_align='left', - v_align='center', - text="Translate Mode", - scale=0.9, - color=(1, 1, 1)) + position=(40, height - 215), + size=(20, 20), + h_align='left', + v_align='center', + text="Translate Mode", + scale=0.9, + color=(1, 1, 1)) decoration = ba.textwidget(parent=self.root_widget, - position=(40, height - 225), - size=(20, 20), - h_align='left', - v_align='center', - text="________________", - scale=0.9, - color=(1, 1, 1)) + position=(40, height - 225), + size=(20, 20), + h_align='left', + v_align='center', + text="________________", + scale=0.9, + color=(1, 1, 1)) language_char_text = ba.textwidget(parent=self.root_widget, - position=(85, height - 273), - size=(20, 20), - h_align='left', - v_align='center', - text='Normal Translation', - scale=0.6, - color=(1, 1, 1)) + position=(85, height - 273), + size=(20, 20), + h_align='left', + v_align='center', + text='Normal Translation', + scale=0.6, + color=(1, 1, 1)) pronunciation_text = ba.textwidget(parent=self.root_widget, - position=(295, height - 273), - size=(20, 20), - h_align='left', - v_align='center', - text="Show Prononciation", - scale=0.6, - color=(1, 1, 1)) + position=(295, height - 273), + size=(20, 20), + h_align='left', + v_align='center', + text="Show Prononciation", + scale=0.6, + color=(1, 1, 1)) from bastd.ui.radiogroup import make_radio_group cur_val = ba.app.config.get('Pronunciation', True) cb1 = ba.checkboxwidget( - parent=self.root_widget, - position=(250, height - 275), - size=(20, 20), - maxwidth=300, - scale=1, - autoselect=True, - text="") + parent=self.root_widget, + position=(250, height - 275), + size=(20, 20), + maxwidth=300, + scale=1, + autoselect=True, + text="") cb2 = ba.checkboxwidget( - parent=self.root_widget, - position=(40, height - 275), - size=(20, 20), - maxwidth=300, - scale=1, - autoselect=True, - text="") + parent=self.root_widget, + position=(40, height - 275), + size=(20, 20), + maxwidth=300, + scale=1, + autoselect=True, + text="") make_radio_group((cb1, cb2), (True, False), cur_val, self._actions_changed) except Exception as e: @@ -783,7 +787,6 @@ def __init__(self): ba.containerwidget(edit=self.root_widget, cancel_button=btn) - def _change_source(self, choice): cfg = ba.app.config cfg['Translate Source Language'] = choice @@ -949,7 +952,7 @@ def __init__(self): ba.containerwidget(edit=self.root_widget, cancel_button=btn) ba.containerwidget(edit=self.root_widget, selected_child=(cbtn if cbtn is not None - and cancel_is_selected else None), + and cancel_is_selected else None), start_button=None) self._translation_btn = ba.buttonwidget(parent=self._subcontainer, @@ -1019,7 +1022,6 @@ def _cancel(self) -> None: ba.containerwidget(edit=self.root_widget, transition='out_scale') - class PartyWindow(ba.Window): """Party list/chat window.""" @@ -1214,7 +1216,8 @@ def __init__(self, origin: Sequence[float] = (0, 0)): button_type='square', autoselect=True, color=self.bg_color, - position=(self._width - 530, self._height - 100), + position=(self._width - 530, + self._height - 100), on_activate_call=self._ip_port_msg) self._settings_button = ba.buttonwidget(parent=self._root_widget, size=(50, 50), @@ -1286,7 +1289,8 @@ def _on_menu_button_press(self) -> None: uiscale = ba.app.ui.uiscale choices = ['muteOption', 'modifyColor', 'addQuickReply', 'removeQuickReply', 'credits'] - choices_display = ['Mute Option', 'Modify Main Color', 'Add as Quick Reply', 'Remove a Quick Reply', 'Credits'] + choices_display = ['Mute Option', 'Modify Main Color', + 'Add as Quick Reply', 'Remove a Quick Reply', 'Credits'] if hasattr(_ba.get_foreground_host_activity(), '_map'): choices.append('manualCamera') @@ -1414,7 +1418,7 @@ def _update(self) -> None: # host if self._roster[index]['client_id'] is not None: is_host = self._roster[index][ - 'client_id'] == -1 + 'client_id'] == -1 else: is_host = (index == 0) @@ -1450,7 +1454,7 @@ def _update(self) -> None: maxwidth=c_width * 0.96 - twd, color=(0.1, 1, 0.1, 0.5), text=ba.Lstr(resource=self._r + - '.hostText'), + '.hostText'), scale=0.4, shadow=0.1, flatness=1.0)) @@ -1497,7 +1501,8 @@ def _update(self) -> None: h_align='center', v_align='center') choices = [i for i in messenger.saved_ids] - choices_display = [ba.Lstr(value=messenger.saved_ids[i]) for i in messenger.saved_ids] + choices_display = [ba.Lstr(value=messenger.saved_ids[i]) + for i in messenger.saved_ids] choices.append('add') choices_display.append(ba.Lstr(value='***Add New***')) filter_widget = PopupMenu( @@ -1743,7 +1748,6 @@ def _apply_translation(translated): data['type'] = 'pronunciation' Translate(data, _apply_translation).start() - def _copy_to_clipboard(self): msg = ba.textwidget(query=self._text_field) if msg == '': @@ -1800,7 +1804,8 @@ def _on_party_member_press(self, client_id: int, is_host: bool, kick_str = ba.Lstr(resource='kickVoteText') uiscale = ba.app.ui.uiscale choices = ['kick', 'mention', 'adminkick'] - choices_display = [kick_str] + list(self._create_baLstr_list(['Mention this guy', f'Kick ID: {client_id}'])) + choices_display = [kick_str] + \ + list(self._create_baLstr_list(['Mention this guy', f'Kick ID: {client_id}'])) choices.append('customCommands') choices_display.append(ba.Lstr(value='Custom Commands')) PopupMenuWindow( @@ -1901,7 +1906,6 @@ def _send_chat_message(self) -> None: Thread(target=messenger._send_request, args=(url, data)).start() Thread(target=check_new_message).start() ba.textwidget(edit=self._text_field, text='') - def _write_quick_responds(self, data): try: @@ -2032,7 +2036,8 @@ def _get_player_info(self, clientID): def _edit_text_msg_box(self, text, action='add'): if isinstance(text, str): if action == 'add': - ba.textwidget(edit=self._text_field, text=ba.textwidget(query=self._text_field) + text) + ba.textwidget(edit=self._text_field, text=ba.textwidget( + query=self._text_field) + text) elif action == 'replace': ba.textwidget(edit=self._text_field, text=text) @@ -2107,7 +2112,9 @@ def __init__(self, wtype): self._id = ba.textwidget(parent=self._root_widget, scale=0.5, color=(1, 1, 1), - text=f'Account: ' + ba.internal.get_v1_account_misc_read_val_2('resolvedAccountID', ''), + text=f'Account: ' + + ba.internal.get_v1_account_misc_read_val_2( + 'resolvedAccountID', ''), size=(0, 0), position=(220, 170), h_align='center', @@ -2525,7 +2532,8 @@ def _change_camera_position(self, direction): elif direction == 'z-': center[2] -= increment elif direction == 'reset': - node.area_of_interest_bounds = activity._map.get_def_bound_box('area_of_interest_bounds') + node.area_of_interest_bounds = activity._map.get_def_bound_box( + 'area_of_interest_bounds') return aoi = (center[0] - size[0] / 2, @@ -2736,8 +2744,8 @@ def _get_store_char_tex(self) -> str: _ba.set_party_icon_always_visible(True) return ('storeCharacterXmas' if ba.internal.get_v1_account_misc_read_val( 'xmas', False) else - 'storeCharacterEaster' if ba.internal.get_v1_account_misc_read_val( - 'easter', False) else 'storeCharacter') + 'storeCharacterEaster' if ba.internal.get_v1_account_misc_read_val( + 'easter', False) else 'storeCharacter') # ba_meta export plugin From d110ae511e3841d377b196c2b4e9f4df104f8cc2 Mon Sep 17 00:00:00 2001 From: Loup <90267658+Loup-Garou911XD@users.noreply.github.com> Date: Fri, 30 Sep 2022 17:15:12 +0530 Subject: [PATCH 0134/1464] Persistent settings and settings window improvement Added moodlightSettings.txt for persistent settings Added save button Added icons to increase and decrease buttons --- plugins/utilities/mood_light.py | 150 +++++++++++++++++++------------- 1 file changed, 91 insertions(+), 59 deletions(-) diff --git a/plugins/utilities/mood_light.py b/plugins/utilities/mood_light.py index fb514c24..77e9f3c6 100644 --- a/plugins/utilities/mood_light.py +++ b/plugins/utilities/mood_light.py @@ -14,22 +14,33 @@ from time import sleep if TYPE_CHECKING: from typing import Any, Sequence, Callable, List, Dict, Tuple, Optional, Union + +def Print(arg1,arg2="",arg3=""): + ba.screenmessage(str(arg1)+str(arg2)+str(arg3)) +try: + with open("moodlightSettings.txt","r") as mltxt: + global Ldefault,Udefault + data=mltxt.read() + Ldefault,Udefault=data.split("\n") + Ldefault=int(Ldefault) + Udefault=int(Udefault) +except: + with open("moodlightSettings.txt","w") as mltxt: + mltxt.write("15 \n 20") + Ldefault,Udefault=15,20 + class SettingWindow(ba.Window): - def __init__(self): - global Ldefault,Udefault - Ldefault=5 - Udefault=20 - self.draw_ui() - + def __init__(self): + self.draw_ui() + def increase_limit(self): global Ldefault,Udefault try: if Udefault>=29 and self.selected=="upper": ba.textwidget(edit=self.warn_text,text="Careful!You risk get blind beyond this point") elif self.selected=="lower" and Ldefault>=-20 or self.selected=="upper" and Udefault<=30: - ba.textwidget(edit=self.warn_text,text="") - + ba.textwidget(edit=self.warn_text,text="") if self.selected=="lower": Ldefault += 1 ba.textwidget(edit=self.lower_text,text=str(Ldefault)) @@ -39,21 +50,19 @@ def increase_limit(self): except AttributeError: ba.textwidget(edit=self.warn_text,text="Click on number to select it") - def decrease_limit(self): - global Ldefault,Udefault + def decrease_limit(self): + global Ldefault,Udefault try: if Ldefault<=-19 and self.selected == "lower": - ba.textwidget(edit=self.warn_text,text="DON'T BE AFRAID OF DARK,IT'S A PLACE WHERE YOU CAN HIDE") + ba.textwidget(edit=self.warn_text,text="DON'T BE AFRAID OF DARK,IT'S A PLACE WHERE YOU CAN HIDE") elif (self.selected == "upper" and Udefault <=30) or (self.selected== "lower" and Ldefault>=-20): ba.textwidget(edit=self.warn_text,text="") - - if self.selected=="lower": Ldefault -= 1 - ba.textwidget(edit=self.lower_text,text=str(Ldefault)) + ba.textwidget(edit=self.lower_text,text=str(Ldefault)) elif self.selected=="upper": Udefault -=1 - ba.textwidget(edit=self.upper_text,text=str(Udefault)) + ba.textwidget(edit=self.upper_text,text=str(Udefault)) except AttributeError: ba.textwidget(edit=self.warn_text,text="Click on number to select it") @@ -66,39 +75,40 @@ def on_text_click(self,selected): ba.textwidget(edit=self.lower_text,color=(0,0,1)) ba.textwidget(edit=self.upper_text,color=(1,1,1)) else: - ba.screenmessage("this should't happen from on_text_click") + Print("this should't happen from on_text_click") def draw_ui(self): self.uiscale=ba.app.ui.uiscale super().__init__( root_widget=ba.containerwidget( - size=(800, 800), + size=(670, 670), on_outside_click_call=self.close, transition="in_right",)) increase_button=ba.buttonwidget( parent=self._root_widget, - position=(250,100), - size=(50,50), - label="+", - scale=2, + position=(600,100), + size=(5,1), + scale=3.5, + extra_touch_border_scale=2.5, + icon=ba.gettexture("upButton"), on_activate_call=self.increase_limit) decrease_button=ba.buttonwidget( parent=self._root_widget, position=(100,100), - size=(50,50), - scale=2, - label="-", + size=(5,1), + scale=3.5, + extra_touch_border_scale=2.5, + icon=ba.gettexture("downButton"), on_activate_call=self.decrease_limit) - - + self.lower_text=ba.textwidget( parent=self._root_widget, size=(200,100), scale=2, - position=(100,300), + position=(100,200), h_align="center", v_align="center", maxwidth=400.0, @@ -110,39 +120,55 @@ def draw_ui(self): parent=self._root_widget, size=(200,100), scale=2, - position=(500,300), + position=(400,200), h_align="center", v_align="center", maxwidth=400.0, text=str(Udefault), click_activate=True, - selectable=True) + selectable=True) self.warn_text=ba.textwidget( parent=self._root_widget, text="", size=(400,100), - position=(200,500), + position=(150,300), h_align="center", v_align="center", maxwidth=600) - close_button=ba.buttonwidget( + self.close_button=ba.buttonwidget( parent=self._root_widget, - position=(700,650), - size=(100,100), - icon=ba.gettexture('crossOut'), - on_activate_call=self.close, - color=(0.8,0.2,0.2)) - - ba.containerwidget(edit=self._root_widget, cancel_button=close_button) - ba.textwidget(edit=self.upper_text,on_activate_call=ba.Call(self.on_text_click,"upper")) - ba.textwidget(edit=self.lower_text,on_activate_call=ba.Call(self.on_text_click,"lower")) + position=(550,590), + size=(30,30), + icon=ba.gettexture("crossOut"), + icon_color=(1,0.2,0.2), + scale=2, + color=(1,0.2,0.2), + extra_touch_border_scale=5, + on_activate_call=self.close,) + save_button=ba.buttonwidget( + parent=self._root_widget, + position=(450,450), + size=(125,70), + scale=1.5, + label="SAVE", + on_activate_call=self.save_settings) + + ba.textwidget(edit=self.upper_text,on_activate_call=ba.Call(self.on_text_click,"upper")) + ba.textwidget(edit=self.lower_text,on_activate_call=ba.Call(self.on_text_click,"lower")) + + def save_settings(self): + with open("moodlightSettings.txt","w") as mltxt: + data="\n".join([str(Ldefault),str(Udefault)]) + mltxt.write(data) + Print("settings saved") + self.close() + def close(self): - ba.containerwidget(edit=self._root_widget, transition="out_right") - - + ba.containerwidget(edit=self._root_widget, transition="out_right",) + # ba_meta export plugin class moodlight(ba.Plugin): def __init__(self): @@ -150,36 +176,42 @@ def __init__(self): Map._old_init = Map.__init__ def on_app_running(self): - try: + try: SettingWindow() _ba.timer(0.5, self.on_chat_message, True) except Exception as err: - ba.screenmessage(str(err)) + Print(err) - def on_chat_message(self): + def on_chat_message(self): messages=_ba.get_chat_messages() if len(messages)>0: lastmessage=messages[-1].split(":")[-1].strip().lower() if lastmessage in ("/mood light","/mood lighting","/mood_light","/mood_lighting","/moodlight","ml"): - _ba.chatmessage("Mood light settings opened") + + with open("moodlightSettings.txt","r") as mltxt: + global Ldefault,Udefault + data=mltxt.read() + Ldefault,Udefault=data.split("\n") + Ldefault=int(Ldefault) + Udefault=int(Udefault) SettingWindow() - + _ba.chatmessage("Mood light settings opened") + def on_plugin_manager_prompt(self): - SettingWindow() - + SettingWindow() + def _new_init(self, vr_overlay_offset: Optional[Sequence[float]] = None) -> None: self._old_init(vr_overlay_offset) in_game = not isinstance(_ba.get_foreground_host_session(), mainmenu.MainMenuSession) if not in_game: return gnode = _ba.getactivity().globalsnode - - def changetint(self): - ba.animate_array(gnode, 'tint', 3, { + + def changetint(): + Range=(random.randrange(Ldefault,Udefault)/10, random.randrange(Ldefault,Udefault)/10, random.randrange(Ldefault,Udefault)/10) + ba.animate_array(gnode, 'tint', 3, { 0.0: gnode.tint, - 1.0: (random.randrange(Ldefault,Udefault)/10, random.randrange(Ldefault,Udefault)/10, random.randrange(Ldefault,Udefault)/10) - }) - _ba.timer(0.3, changetint, repeat= True) - - - Map.__init__ = _new_init + 1.0: Range + }) + _ba.timer(0.3, changetint, repeat= True) + Map.__init__ = _new_init \ No newline at end of file From 3376c4ceabc96aefbabdd5b47dc7d4b2bcbbb7c0 Mon Sep 17 00:00:00 2001 From: Loup <90267658+Loup-Garou911XD@users.noreply.github.com> Date: Fri, 30 Sep 2022 17:48:00 +0530 Subject: [PATCH 0135/1464] Settings window ui improvement --- plugins/utilities/mood_light.py | 41 +++++++++++++++++++++++++++------ 1 file changed, 34 insertions(+), 7 deletions(-) diff --git a/plugins/utilities/mood_light.py b/plugins/utilities/mood_light.py index 77e9f3c6..76ae1f22 100644 --- a/plugins/utilities/mood_light.py +++ b/plugins/utilities/mood_light.py @@ -86,6 +86,16 @@ def draw_ui(self): on_outside_click_call=self.close, transition="in_right",)) + moodlight_label=ba.textwidget( + parent=self._root_widget, + size=(200,100), + position=(150,550), + scale=2, + h_align="center", + v_align="center", + text="Mood light settings", + color=(0,1,0)) + increase_button=ba.buttonwidget( parent=self._root_widget, position=(600,100), @@ -115,6 +125,14 @@ def draw_ui(self): text=str(Ldefault), click_activate=True, selectable=True) + + lower_text_label=ba.textwidget( + parent=self._root_widget, + size=(200,100), + position=(100,150), + h_align="center", + v_align="center", + text="Limit darkness") self.upper_text=ba.textwidget( parent=self._root_widget, @@ -126,12 +144,20 @@ def draw_ui(self): maxwidth=400.0, text=str(Udefault), click_activate=True, - selectable=True) + selectable=True) + + upper_text_label=ba.textwidget( + parent=self._root_widget, + size=(200,100), + position=(400,150), + h_align="center", + v_align="center", + text="Limit brightness") self.warn_text=ba.textwidget( parent=self._root_widget, text="", - size=(400,100), + size=(400,200), position=(150,300), h_align="center", v_align="center", @@ -140,20 +166,22 @@ def draw_ui(self): self.close_button=ba.buttonwidget( parent=self._root_widget, position=(550,590), - size=(30,30), + size=(35,35), icon=ba.gettexture("crossOut"), icon_color=(1,0.2,0.2), scale=2, color=(1,0.2,0.2), extra_touch_border_scale=5, - on_activate_call=self.close,) + on_activate_call=self.close, + button_type="square") save_button=ba.buttonwidget( parent=self._root_widget, - position=(450,450), - size=(125,70), + position=(520,470), + size=(90,70), scale=1.5, label="SAVE", + button_type="square", on_activate_call=self.save_settings) ba.textwidget(edit=self.upper_text,on_activate_call=ba.Call(self.on_text_click,"upper")) @@ -177,7 +205,6 @@ def __init__(self): def on_app_running(self): try: - SettingWindow() _ba.timer(0.5, self.on_chat_message, True) except Exception as err: Print(err) From ede95e386e0b1fca06bc3a204ddfd5adcc1c501a Mon Sep 17 00:00:00 2001 From: Loup <90267658+Loup-Garou911XD@users.noreply.github.com> Date: Fri, 30 Sep 2022 17:58:21 +0530 Subject: [PATCH 0136/1464] Update utilities.json --- plugins/utilities.json | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/plugins/utilities.json b/plugins/utilities.json index 4755401b..3f1a4e32 100644 --- a/plugins/utilities.json +++ b/plugins/utilities.json @@ -8,17 +8,17 @@ "external_url": "", "authors": [ { - "name": "Anonymous", + "name": "LoupGarou", "email": "", - "discord": "" + "discord": "ʟօʊքɢǟʀօʊ#3063" } ], "versions": { "1.0.0": { "api_version": 7, - "commit_sha": "41e239c", - "released_on": "21-09-2022", - "md5sum": "bbaee5f133b41d2edjsjsk3b726403a75e" + "commit_sha": "", + "released_on": "30-09-2022", + "md5sum": "" } } }, From da3bb374b35cb330a2ef83fd706285467034898d Mon Sep 17 00:00:00 2001 From: Loup-Garou911XD Date: Fri, 30 Sep 2022 12:30:48 +0000 Subject: [PATCH 0137/1464] [ci] auto-format --- plugins/utilities/mood_light.py | 433 ++++++++++++++++---------------- 1 file changed, 221 insertions(+), 212 deletions(-) diff --git a/plugins/utilities/mood_light.py b/plugins/utilities/mood_light.py index 76ae1f22..fe8d9dd5 100644 --- a/plugins/utilities/mood_light.py +++ b/plugins/utilities/mood_light.py @@ -1,4 +1,4 @@ -#mood light plugin by ʟօʊքɢǟʀօʊ +# mood light plugin by ʟօʊքɢǟʀօʊ # ba_meta require api 7 from __future__ import annotations @@ -14,231 +14,240 @@ from time import sleep if TYPE_CHECKING: from typing import Any, Sequence, Callable, List, Dict, Tuple, Optional, Union - -def Print(arg1,arg2="",arg3=""): - ba.screenmessage(str(arg1)+str(arg2)+str(arg3)) + + +def Print(arg1, arg2="", arg3=""): + ba.screenmessage(str(arg1)+str(arg2)+str(arg3)) + try: - with open("moodlightSettings.txt","r") as mltxt: - global Ldefault,Udefault - data=mltxt.read() - Ldefault,Udefault=data.split("\n") - Ldefault=int(Ldefault) - Udefault=int(Udefault) + with open("moodlightSettings.txt", "r") as mltxt: + global Ldefault, Udefault + data = mltxt.read() + Ldefault, Udefault = data.split("\n") + Ldefault = int(Ldefault) + Udefault = int(Udefault) except: - with open("moodlightSettings.txt","w") as mltxt: - mltxt.write("15 \n 20") - Ldefault,Udefault=15,20 - + with open("moodlightSettings.txt", "w") as mltxt: + mltxt.write("15 \n 20") + Ldefault, Udefault = 15, 20 + + class SettingWindow(ba.Window): - def __init__(self): - self.draw_ui() - - def increase_limit(self): - global Ldefault,Udefault - try: - if Udefault>=29 and self.selected=="upper": - ba.textwidget(edit=self.warn_text,text="Careful!You risk get blind beyond this point") - elif self.selected=="lower" and Ldefault>=-20 or self.selected=="upper" and Udefault<=30: - ba.textwidget(edit=self.warn_text,text="") - if self.selected=="lower": - Ldefault += 1 - ba.textwidget(edit=self.lower_text,text=str(Ldefault)) - elif self.selected=="upper": - Udefault+=1 - ba.textwidget(edit=self.upper_text,text=str(Udefault)) - except AttributeError: - ba.textwidget(edit=self.warn_text,text="Click on number to select it") - - def decrease_limit(self): - global Ldefault,Udefault - try: - if Ldefault<=-19 and self.selected == "lower": - ba.textwidget(edit=self.warn_text,text="DON'T BE AFRAID OF DARK,IT'S A PLACE WHERE YOU CAN HIDE") - elif (self.selected == "upper" and Udefault <=30) or (self.selected== "lower" and Ldefault>=-20): - ba.textwidget(edit=self.warn_text,text="") - if self.selected=="lower": - Ldefault -= 1 - ba.textwidget(edit=self.lower_text,text=str(Ldefault)) - elif self.selected=="upper": - Udefault -=1 - ba.textwidget(edit=self.upper_text,text=str(Udefault)) - except AttributeError: - ba.textwidget(edit=self.warn_text,text="Click on number to select it") - - def on_text_click(self,selected): - self.selected=selected - if selected=="upper": - ba.textwidget(edit=self.upper_text,color=(0,0,1)) - ba.textwidget(edit=self.lower_text,color=(1,1,1)) - elif selected=="lower": - ba.textwidget(edit=self.lower_text,color=(0,0,1)) - ba.textwidget(edit=self.upper_text,color=(1,1,1)) - else: - Print("this should't happen from on_text_click") - - def draw_ui(self): - self.uiscale=ba.app.ui.uiscale - - super().__init__( - root_widget=ba.containerwidget( - size=(670, 670), - on_outside_click_call=self.close, - transition="in_right",)) - - moodlight_label=ba.textwidget( - parent=self._root_widget, - size=(200,100), - position=(150,550), - scale=2, - h_align="center", - v_align="center", - text="Mood light settings", - color=(0,1,0)) - - increase_button=ba.buttonwidget( - parent=self._root_widget, - position=(600,100), - size=(5,1), - scale=3.5, - extra_touch_border_scale=2.5, - icon=ba.gettexture("upButton"), - on_activate_call=self.increase_limit) - - decrease_button=ba.buttonwidget( - parent=self._root_widget, - position=(100,100), - size=(5,1), - scale=3.5, - extra_touch_border_scale=2.5, - icon=ba.gettexture("downButton"), - on_activate_call=self.decrease_limit) - - self.lower_text=ba.textwidget( - parent=self._root_widget, - size=(200,100), - scale=2, - position=(100,200), - h_align="center", - v_align="center", - maxwidth=400.0, - text=str(Ldefault), - click_activate=True, - selectable=True) - - lower_text_label=ba.textwidget( - parent=self._root_widget, - size=(200,100), - position=(100,150), - h_align="center", - v_align="center", - text="Limit darkness") - - self.upper_text=ba.textwidget( - parent=self._root_widget, - size=(200,100), - scale=2, - position=(400,200), - h_align="center", - v_align="center", - maxwidth=400.0, - text=str(Udefault), - click_activate=True, - selectable=True) - - upper_text_label=ba.textwidget( - parent=self._root_widget, - size=(200,100), - position=(400,150), - h_align="center", - v_align="center", - text="Limit brightness") - - self.warn_text=ba.textwidget( - parent=self._root_widget, - text="", - size=(400,200), - position=(150,300), - h_align="center", - v_align="center", - maxwidth=600) - - self.close_button=ba.buttonwidget( - parent=self._root_widget, - position=(550,590), - size=(35,35), - icon=ba.gettexture("crossOut"), - icon_color=(1,0.2,0.2), - scale=2, - color=(1,0.2,0.2), - extra_touch_border_scale=5, - on_activate_call=self.close, - button_type="square") - - save_button=ba.buttonwidget( - parent=self._root_widget, - position=(520,470), - size=(90,70), - scale=1.5, - label="SAVE", - button_type="square", - on_activate_call=self.save_settings) - - ba.textwidget(edit=self.upper_text,on_activate_call=ba.Call(self.on_text_click,"upper")) - ba.textwidget(edit=self.lower_text,on_activate_call=ba.Call(self.on_text_click,"lower")) - - def save_settings(self): - with open("moodlightSettings.txt","w") as mltxt: - data="\n".join([str(Ldefault),str(Udefault)]) - mltxt.write(data) - Print("settings saved") - self.close() - - def close(self): - ba.containerwidget(edit=self._root_widget, transition="out_right",) - + def __init__(self): + self.draw_ui() + + def increase_limit(self): + global Ldefault, Udefault + try: + if Udefault >= 29 and self.selected == "upper": + ba.textwidget(edit=self.warn_text, + text="Careful!You risk get blind beyond this point") + elif self.selected == "lower" and Ldefault >= -20 or self.selected == "upper" and Udefault <= 30: + ba.textwidget(edit=self.warn_text, text="") + if self.selected == "lower": + Ldefault += 1 + ba.textwidget(edit=self.lower_text, text=str(Ldefault)) + elif self.selected == "upper": + Udefault += 1 + ba.textwidget(edit=self.upper_text, text=str(Udefault)) + except AttributeError: + ba.textwidget(edit=self.warn_text, text="Click on number to select it") + + def decrease_limit(self): + global Ldefault, Udefault + try: + if Ldefault <= -19 and self.selected == "lower": + ba.textwidget(edit=self.warn_text, + text="DON'T BE AFRAID OF DARK,IT'S A PLACE WHERE YOU CAN HIDE") + elif (self.selected == "upper" and Udefault <= 30) or (self.selected == "lower" and Ldefault >= -20): + ba.textwidget(edit=self.warn_text, text="") + if self.selected == "lower": + Ldefault -= 1 + ba.textwidget(edit=self.lower_text, text=str(Ldefault)) + elif self.selected == "upper": + Udefault -= 1 + ba.textwidget(edit=self.upper_text, text=str(Udefault)) + except AttributeError: + ba.textwidget(edit=self.warn_text, text="Click on number to select it") + + def on_text_click(self, selected): + self.selected = selected + if selected == "upper": + ba.textwidget(edit=self.upper_text, color=(0, 0, 1)) + ba.textwidget(edit=self.lower_text, color=(1, 1, 1)) + elif selected == "lower": + ba.textwidget(edit=self.lower_text, color=(0, 0, 1)) + ba.textwidget(edit=self.upper_text, color=(1, 1, 1)) + else: + Print("this should't happen from on_text_click") + + def draw_ui(self): + self.uiscale = ba.app.ui.uiscale + + super().__init__( + root_widget=ba.containerwidget( + size=(670, 670), + on_outside_click_call=self.close, + transition="in_right",)) + + moodlight_label = ba.textwidget( + parent=self._root_widget, + size=(200, 100), + position=(150, 550), + scale=2, + h_align="center", + v_align="center", + text="Mood light settings", + color=(0, 1, 0)) + + increase_button = ba.buttonwidget( + parent=self._root_widget, + position=(600, 100), + size=(5, 1), + scale=3.5, + extra_touch_border_scale=2.5, + icon=ba.gettexture("upButton"), + on_activate_call=self.increase_limit) + + decrease_button = ba.buttonwidget( + parent=self._root_widget, + position=(100, 100), + size=(5, 1), + scale=3.5, + extra_touch_border_scale=2.5, + icon=ba.gettexture("downButton"), + on_activate_call=self.decrease_limit) + + self.lower_text = ba.textwidget( + parent=self._root_widget, + size=(200, 100), + scale=2, + position=(100, 200), + h_align="center", + v_align="center", + maxwidth=400.0, + text=str(Ldefault), + click_activate=True, + selectable=True) + + lower_text_label = ba.textwidget( + parent=self._root_widget, + size=(200, 100), + position=(100, 150), + h_align="center", + v_align="center", + text="Limit darkness") + + self.upper_text = ba.textwidget( + parent=self._root_widget, + size=(200, 100), + scale=2, + position=(400, 200), + h_align="center", + v_align="center", + maxwidth=400.0, + text=str(Udefault), + click_activate=True, + selectable=True) + + upper_text_label = ba.textwidget( + parent=self._root_widget, + size=(200, 100), + position=(400, 150), + h_align="center", + v_align="center", + text="Limit brightness") + + self.warn_text = ba.textwidget( + parent=self._root_widget, + text="", + size=(400, 200), + position=(150, 300), + h_align="center", + v_align="center", + maxwidth=600) + + self.close_button = ba.buttonwidget( + parent=self._root_widget, + position=(550, 590), + size=(35, 35), + icon=ba.gettexture("crossOut"), + icon_color=(1, 0.2, 0.2), + scale=2, + color=(1, 0.2, 0.2), + extra_touch_border_scale=5, + on_activate_call=self.close, + button_type="square") + + save_button = ba.buttonwidget( + parent=self._root_widget, + position=(520, 470), + size=(90, 70), + scale=1.5, + label="SAVE", + button_type="square", + on_activate_call=self.save_settings) + + ba.textwidget(edit=self.upper_text, on_activate_call=ba.Call(self.on_text_click, "upper")) + ba.textwidget(edit=self.lower_text, on_activate_call=ba.Call(self.on_text_click, "lower")) + + def save_settings(self): + with open("moodlightSettings.txt", "w") as mltxt: + data = "\n".join([str(Ldefault), str(Udefault)]) + mltxt.write(data) + Print("settings saved") + self.close() + + def close(self): + ba.containerwidget(edit=self._root_widget, transition="out_right",) + # ba_meta export plugin + + class moodlight(ba.Plugin): def __init__(self): pass Map._old_init = Map.__init__ - + def on_app_running(self): - try: - _ba.timer(0.5, self.on_chat_message, True) + try: + _ba.timer(0.5, self.on_chat_message, True) except Exception as err: - Print(err) - - def on_chat_message(self): - messages=_ba.get_chat_messages() - if len(messages)>0: - lastmessage=messages[-1].split(":")[-1].strip().lower() - if lastmessage in ("/mood light","/mood lighting","/mood_light","/mood_lighting","/moodlight","ml"): - - with open("moodlightSettings.txt","r") as mltxt: - global Ldefault,Udefault - data=mltxt.read() - Ldefault,Udefault=data.split("\n") - Ldefault=int(Ldefault) - Udefault=int(Udefault) + Print(err) + + def on_chat_message(self): + messages = _ba.get_chat_messages() + if len(messages) > 0: + lastmessage = messages[-1].split(":")[-1].strip().lower() + if lastmessage in ("/mood light", "/mood lighting", "/mood_light", "/mood_lighting", "/moodlight", "ml"): + + with open("moodlightSettings.txt", "r") as mltxt: + global Ldefault, Udefault + data = mltxt.read() + Ldefault, Udefault = data.split("\n") + Ldefault = int(Ldefault) + Udefault = int(Udefault) SettingWindow() _ba.chatmessage("Mood light settings opened") - + def on_plugin_manager_prompt(self): - SettingWindow() - + SettingWindow() + def _new_init(self, vr_overlay_offset: Optional[Sequence[float]] = None) -> None: - self._old_init(vr_overlay_offset) + self._old_init(vr_overlay_offset) in_game = not isinstance(_ba.get_foreground_host_session(), mainmenu.MainMenuSession) - if not in_game: return - + if not in_game: + return + gnode = _ba.getactivity().globalsnode - - def changetint(): - Range=(random.randrange(Ldefault,Udefault)/10, random.randrange(Ldefault,Udefault)/10, random.randrange(Ldefault,Udefault)/10) - ba.animate_array(gnode, 'tint', 3, { - 0.0: gnode.tint, - 1.0: Range - }) - _ba.timer(0.3, changetint, repeat= True) - Map.__init__ = _new_init \ No newline at end of file + + def changetint(): + Range = (random.randrange(Ldefault, Udefault)/10, random.randrange(Ldefault, + Udefault)/10, random.randrange(Ldefault, Udefault)/10) + ba.animate_array(gnode, 'tint', 3, { + 0.0: gnode.tint, + 1.0: Range + }) + _ba.timer(0.3, changetint, repeat=True) + Map.__init__ = _new_init From d685575dc35c8a91800aac4550e3ad4e8bea0767 Mon Sep 17 00:00:00 2001 From: Loup <90267658+Loup-Garou911XD@users.noreply.github.com> Date: Fri, 30 Sep 2022 19:24:18 +0530 Subject: [PATCH 0138/1464] Added email --- plugins/utilities.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/utilities.json b/plugins/utilities.json index 3f1a4e32..cbe4ddb7 100644 --- a/plugins/utilities.json +++ b/plugins/utilities.json @@ -9,7 +9,7 @@ "authors": [ { "name": "LoupGarou", - "email": "", + "email": ""LoupGarou5418@outlook.com, "discord": "ʟօʊքɢǟʀօʊ#3063" } ], From a087cd3ec66ce2809a6a077fc77b146b6ea15107 Mon Sep 17 00:00:00 2001 From: Loup <90267658+Loup-Garou911XD@users.noreply.github.com> Date: Fri, 30 Sep 2022 19:24:54 +0530 Subject: [PATCH 0139/1464] Fixed email after breaking it --- plugins/utilities.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/utilities.json b/plugins/utilities.json index cbe4ddb7..0aa19d29 100644 --- a/plugins/utilities.json +++ b/plugins/utilities.json @@ -9,7 +9,7 @@ "authors": [ { "name": "LoupGarou", - "email": ""LoupGarou5418@outlook.com, + "email": "LoupGarou5418@outlook.com", "discord": "ʟօʊքɢǟʀօʊ#3063" } ], From fb1b16e572a606c4e62b12ee984de1d3c81e5a3d Mon Sep 17 00:00:00 2001 From: Loup <90267658+Loup-Garou911XD@users.noreply.github.com> Date: Fri, 30 Sep 2022 21:15:48 +0530 Subject: [PATCH 0140/1464] Update utilities.json --- plugins/utilities.json | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/plugins/utilities.json b/plugins/utilities.json index 0aa19d29..ba7ab8b6 100644 --- a/plugins/utilities.json +++ b/plugins/utilities.json @@ -14,12 +14,7 @@ } ], "versions": { - "1.0.0": { - "api_version": 7, - "commit_sha": "", - "released_on": "30-09-2022", - "md5sum": "" - } + "1.0.0": Null } }, From 27361a9a6c6269323ea55f57efe299b381e07735 Mon Sep 17 00:00:00 2001 From: Loup <90267658+Loup-Garou911XD@users.noreply.github.com> Date: Fri, 30 Sep 2022 21:16:30 +0530 Subject: [PATCH 0141/1464] Smoll n --- plugins/utilities.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/utilities.json b/plugins/utilities.json index ba7ab8b6..d7eaaba8 100644 --- a/plugins/utilities.json +++ b/plugins/utilities.json @@ -14,7 +14,7 @@ } ], "versions": { - "1.0.0": Null + "1.0.0": null } }, From d27440594dbb9ea0ffa1e494d55b5e4cd108e330 Mon Sep 17 00:00:00 2001 From: Loup <90267658+Loup-Garou911XD@users.noreply.github.com> Date: Fri, 30 Sep 2022 21:18:25 +0530 Subject: [PATCH 0142/1464] Moved my comment down --- plugins/utilities/mood_light.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/plugins/utilities/mood_light.py b/plugins/utilities/mood_light.py index fe8d9dd5..32957d3f 100644 --- a/plugins/utilities/mood_light.py +++ b/plugins/utilities/mood_light.py @@ -1,5 +1,3 @@ -# mood light plugin by ʟօʊքɢǟʀօʊ - # ba_meta require api 7 from __future__ import annotations from typing import TYPE_CHECKING, cast @@ -15,6 +13,7 @@ if TYPE_CHECKING: from typing import Any, Sequence, Callable, List, Dict, Tuple, Optional, Union +# mood light plugin by ʟօʊքɢǟʀօʊ def Print(arg1, arg2="", arg3=""): ba.screenmessage(str(arg1)+str(arg2)+str(arg3)) From 38e9393afeaf5e884530269081769b58cb0aebe9 Mon Sep 17 00:00:00 2001 From: Loup-Garou911XD Date: Fri, 30 Sep 2022 15:48:48 +0000 Subject: [PATCH 0143/1464] [ci] auto-format --- plugins/utilities/mood_light.py | 1 + 1 file changed, 1 insertion(+) diff --git a/plugins/utilities/mood_light.py b/plugins/utilities/mood_light.py index 32957d3f..65c5d013 100644 --- a/plugins/utilities/mood_light.py +++ b/plugins/utilities/mood_light.py @@ -15,6 +15,7 @@ # mood light plugin by ʟօʊքɢǟʀօʊ + def Print(arg1, arg2="", arg3=""): ba.screenmessage(str(arg1)+str(arg2)+str(arg3)) From fde9483f5e972eb023ad1003c390f4e30eb33870 Mon Sep 17 00:00:00 2001 From: Loup <90267658+Loup-Garou911XD@users.noreply.github.com> Date: Fri, 30 Sep 2022 21:20:21 +0530 Subject: [PATCH 0144/1464] Removed empty lines --- plugins/utilities/mood_light.py | 4 ---- 1 file changed, 4 deletions(-) diff --git a/plugins/utilities/mood_light.py b/plugins/utilities/mood_light.py index 65c5d013..613c7d78 100644 --- a/plugins/utilities/mood_light.py +++ b/plugins/utilities/mood_light.py @@ -19,7 +19,6 @@ def Print(arg1, arg2="", arg3=""): ba.screenmessage(str(arg1)+str(arg2)+str(arg3)) - try: with open("moodlightSettings.txt", "r") as mltxt: global Ldefault, Udefault @@ -32,7 +31,6 @@ def Print(arg1, arg2="", arg3=""): mltxt.write("15 \n 20") Ldefault, Udefault = 15, 20 - class SettingWindow(ba.Window): def __init__(self): self.draw_ui() @@ -203,8 +201,6 @@ def close(self): ba.containerwidget(edit=self._root_widget, transition="out_right",) # ba_meta export plugin - - class moodlight(ba.Plugin): def __init__(self): pass From 637520d9c61159aac7ab17983eb413aa656dabc9 Mon Sep 17 00:00:00 2001 From: Loup-Garou911XD Date: Fri, 30 Sep 2022 15:50:42 +0000 Subject: [PATCH 0145/1464] [ci] auto-format --- plugins/utilities/mood_light.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/plugins/utilities/mood_light.py b/plugins/utilities/mood_light.py index 613c7d78..65c5d013 100644 --- a/plugins/utilities/mood_light.py +++ b/plugins/utilities/mood_light.py @@ -19,6 +19,7 @@ def Print(arg1, arg2="", arg3=""): ba.screenmessage(str(arg1)+str(arg2)+str(arg3)) + try: with open("moodlightSettings.txt", "r") as mltxt: global Ldefault, Udefault @@ -31,6 +32,7 @@ def Print(arg1, arg2="", arg3=""): mltxt.write("15 \n 20") Ldefault, Udefault = 15, 20 + class SettingWindow(ba.Window): def __init__(self): self.draw_ui() @@ -201,6 +203,8 @@ def close(self): ba.containerwidget(edit=self._root_widget, transition="out_right",) # ba_meta export plugin + + class moodlight(ba.Plugin): def __init__(self): pass From 50ac2201a81adfe724fa8ee2f9ecbf5b60990da2 Mon Sep 17 00:00:00 2001 From: Loup <90267658+Loup-Garou911XD@users.noreply.github.com> Date: Sat, 1 Oct 2022 02:40:59 +0530 Subject: [PATCH 0146/1464] Added external url --- plugins/utilities.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/utilities.json b/plugins/utilities.json index d7eaaba8..25fb8ecc 100644 --- a/plugins/utilities.json +++ b/plugins/utilities.json @@ -5,7 +5,7 @@ "plugins": { "mood_light": { "description": "mood lighting in co-op games" - "external_url": "", + "external_url": "https://github.com/Loup-Garou911XD/plugin-manager", "authors": [ { "name": "LoupGarou", From 2594105db315bcedbd325d39dc865b584a617b29 Mon Sep 17 00:00:00 2001 From: Loup <90267658+Loup-Garou911XD@users.noreply.github.com> Date: Sat, 1 Oct 2022 02:50:08 +0530 Subject: [PATCH 0147/1464] Missed a comma --- plugins/utilities.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/utilities.json b/plugins/utilities.json index 25fb8ecc..85eb02ef 100644 --- a/plugins/utilities.json +++ b/plugins/utilities.json @@ -4,7 +4,7 @@ "plugins_base_url": "http://github.com/bombsquad-community/plugin-manager/{content_type}/{tag}/plugins/utilities", "plugins": { "mood_light": { - "description": "mood lighting in co-op games" + "description": "mood lighting in co-op games", "external_url": "https://github.com/Loup-Garou911XD/plugin-manager", "authors": [ { From 195f70d728ea224815f138c5fa0404fba556141e Mon Sep 17 00:00:00 2001 From: Loup-Garou911XD Date: Fri, 30 Sep 2022 21:20:30 +0000 Subject: [PATCH 0148/1464] [ci] apply-version-metadata --- plugins/utilities.json | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/plugins/utilities.json b/plugins/utilities.json index 85eb02ef..d5eb5fa1 100644 --- a/plugins/utilities.json +++ b/plugins/utilities.json @@ -14,10 +14,14 @@ } ], "versions": { - "1.0.0": null - } - }, - + "1.0.0": { + "api_version": 7, + "commit_sha": "2594105", + "released_on": "30-09-2022", + "md5sum": "131585e571e9d4d60d40bbf7cbbd69e9" + } + } + }, "colorscheme": { "description": "Create custom UI colorschemes!", "external_url": "http://www.youtube.com/watch?v=qatwWrBAvjc", @@ -225,4 +229,4 @@ } } } -} +} \ No newline at end of file From 4523cc8f9cf397302b10a7b9de30114a852609c4 Mon Sep 17 00:00:00 2001 From: Loup <90267658+Loup-Garou911XD@users.noreply.github.com> Date: Sun, 2 Oct 2022 00:12:24 +0530 Subject: [PATCH 0149/1464] Removed value for external url --- plugins/utilities.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/plugins/utilities.json b/plugins/utilities.json index d5eb5fa1..57c2e8d6 100644 --- a/plugins/utilities.json +++ b/plugins/utilities.json @@ -5,7 +5,7 @@ "plugins": { "mood_light": { "description": "mood lighting in co-op games", - "external_url": "https://github.com/Loup-Garou911XD/plugin-manager", + "external_url": "", "authors": [ { "name": "LoupGarou", @@ -229,4 +229,4 @@ } } } -} \ No newline at end of file +} From 97668aab518d548cd97bb07f5fa7420b42277004 Mon Sep 17 00:00:00 2001 From: Loup-Garou911XD Date: Sat, 1 Oct 2022 18:42:59 +0000 Subject: [PATCH 0150/1464] [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 57c2e8d6..e591efa6 100644 --- a/plugins/utilities.json +++ b/plugins/utilities.json @@ -229,4 +229,4 @@ } } } -} +} \ No newline at end of file From c8c29a4edc92412a38073c8816ed2b513023cb6f Mon Sep 17 00:00:00 2001 From: Droopy <90500887+Drooopyyy@users.noreply.github.com> Date: Sun, 2 Oct 2022 00:28:07 +0530 Subject: [PATCH 0151/1464] removed auto updating feature --- plugins/utilities/Updated_Ultra_Partywindow.py | 13 ------------- 1 file changed, 13 deletions(-) diff --git a/plugins/utilities/Updated_Ultra_Partywindow.py b/plugins/utilities/Updated_Ultra_Partywindow.py index ebe8896f..2d39444b 100644 --- a/plugins/utilities/Updated_Ultra_Partywindow.py +++ b/plugins/utilities/Updated_Ultra_Partywindow.py @@ -160,22 +160,9 @@ def _ping(self): try: self.server_online = True version = float(response.replace('v', '')) - if version > __version__: - self._update_version() except: self.error = 'Server offline' - def _update_version(self): - new_file = self._send_request(url=f'{url}/updatepartywindow?get=file') - hash = self._send_request(url=f'{url}/updatepartywindow?get=md5') - if hash and new_file: - file_hash = md5(new_file.encode()).hexdigest() - if hash == file_hash: - with open(__file__, 'w') as f: - f.write(new_file) - _ba.pushcall(ba.Call(ba.screenmessage, - 'Ultra party window updated\nNeeds restart.'), True) - def _signup(self, registration_key): data = dict(pb_id=self.myid, registration_key=registration_key) response = self._send_request(url=f'{url}/signup', data=data) From cc0a7e1220be76041b9e018080c3f9e8e5184f3b Mon Sep 17 00:00:00 2001 From: Loup <90267658+Loup-Garou911XD@users.noreply.github.com> Date: Sun, 2 Oct 2022 00:35:17 +0530 Subject: [PATCH 0152/1464] Fixed Indentation https://github.com/bombsquad-community/plugin-manager/pull/47#pullrequestreview-1127555837 --- plugins/utilities/mood_light.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/plugins/utilities/mood_light.py b/plugins/utilities/mood_light.py index 65c5d013..debebb20 100644 --- a/plugins/utilities/mood_light.py +++ b/plugins/utilities/mood_light.py @@ -207,8 +207,7 @@ def close(self): class moodlight(ba.Plugin): def __init__(self): - pass - Map._old_init = Map.__init__ + Map._old_init = Map.__init__ def on_app_running(self): try: From 2afe98515d01631057c56f5bd61789c1cc1f9826 Mon Sep 17 00:00:00 2001 From: Loup <90267658+Loup-Garou911XD@users.noreply.github.com> Date: Sun, 2 Oct 2022 01:23:43 +0530 Subject: [PATCH 0153/1464] Update mood_light.py --- plugins/utilities/mood_light.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/plugins/utilities/mood_light.py b/plugins/utilities/mood_light.py index debebb20..65c5d013 100644 --- a/plugins/utilities/mood_light.py +++ b/plugins/utilities/mood_light.py @@ -207,7 +207,8 @@ def close(self): class moodlight(ba.Plugin): def __init__(self): - Map._old_init = Map.__init__ + pass + Map._old_init = Map.__init__ def on_app_running(self): try: From 16138295d8ba50011b05447710cd682fca15d0bd Mon Sep 17 00:00:00 2001 From: Loup <90267658+Loup-Garou911XD@users.noreply.github.com> Date: Sun, 2 Oct 2022 04:20:28 +0530 Subject: [PATCH 0154/1464] Fixed some issues Patched `_ba.chatmessage` instead of polling for previous chat message as suggested by https://github.com/bombsquad-community/plugin-manager/pull/47/files/195f70d728ea224815f138c5fa0404fba556141e#r985130539 Moved settings from txt file to `ba.app.config` https://github.com/bombsquad-community/plugin-manager/pull/47/files/195f70d728ea224815f138c5fa0404fba556141e#r985130531 --- plugins/utilities/mood_light.py | 56 ++++++++++++++------------------- 1 file changed, 24 insertions(+), 32 deletions(-) diff --git a/plugins/utilities/mood_light.py b/plugins/utilities/mood_light.py index 65c5d013..9599374c 100644 --- a/plugins/utilities/mood_light.py +++ b/plugins/utilities/mood_light.py @@ -2,8 +2,7 @@ from __future__ import annotations from typing import TYPE_CHECKING, cast -import ba -import _ba +import ba,_ba import random from ba._map import Map from bastd import mainmenu @@ -21,16 +20,11 @@ def Print(arg1, arg2="", arg3=""): try: - with open("moodlightSettings.txt", "r") as mltxt: - global Ldefault, Udefault - data = mltxt.read() - Ldefault, Udefault = data.split("\n") - Ldefault = int(Ldefault) - Udefault = int(Udefault) + Ldefault, Udefault=ba.app.config.get("moodlightingSettings") except: - with open("moodlightSettings.txt", "w") as mltxt: - mltxt.write("15 \n 20") - Ldefault, Udefault = 15, 20 + ba.app.config["moodlightingSettings"]=(15,20) + Ldefault, Udefault=ba.app.config.get("moodlightingSettings") + Print("settings up moodlight") class SettingWindow(ba.Window): @@ -193,44 +187,41 @@ def draw_ui(self): ba.textwidget(edit=self.lower_text, on_activate_call=ba.Call(self.on_text_click, "lower")) def save_settings(self): - with open("moodlightSettings.txt", "w") as mltxt: - data = "\n".join([str(Ldefault), str(Udefault)]) - mltxt.write(data) + ba.app.config["moodlightingSettings"]=(Ldefault,Udefault) Print("settings saved") self.close() def close(self): ba.containerwidget(edit=self._root_widget, transition="out_right",) +Map._old_init = Map.__init__ + +def new_chat_message(msg: Union[str, ba.Lstr], clients:Sequence[int] = None, sender_override: str = None): + old_fcm(msg, clients, sender_override) + if msg == 'ml': + try: + Ldefault, Udefault=ba.app.config.get("moodlightingSettings") + SettingWindow() + _ba.chatmessage("Mood light settings opened") + except Exception as err: + Print(err) + +old_fcm = _ba.chatmessage +_ba.chatmessage = new_chat_message + # ba_meta export plugin class moodlight(ba.Plugin): def __init__(self): pass - Map._old_init = Map.__init__ - + def on_app_running(self): try: - _ba.timer(0.5, self.on_chat_message, True) + pass except Exception as err: Print(err) - def on_chat_message(self): - messages = _ba.get_chat_messages() - if len(messages) > 0: - lastmessage = messages[-1].split(":")[-1].strip().lower() - if lastmessage in ("/mood light", "/mood lighting", "/mood_light", "/mood_lighting", "/moodlight", "ml"): - - with open("moodlightSettings.txt", "r") as mltxt: - global Ldefault, Udefault - data = mltxt.read() - Ldefault, Udefault = data.split("\n") - Ldefault = int(Ldefault) - Udefault = int(Udefault) - SettingWindow() - _ba.chatmessage("Mood light settings opened") - def on_plugin_manager_prompt(self): SettingWindow() @@ -251,3 +242,4 @@ def changetint(): }) _ba.timer(0.3, changetint, repeat=True) Map.__init__ = _new_init + From 5f9ac44f4eadaa9e6ba603bdea8e4fbda2b69a3a Mon Sep 17 00:00:00 2001 From: Loup-Garou911XD Date: Sat, 1 Oct 2022 22:50:49 +0000 Subject: [PATCH 0155/1464] [ci] auto-format --- plugins/utilities/mood_light.py | 25 ++++++++++++++----------- 1 file changed, 14 insertions(+), 11 deletions(-) diff --git a/plugins/utilities/mood_light.py b/plugins/utilities/mood_light.py index 9599374c..0c158eeb 100644 --- a/plugins/utilities/mood_light.py +++ b/plugins/utilities/mood_light.py @@ -2,7 +2,8 @@ from __future__ import annotations from typing import TYPE_CHECKING, cast -import ba,_ba +import ba +import _ba import random from ba._map import Map from bastd import mainmenu @@ -20,11 +21,11 @@ def Print(arg1, arg2="", arg3=""): try: - Ldefault, Udefault=ba.app.config.get("moodlightingSettings") + Ldefault, Udefault = ba.app.config.get("moodlightingSettings") except: - ba.app.config["moodlightingSettings"]=(15,20) - Ldefault, Udefault=ba.app.config.get("moodlightingSettings") - Print("settings up moodlight") + ba.app.config["moodlightingSettings"] = (15, 20) + Ldefault, Udefault = ba.app.config.get("moodlightingSettings") + Print("settings up moodlight") class SettingWindow(ba.Window): @@ -187,25 +188,28 @@ def draw_ui(self): ba.textwidget(edit=self.lower_text, on_activate_call=ba.Call(self.on_text_click, "lower")) def save_settings(self): - ba.app.config["moodlightingSettings"]=(Ldefault,Udefault) + ba.app.config["moodlightingSettings"] = (Ldefault, Udefault) Print("settings saved") self.close() def close(self): ba.containerwidget(edit=self._root_widget, transition="out_right",) + Map._old_init = Map.__init__ -def new_chat_message(msg: Union[str, ba.Lstr], clients:Sequence[int] = None, sender_override: str = None): + +def new_chat_message(msg: Union[str, ba.Lstr], clients: Sequence[int] = None, sender_override: str = None): old_fcm(msg, clients, sender_override) if msg == 'ml': try: - Ldefault, Udefault=ba.app.config.get("moodlightingSettings") + Ldefault, Udefault = ba.app.config.get("moodlightingSettings") SettingWindow() - _ba.chatmessage("Mood light settings opened") + _ba.chatmessage("Mood light settings opened") except Exception as err: Print(err) + old_fcm = _ba.chatmessage _ba.chatmessage = new_chat_message @@ -215,7 +219,7 @@ def new_chat_message(msg: Union[str, ba.Lstr], clients:Sequence[int] = None, sen class moodlight(ba.Plugin): def __init__(self): pass - + def on_app_running(self): try: pass @@ -242,4 +246,3 @@ def changetint(): }) _ba.timer(0.3, changetint, repeat=True) Map.__init__ = _new_init - From 13ca7b04ef27178d3444d05da569fba544afafa1 Mon Sep 17 00:00:00 2001 From: Vishal Date: Mon, 3 Oct 2022 20:20:33 +0530 Subject: [PATCH 0156/1464] Update to Version 0.1.7 --- CHANGELOG.md | 6 +++++ index.json | 1 + plugin_manager.py | 60 ++++++++++++++++++++++++++++++++++++----------- 3 files changed, 53 insertions(+), 14 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 779927ad..ed4f1f91 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,12 @@ ## Plugin Manager (dd-mm-yyyy) +### 0.1.7 (03-10-2022) + +- Added New Option in settings for Notifying new plugins. +- Added a Discord Button to join Bombsquad's Official Discord server. + + ### 0.1.6 (15-09-2022) - Distinguish the settings button with a cyan color (previously was green) in plugin manager window. diff --git a/index.json b/index.json index 363be828..376c192e 100644 --- a/index.json +++ b/index.json @@ -1,6 +1,7 @@ { "plugin_manager_url": "http://github.com/bombsquad-community/plugin-manager/{content_type}/{tag}/plugin_manager.py", "versions": { + "0.1.7": null, "0.1.6": { "api_version": 7, "commit_sha": "2a7ad8e", diff --git a/plugin_manager.py b/plugin_manager.py index 399482c6..f1697f17 100644 --- a/plugin_manager.py +++ b/plugin_manager.py @@ -20,7 +20,7 @@ _uiscale = ba.app.ui.uiscale -PLUGIN_MANAGER_VERSION = "0.1.6" +PLUGIN_MANAGER_VERSION = "0.1.7" REPOSITORY_URL = "http://github.com/bombsquad-community/plugin-manager" CURRENT_TAG = "main" # XXX: Using https with `ba.open_url` seems to trigger a pop-up dialog box on @@ -36,6 +36,7 @@ "plugin_entry_points": re.compile(b"(ba_meta export plugin\n+class )(.*)\\("), "minigames": re.compile(b"(ba_meta export game\n+class )(.*)\\("), } +DISCORD_URL = "https://ballistica.net/discord" _CACHE = {} @@ -124,7 +125,6 @@ def setup_config(self): plugin_manager_config = ba.app.config.setdefault("Community Plugin Manager", {}) plugin_manager_config.setdefault("Custom Sources", []) installed_plugins = plugin_manager_config.setdefault("Installed Plugins", {}) - for plugin_name in tuple(installed_plugins.keys()): plugin = PluginLocal(plugin_name) if not plugin.is_installed: @@ -135,6 +135,7 @@ def setup_config(self): "Auto Update Plugin Manager": True, "Auto Update Plugins": True, "Auto Enable Plugins After Installation": True, + "Notify New Plugins": True } settings = plugin_manager_config.setdefault("Settings", {}) @@ -174,12 +175,34 @@ async def update_plugins(self): plugins_to_update.append(plugin.update()) await asyncio.gather(*plugins_to_update) + async def notify_new_plugins(self): + if not ba.app.config["Community Plugin Manager"]["Settings"]["Notify New Plugins"]: + return + + await self.plugin_manager.setup_index() + try: + num_of_plugins = ba.app.config["Community Plugin Manager"]["Existing Number of Plugins"] + except Exception: + ba.app.config["Community Plugin Manager"]["Existing Number of Plugins"] = len(await self.plugin_manager.categories["All"].get_plugins()) + num_of_plugins = ba.app.config["Community Plugin Manager"]["Existing Number of Plugins"] + ba.app.config.commit() + return + + new_num_of_plugins = len(await self.plugin_manager.categories["All"].get_plugins()) + + if num_of_plugins < new_num_of_plugins: + ba.screenmessage("We got new Plugins for you to try!") + ba.app.config["Community Plugin Manager"]["Existing Number of Plugins"] = new_num_of_plugins + ba.app.config.commit() + + async def execute(self): self.setup_config() try: await asyncio.gather( self.update_plugin_manager(), self.update_plugins(), + self.notify_new_plugins(), ) except urllib.error.URLError: pass @@ -1678,7 +1701,7 @@ async def draw_ui(self): scale=text_scale * 0.8) pos -= 34 * text_scale - pos = height - 220 + pos = height - 200 ba.textwidget(parent=self._root_widget, position=(width * 0.49, pos-5), size=(0, 0), @@ -1689,17 +1712,16 @@ async def draw_ui(self): color=color, maxwidth=width * 0.95) - pos -= 45 - ba.textwidget(parent=self._root_widget, - position=(width * 0.22, pos-5), - size=(0, 0), - h_align='center', - v_align='center', - text=f'API Version: {ba.app.api_version}', - scale=text_scale * 0.7, - color=(0.4, 0.8, 1), - maxwidth=width * 0.95) - pos -= 25 + pos -= 75 + ba.buttonwidget(parent=self._root_widget, + position=((width * 0.20) - button_size[0] / 2, pos), + size=button_size, + on_activate_call=lambda: ba.open_url(DISCORD_URL), + textcolor=b_text_color, + button_type='square', + text_scale=1, + label='Discord') + ba.buttonwidget(parent=self._root_widget, position=((width * 0.49) - button_size[0] / 2, pos), size=button_size, @@ -1756,6 +1778,16 @@ async def draw_ui(self): scale=text_scale * 0.8, color=text_color, maxwidth=width * 0.9) + pos -= 25 + ba.textwidget(parent=self._root_widget, + position=(width * 0.49, pos), + size=(0, 0), + h_align='center', + v_align='center', + text=f'API Version: {ba.app.api_version}', + scale=text_scale * 0.7, + color=(0.4, 0.8, 1), + maxwidth=width * 0.95) pos = height * 0.1 From 09991f7e796d04f7423522f7096b797d19ff7918 Mon Sep 17 00:00:00 2001 From: vishal332008 Date: Mon, 3 Oct 2022 17:02:09 +0000 Subject: [PATCH 0157/1464] [ci] auto-format --- plugin_manager.py | 1 - 1 file changed, 1 deletion(-) diff --git a/plugin_manager.py b/plugin_manager.py index f1697f17..eef9e53f 100644 --- a/plugin_manager.py +++ b/plugin_manager.py @@ -195,7 +195,6 @@ async def notify_new_plugins(self): ba.app.config["Community Plugin Manager"]["Existing Number of Plugins"] = new_num_of_plugins ba.app.config.commit() - async def execute(self): self.setup_config() try: From 8b12e00db6083536fee2d8068a1c9d72c0c5b49b Mon Sep 17 00:00:00 2001 From: vishal332008 Date: Mon, 3 Oct 2022 17:02:10 +0000 Subject: [PATCH 0158/1464] [ci] apply-version-metadata --- index.json | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/index.json b/index.json index 376c192e..bd993c49 100644 --- a/index.json +++ b/index.json @@ -1,7 +1,12 @@ { "plugin_manager_url": "http://github.com/bombsquad-community/plugin-manager/{content_type}/{tag}/plugin_manager.py", "versions": { - "0.1.7": null, + "0.1.7": { + "api_version": 7, + "commit_sha": "09991f7", + "released_on": "03-10-2022", + "md5sum": "283fdf4b1b16102d77b8b67615780d5d" + }, "0.1.6": { "api_version": 7, "commit_sha": "2a7ad8e", From 6f9fc4baaa1d63f114cce35a6376f9d21096b1a5 Mon Sep 17 00:00:00 2001 From: Rikko Date: Mon, 3 Oct 2022 22:35:47 +0530 Subject: [PATCH 0159/1464] Plugin index: Avoid making multiple network requests in parallel --- index.json | 9 ++------- plugin_manager.py | 12 ++++++++++-- 2 files changed, 12 insertions(+), 9 deletions(-) diff --git a/index.json b/index.json index bd993c49..bb9d90d5 100644 --- a/index.json +++ b/index.json @@ -1,12 +1,7 @@ { "plugin_manager_url": "http://github.com/bombsquad-community/plugin-manager/{content_type}/{tag}/plugin_manager.py", "versions": { - "0.1.7": { - "api_version": 7, - "commit_sha": "09991f7", - "released_on": "03-10-2022", - "md5sum": "283fdf4b1b16102d77b8b67615780d5d" - }, + "0.1.7": null, "0.1.6": { "api_version": 7, "commit_sha": "2a7ad8e", @@ -32,4 +27,4 @@ "http://github.com/bombsquad-community/plugin-manager/{content_type}/{tag}/plugins/maps.json" ], "external_source_url": "http://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 eef9e53f..618b1392 100644 --- a/plugin_manager.py +++ b/plugin_manager.py @@ -920,6 +920,7 @@ def __init__(self): self._index = _CACHE.get("index", {}) self.categories = {} self.module_path = sys.modules[__name__].__file__ + self._index_setup_in_progress = False async def get_index(self): if not self._index: @@ -932,13 +933,20 @@ async def get_index(self): headers=self.request_headers, ) response = await async_send_network_request(request) - self._index = json.loads(response.read()) - self.set_index_global_cache(self._index) + index = json.loads(response.read()) + self.set_index_global_cache(index) + self._index = index return self._index async def setup_index(self): + while self._index_setup_in_progress: + # Avoid making multiple network calls to the same resource in parallel. + # Rather wait for the previous network call to complete. + await asyncio.sleep(0.1) + self._index_setup_in_progress = not bool(self._index) index = await self.get_index() await self.setup_plugin_categories(index) + self._index_setup_in_progress = False async def setup_plugin_categories(self, plugin_index): # A hack to have the "All" category show at the top. From 3c2bde366de295e6fd503fa2efcd07196947216a Mon Sep 17 00:00:00 2001 From: rikkolovescats Date: Mon, 3 Oct 2022 17:06:37 +0000 Subject: [PATCH 0160/1464] [ci] apply-version-metadata --- index.json | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/index.json b/index.json index bb9d90d5..1a360cf4 100644 --- a/index.json +++ b/index.json @@ -1,7 +1,12 @@ { "plugin_manager_url": "http://github.com/bombsquad-community/plugin-manager/{content_type}/{tag}/plugin_manager.py", "versions": { - "0.1.7": null, + "0.1.7": { + "api_version": 7, + "commit_sha": "6f9fc4b", + "released_on": "03-10-2022", + "md5sum": "550215c42afa9b38bbc5e67bd0fc740f" + }, "0.1.6": { "api_version": 7, "commit_sha": "2a7ad8e", @@ -27,4 +32,4 @@ "http://github.com/bombsquad-community/plugin-manager/{content_type}/{tag}/plugins/maps.json" ], "external_source_url": "http://github.com/{repository}/{content_type}/{tag}/category.json" -} +} \ No newline at end of file From c5e478721afdd868416e4e650d394715b699e5d4 Mon Sep 17 00:00:00 2001 From: Rikko Date: Tue, 4 Oct 2022 06:42:40 +0530 Subject: [PATCH 0161/1464] Add meta entry --- plugins/utilities.json | 16 +++++++++++++++- ...ltra_Partywindow.py => ultra_party_window.py} | 0 2 files changed, 15 insertions(+), 1 deletion(-) rename plugins/utilities/{Updated_Ultra_Partywindow.py => ultra_party_window.py} (100%) diff --git a/plugins/utilities.json b/plugins/utilities.json index ae08b424..0ff51cab 100644 --- a/plugins/utilities.json +++ b/plugins/utilities.json @@ -208,6 +208,20 @@ "md5sum": "bbaee5f133b41d2eb53e3b726403a75e" } } + }, + "ultra_party_window": { + "description": "Ultra your party window with lots of features", + "external_url": "", + "authors": [ + { + "name": "Droopy", + "email": "", + "discord": "Droopy#3730" + } + ], + "versions": { + "4.0.0": null + } } } -} \ No newline at end of file +} diff --git a/plugins/utilities/Updated_Ultra_Partywindow.py b/plugins/utilities/ultra_party_window.py similarity index 100% rename from plugins/utilities/Updated_Ultra_Partywindow.py rename to plugins/utilities/ultra_party_window.py From 2fe966ccae50ec41d32329438113769dba3820e4 Mon Sep 17 00:00:00 2001 From: Rikko Date: Tue, 4 Oct 2022 06:50:42 +0530 Subject: [PATCH 0162/1464] https -> http https://github.com/bombsquad-community/plugin-manager/pull/48#discussion_r986313257 --- index.json | 9 ++------- plugin_manager.py | 2 +- 2 files changed, 3 insertions(+), 8 deletions(-) diff --git a/index.json b/index.json index 1a360cf4..bb9d90d5 100644 --- a/index.json +++ b/index.json @@ -1,12 +1,7 @@ { "plugin_manager_url": "http://github.com/bombsquad-community/plugin-manager/{content_type}/{tag}/plugin_manager.py", "versions": { - "0.1.7": { - "api_version": 7, - "commit_sha": "6f9fc4b", - "released_on": "03-10-2022", - "md5sum": "550215c42afa9b38bbc5e67bd0fc740f" - }, + "0.1.7": null, "0.1.6": { "api_version": 7, "commit_sha": "2a7ad8e", @@ -32,4 +27,4 @@ "http://github.com/bombsquad-community/plugin-manager/{content_type}/{tag}/plugins/maps.json" ], "external_source_url": "http://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 618b1392..e1db5b8a 100644 --- a/plugin_manager.py +++ b/plugin_manager.py @@ -36,7 +36,7 @@ "plugin_entry_points": re.compile(b"(ba_meta export plugin\n+class )(.*)\\("), "minigames": re.compile(b"(ba_meta export game\n+class )(.*)\\("), } -DISCORD_URL = "https://ballistica.net/discord" +DISCORD_URL = "http://ballistica.net/discord" _CACHE = {} From b1daa236ce0b8a4dc91fb888c1bc20cc12f84bb5 Mon Sep 17 00:00:00 2001 From: rikkolovescats Date: Tue, 4 Oct 2022 01:22:43 +0000 Subject: [PATCH 0163/1464] [ci] apply-version-metadata --- index.json | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/index.json b/index.json index bb9d90d5..e4e02ca9 100644 --- a/index.json +++ b/index.json @@ -1,7 +1,12 @@ { "plugin_manager_url": "http://github.com/bombsquad-community/plugin-manager/{content_type}/{tag}/plugin_manager.py", "versions": { - "0.1.7": null, + "0.1.7": { + "api_version": 7, + "commit_sha": "2fe966c", + "released_on": "04-10-2022", + "md5sum": "78d7a6b3a62f8920d0da0acab20b419a" + }, "0.1.6": { "api_version": 7, "commit_sha": "2a7ad8e", @@ -27,4 +32,4 @@ "http://github.com/bombsquad-community/plugin-manager/{content_type}/{tag}/plugins/maps.json" ], "external_source_url": "http://github.com/{repository}/{content_type}/{tag}/category.json" -} +} \ No newline at end of file From 12c0fa40ec6ac8cbfb73ccc897a32e7ff0b1a2fa Mon Sep 17 00:00:00 2001 From: rikkolovescats Date: Tue, 4 Oct 2022 01:30:32 +0000 Subject: [PATCH 0164/1464] [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 0ff51cab..bbab31a7 100644 --- a/plugins/utilities.json +++ b/plugins/utilities.json @@ -220,8 +220,13 @@ } ], "versions": { - "4.0.0": null + "4.0.0": { + "api_version": 7, + "commit_sha": "a23e8cd", + "released_on": "04-10-2022", + "md5sum": "7da7fae6ddf2560789bbef56f4ff5bd6" + } } } } -} +} \ No newline at end of file From 430da49b8a4a5370bcff78a9551210801f6d36c9 Mon Sep 17 00:00:00 2001 From: Rikko Date: Tue, 4 Oct 2022 07:12:12 +0530 Subject: [PATCH 0165/1464] Save settings, always show party icon --- plugins/utilities.json | 11 +++-------- plugins/utilities/mood_light.py | 2 ++ 2 files changed, 5 insertions(+), 8 deletions(-) diff --git a/plugins/utilities.json b/plugins/utilities.json index e591efa6..2c0698f5 100644 --- a/plugins/utilities.json +++ b/plugins/utilities.json @@ -4,7 +4,7 @@ "plugins_base_url": "http://github.com/bombsquad-community/plugin-manager/{content_type}/{tag}/plugins/utilities", "plugins": { "mood_light": { - "description": "mood lighting in co-op games", + "description": "Dynamic lighting in co-op games (adjustable using \"cm\" chat command)", "external_url": "", "authors": [ { @@ -14,12 +14,7 @@ } ], "versions": { - "1.0.0": { - "api_version": 7, - "commit_sha": "2594105", - "released_on": "30-09-2022", - "md5sum": "131585e571e9d4d60d40bbf7cbbd69e9" - } + "1.0.0": null } }, "colorscheme": { @@ -229,4 +224,4 @@ } } } -} \ No newline at end of file +} diff --git a/plugins/utilities/mood_light.py b/plugins/utilities/mood_light.py index 0c158eeb..496aefe5 100644 --- a/plugins/utilities/mood_light.py +++ b/plugins/utilities/mood_light.py @@ -189,6 +189,7 @@ def draw_ui(self): def save_settings(self): ba.app.config["moodlightingSettings"] = (Ldefault, Udefault) + ba.app.config.commit() Print("settings saved") self.close() @@ -212,6 +213,7 @@ def new_chat_message(msg: Union[str, ba.Lstr], clients: Sequence[int] = None, se old_fcm = _ba.chatmessage _ba.chatmessage = new_chat_message +_ba.set_party_icon_always_visible(True) # ba_meta export plugin From e02f430f07170ee4d9a5d7e7dceebb9e3e95de8b Mon Sep 17 00:00:00 2001 From: rikkolovescats Date: Tue, 4 Oct 2022 01:43:07 +0000 Subject: [PATCH 0166/1464] [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 2c0698f5..b8249c62 100644 --- a/plugins/utilities.json +++ b/plugins/utilities.json @@ -14,7 +14,12 @@ } ], "versions": { - "1.0.0": null + "1.0.0": { + "api_version": 7, + "commit_sha": "430da49", + "released_on": "04-10-2022", + "md5sum": "ca3407db8509eda577643c0490789571" + } } }, "colorscheme": { @@ -224,4 +229,4 @@ } } } -} +} \ No newline at end of file From b48b8513ab052ff270105e8a35399708833b49e2 Mon Sep 17 00:00:00 2001 From: Rikko Date: Tue, 4 Oct 2022 08:01:39 +0530 Subject: [PATCH 0167/1464] Oopsie, it's ml, not cm --- plugins/utilities.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/plugins/utilities.json b/plugins/utilities.json index e8b5af83..3e29cd4a 100644 --- a/plugins/utilities.json +++ b/plugins/utilities.json @@ -4,7 +4,7 @@ "plugins_base_url": "http://github.com/bombsquad-community/plugin-manager/{content_type}/{tag}/plugins/utilities", "plugins": { "mood_light": { - "description": "Dynamic lighting in co-op games (adjustable using \"cm\" chat command)", + "description": "Dynamic lighting in co-op games (adjustable using \"ml\" chat command)", "external_url": "", "authors": [ { @@ -248,4 +248,4 @@ } } } -} \ No newline at end of file +} From e6e984397a93e29f42f7b21f2e544190f1a9032e Mon Sep 17 00:00:00 2001 From: rikkolovescats Date: Tue, 4 Oct 2022 02:32:24 +0000 Subject: [PATCH 0168/1464] [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 3e29cd4a..6d65e740 100644 --- a/plugins/utilities.json +++ b/plugins/utilities.json @@ -248,4 +248,4 @@ } } } -} +} \ No newline at end of file From 8868902bb75efa1593c180511ae36f340ddc8557 Mon Sep 17 00:00:00 2001 From: Loup <90267658+Loup-Garou911XD@users.noreply.github.com> Date: Tue, 4 Oct 2022 13:47:59 +0530 Subject: [PATCH 0169/1464] Added disable button --- plugins/utilities/mood_light.py | 103 ++++++++++++++++++++++---------- 1 file changed, 71 insertions(+), 32 deletions(-) diff --git a/plugins/utilities/mood_light.py b/plugins/utilities/mood_light.py index 496aefe5..b9870437 100644 --- a/plugins/utilities/mood_light.py +++ b/plugins/utilities/mood_light.py @@ -2,8 +2,7 @@ from __future__ import annotations from typing import TYPE_CHECKING, cast -import ba -import _ba +import ba,_ba import random from ba._map import Map from bastd import mainmenu @@ -21,11 +20,19 @@ def Print(arg1, arg2="", arg3=""): try: - Ldefault, Udefault = ba.app.config.get("moodlightingSettings") + Ldefault, Udefault=ba.app.config.get("moodlightingSettings") except: - ba.app.config["moodlightingSettings"] = (15, 20) - Ldefault, Udefault = ba.app.config.get("moodlightingSettings") - Print("settings up moodlight") + ba.app.config["moodlightingSettings"]=(15,20) + Ldefault, Udefault=ba.app.config.get("moodlightingSettings") + Print("settings up moodlight") + Print("Type ml in chat or use plugin manager to access settings") + +try: + loop=ba.app.config.get("moodlightEnabled") +except: + ba.app.config["moodlightEnabled"]=True + ba.app.config.commit() + class SettingWindow(ba.Window): @@ -95,6 +102,15 @@ def draw_ui(self): v_align="center", text="Mood light settings", color=(0, 1, 0)) + + self.enable_button=ba.buttonwidget( + parent=self._root_widget, + position=(100, 470), + size=(90, 70), + scale=1.5, + color=(1,0,0) if loop else (0,1,0), + label="DISABLE" if loop else "ENABLE", + on_activate_call=self.on_enableButton_press) increase_button = ba.buttonwidget( parent=self._root_widget, @@ -172,8 +188,7 @@ def draw_ui(self): scale=2, color=(1, 0.2, 0.2), extra_touch_border_scale=5, - on_activate_call=self.close, - button_type="square") + on_activate_call=self.close) save_button = ba.buttonwidget( parent=self._root_widget, @@ -181,14 +196,29 @@ def draw_ui(self): size=(90, 70), scale=1.5, label="SAVE", - button_type="square", - on_activate_call=self.save_settings) + on_activate_call=self.save_settings) ba.textwidget(edit=self.upper_text, on_activate_call=ba.Call(self.on_text_click, "upper")) ba.textwidget(edit=self.lower_text, on_activate_call=ba.Call(self.on_text_click, "lower")) - + + def on_enableButton_press(self): + global loop + loop=ba.app.config.get("moodlightEnabled") + if loop: + loop=False + label="ENABLE" + color=(0,1,0) + elif not loop: + loop=True + label="DISABLE" + color=(1,0,0) + + ba.app.config["moodlightEnabled"]=loop + ba.app.config.commit() + ba.buttonwidget(edit=self.enable_button,label=label,color=color) + def save_settings(self): - ba.app.config["moodlightingSettings"] = (Ldefault, Udefault) + ba.app.config["moodlightingSettings"]=(Ldefault,Udefault) ba.app.config.commit() Print("settings saved") self.close() @@ -196,24 +226,20 @@ def save_settings(self): def close(self): ba.containerwidget(edit=self._root_widget, transition="out_right",) - Map._old_init = Map.__init__ - -def new_chat_message(msg: Union[str, ba.Lstr], clients: Sequence[int] = None, sender_override: str = None): +def new_chat_message(msg: Union[str, ba.Lstr], clients:Sequence[int] = None, sender_override: str = None): old_fcm(msg, clients, sender_override) if msg == 'ml': try: - Ldefault, Udefault = ba.app.config.get("moodlightingSettings") + Ldefault, Udefault=ba.app.config.get("moodlightingSettings") SettingWindow() - _ba.chatmessage("Mood light settings opened") + _ba.chatmessage("Mood light settings opened") except Exception as err: Print(err) - old_fcm = _ba.chatmessage _ba.chatmessage = new_chat_message -_ba.set_party_icon_always_visible(True) # ba_meta export plugin @@ -221,30 +247,43 @@ def new_chat_message(msg: Union[str, ba.Lstr], clients: Sequence[int] = None, se class moodlight(ba.Plugin): def __init__(self): pass - + def on_app_running(self): try: + _ba.show_progress_bar() + pass except Exception as err: Print(err) - def on_plugin_manager_prompt(self): + def on_plugin_manager_prompt(self):#called by plugin manager SettingWindow() def _new_init(self, vr_overlay_offset: Optional[Sequence[float]] = None) -> None: self._old_init(vr_overlay_offset) - in_game = not isinstance(_ba.get_foreground_host_session(), mainmenu.MainMenuSession) + in_game = not isinstance(_ba.get_foreground_host_session(), mainmenu.MainMenuSession) if not in_game: return - + gnode = _ba.getactivity().globalsnode - - def changetint(): - Range = (random.randrange(Ldefault, Udefault)/10, random.randrange(Ldefault, - Udefault)/10, random.randrange(Ldefault, Udefault)/10) - ba.animate_array(gnode, 'tint', 3, { - 0.0: gnode.tint, - 1.0: Range - }) - _ba.timer(0.3, changetint, repeat=True) + default_tint=(1.100000023841858, 1.0, 0.8999999761581421) + transition_duration=1.0#for future improvements + + def changetint(): + if loop: + Range = (random.randrange(Ldefault, Udefault)/10, random.randrange(Ldefault, + Udefault)/10, random.randrange(Ldefault, Udefault)/10) + ba.animate_array(gnode, 'tint', 3 ,{ + 0.0: gnode.tint, + transition_duration: Range + }) + else: + global timer + timer=None + ba.animate_array(gnode,"tint",3, {0.0:gnode.tint,0.4:default_tint}) + + global timer + timer=ba.Timer(0.3, changetint, repeat=True) + Map.__init__ = _new_init + From cd9658c4dd836ac12c5ff779360260b3f5368580 Mon Sep 17 00:00:00 2001 From: Loup <90267658+Loup-Garou911XD@users.noreply.github.com> Date: Tue, 4 Oct 2022 22:41:05 +0530 Subject: [PATCH 0170/1464] Quality of life improvements --- plugins/utilities/mood_light.py | 160 +++++++++++++++++++------------- 1 file changed, 93 insertions(+), 67 deletions(-) diff --git a/plugins/utilities/mood_light.py b/plugins/utilities/mood_light.py index b9870437..7807d51d 100644 --- a/plugins/utilities/mood_light.py +++ b/plugins/utilities/mood_light.py @@ -1,6 +1,8 @@ # 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 import ba,_ba import random @@ -9,14 +11,31 @@ from bastd.ui.party import PartyWindow from bastd.gameutils import SharedObjects from time import sleep -if TYPE_CHECKING: - from typing import Any, Sequence, Callable, List, Dict, Tuple, Optional, Union - -# mood light plugin by ʟօʊքɢǟʀօʊ - -def Print(arg1, arg2="", arg3=""): - ba.screenmessage(str(arg1)+str(arg2)+str(arg3)) +"""mood light plugin by ʟօʊքɢǟʀօʊ +type ml in chat or use plugin manager to open settings""" + +def Print(*args): + out=" ".join(args) + ba.screenmessage(out) + +def cprint(*args): + out="\n".join(args) + _ba.chatmessage(out) +# +#class printerr:#for debugging +# #def __init__(self): +# global errcounter +# errcounter=1 +# def __enter__(self): +# _ba.chatmessage("executing") +# +# def __exit__(self, exc_type, exc_value, exc_tb): +# cprint(exc_type, exc_value, exc_tb) +# if not(exc_type==None): +# cprint(exc_type, exc_value, exc_tb) +# else: +# cprint("Executed sucessfully","No error") try: @@ -32,6 +51,7 @@ def Print(arg1, arg2="", arg3=""): except: ba.app.config["moodlightEnabled"]=True ba.app.config.commit() + loop=True @@ -98,6 +118,7 @@ def draw_ui(self): size=(200, 100), position=(150, 550), scale=2, + selectable=False, h_align="center", v_align="center", text="Mood light settings", @@ -111,24 +132,26 @@ def draw_ui(self): color=(1,0,0) if loop else (0,1,0), label="DISABLE" if loop else "ENABLE", on_activate_call=self.on_enableButton_press) - - increase_button = ba.buttonwidget( + + + save_button = ba.buttonwidget( parent=self._root_widget, - position=(600, 100), - size=(5, 1), - scale=3.5, - extra_touch_border_scale=2.5, - icon=ba.gettexture("upButton"), - on_activate_call=self.increase_limit) - - decrease_button = ba.buttonwidget( + position=(520, 470), + size=(90, 70), + scale=1.5, + label="SAVE", + on_activate_call=self.save_settings) + + self.close_button = ba.buttonwidget( parent=self._root_widget, - position=(100, 100), - size=(5, 1), - scale=3.5, - extra_touch_border_scale=2.5, - icon=ba.gettexture("downButton"), - on_activate_call=self.decrease_limit) + position=(550, 590), + size=(35, 35), + icon=ba.gettexture("crossOut"), + icon_color=(1, 0.2, 0.2), + scale=2, + color=(1, 0.2, 0.2), + extra_touch_border_scale=5, + on_activate_call=self.close) self.lower_text = ba.textwidget( parent=self._root_widget, @@ -169,6 +192,24 @@ def draw_ui(self): h_align="center", v_align="center", text="Limit brightness") + + decrease_button = ba.buttonwidget( + parent=self._root_widget, + position=(100, 100), + size=(5, 1), + scale=3.5, + extra_touch_border_scale=2.5, + icon=ba.gettexture("downButton"), + on_activate_call=self.decrease_limit) + + increase_button = ba.buttonwidget( + parent=self._root_widget, + position=(600, 100), + size=(5, 1), + scale=3.5, + extra_touch_border_scale=2.5, + icon=ba.gettexture("upButton"), + on_activate_call=self.increase_limit) self.warn_text = ba.textwidget( parent=self._root_widget, @@ -177,27 +218,18 @@ def draw_ui(self): position=(150, 300), h_align="center", v_align="center", - maxwidth=600) - - self.close_button = ba.buttonwidget( - parent=self._root_widget, - position=(550, 590), - size=(35, 35), - icon=ba.gettexture("crossOut"), - icon_color=(1, 0.2, 0.2), - scale=2, - color=(1, 0.2, 0.2), - extra_touch_border_scale=5, - on_activate_call=self.close) - - save_button = ba.buttonwidget( - parent=self._root_widget, - position=(520, 470), - size=(90, 70), - scale=1.5, - label="SAVE", - on_activate_call=self.save_settings) - + maxwidth=600) + +#++++++++++++++++for keyboard navigation++++++++++++++++ + ba.widget(edit=self.enable_button,up_widget=decrease_button,down_widget=self.lower_text,left_widget=save_button,right_widget=save_button) + ba.widget(edit=save_button,up_widget=self.close_button,down_widget=self.upper_text,left_widget=self.enable_button,right_widget=self.enable_button) + ba.widget(edit=self.close_button,up_widget=increase_button,down_widget=save_button,left_widget=self.enable_button,right_widget=save_button) + ba.widget(edit=self.lower_text,up_widget=self.enable_button,down_widget=decrease_button,left_widget=self.upper_text,right_widget=self.upper_text) + ba.widget(edit=self.upper_text,up_widget=save_button,down_widget=increase_button,left_widget=self.lower_text,right_widget=self.lower_text) + ba.widget(edit=decrease_button,up_widget=self.lower_text,down_widget=self.enable_button,left_widget=increase_button,right_widget=increase_button) + ba.widget(edit=increase_button,up_widget=self.upper_text,down_widget=self.close_button,left_widget=decrease_button,right_widget=decrease_button) +#-------------------------------------------------------------------------------------------------- + ba.textwidget(edit=self.upper_text, on_activate_call=ba.Call(self.on_text_click, "upper")) ba.textwidget(edit=self.lower_text, on_activate_call=ba.Call(self.on_text_click, "lower")) @@ -210,9 +242,9 @@ def on_enableButton_press(self): color=(0,1,0) elif not loop: loop=True - label="DISABLE" + label="DISABLE" color=(1,0,0) - + Print("Restart level to enable") ba.app.config["moodlightEnabled"]=loop ba.app.config.commit() ba.buttonwidget(edit=self.enable_button,label=label,color=color) @@ -226,39 +258,33 @@ def save_settings(self): def close(self): ba.containerwidget(edit=self._root_widget, transition="out_right",) -Map._old_init = Map.__init__ - def new_chat_message(msg: Union[str, ba.Lstr], clients:Sequence[int] = None, sender_override: str = None): - old_fcm(msg, clients, sender_override) - if msg == 'ml': - try: - Ldefault, Udefault=ba.app.config.get("moodlightingSettings") - SettingWindow() - _ba.chatmessage("Mood light settings opened") - except Exception as err: - Print(err) - + old_fcm(msg, clients, sender_override) + if msg == 'ml': + try: + Ldefault, Udefault=ba.app.config.get("moodlightingSettings") + SettingWindow() + cprint("Mood light settings opened") + except Exception as err: + Print(err) + old_fcm = _ba.chatmessage _ba.chatmessage = new_chat_message - +_ba.set_party_icon_always_visible(True) +Map._old_init = Map.__init__ + # ba_meta export plugin - class moodlight(ba.Plugin): def __init__(self): pass def on_app_running(self): - try: _ba.show_progress_bar() - pass - except Exception as err: - Print(err) - def on_plugin_manager_prompt(self):#called by plugin manager - SettingWindow() - + SettingWindow() + def _new_init(self, vr_overlay_offset: Optional[Sequence[float]] = None) -> None: self._old_init(vr_overlay_offset) in_game = not isinstance(_ba.get_foreground_host_session(), mainmenu.MainMenuSession) @@ -269,7 +295,7 @@ def _new_init(self, vr_overlay_offset: Optional[Sequence[float]] = None) -> None default_tint=(1.100000023841858, 1.0, 0.8999999761581421) transition_duration=1.0#for future improvements - def changetint(): + def changetint(): if loop: Range = (random.randrange(Ldefault, Udefault)/10, random.randrange(Ldefault, Udefault)/10, random.randrange(Ldefault, Udefault)/10) From 46645a6aadc254ab8df26db6a2ba6017f4722ce8 Mon Sep 17 00:00:00 2001 From: Ayush Saini <36878972+imayushsaini@users.noreply.github.com> Date: Wed, 5 Oct 2022 21:36:29 +0530 Subject: [PATCH 0171/1464] added character chooser and builder --- plugins/utilities.json | 34 +- plugins/utilities/character_chooser.py | 360 +++++++++++++++++ plugins/utilities/character_maker.py | 538 +++++++++++++++++++++++++ 3 files changed, 929 insertions(+), 3 deletions(-) create mode 100644 plugins/utilities/character_chooser.py create mode 100644 plugins/utilities/character_maker.py diff --git a/plugins/utilities.json b/plugins/utilities.json index 6d65e740..b5420137 100644 --- a/plugins/utilities.json +++ b/plugins/utilities.json @@ -133,7 +133,7 @@ "authors": [ { "name": "Mr.Smoothy", - "email": "", + "email": "smoothy@bombsquad.ga", "discord": "mr.smoothy#5824" } ], @@ -158,7 +158,7 @@ "authors": [ { "name": "Mr.Smoothy", - "email": "smoothyt@bombsquad.ga", + "email": "smoothy@bombsquad.ga", "discord": "mr.smoothy#5824" } ], @@ -177,7 +177,7 @@ "authors": [ { "name": "Mr.Smoothy", - "email": "smoothyt@bombsquad.ga", + "email": "smoothy@bombsquad.ga", "discord": "mr.smoothy#5824" } ], @@ -190,6 +190,34 @@ } } }, + "character_chooser": { + "description": "Let you choose your character before joining game.", + "external_url": "https://www.youtube.com/watch?v=hNmv2l-NahE", + "authors": [ + { + "name": "Mr.Smoothy", + "email": "smoothy@bombsquad.ga", + "discord": "mr.smoothy#5824" + } + ], + "versions": { + "1.0.0": null + } + }, + "character_builder": { + "description": "Make new characters by manipulating models and textures.", + "external_url": "https://www.youtube.com/watch?v=q0KxY1hfMPQ", + "authors": [ + { + "name": "Mr.Smoothy", + "email": "smoothy@bombsquad.ga", + "discord": "mr.smoothy#5824" + } + ], + "versions": { + "1.0.0": null + } + }, "icons_keyboard": { "description": "Enable 'Always Use Internal Keyboard' in Settings>Advanced. Double tap space-bar to change keyboards", "external_url": "", diff --git a/plugins/utilities/character_chooser.py b/plugins/utilities/character_chooser.py new file mode 100644 index 00000000..388479eb --- /dev/null +++ b/plugins/utilities/character_chooser.py @@ -0,0 +1,360 @@ +# ba_meta require api 7 + +''' +Character Chooser by Mr.Smoothy + +This plugin will let you choose your character from lobby. + +Install this plugin on your Phone/PC or on Server + +If installed on server :- this will also let players choose server specific custom characters . so no more sharing of character file with all players, +just install this plugin on server ...and players can pick character from lobby . + +Use:- +> select your profile (focus on color and name) +> press ready (punch) +> now use UP/DOWN buttons to scroll character list +> Press ready again (punch) to join the game +> or press Bomb button to go back to profile choosing menu +> END + +Watch : https://www.youtube.com/watch?v=hNmv2l-NahE +Join : https://discord.gg/ucyaesh +Contact : discord mr.smoothy#5824 + + +Share this plugin with your server owner /admins to use it online + + :) + +''' + + +from __future__ import annotations + +from typing import TYPE_CHECKING + +import ba,_ba +from bastd.actor.playerspaz import PlayerSpaz + + +from ba._error import print_exception, print_error, NotFoundError +from ba._gameutils import animate, animate_array +from ba._language import Lstr +from ba._generated.enums import SpecialChar, InputType +from ba._profile import get_player_profile_colors +if TYPE_CHECKING: + from typing import Any, Type, List, Dict, Tuple, Union, Sequence, Optional +import weakref +import os,json +from ba import _lobby +from bastd.actor.spazappearance import * +from ba._lobby import ChangeMessage +from ba._lobby import PlayerReadyMessage + +def __init__(self, vpos: float, sessionplayer: _ba.SessionPlayer, + lobby: 'Lobby') -> None: + self._deek_sound = _ba.getsound('deek') + self._click_sound = _ba.getsound('click01') + self._punchsound = _ba.getsound('punch01') + self._swish_sound = _ba.getsound('punchSwish') + self._errorsound = _ba.getsound('error') + self._mask_texture = _ba.gettexture('characterIconMask') + self._vpos = vpos + self._lobby = weakref.ref(lobby) + self._sessionplayer = sessionplayer + self._inited = False + self._dead = False + self._text_node: Optional[ba.Node] = None + self._profilename = '' + self._profilenames: List[str] = [] + self._ready: bool = False + self._character_names: List[str] = [] + self._last_change: Sequence[Union[float, int]] = (0, 0) + self._profiles: Dict[str, Dict[str, Any]] = {} + + app = _ba.app + + self.bakwas_chars=["Lee","Todd McBurton","Zola","Butch","Witch","warrior","Middle-Man","Alien","OldLady","Gladiator","Wrestler","Gretel","Robot"] + + # Load available player profiles either from the local config or + # from the remote device. + self.reload_profiles() + for name in _ba.app.spaz_appearances: + if name not in self._character_names and name not in self.bakwas_chars: + self._character_names.append(name) + # Note: this is just our local index out of available teams; *not* + # the team-id! + self._selected_team_index: int = self.lobby.next_add_team + + # Store a persistent random character index and colors; we'll use this + # for the '_random' profile. Let's use their input_device id to seed + # it. This will give a persistent character for them between games + # and will distribute characters nicely if everyone is random. + self._random_color, self._random_highlight = ( + get_player_profile_colors(None)) + + # To calc our random character we pick a random one out of our + # unlocked list and then locate that character's index in the full + # list. + char_index_offset = app.lobby_random_char_index_offset + self._random_character_index = ( + (sessionplayer.inputdevice.id + char_index_offset) % + len(self._character_names)) + + # Attempt to set an initial profile based on what was used previously + # for this input-device, etc. + self._profileindex = self._select_initial_profile() + self._profilename = self._profilenames[self._profileindex] + + self._text_node = _ba.newnode('text', + delegate=self, + attrs={ + 'position': (-100, self._vpos), + 'maxwidth': 190, + 'shadow': 0.5, + 'vr_depth': -20, + 'h_align': 'left', + 'v_align': 'center', + 'v_attach': 'top' + }) + animate(self._text_node, 'scale', {0: 0, 0.1: 1.0}) + self.icon = _ba.newnode('image', + owner=self._text_node, + attrs={ + 'position': (-130, self._vpos + 20), + 'mask_texture': self._mask_texture, + 'vr_depth': -10, + 'attach': 'topCenter' + }) + + animate_array(self.icon, 'scale', 2, {0: (0, 0), 0.1: (45, 45)}) + + # Set our initial name to '' in case anyone asks. + self._sessionplayer.setname( + Lstr(resource='choosingPlayerText').evaluate(), real=False) + + # Init these to our rando but they should get switched to the + # selected profile (if any) right after. + self._character_index = self._random_character_index + self._color = self._random_color + self._highlight = self._random_highlight + self.characterchooser=False + self.update_from_profile() + self.update_position() + self._inited = True + + self._set_ready(False) + + + + +def _set_ready(self, ready: bool) -> None: + + # pylint: disable=cyclic-import + from bastd.ui.profile import browser as pbrowser + from ba._general import Call + profilename = self._profilenames[self._profileindex] + + # Handle '_edit' as a special case. + if profilename == '_edit' and ready: + with _ba.Context('ui'): + pbrowser.ProfileBrowserWindow(in_main_menu=False) + + # Give their input-device UI ownership too + # (prevent someone else from snatching it in crowded games) + _ba.set_ui_input_device(self._sessionplayer.inputdevice) + return + + if ready==False: + self._sessionplayer.assigninput( + InputType.LEFT_PRESS, + Call(self.handlemessage, ChangeMessage('team', -1))) + self._sessionplayer.assigninput( + InputType.RIGHT_PRESS, + Call(self.handlemessage, ChangeMessage('team', 1))) + self._sessionplayer.assigninput( + InputType.BOMB_PRESS, + Call(self.handlemessage, ChangeMessage('character', 1))) + self._sessionplayer.assigninput( + InputType.UP_PRESS, + Call(self.handlemessage, ChangeMessage('profileindex', -1))) + self._sessionplayer.assigninput( + InputType.DOWN_PRESS, + Call(self.handlemessage, ChangeMessage('profileindex', 1))) + self._sessionplayer.assigninput( + (InputType.JUMP_PRESS, InputType.PICK_UP_PRESS, + InputType.PUNCH_PRESS), + Call(self.handlemessage, ChangeMessage('ready', 1))) + self._ready = False + self._update_text() + self._sessionplayer.setname('untitled', real=False) + elif ready == True: + self.characterchooser=True + self._sessionplayer.assigninput( + (InputType.LEFT_PRESS, InputType.RIGHT_PRESS, + InputType.UP_PRESS, InputType.DOWN_PRESS, + InputType.JUMP_PRESS, InputType.BOMB_PRESS, + InputType.PICK_UP_PRESS), self._do_nothing) + self._sessionplayer.assigninput( + (InputType.UP_PRESS),Call(self.handlemessage,ChangeMessage('characterchooser',-1))) + self._sessionplayer.assigninput( + (InputType.DOWN_PRESS),Call(self.handlemessage,ChangeMessage('characterchooser',1))) + self._sessionplayer.assigninput( + (InputType.BOMB_PRESS),Call(self.handlemessage,ChangeMessage('ready',0))) + + self._sessionplayer.assigninput( + (InputType.JUMP_PRESS,InputType.PICK_UP_PRESS, InputType.PUNCH_PRESS), + Call(self.handlemessage, ChangeMessage('ready', 2))) + + # Store the last profile picked by this input for reuse. + input_device = self._sessionplayer.inputdevice + name = input_device.name + unique_id = input_device.unique_identifier + device_profiles = _ba.app.config.setdefault( + 'Default Player Profiles', {}) + + # Make an exception if we have no custom profiles and are set + # to random; in that case we'll want to start picking up custom + # profiles if/when one is made so keep our setting cleared. + special = ('_random', '_edit', '__account__') + have_custom_profiles = any(p not in special + for p in self._profiles) + + profilekey = name + ' ' + unique_id + if profilename == '_random' and not have_custom_profiles: + if profilekey in device_profiles: + del device_profiles[profilekey] + else: + device_profiles[profilekey] = profilename + _ba.app.config.commit() + + # Set this player's short and full name. + self._sessionplayer.setname(self._getname(), + self._getname(full=True), + real=True) + self._ready = True + self._update_text() + else: + + + + # Inform the session that this player is ready. + _ba.getsession().handlemessage(PlayerReadyMessage(self)) + + +def handlemessage(self, msg: Any) -> Any: + """Standard generic message handler.""" + + if isinstance(msg, ChangeMessage): + self._handle_repeat_message_attack() + + # If we've been removed from the lobby, ignore this stuff. + if self._dead: + print_error('chooser got ChangeMessage after dying') + return + + if not self._text_node: + print_error('got ChangeMessage after nodes died') + return + if msg.what=='characterchooser': + _ba.playsound(self._click_sound) + # update our index in our local list of characters + self._character_index = ((self._character_index + msg.value) % + len(self._character_names)) + self._update_text() + self._update_icon() + + if msg.what == 'team': + sessionteams = self.lobby.sessionteams + if len(sessionteams) > 1: + _ba.playsound(self._swish_sound) + self._selected_team_index = ( + (self._selected_team_index + msg.value) % + len(sessionteams)) + self._update_text() + self.update_position() + self._update_icon() + + elif msg.what == 'profileindex': + if len(self._profilenames) == 1: + + # This should be pretty hard to hit now with + # automatic local accounts. + _ba.playsound(_ba.getsound('error')) + else: + + # Pick the next player profile and assign our name + # and character based on that. + _ba.playsound(self._deek_sound) + self._profileindex = ((self._profileindex + msg.value) % + len(self._profilenames)) + self.update_from_profile() + + elif msg.what == 'character': + _ba.playsound(self._click_sound) + self.characterchooser=True + # update our index in our local list of characters + self._character_index = ((self._character_index + msg.value) % + len(self._character_names)) + self._update_text() + self._update_icon() + + elif msg.what == 'ready': + self._handle_ready_msg(msg.value) + +def _update_text(self) -> None: + assert self._text_node is not None + if self._ready: + + # Once we're ready, we've saved the name, so lets ask the system + # for it so we get appended numbers and stuff. + text = Lstr(value=self._sessionplayer.getname(full=True)) + if self.characterchooser: + text = Lstr(value='${A}\n${B}', + subs=[('${A}', text), + ('${B}', Lstr(value=""+self._character_names[self._character_index]))]) + self._text_node.scale=0.8 + else: + text = Lstr(value='${A} (${B})', + subs=[('${A}', text), + ('${B}', Lstr(resource='readyText'))]) + else: + text = Lstr(value=self._getname(full=True)) + self._text_node.scale=1.0 + + can_switch_teams = len(self.lobby.sessionteams) > 1 + + # Flash as we're coming in. + fin_color = _ba.safecolor(self.get_color()) + (1, ) + if not self._inited: + animate_array(self._text_node, 'color', 4, { + 0.15: fin_color, + 0.25: (2, 2, 2, 1), + 0.35: fin_color + }) + else: + + # Blend if we're in teams mode; switch instantly otherwise. + if can_switch_teams: + animate_array(self._text_node, 'color', 4, { + 0: self._text_node.color, + 0.1: fin_color + }) + else: + self._text_node.color = fin_color + + self._text_node.text = text + +# ba_meta export plugin +class HeySmoothy(ba.Plugin): + + def __init__(self): + _lobby.Chooser.__init__=__init__ + _lobby.Chooser._set_ready=_set_ready + + _lobby.Chooser._update_text=_update_text + _lobby.Chooser.handlemessage=handlemessage + + + diff --git a/plugins/utilities/character_maker.py b/plugins/utilities/character_maker.py new file mode 100644 index 00000000..f69d9092 --- /dev/null +++ b/plugins/utilities/character_maker.py @@ -0,0 +1,538 @@ +# Released under the MIT License. See LICENSE for details. + + +''' +Character Builder/Maker by Mr.Smoothy +Plugin helps to mix character models and textures in interactive way. + +Watch tutorial : https://www.youtube.com/c/HeySmoothy +Join discord: https://discord.gg/ucyaesh for help +https://github.com/imayushsaini/Bombsquad-Ballistica-Modded-Server/ + +> create team playlist and add character maker mini game +> Use export command to save character +> Character will be saved in CustomCharacter folder inside Bombsquad Mods folder + +*Only one player in that mini game supported ... + +Characters can be used offline or online +for online you need to share character file with server owners. + +*For server owners:_ + You might know what to do with that file, + Still , + refer code after line 455 in this file , add it as a plugin to import characters from json file. + +*For modders:- + You can add more models and texture , check line near 400 and add asset names , you can also modify sounds and icon in json file (optional) . + +To share your character with friends , + send them character .json file and tell them to put file in same location i.e Bombsquad/CustomCharacter or for PC appdata/Local/Bombsquad/Mods/CustomCharacter + this plugin should be installed on their device too + +Dont forget to share your creativity with me , +send your character screenshot discord: mr.smoothy#5824 https://discord.gg/ucyaesh + +Register your character in above discord server , so other server owners can add your characters. + + +Released on 28 May 2021 + + +Update 2 june : use import +''' + + +# ba_meta require api 7 + + +from __future__ import annotations + +from typing import TYPE_CHECKING + +import ba,_ba +from bastd.actor.playerspaz import PlayerSpaz +from bastd.actor.scoreboard import Scoreboard + +if TYPE_CHECKING: + from typing import Any, Type, List, Dict, Tuple, Union, Sequence, Optional + +import os,json +from bastd.actor.spazappearance import * +spazoutfit={ + "color_mask":"neoSpazColorMask", + "color_texture":"neoSpazColor", + "head":"neoSpazHead", + "hand":"neoSpazHand", + "torso":"neoSpazTorso", + "pelvis":"neoSpazTorso", + "upper_arm":"neoSpazUpperArm", + "forearm":"neoSpazForeArm", + "upper_leg":"neoSpazUpperLeg", + "lower_leg":"neoSpazLowerLeg", + "toes_model":"neoSpazToes", + "jump_sounds":['spazJump01', 'spazJump02', 'spazJump03', 'spazJump04'], + "attack_sounds":['spazAttack01', 'spazAttack02', 'spazAttack03', 'spazAttack04'], + "impact_sounds":['spazImpact01', 'spazImpact02', 'spazImpact03', 'spazImpact04'], + "death_sounds":['spazDeath01'], + "pickup_sounds":['spazPickup01'], + "fall_sounds":['spazFall01'], + "icon_texture":"neoSpazIcon", + "icon_mask_texture":"neoSpazIconColorMask", + "style":"spaz" + } +character=None + +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 + + +# ba_meta export game +class CharacterBuilder(ba.TeamGameActivity[Player, Team]): + """A game type based on acquiring kills.""" + + name = 'Character Maker' + description = 'Create your own custom Characters' + + # Print messages when players die since it matters here. + announce_player_deaths = True + + @classmethod + def get_available_settings( + cls, sessiontype: Type[ba.Session]) -> List[ba.Setting]: + settings = [ + ba.IntSetting( + 'Kills to Win Per Player', + 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', 4.0), + ], + default=1.0, + ), + ba.BoolSetting('Epic Mode', default=False), + ] + + + if issubclass(sessiontype, ba.FreeForAllSession): + settings.append( + ba.BoolSetting('Allow Negative Scores', default=False)) + + return settings + + @classmethod + def supports_session_type(cls, sessiontype: Type[ba.Session]) -> bool: + return (issubclass(sessiontype, ba.DualTeamSession) + or issubclass(sessiontype, ba.FreeForAllSession)) + + @classmethod + def get_supported_maps(cls, sessiontype: Type[ba.Session]) -> List[str]: + return ['Rampage'] + + def __init__(self, settings: dict): + + + super().__init__(settings) + + self.initdic() + _ba.set_party_icon_always_visible(True) + self._score_to_win: Optional[int] = None + self._dingsound = ba.getsound('dingSmall') + self._epic_mode = bool(settings['Epic Mode']) + self._kills_to_win_per_player = int( + settings['Kills to Win Per Player']) + self._time_limit = float(settings['Time Limit']) + self._allow_negative_scores = bool( + settings.get('Allow Negative Scores', False)) + self.bodyindex=0 + self.modelindex=0 + self.youtube= ba.newnode( + 'text', + attrs={ + 'text': "youtube.com/c/HeySmoothy", + 'in_world': True, + 'scale': 0.02, + 'color': (1, 0, 0, 0.4), + 'h_align': 'center', + 'position': (0,4,-1.9) + }) + self.discordservere= ba.newnode( + 'text', + attrs={ + 'text': "discord.gg/ucyaesh", + 'in_world': True, + 'scale': 0.02, + 'color': (0.12, 0.3, 0.6, 0.4), + 'h_align': 'center', + 'position': (-3,2.7,-1.9) + }) + # self.discord= ba.newnode( + # 'text', + # attrs={ + # 'text': "mr.smoothy#5824", + # 'in_world': True, + # 'scale': 0.02, + # 'color': (01.2, 0.3, 0.7, 0.4), + # 'h_align': 'center', + # 'position': (4,2.7,-1.9) + # }) + # Base class overrides. + self.bodypart= ba.newnode( + 'text', + attrs={ + 'text': "", + 'in_world': True, + 'scale': 0.02, + 'color': (1, 1, 0, 1), + 'h_align': 'center', + 'position': (-4,6,-4) + }) + self.newmodel = ba.newnode( + 'text', + attrs={ + 'text': "", + 'in_world': True, + 'scale': 0.02, + 'color': (1, 1, 0, 1), + 'h_align': 'center', + 'position': (6,6,-4) + }) + self.slow_motion = self._epic_mode + self.default_music = (ba.MusicType.EPIC if self._epic_mode else + ba.MusicType.TO_THE_DEATH) + + def get_instance_description(self) -> Union[str, Sequence]: + return '' + + def get_instance_description_short(self) -> Union[str, Sequence]: + return '' + + def on_team_join(self, team: Team) -> None: + if self.has_begun(): + pass + + def on_begin(self) -> None: + super().on_begin() + + + def nextBodyPart(self): + self.bodyindex =(self.bodyindex+1)%len(self.dic.keys()) + self.bodypart.delete() + PART=list(self.dic.keys())[self.bodyindex] + self.bodypart=ba.newnode( + 'text', + attrs={ + 'text': PART, + 'in_world': True, + 'scale': 0.02, + 'color': (1, 1, 1, 1), + 'h_align': 'center', + 'position': (-4,6,-4) + }) + + + + def prevBodyPart(self): + self.bodyindex =(self.bodyindex-1)%len(self.dic.keys()) + self.bodypart.delete() + PART=list(self.dic.keys())[self.bodyindex] + self.bodypart=ba.newnode( + 'text', + attrs={ + 'text': PART, + 'in_world': True, + 'scale': 0.02, + 'color': (1, 1, 1, 1), + 'h_align': 'center', + 'position': (-4,6,-4) + }) + + def nextModel(self): + + self.newmodel.delete() + PART=list(self.dic.keys())[self.bodyindex] + self.modelindex =(self.modelindex+1)%len(self.dic[PART]) + model=self.dic[PART][self.modelindex] + self.newmodel=ba.newnode( + 'text', + attrs={ + 'text': model, + 'in_world': True, + 'scale': 0.02, + 'color': (1, 1, 1, 1), + 'h_align': 'center', + 'position': (6,6,-4) + }) + + self.setModel(PART,model) + + def prevModel(self): + + self.newmodel.delete() + PART=list(self.dic.keys())[self.bodyindex] + self.modelindex =(self.modelindex-1)%len(self.dic[PART]) + model=self.dic[PART][self.modelindex] + self.newmodel=ba.newnode( + 'text', + attrs={ + 'text': model, + 'in_world': True, + 'scale': 0.02, + 'color': (1, 1, 1, 1), + 'h_align': 'center', + 'position': (6,6,-4) + }) + self.setModel(PART,model) + + def setModel(self,bodypart,modelname): + global spazoutfit + body=_ba.get_foreground_host_activity().players[0].actor.node + if bodypart=='head': + body.head_model=ba.getmodel(modelname) + elif bodypart=='torso': + body.torso_model=ba.getmodel(modelname) + elif bodypart=='pelvis': + body.pelvis_model=ba.getmodel(modelname) + elif bodypart=='upper_arm': + body.upper_arm_model=ba.getmodel(modelname) + elif bodypart=='forearm': + body.forearm_model=ba.getmodel(modelname) + elif bodypart=='hand': + body.hand_model=ba.getmodel(modelname) + elif bodypart=='upper_leg': + body.upper_leg_model=ba.getmodel(modelname) + elif bodypart=='lower_leg': + body.lower_leg_model=ba.getmodel(modelname) + elif bodypart=='toes_model': + body.toes_model=ba.getmodel(modelname) + elif bodypart=='style': + body.style=modelname + elif bodypart=='color_texture': + body.color_texture=ba.gettexture(modelname) + elif bodypart=='color_mask': + body.color_mask_texture=ba.gettexture(modelname) + spazoutfit[bodypart]=modelname + + def spawn_player(self, player: Player) -> ba.Actor: + global character + if character!=None: + player.character=character + + self.setcurrentcharacter(player.character) + + spaz = self.spawn_player_spaz(player) + + # Let's reconnect this player's controls to this + # spaz but *without* the ability to attack or pick stuff up. + spaz.connect_controls_to_player(enable_punch=False, + enable_jump=False, + enable_bomb=False, + enable_pickup=False) + intp = ba.InputType + player.assigninput(intp.JUMP_PRESS, self.nextBodyPart) + player.assigninput(intp.PICK_UP_PRESS, self.prevBodyPart) + player.assigninput(intp.PUNCH_PRESS, self.nextModel) + player.assigninput(intp.BOMB_PRESS, self.prevModel) + # Also lets have them make some noise when they die. + spaz.play_big_death_sound = True + return spaz + + def handlemessage(self, msg: Any) -> Any: + + if isinstance(msg, ba.PlayerDiedMessage): + + # Augment standard behavior. + super().handlemessage(msg) + + player = msg.getplayer(Player) + self.respawn_player(player) + + + + + + + + else: + return super().handlemessage(msg) + return None + def setcurrentcharacter(self,charname): + global spazoutfit + char=ba.app.spaz_appearances[charname] + spazoutfit['head']=char.head_model + spazoutfit['hand']=char.hand_model + spazoutfit['torso']=char.torso_model + spazoutfit['pelvis']=char.pelvis_model + spazoutfit['upper_arm']=char.upper_arm_model + spazoutfit['forearm']=char.forearm_model + spazoutfit['upper_leg']=char.upper_leg_model + spazoutfit['lower_leg']=char.lower_leg_model + spazoutfit['toes_model']=char.toes_model + spazoutfit['style']=char.style + spazoutfit['color_mask']=char.color_mask_texture + spazoutfit['color_texture']=char.color_texture + + + def _update_scoreboard(self) -> None: + for team in self.teams: + self._scoreboard.set_team_value(team, team.score, + self._score_to_win) + + 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 initdic(self): + self.dic={"head":["bomb","landMine","trees","wing","eyeLid","impactBomb"], + "hand":["hairTuft3","bomb","powerup"], + "torso":["bomb","landMine","bomb"], + "pelvis":["hairTuft4","bomb"], + "upper_arm":["wing","locator","bomb"], + "forearm":["flagPole","bomb"], + "upper_leg":["bomb"], + "lower_leg":["bomb"], + "toes_model":["bomb"], + "style":["spaz","female","ninja","kronk","mel","pirate","santa","frosty","bones","bear","penguin","ali","cyborg","agent","pixie","bunny"], + "color_texture":["kronk","egg1","egg2","egg3","achievementGotTheMoves","bombColor","crossOut","explosion","rgbStripes","powerupCurse","powerupHealth","impactBombColorLit"], + "color_mask":["egg1","egg2","egg3","bombColor","crossOutMask","fontExtras3"] + + } + chars=["neoSpaz","zoe","ninja","kronk","mel","jack","santa","frosty","bones","bear","penguin","ali","cyborg","agent","wizard","pixie","bunny"] + for char in chars: + self.dic["head"].append(char+"Head") + self.dic["hand"].append(char+"Hand") + self.dic["torso"].append(char+"Torso") + if char not in ['mel',"jack","santa"]: + self.dic["pelvis"].append(char+"Pelvis") + self.dic["upper_arm"].append(char+"UpperArm") + self.dic["forearm"].append(char+"ForeArm") + self.dic["upper_leg"].append(char+"UpperLeg") + self.dic["lower_leg"].append(char+"LowerLeg") + self.dic["toes_model"].append(char+"Toes") + self.dic["color_mask"].append(char+"ColorMask") + if char !="kronk": + self.dic["color_texture"].append(char+"Color") + + +cm=_ba.chatmessage + +def _new_chatmessage(msg): + if msg.split(" ")[0]=="export": + if len(msg.split(" "))>1: + savecharacter(msg.split(" ")[1]) + else: + _ba.screenmessage("Enter name of character") + elif msg.split(" ")[0]=="import": + importcharacter(msg[7:]) + + else: + cm(msg) +_ba.chatmessage=_new_chatmessage + + +def savecharacter(name): + path=os.path.join(_ba.env()["python_directory_user"],"CustomCharacters" + os.sep) + if not os.path.isdir(path): + os.makedirs(path) + if _ba.get_foreground_host_activity()!=None: + + with open(path+name+".json",'w') as f: + json.dump(spazoutfit,f,indent=4) + registercharacter(name,spazoutfit) + ba.playsound(ba.getsound("gunCocking")) + _ba.screenmessage("Character Saved") + else: + _ba.screenmessage("Works offline with Character Maker") + +def importcharacter(name): + if name in ba.app.spaz_appearances: + global character + character=name + try: + _ba.get_foreground_host_activity().players[0].actor.node.handlemessage(ba.DieMessage()) + _ba.screenmessage("Imported") + except: + _ba.screenmessage("works offline with character maker") + + + else: + _ba.screenmessage("invalid name check typo \n name is case sensitive") + + +def registercharacter(name,char): + t = Appearance(name.split(".")[0]) + t.color_texture = char['color_texture'] + t.color_mask_texture = char['color_mask'] + t.default_color = (0.6, 0.6, 0.6) + t.default_highlight = (0, 1, 0) + t.icon_texture = char['icon_texture'] + t.icon_mask_texture = char['icon_mask_texture'] + t.head_model = char['head'] + t.torso_model = char['torso'] + t.pelvis_model = char['pelvis'] + t.upper_arm_model = char['upper_arm'] + t.forearm_model = char['forearm'] + t.hand_model = char['hand'] + t.upper_leg_model = char['upper_leg'] + t.lower_leg_model = char['lower_leg'] + t.toes_model = char['toes_model'] + t.jump_sounds = char['jump_sounds'] + t.attack_sounds = char['attack_sounds'] + t.impact_sounds = char['impact_sounds'] + t.death_sounds = char['death_sounds'] + t.pickup_sounds = char['pickup_sounds'] + t.fall_sounds = char['fall_sounds'] + t.style = char['style'] + + + + + + + +# ba_meta export plugin +class HeySmoothy(ba.Plugin): + + def __init__(self): + _ba.set_party_icon_always_visible(True) + + path=os.path.join(_ba.env()["python_directory_user"],"CustomCharacters" + os.sep) + if not os.path.isdir(path): + os.makedirs(path) + files=os.listdir(path) + for file in files: + with open(path+file, 'r') as f: + character = json.load(f) + registercharacter(file,character) + + + + From 9041d5cbf72d42a0d1544783000c06149b2fa82b Mon Sep 17 00:00:00 2001 From: Rikko Date: Wed, 5 Oct 2022 22:21:28 +0530 Subject: [PATCH 0172/1464] Make plugin and filename consistent --- plugins/utilities.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/plugins/utilities.json b/plugins/utilities.json index b5420137..050a1e3a 100644 --- a/plugins/utilities.json +++ b/plugins/utilities.json @@ -204,7 +204,7 @@ "1.0.0": null } }, - "character_builder": { + "character_maker": { "description": "Make new characters by manipulating models and textures.", "external_url": "https://www.youtube.com/watch?v=q0KxY1hfMPQ", "authors": [ @@ -276,4 +276,4 @@ } } } -} \ No newline at end of file +} From 6bdc35eda499a9472c33682ba94fbc287a9e6b41 Mon Sep 17 00:00:00 2001 From: Rikko Date: Wed, 5 Oct 2022 22:30:12 +0530 Subject: [PATCH 0173/1464] Autopep8 --- plugins/utilities/character_chooser.py | 558 ++++++++++++------------- plugins/utilities/character_maker.py | 488 +++++++++++---------- 2 files changed, 517 insertions(+), 529 deletions(-) diff --git a/plugins/utilities/character_chooser.py b/plugins/utilities/character_chooser.py index 388479eb..006c0a4a 100644 --- a/plugins/utilities/character_chooser.py +++ b/plugins/utilities/character_chooser.py @@ -34,7 +34,8 @@ from typing import TYPE_CHECKING -import ba,_ba +import ba +import _ba from bastd.actor.playerspaz import PlayerSpaz @@ -46,315 +47,314 @@ if TYPE_CHECKING: from typing import Any, Type, List, Dict, Tuple, Union, Sequence, Optional import weakref -import os,json +import os +import json from ba import _lobby from bastd.actor.spazappearance import * from ba._lobby import ChangeMessage from ba._lobby import PlayerReadyMessage + def __init__(self, vpos: float, sessionplayer: _ba.SessionPlayer, - lobby: 'Lobby') -> None: - self._deek_sound = _ba.getsound('deek') - self._click_sound = _ba.getsound('click01') - self._punchsound = _ba.getsound('punch01') - self._swish_sound = _ba.getsound('punchSwish') - self._errorsound = _ba.getsound('error') - self._mask_texture = _ba.gettexture('characterIconMask') - self._vpos = vpos - self._lobby = weakref.ref(lobby) - self._sessionplayer = sessionplayer - self._inited = False - self._dead = False - self._text_node: Optional[ba.Node] = None - self._profilename = '' - self._profilenames: List[str] = [] - self._ready: bool = False - self._character_names: List[str] = [] - self._last_change: Sequence[Union[float, int]] = (0, 0) - self._profiles: Dict[str, Dict[str, Any]] = {} - - app = _ba.app - - self.bakwas_chars=["Lee","Todd McBurton","Zola","Butch","Witch","warrior","Middle-Man","Alien","OldLady","Gladiator","Wrestler","Gretel","Robot"] - - # Load available player profiles either from the local config or - # from the remote device. - self.reload_profiles() - for name in _ba.app.spaz_appearances: - if name not in self._character_names and name not in self.bakwas_chars: - self._character_names.append(name) - # Note: this is just our local index out of available teams; *not* - # the team-id! - self._selected_team_index: int = self.lobby.next_add_team - - # Store a persistent random character index and colors; we'll use this - # for the '_random' profile. Let's use their input_device id to seed - # it. This will give a persistent character for them between games - # and will distribute characters nicely if everyone is random. - self._random_color, self._random_highlight = ( - get_player_profile_colors(None)) - - # To calc our random character we pick a random one out of our - # unlocked list and then locate that character's index in the full - # list. - char_index_offset = app.lobby_random_char_index_offset - self._random_character_index = ( - (sessionplayer.inputdevice.id + char_index_offset) % - len(self._character_names)) - - # Attempt to set an initial profile based on what was used previously - # for this input-device, etc. - self._profileindex = self._select_initial_profile() - self._profilename = self._profilenames[self._profileindex] - - self._text_node = _ba.newnode('text', - delegate=self, - attrs={ - 'position': (-100, self._vpos), - 'maxwidth': 190, - 'shadow': 0.5, - 'vr_depth': -20, - 'h_align': 'left', - 'v_align': 'center', - 'v_attach': 'top' - }) - animate(self._text_node, 'scale', {0: 0, 0.1: 1.0}) - self.icon = _ba.newnode('image', - owner=self._text_node, - attrs={ - 'position': (-130, self._vpos + 20), - 'mask_texture': self._mask_texture, - 'vr_depth': -10, - 'attach': 'topCenter' - }) - - animate_array(self.icon, 'scale', 2, {0: (0, 0), 0.1: (45, 45)}) - - # Set our initial name to '' in case anyone asks. - self._sessionplayer.setname( - Lstr(resource='choosingPlayerText').evaluate(), real=False) - - # Init these to our rando but they should get switched to the - # selected profile (if any) right after. - self._character_index = self._random_character_index - self._color = self._random_color - self._highlight = self._random_highlight - self.characterchooser=False - self.update_from_profile() - self.update_position() - self._inited = True - - self._set_ready(False) + lobby: 'Lobby') -> None: + self._deek_sound = _ba.getsound('deek') + self._click_sound = _ba.getsound('click01') + self._punchsound = _ba.getsound('punch01') + self._swish_sound = _ba.getsound('punchSwish') + self._errorsound = _ba.getsound('error') + self._mask_texture = _ba.gettexture('characterIconMask') + self._vpos = vpos + self._lobby = weakref.ref(lobby) + self._sessionplayer = sessionplayer + self._inited = False + self._dead = False + self._text_node: Optional[ba.Node] = None + self._profilename = '' + self._profilenames: List[str] = [] + self._ready: bool = False + self._character_names: List[str] = [] + self._last_change: Sequence[Union[float, int]] = (0, 0) + self._profiles: Dict[str, Dict[str, Any]] = {} + + app = _ba.app + + self.bakwas_chars = ["Lee", "Todd McBurton", "Zola", "Butch", "Witch", "warrior", + "Middle-Man", "Alien", "OldLady", "Gladiator", "Wrestler", "Gretel", "Robot"] + + # Load available player profiles either from the local config or + # from the remote device. + self.reload_profiles() + for name in _ba.app.spaz_appearances: + if name not in self._character_names and name not in self.bakwas_chars: + self._character_names.append(name) + # Note: this is just our local index out of available teams; *not* + # the team-id! + self._selected_team_index: int = self.lobby.next_add_team + + # Store a persistent random character index and colors; we'll use this + # for the '_random' profile. Let's use their input_device id to seed + # it. This will give a persistent character for them between games + # and will distribute characters nicely if everyone is random. + self._random_color, self._random_highlight = ( + get_player_profile_colors(None)) + + # To calc our random character we pick a random one out of our + # unlocked list and then locate that character's index in the full + # list. + char_index_offset = app.lobby_random_char_index_offset + self._random_character_index = ( + (sessionplayer.inputdevice.id + char_index_offset) % + len(self._character_names)) + + # Attempt to set an initial profile based on what was used previously + # for this input-device, etc. + self._profileindex = self._select_initial_profile() + self._profilename = self._profilenames[self._profileindex] + + self._text_node = _ba.newnode('text', + delegate=self, + attrs={ + 'position': (-100, self._vpos), + 'maxwidth': 190, + 'shadow': 0.5, + 'vr_depth': -20, + 'h_align': 'left', + 'v_align': 'center', + 'v_attach': 'top' + }) + animate(self._text_node, 'scale', {0: 0, 0.1: 1.0}) + self.icon = _ba.newnode('image', + owner=self._text_node, + attrs={ + 'position': (-130, self._vpos + 20), + 'mask_texture': self._mask_texture, + 'vr_depth': -10, + 'attach': 'topCenter' + }) + + animate_array(self.icon, 'scale', 2, {0: (0, 0), 0.1: (45, 45)}) + + # Set our initial name to '' in case anyone asks. + self._sessionplayer.setname( + Lstr(resource='choosingPlayerText').evaluate(), real=False) + + # Init these to our rando but they should get switched to the + # selected profile (if any) right after. + self._character_index = self._random_character_index + self._color = self._random_color + self._highlight = self._random_highlight + self.characterchooser = False + self.update_from_profile() + self.update_position() + self._inited = True + + self._set_ready(False) + + +def _set_ready(self, ready: bool) -> None: + # pylint: disable=cyclic-import + from bastd.ui.profile import browser as pbrowser + from ba._general import Call + profilename = self._profilenames[self._profileindex] + + # Handle '_edit' as a special case. + if profilename == '_edit' and ready: + with _ba.Context('ui'): + pbrowser.ProfileBrowserWindow(in_main_menu=False) + + # Give their input-device UI ownership too + # (prevent someone else from snatching it in crowded games) + _ba.set_ui_input_device(self._sessionplayer.inputdevice) + return + + if ready == False: + self._sessionplayer.assigninput( + InputType.LEFT_PRESS, + Call(self.handlemessage, ChangeMessage('team', -1))) + self._sessionplayer.assigninput( + InputType.RIGHT_PRESS, + Call(self.handlemessage, ChangeMessage('team', 1))) + self._sessionplayer.assigninput( + InputType.BOMB_PRESS, + Call(self.handlemessage, ChangeMessage('character', 1))) + self._sessionplayer.assigninput( + InputType.UP_PRESS, + Call(self.handlemessage, ChangeMessage('profileindex', -1))) + self._sessionplayer.assigninput( + InputType.DOWN_PRESS, + Call(self.handlemessage, ChangeMessage('profileindex', 1))) + self._sessionplayer.assigninput( + (InputType.JUMP_PRESS, InputType.PICK_UP_PRESS, + InputType.PUNCH_PRESS), + Call(self.handlemessage, ChangeMessage('ready', 1))) + self._ready = False + self._update_text() + self._sessionplayer.setname('untitled', real=False) + elif ready == True: + self.characterchooser = True + self._sessionplayer.assigninput( + (InputType.LEFT_PRESS, InputType.RIGHT_PRESS, + InputType.UP_PRESS, InputType.DOWN_PRESS, + InputType.JUMP_PRESS, InputType.BOMB_PRESS, + InputType.PICK_UP_PRESS), self._do_nothing) + self._sessionplayer.assigninput( + (InputType.UP_PRESS), Call(self.handlemessage, ChangeMessage('characterchooser', -1))) + self._sessionplayer.assigninput( + (InputType.DOWN_PRESS), Call(self.handlemessage, ChangeMessage('characterchooser', 1))) + self._sessionplayer.assigninput( + (InputType.BOMB_PRESS), Call(self.handlemessage, ChangeMessage('ready', 0))) + + self._sessionplayer.assigninput( + (InputType.JUMP_PRESS, InputType.PICK_UP_PRESS, InputType.PUNCH_PRESS), + Call(self.handlemessage, ChangeMessage('ready', 2))) + + # Store the last profile picked by this input for reuse. + input_device = self._sessionplayer.inputdevice + name = input_device.name + unique_id = input_device.unique_identifier + device_profiles = _ba.app.config.setdefault( + 'Default Player Profiles', {}) + + # Make an exception if we have no custom profiles and are set + # to random; in that case we'll want to start picking up custom + # profiles if/when one is made so keep our setting cleared. + special = ('_random', '_edit', '__account__') + have_custom_profiles = any(p not in special + for p in self._profiles) + + profilekey = name + ' ' + unique_id + if profilename == '_random' and not have_custom_profiles: + if profilekey in device_profiles: + del device_profiles[profilekey] + else: + device_profiles[profilekey] = profilename + _ba.app.config.commit() + # Set this player's short and full name. + self._sessionplayer.setname(self._getname(), + self._getname(full=True), + real=True) + self._ready = True + self._update_text() + else: + # Inform the session that this player is ready. + _ba.getsession().handlemessage(PlayerReadyMessage(self)) -def _set_ready(self, ready: bool) -> None: - # pylint: disable=cyclic-import - from bastd.ui.profile import browser as pbrowser - from ba._general import Call - profilename = self._profilenames[self._profileindex] +def handlemessage(self, msg: Any) -> Any: + """Standard generic message handler.""" - # Handle '_edit' as a special case. - if profilename == '_edit' and ready: - with _ba.Context('ui'): - pbrowser.ProfileBrowserWindow(in_main_menu=False) + if isinstance(msg, ChangeMessage): + self._handle_repeat_message_attack() - # Give their input-device UI ownership too - # (prevent someone else from snatching it in crowded games) - _ba.set_ui_input_device(self._sessionplayer.inputdevice) + # If we've been removed from the lobby, ignore this stuff. + if self._dead: + print_error('chooser got ChangeMessage after dying') return - if ready==False: - self._sessionplayer.assigninput( - InputType.LEFT_PRESS, - Call(self.handlemessage, ChangeMessage('team', -1))) - self._sessionplayer.assigninput( - InputType.RIGHT_PRESS, - Call(self.handlemessage, ChangeMessage('team', 1))) - self._sessionplayer.assigninput( - InputType.BOMB_PRESS, - Call(self.handlemessage, ChangeMessage('character', 1))) - self._sessionplayer.assigninput( - InputType.UP_PRESS, - Call(self.handlemessage, ChangeMessage('profileindex', -1))) - self._sessionplayer.assigninput( - InputType.DOWN_PRESS, - Call(self.handlemessage, ChangeMessage('profileindex', 1))) - self._sessionplayer.assigninput( - (InputType.JUMP_PRESS, InputType.PICK_UP_PRESS, - InputType.PUNCH_PRESS), - Call(self.handlemessage, ChangeMessage('ready', 1))) - self._ready = False + if not self._text_node: + print_error('got ChangeMessage after nodes died') + return + if msg.what == 'characterchooser': + _ba.playsound(self._click_sound) + # update our index in our local list of characters + self._character_index = ((self._character_index + msg.value) % + len(self._character_names)) self._update_text() - self._sessionplayer.setname('untitled', real=False) - elif ready == True: - self.characterchooser=True - self._sessionplayer.assigninput( - (InputType.LEFT_PRESS, InputType.RIGHT_PRESS, - InputType.UP_PRESS, InputType.DOWN_PRESS, - InputType.JUMP_PRESS, InputType.BOMB_PRESS, - InputType.PICK_UP_PRESS), self._do_nothing) - self._sessionplayer.assigninput( - (InputType.UP_PRESS),Call(self.handlemessage,ChangeMessage('characterchooser',-1))) - self._sessionplayer.assigninput( - (InputType.DOWN_PRESS),Call(self.handlemessage,ChangeMessage('characterchooser',1))) - self._sessionplayer.assigninput( - (InputType.BOMB_PRESS),Call(self.handlemessage,ChangeMessage('ready',0))) - - self._sessionplayer.assigninput( - (InputType.JUMP_PRESS,InputType.PICK_UP_PRESS, InputType.PUNCH_PRESS), - Call(self.handlemessage, ChangeMessage('ready', 2))) - - # Store the last profile picked by this input for reuse. - input_device = self._sessionplayer.inputdevice - name = input_device.name - unique_id = input_device.unique_identifier - device_profiles = _ba.app.config.setdefault( - 'Default Player Profiles', {}) - - # Make an exception if we have no custom profiles and are set - # to random; in that case we'll want to start picking up custom - # profiles if/when one is made so keep our setting cleared. - special = ('_random', '_edit', '__account__') - have_custom_profiles = any(p not in special - for p in self._profiles) - - profilekey = name + ' ' + unique_id - if profilename == '_random' and not have_custom_profiles: - if profilekey in device_profiles: - del device_profiles[profilekey] - else: - device_profiles[profilekey] = profilename - _ba.app.config.commit() - - # Set this player's short and full name. - self._sessionplayer.setname(self._getname(), - self._getname(full=True), - real=True) - self._ready = True + self._update_icon() + + if msg.what == 'team': + sessionteams = self.lobby.sessionteams + if len(sessionteams) > 1: + _ba.playsound(self._swish_sound) + self._selected_team_index = ( + (self._selected_team_index + msg.value) % + len(sessionteams)) self._update_text() - else: - + self.update_position() + self._update_icon() + elif msg.what == 'profileindex': + if len(self._profilenames) == 1: - # Inform the session that this player is ready. - _ba.getsession().handlemessage(PlayerReadyMessage(self)) + # This should be pretty hard to hit now with + # automatic local accounts. + _ba.playsound(_ba.getsound('error')) + else: + # Pick the next player profile and assign our name + # and character based on that. + _ba.playsound(self._deek_sound) + self._profileindex = ((self._profileindex + msg.value) % + len(self._profilenames)) + self.update_from_profile() + + elif msg.what == 'character': + _ba.playsound(self._click_sound) + self.characterchooser = True + # update our index in our local list of characters + self._character_index = ((self._character_index + msg.value) % + len(self._character_names)) + self._update_text() + self._update_icon() + + elif msg.what == 'ready': + self._handle_ready_msg(msg.value) -def handlemessage(self, msg: Any) -> Any: - """Standard generic message handler.""" - - if isinstance(msg, ChangeMessage): - self._handle_repeat_message_attack() - - # If we've been removed from the lobby, ignore this stuff. - if self._dead: - print_error('chooser got ChangeMessage after dying') - return - - if not self._text_node: - print_error('got ChangeMessage after nodes died') - return - if msg.what=='characterchooser': - _ba.playsound(self._click_sound) - # update our index in our local list of characters - self._character_index = ((self._character_index + msg.value) % - len(self._character_names)) - self._update_text() - self._update_icon() - - if msg.what == 'team': - sessionteams = self.lobby.sessionteams - if len(sessionteams) > 1: - _ba.playsound(self._swish_sound) - self._selected_team_index = ( - (self._selected_team_index + msg.value) % - len(sessionteams)) - self._update_text() - self.update_position() - self._update_icon() - - elif msg.what == 'profileindex': - if len(self._profilenames) == 1: - - # This should be pretty hard to hit now with - # automatic local accounts. - _ba.playsound(_ba.getsound('error')) - else: - - # Pick the next player profile and assign our name - # and character based on that. - _ba.playsound(self._deek_sound) - self._profileindex = ((self._profileindex + msg.value) % - len(self._profilenames)) - self.update_from_profile() - - elif msg.what == 'character': - _ba.playsound(self._click_sound) - self.characterchooser=True - # update our index in our local list of characters - self._character_index = ((self._character_index + msg.value) % - len(self._character_names)) - self._update_text() - self._update_icon() - - elif msg.what == 'ready': - self._handle_ready_msg(msg.value) def _update_text(self) -> None: - assert self._text_node is not None - if self._ready: - - # Once we're ready, we've saved the name, so lets ask the system - # for it so we get appended numbers and stuff. - text = Lstr(value=self._sessionplayer.getname(full=True)) - if self.characterchooser: - text = Lstr(value='${A}\n${B}', + assert self._text_node is not None + if self._ready: + + # Once we're ready, we've saved the name, so lets ask the system + # for it so we get appended numbers and stuff. + text = Lstr(value=self._sessionplayer.getname(full=True)) + if self.characterchooser: + text = Lstr(value='${A}\n${B}', subs=[('${A}', text), ('${B}', Lstr(value=""+self._character_names[self._character_index]))]) - self._text_node.scale=0.8 - else: - text = Lstr(value='${A} (${B})', - subs=[('${A}', text), - ('${B}', Lstr(resource='readyText'))]) + self._text_node.scale = 0.8 else: - text = Lstr(value=self._getname(full=True)) - self._text_node.scale=1.0 - - can_switch_teams = len(self.lobby.sessionteams) > 1 - - # Flash as we're coming in. - fin_color = _ba.safecolor(self.get_color()) + (1, ) - if not self._inited: + text = Lstr(value='${A} (${B})', + subs=[('${A}', text), + ('${B}', Lstr(resource='readyText'))]) + else: + text = Lstr(value=self._getname(full=True)) + self._text_node.scale = 1.0 + + can_switch_teams = len(self.lobby.sessionteams) > 1 + + # Flash as we're coming in. + fin_color = _ba.safecolor(self.get_color()) + (1, ) + if not self._inited: + animate_array(self._text_node, 'color', 4, { + 0.15: fin_color, + 0.25: (2, 2, 2, 1), + 0.35: fin_color + }) + else: + + # Blend if we're in teams mode; switch instantly otherwise. + if can_switch_teams: animate_array(self._text_node, 'color', 4, { - 0.15: fin_color, - 0.25: (2, 2, 2, 1), - 0.35: fin_color + 0: self._text_node.color, + 0.1: fin_color }) else: + self._text_node.color = fin_color - # Blend if we're in teams mode; switch instantly otherwise. - if can_switch_teams: - animate_array(self._text_node, 'color', 4, { - 0: self._text_node.color, - 0.1: fin_color - }) - else: - self._text_node.color = fin_color - - self._text_node.text = text + self._text_node.text = text # ba_meta export plugin + + class HeySmoothy(ba.Plugin): - + def __init__(self): - _lobby.Chooser.__init__=__init__ - _lobby.Chooser._set_ready=_set_ready - - _lobby.Chooser._update_text=_update_text - _lobby.Chooser.handlemessage=handlemessage - - - + _lobby.Chooser.__init__ = __init__ + _lobby.Chooser._set_ready = _set_ready + + _lobby.Chooser._update_text = _update_text + _lobby.Chooser.handlemessage = handlemessage diff --git a/plugins/utilities/character_maker.py b/plugins/utilities/character_maker.py index f69d9092..218c336f 100644 --- a/plugins/utilities/character_maker.py +++ b/plugins/utilities/character_maker.py @@ -50,38 +50,41 @@ from typing import TYPE_CHECKING -import ba,_ba +import ba +import _ba from bastd.actor.playerspaz import PlayerSpaz from bastd.actor.scoreboard import Scoreboard if TYPE_CHECKING: from typing import Any, Type, List, Dict, Tuple, Union, Sequence, Optional -import os,json +import os +import json from bastd.actor.spazappearance import * -spazoutfit={ - "color_mask":"neoSpazColorMask", - "color_texture":"neoSpazColor", - "head":"neoSpazHead", - "hand":"neoSpazHand", - "torso":"neoSpazTorso", - "pelvis":"neoSpazTorso", - "upper_arm":"neoSpazUpperArm", - "forearm":"neoSpazForeArm", - "upper_leg":"neoSpazUpperLeg", - "lower_leg":"neoSpazLowerLeg", - "toes_model":"neoSpazToes", - "jump_sounds":['spazJump01', 'spazJump02', 'spazJump03', 'spazJump04'], - "attack_sounds":['spazAttack01', 'spazAttack02', 'spazAttack03', 'spazAttack04'], - "impact_sounds":['spazImpact01', 'spazImpact02', 'spazImpact03', 'spazImpact04'], - "death_sounds":['spazDeath01'], - "pickup_sounds":['spazPickup01'], - "fall_sounds":['spazFall01'], - "icon_texture":"neoSpazIcon", - "icon_mask_texture":"neoSpazIconColorMask", - "style":"spaz" - } -character=None +spazoutfit = { + "color_mask": "neoSpazColorMask", + "color_texture": "neoSpazColor", + "head": "neoSpazHead", + "hand": "neoSpazHand", + "torso": "neoSpazTorso", + "pelvis": "neoSpazTorso", + "upper_arm": "neoSpazUpperArm", + "forearm": "neoSpazForeArm", + "upper_leg": "neoSpazUpperLeg", + "lower_leg": "neoSpazLowerLeg", + "toes_model": "neoSpazToes", + "jump_sounds": ['spazJump01', 'spazJump02', 'spazJump03', 'spazJump04'], + "attack_sounds": ['spazAttack01', 'spazAttack02', 'spazAttack03', 'spazAttack04'], + "impact_sounds": ['spazImpact01', 'spazImpact02', 'spazImpact03', 'spazImpact04'], + "death_sounds": ['spazDeath01'], + "pickup_sounds": ['spazPickup01'], + "fall_sounds": ['spazFall01'], + "icon_texture": "neoSpazIcon", + "icon_mask_texture": "neoSpazIconColorMask", + "style": "spaz" +} +character = None + class Player(ba.Player['Team']): """Our player type for this game.""" @@ -140,7 +143,6 @@ def get_available_settings( ba.BoolSetting('Epic Mode', default=False), ] - if issubclass(sessiontype, ba.FreeForAllSession): settings.append( ba.BoolSetting('Allow Negative Scores', default=False)) @@ -157,10 +159,9 @@ def get_supported_maps(cls, sessiontype: Type[ba.Session]) -> List[str]: return ['Rampage'] def __init__(self, settings: dict): - - + super().__init__(settings) - + self.initdic() _ba.set_party_icon_always_visible(True) self._score_to_win: Optional[int] = None @@ -171,28 +172,28 @@ def __init__(self, settings: dict): self._time_limit = float(settings['Time Limit']) self._allow_negative_scores = bool( settings.get('Allow Negative Scores', False)) - self.bodyindex=0 - self.modelindex=0 - self.youtube= ba.newnode( - 'text', - attrs={ - 'text': "youtube.com/c/HeySmoothy", - 'in_world': True, - 'scale': 0.02, - 'color': (1, 0, 0, 0.4), - 'h_align': 'center', - 'position': (0,4,-1.9) - }) - self.discordservere= ba.newnode( - 'text', - attrs={ - 'text': "discord.gg/ucyaesh", - 'in_world': True, - 'scale': 0.02, - 'color': (0.12, 0.3, 0.6, 0.4), - 'h_align': 'center', - 'position': (-3,2.7,-1.9) - }) + self.bodyindex = 0 + self.modelindex = 0 + self.youtube = ba.newnode( + 'text', + attrs={ + 'text': "youtube.com/c/HeySmoothy", + 'in_world': True, + 'scale': 0.02, + 'color': (1, 0, 0, 0.4), + 'h_align': 'center', + 'position': (0, 4, -1.9) + }) + self.discordservere = ba.newnode( + 'text', + attrs={ + 'text': "discord.gg/ucyaesh", + 'in_world': True, + 'scale': 0.02, + 'color': (0.12, 0.3, 0.6, 0.4), + 'h_align': 'center', + 'position': (-3, 2.7, -1.9) + }) # self.discord= ba.newnode( # 'text', # attrs={ @@ -204,26 +205,26 @@ def __init__(self, settings: dict): # 'position': (4,2.7,-1.9) # }) # Base class overrides. - self.bodypart= ba.newnode( - 'text', - attrs={ - 'text': "", - 'in_world': True, - 'scale': 0.02, - 'color': (1, 1, 0, 1), - 'h_align': 'center', - 'position': (-4,6,-4) - }) + self.bodypart = ba.newnode( + 'text', + attrs={ + 'text': "", + 'in_world': True, + 'scale': 0.02, + 'color': (1, 1, 0, 1), + 'h_align': 'center', + 'position': (-4, 6, -4) + }) self.newmodel = ba.newnode( - 'text', - attrs={ - 'text': "", - 'in_world': True, - 'scale': 0.02, - 'color': (1, 1, 0, 1), - 'h_align': 'center', - 'position': (6,6,-4) - }) + 'text', + attrs={ + 'text': "", + 'in_world': True, + 'scale': 0.02, + 'color': (1, 1, 0, 1), + 'h_align': 'center', + 'position': (6, 6, -4) + }) self.slow_motion = self._epic_mode self.default_music = (ba.MusicType.EPIC if self._epic_mode else ba.MusicType.TO_THE_DEATH) @@ -240,113 +241,110 @@ def on_team_join(self, team: Team) -> None: def on_begin(self) -> None: super().on_begin() - def nextBodyPart(self): - self.bodyindex =(self.bodyindex+1)%len(self.dic.keys()) + self.bodyindex = (self.bodyindex+1) % len(self.dic.keys()) self.bodypart.delete() - PART=list(self.dic.keys())[self.bodyindex] - self.bodypart=ba.newnode( - 'text', - attrs={ - 'text': PART, - 'in_world': True, - 'scale': 0.02, - 'color': (1, 1, 1, 1), - 'h_align': 'center', - 'position': (-4,6,-4) - }) - - - + PART = list(self.dic.keys())[self.bodyindex] + self.bodypart = ba.newnode( + 'text', + attrs={ + 'text': PART, + 'in_world': True, + 'scale': 0.02, + 'color': (1, 1, 1, 1), + 'h_align': 'center', + 'position': (-4, 6, -4) + }) + def prevBodyPart(self): - self.bodyindex =(self.bodyindex-1)%len(self.dic.keys()) + self.bodyindex = (self.bodyindex-1) % len(self.dic.keys()) self.bodypart.delete() - PART=list(self.dic.keys())[self.bodyindex] - self.bodypart=ba.newnode( - 'text', - attrs={ - 'text': PART, - 'in_world': True, - 'scale': 0.02, - 'color': (1, 1, 1, 1), - 'h_align': 'center', - 'position': (-4,6,-4) - }) - + PART = list(self.dic.keys())[self.bodyindex] + self.bodypart = ba.newnode( + 'text', + attrs={ + 'text': PART, + 'in_world': True, + 'scale': 0.02, + 'color': (1, 1, 1, 1), + 'h_align': 'center', + 'position': (-4, 6, -4) + }) + def nextModel(self): - + self.newmodel.delete() - PART=list(self.dic.keys())[self.bodyindex] - self.modelindex =(self.modelindex+1)%len(self.dic[PART]) - model=self.dic[PART][self.modelindex] - self.newmodel=ba.newnode( - 'text', - attrs={ - 'text': model, - 'in_world': True, - 'scale': 0.02, - 'color': (1, 1, 1, 1), - 'h_align': 'center', - 'position': (6,6,-4) - }) - - self.setModel(PART,model) - + PART = list(self.dic.keys())[self.bodyindex] + self.modelindex = (self.modelindex+1) % len(self.dic[PART]) + model = self.dic[PART][self.modelindex] + self.newmodel = ba.newnode( + 'text', + attrs={ + 'text': model, + 'in_world': True, + 'scale': 0.02, + 'color': (1, 1, 1, 1), + 'h_align': 'center', + 'position': (6, 6, -4) + }) + + self.setModel(PART, model) + def prevModel(self): - + self.newmodel.delete() - PART=list(self.dic.keys())[self.bodyindex] - self.modelindex =(self.modelindex-1)%len(self.dic[PART]) - model=self.dic[PART][self.modelindex] - self.newmodel=ba.newnode( - 'text', - attrs={ - 'text': model, - 'in_world': True, - 'scale': 0.02, - 'color': (1, 1, 1, 1), - 'h_align': 'center', - 'position': (6,6,-4) - }) - self.setModel(PART,model) - - def setModel(self,bodypart,modelname): + PART = list(self.dic.keys())[self.bodyindex] + self.modelindex = (self.modelindex-1) % len(self.dic[PART]) + model = self.dic[PART][self.modelindex] + self.newmodel = ba.newnode( + 'text', + attrs={ + 'text': model, + 'in_world': True, + 'scale': 0.02, + 'color': (1, 1, 1, 1), + 'h_align': 'center', + 'position': (6, 6, -4) + }) + self.setModel(PART, model) + + def setModel(self, bodypart, modelname): global spazoutfit - body=_ba.get_foreground_host_activity().players[0].actor.node - if bodypart=='head': - body.head_model=ba.getmodel(modelname) - elif bodypart=='torso': - body.torso_model=ba.getmodel(modelname) - elif bodypart=='pelvis': - body.pelvis_model=ba.getmodel(modelname) - elif bodypart=='upper_arm': - body.upper_arm_model=ba.getmodel(modelname) - elif bodypart=='forearm': - body.forearm_model=ba.getmodel(modelname) - elif bodypart=='hand': - body.hand_model=ba.getmodel(modelname) - elif bodypart=='upper_leg': - body.upper_leg_model=ba.getmodel(modelname) - elif bodypart=='lower_leg': - body.lower_leg_model=ba.getmodel(modelname) - elif bodypart=='toes_model': - body.toes_model=ba.getmodel(modelname) - elif bodypart=='style': - body.style=modelname - elif bodypart=='color_texture': - body.color_texture=ba.gettexture(modelname) - elif bodypart=='color_mask': - body.color_mask_texture=ba.gettexture(modelname) - spazoutfit[bodypart]=modelname - + body = _ba.get_foreground_host_activity().players[0].actor.node + if bodypart == 'head': + body.head_model = ba.getmodel(modelname) + elif bodypart == 'torso': + body.torso_model = ba.getmodel(modelname) + elif bodypart == 'pelvis': + body.pelvis_model = ba.getmodel(modelname) + elif bodypart == 'upper_arm': + body.upper_arm_model = ba.getmodel(modelname) + elif bodypart == 'forearm': + body.forearm_model = ba.getmodel(modelname) + elif bodypart == 'hand': + body.hand_model = ba.getmodel(modelname) + elif bodypart == 'upper_leg': + body.upper_leg_model = ba.getmodel(modelname) + elif bodypart == 'lower_leg': + body.lower_leg_model = ba.getmodel(modelname) + elif bodypart == 'toes_model': + body.toes_model = ba.getmodel(modelname) + elif bodypart == 'style': + body.style = modelname + elif bodypart == 'color_texture': + body.color_texture = ba.gettexture(modelname) + elif bodypart == 'color_mask': + body.color_mask_texture = ba.gettexture(modelname) + spazoutfit[bodypart] = modelname + def spawn_player(self, player: Player) -> ba.Actor: global character - if character!=None: - player.character=character + if character != None: + player.character = character self.setcurrentcharacter(player.character) - + spaz = self.spawn_player_spaz(player) # Let's reconnect this player's controls to this @@ -374,31 +372,25 @@ def handlemessage(self, msg: Any) -> Any: player = msg.getplayer(Player) self.respawn_player(player) - - - - - - else: return super().handlemessage(msg) return None - def setcurrentcharacter(self,charname): - global spazoutfit - char=ba.app.spaz_appearances[charname] - spazoutfit['head']=char.head_model - spazoutfit['hand']=char.hand_model - spazoutfit['torso']=char.torso_model - spazoutfit['pelvis']=char.pelvis_model - spazoutfit['upper_arm']=char.upper_arm_model - spazoutfit['forearm']=char.forearm_model - spazoutfit['upper_leg']=char.upper_leg_model - spazoutfit['lower_leg']=char.lower_leg_model - spazoutfit['toes_model']=char.toes_model - spazoutfit['style']=char.style - spazoutfit['color_mask']=char.color_mask_texture - spazoutfit['color_texture']=char.color_texture + def setcurrentcharacter(self, charname): + global spazoutfit + char = ba.app.spaz_appearances[charname] + spazoutfit['head'] = char.head_model + spazoutfit['hand'] = char.hand_model + spazoutfit['torso'] = char.torso_model + spazoutfit['pelvis'] = char.pelvis_model + spazoutfit['upper_arm'] = char.upper_arm_model + spazoutfit['forearm'] = char.forearm_model + spazoutfit['upper_leg'] = char.upper_leg_model + spazoutfit['lower_leg'] = char.lower_leg_model + spazoutfit['toes_model'] = char.toes_model + spazoutfit['style'] = char.style + spazoutfit['color_mask'] = char.color_mask_texture + spazoutfit['color_texture'] = char.color_texture def _update_scoreboard(self) -> None: for team in self.teams: @@ -410,27 +402,29 @@ def end_game(self) -> None: for team in self.teams: results.set_team_score(team, team.score) self.end(results=results) + def initdic(self): - self.dic={"head":["bomb","landMine","trees","wing","eyeLid","impactBomb"], - "hand":["hairTuft3","bomb","powerup"], - "torso":["bomb","landMine","bomb"], - "pelvis":["hairTuft4","bomb"], - "upper_arm":["wing","locator","bomb"], - "forearm":["flagPole","bomb"], - "upper_leg":["bomb"], - "lower_leg":["bomb"], - "toes_model":["bomb"], - "style":["spaz","female","ninja","kronk","mel","pirate","santa","frosty","bones","bear","penguin","ali","cyborg","agent","pixie","bunny"], - "color_texture":["kronk","egg1","egg2","egg3","achievementGotTheMoves","bombColor","crossOut","explosion","rgbStripes","powerupCurse","powerupHealth","impactBombColorLit"], - "color_mask":["egg1","egg2","egg3","bombColor","crossOutMask","fontExtras3"] - - } - chars=["neoSpaz","zoe","ninja","kronk","mel","jack","santa","frosty","bones","bear","penguin","ali","cyborg","agent","wizard","pixie","bunny"] + self.dic = {"head": ["bomb", "landMine", "trees", "wing", "eyeLid", "impactBomb"], + "hand": ["hairTuft3", "bomb", "powerup"], + "torso": ["bomb", "landMine", "bomb"], + "pelvis": ["hairTuft4", "bomb"], + "upper_arm": ["wing", "locator", "bomb"], + "forearm": ["flagPole", "bomb"], + "upper_leg": ["bomb"], + "lower_leg": ["bomb"], + "toes_model": ["bomb"], + "style": ["spaz", "female", "ninja", "kronk", "mel", "pirate", "santa", "frosty", "bones", "bear", "penguin", "ali", "cyborg", "agent", "pixie", "bunny"], + "color_texture": ["kronk", "egg1", "egg2", "egg3", "achievementGotTheMoves", "bombColor", "crossOut", "explosion", "rgbStripes", "powerupCurse", "powerupHealth", "impactBombColorLit"], + "color_mask": ["egg1", "egg2", "egg3", "bombColor", "crossOutMask", "fontExtras3"] + + } + chars = ["neoSpaz", "zoe", "ninja", "kronk", "mel", "jack", "santa", "frosty", + "bones", "bear", "penguin", "ali", "cyborg", "agent", "wizard", "pixie", "bunny"] for char in chars: self.dic["head"].append(char+"Head") self.dic["hand"].append(char+"Hand") self.dic["torso"].append(char+"Torso") - if char not in ['mel',"jack","santa"]: + if char not in ['mel', "jack", "santa"]: self.dic["pelvis"].append(char+"Pelvis") self.dic["upper_arm"].append(char+"UpperArm") self.dic["forearm"].append(char+"ForeArm") @@ -438,101 +432,95 @@ def initdic(self): self.dic["lower_leg"].append(char+"LowerLeg") self.dic["toes_model"].append(char+"Toes") self.dic["color_mask"].append(char+"ColorMask") - if char !="kronk": + if char != "kronk": self.dic["color_texture"].append(char+"Color") -cm=_ba.chatmessage +cm = _ba.chatmessage + def _new_chatmessage(msg): - if msg.split(" ")[0]=="export": - if len(msg.split(" "))>1: + if msg.split(" ")[0] == "export": + if len(msg.split(" ")) > 1: savecharacter(msg.split(" ")[1]) else: _ba.screenmessage("Enter name of character") - elif msg.split(" ")[0]=="import": + elif msg.split(" ")[0] == "import": importcharacter(msg[7:]) else: cm(msg) -_ba.chatmessage=_new_chatmessage + + +_ba.chatmessage = _new_chatmessage def savecharacter(name): - path=os.path.join(_ba.env()["python_directory_user"],"CustomCharacters" + os.sep) + path = os.path.join(_ba.env()["python_directory_user"], "CustomCharacters" + os.sep) if not os.path.isdir(path): os.makedirs(path) - if _ba.get_foreground_host_activity()!=None: + if _ba.get_foreground_host_activity() != None: - with open(path+name+".json",'w') as f: - json.dump(spazoutfit,f,indent=4) - registercharacter(name,spazoutfit) + with open(path+name+".json", 'w') as f: + json.dump(spazoutfit, f, indent=4) + registercharacter(name, spazoutfit) ba.playsound(ba.getsound("gunCocking")) _ba.screenmessage("Character Saved") else: _ba.screenmessage("Works offline with Character Maker") + def importcharacter(name): if name in ba.app.spaz_appearances: global character - character=name + character = name try: _ba.get_foreground_host_activity().players[0].actor.node.handlemessage(ba.DieMessage()) _ba.screenmessage("Imported") except: _ba.screenmessage("works offline with character maker") - else: _ba.screenmessage("invalid name check typo \n name is case sensitive") -def registercharacter(name,char): - t = Appearance(name.split(".")[0]) - t.color_texture = char['color_texture'] - t.color_mask_texture = char['color_mask'] - t.default_color = (0.6, 0.6, 0.6) - t.default_highlight = (0, 1, 0) - t.icon_texture = char['icon_texture'] - t.icon_mask_texture = char['icon_mask_texture'] - t.head_model = char['head'] - t.torso_model = char['torso'] - t.pelvis_model = char['pelvis'] - t.upper_arm_model = char['upper_arm'] - t.forearm_model = char['forearm'] - t.hand_model = char['hand'] - t.upper_leg_model = char['upper_leg'] - t.lower_leg_model = char['lower_leg'] - t.toes_model = char['toes_model'] - t.jump_sounds = char['jump_sounds'] - t.attack_sounds = char['attack_sounds'] - t.impact_sounds = char['impact_sounds'] - t.death_sounds = char['death_sounds'] - t.pickup_sounds = char['pickup_sounds'] - t.fall_sounds = char['fall_sounds'] - t.style = char['style'] - - - - - +def registercharacter(name, char): + t = Appearance(name.split(".")[0]) + t.color_texture = char['color_texture'] + t.color_mask_texture = char['color_mask'] + t.default_color = (0.6, 0.6, 0.6) + t.default_highlight = (0, 1, 0) + t.icon_texture = char['icon_texture'] + t.icon_mask_texture = char['icon_mask_texture'] + t.head_model = char['head'] + t.torso_model = char['torso'] + t.pelvis_model = char['pelvis'] + t.upper_arm_model = char['upper_arm'] + t.forearm_model = char['forearm'] + t.hand_model = char['hand'] + t.upper_leg_model = char['upper_leg'] + t.lower_leg_model = char['lower_leg'] + t.toes_model = char['toes_model'] + t.jump_sounds = char['jump_sounds'] + t.attack_sounds = char['attack_sounds'] + t.impact_sounds = char['impact_sounds'] + t.death_sounds = char['death_sounds'] + t.pickup_sounds = char['pickup_sounds'] + t.fall_sounds = char['fall_sounds'] + t.style = char['style'] # ba_meta export plugin class HeySmoothy(ba.Plugin): - + def __init__(self): _ba.set_party_icon_always_visible(True) - path=os.path.join(_ba.env()["python_directory_user"],"CustomCharacters" + os.sep) + path = os.path.join(_ba.env()["python_directory_user"], "CustomCharacters" + os.sep) if not os.path.isdir(path): os.makedirs(path) - files=os.listdir(path) + files = os.listdir(path) for file in files: with open(path+file, 'r') as f: character = json.load(f) - registercharacter(file,character) - - - - + registercharacter(file, character) From 83ddff5986c5ab1e452dc61f156fdccaa0a158b5 Mon Sep 17 00:00:00 2001 From: Rikko Date: Wed, 5 Oct 2022 22:30:29 +0530 Subject: [PATCH 0174/1464] Apply metadata --- plugins/utilities.json | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/plugins/utilities.json b/plugins/utilities.json index 050a1e3a..e6f5b367 100644 --- a/plugins/utilities.json +++ b/plugins/utilities.json @@ -201,7 +201,12 @@ } ], "versions": { - "1.0.0": null + "1.0.0": { + "api_version": 7, + "commit_sha": "9a2c3b", + "released_on": "05-10-2022", + "md5sum": "da7dfd7e3837ae8f1578b0cb0983f780" + } } }, "character_maker": { @@ -215,7 +220,12 @@ } ], "versions": { - "1.0.0": null + "1.0.0": { + "api_version": 7, + "commit_sha": "9a2c3b", + "released_on": "05-10-2022", + "md5sum": "0a3bd5728b7bbad6a7d4562079b05fea" + } } }, "icons_keyboard": { @@ -276,4 +286,4 @@ } } } -} +} \ No newline at end of file From c05e7060c3ab36a03188c2ca7d128d9956faeefc Mon Sep 17 00:00:00 2001 From: Rikko Date: Wed, 5 Oct 2022 22:36:50 +0530 Subject: [PATCH 0175/1464] Update MD5 hashes --- plugins/utilities.json | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/plugins/utilities.json b/plugins/utilities.json index e6f5b367..7badf8da 100644 --- a/plugins/utilities.json +++ b/plugins/utilities.json @@ -203,9 +203,9 @@ "versions": { "1.0.0": { "api_version": 7, - "commit_sha": "9a2c3b", + "commit_sha": "ff4de19", "released_on": "05-10-2022", - "md5sum": "da7dfd7e3837ae8f1578b0cb0983f780" + "md5sum": "38d47297d4048a2fe1022ea841c76f91" } } }, @@ -222,9 +222,9 @@ "versions": { "1.0.0": { "api_version": 7, - "commit_sha": "9a2c3b", + "commit_sha": "ff4de19", "released_on": "05-10-2022", - "md5sum": "0a3bd5728b7bbad6a7d4562079b05fea" + "md5sum": "f734fa33994c7cfafc637b7e3dca60ce" } } }, From 96a71b57a8c53ced2e1b139fd6ec10b9a8785055 Mon Sep 17 00:00:00 2001 From: Loup-Garou911XD Date: Thu, 6 Oct 2022 05:40:50 +0000 Subject: [PATCH 0176/1464] [ci] auto-format --- plugins/utilities/mood_light.py | 188 +++++++++++++++++--------------- 1 file changed, 99 insertions(+), 89 deletions(-) diff --git a/plugins/utilities/mood_light.py b/plugins/utilities/mood_light.py index 7807d51d..3eb85275 100644 --- a/plugins/utilities/mood_light.py +++ b/plugins/utilities/mood_light.py @@ -4,7 +4,8 @@ if TYPE_CHECKING: from typing import Any, Sequence, Callable, List, Dict, Tuple, Optional, Union -import ba,_ba +import ba +import _ba import random from ba._map import Map from bastd import mainmenu @@ -15,44 +16,45 @@ """mood light plugin by ʟօʊքɢǟʀօʊ type ml in chat or use plugin manager to open settings""" + def Print(*args): - out=" ".join(args) + out = " ".join(args) ba.screenmessage(out) + def cprint(*args): - out="\n".join(args) + out = "\n".join(args) _ba.chatmessage(out) -# -#class printerr:#for debugging +# +# class printerr:#for debugging # #def __init__(self): # global errcounter # errcounter=1 # def __enter__(self): # _ba.chatmessage("executing") -# +# # def __exit__(self, exc_type, exc_value, exc_tb): -# cprint(exc_type, exc_value, exc_tb) +# cprint(exc_type, exc_value, exc_tb) # if not(exc_type==None): -# cprint(exc_type, exc_value, exc_tb) +# cprint(exc_type, exc_value, exc_tb) # else: # cprint("Executed sucessfully","No error") try: - Ldefault, Udefault=ba.app.config.get("moodlightingSettings") + Ldefault, Udefault = ba.app.config.get("moodlightingSettings") except: - ba.app.config["moodlightingSettings"]=(15,20) - Ldefault, Udefault=ba.app.config.get("moodlightingSettings") - Print("settings up moodlight") - Print("Type ml in chat or use plugin manager to access settings") + ba.app.config["moodlightingSettings"] = (15, 20) + Ldefault, Udefault = ba.app.config.get("moodlightingSettings") + Print("settings up moodlight") + Print("Type ml in chat or use plugin manager to access settings") try: - loop=ba.app.config.get("moodlightEnabled") + loop = ba.app.config.get("moodlightEnabled") except: - ba.app.config["moodlightEnabled"]=True + ba.app.config["moodlightEnabled"] = True ba.app.config.commit() - loop=True - + loop = True class SettingWindow(ba.Window): @@ -123,25 +125,24 @@ def draw_ui(self): v_align="center", text="Mood light settings", color=(0, 1, 0)) - - self.enable_button=ba.buttonwidget( + + self.enable_button = ba.buttonwidget( parent=self._root_widget, position=(100, 470), size=(90, 70), scale=1.5, - color=(1,0,0) if loop else (0,1,0), + color=(1, 0, 0) if loop else (0, 1, 0), label="DISABLE" if loop else "ENABLE", on_activate_call=self.on_enableButton_press) - - + save_button = ba.buttonwidget( parent=self._root_widget, position=(520, 470), size=(90, 70), scale=1.5, label="SAVE", - on_activate_call=self.save_settings) - + on_activate_call=self.save_settings) + self.close_button = ba.buttonwidget( parent=self._root_widget, position=(550, 590), @@ -192,7 +193,7 @@ def draw_ui(self): h_align="center", v_align="center", text="Limit brightness") - + decrease_button = ba.buttonwidget( parent=self._root_widget, position=(100, 100), @@ -200,7 +201,7 @@ def draw_ui(self): scale=3.5, extra_touch_border_scale=2.5, icon=ba.gettexture("downButton"), - on_activate_call=self.decrease_limit) + on_activate_call=self.decrease_limit) increase_button = ba.buttonwidget( parent=self._root_widget, @@ -218,39 +219,46 @@ def draw_ui(self): position=(150, 300), h_align="center", v_align="center", - maxwidth=600) - -#++++++++++++++++for keyboard navigation++++++++++++++++ - ba.widget(edit=self.enable_button,up_widget=decrease_button,down_widget=self.lower_text,left_widget=save_button,right_widget=save_button) - ba.widget(edit=save_button,up_widget=self.close_button,down_widget=self.upper_text,left_widget=self.enable_button,right_widget=self.enable_button) - ba.widget(edit=self.close_button,up_widget=increase_button,down_widget=save_button,left_widget=self.enable_button,right_widget=save_button) - ba.widget(edit=self.lower_text,up_widget=self.enable_button,down_widget=decrease_button,left_widget=self.upper_text,right_widget=self.upper_text) - ba.widget(edit=self.upper_text,up_widget=save_button,down_widget=increase_button,left_widget=self.lower_text,right_widget=self.lower_text) - ba.widget(edit=decrease_button,up_widget=self.lower_text,down_widget=self.enable_button,left_widget=increase_button,right_widget=increase_button) - ba.widget(edit=increase_button,up_widget=self.upper_text,down_widget=self.close_button,left_widget=decrease_button,right_widget=decrease_button) -#-------------------------------------------------------------------------------------------------- - + maxwidth=600) + +# ++++++++++++++++for keyboard navigation++++++++++++++++ + ba.widget(edit=self.enable_button, up_widget=decrease_button, + down_widget=self.lower_text, left_widget=save_button, right_widget=save_button) + ba.widget(edit=save_button, up_widget=self.close_button, down_widget=self.upper_text, + left_widget=self.enable_button, right_widget=self.enable_button) + ba.widget(edit=self.close_button, up_widget=increase_button, down_widget=save_button, + left_widget=self.enable_button, right_widget=save_button) + ba.widget(edit=self.lower_text, up_widget=self.enable_button, down_widget=decrease_button, + left_widget=self.upper_text, right_widget=self.upper_text) + ba.widget(edit=self.upper_text, up_widget=save_button, down_widget=increase_button, + left_widget=self.lower_text, right_widget=self.lower_text) + ba.widget(edit=decrease_button, up_widget=self.lower_text, down_widget=self.enable_button, + left_widget=increase_button, right_widget=increase_button) + ba.widget(edit=increase_button, up_widget=self.upper_text, down_widget=self.close_button, + left_widget=decrease_button, right_widget=decrease_button) +# -------------------------------------------------------------------------------------------------- + ba.textwidget(edit=self.upper_text, on_activate_call=ba.Call(self.on_text_click, "upper")) ba.textwidget(edit=self.lower_text, on_activate_call=ba.Call(self.on_text_click, "lower")) - + def on_enableButton_press(self): global loop - loop=ba.app.config.get("moodlightEnabled") + loop = ba.app.config.get("moodlightEnabled") if loop: - loop=False - label="ENABLE" - color=(0,1,0) + loop = False + label = "ENABLE" + color = (0, 1, 0) elif not loop: - loop=True - label="DISABLE" - color=(1,0,0) - Print("Restart level to enable") - ba.app.config["moodlightEnabled"]=loop + loop = True + label = "DISABLE" + color = (1, 0, 0) + Print("Restart level to enable") + ba.app.config["moodlightEnabled"] = loop ba.app.config.commit() - ba.buttonwidget(edit=self.enable_button,label=label,color=color) - + ba.buttonwidget(edit=self.enable_button, label=label, color=color) + def save_settings(self): - ba.app.config["moodlightingSettings"]=(Ldefault,Udefault) + ba.app.config["moodlightingSettings"] = (Ldefault, Udefault) ba.app.config.commit() Print("settings saved") self.close() @@ -258,58 +266,60 @@ def save_settings(self): def close(self): ba.containerwidget(edit=self._root_widget, transition="out_right",) -def new_chat_message(msg: Union[str, ba.Lstr], clients:Sequence[int] = None, sender_override: str = None): - old_fcm(msg, clients, sender_override) - if msg == 'ml': - try: - Ldefault, Udefault=ba.app.config.get("moodlightingSettings") - SettingWindow() - cprint("Mood light settings opened") - except Exception as err: - Print(err) - + +def new_chat_message(msg: Union[str, ba.Lstr], clients: Sequence[int] = None, sender_override: str = None): + old_fcm(msg, clients, sender_override) + if msg == 'ml': + try: + Ldefault, Udefault = ba.app.config.get("moodlightingSettings") + SettingWindow() + cprint("Mood light settings opened") + except Exception as err: + Print(err) + + old_fcm = _ba.chatmessage _ba.chatmessage = new_chat_message _ba.set_party_icon_always_visible(True) -Map._old_init = Map.__init__ - +Map._old_init = Map.__init__ + # ba_meta export plugin + class moodlight(ba.Plugin): def __init__(self): pass - + def on_app_running(self): - _ba.show_progress_bar() + _ba.show_progress_bar() + + def on_plugin_manager_prompt(self): # called by plugin manager + SettingWindow() - def on_plugin_manager_prompt(self):#called by plugin manager - SettingWindow() - def _new_init(self, vr_overlay_offset: Optional[Sequence[float]] = None) -> None: self._old_init(vr_overlay_offset) - in_game = not isinstance(_ba.get_foreground_host_session(), mainmenu.MainMenuSession) + in_game = not isinstance(_ba.get_foreground_host_session(), mainmenu.MainMenuSession) if not in_game: return - + gnode = _ba.getactivity().globalsnode - default_tint=(1.100000023841858, 1.0, 0.8999999761581421) - transition_duration=1.0#for future improvements - - def changetint(): - if loop: - Range = (random.randrange(Ldefault, Udefault)/10, random.randrange(Ldefault, - Udefault)/10, random.randrange(Ldefault, Udefault)/10) - ba.animate_array(gnode, 'tint', 3 ,{ - 0.0: gnode.tint, - transition_duration: Range - }) - else: - global timer - timer=None - ba.animate_array(gnode,"tint",3, {0.0:gnode.tint,0.4:default_tint}) - + default_tint = (1.100000023841858, 1.0, 0.8999999761581421) + transition_duration = 1.0 # for future improvements + + def changetint(): + if loop: + Range = (random.randrange(Ldefault, Udefault)/10, random.randrange(Ldefault, + Udefault)/10, random.randrange(Ldefault, Udefault)/10) + ba.animate_array(gnode, 'tint', 3, { + 0.0: gnode.tint, + transition_duration: Range + }) + else: + global timer + timer = None + ba.animate_array(gnode, "tint", 3, {0.0: gnode.tint, 0.4: default_tint}) + global timer - timer=ba.Timer(0.3, changetint, repeat=True) - - Map.__init__ = _new_init + timer = ba.Timer(0.3, changetint, repeat=True) + Map.__init__ = _new_init From 99a837b772e4e805e15a8fae5784c4f70f6002df Mon Sep 17 00:00:00 2001 From: Loup <90267658+Loup-Garou911XD@users.noreply.github.com> Date: Thu, 6 Oct 2022 11:32:21 +0530 Subject: [PATCH 0177/1464] Removed unused code --- plugins/utilities/mood_light.py | 15 --------------- 1 file changed, 15 deletions(-) diff --git a/plugins/utilities/mood_light.py b/plugins/utilities/mood_light.py index 3eb85275..c2f6cef9 100644 --- a/plugins/utilities/mood_light.py +++ b/plugins/utilities/mood_light.py @@ -25,21 +25,6 @@ def Print(*args): def cprint(*args): out = "\n".join(args) _ba.chatmessage(out) -# -# class printerr:#for debugging -# #def __init__(self): -# global errcounter -# errcounter=1 -# def __enter__(self): -# _ba.chatmessage("executing") -# -# def __exit__(self, exc_type, exc_value, exc_tb): -# cprint(exc_type, exc_value, exc_tb) -# if not(exc_type==None): -# cprint(exc_type, exc_value, exc_tb) -# else: -# cprint("Executed sucessfully","No error") - try: Ldefault, Udefault = ba.app.config.get("moodlightingSettings") From 454ed537e312cce8696c28613003712a960910e0 Mon Sep 17 00:00:00 2001 From: Loup-Garou911XD Date: Thu, 6 Oct 2022 06:02:49 +0000 Subject: [PATCH 0178/1464] [ci] auto-format --- plugins/utilities/mood_light.py | 1 + 1 file changed, 1 insertion(+) diff --git a/plugins/utilities/mood_light.py b/plugins/utilities/mood_light.py index c2f6cef9..0a0b8272 100644 --- a/plugins/utilities/mood_light.py +++ b/plugins/utilities/mood_light.py @@ -26,6 +26,7 @@ def cprint(*args): out = "\n".join(args) _ba.chatmessage(out) + try: Ldefault, Udefault = ba.app.config.get("moodlightingSettings") except: From d04d04e4913af738f8c242d7222fde1cc1b4c5ea Mon Sep 17 00:00:00 2001 From: Loup <90267658+Loup-Garou911XD@users.noreply.github.com> Date: Thu, 6 Oct 2022 11:36:28 +0530 Subject: [PATCH 0179/1464] Added version 1.2.0 --- plugins/utilities.json | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/plugins/utilities.json b/plugins/utilities.json index 7badf8da..a0412b8e 100644 --- a/plugins/utilities.json +++ b/plugins/utilities.json @@ -14,6 +14,8 @@ } ], "versions": { + "1.2.0":{ + }, "1.0.0": { "api_version": 7, "commit_sha": "430da49", @@ -286,4 +288,4 @@ } } } -} \ No newline at end of file +} From 59940fd9575acca828e9bbd6a3c8099147709ad4 Mon Sep 17 00:00:00 2001 From: Loup-Garou911XD Date: Thu, 6 Oct 2022 06:06:51 +0000 Subject: [PATCH 0180/1464] [ci] apply-version-metadata --- plugins/utilities.json | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/plugins/utilities.json b/plugins/utilities.json index a0412b8e..08a50975 100644 --- a/plugins/utilities.json +++ b/plugins/utilities.json @@ -14,8 +14,7 @@ } ], "versions": { - "1.2.0":{ - }, + "1.2.0": {}, "1.0.0": { "api_version": 7, "commit_sha": "430da49", @@ -288,4 +287,4 @@ } } } -} +} \ No newline at end of file From d838115de3f06f62b8f8076304afd72d6b069f90 Mon Sep 17 00:00:00 2001 From: Loup <90267658+Loup-Garou911XD@users.noreply.github.com> Date: Thu, 6 Oct 2022 11:41:52 +0530 Subject: [PATCH 0181/1464] Update utilities.json --- plugins/utilities.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/plugins/utilities.json b/plugins/utilities.json index 08a50975..b4c6ef2b 100644 --- a/plugins/utilities.json +++ b/plugins/utilities.json @@ -14,7 +14,7 @@ } ], "versions": { - "1.2.0": {}, + "1.2.0": null, "1.0.0": { "api_version": 7, "commit_sha": "430da49", @@ -287,4 +287,4 @@ } } } -} \ No newline at end of file +} From 6b66c44167f5a30107167098f3bfd9196af8dcea Mon Sep 17 00:00:00 2001 From: Loup-Garou911XD Date: Thu, 6 Oct 2022 06:12:17 +0000 Subject: [PATCH 0182/1464] [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 b4c6ef2b..98bffec8 100644 --- a/plugins/utilities.json +++ b/plugins/utilities.json @@ -14,7 +14,12 @@ } ], "versions": { - "1.2.0": null, + "1.2.0": { + "api_version": 7, + "commit_sha": "d838115", + "released_on": "06-10-2022", + "md5sum": "bcb8e605969eef35a210590b410e2d44" + }, "1.0.0": { "api_version": 7, "commit_sha": "430da49", @@ -287,4 +292,4 @@ } } } -} +} \ No newline at end of file From 6e5964a01bab0c81ac196206a741164469c630bf Mon Sep 17 00:00:00 2001 From: Loup <90267658+Loup-Garou911XD@users.noreply.github.com> Date: Mon, 10 Oct 2022 13:53:11 +0530 Subject: [PATCH 0183/1464] Made variables global Made Ldefault,Udefault variables global in new_chat function --- plugins/utilities/mood_light.py | 1 + 1 file changed, 1 insertion(+) diff --git a/plugins/utilities/mood_light.py b/plugins/utilities/mood_light.py index 0a0b8272..8ed9801d 100644 --- a/plugins/utilities/mood_light.py +++ b/plugins/utilities/mood_light.py @@ -257,6 +257,7 @@ def new_chat_message(msg: Union[str, ba.Lstr], clients: Sequence[int] = None, se old_fcm(msg, clients, sender_override) if msg == 'ml': try: + global Ldefault,Udefault Ldefault, Udefault = ba.app.config.get("moodlightingSettings") SettingWindow() cprint("Mood light settings opened") From 7f7e2fd0a4cc81739293014f611115fde415951f Mon Sep 17 00:00:00 2001 From: Loup-Garou911XD Date: Mon, 10 Oct 2022 08:23:32 +0000 Subject: [PATCH 0184/1464] [ci] auto-format --- plugins/utilities/mood_light.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/utilities/mood_light.py b/plugins/utilities/mood_light.py index 8ed9801d..df1024f5 100644 --- a/plugins/utilities/mood_light.py +++ b/plugins/utilities/mood_light.py @@ -257,7 +257,7 @@ def new_chat_message(msg: Union[str, ba.Lstr], clients: Sequence[int] = None, se old_fcm(msg, clients, sender_override) if msg == 'ml': try: - global Ldefault,Udefault + global Ldefault, Udefault Ldefault, Udefault = ba.app.config.get("moodlightingSettings") SettingWindow() cprint("Mood light settings opened") From 86a22ce16ab59a99e6cbdd8daed73f4f2924368a Mon Sep 17 00:00:00 2001 From: Freaku17 <92618708+Freaku17@users.noreply.github.com> Date: Mon, 10 Oct 2022 20:37:49 +0530 Subject: [PATCH 0185/1464] Fix `chatmessage` in character_maker --- plugins/utilities/character_maker.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/plugins/utilities/character_maker.py b/plugins/utilities/character_maker.py index 218c336f..ba011676 100644 --- a/plugins/utilities/character_maker.py +++ b/plugins/utilities/character_maker.py @@ -439,7 +439,7 @@ def initdic(self): cm = _ba.chatmessage -def _new_chatmessage(msg): +def _new_chatmessage(msg: str | ba.Lstr, clients: Sequence[int] | None = None, sender_override: str | None = None): if msg.split(" ")[0] == "export": if len(msg.split(" ")) > 1: savecharacter(msg.split(" ")[1]) @@ -449,7 +449,7 @@ def _new_chatmessage(msg): importcharacter(msg[7:]) else: - cm(msg) + cm(msg, clients, sender_override) _ba.chatmessage = _new_chatmessage From 225aec8a52f2595f04ad36aea4a90e731057a6c7 Mon Sep 17 00:00:00 2001 From: Freaku17 <92618708+Freaku17@users.noreply.github.com> Date: Mon, 10 Oct 2022 20:43:22 +0530 Subject: [PATCH 0186/1464] Update utilities.json Manually updating this, so as to avoid changing "released_on" date Not a new version as it's just a `fix` --- plugins/utilities.json | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/plugins/utilities.json b/plugins/utilities.json index 98bffec8..0f55e4d3 100644 --- a/plugins/utilities.json +++ b/plugins/utilities.json @@ -228,9 +228,9 @@ "versions": { "1.0.0": { "api_version": 7, - "commit_sha": "ff4de19", + "commit_sha": "86a22ce", "released_on": "05-10-2022", - "md5sum": "f734fa33994c7cfafc637b7e3dca60ce" + "md5sum": "b19ff011b6e229544324d4310770d7b9" } } }, @@ -292,4 +292,4 @@ } } } -} \ No newline at end of file +} From 9b385ff4f6c3223a2acd10fcbe07fadc9ecbb969 Mon Sep 17 00:00:00 2001 From: Freaku17 Date: Mon, 10 Oct 2022 15:15:11 +0000 Subject: [PATCH 0187/1464] [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 0f55e4d3..a0dca85a 100644 --- a/plugins/utilities.json +++ b/plugins/utilities.json @@ -292,4 +292,4 @@ } } } -} +} \ No newline at end of file From 8256d182679c84dd32d704668b59df62848d1257 Mon Sep 17 00:00:00 2001 From: Freaku17 <92618708+Freaku17@users.noreply.github.com> Date: Mon, 10 Oct 2022 21:03:54 +0530 Subject: [PATCH 0188/1464] Update utilities.json --- plugins/utilities.json | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/plugins/utilities.json b/plugins/utilities.json index a0dca85a..4169bc87 100644 --- a/plugins/utilities.json +++ b/plugins/utilities.json @@ -228,10 +228,11 @@ "versions": { "1.0.0": { "api_version": 7, - "commit_sha": "86a22ce", + "commit_sha": "ff4de19", "released_on": "05-10-2022", - "md5sum": "b19ff011b6e229544324d4310770d7b9" - } + "md5sum": "f734fa33994c7cfafc637b7e3dca60ce" + }, + "1.0.1": null } }, "icons_keyboard": { @@ -292,4 +293,4 @@ } } } -} \ No newline at end of file +} From 85f8b55706e14e4adf9709c8e4d680416491fa7d Mon Sep 17 00:00:00 2001 From: Freaku17 Date: Mon, 10 Oct 2022 15:34:15 +0000 Subject: [PATCH 0189/1464] [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 4169bc87..66eb91bd 100644 --- a/plugins/utilities.json +++ b/plugins/utilities.json @@ -293,4 +293,4 @@ } } } -} +} \ No newline at end of file From a2a7d87c1c505136a86c48edcff3b2dc69680461 Mon Sep 17 00:00:00 2001 From: Rikko Date: Mon, 10 Oct 2022 21:43:08 +0530 Subject: [PATCH 0190/1464] ci: sort plugin versions --- test/auto_apply_version_metadata.py | 36 +++++++++++++++++++++-------- 1 file changed, 27 insertions(+), 9 deletions(-) diff --git a/test/auto_apply_version_metadata.py b/test/auto_apply_version_metadata.py index 317c3bcf..5dd8b5bd 100644 --- a/test/auto_apply_version_metadata.py +++ b/test/auto_apply_version_metadata.py @@ -6,6 +6,10 @@ import datetime +def get_comparable_version_tuple_from_string(version_string): + return tuple(map(int, version_string.split("."))) + + class PluginVersionMetadata: def __init__(self, plugin_name, version_name, plugin_path, from_json={}): self.plugin_name = plugin_name @@ -69,6 +73,20 @@ def calculate_md5sum(self): md5sum = hashlib.md5(self._content).hexdigest() return md5sum + def sort_versions(self): + if self._content is None: + with open(self.plugin_path, "rb") as fin: + self._content = fin.read() + + versions = self.json["plugins"][self.plugin_name]["versions"] + sorted_versions = dict(sorted( + tuple(versions.items()), + key=lambda version: get_comparable_version_tuple_from_string(version[0]), + reverse=True, + )) + self.json["plugins"][self.plugin_name]["versions"] = sorted_versions + return self + class CategoryVersionMetadata: def __init__(self, category_metadata_base): @@ -79,15 +97,14 @@ def __init__(self, category_metadata_base): def get_plugins_having_null_version_values(self): for plugin_name, plugin_metadata in self.category_metadata["plugins"].items(): - latest_version_name, latest_version_metadata = tuple( - plugin_metadata["versions"].items())[0] - if latest_version_metadata is None: - plugin_path = f"{os.path.join(self.category_metadata_base, f'{plugin_name}.py')}" - yield PluginVersionMetadata( - plugin_name, - latest_version_name, - plugin_path, - ) + for version_name, version_metadata in plugin_metadata["versions"].items(): + if version_metadata is None: + plugin_path = f"{os.path.join(self.category_metadata_base, f'{plugin_name}.py')}" + yield PluginVersionMetadata( + plugin_name, + version_name, + plugin_path, + ) def get_plugins_having_diff_last_md5sum_version_values(self): for plugin_name, plugin_metadata in self.category_metadata["plugins"].items(): @@ -121,6 +138,7 @@ def apply_metadata_to_plugins(self, commit_sha, plugins): .set_commit_sha(commit_sha) .set_released_on(today) .set_md5sum() + .sort_versions() .json ) return category_json From da1031887e106525f0a3acf6d7d8e632c198bb7f Mon Sep 17 00:00:00 2001 From: Rikko Date: Mon, 10 Oct 2022 21:49:36 +0530 Subject: [PATCH 0191/1464] Reorder versions --- plugins/utilities.json | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/plugins/utilities.json b/plugins/utilities.json index 66eb91bd..6f7d72f0 100644 --- a/plugins/utilities.json +++ b/plugins/utilities.json @@ -226,13 +226,13 @@ } ], "versions": { + "1.0.1": null, "1.0.0": { "api_version": 7, "commit_sha": "ff4de19", "released_on": "05-10-2022", "md5sum": "f734fa33994c7cfafc637b7e3dca60ce" - }, - "1.0.1": null + } } }, "icons_keyboard": { @@ -293,4 +293,4 @@ } } } -} \ No newline at end of file +} From c5404f71dc95aa8cec4fd294935dd865f2f47f41 Mon Sep 17 00:00:00 2001 From: rikkolovescats Date: Mon, 10 Oct 2022 16:20:23 +0000 Subject: [PATCH 0192/1464] [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 6f7d72f0..63413f65 100644 --- a/plugins/utilities.json +++ b/plugins/utilities.json @@ -226,7 +226,12 @@ } ], "versions": { - "1.0.1": null, + "1.0.1": { + "api_version": 7, + "commit_sha": "da10318", + "released_on": "10-10-2022", + "md5sum": "b19ff011b6e229544324d4310770d7b9" + }, "1.0.0": { "api_version": 7, "commit_sha": "ff4de19", @@ -293,4 +298,4 @@ } } } -} +} \ No newline at end of file From 9cb71d94089c8352d6c8b878a9b26fa27010b1a7 Mon Sep 17 00:00:00 2001 From: Cross Joy <87638792+CrossJoy@users.noreply.github.com> Date: Sat, 22 Oct 2022 18:14:29 +0800 Subject: [PATCH 0193/1464] Added a new minigame Added Ultimate Last Stand by Cross Joy minigame. --- plugins/minigames/ultimate_last_stand.py | 620 +++++++++++++++++++++++ 1 file changed, 620 insertions(+) create mode 100644 plugins/minigames/ultimate_last_stand.py diff --git a/plugins/minigames/ultimate_last_stand.py b/plugins/minigames/ultimate_last_stand.py new file mode 100644 index 00000000..8b159331 --- /dev/null +++ b/plugins/minigames/ultimate_last_stand.py @@ -0,0 +1,620 @@ +"""Ultimate Last Stand V2: +Made by Cross Joy""" + +# Anyone who wanna help me in giving suggestion/ fix bugs/ by creating PR, +# Can visit my github https://github.com/CrossJoy/Bombsquad-Modding + +# You can contact me through discord: +# My Discord Id: Cross Joy#0721 +# My BS Discord Server: https://discord.gg/JyBY6haARJ + + +# ---------------------------------------------------------------------------- +# V2 What's new? + +# - The "Player can't fight each other" system is removed, +# players exploiting the features and, I know ideas how to fix it especially +# the freeze handlemessage + +# - Added new bot: Ice Bot + +# - The bot spawn location will be more randomize rather than based on players +# position, I don't wanna players stay at the corner of the map. + +# - Some codes clean up. + +# ---------------------------------------------------------------------------- + +# ba_meta require api 7 + +from __future__ import annotations + +import random +from dataclasses import dataclass +from typing import TYPE_CHECKING + +import ba +from bastd.actor.playerspaz import PlayerSpaz +from bastd.actor.bomb import TNTSpawner +from bastd.actor.onscreentimer import OnScreenTimer +from bastd.actor.scoreboard import Scoreboard +from bastd.actor.spazfactory import SpazFactory +from bastd.actor.spazbot import (SpazBot, SpazBotSet, BomberBot, + BomberBotPro, BomberBotProShielded, + BrawlerBot, BrawlerBotPro, + BrawlerBotProShielded, TriggerBot, + TriggerBotPro, TriggerBotProShielded, + ChargerBot, StickyBot, ExplodeyBot) + +if TYPE_CHECKING: + from typing import Any, Sequence + from bastd.actor.spazbot import SpazBot + + +class IceBot(SpazBot): + """A slow moving bot with ice bombs. + + category: Bot Classes + """ + character = 'Pascal' + punchiness = 0.9 + throwiness = 1 + charge_speed_min = 1 + charge_speed_max = 1 + throw_dist_min = 5.0 + throw_dist_max = 20 + run = True + charge_dist_min = 10.0 + charge_dist_max = 11.0 + default_bomb_type = 'ice' + default_bomb_count = 1 + points_mult = 3 + + +class Icon(ba.Actor): + """Creates in in-game icon on screen.""" + + def __init__(self, + player: Player, + position: tuple[float, float], + scale: float, + show_lives: bool = True, + show_death: bool = True, + name_scale: float = 1.0, + name_maxwidth: float = 115.0, + flatness: float = 1.0, + shadow: float = 1.0): + super().__init__() + + self._player = player + self._show_lives = show_lives + self._show_death = show_death + self._name_scale = name_scale + self._outline_tex = ba.gettexture('characterIconMask') + + icon = player.get_icon() + self.node = ba.newnode('image', + delegate=self, + attrs={ + 'texture': icon['texture'], + 'tint_texture': icon['tint_texture'], + 'tint_color': icon['tint_color'], + 'vr_depth': 400, + 'tint2_color': icon['tint2_color'], + 'mask_texture': self._outline_tex, + 'opacity': 1.0, + 'absolute_scale': True, + 'attach': 'bottomCenter' + }) + self._name_text = ba.newnode( + 'text', + owner=self.node, + attrs={ + 'text': ba.Lstr(value=player.getname()), + 'color': ba.safecolor(player.team.color), + 'h_align': 'center', + 'v_align': 'center', + 'vr_depth': 410, + 'maxwidth': name_maxwidth, + 'shadow': shadow, + 'flatness': flatness, + 'h_attach': 'center', + 'v_attach': 'bottom' + }) + if self._show_lives: + self._lives_text = ba.newnode('text', + owner=self.node, + attrs={ + 'text': 'x0', + 'color': (1, 1, 0.5), + 'h_align': 'left', + 'vr_depth': 430, + 'shadow': 1.0, + 'flatness': 1.0, + 'h_attach': 'center', + 'v_attach': 'bottom' + }) + self.set_position_and_scale(position, scale) + + def set_position_and_scale(self, position: tuple[float, float], + scale: float) -> None: + """(Re)position the icon.""" + assert self.node + self.node.position = position + self.node.scale = [70.0 * scale] + self._name_text.position = (position[0], position[1] + scale * 52.0) + self._name_text.scale = 1.0 * scale * self._name_scale + if self._show_lives: + self._lives_text.position = (position[0] + scale * 10.0, + position[1] - scale * 43.0) + self._lives_text.scale = 1.0 * scale + + def update_for_lives(self) -> None: + """Update for the target player's current lives.""" + if self._player: + lives = self._player.lives + else: + lives = 0 + if self._show_lives: + if lives > 0: + self._lives_text.text = 'x' + str(lives - 1) + else: + self._lives_text.text = '' + if lives == 0: + self._name_text.opacity = 0.2 + assert self.node + self.node.color = (0.7, 0.3, 0.3) + self.node.opacity = 0.2 + + def handle_player_spawned(self) -> None: + """Our player spawned; hooray!""" + if not self.node: + return + self.node.opacity = 1.0 + self.update_for_lives() + + def handle_player_died(self) -> None: + """Well poo; our player died.""" + if not self.node: + return + if self._show_death: + ba.animate( + self.node, 'opacity', { + 0.00: 1.0, + 0.05: 0.0, + 0.10: 1.0, + 0.15: 0.0, + 0.20: 1.0, + 0.25: 0.0, + 0.30: 1.0, + 0.35: 0.0, + 0.40: 1.0, + 0.45: 0.0, + 0.50: 1.0, + 0.55: 0.2 + }) + lives = self._player.lives + if lives == 0: + ba.timer(0.6, self.update_for_lives) + + def handlemessage(self, msg: Any) -> Any: + if isinstance(msg, ba.DieMessage): + self.node.delete() + return None + return super().handlemessage(msg) + + +@dataclass +class SpawnInfo: + """Spawning info for a particular bot type.""" + spawnrate: float + increase: float + dincrease: float + + +class Player(ba.Player['Team']): + """Our player type for this game.""" + + def __init__(self) -> None: + super().__init__() + self.death_time: float | None = None + self.lives = 0 + self.icons: list[Icon] = [] + + +class Team(ba.Team[Player]): + """Our team type for this game.""" + + def __init__(self) -> None: + self.survival_seconds: int | None = None + self.spawn_order: list[Player] = [] + + +# ba_meta export game +class UltimateLastStand(ba.TeamGameActivity[Player, Team]): + """Minigame involving dodging falling bombs.""" + + name = 'Ultimate Last Stand' + description = 'Only the strongest will stand at the end.' + scoreconfig = ba.ScoreConfig(label='Survived', + scoretype=ba.ScoreType.SECONDS, + none_is_winner=True) + + # Print messages when players die (since its meaningful in this game). + announce_player_deaths = True + + # Don't allow joining after we start + # (would enable leave/rejoin tomfoolery). + allow_mid_activity_joins = False + + @classmethod + def get_available_settings( + cls, + sessiontype: type[ba.Session]) -> list[ba.Setting]: + settings = [ + ba.IntSetting( + 'Lives Per Player', + default=1, + min_value=1, + max_value=10, + increment=1, + ), + ba.FloatChoiceSetting( + 'Respawn Times', + choices=[ + ('Shorter', 0.25), + ('Short', 0.5), + ('Normal', 1.0), + ('Long', 2.0), + ('Longer', 4.0), + ], + default=1.0, + ), + ba.BoolSetting('Epic Mode', default=False), + ] + if issubclass(sessiontype, ba.DualTeamSession): + settings.append( + ba.BoolSetting('Balance Total Lives', default=False)) + return settings + + # We're currently hard-coded for one map. + @classmethod + def get_supported_maps(cls, sessiontype: type[ba.Session]) -> list[str]: + return ['Rampage'] + + # We support teams, free-for-all, and co-op sessions. + @classmethod + def supports_session_type(cls, sessiontype: type[ba.Session]) -> bool: + return (issubclass(sessiontype, ba.DualTeamSession) + or issubclass(sessiontype, ba.FreeForAllSession)) + + def __init__(self, settings: dict): + super().__init__(settings) + + self._scoreboard = Scoreboard() + self._start_time: float | None = None + self._vs_text: ba.Actor | None = None + self._round_end_timer: ba.Timer | None = None + self._lives_per_player = int(settings['Lives Per Player']) + self._balance_total_lives = bool( + settings.get('Balance Total Lives', False)) + self._epic_mode = settings.get('Epic Mode', True) + self._last_player_death_time: float | None = None + self._timer: OnScreenTimer | None = None + self._tntspawner: TNTSpawner | None = None + self._new_wave_sound = ba.getsound('scoreHit01') + self._bots = SpazBotSet() + self._tntspawnpos = (0, 5.5, -6) + self.spazList = [] + + # Base class overrides: + self.slow_motion = self._epic_mode + self.default_music = (ba.MusicType.EPIC + if self._epic_mode else ba.MusicType.SURVIVAL) + + self.node = ba.newnode('text', + attrs={ + 'v_attach': 'bottom', + 'h_align': 'center', + 'color': (0.83, 0.69, 0.21), + 'flatness': 0.5, + 'shadow': 0.5, + 'position': (0, 75), + 'scale': 0.7, + 'text': 'By Cross Joy' + }) + + # For each bot type: [spawnrate, increase, d_increase] + self._bot_spawn_types = { + BomberBot: SpawnInfo(1.00, 0.00, 0.000), + BomberBotPro: SpawnInfo(0.00, 0.05, 0.001), + BomberBotProShielded: SpawnInfo(0.00, 0.02, 0.002), + BrawlerBot: SpawnInfo(1.00, 0.00, 0.000), + BrawlerBotPro: SpawnInfo(0.00, 0.05, 0.001), + BrawlerBotProShielded: SpawnInfo(0.00, 0.02, 0.002), + TriggerBot: SpawnInfo(0.30, 0.00, 0.000), + TriggerBotPro: SpawnInfo(0.00, 0.05, 0.001), + TriggerBotProShielded: SpawnInfo(0.00, 0.02, 0.002), + ChargerBot: SpawnInfo(0.30, 0.05, 0.000), + StickyBot: SpawnInfo(0.10, 0.03, 0.001), + IceBot: SpawnInfo(0.10, 0.03, 0.001), + ExplodeyBot: SpawnInfo(0.05, 0.02, 0.002) + } # yapf: disable + + # Some base class overrides: + self.default_music = (ba.MusicType.EPIC + if self._epic_mode else ba.MusicType.SURVIVAL) + if self._epic_mode: + self.slow_motion = True + + def get_instance_description(self) -> str | Sequence: + return 'Only the strongest team will stand at the end.' if isinstance( + self.session, + ba.DualTeamSession) else 'Only the strongest will stand at the end.' + + def get_instance_description_short(self) -> str | Sequence: + return 'Only the strongest team will stand at the end.' if isinstance( + self.session, + ba.DualTeamSession) else 'Only the strongest will stand at the end.' + + def on_transition_in(self) -> None: + super().on_transition_in() + ba.timer(1.3, ba.Call(ba.playsound, self._new_wave_sound)) + + def on_player_join(self, player: Player) -> None: + player.lives = self._lives_per_player + + # Don't waste time doing this until begin. + player.icons = [Icon(player, position=(0, 50), scale=0.8)] + if player.lives > 0: + self.spawn_player(player) + + if self.has_begun(): + self._update_icons() + + def on_begin(self) -> None: + super().on_begin() + ba.animate_array(node=self.node, attr='color', size=3, keys={ + 0.0: (0.5, 0.5, 0.5), + 0.8: (0.83, 0.69, 0.21), + 1.6: (0.5, 0.5, 0.5) + }, loop=True) + + ba.timer(0.001, ba.WeakCall(self._start_bot_updates)) + self._tntspawner = TNTSpawner(position=self._tntspawnpos, + respawn_time=10.0) + + self._timer = OnScreenTimer() + self._timer.start() + self.setup_standard_powerup_drops() + + # Check for immediate end (if we've only got 1 player, etc). + self._start_time = ba.time() + + # If balance-team-lives is on, add lives to the smaller team until + # total lives match. + if (isinstance(self.session, ba.DualTeamSession) + and self._balance_total_lives and self.teams[0].players + and self.teams[1].players): + if self._get_total_team_lives( + self.teams[0]) < self._get_total_team_lives(self.teams[1]): + lesser_team = self.teams[0] + greater_team = self.teams[1] + else: + lesser_team = self.teams[1] + greater_team = self.teams[0] + add_index = 0 + while (self._get_total_team_lives(lesser_team) < + self._get_total_team_lives(greater_team)): + lesser_team.players[add_index].lives += 1 + add_index = (add_index + 1) % len(lesser_team.players) + + ba.timer(1.0, self._update, repeat=True) + self._update_icons() + + # We could check game-over conditions at explicit trigger points, + # but lets just do the simple thing and poll it. + + def _update_icons(self) -> None: + # pylint: disable=too-many-branches + + # In free-for-all mode, everyone is just lined up along the bottom. + if isinstance(self.session, ba.FreeForAllSession): + count = len(self.teams) + x_offs = 85 + xval = x_offs * (count - 1) * -0.5 + for team in self.teams: + if len(team.players) == 1: + player = team.players[0] + for icon in player.icons: + icon.set_position_and_scale((xval, 30), 0.7) + icon.update_for_lives() + xval += x_offs + + # In teams mode we split up teams. + else: + for team in self.teams: + if team.id == 0: + xval = -50 + x_offs = -85 + else: + xval = 50 + x_offs = 85 + for player in team.players: + for icon in player.icons: + icon.set_position_and_scale((xval, 30), 0.7) + icon.update_for_lives() + xval += x_offs + + def on_player_leave(self, player: Player) -> None: + # Augment default behavior. + super().on_player_leave(player) + player.icons = [] + + # Update icons in a moment since our team will be gone from the + # list then. + ba.timer(0, self._update_icons) + + # If the player to leave was the last in spawn order and had + # their final turn currently in-progress, mark the survival time + # for their team. + if self._get_total_team_lives(player.team) == 0: + assert self._start_time is not None + player.team.survival_seconds = int(ba.time() - self._start_time) + + # A departing player may trigger game-over. + + # overriding the default character spawning.. + def spawn_player(self, player: Player) -> ba.Actor: + actor = self.spawn_player_spaz(player) + ba.timer(0.3, ba.Call(self._print_lives, player)) + + # If we have any icons, update their state. + for icon in player.icons: + icon.handle_player_spawned() + return actor + + def _print_lives(self, player: Player) -> None: + from bastd.actor import popuptext + + # We get called in a timer so it's possible our player has left/etc. + if not player or not player.is_alive() or not player.node: + return + + popuptext.PopupText('x' + str(player.lives - 1), + color=(1, 1, 0, 1), + offset=(0, -0.8, 0), + random_offset=0.0, + scale=1.8, + position=player.node.position).autoretain() + + def _get_total_team_lives(self, team: Team) -> int: + return sum(player.lives for player in team.players) + + def _start_bot_updates(self) -> None: + self._bot_update_interval = 3.3 - 0.3 * (len(self.players)) + self._update_bots() + self._update_bots() + if len(self.players) > 2: + self._update_bots() + if len(self.players) > 3: + self._update_bots() + self._bot_update_timer = ba.Timer(self._bot_update_interval, + ba.WeakCall(self._update_bots)) + + def _update_bots(self) -> None: + assert self._bot_update_interval is not None + self._bot_update_interval = max(0.5, self._bot_update_interval * 0.98) + self._bot_update_timer = ba.Timer(self._bot_update_interval, + ba.WeakCall(self._update_bots)) + botspawnpts: list[Sequence[float]] = [[-5.0, 5.5, -4.14], + [0.0, 5.5, -4.14], + [5.0, 5.5, -4.14]] + for player in self.players: + try: + if player.is_alive(): + assert isinstance(player.actor, PlayerSpaz) + assert player.actor.node + except Exception: + ba.print_exception('Error updating bots.') + + spawnpt = random.choice( + [botspawnpts[0], botspawnpts[1], botspawnpts[2]]) + + spawnpt = (spawnpt[0] + 3.0 * (random.random() - 0.5), spawnpt[1], + 2.0 * (random.random() - 0.5) + spawnpt[2]) + + # Normalize our bot type total and find a random number within that. + total = 0.0 + for spawninfo in self._bot_spawn_types.values(): + total += spawninfo.spawnrate + randval = random.random() * total + + # Now go back through and see where this value falls. + total = 0 + bottype: type[SpazBot] | None = None + for spawntype, spawninfo in self._bot_spawn_types.items(): + total += spawninfo.spawnrate + if randval <= total: + bottype = spawntype + break + spawn_time = 1.0 + assert bottype is not None + self._bots.spawn_bot(bottype, pos=spawnpt, spawn_time=spawn_time) + + # After every spawn we adjust our ratios slightly to get more + # difficult. + for spawninfo in self._bot_spawn_types.values(): + spawninfo.spawnrate += spawninfo.increase + spawninfo.increase += spawninfo.dincrease + + # Various high-level game events come through this method. + def handlemessage(self, msg: Any) -> Any: + if isinstance(msg, ba.PlayerDiedMessage): + + # Augment standard behavior. + super().handlemessage(msg) + + curtime = ba.time() + + # Record the player's moment of death. + # assert isinstance(msg.spaz.player + msg.getplayer(Player).death_time = curtime + + player: Player = msg.getplayer(Player) + + player.lives -= 1 + if player.lives < 0: + player.lives = 0 + + # If we have any icons, update their state. + for icon in player.icons: + icon.handle_player_died() + + # Play big death sound on our last death + # or for every one in solo mode. + if player.lives == 0: + ba.playsound(SpazFactory.get().single_player_death_sound) + + # If we hit zero lives, we're dead (and our team might be too). + if player.lives == 0: + # If the whole team is now dead, mark their survival time. + if self._get_total_team_lives(player.team) == 0: + assert self._start_time is not None + player.team.survival_seconds = int(ba.time() - + self._start_time) + else: + # Otherwise, in regular mode, respawn. + self.respawn_player(player) + + def _get_living_teams(self) -> list[Team]: + return [ + team for team in self.teams + if len(team.players) > 0 and any(player.lives > 0 + for player in team.players) + ] + + def _update(self) -> None: + # If we're down to 1 or fewer living teams, start a timer to end + # the game (allows the dust to settle and draws to occur if deaths + # are close enough). + if len(self._get_living_teams()) < 2: + self._round_end_timer = ba.Timer(0.5, self.end_game) + + def end_game(self) -> None: + # Stop updating our time text, and set the final time to match + # exactly when our last guy died. + self._timer.stop(endtime=self._last_player_death_time) + + # Ok now calc game results: set a score for each team and then tell + # the game to end. + results = ba.GameResults() + + # Remember that 'free-for-all' mode is simply a special form + # of 'teams' mode where each player gets their own team, so we can + # just always deal in teams and have all cases covered. + for team in self.teams: + # Submit the score value in milliseconds. + results.set_team_score(team, team.survival_seconds) + + self.end(results=results) From c1c23f49b75571bad0e5a34568bf5871f3bd3707 Mon Sep 17 00:00:00 2001 From: Cross Joy <87638792+CrossJoy@users.noreply.github.com> Date: Sat, 22 Oct 2022 18:25:10 +0800 Subject: [PATCH 0194/1464] Added new minigames Added Ultimate Last Stand by Cross Joy minigame --- plugins/minigames.json | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/plugins/minigames.json b/plugins/minigames.json index 68702d78..598d333d 100644 --- a/plugins/minigames.json +++ b/plugins/minigames.json @@ -3,6 +3,20 @@ "description": "Minigames", "plugins_base_url": "http://github.com/bombsquad-community/plugin-manager/{content_type}/{tag}/plugins/minigames", "plugins": { + "ultimate_last_stand": { + "description": "Bring Last Stand minigame into team fight and FFA.", + "external_url": "", + "authors": [ + { + "name": "Cross Joy", + "email": "cross.joy.official@gmail.com", + "discord": "Cross Joy#0721" + } + ], + "versions": { + "2.0.0": null + } + }, "alliance_elimination": { "description": "Fight in groups of duo, trio, or more. Last remaining alive wins.", "external_url": "", @@ -80,4 +94,4 @@ } } } -} \ No newline at end of file +} From 8b257b322e9c7c3538527dc1ae689bc069925ac7 Mon Sep 17 00:00:00 2001 From: CrossJoy Date: Sat, 22 Oct 2022 10:31:05 +0000 Subject: [PATCH 0195/1464] [ci] auto-format --- plugins/minigames/ultimate_last_stand.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/plugins/minigames/ultimate_last_stand.py b/plugins/minigames/ultimate_last_stand.py index 8b159331..b74d0027 100644 --- a/plugins/minigames/ultimate_last_stand.py +++ b/plugins/minigames/ultimate_last_stand.py @@ -249,8 +249,8 @@ class UltimateLastStand(ba.TeamGameActivity[Player, Team]): @classmethod def get_available_settings( - cls, - sessiontype: type[ba.Session]) -> list[ba.Setting]: + cls, + sessiontype: type[ba.Session]) -> list[ba.Setting]: settings = [ ba.IntSetting( 'Lives Per Player', @@ -395,7 +395,7 @@ def on_begin(self) -> None: # total lives match. if (isinstance(self.session, ba.DualTeamSession) and self._balance_total_lives and self.teams[0].players - and self.teams[1].players): + and self.teams[1].players): if self._get_total_team_lives( self.teams[0]) < self._get_total_team_lives(self.teams[1]): lesser_team = self.teams[0] From 3a8480153555f60ee52d2a93b5071f20dcc77d10 Mon Sep 17 00:00:00 2001 From: CrossJoy Date: Sat, 22 Oct 2022 10:31:06 +0000 Subject: [PATCH 0196/1464] [ci] apply-version-metadata --- plugins/minigames.json | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/plugins/minigames.json b/plugins/minigames.json index 598d333d..d44b49fd 100644 --- a/plugins/minigames.json +++ b/plugins/minigames.json @@ -14,7 +14,12 @@ } ], "versions": { - "2.0.0": null + "2.0.0": { + "api_version": 7, + "commit_sha": "8b257b3", + "released_on": "22-10-2022", + "md5sum": "4f99e4594cac5a9df137faa257f919dc" + } } }, "alliance_elimination": { @@ -94,4 +99,4 @@ } } } -} +} \ No newline at end of file From e1e5097ebbde9899f5296e84397b23daa31f0347 Mon Sep 17 00:00:00 2001 From: Loup <90267658+Loup-Garou911XD@users.noreply.github.com> Date: Fri, 28 Oct 2022 18:21:24 +0530 Subject: [PATCH 0197/1464] Added has_settings_ui() and show_settings_ui() --- plugins/utilities/mood_light.py | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/plugins/utilities/mood_light.py b/plugins/utilities/mood_light.py index df1024f5..3ba0b304 100644 --- a/plugins/utilities/mood_light.py +++ b/plugins/utilities/mood_light.py @@ -4,14 +4,13 @@ if TYPE_CHECKING: from typing import Any, Sequence, Callable, List, Dict, Tuple, Optional, Union +import random import ba import _ba -import random from ba._map import Map from bastd import mainmenu from bastd.ui.party import PartyWindow from bastd.gameutils import SharedObjects -from time import sleep """mood light plugin by ʟօʊքɢǟʀօʊ type ml in chat or use plugin manager to open settings""" @@ -257,12 +256,12 @@ def new_chat_message(msg: Union[str, ba.Lstr], clients: Sequence[int] = None, se old_fcm(msg, clients, sender_override) if msg == 'ml': try: - global Ldefault, Udefault + global Ldefault,Udefault Ldefault, Udefault = ba.app.config.get("moodlightingSettings") SettingWindow() cprint("Mood light settings opened") except Exception as err: - Print(err) + Print(err,"-from new_chat_message") old_fcm = _ba.chatmessage @@ -279,9 +278,12 @@ def __init__(self): def on_app_running(self): _ba.show_progress_bar() - - def on_plugin_manager_prompt(self): # called by plugin manager + + def has_settings_ui(self): + return True + def show_settings_ui(self,button): SettingWindow() + def _new_init(self, vr_overlay_offset: Optional[Sequence[float]] = None) -> None: self._old_init(vr_overlay_offset) From b8186247786b05a0eda7efdcbbe832e7c7a3bdb9 Mon Sep 17 00:00:00 2001 From: Loup-Garou911XD Date: Fri, 28 Oct 2022 12:51:45 +0000 Subject: [PATCH 0198/1464] [ci] auto-format --- plugins/utilities/mood_light.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/plugins/utilities/mood_light.py b/plugins/utilities/mood_light.py index 3ba0b304..733adef6 100644 --- a/plugins/utilities/mood_light.py +++ b/plugins/utilities/mood_light.py @@ -256,12 +256,12 @@ def new_chat_message(msg: Union[str, ba.Lstr], clients: Sequence[int] = None, se old_fcm(msg, clients, sender_override) if msg == 'ml': try: - global Ldefault,Udefault + global Ldefault, Udefault Ldefault, Udefault = ba.app.config.get("moodlightingSettings") SettingWindow() cprint("Mood light settings opened") except Exception as err: - Print(err,"-from new_chat_message") + Print(err, "-from new_chat_message") old_fcm = _ba.chatmessage @@ -278,12 +278,12 @@ def __init__(self): def on_app_running(self): _ba.show_progress_bar() - + def has_settings_ui(self): return True - def show_settings_ui(self,button): + + def show_settings_ui(self, button): SettingWindow() - def _new_init(self, vr_overlay_offset: Optional[Sequence[float]] = None) -> None: self._old_init(vr_overlay_offset) From 1a56b577ff98221df56df25f7b79c72fa1a908f8 Mon Sep 17 00:00:00 2001 From: Loup <90267658+Loup-Garou911XD@users.noreply.github.com> Date: Fri, 28 Oct 2022 18:33:06 +0530 Subject: [PATCH 0199/1464] Changed version to 1.2.1 --- plugins/utilities.json | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/plugins/utilities.json b/plugins/utilities.json index 63413f65..d62682b4 100644 --- a/plugins/utilities.json +++ b/plugins/utilities.json @@ -14,6 +14,7 @@ } ], "versions": { + "1.2.1": null, "1.2.0": { "api_version": 7, "commit_sha": "d838115", @@ -298,4 +299,4 @@ } } } -} \ No newline at end of file +} From cb4d34bec48882272cd8532725060eca867d4f4e Mon Sep 17 00:00:00 2001 From: Loup-Garou911XD Date: Fri, 28 Oct 2022 13:03:30 +0000 Subject: [PATCH 0200/1464] [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 d62682b4..d3c9ac14 100644 --- a/plugins/utilities.json +++ b/plugins/utilities.json @@ -14,7 +14,12 @@ } ], "versions": { - "1.2.1": null, + "1.2.1": { + "api_version": 7, + "commit_sha": "1a56b57", + "released_on": "28-10-2022", + "md5sum": "81414a2b497da3d2340a4d7eb004336c" + }, "1.2.0": { "api_version": 7, "commit_sha": "d838115", @@ -299,4 +304,4 @@ } } } -} +} \ No newline at end of file From e59073b7d3d05573310a96d7b0e705158ac16b3d Mon Sep 17 00:00:00 2001 From: Rikko Date: Wed, 2 Nov 2022 15:09:34 +0530 Subject: [PATCH 0201/1464] Add Soccer --- plugins/minigames.json | 16 +- plugins/minigames/soccer.py | 372 ++++++++++++++++++++++++++++++++++++ 2 files changed, 387 insertions(+), 1 deletion(-) create mode 100644 plugins/minigames/soccer.py diff --git a/plugins/minigames.json b/plugins/minigames.json index d44b49fd..6dfe5d6e 100644 --- a/plugins/minigames.json +++ b/plugins/minigames.json @@ -97,6 +97,20 @@ "md5sum": "c84b7f415de5d3e9189ee73fc0e3ce93" } } + }, + "soccer": { + "description": "Shoot the ball in left or right edge of the map to score", + "external_url": "", + "authors": [ + { + "name": "Stary_Agent", + "email": "", + "discord": "" + } + ], + "versions": { + "1.0.0": null + } } } -} \ No newline at end of file +} diff --git a/plugins/minigames/soccer.py b/plugins/minigames/soccer.py new file mode 100644 index 00000000..d86c7d54 --- /dev/null +++ b/plugins/minigames/soccer.py @@ -0,0 +1,372 @@ +# Released under the MIT License. See LICENSE for details. +# BY Stary_Agent +"""Hockey game and support classes.""" + +# ba_meta require api 7 +# (see https://ballistica.net/wiki/meta-tag-system) + +from __future__ import annotations + +from typing import TYPE_CHECKING + +import ba +from bastd.actor.playerspaz import PlayerSpaz +from bastd.actor.scoreboard import Scoreboard +from bastd.actor.powerupbox import PowerupBoxFactory +from bastd.gameutils import SharedObjects + +if TYPE_CHECKING: + from typing import Any, Sequence, Dict, Type, List, Optional, Union + + +class PuckDiedMessage: + """Inform something that a puck has died.""" + + def __init__(self, puck: Puck): + self.puck = puck + + +class Puck(ba.Actor): + """A lovely giant hockey puck.""" + + def __init__(self, position: Sequence[float] = (0.0, 1.0, 0.0)): + super().__init__() + shared = SharedObjects.get() + activity = self.getactivity() + + # 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, HockeyGame) + pmats = [shared.object_material, activity.puck_material] + self.node = ba.newnode('prop', + delegate=self, + attrs={ + 'model': activity.puck_model, + 'color_texture': activity.puck_tex, + 'body': 'sphere', + 'reflection': 'soft', + 'reflection_scale': [0.2], + 'shadow_size': 0.5, + 'is_area_of_interest': True, + 'position': self._spawn_pos, + 'materials': pmats + }) + ba.animate(self.node, 'model_scale', {0: 0, 0.2: 1.3, 0.26: 1}) + + def handlemessage(self, msg: Any) -> Any: + if isinstance(msg, ba.DieMessage): + assert self.node + self.node.delete() + activity = self._activity() + if activity and not msg.immediate: + activity.handlemessage(PuckDiedMessage(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.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 + else: + 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 + + +# ba_meta export game +class HockeyGame(ba.TeamGameActivity[Player, Team]): + """Ice hockey game.""" + + name = 'Epic Soccer' + description = 'Score some goals.' + available_settings = [ + ba.IntSetting( + 'Score to Win', + min_value=1, + default=1, + 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.1), + ('Short', 0.5), + ('Normal', 1.0), + ('Long', 2.0), + ('Longer', 4.0), + ], + default=1.0, + ), + ] + 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 ba.getmaps('football') + + def __init__(self, settings: dict): + super().__init__(settings) + shared = SharedObjects.get() + self.slow_motion = True + 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.puck_model = ba.getmodel('bomb') + self.puck_tex = ba.gettexture('landMine') + self.puck_scored_tex = ba.gettexture('landMineLit') + self._puck_sound = ba.getsound('metalHit') + self.puck_material = ba.Material() + self.puck_material.add_actions(actions=(('modify_part_collision', + 'friction', 0.5))) + self.puck_material.add_actions(conditions=('they_have_material', + shared.pickup_material), + actions=('modify_part_collision', + 'collide', True)) + self.puck_material.add_actions( + conditions=( + ('we_are_younger_than', 100), + 'and', + ('they_have_material', shared.object_material), + ), + actions=('modify_node_collision', 'collide', False), + ) + self.puck_material.add_actions(conditions=('they_have_material', + shared.footing_material), + actions=('impact_sound', + self._puck_sound, 0.2, 5)) + + # Keep track of which player last touched the puck + self.puck_material.add_actions( + conditions=('they_have_material', shared.player_material), + actions=(('call', 'at_connect', + self._handle_puck_player_collide), )) + + # We want the puck to kill powerups; not get stopped by them + self.puck_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.puck_material), + actions=(('modify_part_collision', 'collide', + True), ('modify_part_collision', 'physical', False), + ('call', 'at_connect', self._handle_score))) + self._puck_spawn_pos: Optional[Sequence[float]] = None + self._score_regions: Optional[List[ba.NodeActor]] = None + self._puck: Optional[Puck] = 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 'Score a goal.' + return 'Score ${ARG1} goals.', self._score_to_win + + def get_instance_description_short(self) -> Union[str, Sequence]: + if self._score_to_win == 1: + return 'score a goal' + return 'score ${ARG1} goals', self._score_to_win + + def on_begin(self) -> None: + super().on_begin() + + self.setup_standard_time_limit(self._time_limit) + self.setup_standard_powerup_drops() + self._puck_spawn_pos = self.map.get_flag_position(None) + self._spawn_puck() + + # Set up the two score regions. + defs = self.map.defs + self._score_regions = [] + self._score_regions.append( + ba.NodeActor( + ba.newnode('region', + attrs={ + 'position': defs.boxes['goal1'][0:3], + 'scale': defs.boxes['goal1'][6:9], + 'type': 'box', + 'materials': [self._score_region_material] + }))) + self._score_regions.append( + ba.NodeActor( + ba.newnode('region', + attrs={ + 'position': defs.boxes['goal2'][0:3], + 'scale': defs.boxes['goal2'][6:9], + 'type': 'box', + 'materials': [self._score_region_material] + }))) + self._update_scoreboard() + ba.playsound(self._chant_sound) + + def on_team_join(self, team: Team) -> None: + self._update_scoreboard() + + def _handle_puck_player_collide(self) -> None: + collision = ba.getcollision() + try: + puck = collision.sourcenode.getdelegate(Puck, True) + player = collision.opposingnode.getdelegate(PlayerSpaz, + True).getplayer( + Player, True) + except ba.NotFoundError: + return + + puck.last_players_to_touch[player.team.id] = player + + def _kill_puck(self) -> None: + self._puck = None + + def _handle_score(self) -> None: + """A point has been scored.""" + + assert self._puck is not None + assert self._score_regions is not None + + # Our puck might stick around for a second or two + # we don't want it to be able to score again. + if self._puck.scored: + return + + region = ba.getcollision().sourcenode + index = 0 + for index in range(len(self._score_regions)): + if region == self._score_regions[index].node: + break + + for team in self.teams: + if team.id == index: + scoring_team = team + team.score += 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._puck.last_players_to_touch + and self._puck.last_players_to_touch[scoring_team.id]): + self.stats.player_scored( + self._puck.last_players_to_touch[scoring_team.id], + 20, + big_message=True) + + # End game if we won. + if team.score >= self._score_to_win: + self.end_game() + + ba.playsound(self._foghorn_sound) + ba.playsound(self._cheer_sound) + + self._puck.scored = True + + # Change puck texture to something cool + self._puck.node.color_texture = self.puck_scored_tex + # Kill the puck (it'll respawn itself shortly). + ba.timer(1.0, self._kill_puck) + + light = ba.newnode('light', + attrs={ + 'position': ba.getcollision().position, + 'height_attenuated': False, + 'color': (1, 0, 0) + }) + ba.animate(light, 'intensity', {0: 0, 0.5: 1, 1.0: 0}, loop=True) + ba.timer(1.0, light.delete) + + 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): + # Augment standard behavior... + super().handlemessage(msg) + self.respawn_player(msg.getplayer(Player)) + + # Respawn dead pucks. + elif isinstance(msg, PuckDiedMessage): + if not self.has_ended(): + ba.timer(3.0, self._spawn_puck) + else: + super().handlemessage(msg) + + def _flash_puck_spawn(self) -> None: + light = ba.newnode('light', + attrs={ + 'position': self._puck_spawn_pos, + 'height_attenuated': False, + 'color': (1, 0, 0) + }) + ba.animate(light, 'intensity', {0.0: 0, 0.25: 1, 0.5: 0}, loop=True) + ba.timer(1.0, light.delete) + + def _spawn_puck(self) -> None: + ba.playsound(self._swipsound) + ba.playsound(self._whistle_sound) + self._flash_puck_spawn() + assert self._puck_spawn_pos is not None + self._puck = Puck(position=self._puck_spawn_pos) From 33e866152c46e1179e6713fae8f206e48d1d04fc Mon Sep 17 00:00:00 2001 From: rikkolovescats Date: Wed, 2 Nov 2022 09:40:03 +0000 Subject: [PATCH 0202/1464] [ci] apply-version-metadata --- plugins/minigames.json | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/plugins/minigames.json b/plugins/minigames.json index 6dfe5d6e..989ca69c 100644 --- a/plugins/minigames.json +++ b/plugins/minigames.json @@ -109,8 +109,13 @@ } ], "versions": { - "1.0.0": null + "1.0.0": { + "api_version": 7, + "commit_sha": "e59073b", + "released_on": "02-11-2022", + "md5sum": "ceb7ac417c85396722fa9f7fee3cfc01" + } } } } -} +} \ No newline at end of file From 85304770d332d58e48f500dd6d71a9edb75f4176 Mon Sep 17 00:00:00 2001 From: Loup <90267658+Loup-Garou911XD@users.noreply.github.com> Date: Thu, 3 Nov 2022 22:37:45 +0530 Subject: [PATCH 0203/1464] Add files via upload --- plugins/utilities/CustomDeath.py | 38 ++ plugins/utilities/MaxPlayers.py | 356 ++++++++++++++++++ plugins/utilities/QuickCustonGame.py | 373 +++++++++++++++++++ plugins/utilities/RandomColors.py | 48 +++ plugins/utilities/chat_cmd.py | 531 +++++++++++++++++++++++++++ 5 files changed, 1346 insertions(+) create mode 100644 plugins/utilities/CustomDeath.py create mode 100644 plugins/utilities/MaxPlayers.py create mode 100644 plugins/utilities/QuickCustonGame.py create mode 100644 plugins/utilities/RandomColors.py create mode 100644 plugins/utilities/chat_cmd.py diff --git a/plugins/utilities/CustomDeath.py b/plugins/utilities/CustomDeath.py new file mode 100644 index 00000000..809db736 --- /dev/null +++ b/plugins/utilities/CustomDeath.py @@ -0,0 +1,38 @@ +# ba_meta require api 7 +# (see https://ballistica.net/wiki/meta-tag-system) + +from __future__ import annotations + +from typing import TYPE_CHECKING + +import ba +from bastd.actor.spaz import Spaz + +if TYPE_CHECKING: + from typing import Any + + +Spaz.oldhandlemessage = Spaz.handlemessage +def handlemessage(self, msg: Any) -> Any: + if isinstance(msg, ba.DieMessage): + if self.node: + self.node.color_texture = ba.gettexture('bonesColor') + self.node.color_mask_texture = ba.gettexture('bonesColorMask') + self.node.head_model = ba.getmodel('bonesHead') + self.node.torso_model = ba.getmodel('bonesTorso') + self.node.pelvis_model = ba.getmodel('bonesPelvis') + self.node.upper_arm_model = ba.getmodel('bonesUpperArm') + self.node.forearm_model = ba.getmodel('bonesForeArm') + self.node.hand_model = ba.getmodel('bonesHand') + self.node.upper_leg_model = ba.getmodel('bonesUpperLeg') + self.node.lower_leg_model = ba.getmodel('bonesLowerLeg') + self.node.toes_model = ba.getmodel('bonesToes') + self.node.style = 'bones' + self.oldhandlemessage(msg) + else: + return self.oldhandlemessage(msg) + + +# ba_meta export plugin +class CustomDeath(ba.Plugin): + Spaz.handlemessage = handlemessage diff --git a/plugins/utilities/MaxPlayers.py b/plugins/utilities/MaxPlayers.py new file mode 100644 index 00000000..dce5ec04 --- /dev/null +++ b/plugins/utilities/MaxPlayers.py @@ -0,0 +1,356 @@ +"""===========MAX_PLAYERS===========""" + +# ba_meta require api 7 +# (see https://ballistica.net/wiki/meta-tag-system) + +from __future__ import annotations +from typing import TYPE_CHECKING + +import ba +import _ba +from ba._session import Session +from ba._coopsession import CoopSession, TEAM_COLORS, TEAM_NAMES +from ba._multiteamsession import MultiTeamSession +from bastd.ui.gather import GatherWindow +from bastd.ui.popup import PopupWindow + +if TYPE_CHECKING: + from typing import List, Any, Optional, Sequence + + +cfg = ba.app.config +cmp = {'coop_max_players': 4, + 'teams_max_players': 8, + 'ffa_max_players': 8} + +lang = ba.app.lang.language +if lang == 'Spanish': + title_text = 'Máximo de Jugadores' + title_short_text = 'Jugadores' + coop_text = 'Cooperativo' + teams_text = 'Equipos' + ffa_text = 'Todos Contra Todos' +else: + title_text = 'Max Players' + title_short_text = 'Players' + coop_text = 'Co-op' + teams_text = 'Teams' + ffa_text = 'FFA' + +class ConfigNumberEdit: + + def __init__(self, + parent: ba.Widget, + position: Tuple[float, float], + value: int, + config: str, + text: str): + self._increment = 1 + self._minval = 1 + self._maxval = 100 + self._value = value + self._config = config + + textscale = 1.0 + self.nametext = ba.textwidget( + parent=parent, + position=(position[0], position[1]), + size=(100, 30), + text=text, + maxwidth=150, + color=(0.8, 0.8, 0.8, 1.0), + h_align='left', + v_align='center', + scale=textscale) + self.valuetext = ba.textwidget( + parent=parent, + position=(position[0]+150, position[1]), + size=(60, 28), + editable=False, + color=(0.3, 1.0, 0.3, 1.0), + h_align='right', + v_align='center', + text=str(value), + padding=2) + self.minusbutton = ba.buttonwidget( + parent=parent, + position=(position[0]+240, position[1]), + size=(28, 28), + label='-', + autoselect=True, + on_activate_call=ba.Call(self._down), + repeat=True) + self.plusbutton = ba.buttonwidget( + parent=parent, + position=(position[0]+290, position[1]), + size=(28, 28), + label='+', + autoselect=True, + on_activate_call=ba.Call(self._up), + repeat=True) + + def _up(self) -> None: + self._value = min(self._maxval, self._value + self._increment) + self._update_display() + + def _down(self) -> None: + self._value = max(self._minval, self._value - self._increment) + self._update_display() + + def _update_display(self) -> None: + ba.textwidget(edit=self.valuetext, text=str(self._value)) + cfg['Config Max Players'][self._config] = self._value + cfg.apply_and_commit() + +class SettingsMaxPlayers(PopupWindow): + + def __init__(self): + # pylint: disable=too-many-locals + uiscale = ba.app.ui.uiscale + self._transitioning_out = False + self._width = 400 + self._height = 220 + bg_color = (0.5, 0.4, 0.6) + + # creates our _root_widget + PopupWindow.__init__(self, + position=(0.0, 0.0), + size=(self._width, self._height), + scale=1.2, + bg_color=bg_color) + + self._cancel_button = ba.buttonwidget( + parent=self.root_widget, + position=(25, self._height - 40), + size=(50, 50), + scale=0.58, + label='', + color=bg_color, + on_activate_call=self._on_cancel_press, + autoselect=True, + icon=ba.gettexture('crossOut'), + iconscale=1.2) + ba.containerwidget(edit=self.root_widget, + cancel_button=self._cancel_button) + + ba.textwidget( + parent=self.root_widget, + position=(self._width * 0.5, self._height - 30), + size=(0, 0), + h_align='center', + v_align='center', + scale=0.8, + text=title_text, + maxwidth=200, + color=ba.app.ui.title_color) + + posx = 33 + posy = self._height + + # co-op + ConfigNumberEdit(parent=self.root_widget, + position=(posx, posy*0.6), + value=cfg['Config Max Players']['coop_max_players'], + config='coop_max_players', + text=coop_text) + + # teams + ConfigNumberEdit(parent=self.root_widget, + position=(posx, posy*0.38), + value=cfg['Config Max Players']['teams_max_players'], + config='teams_max_players', + text=teams_text) + + # ffa + ConfigNumberEdit(parent=self.root_widget, + position=(posx, posy*0.16), + value=cfg['Config Max Players']['ffa_max_players'], + config='ffa_max_players', + text=ffa_text) + + def _on_cancel_press(self) -> None: + self._transition_out() + + def _transition_out(self) -> None: + if not self._transitioning_out: + self._transitioning_out = True + ba.containerwidget(edit=self.root_widget, transition='out_scale') + + def on_popup_cancel(self) -> None: + ba.playsound(ba.getsound('swish')) + self._transition_out() + +def __init__(self) -> None: + """Instantiate a co-op mode session.""" + # pylint: disable=cyclic-import + from ba._campaign import getcampaign + from bastd.activity.coopjoin import CoopJoinActivity + + _ba.increment_analytics_count('Co-op session start') + app = _ba.app + + # If they passed in explicit min/max, honor that. + # Otherwise defer to user overrides or defaults. + if 'min_players' in app.coop_session_args: + min_players = app.coop_session_args['min_players'] + else: + min_players = 1 + if 'max_players' in app.coop_session_args: + max_players = app.coop_session_args['max_players'] + else: + max_players = app.config.get( + 'Coop Game Max Players', + cfg['Config Max Players']['coop_max_players']) + + # print('FIXME: COOP SESSION WOULD CALC DEPS.') + depsets: Sequence[ba.DependencySet] = [] + + Session.__init__(self, + depsets, + team_names=TEAM_NAMES, + team_colors=TEAM_COLORS, + min_players=min_players, + max_players=max_players) + + # Tournament-ID if we correspond to a co-op tournament (otherwise None) + self.tournament_id: Optional[str] = ( + app.coop_session_args.get('tournament_id')) + + self.campaign = getcampaign(app.coop_session_args['campaign']) + self.campaign_level_name: str = app.coop_session_args['level'] + + self._ran_tutorial_activity = False + self._tutorial_activity: Optional[ba.Activity] = None + self._custom_menu_ui: List[Dict[str, Any]] = [] + + # Start our joining screen. + self.setactivity(_ba.newactivity(CoopJoinActivity)) + + self._next_game_instance: Optional[ba.GameActivity] = None + self._next_game_level_name: Optional[str] = None + self._update_on_deck_game_instances() + +def get_max_players(self) -> int: + """Return max number of ba.Players allowed to join the game at once.""" + if self.use_teams: + return _ba.app.config.get( + 'Team Game Max Players', + cfg['Config Max Players']['teams_max_players']) + return _ba.app.config.get( + 'Free-for-All Max Players', + cfg['Config Max Players']['ffa_max_players']) + +GatherWindow.__old_init__ = GatherWindow.__init__ +def __gather_init__(self, + transition: Optional[str] = 'in_right', + origin_widget: ba.Widget = None): + self.__old_init__(transition, origin_widget) + def _do_max_players(): + SettingsMaxPlayers() + self._max_players_button = ba.buttonwidget( + parent=self._root_widget, + position=(self._width*0.72, self._height*0.91), + size=(220, 60), + scale=1.0, + color=(0.6, 0.0, 0.9), + icon=ba.gettexture('usersButton'), + iconscale=1.5, + autoselect=True, + label=title_short_text, + button_type='regular', + on_activate_call=_do_max_players) + +def _save_state(self) -> None: + try: + for tab in self._tabs.values(): + tab.save_state() + + sel = self._root_widget.get_selected_child() + selected_tab_ids = [ + tab_id for tab_id, tab in self._tab_row.tabs.items() + if sel == tab.button + ] + if sel == self._back_button: + sel_name = 'Back' + elif sel == self._max_players_button: + sel_name = 'Max Players' + elif selected_tab_ids: + assert len(selected_tab_ids) == 1 + sel_name = f'Tab:{selected_tab_ids[0].value}' + elif sel == self._tab_container: + sel_name = 'TabContainer' + else: + raise ValueError(f'unrecognized selection: \'{sel}\'') + ba.app.ui.window_states[type(self)] = { + 'sel_name': sel_name, + } + except Exception: + ba.print_exception(f'Error saving state for {self}.') + +def _restore_state(self) -> None: + from efro.util import enum_by_value + try: + for tab in self._tabs.values(): + tab.restore_state() + + sel: Optional[ba.Widget] + winstate = ba.app.ui.window_states.get(type(self), {}) + sel_name = winstate.get('sel_name', None) + assert isinstance(sel_name, (str, type(None))) + current_tab = self.TabID.ABOUT + gather_tab_val = ba.app.config.get('Gather Tab') + try: + stored_tab = enum_by_value(self.TabID, gather_tab_val) + if stored_tab in self._tab_row.tabs: + current_tab = stored_tab + except ValueError: + pass + self._set_tab(current_tab) + if sel_name == 'Back': + sel = self._back_button + elif sel_name == 'Max Players': + sel = self._back_button + elif sel_name == 'TabContainer': + sel = self._tab_container + elif isinstance(sel_name, str) and sel_name.startswith('Tab:'): + try: + sel_tab_id = enum_by_value(self.TabID, + sel_name.split(':')[-1]) + except ValueError: + sel_tab_id = self.TabID.ABOUT + sel = self._tab_row.tabs[sel_tab_id].button + else: + sel = self._tab_row.tabs[current_tab].button + ba.containerwidget(edit=self._root_widget, selected_child=sel) + except Exception: + ba.print_exception('Error restoring gather-win state.') + +# ba_meta export plugin +class MaxPlayersPlugin(ba.Plugin): + + def has_settings_ui(self) -> bool: + return True + + def show_settings_ui(self, source_widget: ba.Widget | None) -> None: + SettingsMaxPlayers() + + if 'Config Max Players' in ba.app.config: + old_config = ba.app.config['Config Max Players'] + for setting in cmp: + if setting not in old_config: + ba.app.config['Config Max Players'].update({setting:cmp[setting]}) + remove_list = [] + for setting in old_config: + if setting not in cmp: + remove_list.append(setting) + for element in remove_list: + ba.app.config['Config Max Players'].pop(element) + else: + ba.app.config['Config Max Players'] = cmp + ba.app.config.apply_and_commit() + + CoopSession.__init__ = __init__ + MultiTeamSession.get_max_players = get_max_players + GatherWindow.__init__ = __gather_init__ + GatherWindow._save_state = _save_state + GatherWindow._restore_state = _restore_state diff --git a/plugins/utilities/QuickCustonGame.py b/plugins/utilities/QuickCustonGame.py new file mode 100644 index 00000000..dcc93c48 --- /dev/null +++ b/plugins/utilities/QuickCustonGame.py @@ -0,0 +1,373 @@ +# ba_meta require api 7 +# (see https://ballistica.net/wiki/meta-tag-system) + +from __future__ import annotations + +from typing import TYPE_CHECKING + +import ba +import _ba +from bastd.ui.play import PlayWindow +from bastd.ui.playlist.addgame import PlaylistAddGameWindow +from ba._freeforallsession import FreeForAllSession +from bastd.activity.multiteamjoin import MultiTeamJoinActivity + +if TYPE_CHECKING: + pass + + +lang = ba.app.lang.language + +if lang == 'Spanish': + custom_txt = 'personalizar...' +else: + custom_txt = 'custom...' + + +if 'quick_game_button' in ba.app.config: + config = ba.app.config['quick_game_button'] +else: + config = {'selected': None, 'config': None} + ba.app.config['quick_game_button'] = config + ba.app.config.commit() + +def start_game(session: ba.Session, fadeout: bool = True): + def callback(): + if fadeout: + _ba.unlock_all_input() + try: + _ba.new_host_session(session) + except Exception: + from bastd import mainmenu + ba.print_exception('exception running session', session) + + # Drop back into a main menu session. + _ba.new_host_session(mainmenu.MainMenuSession) + + if fadeout: + _ba.fade_screen(False, time=0.25, endcall=callback) + _ba.lock_all_input() + else: + callback() + +class SimplePlaylist: + + def __init__(self, + settings: dict, + gametype: type[ba.GameActivity]): + self.settings = settings + self.gametype = gametype + + def pull_next(self) -> None: + if 'map' not in self.settings['settings']: + settings = dict( + map=self.settings['map'], **self.settings['settings']) + else: + settings = self.settings['settings'] + return dict(resolved_type=self.gametype, settings=settings) + +class CustomSession(FreeForAllSession): + + def __init__(self, *args, **kwargs): + # pylint: disable=cyclic-import + self.use_teams = False + self._tutorial_activity_instance = None + ba.Session.__init__(self, depsets=[], + team_names=None, + team_colors=None, + min_players=1, + max_players=self.get_max_players()) + + self._series_length = 1 + self._ffa_series_length = 1 + + # Which game activity we're on. + self._game_number = 0 + self._playlist = SimplePlaylist(self._config, self._gametype) + config['selected'] = self._gametype.__name__ + config['config'] = self._config + ba.app.config.commit() + + # Get a game on deck ready to go. + self._current_game_spec: Optional[Dict[str, Any]] = None + self._next_game_spec: Dict[str, Any] = self._playlist.pull_next() + self._next_game: Type[ba.GameActivity] = ( + self._next_game_spec['resolved_type']) + + # Go ahead and instantiate the next game we'll + # use so it has lots of time to load. + self._instantiate_next_game() + + # Start in our custom join screen. + self.setactivity(_ba.newactivity(MultiTeamJoinActivity)) + + +class SelectGameWindow(PlaylistAddGameWindow): + + def __init__(self, transition: str = 'in_right'): + class EditController: + _sessiontype = ba.FreeForAllSession + + def get_session_type(self) -> Type[ba.Session]: + return self._sessiontype + + self._editcontroller = EditController() + self._r = 'addGameWindow' + uiscale = ba.app.ui.uiscale + self._width = 750 if uiscale is ba.UIScale.SMALL else 650 + x_inset = 50 if uiscale is ba.UIScale.SMALL else 0 + self._height = (346 if uiscale is ba.UIScale.SMALL else + 380 if uiscale is ba.UIScale.MEDIUM else 440) + top_extra = 30 if uiscale is ba.UIScale.SMALL else 20 + self._scroll_width = 210 + + self._root_widget = ba.containerwidget( + size=(self._width, self._height + top_extra), + transition=transition, + scale=(2.17 if uiscale is ba.UIScale.SMALL else + 1.5 if uiscale is ba.UIScale.MEDIUM else 1.0), + stack_offset=(0, 1) if uiscale is ba.UIScale.SMALL else (0, 0)) + + self._back_button = ba.buttonwidget(parent=self._root_widget, + position=(58 + x_inset, + self._height - 53), + size=(165, 70), + scale=0.75, + text_scale=1.2, + label=ba.Lstr(resource='backText'), + autoselect=True, + button_type='back', + on_activate_call=self._back) + self._select_button = select_button = ba.buttonwidget( + parent=self._root_widget, + position=(self._width - (172 + x_inset), self._height - 50), + autoselect=True, + size=(160, 60), + scale=0.75, + text_scale=1.2, + label=ba.Lstr(resource='selectText'), + on_activate_call=self._add) + + if ba.app.ui.use_toolbars: + ba.widget(edit=select_button, + right_widget=_ba.get_special_widget('party_button')) + + ba.textwidget(parent=self._root_widget, + position=(self._width * 0.5, self._height - 28), + size=(0, 0), + scale=1.0, + text=ba.Lstr(resource=self._r + '.titleText'), + h_align='center', + color=ba.app.ui.title_color, + maxwidth=250, + v_align='center') + v = self._height - 64 + + self._selected_title_text = ba.textwidget( + parent=self._root_widget, + position=(x_inset + self._scroll_width + 50 + 30, v - 15), + size=(0, 0), + scale=1.0, + color=(0.7, 1.0, 0.7, 1.0), + maxwidth=self._width - self._scroll_width - 150 - x_inset * 2, + h_align='left', + v_align='center') + v -= 30 + + self._selected_description_text = ba.textwidget( + parent=self._root_widget, + position=(x_inset + self._scroll_width + 50 + 30, v), + size=(0, 0), + scale=0.7, + color=(0.5, 0.8, 0.5, 1.0), + maxwidth=self._width - self._scroll_width - 150 - x_inset * 2, + h_align='left') + + scroll_height = self._height - 100 + + v = self._height - 60 + + self._scrollwidget = ba.scrollwidget(parent=self._root_widget, + position=(x_inset + 61, + v - scroll_height), + size=(self._scroll_width, + scroll_height), + highlight=False) + ba.widget(edit=self._scrollwidget, + up_widget=self._back_button, + left_widget=self._back_button, + right_widget=select_button) + self._column: Optional[ba.Widget] = None + + v -= 35 + ba.containerwidget(edit=self._root_widget, + cancel_button=self._back_button, + start_button=select_button) + self._selected_game_type: Optional[Type[ba.GameActivity]] = None + + ba.containerwidget(edit=self._root_widget, + selected_child=self._scrollwidget) + + self._game_types: list[type[ba.GameActivity]] = [] + + # Get actual games loading in the bg. + ba.app.meta.load_exported_classes(ba.GameActivity, + self._on_game_types_loaded, + completion_cb_in_bg_thread=True) + + # Refresh with our initial empty list. We'll refresh again once + # game loading is complete. + self._refresh() + + if config['selected']: + for gt in self._game_types: + if gt.__name__ == config['selected']: + self._refresh(selected=gt) + self._set_selected_game_type(gt) + + def _refresh(self, + select_get_more_games_button: bool = False, + selected: bool = None) -> None: + # from ba.internal import get_game_types + + if self._column is not None: + self._column.delete() + + self._column = ba.columnwidget(parent=self._scrollwidget, + border=2, + margin=0) + + for i, gametype in enumerate(self._game_types): + + def _doit() -> None: + if self._select_button: + ba.timer(0.1, + self._select_button.activate, + timetype=ba.TimeType.REAL) + + txt = ba.textwidget(parent=self._column, + position=(0, 0), + size=(self._width - 88, 24), + text=gametype.get_display_string(), + h_align='left', + v_align='center', + color=(0.8, 0.8, 0.8, 1.0), + maxwidth=self._scroll_width * 0.8, + on_select_call=ba.Call( + self._set_selected_game_type, gametype), + always_highlight=True, + selectable=True, + on_activate_call=_doit) + if i == 0: + ba.widget(edit=txt, up_widget=self._back_button) + + self._get_more_games_button = ba.buttonwidget( + parent=self._column, + autoselect=True, + label=ba.Lstr(resource=self._r + '.getMoreGamesText'), + color=(0.54, 0.52, 0.67), + textcolor=(0.7, 0.65, 0.7), + on_activate_call=self._on_get_more_games_press, + size=(178, 50)) + if select_get_more_games_button: + ba.containerwidget(edit=self._column, + selected_child=self._get_more_games_button, + visible_child=self._get_more_games_button) + + def _add(self) -> None: + _ba.lock_all_input() # Make sure no more commands happen. + ba.timer(0.1, _ba.unlock_all_input, timetype=ba.TimeType.REAL) + gameconfig = {} + if config['selected'] == self._selected_game_type.__name__: + if config['config']: + gameconfig = config['config'] + if 'map' in gameconfig: + gameconfig['settings']['map'] = gameconfig.pop('map') + self._selected_game_type.create_settings_ui( + self._editcontroller.get_session_type(), + gameconfig, + self._edit_game_done) + + def _edit_game_done(self, config: Optional[Dict[str, Any]]) -> None: + if config: + CustomSession._config = config + CustomSession._gametype = self._selected_game_type + start_game(CustomSession) + else: + ba.app.ui.clear_main_menu_window(transition='out_right') + ba.app.ui.set_main_menu_window( + SelectGameWindow(transition='in_left').get_root_widget()) + + def _back(self) -> None: + ba.containerwidget(edit=self._root_widget, transition='out_right') + ba.app.ui.set_main_menu_window( + PlayWindow(transition='in_left').get_root_widget()) + + +PlayWindow._old_init = PlayWindow.__init__ +def __init__(self, *args, **kwargs): + self._old_init() + + width = 800 + height = 550 + + def do_quick_game() -> None: + self._save_state() + ba.containerwidget(edit=self._root_widget, transition='out_left') + ba.app.ui.set_main_menu_window( + SelectGameWindow().get_root_widget()) + + self._quick_game_button = ba.buttonwidget( + parent=self._root_widget, + position=(width - 55 - 120, height - 132), + autoselect=True, + size=(120, 60), + scale=1.1, + text_scale=1.2, + label=custom_txt, + on_activate_call=do_quick_game, + color=(0.54, 0.52, 0.67), + textcolor=(0.7, 0.65, 0.7)) + + self._restore_state() + +def states(self) -> None: + return { + 'Team Games': self._teams_button, + 'Co-op Games': self._coop_button, + 'Free-for-All Games': self._free_for_all_button, + 'Back': self._back_button, + 'Quick Game': self._quick_game_button + } + +def _save_state(self) -> None: + swapped = {v: k for k, v in states(self).items()} + if self._root_widget.get_selected_child() in swapped: + ba.app.ui.window_states[ + self.__class__.__name__] = swapped[ + self._root_widget.get_selected_child()] + else: + ba.print_exception(f'Error saving state for {self}.') + +def _restore_state(self) -> None: + if not hasattr(self, '_quick_game_button'): + return # ensure that our monkey patched init ran + if self.__class__.__name__ not in ba.app.ui.window_states: + ba.containerwidget(edit=self._root_widget, + selected_child=self._coop_button) + return + sel = states(self).get( + ba.app.ui.window_states[self.__class__.__name__], None) + if sel: + ba.containerwidget(edit=self._root_widget, selected_child=sel) + else: + ba.containerwidget(edit=self._root_widget, + selected_child=self._coop_button) + ba.print_exception(f'Error restoring state for {self}.') + + +# ba_meta export plugin +class QuickGamePlugin(ba.Plugin): + PlayWindow.__init__ = __init__ + PlayWindow._save_state = _save_state + PlayWindow._restore_state = _restore_state diff --git a/plugins/utilities/RandomColors.py b/plugins/utilities/RandomColors.py new file mode 100644 index 00000000..eacf0bed --- /dev/null +++ b/plugins/utilities/RandomColors.py @@ -0,0 +1,48 @@ +# ba_meta require api 7 +# (see https://ballistica.net/wiki/meta-tag-system) + +from __future__ import annotations + +from typing import TYPE_CHECKING + +import ba +import random +from bastd.actor import bomb + +if TYPE_CHECKING: + from typing import Sequence + + +class NewBlast(bomb.Blast): + def __init__( + self, + position: Sequence[float] = (0.0, 1.0, 0.0), + velocity: Sequence[float] = (0.0, 0.0, 0.0), + blast_radius: float = 2.0, + blast_type: str = 'normal', + source_player: ba.Player | None = None, + hit_type: str = 'explosion', + hit_subtype: str = 'normal', + ): + super().__init__(position, velocity, blast_radius, blast_type, + source_player, hit_type, hit_subtype) + scorch_radius = light_radius = self.radius + if self.blast_type == 'tnt': + scorch_radius *= 1.15 + scorch = ba.newnode( + 'scorch', + attrs={ + 'position': position, + 'size': scorch_radius * 0.5, + 'big': (self.blast_type == 'tnt'), + }, + ) + random_color = (random.random(), random.random(), random.random()) + scorch.color = ba.safecolor(random_color) + ba.animate(scorch, 'presence', {3.000: 1, 13.000: 0}) + ba.timer(13.0, scorch.delete) + + +# ba_meta export plugin +class RandomColorsPlugin(ba.Plugin): + bomb.Blast = NewBlast diff --git a/plugins/utilities/chat_cmd.py b/plugins/utilities/chat_cmd.py new file mode 100644 index 00000000..cc9150d6 --- /dev/null +++ b/plugins/utilities/chat_cmd.py @@ -0,0 +1,531 @@ +"""python 3.9 | chatcmd for a beutiful game - BombSquad OwO""" +# modded by IM_NOT_PRANAV#7874 + +# biggggggg thankssssssssssssss to FireFighter1037 for helping everything + +# -*- coding: utf-8 -*- +# ba_meta require api 7 +from _ba import env,get_foreground_host_activity,get_foreground_host_session,get_game_roster, get_chat_messages,set_party_icon_always_visible, chatmessage as cmsg, screenmessage as smsg +import ba + +#our prefix that what we starts cmds with +px='/' + +#main class +class _cmds: + + def _process_cmd(): + set_party_icon_always_visible(True) + messages=get_chat_messages() + if len(messages)>1: + lastmsg = messages[len(messages)-1] + + m=lastmsg.split(' ')[1] + if m.startswith(px): + return _cmds._handle() + else: + pass + + def _handle(): + messages=get_chat_messages() + if len(messages)>1: + lastmsg = messages[len(messages)-1] + + m=lastmsg.split(' ')[1] #cmd + n=lastmsg.split(' ')[2:] #aguments + + roster=get_game_roster() + session=get_foreground_host_session() + session_players=session.sessionplayers + + activity=get_foreground_host_activity() + activity_players=activity.players + + if m == px: + cmsg(px+'help for help') + + elif m == px+'help' : + if n==[]: + cmsg('===========================================') + cmsg(f' {px}help 1 - for page 1 | simple commands') + cmsg(f' {px}help 2 - for page 2 | all or number of list cmds') + cmsg(f' {px}help 3 - for page 3 | Other useful cmds') + cmsg('===========================================') + elif n[0]=='1': + cmsg('============================') + cmsg(f' {px}help 1 page 1 |') + cmsg(f' {px}help 1 page 2 |') + cmsg('============================') + if n[1] in [ 'page' , 'Page' , ]: + if n[2]=='1': + cmsg('============== Help 1, Page 1 ==============') + cmsg(f' your command prefix is or all commands starts with - {px}') + cmsg(f' {px}list or {px}l -- to see ids of players and execute commands') + cmsg(f' {px}uniqeid or {px}id -- to see accountid/uniqeid of player') + cmsg(f' {px}quit or {px}restart -- to restart the game') + cmsg(f' {px}mute/unmute -- to mute chat for everyone in your game') + elif n[2]=='2': + cmsg('============== Help 1, Page 2 ==============') + cmsg(f' {px}pause -- to pause everyone in your game') + cmsg(f' {px}nv or {px}night -- to make night in your game') + cmsg(f' {px}dv or {px}day -- to make night in your game') + cmsg(f' {px}camera_mode -- to rotate camera ,repat to off') + cmsg('===========================================') + elif n[0]=='2': + cmsg('============================') + cmsg(f' {px}help 2 page 1 |') + cmsg(f' {px}help 2 page 2 |') + cmsg(f' {px}help 2 page 3 |') + cmsg('============================') + if n[1] in [ 'page' , 'Page' ]: + if n[2] == '1': + cmsg('============== Help 2 Page 1 ==============') + cmsg(f' {px}kill all or {px}kill number of list | kills the player') + cmsg(f' {px}heal all or {px}heal number of list | heals the players') + cmsg(f' {px}freeze all or {px}freeze number of list | freeze the player') + cmsg(f' {px}unfreeze/thaw all or {px}unfreeze/thaw number of list | unfreeze the player') + cmsg(f' {px}gloves all or {px}gloves number of list | give gloves to player') + cmsg('============================') + elif n[2] == '2': + cmsg('============== Help 2 Page 2 ==============') + cmsg(f' {px}shield all or {px}shield number of list | give shield the player') + cmsg(f' {px}fall all or {px}fall number of list | teleport in down and fall up the player') + cmsg(f' {px}curse all or {px}curse number of list | curse the player') + cmsg(f' {px}creepy all or {px}creepy number of list | make creepy actor of player') + cmsg(f' {px}inv all or {px}inv number of list | makes invisible player') + cmsg(f' {px}celebrate all or {px}celebrate number of list | celebrate action to the player') + cmsg('============================') + elif n[2] == '3': + cmsg('============== Help 2 Page 3 ==============') + cmsg(f' {px}gm all or {px}gm number of list | give bs gods like powers to player') + cmsg(f' {px}sp all or {px}sp number of list | give superrrrrrr damages when punch to player') + cmsg(f' {px}sleep all or {px}sleep number of list | sleep up the player') + cmsg(f' {px}fly all or {px}fly number of list | fly up the player ') + cmsg(f' {px}hug number of list | hugup the player') + cmsg('============================') + + elif n[0]=='3': + cmsg('============================') + cmsg(f" {px}d_bomb bombType | changes default bomb | do {px}d_bomb help for bomb names ") + cmsg(f' {px}dbc (number of bombs) | changes default count of player') + cmsg('============================') + + + elif m in [ px+'list' , px+'l' , px+'clientids' , px+'ids' , px+'playerids' ]: + cmsg('======= Indexs ======') + for i in session_players: + cmsg(i.getname()+' --> '+str(session_players.index(i))+'\n') + if not roster ==[]: + for i in roster: + cmsg(f'======For {px}kick only======') + cmsg(str(i['players'][0]['nam_full'])+' - '+str(i['client_id'])) + + elif m in [ px+'uniqeid' , px+'id' , px+'pb-id' , px+'pb' , px+'accountid' ]: + if n==[]: + cmsg(f'use : {px}uniqeid number of list') + else: + try: + id=session_players[int(n[0])] + cmsg(id.getname()+"'s accountid is "+id.get_v1_account_id()) + except: + cmsg('could not found player') + + elif m in [ px+'quit' , px+'restart' ]: + ba.quit() + + elif m in [ px+'mute' , px+'mutechat' ]: + cfg=ba.app.config + cfg['Chat Muted']=True + cfg.apply_and_commit() + cmsg('muted') + smsg(f'chat muted use {px}unmute and click on send to unmute') + + elif m in [ px+'unmute' , px+'unmutechat' ]: + cfg=ba.app.config + cfg['Chat Muted']=False + cfg.apply_and_commit() + cmsg('un_muted') + smsg('chat un_muted') + + elif m in [ px+'end' , px+'next' ]: + if n==[]: + try: + activity.end_game() + cmsg('Game ended Hope you scored great') + except: + cmsg('Game already ended') + + elif m in [ px+'dv' , px+'day' ]: + if activity.globalsnode.tint==(1.0,1.0,1.0): + cmsg(f'alwardy {px}dv is on ,do {px}nv for night') + else: + activity.globalsnode.tint=(1.0,1.0,1.0) + cmsg('day mode on!') + + elif m in [ px+'nv' , px+'night' ]: + if activity.globalsnode.tint==(0.5, 0.7, 1.0): + cmsg(f'alwardy {px}nv is on ,do {px}dv for day') + else: + activity.globalsnode.tint=(0.5, 0.7, 1.0) + cmsg('night mode on!') + + elif m in [ px+'sm' , px+'slow' , px+'slowmo' ]: + if n==[]: + if not activity.globalsnode.slow_motion: + activity.globalsnode.slow_motion=True + cmsg('Game in Epic Mode Now') + else: + activity.globalsnode.slow_motion=False + cmsg('Game in normal mode now ') + + elif m in [ px+'pause' , px+'pausegame' ]: + if n == []: + if not activity.globalsnode.paused: + activity.globalsnode.paused=True + cmsg('Game Paused') + else: + activity.globalsnode.paused=False + cmsg('Game un paused') + + elif m in [ px+'cameraMode', px+'camera_mode' , px+'rotate_camera' ]: + if n == []: + if not activity.globalsnode.camera_mode == 'rotate': + activity.globalsnode.camera_mode = 'rotate' + cmsg('camera mode is rotate now') + else: + activity.globalsnode.camera_mode = 'follow' + cmsg('camera mode is normal now') + + elif m in [ px+'remove' , px+'rm' ]: + if n == []: + cmsg(f'{px}remove all or {px}remove number in list') + elif n[0] == 'all': + for i in session_players: + i.remove_from_game() + cmsg('Removed All') + else: + try: + r=session_players[int(n[0])] + r.remove_from_game() + cmsg('Removed') #cant use getname() activity alwrady finish + except: + cmsg('could not found player') + elif m in [ px+'inv' , px+'invisible' ]: + if n==[]: + cmsg(f'help : {px}inv all or {px}inv number of list') + elif n[0]=='all': + for i in activity_players: + body=i.actor.node + if not body.torso_model==None: + body.head_model=None + body.torso_model=None + body.upper_arm_model=None + body.forearm_model=None + body.pelvis_model=None + body.hand_model=None + body.toes_model=None + body.upper_leg_model=None + body.lower_leg_model=None + body.style='cyborg' + cmsg('All invisible now Dont get cought') + else: + cmsg('alwardy invisible') + else: + body=activity_players[int(n[0])].actor.node + is_name=session_players[int(n[0])].getname() + if not body.torso_model==None: + body.head_model=None + body.torso_model=None + body.upper_arm_model=None + body.forearm_model=None + body.pelvis_model=None + body.hand_model=None + body.toes_model=None + body.upper_leg_model=None + body.lower_leg_model=None + body.style='cyborg' + cmsg(is_name+' using invisiblelity ') + else: + cmsg('alwardy invisible') + + elif m in [ px+'hl' , px+'headless' ]: + if n==[]: + cmsg(f'help : {px}spaz all or {px}spaz number of list') + elif n[0]=='all': + for i in activity_players: + body=i.actor.node + if not body.head_model==None: + body.head_model=None + body.style='cyborg' + cmsg('headless ? xD') + else: + cmsg('alwardy headless are you really headless?') + else: + body=activity_players[int(n[0])].actor.node + is_name=session_players[int(n[0])].getname() + if not body.head_model==None: + body.head_model=None + body.style='cyborg' + cmsg(is_name+'is headless now xD') + else: + cmsg('alwardy headless are you really headless?') + + elif m in [ px+'creepy' , px+'creep' ]: + if n==[]: + cmsg(f'use: {px}creepy all or {px}creepy number of list') + elif n[0]=='all': + for i in activity_players: + body=i.actor.node + body.head_model=None + body.handlemessage(ba.PowerupMessage(poweruptype='punch')) + body.handlemessage(ba.PowerupMessage(poweruptype='shield')) + cmsg('dont creep out childs all will be scared') + else: + try: + body=activity_players[int(n[0])].actor.node + body.head_model=None + body.handlemessage(ba.PowerupMessage(poweruptype='punch')) + body.handlemessage(ba.PowerupMessage(poweruptype='shield')) + cmsg('dont creep out childs all will be scared') + except: + cmsg('could not found player to make') + + elif m in [ px+'kill' , px+'die' ]: + if n == []: + cmsg(f'Use : {px}kill all or {px}kill number of list') + elif n[0]=='all': + for i in activity_players: + i.actor.node.handlemessage(ba.DieMessage()) + cmsg('Killed all') + else: + is_name=session_players[int(n[0])].getname() + activity_players[int(n[0])].actor.node.handlemessage(ba.DieMessage()) + cmsg('Killed '+is_name) + + elif m in [ px+'heal' , px+'heath' ]: + if n == []: + cmsg(f'Use: {px}heal all or {px}heal number of list') + elif n[0]=='all': + for i in activity_players: + i.actor.node.handlemessage(ba.PowerupMessage(poweruptype='health')) + cmsg('Heald all') + else: + is_name=session_players[int(n[0])].getname() + activity_players[int(n[0])].actor.node.handlemessage(ba.PowerupMessage(poweruptype='health')) + cmsg('Heald '+is_name) + + elif m in [ px+'curse' , px+'cur' ]: + if n == []: + cmsg(f'Use: {px}curse all or {px}curse number of list') + elif n[0]=='all': + for i in activity_players: + i.actor.node.handlemessage(ba.PowerupMessage(poweruptype='curse')) + cmsg('Cursed all') + else: + is_name=session_players[int(n[0])].getname() + activity_players[int(n[0])].actor.node.handlemessage(ba.PowerupMessage(poweruptype='curse')) + cmsg('Cursed '+is_name) + + elif m in [ px+'sleep' ]: + if n == []: + cmsg(f'Use: {px}sleep all or {px}sleep number of list') + elif n[0]=='all': + for i in activity_players: + i.actor.node.handlemessage('knockout', 8000) + cmsg('Sleep all its Night :)') + else: + is_name=session_players[int(n[0])].getname() + activity_players[int(n[0])].actor.node.handlemessage('knockout', 8000) + cmsg(is_name+' sleeped now') + + elif m in [ px+'sp' , px+'superpunch' ]: + if n == []: + cmsg(f'Use : {px}sp/superpunch all or {px}sp/superpunch number of list') + elif n[0]=='all': + for i in activity_players: + if not i.actor._punch_power_scale==15: + i.actor._punch_power_scale=15 + i.actor._punch_cooldown=0 + cmsg('Everyone enjoy your Super punches') + else: + i.actor._punch_power_scale=1.2 + i.actor._punch_cooldown=400 + cmsg('Super punches off now') + else: + try: + if not activity_players[int(n[0])].actor._punch_power_scale==15: + is_name=session_players[int(n[0])].getname() + activity_players[int(n[0])].actor._punch_power_scale=15 + activity_players[int(n[0])].actor._punch_cooldown=0 + cmsg(is_name+' using super punches get away from him') + else: + activity_players[int(n[0])].actor._punch_power_scale=1.2 + activity_players[int(n[0])].actor._punch_cooldown=400 + cmsg(':( ') + except: + pass + + elif m in [ px+'gloves' , px+'punch' ]: + if n == []: + cmsg(f'Use: {px}gloves all or {px}gloves number of list') + elif n[0]=='all': + for i in activity_players: + i.actor.node.handlemessage(ba.PowerupMessage(poweruptype='punch')) + cmsg('Free Gloves enjoy all') + else: + is_name=session_players[int(n[0])].getname() + activity_players[int(n[0])].actor.node.handlemessage(ba.PowerupMessage(poweruptype='punch')) + cmsg(is_name+' using gloves') + + + elif m in [ px+'shield' , px+'protect' ]: + if n == []: + cmsg(f'Use: {px}shield all or {px}shield number of list') + elif n[0]=='all': + for i in activity_players: + i.actor.node.handlemessage(ba.PowerupMessage(poweruptype='shield')) + cmsg('Everyone enjoy free shield :)') + else: + is_name=session_players[int(n[0])].getname() + activity_players[int(n[0])].actor.node.handlemessage(ba.PowerupMessage(poweruptype='shield')) + cmsg(is_name+' using shield') + + elif m in [ px+'freeze' , px+'ice' ]: + if n == []: + cmsg(f'Use: {px}freeze all or {px}freeze number of list') + elif n[0]=='all': + for i in activity_players: + i.actor.node.handlemessage(ba.FreezeMessage()) + cmsg('Freezed all') + else: + is_name=session_players[int(n[0])].getname() + activity_players[int(n[0])].actor.node.handlemessage(ba.FreezeMessage()) + cmsg('Un freezed '+is_name) + + elif m in [ px+'unfreeze' , px+'thaw' ]: + if n == []: + cmsg(f'Use: {px}unfreeze/thaw all or {px}unfreeze/thaw number of list') + elif n[0]=='all': + for i in activity_players: + i.actor.node.handlemessage(ba.ThawMessage()) + cmsg('Un freezed all ') + else: + is_name=session_players[int(n[0])].getname() + activity_players[int(n[0])].actor.node.handlemessage(ba.ThawMessage()) + cmsg('Un freezed '+is_name) + + elif m in [ px+'fall' ]: + if n == []: + cmsg(f'Use: {px}fall all or {px}fall number of list') + elif n[0]=='all': + for i in activity_players: + i.actor.node.handlemessage(ba.StandMessage()) + cmsg('Felt everyone') + else: + is_name=session_players[int(n[0])].getname() + activity_players[int(n[0])].actor.node.handlemessage(ba.StandMessage()) + cmsg(is_name+' got felt') + + elif m in [ px+'celebrate' , px+'celeb' ]: + if n == []: + cmsg(f'Use: {px}celebrate all or {px}celebrate number of list') + elif n[0]=='all': + for i in activity_players: + i.actor.node.handlemessage(ba.CelebrateMessage()) + cmsg('Celebrate all :)') + else: + is_name=session_players[int(n[0])].getname() + activity_players[int(n[0])].actor.node.handlemessage(ba.CelebrateMessage()) + cmsg(is_name+' is celebrating bt why?') + + elif m in [ px+'fly' ]: + if n==[]: + cmsg(f'Use: {px}fly all or {px}fly number of list') + elif n[0]=='all': + for i in activity_players: + if not i.actor.node.fly==True: + i.actor.node.fly=True + cmsg('fly all dont go out ok') + else: + i.actor.node.fly=False + cmsg('flying mode off') + else: + try: + is_name=session_players[int(n[0])].getname() + if not activity_players[int(n[0])].actor.node.fly==True: + activity_players[int(n[0])].actor.node.fly=True + cmsg(is_name+' is flying') + else: + activity_players[int(n[0])].actor.node.fly=False + cmsg('fly off :(') + except: + cmsg('player not found') + pass + + elif m in [ px+'gm' , px+'godmode' ]: + if n==[]: + cmsg(f'Use: {px}gm all or {px}gm number of list') + elif n[0]=='all': + for i in activity_players: + if not i.actor.node.hockey==True: + i.actor.node.hockey=True + i.actor.node.invincible=True + i.actor._punch_power_scale=7 + cmsg('Gmed all ') + else: + i.actor.node.hockey=False + i.actor.node.invincible=False + i.actor._punch_power_scale=1.2 + cmsg('Un gmed all') + else: + try: + is_name=session_players[int(n[0])].getname() + if not activity_players[int(n[0])].actor.node.hockey==True: + activity_players[int(n[0])].actor.node.hockey=True + activity_players[int(n[0])].actor.node.invincible=True + activity_players[int(n[0])].actor._punch_power_scale=7 + cmsg('Gmed '+is_name) + else: + activity_players[int(n[0])].actor.node.hockey=False + activity_players[int(n[0])].actor.node.invincible=False + activity_players[int(n[0])].actor._punch_power_scale=1.2 + cmsg('un gmed '+is_name) + except: + cmsg('could not found player') + elif m in [ px+'d_bomb', px+'default_bomb' ]: + if n == []: + cmsg(f'Use: {px}d_bomb/default_bomb all or {px}d_bomb number of list ,type {px}d_bomb help for help') + elif n[0]=='help': + cmsg("bombtypes - ['ice', 'impact', 'land_mine', 'normal', 'sticky','tnt']") + elif n[0] in [ 'ice' , 'impact', 'land_mine' , 'normal' , 'sticky' , 'tnt']: + for i in activity_players: + i.actor.bomb_type=n[0] + cmsg('default bomb type - '+str(n[0])+' now') + else: + cmsg('unkwon bombtype , type {px}d_bomb help for help') + + elif m in [ px+'d_bomb_count', px+'default_bomb_count' , px+'dbc' ]: + if n == []: + cmsg(f'Use: {px}d_bomb_count/default_bomb/dbc all or {px}d_bomb_count/default_bomb_count/dbc number of list') + else: + try: + for i in activity_players: + i.actor.set_bomb_count(int(n[0])) + cmsg('default bomb count is '+(str(n[0]))+' now') + except: + cmsg('Must use number to use') + elif m in [ px+'credits' ]: + if n==[]: + cmsg(u'\U0001F95A created by Nazz \U0001F95A') + cmsg(u'\U0001F95A Nazz are past/present/future \U0001F95A') + cmsg(u'\U0001F95A everything is Nazz \U0001F95A') + + + +# ba.timer(0.05, _update, repeat=True) +def same(): + ba.timer(0.5, _cmds._process_cmd, True) + +# ba_meta export plugin +class _enableee(ba.Plugin): + same() \ No newline at end of file From d58e326d4ca1198e4286540fe059a6f7eec522a9 Mon Sep 17 00:00:00 2001 From: Loup-Garou911XD Date: Thu, 3 Nov 2022 17:08:09 +0000 Subject: [PATCH 0204/1464] [ci] auto-format --- plugins/utilities/CustomDeath.py | 2 + plugins/utilities/MaxPlayers.py | 18 +- plugins/utilities/QuickCustonGame.py | 12 +- plugins/utilities/RandomColors.py | 40 +- plugins/utilities/chat_cmd.py | 1038 +++++++++++++------------- 5 files changed, 572 insertions(+), 538 deletions(-) diff --git a/plugins/utilities/CustomDeath.py b/plugins/utilities/CustomDeath.py index 809db736..b3730e12 100644 --- a/plugins/utilities/CustomDeath.py +++ b/plugins/utilities/CustomDeath.py @@ -13,6 +13,8 @@ Spaz.oldhandlemessage = Spaz.handlemessage + + def handlemessage(self, msg: Any) -> Any: if isinstance(msg, ba.DieMessage): if self.node: diff --git a/plugins/utilities/MaxPlayers.py b/plugins/utilities/MaxPlayers.py index dce5ec04..6d6257a4 100644 --- a/plugins/utilities/MaxPlayers.py +++ b/plugins/utilities/MaxPlayers.py @@ -37,6 +37,7 @@ teams_text = 'Teams' ffa_text = 'FFA' + class ConfigNumberEdit: def __init__(self, @@ -102,6 +103,7 @@ def _update_display(self) -> None: cfg['Config Max Players'][self._config] = self._value cfg.apply_and_commit() + class SettingsMaxPlayers(PopupWindow): def __init__(self): @@ -180,6 +182,7 @@ def on_popup_cancel(self) -> None: ba.playsound(ba.getsound('swish')) self._transition_out() + def __init__(self) -> None: """Instantiate a co-op mode session.""" # pylint: disable=cyclic-import @@ -230,6 +233,7 @@ def __init__(self) -> None: self._next_game_level_name: Optional[str] = None self._update_on_deck_game_instances() + def get_max_players(self) -> int: """Return max number of ba.Players allowed to join the game at once.""" if self.use_teams: @@ -240,11 +244,15 @@ def get_max_players(self) -> int: 'Free-for-All Max Players', cfg['Config Max Players']['ffa_max_players']) + GatherWindow.__old_init__ = GatherWindow.__init__ + + def __gather_init__(self, - transition: Optional[str] = 'in_right', - origin_widget: ba.Widget = None): + transition: Optional[str] = 'in_right', + origin_widget: ba.Widget = None): self.__old_init__(transition, origin_widget) + def _do_max_players(): SettingsMaxPlayers() self._max_players_button = ba.buttonwidget( @@ -260,6 +268,7 @@ def _do_max_players(): button_type='regular', on_activate_call=_do_max_players) + def _save_state(self) -> None: try: for tab in self._tabs.values(): @@ -287,6 +296,7 @@ def _save_state(self) -> None: except Exception: ba.print_exception(f'Error saving state for {self}.') + def _restore_state(self) -> None: from efro.util import enum_by_value try: @@ -326,6 +336,8 @@ def _restore_state(self) -> None: ba.print_exception('Error restoring gather-win state.') # ba_meta export plugin + + class MaxPlayersPlugin(ba.Plugin): def has_settings_ui(self) -> bool: @@ -338,7 +350,7 @@ def show_settings_ui(self, source_widget: ba.Widget | None) -> None: old_config = ba.app.config['Config Max Players'] for setting in cmp: if setting not in old_config: - ba.app.config['Config Max Players'].update({setting:cmp[setting]}) + ba.app.config['Config Max Players'].update({setting: cmp[setting]}) remove_list = [] for setting in old_config: if setting not in cmp: diff --git a/plugins/utilities/QuickCustonGame.py b/plugins/utilities/QuickCustonGame.py index dcc93c48..259dff2b 100644 --- a/plugins/utilities/QuickCustonGame.py +++ b/plugins/utilities/QuickCustonGame.py @@ -19,9 +19,9 @@ lang = ba.app.lang.language if lang == 'Spanish': - custom_txt = 'personalizar...' + custom_txt = 'personalizar...' else: - custom_txt = 'custom...' + custom_txt = 'custom...' if 'quick_game_button' in ba.app.config: @@ -31,6 +31,7 @@ ba.app.config['quick_game_button'] = config ba.app.config.commit() + def start_game(session: ba.Session, fadeout: bool = True): def callback(): if fadeout: @@ -50,6 +51,7 @@ def callback(): else: callback() + class SimplePlaylist: def __init__(self, @@ -66,6 +68,7 @@ def pull_next(self) -> None: settings = self.settings['settings'] return dict(resolved_type=self.gametype, settings=settings) + class CustomSession(FreeForAllSession): def __init__(self, *args, **kwargs): @@ -305,6 +308,8 @@ def _back(self) -> None: PlayWindow._old_init = PlayWindow.__init__ + + def __init__(self, *args, **kwargs): self._old_init() @@ -331,6 +336,7 @@ def do_quick_game() -> None: self._restore_state() + def states(self) -> None: return { 'Team Games': self._teams_button, @@ -340,6 +346,7 @@ def states(self) -> None: 'Quick Game': self._quick_game_button } + def _save_state(self) -> None: swapped = {v: k for k, v in states(self).items()} if self._root_widget.get_selected_child() in swapped: @@ -349,6 +356,7 @@ def _save_state(self) -> None: else: ba.print_exception(f'Error saving state for {self}.') + def _restore_state(self) -> None: if not hasattr(self, '_quick_game_button'): return # ensure that our monkey patched init ran diff --git a/plugins/utilities/RandomColors.py b/plugins/utilities/RandomColors.py index eacf0bed..3ea0ba6e 100644 --- a/plugins/utilities/RandomColors.py +++ b/plugins/utilities/RandomColors.py @@ -10,11 +10,11 @@ from bastd.actor import bomb if TYPE_CHECKING: - from typing import Sequence + from typing import Sequence class NewBlast(bomb.Blast): - def __init__( + def __init__( self, position: Sequence[float] = (0.0, 1.0, 0.0), velocity: Sequence[float] = (0.0, 0.0, 0.0), @@ -24,25 +24,25 @@ def __init__( hit_type: str = 'explosion', hit_subtype: str = 'normal', ): - super().__init__(position, velocity, blast_radius, blast_type, - source_player, hit_type, hit_subtype) - scorch_radius = light_radius = self.radius - if self.blast_type == 'tnt': - scorch_radius *= 1.15 - scorch = ba.newnode( - 'scorch', - attrs={ - 'position': position, - 'size': scorch_radius * 0.5, - 'big': (self.blast_type == 'tnt'), - }, - ) - random_color = (random.random(), random.random(), random.random()) - scorch.color = ba.safecolor(random_color) - ba.animate(scorch, 'presence', {3.000: 1, 13.000: 0}) - ba.timer(13.0, scorch.delete) + super().__init__(position, velocity, blast_radius, blast_type, + source_player, hit_type, hit_subtype) + scorch_radius = light_radius = self.radius + if self.blast_type == 'tnt': + scorch_radius *= 1.15 + scorch = ba.newnode( + 'scorch', + attrs={ + 'position': position, + 'size': scorch_radius * 0.5, + 'big': (self.blast_type == 'tnt'), + }, + ) + random_color = (random.random(), random.random(), random.random()) + scorch.color = ba.safecolor(random_color) + ba.animate(scorch, 'presence', {3.000: 1, 13.000: 0}) + ba.timer(13.0, scorch.delete) # ba_meta export plugin class RandomColorsPlugin(ba.Plugin): - bomb.Blast = NewBlast + bomb.Blast = NewBlast diff --git a/plugins/utilities/chat_cmd.py b/plugins/utilities/chat_cmd.py index cc9150d6..5bb3da4f 100644 --- a/plugins/utilities/chat_cmd.py +++ b/plugins/utilities/chat_cmd.py @@ -4,528 +4,540 @@ # biggggggg thankssssssssssssss to FireFighter1037 for helping everything # -*- coding: utf-8 -*- -# ba_meta require api 7 -from _ba import env,get_foreground_host_activity,get_foreground_host_session,get_game_roster, get_chat_messages,set_party_icon_always_visible, chatmessage as cmsg, screenmessage as smsg +# ba_meta require api 7 +from _ba import env, get_foreground_host_activity, get_foreground_host_session, get_game_roster, get_chat_messages, set_party_icon_always_visible, chatmessage as cmsg, screenmessage as smsg import ba -#our prefix that what we starts cmds with -px='/' +# our prefix that what we starts cmds with +px = '/' + +# main class + -#main class class _cmds: - - def _process_cmd(): - set_party_icon_always_visible(True) - messages=get_chat_messages() - if len(messages)>1: - lastmsg = messages[len(messages)-1] - - m=lastmsg.split(' ')[1] - if m.startswith(px): - return _cmds._handle() - else: - pass - - def _handle(): - messages=get_chat_messages() - if len(messages)>1: - lastmsg = messages[len(messages)-1] - - m=lastmsg.split(' ')[1] #cmd - n=lastmsg.split(' ')[2:] #aguments - - roster=get_game_roster() - session=get_foreground_host_session() - session_players=session.sessionplayers - - activity=get_foreground_host_activity() - activity_players=activity.players - - if m == px: - cmsg(px+'help for help') - - elif m == px+'help' : - if n==[]: - cmsg('===========================================') - cmsg(f' {px}help 1 - for page 1 | simple commands') - cmsg(f' {px}help 2 - for page 2 | all or number of list cmds') - cmsg(f' {px}help 3 - for page 3 | Other useful cmds') - cmsg('===========================================') - elif n[0]=='1': - cmsg('============================') - cmsg(f' {px}help 1 page 1 |') - cmsg(f' {px}help 1 page 2 |') - cmsg('============================') - if n[1] in [ 'page' , 'Page' , ]: - if n[2]=='1': - cmsg('============== Help 1, Page 1 ==============') - cmsg(f' your command prefix is or all commands starts with - {px}') - cmsg(f' {px}list or {px}l -- to see ids of players and execute commands') - cmsg(f' {px}uniqeid or {px}id -- to see accountid/uniqeid of player') - cmsg(f' {px}quit or {px}restart -- to restart the game') - cmsg(f' {px}mute/unmute -- to mute chat for everyone in your game') - elif n[2]=='2': - cmsg('============== Help 1, Page 2 ==============') - cmsg(f' {px}pause -- to pause everyone in your game') - cmsg(f' {px}nv or {px}night -- to make night in your game') - cmsg(f' {px}dv or {px}day -- to make night in your game') - cmsg(f' {px}camera_mode -- to rotate camera ,repat to off') - cmsg('===========================================') - elif n[0]=='2': - cmsg('============================') - cmsg(f' {px}help 2 page 1 |') - cmsg(f' {px}help 2 page 2 |') - cmsg(f' {px}help 2 page 3 |') - cmsg('============================') - if n[1] in [ 'page' , 'Page' ]: - if n[2] == '1': - cmsg('============== Help 2 Page 1 ==============') - cmsg(f' {px}kill all or {px}kill number of list | kills the player') - cmsg(f' {px}heal all or {px}heal number of list | heals the players') - cmsg(f' {px}freeze all or {px}freeze number of list | freeze the player') - cmsg(f' {px}unfreeze/thaw all or {px}unfreeze/thaw number of list | unfreeze the player') - cmsg(f' {px}gloves all or {px}gloves number of list | give gloves to player') - cmsg('============================') - elif n[2] == '2': - cmsg('============== Help 2 Page 2 ==============') - cmsg(f' {px}shield all or {px}shield number of list | give shield the player') - cmsg(f' {px}fall all or {px}fall number of list | teleport in down and fall up the player') - cmsg(f' {px}curse all or {px}curse number of list | curse the player') - cmsg(f' {px}creepy all or {px}creepy number of list | make creepy actor of player') - cmsg(f' {px}inv all or {px}inv number of list | makes invisible player') - cmsg(f' {px}celebrate all or {px}celebrate number of list | celebrate action to the player') - cmsg('============================') - elif n[2] == '3': - cmsg('============== Help 2 Page 3 ==============') - cmsg(f' {px}gm all or {px}gm number of list | give bs gods like powers to player') - cmsg(f' {px}sp all or {px}sp number of list | give superrrrrrr damages when punch to player') - cmsg(f' {px}sleep all or {px}sleep number of list | sleep up the player') - cmsg(f' {px}fly all or {px}fly number of list | fly up the player ') - cmsg(f' {px}hug number of list | hugup the player') - cmsg('============================') - - elif n[0]=='3': - cmsg('============================') - cmsg(f" {px}d_bomb bombType | changes default bomb | do {px}d_bomb help for bomb names ") - cmsg(f' {px}dbc (number of bombs) | changes default count of player') - cmsg('============================') - - - elif m in [ px+'list' , px+'l' , px+'clientids' , px+'ids' , px+'playerids' ]: - cmsg('======= Indexs ======') - for i in session_players: - cmsg(i.getname()+' --> '+str(session_players.index(i))+'\n') - if not roster ==[]: - for i in roster: - cmsg(f'======For {px}kick only======') - cmsg(str(i['players'][0]['nam_full'])+' - '+str(i['client_id'])) - - elif m in [ px+'uniqeid' , px+'id' , px+'pb-id' , px+'pb' , px+'accountid' ]: - if n==[]: - cmsg(f'use : {px}uniqeid number of list') - else: - try: - id=session_players[int(n[0])] - cmsg(id.getname()+"'s accountid is "+id.get_v1_account_id()) - except: - cmsg('could not found player') - - elif m in [ px+'quit' , px+'restart' ]: - ba.quit() - - elif m in [ px+'mute' , px+'mutechat' ]: - cfg=ba.app.config - cfg['Chat Muted']=True - cfg.apply_and_commit() - cmsg('muted') - smsg(f'chat muted use {px}unmute and click on send to unmute') - - elif m in [ px+'unmute' , px+'unmutechat' ]: - cfg=ba.app.config - cfg['Chat Muted']=False - cfg.apply_and_commit() - cmsg('un_muted') - smsg('chat un_muted') - - elif m in [ px+'end' , px+'next' ]: - if n==[]: - try: - activity.end_game() - cmsg('Game ended Hope you scored great') - except: - cmsg('Game already ended') - - elif m in [ px+'dv' , px+'day' ]: - if activity.globalsnode.tint==(1.0,1.0,1.0): - cmsg(f'alwardy {px}dv is on ,do {px}nv for night') - else: - activity.globalsnode.tint=(1.0,1.0,1.0) - cmsg('day mode on!') - - elif m in [ px+'nv' , px+'night' ]: - if activity.globalsnode.tint==(0.5, 0.7, 1.0): - cmsg(f'alwardy {px}nv is on ,do {px}dv for day') - else: - activity.globalsnode.tint=(0.5, 0.7, 1.0) - cmsg('night mode on!') - - elif m in [ px+'sm' , px+'slow' , px+'slowmo' ]: - if n==[]: - if not activity.globalsnode.slow_motion: - activity.globalsnode.slow_motion=True - cmsg('Game in Epic Mode Now') - else: - activity.globalsnode.slow_motion=False - cmsg('Game in normal mode now ') - - elif m in [ px+'pause' , px+'pausegame' ]: - if n == []: - if not activity.globalsnode.paused: - activity.globalsnode.paused=True - cmsg('Game Paused') - else: - activity.globalsnode.paused=False - cmsg('Game un paused') - - elif m in [ px+'cameraMode', px+'camera_mode' , px+'rotate_camera' ]: - if n == []: - if not activity.globalsnode.camera_mode == 'rotate': - activity.globalsnode.camera_mode = 'rotate' - cmsg('camera mode is rotate now') - else: - activity.globalsnode.camera_mode = 'follow' - cmsg('camera mode is normal now') - - elif m in [ px+'remove' , px+'rm' ]: - if n == []: - cmsg(f'{px}remove all or {px}remove number in list') - elif n[0] == 'all': - for i in session_players: - i.remove_from_game() - cmsg('Removed All') - else: - try: - r=session_players[int(n[0])] - r.remove_from_game() - cmsg('Removed') #cant use getname() activity alwrady finish - except: - cmsg('could not found player') - elif m in [ px+'inv' , px+'invisible' ]: - if n==[]: - cmsg(f'help : {px}inv all or {px}inv number of list') - elif n[0]=='all': - for i in activity_players: - body=i.actor.node - if not body.torso_model==None: - body.head_model=None - body.torso_model=None - body.upper_arm_model=None - body.forearm_model=None - body.pelvis_model=None - body.hand_model=None - body.toes_model=None - body.upper_leg_model=None - body.lower_leg_model=None - body.style='cyborg' - cmsg('All invisible now Dont get cought') - else: - cmsg('alwardy invisible') - else: - body=activity_players[int(n[0])].actor.node - is_name=session_players[int(n[0])].getname() - if not body.torso_model==None: - body.head_model=None - body.torso_model=None - body.upper_arm_model=None - body.forearm_model=None - body.pelvis_model=None - body.hand_model=None - body.toes_model=None - body.upper_leg_model=None - body.lower_leg_model=None - body.style='cyborg' - cmsg(is_name+' using invisiblelity ') - else: - cmsg('alwardy invisible') - - elif m in [ px+'hl' , px+'headless' ]: - if n==[]: - cmsg(f'help : {px}spaz all or {px}spaz number of list') - elif n[0]=='all': - for i in activity_players: - body=i.actor.node - if not body.head_model==None: - body.head_model=None - body.style='cyborg' - cmsg('headless ? xD') - else: - cmsg('alwardy headless are you really headless?') - else: - body=activity_players[int(n[0])].actor.node - is_name=session_players[int(n[0])].getname() - if not body.head_model==None: - body.head_model=None - body.style='cyborg' - cmsg(is_name+'is headless now xD') - else: - cmsg('alwardy headless are you really headless?') - - elif m in [ px+'creepy' , px+'creep' ]: - if n==[]: - cmsg(f'use: {px}creepy all or {px}creepy number of list') - elif n[0]=='all': - for i in activity_players: - body=i.actor.node - body.head_model=None - body.handlemessage(ba.PowerupMessage(poweruptype='punch')) - body.handlemessage(ba.PowerupMessage(poweruptype='shield')) - cmsg('dont creep out childs all will be scared') - else: - try: - body=activity_players[int(n[0])].actor.node - body.head_model=None - body.handlemessage(ba.PowerupMessage(poweruptype='punch')) - body.handlemessage(ba.PowerupMessage(poweruptype='shield')) - cmsg('dont creep out childs all will be scared') - except: - cmsg('could not found player to make') - - elif m in [ px+'kill' , px+'die' ]: - if n == []: - cmsg(f'Use : {px}kill all or {px}kill number of list') - elif n[0]=='all': - for i in activity_players: - i.actor.node.handlemessage(ba.DieMessage()) - cmsg('Killed all') - else: - is_name=session_players[int(n[0])].getname() - activity_players[int(n[0])].actor.node.handlemessage(ba.DieMessage()) - cmsg('Killed '+is_name) - - elif m in [ px+'heal' , px+'heath' ]: - if n == []: - cmsg(f'Use: {px}heal all or {px}heal number of list') - elif n[0]=='all': - for i in activity_players: - i.actor.node.handlemessage(ba.PowerupMessage(poweruptype='health')) - cmsg('Heald all') - else: - is_name=session_players[int(n[0])].getname() - activity_players[int(n[0])].actor.node.handlemessage(ba.PowerupMessage(poweruptype='health')) - cmsg('Heald '+is_name) - - elif m in [ px+'curse' , px+'cur' ]: - if n == []: - cmsg(f'Use: {px}curse all or {px}curse number of list') - elif n[0]=='all': - for i in activity_players: - i.actor.node.handlemessage(ba.PowerupMessage(poweruptype='curse')) - cmsg('Cursed all') - else: - is_name=session_players[int(n[0])].getname() - activity_players[int(n[0])].actor.node.handlemessage(ba.PowerupMessage(poweruptype='curse')) - cmsg('Cursed '+is_name) - - elif m in [ px+'sleep' ]: - if n == []: - cmsg(f'Use: {px}sleep all or {px}sleep number of list') - elif n[0]=='all': - for i in activity_players: - i.actor.node.handlemessage('knockout', 8000) - cmsg('Sleep all its Night :)') - else: - is_name=session_players[int(n[0])].getname() - activity_players[int(n[0])].actor.node.handlemessage('knockout', 8000) - cmsg(is_name+' sleeped now') - - elif m in [ px+'sp' , px+'superpunch' ]: - if n == []: - cmsg(f'Use : {px}sp/superpunch all or {px}sp/superpunch number of list') - elif n[0]=='all': - for i in activity_players: - if not i.actor._punch_power_scale==15: - i.actor._punch_power_scale=15 - i.actor._punch_cooldown=0 - cmsg('Everyone enjoy your Super punches') - else: - i.actor._punch_power_scale=1.2 - i.actor._punch_cooldown=400 - cmsg('Super punches off now') - else: - try: - if not activity_players[int(n[0])].actor._punch_power_scale==15: - is_name=session_players[int(n[0])].getname() - activity_players[int(n[0])].actor._punch_power_scale=15 - activity_players[int(n[0])].actor._punch_cooldown=0 - cmsg(is_name+' using super punches get away from him') - else: - activity_players[int(n[0])].actor._punch_power_scale=1.2 - activity_players[int(n[0])].actor._punch_cooldown=400 - cmsg(':( ') - except: - pass - - elif m in [ px+'gloves' , px+'punch' ]: - if n == []: - cmsg(f'Use: {px}gloves all or {px}gloves number of list') - elif n[0]=='all': - for i in activity_players: - i.actor.node.handlemessage(ba.PowerupMessage(poweruptype='punch')) - cmsg('Free Gloves enjoy all') - else: - is_name=session_players[int(n[0])].getname() - activity_players[int(n[0])].actor.node.handlemessage(ba.PowerupMessage(poweruptype='punch')) - cmsg(is_name+' using gloves') - - - elif m in [ px+'shield' , px+'protect' ]: - if n == []: - cmsg(f'Use: {px}shield all or {px}shield number of list') - elif n[0]=='all': - for i in activity_players: - i.actor.node.handlemessage(ba.PowerupMessage(poweruptype='shield')) - cmsg('Everyone enjoy free shield :)') - else: - is_name=session_players[int(n[0])].getname() - activity_players[int(n[0])].actor.node.handlemessage(ba.PowerupMessage(poweruptype='shield')) - cmsg(is_name+' using shield') - - elif m in [ px+'freeze' , px+'ice' ]: - if n == []: - cmsg(f'Use: {px}freeze all or {px}freeze number of list') - elif n[0]=='all': - for i in activity_players: - i.actor.node.handlemessage(ba.FreezeMessage()) - cmsg('Freezed all') - else: - is_name=session_players[int(n[0])].getname() - activity_players[int(n[0])].actor.node.handlemessage(ba.FreezeMessage()) - cmsg('Un freezed '+is_name) - - elif m in [ px+'unfreeze' , px+'thaw' ]: - if n == []: - cmsg(f'Use: {px}unfreeze/thaw all or {px}unfreeze/thaw number of list') - elif n[0]=='all': - for i in activity_players: - i.actor.node.handlemessage(ba.ThawMessage()) - cmsg('Un freezed all ') - else: - is_name=session_players[int(n[0])].getname() - activity_players[int(n[0])].actor.node.handlemessage(ba.ThawMessage()) - cmsg('Un freezed '+is_name) - - elif m in [ px+'fall' ]: - if n == []: - cmsg(f'Use: {px}fall all or {px}fall number of list') - elif n[0]=='all': - for i in activity_players: - i.actor.node.handlemessage(ba.StandMessage()) - cmsg('Felt everyone') - else: - is_name=session_players[int(n[0])].getname() - activity_players[int(n[0])].actor.node.handlemessage(ba.StandMessage()) - cmsg(is_name+' got felt') - - elif m in [ px+'celebrate' , px+'celeb' ]: - if n == []: - cmsg(f'Use: {px}celebrate all or {px}celebrate number of list') - elif n[0]=='all': - for i in activity_players: - i.actor.node.handlemessage(ba.CelebrateMessage()) - cmsg('Celebrate all :)') - else: - is_name=session_players[int(n[0])].getname() - activity_players[int(n[0])].actor.node.handlemessage(ba.CelebrateMessage()) - cmsg(is_name+' is celebrating bt why?') - - elif m in [ px+'fly' ]: - if n==[]: - cmsg(f'Use: {px}fly all or {px}fly number of list') - elif n[0]=='all': - for i in activity_players: - if not i.actor.node.fly==True: - i.actor.node.fly=True - cmsg('fly all dont go out ok') - else: - i.actor.node.fly=False - cmsg('flying mode off') - else: - try: - is_name=session_players[int(n[0])].getname() - if not activity_players[int(n[0])].actor.node.fly==True: - activity_players[int(n[0])].actor.node.fly=True - cmsg(is_name+' is flying') - else: - activity_players[int(n[0])].actor.node.fly=False - cmsg('fly off :(') - except: - cmsg('player not found') - pass - - elif m in [ px+'gm' , px+'godmode' ]: - if n==[]: - cmsg(f'Use: {px}gm all or {px}gm number of list') - elif n[0]=='all': - for i in activity_players: - if not i.actor.node.hockey==True: - i.actor.node.hockey=True - i.actor.node.invincible=True - i.actor._punch_power_scale=7 - cmsg('Gmed all ') - else: - i.actor.node.hockey=False - i.actor.node.invincible=False - i.actor._punch_power_scale=1.2 - cmsg('Un gmed all') - else: - try: - is_name=session_players[int(n[0])].getname() - if not activity_players[int(n[0])].actor.node.hockey==True: - activity_players[int(n[0])].actor.node.hockey=True - activity_players[int(n[0])].actor.node.invincible=True - activity_players[int(n[0])].actor._punch_power_scale=7 - cmsg('Gmed '+is_name) - else: - activity_players[int(n[0])].actor.node.hockey=False - activity_players[int(n[0])].actor.node.invincible=False - activity_players[int(n[0])].actor._punch_power_scale=1.2 - cmsg('un gmed '+is_name) - except: - cmsg('could not found player') - elif m in [ px+'d_bomb', px+'default_bomb' ]: - if n == []: - cmsg(f'Use: {px}d_bomb/default_bomb all or {px}d_bomb number of list ,type {px}d_bomb help for help') - elif n[0]=='help': - cmsg("bombtypes - ['ice', 'impact', 'land_mine', 'normal', 'sticky','tnt']") - elif n[0] in [ 'ice' , 'impact', 'land_mine' , 'normal' , 'sticky' , 'tnt']: - for i in activity_players: - i.actor.bomb_type=n[0] - cmsg('default bomb type - '+str(n[0])+' now') - else: - cmsg('unkwon bombtype , type {px}d_bomb help for help') - - elif m in [ px+'d_bomb_count', px+'default_bomb_count' , px+'dbc' ]: - if n == []: - cmsg(f'Use: {px}d_bomb_count/default_bomb/dbc all or {px}d_bomb_count/default_bomb_count/dbc number of list') - else: - try: - for i in activity_players: - i.actor.set_bomb_count(int(n[0])) - cmsg('default bomb count is '+(str(n[0]))+' now') - except: - cmsg('Must use number to use') - elif m in [ px+'credits' ]: - if n==[]: - cmsg(u'\U0001F95A created by Nazz \U0001F95A') - cmsg(u'\U0001F95A Nazz are past/present/future \U0001F95A') - cmsg(u'\U0001F95A everything is Nazz \U0001F95A') + def _process_cmd(): + set_party_icon_always_visible(True) + messages = get_chat_messages() + if len(messages) > 1: + lastmsg = messages[len(messages)-1] + + m = lastmsg.split(' ')[1] + if m.startswith(px): + return _cmds._handle() + else: + pass + + def _handle(): + messages = get_chat_messages() + if len(messages) > 1: + lastmsg = messages[len(messages)-1] + + m = lastmsg.split(' ')[1] # cmd + n = lastmsg.split(' ')[2:] # aguments + + roster = get_game_roster() + session = get_foreground_host_session() + session_players = session.sessionplayers + + activity = get_foreground_host_activity() + activity_players = activity.players + + if m == px: + cmsg(px+'help for help') + + elif m == px+'help': + if n == []: + cmsg('===========================================') + cmsg(f' {px}help 1 - for page 1 | simple commands') + cmsg(f' {px}help 2 - for page 2 | all or number of list cmds') + cmsg(f' {px}help 3 - for page 3 | Other useful cmds') + cmsg('===========================================') + elif n[0] == '1': + cmsg('============================') + cmsg(f' {px}help 1 page 1 |') + cmsg(f' {px}help 1 page 2 |') + cmsg('============================') + if n[1] in ['page', 'Page', ]: + if n[2] == '1': + cmsg('============== Help 1, Page 1 ==============') + cmsg(f' your command prefix is or all commands starts with - {px}') + cmsg(f' {px}list or {px}l -- to see ids of players and execute commands') + cmsg(f' {px}uniqeid or {px}id -- to see accountid/uniqeid of player') + cmsg(f' {px}quit or {px}restart -- to restart the game') + cmsg(f' {px}mute/unmute -- to mute chat for everyone in your game') + elif n[2] == '2': + cmsg('============== Help 1, Page 2 ==============') + cmsg(f' {px}pause -- to pause everyone in your game') + cmsg(f' {px}nv or {px}night -- to make night in your game') + cmsg(f' {px}dv or {px}day -- to make night in your game') + cmsg(f' {px}camera_mode -- to rotate camera ,repat to off') + cmsg('===========================================') + elif n[0] == '2': + cmsg('============================') + cmsg(f' {px}help 2 page 1 |') + cmsg(f' {px}help 2 page 2 |') + cmsg(f' {px}help 2 page 3 |') + cmsg('============================') + if n[1] in ['page', 'Page']: + if n[2] == '1': + cmsg('============== Help 2 Page 1 ==============') + cmsg(f' {px}kill all or {px}kill number of list | kills the player') + cmsg(f' {px}heal all or {px}heal number of list | heals the players') + cmsg(f' {px}freeze all or {px}freeze number of list | freeze the player') + cmsg( + f' {px}unfreeze/thaw all or {px}unfreeze/thaw number of list | unfreeze the player') + cmsg(f' {px}gloves all or {px}gloves number of list | give gloves to player') + cmsg('============================') + elif n[2] == '2': + cmsg('============== Help 2 Page 2 ==============') + cmsg(f' {px}shield all or {px}shield number of list | give shield the player') + cmsg( + f' {px}fall all or {px}fall number of list | teleport in down and fall up the player') + cmsg(f' {px}curse all or {px}curse number of list | curse the player') + cmsg( + f' {px}creepy all or {px}creepy number of list | make creepy actor of player') + cmsg(f' {px}inv all or {px}inv number of list | makes invisible player') + cmsg( + f' {px}celebrate all or {px}celebrate number of list | celebrate action to the player') + cmsg('============================') + elif n[2] == '3': + cmsg('============== Help 2 Page 3 ==============') + cmsg(f' {px}gm all or {px}gm number of list | give bs gods like powers to player') + cmsg( + f' {px}sp all or {px}sp number of list | give superrrrrrr damages when punch to player') + cmsg(f' {px}sleep all or {px}sleep number of list | sleep up the player') + cmsg(f' {px}fly all or {px}fly number of list | fly up the player ') + cmsg(f' {px}hug number of list | hugup the player') + cmsg('============================') + + elif n[0] == '3': + cmsg('============================') + cmsg(f" {px}d_bomb bombType | changes default bomb | do {px}d_bomb help for bomb names ") + cmsg(f' {px}dbc (number of bombs) | changes default count of player') + cmsg('============================') + + elif m in [px+'list', px+'l', px+'clientids', px+'ids', px+'playerids']: + cmsg('======= Indexs ======') + for i in session_players: + cmsg(i.getname()+' --> '+str(session_players.index(i))+'\n') + if not roster == []: + for i in roster: + cmsg(f'======For {px}kick only======') + cmsg(str(i['players'][0]['nam_full'])+' - '+str(i['client_id'])) + + elif m in [px+'uniqeid', px+'id', px+'pb-id', px+'pb', px+'accountid']: + if n == []: + cmsg(f'use : {px}uniqeid number of list') + else: + try: + id = session_players[int(n[0])] + cmsg(id.getname()+"'s accountid is "+id.get_v1_account_id()) + except: + cmsg('could not found player') + + elif m in [px+'quit', px+'restart']: + ba.quit() + + elif m in [px+'mute', px+'mutechat']: + cfg = ba.app.config + cfg['Chat Muted'] = True + cfg.apply_and_commit() + cmsg('muted') + smsg(f'chat muted use {px}unmute and click on send to unmute') + + elif m in [px+'unmute', px+'unmutechat']: + cfg = ba.app.config + cfg['Chat Muted'] = False + cfg.apply_and_commit() + cmsg('un_muted') + smsg('chat un_muted') + + elif m in [px+'end', px+'next']: + if n == []: + try: + activity.end_game() + cmsg('Game ended Hope you scored great') + except: + cmsg('Game already ended') + + elif m in [px+'dv', px+'day']: + if activity.globalsnode.tint == (1.0, 1.0, 1.0): + cmsg(f'alwardy {px}dv is on ,do {px}nv for night') + else: + activity.globalsnode.tint = (1.0, 1.0, 1.0) + cmsg('day mode on!') + + elif m in [px+'nv', px+'night']: + if activity.globalsnode.tint == (0.5, 0.7, 1.0): + cmsg(f'alwardy {px}nv is on ,do {px}dv for day') + else: + activity.globalsnode.tint = (0.5, 0.7, 1.0) + cmsg('night mode on!') + + elif m in [px+'sm', px+'slow', px+'slowmo']: + if n == []: + if not activity.globalsnode.slow_motion: + activity.globalsnode.slow_motion = True + cmsg('Game in Epic Mode Now') + else: + activity.globalsnode.slow_motion = False + cmsg('Game in normal mode now ') + + elif m in [px+'pause', px+'pausegame']: + if n == []: + if not activity.globalsnode.paused: + activity.globalsnode.paused = True + cmsg('Game Paused') + else: + activity.globalsnode.paused = False + cmsg('Game un paused') + + elif m in [px+'cameraMode', px+'camera_mode', px+'rotate_camera']: + if n == []: + if not activity.globalsnode.camera_mode == 'rotate': + activity.globalsnode.camera_mode = 'rotate' + cmsg('camera mode is rotate now') + else: + activity.globalsnode.camera_mode = 'follow' + cmsg('camera mode is normal now') + + elif m in [px+'remove', px+'rm']: + if n == []: + cmsg(f'{px}remove all or {px}remove number in list') + elif n[0] == 'all': + for i in session_players: + i.remove_from_game() + cmsg('Removed All') + else: + try: + r = session_players[int(n[0])] + r.remove_from_game() + cmsg('Removed') # cant use getname() activity alwrady finish + except: + cmsg('could not found player') + elif m in [px+'inv', px+'invisible']: + if n == []: + cmsg(f'help : {px}inv all or {px}inv number of list') + elif n[0] == 'all': + for i in activity_players: + body = i.actor.node + if not body.torso_model == None: + body.head_model = None + body.torso_model = None + body.upper_arm_model = None + body.forearm_model = None + body.pelvis_model = None + body.hand_model = None + body.toes_model = None + body.upper_leg_model = None + body.lower_leg_model = None + body.style = 'cyborg' + cmsg('All invisible now Dont get cought') + else: + cmsg('alwardy invisible') + else: + body = activity_players[int(n[0])].actor.node + is_name = session_players[int(n[0])].getname() + if not body.torso_model == None: + body.head_model = None + body.torso_model = None + body.upper_arm_model = None + body.forearm_model = None + body.pelvis_model = None + body.hand_model = None + body.toes_model = None + body.upper_leg_model = None + body.lower_leg_model = None + body.style = 'cyborg' + cmsg(is_name+' using invisiblelity ') + else: + cmsg('alwardy invisible') + + elif m in [px+'hl', px+'headless']: + if n == []: + cmsg(f'help : {px}spaz all or {px}spaz number of list') + elif n[0] == 'all': + for i in activity_players: + body = i.actor.node + if not body.head_model == None: + body.head_model = None + body.style = 'cyborg' + cmsg('headless ? xD') + else: + cmsg('alwardy headless are you really headless?') + else: + body = activity_players[int(n[0])].actor.node + is_name = session_players[int(n[0])].getname() + if not body.head_model == None: + body.head_model = None + body.style = 'cyborg' + cmsg(is_name+'is headless now xD') + else: + cmsg('alwardy headless are you really headless?') + + elif m in [px+'creepy', px+'creep']: + if n == []: + cmsg(f'use: {px}creepy all or {px}creepy number of list') + elif n[0] == 'all': + for i in activity_players: + body = i.actor.node + body.head_model = None + body.handlemessage(ba.PowerupMessage(poweruptype='punch')) + body.handlemessage(ba.PowerupMessage(poweruptype='shield')) + cmsg('dont creep out childs all will be scared') + else: + try: + body = activity_players[int(n[0])].actor.node + body.head_model = None + body.handlemessage(ba.PowerupMessage(poweruptype='punch')) + body.handlemessage(ba.PowerupMessage(poweruptype='shield')) + cmsg('dont creep out childs all will be scared') + except: + cmsg('could not found player to make') + + elif m in [px+'kill', px+'die']: + if n == []: + cmsg(f'Use : {px}kill all or {px}kill number of list') + elif n[0] == 'all': + for i in activity_players: + i.actor.node.handlemessage(ba.DieMessage()) + cmsg('Killed all') + else: + is_name = session_players[int(n[0])].getname() + activity_players[int(n[0])].actor.node.handlemessage(ba.DieMessage()) + cmsg('Killed '+is_name) + + elif m in [px+'heal', px+'heath']: + if n == []: + cmsg(f'Use: {px}heal all or {px}heal number of list') + elif n[0] == 'all': + for i in activity_players: + i.actor.node.handlemessage(ba.PowerupMessage(poweruptype='health')) + cmsg('Heald all') + else: + is_name = session_players[int(n[0])].getname() + activity_players[int(n[0])].actor.node.handlemessage( + ba.PowerupMessage(poweruptype='health')) + cmsg('Heald '+is_name) + + elif m in [px+'curse', px+'cur']: + if n == []: + cmsg(f'Use: {px}curse all or {px}curse number of list') + elif n[0] == 'all': + for i in activity_players: + i.actor.node.handlemessage(ba.PowerupMessage(poweruptype='curse')) + cmsg('Cursed all') + else: + is_name = session_players[int(n[0])].getname() + activity_players[int(n[0])].actor.node.handlemessage( + ba.PowerupMessage(poweruptype='curse')) + cmsg('Cursed '+is_name) + + elif m in [px+'sleep']: + if n == []: + cmsg(f'Use: {px}sleep all or {px}sleep number of list') + elif n[0] == 'all': + for i in activity_players: + i.actor.node.handlemessage('knockout', 8000) + cmsg('Sleep all its Night :)') + else: + is_name = session_players[int(n[0])].getname() + activity_players[int(n[0])].actor.node.handlemessage('knockout', 8000) + cmsg(is_name+' sleeped now') + + elif m in [px+'sp', px+'superpunch']: + if n == []: + cmsg(f'Use : {px}sp/superpunch all or {px}sp/superpunch number of list') + elif n[0] == 'all': + for i in activity_players: + if not i.actor._punch_power_scale == 15: + i.actor._punch_power_scale = 15 + i.actor._punch_cooldown = 0 + cmsg('Everyone enjoy your Super punches') + else: + i.actor._punch_power_scale = 1.2 + i.actor._punch_cooldown = 400 + cmsg('Super punches off now') + else: + try: + if not activity_players[int(n[0])].actor._punch_power_scale == 15: + is_name = session_players[int(n[0])].getname() + activity_players[int(n[0])].actor._punch_power_scale = 15 + activity_players[int(n[0])].actor._punch_cooldown = 0 + cmsg(is_name+' using super punches get away from him') + else: + activity_players[int(n[0])].actor._punch_power_scale = 1.2 + activity_players[int(n[0])].actor._punch_cooldown = 400 + cmsg(':( ') + except: + pass + + elif m in [px+'gloves', px+'punch']: + if n == []: + cmsg(f'Use: {px}gloves all or {px}gloves number of list') + elif n[0] == 'all': + for i in activity_players: + i.actor.node.handlemessage(ba.PowerupMessage(poweruptype='punch')) + cmsg('Free Gloves enjoy all') + else: + is_name = session_players[int(n[0])].getname() + activity_players[int(n[0])].actor.node.handlemessage( + ba.PowerupMessage(poweruptype='punch')) + cmsg(is_name+' using gloves') + + elif m in [px+'shield', px+'protect']: + if n == []: + cmsg(f'Use: {px}shield all or {px}shield number of list') + elif n[0] == 'all': + for i in activity_players: + i.actor.node.handlemessage(ba.PowerupMessage(poweruptype='shield')) + cmsg('Everyone enjoy free shield :)') + else: + is_name = session_players[int(n[0])].getname() + activity_players[int(n[0])].actor.node.handlemessage( + ba.PowerupMessage(poweruptype='shield')) + cmsg(is_name+' using shield') + + elif m in [px+'freeze', px+'ice']: + if n == []: + cmsg(f'Use: {px}freeze all or {px}freeze number of list') + elif n[0] == 'all': + for i in activity_players: + i.actor.node.handlemessage(ba.FreezeMessage()) + cmsg('Freezed all') + else: + is_name = session_players[int(n[0])].getname() + activity_players[int(n[0])].actor.node.handlemessage(ba.FreezeMessage()) + cmsg('Un freezed '+is_name) + + elif m in [px+'unfreeze', px+'thaw']: + if n == []: + cmsg(f'Use: {px}unfreeze/thaw all or {px}unfreeze/thaw number of list') + elif n[0] == 'all': + for i in activity_players: + i.actor.node.handlemessage(ba.ThawMessage()) + cmsg('Un freezed all ') + else: + is_name = session_players[int(n[0])].getname() + activity_players[int(n[0])].actor.node.handlemessage(ba.ThawMessage()) + cmsg('Un freezed '+is_name) + + elif m in [px+'fall']: + if n == []: + cmsg(f'Use: {px}fall all or {px}fall number of list') + elif n[0] == 'all': + for i in activity_players: + i.actor.node.handlemessage(ba.StandMessage()) + cmsg('Felt everyone') + else: + is_name = session_players[int(n[0])].getname() + activity_players[int(n[0])].actor.node.handlemessage(ba.StandMessage()) + cmsg(is_name+' got felt') + + elif m in [px+'celebrate', px+'celeb']: + if n == []: + cmsg(f'Use: {px}celebrate all or {px}celebrate number of list') + elif n[0] == 'all': + for i in activity_players: + i.actor.node.handlemessage(ba.CelebrateMessage()) + cmsg('Celebrate all :)') + else: + is_name = session_players[int(n[0])].getname() + activity_players[int(n[0])].actor.node.handlemessage(ba.CelebrateMessage()) + cmsg(is_name+' is celebrating bt why?') + + elif m in [px+'fly']: + if n == []: + cmsg(f'Use: {px}fly all or {px}fly number of list') + elif n[0] == 'all': + for i in activity_players: + if not i.actor.node.fly == True: + i.actor.node.fly = True + cmsg('fly all dont go out ok') + else: + i.actor.node.fly = False + cmsg('flying mode off') + else: + try: + is_name = session_players[int(n[0])].getname() + if not activity_players[int(n[0])].actor.node.fly == True: + activity_players[int(n[0])].actor.node.fly = True + cmsg(is_name+' is flying') + else: + activity_players[int(n[0])].actor.node.fly = False + cmsg('fly off :(') + except: + cmsg('player not found') + pass + + elif m in [px+'gm', px+'godmode']: + if n == []: + cmsg(f'Use: {px}gm all or {px}gm number of list') + elif n[0] == 'all': + for i in activity_players: + if not i.actor.node.hockey == True: + i.actor.node.hockey = True + i.actor.node.invincible = True + i.actor._punch_power_scale = 7 + cmsg('Gmed all ') + else: + i.actor.node.hockey = False + i.actor.node.invincible = False + i.actor._punch_power_scale = 1.2 + cmsg('Un gmed all') + else: + try: + is_name = session_players[int(n[0])].getname() + if not activity_players[int(n[0])].actor.node.hockey == True: + activity_players[int(n[0])].actor.node.hockey = True + activity_players[int(n[0])].actor.node.invincible = True + activity_players[int(n[0])].actor._punch_power_scale = 7 + cmsg('Gmed '+is_name) + else: + activity_players[int(n[0])].actor.node.hockey = False + activity_players[int(n[0])].actor.node.invincible = False + activity_players[int(n[0])].actor._punch_power_scale = 1.2 + cmsg('un gmed '+is_name) + except: + cmsg('could not found player') + elif m in [px+'d_bomb', px+'default_bomb']: + if n == []: + cmsg( + f'Use: {px}d_bomb/default_bomb all or {px}d_bomb number of list ,type {px}d_bomb help for help') + elif n[0] == 'help': + cmsg("bombtypes - ['ice', 'impact', 'land_mine', 'normal', 'sticky','tnt']") + elif n[0] in ['ice', 'impact', 'land_mine', 'normal', 'sticky', 'tnt']: + for i in activity_players: + i.actor.bomb_type = n[0] + cmsg('default bomb type - '+str(n[0])+' now') + else: + cmsg('unkwon bombtype , type {px}d_bomb help for help') + + elif m in [px+'d_bomb_count', px+'default_bomb_count', px+'dbc']: + if n == []: + cmsg( + f'Use: {px}d_bomb_count/default_bomb/dbc all or {px}d_bomb_count/default_bomb_count/dbc number of list') + else: + try: + for i in activity_players: + i.actor.set_bomb_count(int(n[0])) + cmsg('default bomb count is '+(str(n[0]))+' now') + except: + cmsg('Must use number to use') + elif m in [px+'credits']: + if n == []: + cmsg(u'\U0001F95A created by Nazz \U0001F95A') + cmsg(u'\U0001F95A Nazz are past/present/future \U0001F95A') + cmsg(u'\U0001F95A everything is Nazz \U0001F95A') # ba.timer(0.05, _update, repeat=True) def same(): - ba.timer(0.5, _cmds._process_cmd, True) + ba.timer(0.5, _cmds._process_cmd, True) # ba_meta export plugin + + class _enableee(ba.Plugin): - same() \ No newline at end of file + same() From 2d294591775e793d537c099651e0dc2ce4013890 Mon Sep 17 00:00:00 2001 From: Loup <90267658+Loup-Garou911XD@users.noreply.github.com> Date: Thu, 3 Nov 2022 22:41:35 +0530 Subject: [PATCH 0205/1464] Added CustomDeath, MaxPlayers, QuickCustomgame, randomColors, and chat_cmd --- plugins/utilities.json | 77 +++++++++++++++++++++++++++++++++++++++++- 1 file changed, 76 insertions(+), 1 deletion(-) diff --git a/plugins/utilities.json b/plugins/utilities.json index d3c9ac14..f62619e6 100644 --- a/plugins/utilities.json +++ b/plugins/utilities.json @@ -3,6 +3,81 @@ "description": "Utilities", "plugins_base_url": "http://github.com/bombsquad-community/plugin-manager/{content_type}/{tag}/plugins/utilities", "plugins": { + "CustomDeath": { + "description": "Characters turn to Bones after death", + "external_url": "https://youtube.com/c/JoseANG3LYT", + "authors": [ + { + "name": "JoseAng3l", + "email": null, + "discord": "! JoseANG3L#0268" + } + ], + "versions": { + "1.0.0": null + } + }, + "MaxPlayers": { + "description": "Increase the max player limit of 8 players", + "external_url": "https://youtube.com/c/JoseANG3LYT", + "authors": [ + { + "name": "JoseAng3l", + "email": null, + "discord": "! JoseANG3L#0268" + } + ], + "versions": { + "1.0.0": null + } + }, + "QuickCustomGame": { + "description": "Quckly create a custom game with any gamemode", + "external_url": "https://youtube.com/c/JoseANG3LYT", + "authors": [ + { + "name": "JoseAng3l", + "email": null, + "discord": "! JoseANG3L#0268" + } + ], + "versions": { + "1.0.0": null + } + }, + "RandomColors": { + "description": "Creates patches of random color after bomb explosions", + "external_url": "https://youtube.com/c/JoseANG3LYT", + "authors": [ + { + "name": "JoseAng3l", + "email": null, + "discord": "! JoseANG3L#0268" + } + ], + "versions": { + "1.0.0": null + } + }, + "chat_cmd": { + "description": "chatcmd for a beutiful game - BombSquad OwO,type /help in chat for more info", + "external_url": "", + "authors": [ + { + "name": "IM_NOT_PRANAV#7874", + "email": null, + "discord": "IM_NOT_PRANAV#7874" + }, + { + "name": "FireFighter1037 ", + "email": null, + "discord": null + } + ], + "versions": { + "1.0.0": null + } + }, "mood_light": { "description": "Dynamic lighting in co-op games (adjustable using \"ml\" chat command)", "external_url": "", @@ -304,4 +379,4 @@ } } } -} \ No newline at end of file +} From d513809ad3742a33e7c0a720571f2f50cacf5bf6 Mon Sep 17 00:00:00 2001 From: Loup <90267658+Loup-Garou911XD@users.noreply.github.com> Date: Thu, 3 Nov 2022 22:59:16 +0530 Subject: [PATCH 0206/1464] Add files via upload --- plugins/minigames/BasketBomb.py | 754 ++++++++++++++++++++++++ plugins/minigames/Boxing.py | 240 ++++++++ plugins/minigames/MeteorShower.py | 406 +++++++++++++ plugins/minigames/SimonSays.py | 333 +++++++++++ plugins/minigames/SquidRace.py | 949 ++++++++++++++++++++++++++++++ plugins/minigames/ZombieHorde.py | 878 +++++++++++++++++++++++++++ 6 files changed, 3560 insertions(+) create mode 100644 plugins/minigames/BasketBomb.py create mode 100644 plugins/minigames/Boxing.py create mode 100644 plugins/minigames/MeteorShower.py create mode 100644 plugins/minigames/SimonSays.py create mode 100644 plugins/minigames/SquidRace.py create mode 100644 plugins/minigames/ZombieHorde.py diff --git a/plugins/minigames/BasketBomb.py b/plugins/minigames/BasketBomb.py new file mode 100644 index 00000000..c9030e5a --- /dev/null +++ b/plugins/minigames/BasketBomb.py @@ -0,0 +1,754 @@ +# Released under the MIT License. See LICENSE for details. +# ba_meta require api 7 +# (see https://ballistica.net/wiki/meta-tag-system) + +from __future__ import annotations + +from typing import TYPE_CHECKING + +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 bastd.actor import playerspaz as ps +from bastd import maps + +if TYPE_CHECKING: + from typing import Any, Sequence, Dict, Type, List, Optional, Union + +bsuSpaz = None + +def getlanguage(text, sub: str = ''): + lang = _ba.app.lang.language + translate = { + "Name": + {"Spanish": "Baloncesto", + "English": "Basketbomb", + "Portuguese": "Basketbomb"}, + "Info": + {"Spanish": "Anota todas las canastas y sé el MVP.", + "English": "Score all the baskets and be the MVP.", + "Portuguese": "Marque cada cesta e seja o MVP."}, + "Info-Short": + {"Spanish": f"Anota {sub} canasta(s) para ganar", + "English": f"Score {sub} baskets to win", + "Portuguese": f"Cestas de {sub} pontos para ganhar"}, + "S: Powerups": + {"Spanish": "Aparecer Potenciadores", + "English": "Powerups Spawn", + "Portuguese": "Habilitar Potenciadores"}, + "S: Velocity": + {"Spanish": "Activar velocidad", + "English": "Enable speed", + "Portuguese": "Ativar velocidade"}, + } + + languages = ['Spanish','Portuguese','English'] + if lang not in languages: lang = 'English' + + if text not in translate: + return text + return translate[text][lang] + +class BallDiedMessage: + def __init__(self, ball: Ball): + self.ball = ball + +class Ball(ba.Actor): + def __init__(self, position: Sequence[float] = (0.0, 1.0, 0.0)): + super().__init__() + shared = SharedObjects.get() + activity = self.getactivity() + velocty = (0.0, 8.0, 0.0) + _scale = 1.2 + + self._spawn_pos = (position[0], position[1] + 0.5, position[2]) + self.last_players_to_touch: Dict[int, Player] = {} + self.scored = False + + assert activity is not None + assert isinstance(activity, BasketGame) + + 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': 'sphere', + 'reflection': 'soft', + 'body_scale': 1.0 * _scale, + 'reflection_scale': [1.3], + 'shadow_size': 1.0, + 'gravity_scale': 0.92, + 'density': max(0.4 * _scale, 0.3), + 'position': self._spawn_pos, + 'velocity': velocty, + 'materials': pmats}) + self.scale = scale = 0.25 * _scale + ba.animate(self.node, 'model_scale', {0: 0, 0.2: scale*1.3, 0.26: scale}) + + def handlemessage(self, msg: Any) -> Any: + if isinstance(msg, ba.DieMessage): + assert self.node + self.node.delete() + activity = self._activity() + if activity and not msg.immediate: + activity.handlemessage(BallDiedMessage(self)) + + elif isinstance(msg, ba.OutOfBoundsMessage): + assert self.node + self.node.position = self._spawn_pos + self.node.velocity = (0.0, 0.0, 0.0) + + 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]) + + 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 + else: + 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 + +class Points: + postes = dict() + postes['pal_0'] = (10.64702320098877, 0.0000000000000000, 0.0000000000000000) #10.736066818237305, 0.3002409040927887, 0.5281256437301636 + postes['pal_1'] = (-10.64702320098877, 0.0000000000000000, 0.0000000000000000) + +# ba_meta export game +class BasketGame(ba.TeamGameActivity[Player, Team]): + + name = getlanguage('Name') + description = getlanguage('Info') + available_settings = [ + ba.IntSetting( + 'Score to Win', + min_value=1, + default=1, + 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', 4.0), + ], + default=1.0, + ), + ba.BoolSetting(getlanguage('S: Powerups'), default=True), + ba.BoolSetting(getlanguage('S: Velocity'), default=False), + ba.BoolSetting('Epic Mode', 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 ['BasketBall Stadium', 'BasketBall Stadium V2'] + + def __init__(self, settings: dict): + super().__init__(settings) + 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('shield') + self.ball_tex = ba.gettexture('fontExtras3') + self._ball_sound = ba.getsound('bunnyJump') + self._powerups = bool(settings[getlanguage('S: Powerups')]) + self._speed = bool(settings[getlanguage('S: Velocity')]) + self._epic_mode = bool(settings['Epic Mode']) + 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, 5)) + + # 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), )) + + 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._ball_spawn_pos: Optional[Sequence[float]] = None + self._score_regions: Optional[List[ba.NodeActor]] = 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]: + return getlanguage('Info-Short', sub=self._score_to_win) + + def get_instance_description_short(self) -> Union[str, Sequence]: + return getlanguage('Info-Short', sub=self._score_to_win) + + def on_begin(self) -> None: + super().on_begin() + + self.setup_standard_time_limit(self._time_limit) + + if self._powerups: + self.setup_standard_powerup_drops() + + self._ball_spawn_pos = self.map.get_flag_position(None) + self._spawn_ball() + + defs = self.map.defs + self._score_regions = [] + self._score_regions.append( + ba.NodeActor( + ba.newnode('region', + attrs={ + 'position': defs.boxes['goal1'][0:3], + 'scale': defs.boxes['goal1'][6:9], + 'type': 'box', + 'materials': [] + }))) + self._score_regions.append( + ba.NodeActor( + ba.newnode('region', + attrs={ + 'position': defs.boxes['goal2'][0:3], + 'scale': defs.boxes['goal2'][6:9], + 'type': 'box', + 'materials': [] + }))) + self._update_scoreboard() + ba.playsound(self._chant_sound) + + for id, team in enumerate(self.teams): + self.postes(id) + + 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 _handle_score(self, team_index: int = None) -> None: + assert self._ball is not None + assert self._score_regions is not None + + if self._ball.scored: + return + + region = ba.getcollision().sourcenode + index = 0 + for index in range(len(self._score_regions)): + if region == self._score_regions[index].node: + break + + if team_index is not None: + index = team_index + + for team in self.teams: + if team.id == index: + scoring_team = team + team.score += 1 + + for player in team.players: + if player.actor: + player.actor.handlemessage(ba.CelebrateMessage(2.0)) + + 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) + + if team.score >= self._score_to_win: + self.end_game() + + #ba.playsound(self._foghorn_sound) + ba.playsound(self._cheer_sound) + + self._ball.scored = True + + # Kill the ball (it'll respawn itself shortly). + ba.timer(1.0, self._kill_ball) + + light = ba.newnode('light', + attrs={ + 'position': ba.getcollision().position, + 'height_attenuated': False, + 'color': (1, 0, 0) + }) + ba.animate(light, 'intensity', {0: 0, 0.5: 1, 1.0: 0}, loop=True) + ba.timer(1.0, light.delete) + + 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 id, team in enumerate(self.teams): + self._scoreboard.set_team_value(team, team.score, winscore) + #self.postes(id) + + def spawn_player(self, player: Player) -> ba.Actor: + if bsuSpaz is None: + spaz = self.spawn_player_spaz(player) + else: + ps.PlayerSpaz = bsuSpaz.BskSpaz + spaz = self.spawn_player_spaz(player) + ps.PlayerSpaz = bsuSpaz.OldPlayerSpaz + + if self._speed: + spaz.node.hockey = True + return spaz + + def handlemessage(self, msg: Any) -> Any: + if isinstance(msg, ba.PlayerDiedMessage): + super().handlemessage(msg) + self.respawn_player(msg.getplayer(Player)) + elif isinstance(msg, BallDiedMessage): + if not self.has_ended(): + ba.timer(3.0, self._spawn_ball) + else: + super().handlemessage(msg) + + def postes(self, team_id: int): + if not hasattr(self._map, 'poste_'+str(team_id)): + setattr(self._map, 'poste_'+str(team_id), + Palos(team=team_id, + position=Points.postes['pal_' + + str(team_id)]).autoretain()) + + def _flash_ball_spawn(self) -> None: + light = ba.newnode('light', + attrs={ + 'position': self._ball_spawn_pos, + 'height_attenuated': False, + 'color': (1, 0, 0) + }) + ba.animate(light, 'intensity', {0.0: 0, 0.25: 1, 0.5: 0}, loop=True) + ba.timer(1.0, light.delete) + + def _spawn_ball(self) -> None: + ba.playsound(self._swipsound) + ba.playsound(self._whistle_sound) + self._flash_ball_spawn() + assert self._ball_spawn_pos is not None + self._ball = Ball(position=self._ball_spawn_pos) + +class Aro(ba.Actor): + def __init__(self, team: int = 0, + position: Sequence[float] = (0.0, 1.0, 0.0)): + super().__init__() + act = self.getactivity() + shared = SharedObjects.get() + setattr(self, 'team', team) + setattr(self, 'locs', []) + + # Material Para; Traspasar Objetos + self.no_collision = ba.Material() + self.no_collision.add_actions( + actions=(('modify_part_collision', 'collide', False))) + + self.collision = ba.Material() + self.collision.add_actions( + actions=(('modify_part_collision', 'collide', True))) + + # Score + self._score_region_material = ba.Material() + self._score_region_material.add_actions( + conditions=('they_have_material', act.ball_material), + actions=(('modify_part_collision', 'collide', + True), ('modify_part_collision', 'physical', False), + ('call', 'at_connect', self._annotation))) + + self._spawn_pos = (position[0], position[1], position[2]) + self._materials_region0 = [self.collision, + shared.footing_material] + + model = None + tex = ba.gettexture('null') + + pmats = [self.no_collision] + self.node = ba.newnode('prop', + delegate=self, + attrs={ + 'model': model, + 'color_texture': tex, + 'body': 'box', + 'reflection': 'soft', + 'reflection_scale': [1.5], + 'shadow_size': 0.1, + 'position': self._spawn_pos, + 'materials': pmats}) + + self.scale = scale = 1.4 + ba.animate(self.node, 'model_scale', {0: 0}) + + pos = (position[0], position[1]+0.6, position[2]) + self.regions: List[ba.Node] = [ + ba.newnode('region', + attrs={'position': position, + 'scale': (0.6, 0.05, 0.6), + 'type': 'box', + 'materials': self._materials_region0}), + + ba.newnode('region', + attrs={'position': pos, + 'scale': (0.5, 0.3, 0.9), + 'type': 'box', + 'materials': [self._score_region_material]}) + ] + self.regions[0].connectattr('position', self.node, 'position') + #self.regions[0].connectattr('position', self.regions[1], 'position') + + locs_count = 9 + pos = list(position) + + try: + id = 0 if team == 1 else 1 + color = act.teams[id].color + except: color = (1,1,1) + + while locs_count > 1: + scale = (1.5 * 0.1 * locs_count) + 0.8 + + self.locs.append(ba.newnode('locator', + owner=self.node, + attrs={'shape': 'circleOutline', + 'position': pos, + 'color': color, + 'opacity': 1.0, + 'size': [scale], + 'draw_beauty': True, + 'additive': False})) + + pos[1] -= 0.1 + locs_count -= 1 + + def _annotation(self): + assert len(self.regions) >= 2 + ball = self.getactivity()._ball + + if ball: + p = self.regions[0].position + ball.node.position = p + ball.node.velocity = (0.0, 0.0, 0.0) + + act = self.getactivity() + act._handle_score(self.team) + + def handlemessage(self, msg: Any) -> Any: + if isinstance(msg, ba.DieMessage): + if self.node.exists(): + self.node.delete() + else: + super().handlemessage(msg) + +class Cuadro(ba.Actor): + def __init__(self, team: int = 0, + position: Sequence[float] = (0.0, 1.0, 0.0)): + super().__init__() + act = self.getactivity() + shared = SharedObjects.get() + setattr(self, 'locs', []) + + self.collision = ba.Material() + self.collision.add_actions( + actions=(('modify_part_collision', 'collide', True))) + + pos = (position[0], position[1]+0.9, position[2]+1.5) + self.region: ba.Node = ba.newnode('region', + attrs={'position': pos, + 'scale': (0.5, 2.7, 2.5), + 'type': 'box', + 'materials': [self.collision, + shared.footing_material]}) + + #self.shield = ba.newnode('shield', attrs={'radius': 1.0, 'color': (0,10,0)}) + #self.region.connectattr('position', self.shield, 'position') + + position = (position[0], position[1], position[2]+0.09) + pos = list(position) + oldpos = list(position) + old_count = 14 + + count = old_count + count_y = 9 + + try: + id = 0 if team == 1 else 1 + color = act.teams[id].color + except: color = (1,1,1) + + while(count_y != 1): + + while(count != 1): + pos[2] += 0.19 + + self.locs.append( + ba.newnode('locator', + owner=self.region, + attrs={'shape': 'circle', + 'position': pos, + 'size': [0.5], + 'color': color, + 'opacity': 1.0, + 'draw_beauty': True, + 'additive': False})) + count -= 1 + + + count = old_count + pos[1] += 0.2 + pos[2] = oldpos[2] + count_y -= 1 + + def handlemessage(self, msg: Any) -> Any: + if isinstance(msg, ba.DieMessage): + if self.node.exists(): + self.node.delete() + else: + super().handlemessage(msg) + +class Palos(ba.Actor): + def __init__(self, team: int = 0, + position: Sequence[float] = (0.0, 1.0, 0.0)): + super().__init__() + shared = SharedObjects.get() + activity = self.getactivity() + self._pos = position + self.aro = None + self.cua = None + + # Material Para; Traspasar Objetos + self.no_collision = ba.Material() + self.no_collision.add_actions( + actions=(('modify_part_collision', 'collide', False))) + + # + self.collision = ba.Material() + self.collision.add_actions( + actions=(('modify_part_collision', 'collide', True))) + + # Spawn just above the provided point. + self._spawn_pos = (position[0], position[2]+2.5, position[2]) + + model = ba.getmodel('flagPole') + tex = ba.gettexture('flagPoleColor') + + pmats = [self.no_collision] + self.node = ba.newnode('prop', + delegate=self, + attrs={ + 'model': model, + 'color_texture': tex, + 'body': 'puck', + 'reflection': 'soft', + 'reflection_scale': [2.6], + 'shadow_size': 0, + 'is_area_of_interest': True, + 'position': self._spawn_pos, + 'materials': pmats + }) + self.scale = scale = 4.0 + ba.animate(self.node, 'model_scale', {0: scale}) + + self.loc = ba.newnode('locator', + owner=self.node, + attrs={'shape': 'circle', + 'position': position, + 'color': (1,1,0), + 'opacity': 1.0, + 'draw_beauty': False, + 'additive': True}) + + self._y = _y = 0.30 + _x = -0.25 if team == 1 else 0.25 + _pos = (position[0]+_x, position[1]-1.5 + _y, position[2]) + self.region = ba.newnode('region', + attrs={ + 'position': _pos, + 'scale': (0.4, 8, 0.4), + 'type': 'box', + 'materials': [self.collision]}) + self.region.connectattr('position', self.node, 'position') + + _y = self._y + position = self._pos + if team == 0: + pos = (position[0]-0.8, position[1] + 2.0 + _y, position[2]) + else: pos = (position[0]+0.8, position[1] + 2.0 + _y, position[2]) + + if self.aro is None: + self.aro = Aro(team, pos).autoretain() + + if self.cua is None: + pos = (position[0], position[1] + 1.8 + _y, position[2]-1.4) + self.cua = Cuadro(team, pos).autoretain() + + def handlemessage(self, msg: Any) -> Any: + if isinstance(msg, ba.DieMessage): + if self.node.exists(): + self.node.delete() + else: + super().handlemessage(msg) + +class BasketMap(maps.FootballStadium): + name = 'BasketBall Stadium' + + @classmethod + def get_play_types(cls) -> List[str]: + """Return valid play types for this map.""" + return [] + + def __init__(self) -> None: + super().__init__() + + gnode = ba.getactivity().globalsnode + gnode.tint = [(0.806, 0.8, 1.0476), (1.3, 1.2, 1.0)][0] + gnode.ambient_color = (1.3, 1.2, 1.0) + gnode.vignette_outer = (0.57, 0.57, 0.57) + gnode.vignette_inner = (0.9, 0.9, 0.9) + gnode.vr_camera_offset = (0, -0.8, -1.1) + gnode.vr_near_clip = 0.5 + +class BasketMapV2(maps.HockeyStadium): + name = 'BasketBall Stadium V2' + + def __init__(self) -> None: + super().__init__() + + shared = SharedObjects.get() + self.node.materials = [shared.footing_material] + self.node.collide_model = ba.getcollidemodel('footballStadiumCollide') + self.node.model = None + self.stands.model = None + self.floor.reflection = 'soft' + self.floor.reflection_scale = [1.6] + self.floor.color = (1.1, 0.05, 0.8) + + self.background = ba.newnode('terrain', + attrs={'model': ba.getmodel('thePadBG'), + 'lighting': False, + 'background': True, + 'color': (1.0, 0.2, 1.0), + 'color_texture': ba.gettexture('menuBG')}) + + gnode = ba.getactivity().globalsnode + gnode.floor_reflection = True + gnode.debris_friction = 0.3 + gnode.debris_kill_height = -0.3 + gnode.tint = [(1.2, 1.3, 1.33), (0.7, 0.9, 1.0)][1] + gnode.ambient_color = (1.15, 1.25, 1.6) + gnode.vignette_outer = (0.66, 0.67, 0.73) + gnode.vignette_inner = (0.93, 0.93, 0.95) + gnode.vr_camera_offset = (0, -0.8, -1.1) + gnode.vr_near_clip = 0.5 + self.is_hockey = False + + ################## + self.collision = ba.Material() + self.collision.add_actions( + actions=(('modify_part_collision', 'collide', True))) + + self.regions: List[ba.Node] = [ + ba.newnode('region', + attrs={'position': (12.676897048950195, 0.2997918128967285, 5.583303928375244), + 'scale': (1.01, 12, 28), + 'type': 'box', + 'materials': [self.collision]}), + + ba.newnode('region', + attrs={'position': (11.871315956115723, 0.29975247383117676, 5.711406707763672), + 'scale': (50, 12, 0.9), + 'type': 'box', + 'materials': [self.collision]}), + + ba.newnode('region', + attrs={'position': (-12.776557922363281, 0.30036890506744385, 4.96237850189209), + 'scale': (1.01, 12, 28), + 'type': 'box', + 'materials': [self.collision]}), + ] + +ba._map.register_map(BasketMap) +ba._map.register_map(BasketMapV2) \ No newline at end of file diff --git a/plugins/minigames/Boxing.py b/plugins/minigames/Boxing.py new file mode 100644 index 00000000..0a6a4b21 --- /dev/null +++ b/plugins/minigames/Boxing.py @@ -0,0 +1,240 @@ +# ba_meta require api 7 +# (see https://ballistica.net/wiki/meta-tag-system) + +from __future__ import annotations + +from typing import TYPE_CHECKING + +import ba +from bastd.actor.playerspaz import PlayerSpaz +from bastd.actor.scoreboard import Scoreboard +from bastd.game.deathmatch import DeathMatchGame + +if TYPE_CHECKING: + from typing import Any, Sequence + + +lang = ba.app.lang.language + +if lang == 'Spanish': + name = 'Super Boxeo' + description = ('¡Sin bombas!\n' + '¡Noquea a los enemigos con tus propias manos!\n') + super_jump_text = 'Super Salto' + enable_powerups = 'Habilitar Potenciadores' +else: + name = 'Super Boxing' + description = ('No bombs!\n' + 'Knock out your enemies using your bare hands!\n') + super_jump_text = 'Super Jump' + enable_powerups = 'Enable Powerups' + + +class NewPlayerSpaz(PlayerSpaz): + + def __init__(self, + player: ba.Player, + color: Sequence[float] = (1.0, 1.0, 1.0), + highlight: Sequence[float] = (0.5, 0.5, 0.5), + character: str = 'Spaz', + powerups_expire: bool = True, + super_jump: bool = False): + super().__init__(player=player, + color=color, + highlight=highlight, + character=character, + powerups_expire=powerups_expire) + from bastd.gameutils import SharedObjects + shared = SharedObjects.get() + self._super_jump = super_jump + self.jump_mode = False + self.super_jump_material = ba.Material() + self.super_jump_material.add_actions( + conditions=('they_have_material', shared.footing_material), + actions=( + ('call', 'at_connect', ba.Call(self.jump_state, True)), + ('call', 'at_disconnect', ba.Call(self.jump_state, False)) + ), + ) + self.node.roller_materials += (self.super_jump_material, ) + + def jump_state(self, mode: bool) -> None: + self.jump_mode = mode + + def on_jump_press(self) -> None: + """ + Called to 'press jump' on this spaz; + used by player or AI connections. + """ + if not self.node: + return + t_ms = ba.time(timeformat=ba.TimeFormat.MILLISECONDS) + assert isinstance(t_ms, int) + if t_ms - self.last_jump_time_ms >= self._jump_cooldown: + self.node.jump_pressed = True + self.last_jump_time_ms = t_ms + if self._player.is_alive() and self.jump_mode and ( + self._super_jump): + def do_jump(): + self.node.handlemessage( + 'impulse', + self.node.position[0], + self.node.position[1], + self.node.position[2], + 0, 0, 0, 150, 150, 0, 0, 0, 1, 0 + ) + ba.timer(0.0, do_jump) + ba.timer(0.1, do_jump) + ba.timer(0.2, do_jump) + self._turbo_filter_add_press('jump') + + +# ba_meta export game +class BoxingGame(DeathMatchGame): + + name = name + description = description + + @classmethod + def get_available_settings( + cls, sessiontype: type[ba.Session] + ) -> list[ba.Setting]: + settings = [ + ba.IntSetting( + 'Kills to Win Per Player', + 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', 4.0), + ], + default=1.0, + ), + ba.BoolSetting(super_jump_text, default=False), + ba.BoolSetting(enable_powerups, default=False), + ba.BoolSetting('Epic Mode', default=False), + ] + + # In teams mode, a suicide gives a point to the other team, but in + # free-for-all it subtracts from your own score. By default we clamp + # this at zero to benefit new players, but pro players might like to + # be able to go negative. (to avoid a strategy of just + # suiciding until you get a good drop) + if issubclass(sessiontype, ba.FreeForAllSession): + settings.append( + ba.BoolSetting('Allow Negative Scores', default=False) + ) + + return settings + + def __init__(self, settings: dict): + super().__init__(settings) + self._scoreboard = Scoreboard() + self._score_to_win: int | None = None + self._dingsound = ba.getsound('dingSmall') + self._epic_mode = bool(settings['Epic Mode']) + self._kills_to_win_per_player = int(settings['Kills to Win Per Player']) + self._time_limit = float(settings['Time Limit']) + self._allow_negative_scores = bool( + settings.get('Allow Negative Scores', False) + ) + self._super_jump = bool(settings[super_jump_text]) + self._enable_powerups = bool(settings[enable_powerups]) + + # Base class overrides. + self.slow_motion = self._epic_mode + self.default_music = ( + ba.MusicType.EPIC if self._epic_mode else ba.MusicType.TO_THE_DEATH + ) + + def on_begin(self) -> None: + ba.TeamGameActivity.on_begin(self) + self.setup_standard_time_limit(self._time_limit) + if self._enable_powerups: + self.setup_standard_powerup_drops() + + # Base kills needed to win on the size of the largest team. + self._score_to_win = self._kills_to_win_per_player * max( + 1, max(len(t.players) for t in self.teams) + ) + self._update_scoreboard() + + def _standard_drop_powerup(self, index: int, expire: bool = True) -> None: + # pylint: disable=cyclic-import + from bastd.actor.powerupbox import PowerupBox, PowerupBoxFactory + + PowerupBox( + position=self.map.powerup_spawn_points[index], + poweruptype=PowerupBoxFactory.get().get_random_powerup_type( + excludetypes=['triple_bombs','ice_bombs','impact_bombs', + 'land_mines','sticky_bombs','punch'] + ), + expire=expire, + ).autoretain() + + def spawn_player(self, player: Player) -> ba.Actor: + import random + from ba import _math + from ba._gameutils import animate + from ba._coopsession import CoopSession + + if isinstance(self.session, ba.DualTeamSession): + position = self.map.get_start_position(player.team.id) + else: + # otherwise do free-for-all spawn locations + position = self.map.get_ffa_start_position(self.players) + angle = None + name = player.getname() + color = player.color + highlight = player.highlight + + light_color = _math.normalized_color(color) + display_color = ba.safecolor(color, target_intensity=0.75) + + spaz = NewPlayerSpaz(color=color, + highlight=highlight, + character=player.character, + player=player, + super_jump=self._super_jump) + + player.actor = spaz + assert spaz.node + + spaz.node.name = name + spaz.node.name_color = display_color + + # Move to the stand position and add a flash of light. + spaz.handlemessage( + ba.StandMessage( + position, + angle if angle is not None else random.uniform(0, 360))) + ba.playsound(self._spawn_sound, 1, position=spaz.node.position) + light = ba.newnode('light', attrs={'color': light_color}) + spaz.node.connectattr('position', light, 'position') + animate(light, 'intensity', {0: 0, 0.25: 1, 0.5: 0}) + ba.timer(0.5, light.delete) + + # custom + spaz.connect_controls_to_player(enable_bomb=False) + spaz.equip_boxing_gloves() + + return spaz diff --git a/plugins/minigames/MeteorShower.py b/plugins/minigames/MeteorShower.py new file mode 100644 index 00000000..149f2a91 --- /dev/null +++ b/plugins/minigames/MeteorShower.py @@ -0,0 +1,406 @@ +# ba_meta require api 7 +# (see https://ballistica.net/wiki/meta-tag-system) + +from __future__ import annotations + +import random +from typing import TYPE_CHECKING + +import ba +from bastd.actor.bomb import Bomb +from bastd.actor.onscreentimer import OnScreenTimer + +if TYPE_CHECKING: + from typing import Any, Sequence + + +lang = ba.app.lang.language + +if lang == 'Spanish': + name = 'Lluvia de Meteoritos v2' + bomb_type = 'Tipo de Bomba' + ice = 'hielo' + sticky = 'pegajosa' + impact = 'insta-bomba' + land_mine = 'mina terrestre' + random_bomb = 'aleatoria' + normal_rain = 'Lluvia Normal' + frozen_rain = 'Lluvia Congelada' + sticky_rain = 'Lluvia Pegajosa' + impact_rain = 'Lluvia de Impacto' + mine_rain = 'Lluvia de Minas' + tnt_rain = 'Lluvia de TNT' + random_rain = 'Lluvia Aleatoria' +else: + name = 'Meteor Shower v2' + bomb_type = 'Bomb Type' + ice = 'ice' + sticky = 'sticky' + impact = 'impact' + land_mine = 'land mine' + random_bomb = 'random' + normal_rain = 'Normal Rain' + frozen_rain = 'Frozen Rain' + sticky_rain = 'Sticky Rain' + impact_rain = 'Impact Rain' + mine_rain = 'Mine Rain' + tnt_rain = 'TNT Rain' + random_rain = 'Random Rain' + + +class Player(ba.Player['Team']): + """Our player type for this game.""" + + def __init__(self) -> None: + super().__init__() + self.death_time: float | None = None + + +class Team(ba.Team[Player]): + """Our team type for this game.""" + + +# ba_meta export game +class MeteorShowerv2Game(ba.TeamGameActivity[Player, Team]): + """Minigame involving dodging falling bombs.""" + + name = name + description = 'Dodge the falling bombs.' + scoreconfig = ba.ScoreConfig( + label='Survived', scoretype=ba.ScoreType.MILLISECONDS, version='B' + ) + + # Print messages when players die (since its meaningful in this game). + announce_player_deaths = True + + # Don't allow joining after we start + # (would enable leave/rejoin tomfoolery). + allow_mid_activity_joins = False + + @classmethod + def get_available_settings( + cls, sessiontype: type[ba.Session] + ) -> list[ba.Setting]: + settings = [ + ba.IntChoiceSetting( + bomb_type, + choices=[ + ('normal', 0), + (ice, 1), + (sticky, 2), + (impact, 3), + (land_mine, 4), + ('tnt', 5), + (random_bomb, 6) + ], + default=0, + ), + ba.BoolSetting('Epic Mode', default=False), + ] + return settings + + # We're currently hard-coded for one map. + @classmethod + def get_supported_maps(cls, sessiontype: type[ba.Session]) -> list[str]: + return ['Rampage'] + + # We support teams, free-for-all, and co-op sessions. + @classmethod + def supports_session_type(cls, sessiontype: type[ba.Session]) -> bool: + return ( + issubclass(sessiontype, ba.DualTeamSession) + or issubclass(sessiontype, ba.FreeForAllSession) + or issubclass(sessiontype, ba.CoopSession) + ) + + def __init__(self, settings: dict): + super().__init__(settings) + btype = int(settings[bomb_type]) + if btype == 0: + newbtype = 'normal' + elif btype == 1: + newbtype = 'ice' + elif btype == 2: + newbtype = 'sticky' + elif btype == 3: + newbtype = 'impact' + elif btype == 4: + newbtype = 'land_mine' + elif btype == 5: + newbtype = 'tnt' + else: + newbtype = 'random' + self._bomb_type = newbtype + self._epic_mode = settings.get('Epic Mode', False) + self._last_player_death_time: float | None = None + self._meteor_time = 2.0 + self._timer: OnScreenTimer | None = None + + # Some base class overrides: + self.default_music = ( + ba.MusicType.EPIC if self._epic_mode else ba.MusicType.SURVIVAL + ) + if self._epic_mode: + self.slow_motion = True + + def on_begin(self) -> None: + super().on_begin() + + # Drop a wave every few seconds.. and every so often drop the time + # between waves ..lets have things increase faster if we have fewer + # players. + delay = 5.0 if len(self.players) > 2 else 2.5 + if self._epic_mode: + delay *= 0.25 + ba.timer(delay, self._decrement_meteor_time, repeat=True) + + # Kick off the first wave in a few seconds. + delay = 3.0 + if self._epic_mode: + delay *= 0.25 + ba.timer(delay, self._set_meteor_timer) + + self._timer = OnScreenTimer() + self._timer.start() + + # Check for immediate end (if we've only got 1 player, etc). + ba.timer(5.0, self._check_end_game) + + def on_player_leave(self, player: Player) -> None: + # Augment default behavior. + super().on_player_leave(player) + + # A departing player may trigger game-over. + self._check_end_game() + + # overriding the default character spawning.. + def spawn_player(self, player: Player) -> ba.Actor: + spaz = self.spawn_player_spaz(player) + + # Let's reconnect this player's controls to this + # spaz but *without* the ability to attack or pick stuff up. + spaz.connect_controls_to_player( + enable_punch=False, enable_bomb=False, enable_pickup=False + ) + + # Also lets have them make some noise when they die. + spaz.play_big_death_sound = True + return spaz + + # Various high-level game events come through this method. + def handlemessage(self, msg: Any) -> Any: + if isinstance(msg, ba.PlayerDiedMessage): + + # Augment standard behavior. + super().handlemessage(msg) + + curtime = ba.time() + + # Record the player's moment of death. + # assert isinstance(msg.spaz.player + msg.getplayer(Player).death_time = curtime + + # In co-op mode, end the game the instant everyone dies + # (more accurate looking). + # In teams/ffa, allow a one-second fudge-factor so we can + # get more draws if players die basically at the same time. + if isinstance(self.session, ba.CoopSession): + # Teams will still show up if we check now.. check in + # the next cycle. + ba.pushcall(self._check_end_game) + + # Also record this for a final setting of the clock. + self._last_player_death_time = curtime + else: + ba.timer(1.0, self._check_end_game) + + else: + # Default handler: + return super().handlemessage(msg) + return None + + def _check_end_game(self) -> None: + living_team_count = 0 + for team in self.teams: + for player in team.players: + if player.is_alive(): + living_team_count += 1 + break + + # In co-op, we go till everyone is dead.. otherwise we go + # until one team remains. + if isinstance(self.session, ba.CoopSession): + if living_team_count <= 0: + self.end_game() + else: + if living_team_count <= 1: + self.end_game() + + def _set_meteor_timer(self) -> None: + ba.timer( + (1.0 + 0.2 * random.random()) * self._meteor_time, + self._drop_bomb_cluster, + ) + + def _drop_bomb_cluster(self) -> None: + + # Random note: code like this is a handy way to plot out extents + # and debug things. + loc_test = False + if loc_test: + ba.newnode('locator', attrs={'position': (8, 6, -5.5)}) + ba.newnode('locator', attrs={'position': (8, 6, -2.3)}) + ba.newnode('locator', attrs={'position': (-7.3, 6, -5.5)}) + ba.newnode('locator', attrs={'position': (-7.3, 6, -2.3)}) + + # Drop several bombs in series. + delay = 0.0 + for _i in range(random.randrange(1, 3)): + # Drop them somewhere within our bounds with velocity pointing + # toward the opposite side. + pos = ( + -7.3 + 15.3 * random.random(), + 11, + -5.57 + 2.1 * random.random(), + ) + dropdir = -1.0 if pos[0] > 0 else 1.0 + vel = ( + (-5.0 + random.random() * 30.0) * dropdir, + random.uniform(-3.066, -4.12), + 0, + ) + ba.timer(delay, ba.Call(self._drop_bomb, pos, vel)) + delay += 0.1 + self._set_meteor_timer() + + def _drop_bomb( + self, position: Sequence[float], velocity: Sequence[float] + ) -> None: + if self._bomb_type == 'tnt': + bomb_type = random.choice(['tnt','tnt','tnt','tnt','impact']) + elif self._bomb_type == 'land_mine': + bomb_type = random.choice([ + 'land_mine','land_mine','land_mine','land_mine','impact']) + elif self._bomb_type == 'random': + bomb_type = random.choice([ + 'normal','ice','sticky','impact','land_mine','tnt']) + else: + bomb_type = self._bomb_type + Bomb(position=position, + velocity=velocity, + bomb_type=bomb_type).autoretain() + + def _decrement_meteor_time(self) -> None: + self._meteor_time = max(0.01, self._meteor_time * 0.9) + + def end_game(self) -> None: + cur_time = ba.time() + assert self._timer is not None + start_time = self._timer.getstarttime() + + # Mark death-time as now for any still-living players + # and award players points for how long they lasted. + # (these per-player scores are only meaningful in team-games) + for team in self.teams: + for player in team.players: + survived = False + + # Throw an extra fudge factor in so teams that + # didn't die come out ahead of teams that did. + if player.death_time is None: + survived = True + player.death_time = cur_time + 1 + + # Award a per-player score depending on how many seconds + # they lasted (per-player scores only affect teams mode; + # everywhere else just looks at the per-team score). + score = int(player.death_time - self._timer.getstarttime()) + if survived: + score += 50 # A bit extra for survivors. + self.stats.player_scored(player, score, screenmessage=False) + + # Stop updating our time text, and set the final time to match + # exactly when our last guy died. + self._timer.stop(endtime=self._last_player_death_time) + + # Ok now calc game results: set a score for each team and then tell + # the game to end. + results = ba.GameResults() + + # Remember that 'free-for-all' mode is simply a special form + # of 'teams' mode where each player gets their own team, so we can + # just always deal in teams and have all cases covered. + for team in self.teams: + + # Set the team score to the max time survived by any player on + # that team. + longest_life = 0.0 + for player in team.players: + assert player.death_time is not None + longest_life = max(longest_life, player.death_time - start_time) + + # Submit the score value in milliseconds. + results.set_team_score(team, int(1000.0 * longest_life)) + + self.end(results=results) + + +# ba_meta export plugin +class MeteorShowerv2Coop(ba.Plugin): + def on_app_running(self) -> None: + ba.app.add_coop_practice_level( + ba.Level( + normal_rain, + gametype=MeteorShowerv2Game, + settings={bomb_type: 0}, + preview_texture_name='rampagePreview', + ) + ) + ba.app.add_coop_practice_level( + ba.Level( + frozen_rain, + gametype=MeteorShowerv2Game, + settings={bomb_type: 1}, + preview_texture_name='rampagePreview', + ) + ) + ba.app.add_coop_practice_level( + ba.Level( + sticky_rain, + gametype=MeteorShowerv2Game, + settings={bomb_type: 2}, + preview_texture_name='rampagePreview', + ) + ) + ba.app.add_coop_practice_level( + ba.Level( + impact_rain, + gametype=MeteorShowerv2Game, + settings={bomb_type: 3}, + preview_texture_name='rampagePreview', + ) + ) + ba.app.add_coop_practice_level( + ba.Level( + mine_rain, + gametype=MeteorShowerv2Game, + settings={bomb_type: 4}, + preview_texture_name='rampagePreview', + ) + ) + ba.app.add_coop_practice_level( + ba.Level( + tnt_rain, + gametype=MeteorShowerv2Game, + settings={bomb_type: 5}, + preview_texture_name='rampagePreview', + ) + ) + ba.app.add_coop_practice_level( + ba.Level( + random_rain, + gametype=MeteorShowerv2Game, + settings={bomb_type: 6}, + preview_texture_name='rampagePreview', + ) + ) diff --git a/plugins/minigames/SimonSays.py b/plugins/minigames/SimonSays.py new file mode 100644 index 00000000..151963d8 --- /dev/null +++ b/plugins/minigames/SimonSays.py @@ -0,0 +1,333 @@ +#SimonSays +# you had really better do what Simon says... +# ba_meta require api 7 +from __future__ import annotations + +from typing import TYPE_CHECKING + +if TYPE_CHECKING: + from typing import Any, Union, Sequence + +from ba import _gameutils +import ba +import random + +class CustomText(ba.Actor): + """Text that pops up above a position to denote something special. + + category: Gameplay Classes + """ + + def __init__(self, + text: Union[str, ba.Lstr], + position: Sequence[float] = (0.0, 0.0, 0.0), + color: Sequence[float] = (1.0, 1.0, 1.0, 1.0), + random_offset: float = 0.5, + duration: float = 1.5, + offset: Sequence[float] = (0.0, 0.0, 0.0), + scale: float = 1.0): + super().__init__() + if len(color) == 3: + color = (color[0], color[1], color[2], 1.0) + pos = (position[0] + offset[0] + random_offset * + (0.5 - random.random()), position[1] + offset[0] + + random_offset * (0.5 - random.random()), position[2] + + offset[0] + random_offset * (0.5 - random.random())) + self.node = ba.newnode('text', + attrs={ + 'text': text, + 'in_world': True, + 'shadow': 1.0, + 'flatness': 1.0, + 'h_align': 'center'},delegate=self) + lifespan = duration + ba.animate( + self.node, 'scale', { + 0: 0.0, + lifespan * 0.11: 0.020 * 0.7 * scale, + lifespan * 0.16: 0.013 * 0.7 * scale, + lifespan * 0.25: 0.014 * 0.7 * scale + }) + self._tcombine = ba.newnode('combine', + owner=self.node, + attrs={ + 'input0': pos[0], + 'input2': pos[2], + 'size': 3 + }) + ba.animate(self._tcombine, 'input1', { + 0: pos[1] + 1.5, + lifespan: pos[1] + 2.0 + }) + self._tcombine.connectattr('output', self.node, 'position') + # fade our opacity in/out + self._combine = ba.newnode('combine', + owner=self.node, + attrs={ + 'input0': color[0], + 'input1': color[1], + 'input2': color[2], + 'size': 4 + }) + for i in range(4): + ba.animate( + self._combine, 'input' + str(i), { + 0.13 * lifespan: color[i], + 0.18 * lifespan: 4.0 * color[i], + 0.22 * lifespan: color[i]}) + ba.animate(self._combine, 'input3', { + 0: 0, + 0.1 * lifespan: color[3], + 0.7 * lifespan: color[3], + lifespan: 0}) + self._combine.connectattr('output', self.node, 'color') + self._die_timer = ba.Timer( + lifespan, ba.WeakCall(self.handlemessage, ba.DieMessage())) + def handlemessage(self, msg: Any) -> Any: + assert not self.expired + if isinstance(msg, ba.DieMessage): + if self.node: + self.node.delete() + else: + super().handlemessage(msg) + +class Player(ba.Player['Team']): + """Our player type for this game.""" + def __init__(self) -> None: + self.score = 0 + +class Team(ba.Team[Player]): + """Our team type for this game.""" + + def __init__(self) -> None: + self.score = 0 + +# ba_meta export game +class SimonSays(ba.TeamGameActivity[Player, Team]): + name = "Simon Says" + description = "You have to better do what Simon says!" + @classmethod + def get_available_settings(cls, sessiontype: Type[ba.Session]) -> List[ba.Setting]: + settings = [ + ba.BoolSetting("Epic Mode", default=False), + ba.BoolSetting("Enable Jumping", default=False), + ba.BoolSetting("Enable Punching", default=False), + ba.BoolSetting("Enable Picking Up", default=False), + ba.IntChoiceSetting("Timer Speed", + choices=[("Snaily", 1200), + ("Slow", 900), + ("Normal", 655), + ("Fast", 544), + ("Turbo", 460)], default=655), + + ba.FloatChoiceSetting("Text Duration", + choices=[("Slow", 2.5), + ("Normal", 1.5), + ("Mediocre", 1.0), + ("Quick", 0.75)], default=1.5)] + return settings + + @classmethod + def get_supported_maps(cls, sessiontype: Type[ba.Session]) -> List[str]: + return ["Courtyard"] + + @classmethod + def supports_session_type(cls, sessiontype: Type[ba.Session]) -> bool: + return issubclass(sessiontype, ba.FreeForAllSession) + + def __init__(self, settings: dict): + super().__init__(settings) + self.settings = settings + self._is_slow_motion = bool(settings['Epic Mode']) + self.speed = float(settings['Timer Speed']) + self.lifespan = float(settings['Text Duration']) + self.round_num = 0 + self.string = "" + self.now = 0 + self.simon = False + self.ended = False + self.counter_loop = None + self.time = 5000 + self._r1 = 2 + self.ct_text = ba.newnode('text',attrs={ + 'in_world': True, + 'text':'......', + 'shadow': 1.0, + 'color': (1.0,1.0,1.0), + 'flatness': 0.5, + 'position': (-5.627144702, 3.3275475, -9.572879116), + 'scale': 0.05}) + self.n1 = ba.newnode('locator',attrs={'shape':'circle','position':(-4,0,-6), + 'color':(1,0,0),'opacity':0.5, + 'draw_beauty':True,'additive':True}) + self.n2 = ba.newnode('locator',attrs={'shape':'circle','position':(0,0,-6), + 'color':(0,1,0),'opacity':0.5, + 'draw_beauty':True,'additive':True}) + self.n3 = ba.newnode('locator',attrs={'shape':'circle','position':(4,0,-6), + 'color':(0,0,1),'opacity':0.5, + 'draw_beauty':True,'additive':True}) + self.n4 = ba.newnode('locator',attrs={'shape':'circle','position':(-4,0,-2), + 'color':(1,1,0),'opacity':0.5, + 'draw_beauty':True,'additive':True}) + self.n5 = ba.newnode('locator',attrs={'shape':'circle','position':(0,0,-2), + 'color':(0,1,1),'opacity':0.5, + 'draw_beauty':True,'additive':True}) + self.n6 = ba.newnode('locator',attrs={'shape':'circle','position':(4,0,-2), + 'color':(1,0,1),'opacity':0.5, + 'draw_beauty':True,'additive':True}) + self.n7 = ba.newnode('locator',attrs={'shape':'circle','position':(-4,0,2), + 'color':(.5,.5,.5),'opacity':0.5, + 'draw_beauty':True,'additive':True}) + self.n8 = ba.newnode('locator',attrs={'shape':'circle','position':(0,0,2), + 'color':(.5,.325,0),'opacity':0.5, + 'draw_beauty':True,'additive':True}) + self.n9 = ba.newnode('locator',attrs={'shape':'circle','position':(4,0,2), + 'color':(1,1,1),'opacity':0.5, + 'draw_beauty':True,'additive':True}) + self.options = ["red", "green", "blue", "yellow", "teal", "purple", "gray", "orange", "white", "top", "bottom", "middle row", "left", "right", "center column", "outside"] + self.default_music = ba.MusicType.FLAG_CATCHER + + def get_instance_description(self) -> str: + return 'Follow the commands... but only when \"Simon says!"' + + def on_player_join(self, player: Player) -> None: + if self.has_begun(): + ba.screenmessage( + ba.Lstr(resource = 'playerDelayedJoinText', + subs = [('${PLAYER}', player.getname(full=True))]), + color=(0, 1, 0),) + return + else: + self.spawn_player(player) + + def on_begin(self) -> None: + super().on_begin() + s = self.settings + _gameutils.animate_array(self.n1,'size',1,{0:[0.0],0.2:[self._r1*2.0]}) + _gameutils.animate_array(self.n2,'size',1,{0:[0.0],0.2:[self._r1*2.0]}) + _gameutils.animate_array(self.n3,'size',1,{0:[0.0],0.2:[self._r1*2.0]}) + _gameutils.animate_array(self.n4,'size',1,{0:[0.0],0.2:[self._r1*2.0]}) + _gameutils.animate_array(self.n5,'size',1,{0:[0.0],0.2:[self._r1*2.0]}) + _gameutils.animate_array(self.n6,'size',1,{0:[0.0],0.2:[self._r1*2.0]}) + _gameutils.animate_array(self.n7,'size',1,{0:[0.0],0.2:[self._r1*2.0]}) + _gameutils.animate_array(self.n8,'size',1,{0:[0.0],0.2:[self._r1*2.0]}) + _gameutils.animate_array(self.n9,'size',1,{0:[0.0],0.2:[self._r1*2.0]}) + for team in self.teams: + team.score = 0 + for player in self.players: + player.score = 0 + # check for immediate end if theres only 1 player + if len(self.players) == 1: + ba.timer(4000, lambda: self.check_end(),timeformat=ba.TimeFormat.MILLISECONDS) + else: + ba.timer(6000, self.call_round, timeformat=ba.TimeFormat.MILLISECONDS) + + def spawn_player(self, player: PlayerType) -> ba.Actor: + assert player + spaz = self.spawn_player_spaz(player, position=(0 + random.uniform(-3.6, 3.6), 2.9, -2 + random.uniform(-3.6, 3.6))) + assert spaz.node + spaz.connect_controls_to_player( + enable_bomb=False, + enable_run = True, + enable_punch = self.settings["Enable Punching"], + enable_pickup = self.settings["Enable Picking Up"], + enable_jump = self.settings["Enable Jumping"]) + + def call_round(self) -> None: + if self.ended: return + self.round_num += 1 + self.num = random.randint(0, 15) + self.numa = self.num + self.simon = random.choice([True, False]) + false_prefix = random.choices(['Simon say r', 'Simon said r', 'Simon r', 'Simons says r', 'Simons r', 'R'], weights=[35,45,45,39,49,100])[0] + if self.numa < 9: + if not self.simon: line = false_prefix + "un to the " + self.options[self.numa] + " circle!" + else: line = "Run to the " + self.options[self.numa] + " circle!" + + elif self.numa < 15: + if not self.simon: line = false_prefix + "un to the " + self.options[self.numa] + "!" + else: line = "Run to the " + self.options[self.numa] + "!" + + else: + if not self.simon: line = false_prefix + "un outside of the circles!" + else: line = "Run outside of the circles!" + + + if self.simon: + line = "Simon says " + line[0].lower() + line[1:] + self.text = CustomText(line, + position=(0, 5, -4), + color=(0.68, 0.95, 1.12), + random_offset=0.5, + offset=(0, 0, 0), + duration=self.lifespan, + scale=2.0).autoretain() + self.now = 6 + def dummy_check(): + self.string = "...." + self.check_round() + def set_counter(): + self.now = self.now - 1 + if self.now == 0: + self.string = "0" + self.ct_text.text = self.string + self.counter_loop = None + ba.timer(1, dummy_check, timeformat=ba.TimeFormat.MILLISECONDS) + else: + self.ct_text.text = str(self.now) + ba.playsound(ba.getsound('tick')) + self.counter_loop = ba.Timer(self.speed, set_counter ,timeformat=ba.TimeFormat.MILLISECONDS,repeat=True) + + def check_round(self) -> None: + if self.ended: return + for player in self.players: + if player.is_alive(): + safe = True if self.options[self.numa] in self.in_circle(player.actor.node.position_center) else False + if ((self.simon and safe == False) or ((not self.simon) and safe == True)): + player.team.score = self.round_num + player.actor.handlemessage(ba.DieMessage()) + ba.timer(1633, self.call_round, timeformat=ba.TimeFormat.MILLISECONDS) + + + def in_circle(self, pos) -> None: + circles = [] + x = pos[0] + z = pos[2] + if (x + 4) ** 2 + (z + 6) ** 2 < 4: circles.append("red") + elif (x) ** 2 + (z + 6) ** 2 < 4: circles.append("green") + elif (x - 4) ** 2 + (z + 6) ** 2 < 4: circles.append("blue") + elif (x + 4) ** 2 + (z + 2) ** 2 < 4: circles.append("yellow") + elif (x) ** 2 + (z + 2) ** 2 < 4: circles.append("teal") + elif (x - 4) ** 2 + (z + 2) ** 2 < 4: circles.append("purple") + elif (x + 4) ** 2 + (z - 2) ** 2 < 4: circles.append("gray") + elif (x) ** 2 + (z - 2) ** 2 < 4: circles.append("orange") + elif (x - 4) ** 2 + (z - 2) ** 2 < 4: circles.append("white") + else: circles.append("outside") + if x < -2: circles.append("left") + if x > 2: circles.append("right") + if x > -2 and x < 2: circles.append("center column") + if z > 0: circles.append("bottom") + if z < -4: circles.append("top") + if z < 0 and z > -4: circles.append("middle row") + return circles + + def handlemessage(self, msg) -> None: + if isinstance(msg, ba.PlayerDiedMessage): + self.check_end() + else: + super().handlemessage(msg) + + def end_game(self) -> None: + self.ended = True + results = ba.GameResults() + for team in self.teams: + results.set_team_score(team, team.score) + self.end(results=results) + + def check_end(self) -> None: + i = 0 + for player in self.players: + if player.is_alive(): + i += 1 + if i <= 2 : + ba.timer(0.6, lambda: self.end_game()) diff --git a/plugins/minigames/SquidRace.py b/plugins/minigames/SquidRace.py new file mode 100644 index 00000000..c13276a2 --- /dev/null +++ b/plugins/minigames/SquidRace.py @@ -0,0 +1,949 @@ +# Released under the MIT License. See LICENSE for details. +# +"""Defines Race mini-game.""" + +# ba_meta require api 7 +# (see https://ballistica.net/wiki/meta-tag-system) + +from __future__ import annotations + +import random +from typing import TYPE_CHECKING +from dataclasses import dataclass + +import ba +from bastd.actor.bomb import Bomb, Blast, ExplodeHitMessage +from bastd.actor.playerspaz import PlayerSpaz +from bastd.actor.scoreboard import Scoreboard +from bastd.gameutils import SharedObjects + +if TYPE_CHECKING: + from typing import (Any, Type, Tuple, List, Sequence, Optional, Dict, + Union) + from bastd.actor.onscreentimer import OnScreenTimer + + +class NewBlast(Blast): + def handlemessage(self, msg: Any) -> Any: + if isinstance(msg, ExplodeHitMessage): + pass + else: + return super().handlemessage(msg) + +@dataclass +class RaceMine: + """Holds info about a mine on the track.""" + point: Sequence[float] + mine: Optional[Bomb] + + +class RaceRegion(ba.Actor): + """Region used to track progress during a race.""" + + def __init__(self, pt: Sequence[float], index: int): + super().__init__() + activity = self.activity + assert isinstance(activity, RaceGame) + self.pos = pt + self.index = index + self.node = ba.newnode( + 'region', + delegate=self, + attrs={ + 'position': pt[:3], + 'scale': (pt[3] * 2.0, pt[4] * 2.0, pt[5] * 2.0), + 'type': 'box', + 'materials': [activity.race_region_material] + }) + + +class Player(ba.Player['Team']): + """Our player type for this game.""" + + def __init__(self) -> None: + self.distance_txt: Optional[ba.Node] = None + self.last_region = 0 + self.lap = 0 + self.distance = 0.0 + self.finished = False + self.rank: Optional[int] = None + + +class Team(ba.Team[Player]): + """Our team type for this game.""" + + def __init__(self) -> None: + self.time: Optional[float] = None + self.lap = 0 + self.finished = False + + +# ba_meta export game +class SquidRaceGame(ba.TeamGameActivity[Player, Team]): + """Game of racing around a track.""" + + name = 'Squid Race' + description = 'Run real fast!' + scoreconfig = ba.ScoreConfig(label='Time', + lower_is_better=True, + scoretype=ba.ScoreType.MILLISECONDS) + + @classmethod + def get_available_settings( + cls, sessiontype: Type[ba.Session]) -> List[ba.Setting]: + settings = [ + ba.IntSetting('Laps', min_value=1, default=3, increment=1), + ba.IntChoiceSetting( + 'Time Limit', + default=0, + choices=[ + ('None', 0), + ('1 Minute', 60), + ('2 Minutes', 120), + ('5 Minutes', 300), + ('10 Minutes', 600), + ('20 Minutes', 1200), + ], + ), + ba.IntChoiceSetting( + 'Mine Spawning', + default=4000, + choices=[ + ('No Mines', 0), + ('8 Seconds', 8000), + ('4 Seconds', 4000), + ('2 Seconds', 2000), + ], + ), + ba.IntChoiceSetting( + 'Bomb Spawning', + choices=[ + ('None', 0), + ('8 Seconds', 8000), + ('4 Seconds', 4000), + ('2 Seconds', 2000), + ('1 Second', 1000), + ], + default=2000, + ), + ba.BoolSetting('Epic Mode', default=False), + ] + + # We have some specific settings in teams mode. + if issubclass(sessiontype, ba.DualTeamSession): + settings.append( + ba.BoolSetting('Entire Team Must Finish', default=False)) + return settings + + @classmethod + def supports_session_type(cls, sessiontype: Type[ba.Session]) -> bool: + return issubclass(sessiontype, ba.MultiTeamSession) + + @classmethod + def get_supported_maps(cls, sessiontype: Type[ba.Session]) -> List[str]: + return ba.getmaps('race') + + def __init__(self, settings: dict): + self._race_started = False + super().__init__(settings) + self._scoreboard = Scoreboard() + self._score_sound = ba.getsound('score') + self._swipsound = ba.getsound('swip') + self._last_team_time: Optional[float] = None + self._front_race_region: Optional[int] = None + self._nub_tex = ba.gettexture('nub') + self._beep_1_sound = ba.getsound('raceBeep1') + self._beep_2_sound = ba.getsound('raceBeep2') + self.race_region_material: Optional[ba.Material] = None + self._regions: List[RaceRegion] = [] + self._team_finish_pts: Optional[int] = None + self._time_text: Optional[ba.Actor] = None + self._timer: Optional[OnScreenTimer] = None + self._race_mines: Optional[List[RaceMine]] = None + self._race_mine_timer: Optional[ba.Timer] = None + self._scoreboard_timer: Optional[ba.Timer] = None + self._player_order_update_timer: Optional[ba.Timer] = None + self._start_lights: Optional[List[ba.Node]] = None + self._squid_lights: Optional[List[ba.Node]] = None + self._countdown_timer: int = 0 + self._sq_mode: str = 'Easy' + self._tick_timer: Optional[ba.Timer] = None + self._bomb_spawn_timer: Optional[ba.Timer] = None + self._laps = int(settings['Laps']) + self._entire_team_must_finish = bool( + settings.get('Entire Team Must Finish', False)) + self._time_limit = float(settings['Time Limit']) + self._mine_spawning = int(settings['Mine Spawning']) + self._bomb_spawning = int(settings['Bomb Spawning']) + self._epic_mode = bool(settings['Epic Mode']) + + self._countdownsounds = { + 10: ba.getsound('announceTen'), + 9: ba.getsound('announceNine'), + 8: ba.getsound('announceEight'), + 7: ba.getsound('announceSeven'), + 6: ba.getsound('announceSix'), + 5: ba.getsound('announceFive'), + 4: ba.getsound('announceFour'), + 3: ba.getsound('announceThree'), + 2: ba.getsound('announceTwo'), + 1: ba.getsound('announceOne') + } + + # Base class overrides. + self.slow_motion = self._epic_mode + self.default_music = (ba.MusicType.EPIC_RACE + if self._epic_mode else ba.MusicType.RACE) + + def get_instance_description(self) -> Union[str, Sequence]: + if (isinstance(self.session, ba.DualTeamSession) + and self._entire_team_must_finish): + t_str = ' Your entire team has to finish.' + else: + t_str = '' + + if self._laps > 1: + return 'Run ${ARG1} laps.' + t_str, self._laps + return 'Run 1 lap.' + t_str + + def get_instance_description_short(self) -> Union[str, Sequence]: + if self._laps > 1: + return 'run ${ARG1} laps', self._laps + return 'run 1 lap' + + def on_transition_in(self) -> None: + super().on_transition_in() + shared = SharedObjects.get() + pts = self.map.get_def_points('race_point') + mat = self.race_region_material = ba.Material() + mat.add_actions(conditions=('they_have_material', + shared.player_material), + actions=( + ('modify_part_collision', 'collide', True), + ('modify_part_collision', 'physical', False), + ('call', 'at_connect', + self._handle_race_point_collide), + )) + for rpt in pts: + self._regions.append(RaceRegion(rpt, len(self._regions))) + + def _flash_player(self, player: Player, scale: float) -> None: + assert isinstance(player.actor, PlayerSpaz) + assert player.actor.node + pos = player.actor.node.position + light = ba.newnode('light', + attrs={ + 'position': pos, + 'color': (1, 1, 0), + 'height_attenuated': False, + 'radius': 0.4 + }) + ba.timer(0.5, light.delete) + ba.animate(light, 'intensity', {0: 0, 0.1: 1.0 * scale, 0.5: 0}) + + def _handle_race_point_collide(self) -> None: + # FIXME: Tidy this up. + # pylint: disable=too-many-statements + # pylint: disable=too-many-branches + # pylint: disable=too-many-nested-blocks + collision = ba.getcollision() + try: + region = collision.sourcenode.getdelegate(RaceRegion, True) + player = collision.opposingnode.getdelegate(PlayerSpaz, + True).getplayer( + Player, True) + except ba.NotFoundError: + return + + last_region = player.last_region + this_region = region.index + + if last_region != this_region: + + # If a player tries to skip regions, smite them. + # Allow a one region leeway though (its plausible players can get + # blown over a region, etc). + if this_region > last_region + 2: + if player.is_alive(): + assert player.actor + player.actor.handlemessage(ba.DieMessage()) + ba.screenmessage(ba.Lstr( + translate=('statements', 'Killing ${NAME} for' + ' skipping part of the track!'), + subs=[('${NAME}', player.getname(full=True))]), + color=(1, 0, 0)) + else: + # If this player is in first, note that this is the + # front-most race-point. + if player.rank == 0: + self._front_race_region = this_region + + player.last_region = this_region + if last_region >= len(self._regions) - 2 and this_region == 0: + team = player.team + player.lap = min(self._laps, player.lap + 1) + + # In teams mode with all-must-finish on, the team lap + # value is the min of all team players. + # Otherwise its the max. + if isinstance(self.session, ba.DualTeamSession + ) and self._entire_team_must_finish: + team.lap = min([p.lap for p in team.players]) + else: + team.lap = max([p.lap for p in team.players]) + + # A player is finishing. + if player.lap == self._laps: + + # In teams mode, hand out points based on the order + # players come in. + if isinstance(self.session, ba.DualTeamSession): + assert self._team_finish_pts is not None + if self._team_finish_pts > 0: + self.stats.player_scored(player, + self._team_finish_pts, + screenmessage=False) + self._team_finish_pts -= 25 + + # Flash where the player is. + self._flash_player(player, 1.0) + player.finished = True + assert player.actor + player.actor.handlemessage( + ba.DieMessage(immediate=True)) + + # Makes sure noone behind them passes them in rank + # while finishing. + player.distance = 9999.0 + + # If the whole team has finished the race. + if team.lap == self._laps: + ba.playsound(self._score_sound) + player.team.finished = True + assert self._timer is not None + elapsed = ba.time() - self._timer.getstarttime() + self._last_team_time = player.team.time = elapsed + + # Team has yet to finish. + else: + ba.playsound(self._swipsound) + + # They've just finished a lap but not the race. + else: + ba.playsound(self._swipsound) + self._flash_player(player, 0.3) + + # Print their lap number over their head. + try: + assert isinstance(player.actor, PlayerSpaz) + mathnode = ba.newnode('math', + owner=player.actor.node, + attrs={ + 'input1': (0, 1.9, 0), + 'operation': 'add' + }) + player.actor.node.connectattr( + 'torso_position', mathnode, 'input2') + tstr = ba.Lstr(resource='lapNumberText', + subs=[('${CURRENT}', + str(player.lap + 1)), + ('${TOTAL}', str(self._laps)) + ]) + txtnode = ba.newnode('text', + owner=mathnode, + attrs={ + 'text': tstr, + 'in_world': True, + 'color': (1, 1, 0, 1), + 'scale': 0.015, + 'h_align': 'center' + }) + mathnode.connectattr('output', txtnode, 'position') + ba.animate(txtnode, 'scale', { + 0.0: 0, + 0.2: 0.019, + 2.0: 0.019, + 2.2: 0 + }) + ba.timer(2.3, mathnode.delete) + except Exception: + ba.print_exception('Error printing lap.') + + def on_team_join(self, team: Team) -> None: + self._update_scoreboard() + + def on_player_join(self, player: Player) -> None: + # Don't allow joining after we start + # (would enable leave/rejoin tomfoolery). + if self.has_begun(): + ba.screenmessage( + ba.Lstr(resource='playerDelayedJoinText', + subs=[('${PLAYER}', player.getname(full=True))]), + color=(0, 1, 0), + ) + return + self.spawn_player(player) + + def on_player_leave(self, player: Player) -> None: + super().on_player_leave(player) + + # A player leaving disqualifies the team if 'Entire Team Must Finish' + # is on (otherwise in teams mode everyone could just leave except the + # leading player to win). + if (isinstance(self.session, ba.DualTeamSession) + and self._entire_team_must_finish): + ba.screenmessage(ba.Lstr( + translate=('statements', + '${TEAM} is disqualified because ${PLAYER} left'), + subs=[('${TEAM}', player.team.name), + ('${PLAYER}', player.getname(full=True))]), + color=(1, 1, 0)) + player.team.finished = True + player.team.time = None + player.team.lap = 0 + ba.playsound(ba.getsound('boo')) + for otherplayer in player.team.players: + otherplayer.lap = 0 + otherplayer.finished = True + try: + if otherplayer.actor is not None: + otherplayer.actor.handlemessage(ba.DieMessage()) + except Exception: + ba.print_exception('Error sending DieMessage.') + + # Defer so team/player lists will be updated. + ba.pushcall(self._check_end_game) + + def _update_scoreboard(self) -> None: + for team in self.teams: + distances = [player.distance for player in team.players] + if not distances: + teams_dist = 0.0 + else: + if (isinstance(self.session, ba.DualTeamSession) + and self._entire_team_must_finish): + teams_dist = min(distances) + else: + teams_dist = max(distances) + self._scoreboard.set_team_value( + team, + teams_dist, + self._laps, + flash=(teams_dist >= float(self._laps)), + show_value=False) + + def on_begin(self) -> None: + from bastd.actor.onscreentimer import OnScreenTimer + super().on_begin() + self.setup_standard_time_limit(self._time_limit) + self.setup_standard_powerup_drops() + self._team_finish_pts = 100 + + # Throw a timer up on-screen. + self._time_text = ba.NodeActor( + ba.newnode('text', + attrs={ + 'v_attach': 'top', + 'h_attach': 'center', + 'h_align': 'center', + 'color': (1, 1, 0.5, 1), + 'flatness': 0.5, + 'shadow': 0.5, + 'position': (0, -50), + 'scale': 1.4, + 'text': '' + })) + self._timer = OnScreenTimer() + + if self._mine_spawning != 0: + self._race_mines = [ + RaceMine(point=p, mine=None) + for p in self.map.get_def_points('race_mine') + ] + if self._race_mines: + self._race_mine_timer = ba.Timer(0.001 * self._mine_spawning, + self._update_race_mine, + repeat=True) + + self._scoreboard_timer = ba.Timer(0.25, + self._update_scoreboard, + repeat=True) + self._player_order_update_timer = ba.Timer(0.25, + self._update_player_order, + repeat=True) + + if self.slow_motion: + t_scale = 0.4 + light_y = 50 + else: + t_scale = 1.0 + light_y = 150 + lstart = 7.1 * t_scale + inc = 1.25 * t_scale + + ba.timer(lstart, self._do_light_1) + ba.timer(lstart + inc, self._do_light_2) + ba.timer(lstart + 2 * inc, self._do_light_3) + ba.timer(lstart + 3 * inc, self._start_race) + + self._start_lights = [] + for i in range(4): + lnub = ba.newnode('image', + attrs={ + 'texture': ba.gettexture('nub'), + 'opacity': 1.0, + 'absolute_scale': True, + 'position': (-75 + i * 50, light_y), + 'scale': (50, 50), + 'attach': 'center' + }) + ba.animate( + lnub, 'opacity', { + 4.0 * t_scale: 0, + 5.0 * t_scale: 1.0, + 12.0 * t_scale: 1.0, + 12.5 * t_scale: 0.0 + }) + ba.timer(13.0 * t_scale, lnub.delete) + self._start_lights.append(lnub) + + self._start_lights[0].color = (0.2, 0, 0) + self._start_lights[1].color = (0.2, 0, 0) + self._start_lights[2].color = (0.2, 0.05, 0) + self._start_lights[3].color = (0.0, 0.3, 0) + + self._squid_lights = [] + for i in range(2): + lnub = ba.newnode('image', + attrs={ + 'texture': ba.gettexture('nub'), + 'opacity': 1.0, + 'absolute_scale': True, + 'position': (-33 + i * 65, 220), + 'scale': (60, 60), + 'attach': 'center' + }) + ba.animate( + lnub, 'opacity', { + 4.0 * t_scale: 0, + 5.0 * t_scale: 1.0}) + self._squid_lights.append(lnub) + self._squid_lights[0].color = (0.2, 0, 0) + self._squid_lights[1].color = (0.0, 0.3, 0) + + ba.timer(1.0, self._check_squid_end, repeat=True) + self._squidgame_countdown() + + def _squidgame_countdown(self) -> None: + self._countdown_timer = 80 * self._laps # 80 + ba.newnode( + 'image', + attrs={ + 'opacity': 0.7, + 'color': (0.2, 0.2, 0.2), + 'attach': 'topCenter', + 'position': (-220, -40), + 'scale': (135, 45), + 'texture': ba.gettexture('bar')}) + ba.newnode( + 'image', + attrs={ + 'opacity': 1.0, + 'color': (1.0, 0.0, 0.0), + 'attach': 'topCenter', + 'position': (-220, -38), + 'scale':(155, 65), + 'texture': ba.gettexture('uiAtlas'), + 'model_transparent': ba.getmodel('meterTransparent')}) + self._sgcountdown_text = ba.newnode( + 'text', + attrs={ + 'v_attach': 'top', + 'h_attach': 'center', + 'h_align': 'center', + 'position': (-220, -57), + 'shadow': 0.5, + 'flatness': 0.5, + 'scale': 1.1, + 'text': str(self._countdown_timer)+"s"}) + + def _update_sgcountdown(self) -> None: + self._countdown_timer -= 1 + self._countdown_timer + if self._countdown_timer <= 0: + self._countdown_timer = 0 + self._squid_game_all_die() + if self._countdown_timer == 20: + self._sq_mode = 'Hard' + ba.playsound(ba.getsound('alarm')) + if self._countdown_timer == 40: + self._sq_mode = 'Normal' + if self._countdown_timer <= 20: + self._sgcountdown_text.color = (1.2, 0.0, 0.0) + self._sgcountdown_text.scale = 1.2 + if self._countdown_timer in self._countdownsounds: + ba.playsound(self._countdownsounds[self._countdown_timer]) + else: + self._sgcountdown_text.color = (1.0, 1.0, 1.0) + self._sgcountdown_text.text = str(self._countdown_timer)+"s" + + def _squid_game_all_die(self) -> None: + for player in self.players: + if player.is_alive(): + player.actor._cursed = True + player.actor.handlemessage(ba.DieMessage()) + NewBlast( + position=player.actor.node.position, + velocity=player.actor.node.velocity, + blast_radius=3.0, + blast_type='normal').autoretain() + player.actor.handlemessage( + ba.HitMessage( + pos=player.actor.node.position, + velocity=player.actor.node.velocity, + magnitude=2000, + hit_type='explosion', + hit_subtype='normal', + radius=2.0, + source_player=None)) + player.actor._cursed = False + + def _do_ticks(self) -> None: + def do_ticks(): + if self._ticks: + ba.playsound(ba.getsound('tick')) + self._tick_timer = ba.timer(1.0, do_ticks, repeat=True) + + def _start_squid_game(self) -> None: + easy = [4.5,5,5.5,6] + normal = [4,4.5,5] + hard = [3,3.5,4] + random_number = random.choice( + hard if self._sq_mode == 'Hard' else + normal if self._sq_mode == 'Normal' else easy) + # if random_number == 6: + # ba.playsound(ba.getsound('lrlg_06s')) + # elif random_number == 5.5: + # ba.playsound(ba.getsound('lrlg_055s')) + # elif random_number == 5: + # ba.playsound(ba.getsound('lrlg_05s')) + # elif random_number == 4.5: + # ba.playsound(ba.getsound('lrlg_045s')) + # elif random_number == 4: + # ba.playsound(ba.getsound('lrlg_04s')) + # elif random_number == 3.5: + # ba.playsound(ba.getsound('lrlg_035s')) + # elif random_number == 3: + # ba.playsound(ba.getsound('lrlg_03s')) + self._squid_lights[0].color = (0.2, 0, 0) + self._squid_lights[1].color = (0.0, 1.0, 0) + self._do_delete = False + self._ticks = True + ba.timer(random_number, self._stop_squid_game) + + def _stop_squid_game(self) -> None: + self._ticks = False + self._squid_lights[0].color = (1.0, 0, 0) + self._squid_lights[1].color = (0.0, 0.3, 0) + ba.timer(0.2, self._check_delete) + + def _check_delete(self) -> None: + for player in self.players: + if player.is_alive(): + player.customdata['position'] = None + player.customdata['position'] = player.actor.node.position + self._do_delete = True + ba.timer(3.0 if self._sq_mode == 'Hard' else 4.0, + self._start_squid_game) + + def _start_delete(self) -> None: + for player in self.players: + if player.is_alive() and self._do_delete: + + posx = float("%.1f" % player.customdata['position'][0]) + posz = float("%.1f" % player.customdata['position'][1]) + posy = float("%.1f" % player.customdata['position'][2]) + + posx_list = [ + round(posx,1),round(posx+0.1,1),round(posx+0.2,1), + round(posx-0.1,1),round(posx-0.2,1)] + current_posx = float("%.1f" % player.actor.node.position[0]) + + posz_list = [ + round(posz,1),round(posz+0.1,1),round(posz+0.2,1), + round(posz-0.1,1),round(posz-0.2,1)] + current_posz = float("%.1f" % player.actor.node.position[1]) + + posy_list = [ + round(posy,1),round(posy+0.1,1),round(posy+0.2,1), + round(posy-0.1,1),round(posy-0.2,1)] + current_posy = float("%.1f" % player.actor.node.position[2]) + + if not (current_posx in posx_list) or not ( + current_posz in posz_list) or not ( + current_posy in posy_list): + player.actor._cursed = True + player.actor.handlemessage(ba.DieMessage()) + NewBlast( + position=player.actor.node.position, + velocity=player.actor.node.velocity, + blast_radius=3.0, + blast_type='normal').autoretain() + player.actor.handlemessage( + ba.HitMessage( + pos=player.actor.node.position, + velocity=player.actor.node.velocity, + magnitude=2000, + hit_type='explosion', + hit_subtype='normal', + radius=2.0, + source_player=None)) + player.actor._cursed = False + + def _check_squid_end(self) -> None: + squid_player_alive = 0 + for player in self.players: + if player.is_alive(): + squid_player_alive += 1 + break + if squid_player_alive < 1: + self.end_game() + + def _do_light_1(self) -> None: + assert self._start_lights is not None + self._start_lights[0].color = (1.0, 0, 0) + ba.playsound(self._beep_1_sound) + + def _do_light_2(self) -> None: + assert self._start_lights is not None + self._start_lights[1].color = (1.0, 0, 0) + ba.playsound(self._beep_1_sound) + + def _do_light_3(self) -> None: + assert self._start_lights is not None + self._start_lights[2].color = (1.0, 0.3, 0) + ba.playsound(self._beep_1_sound) + + def _start_race(self) -> None: + assert self._start_lights is not None + self._start_lights[3].color = (0.0, 1.0, 0) + ba.playsound(self._beep_2_sound) + for player in self.players: + if player.actor is not None: + try: + assert isinstance(player.actor, PlayerSpaz) + player.actor.connect_controls_to_player() + except Exception: + ba.print_exception('Error in race player connects.') + assert self._timer is not None + self._timer.start() + + if self._bomb_spawning != 0: + self._bomb_spawn_timer = ba.Timer(0.001 * self._bomb_spawning, + self._spawn_bomb, + repeat=True) + + self._race_started = True + self._squid_lights[1].color = (0.0, 1.0, 0) + self._start_squid_game() + self._do_ticks() + ba.timer(0.2, self._start_delete, repeat=True) + ba.timer(1.0, self._update_sgcountdown, repeat=True) + + def _update_player_order(self) -> None: + + # Calc all player distances. + for player in self.players: + pos: Optional[ba.Vec3] + try: + pos = player.position + except ba.NotFoundError: + pos = None + if pos is not None: + r_index = player.last_region + rg1 = self._regions[r_index] + r1pt = ba.Vec3(rg1.pos[:3]) + rg2 = self._regions[0] if r_index == len( + self._regions) - 1 else self._regions[r_index + 1] + r2pt = ba.Vec3(rg2.pos[:3]) + r2dist = (pos - r2pt).length() + amt = 1.0 - (r2dist / (r2pt - r1pt).length()) + amt = player.lap + (r_index + amt) * (1.0 / len(self._regions)) + player.distance = amt + + # Sort players by distance and update their ranks. + p_list = [(player.distance, player) for player in self.players] + + p_list.sort(reverse=True, key=lambda x: x[0]) + for i, plr in enumerate(p_list): + plr[1].rank = i + if plr[1].actor: + node = plr[1].distance_txt + if node: + node.text = str(i + 1) if plr[1].is_alive() else '' + + def _spawn_bomb(self) -> None: + if self._front_race_region is None: + return + region = (self._front_race_region + 3) % len(self._regions) + pos = self._regions[region].pos + + # Don't use the full region so we're less likely to spawn off a cliff. + region_scale = 0.8 + x_range = ((-0.5, 0.5) if pos[3] == 0 else + (-region_scale * pos[3], region_scale * pos[3])) + z_range = ((-0.5, 0.5) if pos[5] == 0 else + (-region_scale * pos[5], region_scale * pos[5])) + pos = (pos[0] + random.uniform(*x_range), pos[1] + 1.0, + pos[2] + random.uniform(*z_range)) + ba.timer(random.uniform(0.0, 2.0), + ba.WeakCall(self._spawn_bomb_at_pos, pos)) + + def _spawn_bomb_at_pos(self, pos: Sequence[float]) -> None: + if self.has_ended(): + return + Bomb(position=pos, bomb_type='normal').autoretain() + + def _make_mine(self, i: int) -> None: + assert self._race_mines is not None + rmine = self._race_mines[i] + rmine.mine = Bomb(position=rmine.point[:3], bomb_type='land_mine') + rmine.mine.arm() + + def _flash_mine(self, i: int) -> None: + assert self._race_mines is not None + rmine = self._race_mines[i] + light = ba.newnode('light', + attrs={ + 'position': rmine.point[:3], + 'color': (1, 0.2, 0.2), + 'radius': 0.1, + 'height_attenuated': False + }) + ba.animate(light, 'intensity', {0.0: 0, 0.1: 1.0, 0.2: 0}, loop=True) + ba.timer(1.0, light.delete) + + def _update_race_mine(self) -> None: + assert self._race_mines is not None + m_index = -1 + rmine = None + for _i in range(3): + m_index = random.randrange(len(self._race_mines)) + rmine = self._race_mines[m_index] + if not rmine.mine: + break + assert rmine is not None + if not rmine.mine: + self._flash_mine(m_index) + ba.timer(0.95, ba.Call(self._make_mine, m_index)) + + def spawn_player(self, player: Player) -> ba.Actor: + if player.team.finished: + # FIXME: This is not type-safe! + # This call is expected to always return an Actor! + # Perhaps we need something like can_spawn_player()... + # noinspection PyTypeChecker + return None # type: ignore + pos = self._regions[player.last_region].pos + + # Don't use the full region so we're less likely to spawn off a cliff. + region_scale = 0.8 + x_range = ((-0.5, 0.5) if pos[3] == 0 else + (-region_scale * pos[3], region_scale * pos[3])) + z_range = ((-0.5, 0.5) if pos[5] == 0 else + (-region_scale * pos[5], region_scale * pos[5])) + pos = (pos[0] + random.uniform(*x_range), pos[1], + pos[2] + random.uniform(*z_range)) + spaz = self.spawn_player_spaz( + player, position=pos, angle=90 if not self._race_started else None) + assert spaz.node + + # Prevent controlling of characters before the start of the race. + if not self._race_started: + spaz.disconnect_controls_from_player() + + mathnode = ba.newnode('math', + owner=spaz.node, + attrs={ + 'input1': (0, 1.4, 0), + 'operation': 'add' + }) + spaz.node.connectattr('torso_position', mathnode, 'input2') + + distance_txt = ba.newnode('text', + owner=spaz.node, + attrs={ + 'text': '', + 'in_world': True, + 'color': (1, 1, 0.4), + 'scale': 0.02, + 'h_align': 'center' + }) + player.distance_txt = distance_txt + mathnode.connectattr('output', distance_txt, 'position') + return spaz + + def _check_end_game(self) -> None: + + # If there's no teams left racing, finish. + teams_still_in = len([t for t in self.teams if not t.finished]) + if teams_still_in == 0: + self.end_game() + return + + # Count the number of teams that have completed the race. + teams_completed = len( + [t for t in self.teams if t.finished and t.time is not None]) + + if teams_completed > 0: + session = self.session + + # In teams mode its over as soon as any team finishes the race + + # FIXME: The get_ffa_point_awards code looks dangerous. + if isinstance(session, ba.DualTeamSession): + self.end_game() + else: + # In ffa we keep the race going while there's still any points + # to be handed out. Find out how many points we have to award + # and how many teams have finished, and once that matches + # we're done. + assert isinstance(session, ba.FreeForAllSession) + points_to_award = len(session.get_ffa_point_awards()) + if teams_completed >= points_to_award - teams_completed: + self.end_game() + return + + def end_game(self) -> None: + + # Stop updating our time text, and set it to show the exact last + # finish time if we have one. (so users don't get upset if their + # final time differs from what they see onscreen by a tiny amount) + assert self._timer is not None + if self._timer.has_started(): + self._timer.stop( + endtime=None if self._last_team_time is None else ( + self._timer.getstarttime() + self._last_team_time)) + + results = ba.GameResults() + + for team in self.teams: + if team.time is not None: + # We store time in seconds, but pass a score in milliseconds. + results.set_team_score(team, int(team.time * 1000.0)) + else: + results.set_team_score(team, None) + + # We don't announce a winner in ffa mode since its probably been a + # while since the first place guy crossed the finish line so it seems + # odd to be announcing that now. + self.end(results=results, + announce_winning_team=isinstance(self.session, + ba.DualTeamSession)) + + def handlemessage(self, msg: Any) -> Any: + if isinstance(msg, ba.PlayerDiedMessage): + # Augment default behavior. + super().handlemessage(msg) + else: + super().handlemessage(msg) diff --git a/plugins/minigames/ZombieHorde.py b/plugins/minigames/ZombieHorde.py new file mode 100644 index 00000000..673c9f51 --- /dev/null +++ b/plugins/minigames/ZombieHorde.py @@ -0,0 +1,878 @@ +# ba_meta require api 7 +# (see https://ballistica.net/wiki/meta-tag-system) + +from __future__ import annotations + +from typing import TYPE_CHECKING + +import ba +import _ba +import copy +import random +from ba import _math +from ba._coopsession import CoopSession +from ba._messages import PlayerDiedMessage, StandMessage +from bastd.actor.playerspaz import PlayerSpaz +from bastd.actor.scoreboard import Scoreboard +from bastd.game.elimination import Icon, Player +from bastd.actor.spaz import PickupMessage +from bastd.actor.spazbot import SpazBotSet, BrawlerBot, SpazBotDiedMessage +from bastd.actor.spazfactory import SpazFactory + + +if TYPE_CHECKING: + from typing import Any, Sequence + + +class PlayerSpaz_Zom(PlayerSpaz): + def handlemessage(self, m: Any) -> Any: + if isinstance(m, ba.HitMessage): + if not self.node: + return + if not m._source_player is None: + try: + playa = m._source_player.getname(True, False) + if not playa is None: + if m._source_player.lives < 1: + super().handlemessage(m) + except: + super().handlemessage(m) + else: + super().handlemessage(m) + + elif isinstance(m, ba.FreezeMessage): + pass + + elif isinstance(m, PickupMessage): + if not self.node: + return None + + try: + collision = ba.getcollision() + opposingnode = collision.opposingnode + opposingbody = collision.opposingbody + except ba.NotFoundError: + return True + + try: + if opposingnode.invincible: + return True + except Exception: + pass + + try: + playa = opposingnode._source_player.getname(True, False) + if not playa is None: + if opposingnode._source_player.lives > 0: + return True + except Exception: + pass + + if (opposingnode.getnodetype() == 'spaz' + and not opposingnode.shattered and opposingbody == 4): + opposingbody = 1 + + held = self.node.hold_node + if held and held.getnodetype() == 'flag': + return True + + self.node.hold_body = opposingbody + self.node.hold_node = opposingnode + else: + return super().handlemessage(m) + return None + +class PlayerZombie(PlayerSpaz): + def handlemessage(self, m: Any) -> Any: + if isinstance(m, ba.HitMessage): + if not self.node: + return None + if not m._source_player is None: + try: + playa = m._source_player.getname(True, False) + if playa is None: + pass + else: + super().handlemessage(m) + except: + super().handlemessage(m) + else: + super().handlemessage(m) + else: + super().handlemessage(m) + +class zBotSet(SpazBotSet): + def start_moving(self) -> None: + """Start processing bot AI updates so they start doing their thing.""" + self._bot_update_timer = ba.Timer(0.05, + ba.WeakCall(self.zUpdate), + repeat=True) + + def zUpdate(self) -> None: + + try: + bot_list = self._bot_lists[self._bot_update_list] = ([ + b for b in self._bot_lists[self._bot_update_list] if b + ]) + except Exception: + bot_list = [] + ba.print_exception('Error updating bot list: ' + + str(self._bot_lists[self._bot_update_list])) + self._bot_update_list = (self._bot_update_list + + 1) % self._bot_list_count + + player_pts = [] + for player in ba.getactivity().players: + assert isinstance(player, ba.Player) + try: + if player.is_alive(): + assert isinstance(player.actor, Spaz) + assert player.actor.node + if player.lives > 0: + player_pts.append( + (ba.Vec3(player.actor.node.position), + ba.Vec3(player.actor.node.velocity))) + except Exception: + ba.print_exception('Error on bot-set _update.') + + for bot in bot_list: + bot.set_player_points(player_pts) + bot.update_ai() + +class Team(ba.Team[Player]): + """Our team type for this game.""" + + def __init__(self) -> None: + self.score = 0 + self.spawn_order: list[Player] = [] + + +# ba_meta export game +class ZombieHorde(ba.TeamGameActivity[Player, Team]): + + name = 'Zombie Horde' + description = 'Kill walkers for points!' + scoreconfig = ba.ScoreConfig(label='Score', + scoretype=ba.ScoreType.POINTS, + none_is_winner=False, + lower_is_better=False) + # Show messages when players die since it's meaningful here. + announce_player_deaths = True + + @classmethod + def get_available_settings( + cls, sessiontype: type[ba.Session]) -> list[ba.Setting]: + settings = [ + ba.IntSetting( + 'Lives Per Player', + default=1, + min_value=1, + max_value=10, + increment=1, + ), + ba.IntSetting( + 'Max Zombies', + default=10, + min_value=5, + max_value=50, + increment=5, + ), + 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', 4.0), + ], + default=1.0, + ), + ba.BoolSetting('Epic Mode', default=False), + ] + if issubclass(sessiontype, ba.DualTeamSession): + settings.append(ba.BoolSetting('Solo Mode', default=False)) + settings.append( + ba.BoolSetting('Balance Total Lives', default=False)) + return settings + + @classmethod + def supports_session_type(cls, sessiontype: type[ba.Session]) -> bool: + return (issubclass(sessiontype, ba.DualTeamSession) + or issubclass(sessiontype, ba.FreeForAllSession)) + + @classmethod + def get_supported_maps(cls, sessiontype: type[ba.Session]) -> list[str]: + return ba.getmaps('melee') + + def __init__(self, settings: dict): + super().__init__(settings) + self._scoreboard = Scoreboard() + self._start_time: float | None = None + self._vs_text: ba.Actor | None = None + self._round_end_timer: ba.Timer | None = None + self._epic_mode = bool(settings['Epic Mode']) + self._lives_per_player = int(settings['Lives Per Player']) + self._max_zombies = int(settings['Max Zombies']) + self._time_limit = float(settings['Time Limit']) + self._balance_total_lives = bool( + settings.get('Balance Total Lives', False)) + self._solo_mode = bool(settings.get('Solo Mode', False)) + + # Base class overrides: + self.slow_motion = self._epic_mode + self.default_music = (ba.MusicType.EPIC + if self._epic_mode else ba.MusicType.SURVIVAL) + + self.spazList = [] + self.zombieQ = 0 + + activity = ba.getactivity() + my_factory = SpazFactory.get() + + appears = ['Kronk','Zoe','Pixel','Agent Johnson', + 'Bones','Frosty','Kronk2'] + myAppear = copy.copy(ba.app.spaz_appearances['Kronk']) + myAppear.name = 'Kronk2' + ba.app.spaz_appearances['Kronk2'] = myAppear + for appear in appears: + my_factory.get_media(appear) + med = my_factory.spaz_media + med['Kronk2']['head_model'] = med['Zoe']['head_model'] + med['Kronk2']['color_texture'] = med['Agent Johnson']['color_texture'] + med['Kronk2']['color_mask_texture']=med['Pixel']['color_mask_texture'] + med['Kronk2']['torso_model'] = med['Bones']['torso_model'] + med['Kronk2']['pelvis_model'] = med['Pixel']['pelvis_model'] + med['Kronk2']['upper_arm_model'] = med['Frosty']['upper_arm_model'] + med['Kronk2']['forearm_model'] = med['Frosty']['forearm_model'] + med['Kronk2']['hand_model'] = med['Bones']['hand_model'] + med['Kronk2']['upper_leg_model'] = med['Bones']['upper_leg_model'] + med['Kronk2']['lower_leg_model'] = med['Pixel']['lower_leg_model'] + med['Kronk2']['toes_model'] = med['Bones']['toes_model'] + + def get_instance_description(self) -> str | Sequence: + return ('Kill walkers for points! ', + 'Dead player walker: 2 points!') if isinstance( + self.session, ba.DualTeamSession) else ( + 'Kill walkers for points! Dead player walker: 2 points!') + + def get_instance_description_short(self) -> str | Sequence: + return ('Kill walkers for points! ', + 'Dead player walker: 2 points!') if isinstance( + self.session, ba.DualTeamSession) else ( + 'Kill walkers for points! Dead player walker: 2 points!') + + def on_player_join(self, player: Player) -> None: + if self.has_begun(): + player.lives = 0 + player.icons = [] + ba.screenmessage( + ba.Lstr(resource='playerDelayedJoinText', + subs=[('${PLAYER}', player.getname(full=True))]), + color=(0, 1, 0), + ) + return + + player.lives = self._lives_per_player + + if self._solo_mode: + player.icons = [] + player.team.spawn_order.append(player) + self._update_solo_mode() + else: + player.icons = [Icon(player, position=(0, 50), scale=0.8)] + if player.lives > 0: + self.spawn_player(player) + + if self.has_begun(): + self._update_icons() + + def _update_solo_mode(self) -> None: + for team in self.teams: + team.spawn_order = [p for p in team.spawn_order if p] + for player in team.spawn_order: + assert isinstance(player, Player) + if player.lives > 0: + if not player.is_alive(): + self.spawn_player(player) + break + + def on_begin(self) -> None: + super().on_begin() + self._start_time = ba.time() + self.setup_standard_time_limit(self._time_limit) + self.setup_standard_powerup_drops() + self.zombieQ = 1 + if self._solo_mode: + self._vs_text = ba.NodeActor( + ba.newnode('text', + attrs={ + 'position': (0, 105), + 'h_attach': 'center', + 'h_align': 'center', + 'maxwidth': 200, + 'shadow': 0.5, + 'vr_depth': 390, + 'scale': 0.6, + 'v_attach': 'bottom', + 'color': (0.8, 0.8, 0.3, 1.0), + 'text': ba.Lstr(resource='vsText') + })) + + # If balance-team-lives is on, add lives to the smaller team until + # total lives match. + if (isinstance(self.session, ba.DualTeamSession) + and self._balance_total_lives and self.teams[0].players + and self.teams[1].players): + if self._get_total_team_lives( + self.teams[0]) < self._get_total_team_lives(self.teams[1]): + lesser_team = self.teams[0] + greater_team = self.teams[1] + else: + lesser_team = self.teams[1] + greater_team = self.teams[0] + add_index = 0 + while (self._get_total_team_lives(lesser_team) < + self._get_total_team_lives(greater_team)): + lesser_team.players[add_index].lives += 1 + add_index = (add_index + 1) % len(lesser_team.players) + + self._bots = zBotSet() + + #Set colors and character for ToughGuyBot to be zombie + setattr(BrawlerBot, 'color', (0.4,0.1,0.05)) + setattr(BrawlerBot, 'highlight', (0.2,0.4,0.3)) + setattr(BrawlerBot, 'character', 'Kronk2') + # start some timers to spawn bots + thePt = self.map.get_ffa_start_position(self.players) + + self._update_icons() + + # We could check game-over conditions at explicit trigger points, + # but lets just do the simple thing and poll it. + ba.timer(1.0, self._update, repeat=True) + + def _update_icons(self) -> None: + # pylint: disable=too-many-branches + + # In free-for-all mode, everyone is just lined up along the bottom. + if isinstance(self.session, ba.FreeForAllSession): + count = len(self.teams) + x_offs = 85 + xval = x_offs * (count - 1) * -0.5 + for team in self.teams: + if len(team.players) == 1: + player = team.players[0] + for icon in player.icons: + icon.set_position_and_scale((xval, 30), 0.7) + icon.update_for_lives() + xval += x_offs + + # In teams mode we split up teams. + else: + if self._solo_mode: + # First off, clear out all icons. + for player in self.players: + player.icons = [] + + # Now for each team, cycle through our available players + # adding icons. + for team in self.teams: + if team.id == 0: + xval = -60 + x_offs = -78 + else: + xval = 60 + x_offs = 78 + is_first = True + test_lives = 1 + while True: + players_with_lives = [ + p for p in team.spawn_order + if p and p.lives >= test_lives + ] + if not players_with_lives: + break + for player in players_with_lives: + player.icons.append( + Icon(player, + position=(xval, (40 if is_first else 25)), + scale=1.0 if is_first else 0.5, + name_maxwidth=130 if is_first else 75, + name_scale=0.8 if is_first else 1.0, + flatness=0.0 if is_first else 1.0, + shadow=0.5 if is_first else 1.0, + show_death=is_first, + show_lives=False)) + xval += x_offs * (0.8 if is_first else 0.56) + is_first = False + test_lives += 1 + # Non-solo mode. + else: + for team in self.teams: + if team.id == 0: + xval = -50 + x_offs = -85 + else: + xval = 50 + x_offs = 85 + for player in team.players: + for icon in player.icons: + icon.set_position_and_scale((xval, 30), 0.7) + icon.update_for_lives() + xval += x_offs + + + def _get_spawn_point(self, player: Player) -> ba.Vec3 | None: + del player # Unused. + + # In solo-mode, if there's an existing live player on the map, spawn at + # whichever spot is farthest from them (keeps the action spread out). + if self._solo_mode: + living_player = None + living_player_pos = None + for team in self.teams: + for tplayer in team.players: + if tplayer.is_alive(): + assert tplayer.node + ppos = tplayer.node.position + living_player = tplayer + living_player_pos = ppos + break + if living_player: + assert living_player_pos is not None + player_pos = ba.Vec3(living_player_pos) + points: list[tuple[float, ba.Vec3]] = [] + for team in self.teams: + start_pos = ba.Vec3(self.map.get_start_position(team.id)) + points.append( + ((start_pos - player_pos).length(), start_pos)) + # Hmm.. we need to sorting vectors too? + points.sort(key=lambda x: x[0]) + return points[-1][1] + return None + + def spawn_player(self, player: Player) -> ba.Actor: + position = self.map.get_ffa_start_position(self.players) + angle = 20 + name = player.getname() + + light_color = _math.normalized_color(player.color) + display_color = _ba.safecolor(player.color, target_intensity=0.75) + spaz = PlayerSpaz_Zom(color=player.color, + highlight=player.highlight, + character=player.character, + player=player) + player.actor = spaz + assert spaz.node + self.spazList.append(spaz) + + if isinstance(self.session, CoopSession) and self.map.getname() in [ + 'Courtyard', 'Tower D' + ]: + mat = self.map.preloaddata['collide_with_wall_material'] + assert isinstance(spaz.node.materials, tuple) + assert isinstance(spaz.node.roller_materials, tuple) + spaz.node.materials += (mat, ) + spaz.node.roller_materials += (mat, ) + + spaz.node.name = name + spaz.node.name_color = display_color + spaz.connect_controls_to_player() + factory = SpazFactory() + + # Move to the stand position and add a flash of light. + spaz.handlemessage( + StandMessage( + position, + angle if angle is not None else random.uniform(0, 360))) + _ba.playsound(self._spawn_sound, 1, position=spaz.node.position) + light = _ba.newnode('light', attrs={'color': light_color}) + spaz.node.connectattr('position', light, 'position') + ba.animate(light, 'intensity', {0: 0, 0.25: 1, 0.5: 0}) + _ba.timer(0.5, light.delete) + + if not self._solo_mode: + ba.timer(0.3, ba.Call(self._print_lives, player)) + + for icon in player.icons: + icon.handle_player_spawned() + return spaz + + def respawn_player_zombie(self, + player: Player, + respawn_time: float | None = None) -> None: + # pylint: disable=cyclic-import + + assert player + if respawn_time is None: + teamsize = len(player.team.players) + if teamsize == 1: + respawn_time = 3.0 + elif teamsize == 2: + respawn_time = 5.0 + elif teamsize == 3: + respawn_time = 6.0 + else: + respawn_time = 7.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, ba.WeakCall( + self.spawn_player_if_exists_as_zombie, player)) + player.customdata['respawn_icon'] = RespawnIcon( + player, respawn_time) + + def spawn_player_if_exists_as_zombie(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_zombie(player) + + def spawn_player_zombie(self, player: PlayerType) -> ba.Actor: + position = self.map.get_ffa_start_position(self.players) + angle = 20 + name = player.getname() + + light_color = _math.normalized_color(player.color) + display_color = _ba.safecolor(player.color, target_intensity=0.75) + spaz = PlayerSpaz_Zom(color=player.color, + highlight=player.highlight, + character='Kronk2', + player=player) + player.actor = spaz + assert spaz.node + self.spazList.append(spaz) + + if isinstance(self.session, CoopSession) and self.map.getname() in [ + 'Courtyard', 'Tower D' + ]: + mat = self.map.preloaddata['collide_with_wall_material'] + assert isinstance(spaz.node.materials, tuple) + assert isinstance(spaz.node.roller_materials, tuple) + spaz.node.materials += (mat, ) + spaz.node.roller_materials += (mat, ) + + spaz.node.name = name + spaz.node.name_color = display_color + spaz.connect_controls_to_player(enable_punch=True, + enable_bomb=False, + enable_pickup=False) + + # Move to the stand position and add a flash of light. + spaz.handlemessage( + StandMessage( + position, + angle if angle is not None else random.uniform(0, 360))) + _ba.playsound(self._spawn_sound, 1, position=spaz.node.position) + light = _ba.newnode('light', attrs={'color': light_color}) + spaz.node.connectattr('position', light, 'position') + ba.animate(light, 'intensity', {0: 0, 0.25: 1, 0.5: 0}) + _ba.timer(0.5, light.delete) + + if not self._solo_mode: + ba.timer(0.3, ba.Call(self._print_lives, player)) + + for icon in player.icons: + icon.handle_player_spawned() + return spaz + + def _print_lives(self, player: Player) -> None: + from bastd.actor import popuptext + + # We get called in a timer so it's possible our player has left/etc. + if not player or not player.is_alive() or not player.node: + return + + try: + pos = player.actor.node.position + except Exception as e: + print('EXC getting player pos in bsElim',e) + return + if player.lives > 0: + popuptext.PopupText('x' + str(player.lives - 1), + color=(1, 1, 0, 1), + offset=(0, -0.8, 0), + random_offset=0.0, + scale=1.8, + position=pos).autoretain() + else: + popuptext.PopupText('Dead!', + color=(1, 1, 0, 1), + offset=(0, -0.8, 0), + random_offset=0.0, + scale=1.8, + position=pos).autoretain() + + def on_player_leave(self, player: Player) -> None: + super().on_player_leave(player) + player.icons = [] + + # Remove us from spawn-order. + if self._solo_mode: + if player in player.team.spawn_order: + player.team.spawn_order.remove(player) + + # Update icons in a moment since our team will be gone from the + # list then. + ba.timer(0, self._update_icons) + + def _get_total_team_lives(self, team: Team) -> int: + return sum(player.lives for player in team.players) + + def handlemessage(self, msg: Any) -> Any: + if isinstance(msg, ba.PlayerDiedMessage): + + # Augment standard behavior. + super().handlemessage(msg) + player: Player = msg.getplayer(Player) + + if player.lives > 0: + player.lives -= 1 + else: + if msg._killerplayer: + if msg._killerplayer.lives > 0: + msg._killerplayer.team.score += 2 + self._update_scoreboard() + + if msg._player in self.spazList: + self.spazList.remove(msg._player) + if player.lives < 0: + ba.print_error( + "Got lives < 0 in Elim; this shouldn't happen. solo:" + + str(self._solo_mode)) + player.lives = 0 + + # If we have any icons, update their state. + for icon in player.icons: + icon.handle_player_died() + + # Play big death sound on our last death + # or for every one in solo mode. + if self._solo_mode or player.lives == 0: + ba.playsound(SpazFactory.get().single_player_death_sound) + + # If we hit zero lives, we're dead (and our team might be too). + if player.lives == 0: + self.respawn_player_zombie(player) + else: + # Otherwise, in regular mode, respawn. + if not self._solo_mode: + self.respawn_player(player) + + # In solo, put ourself at the back of the spawn order. + if self._solo_mode: + player.team.spawn_order.remove(player) + player.team.spawn_order.append(player) + + elif isinstance(msg, SpazBotDiedMessage): + self._onSpazBotDied(msg) + super().handlemessage(msg)#bs.PopupText("died",position=self._position,color=popupColor,scale=popupScale).autoRetain() + else: + super().handlemessage(msg) + + def _update(self) -> None: + if self.zombieQ > 0: + self.zombieQ -= 1 + self.spawn_zombie() + if self._solo_mode: + # For both teams, find the first player on the spawn order + # list with lives remaining and spawn them if they're not alive. + for team in self.teams: + # Prune dead players from the spawn order. + team.spawn_order = [p for p in team.spawn_order if p] + for player in team.spawn_order: + assert isinstance(player, Player) + if player.lives > 0: + if not player.is_alive(): + self.spawn_player(player) + self._update_icons() + break + + # If we're down to 1 or fewer living teams, start a timer to end + # the game (allows the dust to settle and draws to occur if deaths + # are close enough). + teamsRemain = self._get_living_teams() + if len(teamsRemain) < 2: + if len(teamsRemain) == 1: + theScores = [] + for team in self.teams: + theScores.append(team.score) + if teamsRemain[0].score < max(theScores): + pass + elif teamsRemain[0].score == max( + theScores) and theScores.count(max(theScores)) > 1: + pass + else: + self._round_end_timer = ba.Timer(0.5, self.end_game) + else: + self._round_end_timer = ba.Timer(0.5, self.end_game) + + def spawn_zombie(self) -> None: + #We need a Z height... + thePt = list(self.get_random_point_in_play()) + thePt2 = self.map.get_ffa_start_position(self.players) + thePt[1] = thePt2[1] + ba.timer(0.1, ba.Call( + self._bots.spawn_bot, BrawlerBot, pos=thePt, spawn_time=1.0)) + + def _onSpazBotDied(self,DeathMsg) -> None: + #Just in case we are over max... + if len(self._bots.get_living_bots()) < self._max_zombies: + self.zombieQ += 1 + + if DeathMsg.killerplayer is None: + pass + else: + player = DeathMsg.killerplayer + if not player: + return + if player.lives < 1: + return + player.team.score += 1 + self.zombieQ += 1 + self._update_scoreboard() + + def get_random_point_in_play(self) -> None: + myMap = self.map.getname() + if myMap == 'Doom Shroom': + while True: + x = random.uniform(-1.0,1.0) + y = random.uniform(-1.0,1.0) + if x*x+y*y < 1.0: break + return ((8.0*x,8.0,-3.5+5.0*y)) + elif myMap == 'Rampage': + x = random.uniform(-6.0,7.0) + y = random.uniform(-6.0,-2.5) + return ((x, 8.0, y)) + elif myMap == 'Hockey Stadium': + x = random.uniform(-11.5,11.5) + y = random.uniform(-4.5,4.5) + return ((x, 5.0, y)) + elif myMap == 'Courtyard': + x = random.uniform(-4.3,4.3) + y = random.uniform(-4.4,0.3) + return ((x, 8.0, y)) + elif myMap == 'Crag Castle': + x = random.uniform(-6.7,8.0) + y = random.uniform(-6.0,0.0) + return ((x, 12.0, y)) + elif myMap == 'Big G': + x = random.uniform(-8.7,8.0) + y = random.uniform(-7.5,6.5) + return ((x, 8.0, y)) + elif myMap == 'Football Stadium': + x = random.uniform(-12.5,12.5) + y = random.uniform(-5.0,5.5) + return ((x, 8.0, y)) + else: + x = random.uniform(-5.0,5.0) + y = random.uniform(-6.0,0.0) + return ((x, 8.0, y)) + + def _update_scoreboard(self) -> None: + for team in self.teams: + self._scoreboard.set_team_value(team, team.score) + + def _get_living_teams(self) -> list[Team]: + return [ + team for team in self.teams + if len(team.players) > 0 and any(player.lives > 0 + for player in team.players) + ] + + def end_game(self) -> None: + if self.has_ended(): + return + setattr(BrawlerBot, 'color', (0.6, 0.6, 0.6)) + setattr(BrawlerBot, 'highlight', (0.6, 0.6, 0.6)) + setattr(BrawlerBot, 'character', 'Kronk') + results = ba.GameResults() + self._vs_text = None # Kill our 'vs' if its there. + for team in self.teams: + results.set_team_score(team, team.score) + self.end(results=results) + + +# ba_meta export game +class ZombieHordeCoop(ZombieHorde): + + name = 'Zombie Horde' + + @classmethod + def get_supported_maps(cls, sessiontype: type[ba.Session]) -> list[str]: + return ['Football Stadium'] + + @classmethod + def supports_session_type(cls, sessiontype: type[ba.Session]) -> bool: + return (issubclass(sessiontype, ba.CoopSession)) + + def _update(self) -> None: + if self.zombieQ > 0: + self.zombieQ -= 1 + self.spawn_zombie() + if self._solo_mode: + # For both teams, find the first player on the spawn order + # list with lives remaining and spawn them if they're not alive. + for team in self.teams: + # Prune dead players from the spawn order. + team.spawn_order = [p for p in team.spawn_order if p] + for player in team.spawn_order: + assert isinstance(player, Player) + if player.lives > 0: + if not player.is_alive(): + self.spawn_player(player) + self._update_icons() + break + + if not any(player.is_alive() for player in self.teams[0].players): + self._round_end_timer = ba.Timer(0.5, self.end_game) + + def handlemessage(self, msg: Any) -> Any: + if isinstance(msg, ba.PlayerDiedMessage): + # Augment standard behavior. + ba.TeamGameActivity.handlemessage(self, msg) + player: Player = msg.getplayer(Player) + # If we have any icons, update their state. + for icon in player.icons: + icon.handle_player_died() + else: + super().handlemessage(msg) + + +# ba_meta export plugin +class ZombieHordeLevel(ba.Plugin): + def on_app_running(self) -> None: + ba.app.add_coop_practice_level( + ba.Level( + 'Zombie Horde', + gametype=ZombieHordeCoop, + settings={}, + preview_texture_name='footballStadiumPreview', + ) + ) From c052a1d7c14f43f68474edb180de10fbfcb6c9dc Mon Sep 17 00:00:00 2001 From: Loup-Garou911XD Date: Thu, 3 Nov 2022 17:29:43 +0000 Subject: [PATCH 0207/1464] [ci] auto-format --- plugins/minigames/BasketBomb.py | 279 +++++------ plugins/minigames/Boxing.py | 424 ++++++++--------- plugins/minigames/MeteorShower.py | 744 +++++++++++++++--------------- plugins/minigames/SimonSays.py | 293 +++++++----- plugins/minigames/SquidRace.py | 29 +- plugins/minigames/ZombieHorde.py | 66 +-- 6 files changed, 947 insertions(+), 888 deletions(-) diff --git a/plugins/minigames/BasketBomb.py b/plugins/minigames/BasketBomb.py index c9030e5a..78c35b8e 100644 --- a/plugins/minigames/BasketBomb.py +++ b/plugins/minigames/BasketBomb.py @@ -6,7 +6,8 @@ from typing import TYPE_CHECKING -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 @@ -19,42 +20,46 @@ bsuSpaz = None + def getlanguage(text, sub: str = ''): lang = _ba.app.lang.language translate = { - "Name": - {"Spanish": "Baloncesto", - "English": "Basketbomb", - "Portuguese": "Basketbomb"}, - "Info": - {"Spanish": "Anota todas las canastas y sé el MVP.", - "English": "Score all the baskets and be the MVP.", - "Portuguese": "Marque cada cesta e seja o MVP."}, - "Info-Short": - {"Spanish": f"Anota {sub} canasta(s) para ganar", - "English": f"Score {sub} baskets to win", - "Portuguese": f"Cestas de {sub} pontos para ganhar"}, - "S: Powerups": - {"Spanish": "Aparecer Potenciadores", - "English": "Powerups Spawn", - "Portuguese": "Habilitar Potenciadores"}, - "S: Velocity": + "Name": + {"Spanish": "Baloncesto", + "English": "Basketbomb", + "Portuguese": "Basketbomb"}, + "Info": + {"Spanish": "Anota todas las canastas y sé el MVP.", + "English": "Score all the baskets and be the MVP.", + "Portuguese": "Marque cada cesta e seja o MVP."}, + "Info-Short": + {"Spanish": f"Anota {sub} canasta(s) para ganar", + "English": f"Score {sub} baskets to win", + "Portuguese": f"Cestas de {sub} pontos para ganhar"}, + "S: Powerups": + {"Spanish": "Aparecer Potenciadores", + "English": "Powerups Spawn", + "Portuguese": "Habilitar Potenciadores"}, + "S: Velocity": {"Spanish": "Activar velocidad", "English": "Enable speed", "Portuguese": "Ativar velocidade"}, - } - - languages = ['Spanish','Portuguese','English'] - if lang not in languages: lang = 'English' + } + + languages = ['Spanish', 'Portuguese', 'English'] + if lang not in languages: + lang = 'English' if text not in translate: return text return translate[text][lang] + class BallDiedMessage: def __init__(self, ball: Ball): self.ball = ball + class Ball(ba.Actor): def __init__(self, position: Sequence[float] = (0.0, 1.0, 0.0)): super().__init__() @@ -62,14 +67,14 @@ def __init__(self, position: Sequence[float] = (0.0, 1.0, 0.0)): activity = self.getactivity() velocty = (0.0, 8.0, 0.0) _scale = 1.2 - + self._spawn_pos = (position[0], position[1] + 0.5, position[2]) self.last_players_to_touch: Dict[int, Player] = {} self.scored = False assert activity is not None assert isinstance(activity, BasketGame) - + pmats = [shared.object_material, activity.ball_material] self.node = ba.newnode('prop', delegate=self, @@ -132,14 +137,18 @@ class Team(ba.Team[Player]): def __init__(self) -> None: self.score = 0 + class Points: postes = dict() - postes['pal_0'] = (10.64702320098877, 0.0000000000000000, 0.0000000000000000) #10.736066818237305, 0.3002409040927887, 0.5281256437301636 + # 10.736066818237305, 0.3002409040927887, 0.5281256437301636 + postes['pal_0'] = (10.64702320098877, 0.0000000000000000, 0.0000000000000000) postes['pal_1'] = (-10.64702320098877, 0.0000000000000000, 0.0000000000000000) # ba_meta export game + + class BasketGame(ba.TeamGameActivity[Player, Team]): - + name = getlanguage('Name') description = getlanguage('Info') available_settings = [ @@ -202,7 +211,7 @@ def __init__(self, settings: dict): self._speed = bool(settings[getlanguage('S: Velocity')]) self._epic_mode = bool(settings['Epic Mode']) self.slow_motion = self._epic_mode - + self.ball_material = ba.Material() self.ball_material.add_actions(actions=(('modify_part_collision', 'friction', 0.5))) @@ -251,10 +260,10 @@ def on_begin(self) -> None: super().on_begin() self.setup_standard_time_limit(self._time_limit) - + if self._powerups: self.setup_standard_powerup_drops() - + self._ball_spawn_pos = self.map.get_flag_position(None) self._spawn_ball() @@ -336,7 +345,7 @@ def _handle_score(self, team_index: int = None) -> None: if team.score >= self._score_to_win: self.end_game() - #ba.playsound(self._foghorn_sound) + # ba.playsound(self._foghorn_sound) ba.playsound(self._cheer_sound) self._ball.scored = True @@ -366,8 +375,8 @@ def _update_scoreboard(self) -> None: winscore = self._score_to_win for id, team in enumerate(self.teams): self._scoreboard.set_team_value(team, team.score, winscore) - #self.postes(id) - + # self.postes(id) + def spawn_player(self, player: Player) -> ba.Actor: if bsuSpaz is None: spaz = self.spawn_player_spaz(player) @@ -375,7 +384,7 @@ def spawn_player(self, player: Player) -> ba.Actor: ps.PlayerSpaz = bsuSpaz.BskSpaz spaz = self.spawn_player_spaz(player) ps.PlayerSpaz = bsuSpaz.OldPlayerSpaz - + if self._speed: spaz.node.hockey = True return spaz @@ -393,9 +402,9 @@ def handlemessage(self, msg: Any) -> Any: def postes(self, team_id: int): if not hasattr(self._map, 'poste_'+str(team_id)): setattr(self._map, 'poste_'+str(team_id), - Palos(team=team_id, - position=Points.postes['pal_' + - str(team_id)]).autoretain()) + Palos(team=team_id, + position=Points.postes['pal_' + + str(team_id)]).autoretain()) def _flash_ball_spawn(self) -> None: light = ba.newnode('light', @@ -414,6 +423,7 @@ def _spawn_ball(self) -> None: assert self._ball_spawn_pos is not None self._ball = Ball(position=self._ball_spawn_pos) + class Aro(ba.Actor): def __init__(self, team: int = 0, position: Sequence[float] = (0.0, 1.0, 0.0)): @@ -422,7 +432,7 @@ def __init__(self, team: int = 0, shared = SharedObjects.get() setattr(self, 'team', team) setattr(self, 'locs', []) - + # Material Para; Traspasar Objetos self.no_collision = ba.Material() self.no_collision.add_actions( @@ -443,10 +453,10 @@ def __init__(self, team: int = 0, self._spawn_pos = (position[0], position[1], position[2]) self._materials_region0 = [self.collision, shared.footing_material] - + model = None tex = ba.gettexture('null') - + pmats = [self.no_collision] self.node = ba.newnode('prop', delegate=self, @@ -459,55 +469,56 @@ def __init__(self, team: int = 0, 'shadow_size': 0.1, 'position': self._spawn_pos, 'materials': pmats}) - + self.scale = scale = 1.4 ba.animate(self.node, 'model_scale', {0: 0}) pos = (position[0], position[1]+0.6, position[2]) self.regions: List[ba.Node] = [ ba.newnode('region', - attrs={'position': position, - 'scale': (0.6, 0.05, 0.6), - 'type': 'box', - 'materials': self._materials_region0}), - + attrs={'position': position, + 'scale': (0.6, 0.05, 0.6), + 'type': 'box', + 'materials': self._materials_region0}), + ba.newnode('region', - attrs={'position': pos, - 'scale': (0.5, 0.3, 0.9), - 'type': 'box', - 'materials': [self._score_region_material]}) - ] + attrs={'position': pos, + 'scale': (0.5, 0.3, 0.9), + 'type': 'box', + 'materials': [self._score_region_material]}) + ] self.regions[0].connectattr('position', self.node, 'position') #self.regions[0].connectattr('position', self.regions[1], 'position') locs_count = 9 pos = list(position) - + try: id = 0 if team == 1 else 1 color = act.teams[id].color - except: color = (1,1,1) - + except: + color = (1, 1, 1) + while locs_count > 1: scale = (1.5 * 0.1 * locs_count) + 0.8 self.locs.append(ba.newnode('locator', - owner=self.node, - attrs={'shape': 'circleOutline', - 'position': pos, - 'color': color, - 'opacity': 1.0, - 'size': [scale], - 'draw_beauty': True, - 'additive': False})) - + owner=self.node, + attrs={'shape': 'circleOutline', + 'position': pos, + 'color': color, + 'opacity': 1.0, + 'size': [scale], + 'draw_beauty': True, + 'additive': False})) + pos[1] -= 0.1 locs_count -= 1 - + def _annotation(self): assert len(self.regions) >= 2 ball = self.getactivity()._ball - + if ball: p = self.regions[0].position ball.node.position = p @@ -523,6 +534,7 @@ def handlemessage(self, msg: Any) -> Any: else: super().handlemessage(msg) + class Cuadro(ba.Actor): def __init__(self, team: int = 0, position: Sequence[float] = (0.0, 1.0, 0.0)): @@ -536,13 +548,13 @@ def __init__(self, team: int = 0, actions=(('modify_part_collision', 'collide', True))) pos = (position[0], position[1]+0.9, position[2]+1.5) - self.region: ba.Node = ba.newnode('region', - attrs={'position': pos, - 'scale': (0.5, 2.7, 2.5), - 'type': 'box', - 'materials': [self.collision, - shared.footing_material]}) - + self.region: ba.Node = ba.newnode('region', + attrs={'position': pos, + 'scale': (0.5, 2.7, 2.5), + 'type': 'box', + 'materials': [self.collision, + shared.footing_material]}) + #self.shield = ba.newnode('shield', attrs={'radius': 1.0, 'color': (0,10,0)}) #self.region.connectattr('position', self.shield, 'position') @@ -550,38 +562,38 @@ def __init__(self, team: int = 0, pos = list(position) oldpos = list(position) old_count = 14 - + count = old_count count_y = 9 try: id = 0 if team == 1 else 1 color = act.teams[id].color - except: color = (1,1,1) + except: + color = (1, 1, 1) - while(count_y != 1): + while (count_y != 1): - while(count != 1): + while (count != 1): pos[2] += 0.19 - + self.locs.append( ba.newnode('locator', - owner=self.region, - attrs={'shape': 'circle', - 'position': pos, - 'size': [0.5], - 'color': color, - 'opacity': 1.0, - 'draw_beauty': True, - 'additive': False})) + owner=self.region, + attrs={'shape': 'circle', + 'position': pos, + 'size': [0.5], + 'color': color, + 'opacity': 1.0, + 'draw_beauty': True, + 'additive': False})) count -= 1 - count = old_count pos[1] += 0.2 pos[2] = oldpos[2] count_y -= 1 - + def handlemessage(self, msg: Any) -> Any: if isinstance(msg, ba.DieMessage): if self.node.exists(): @@ -589,6 +601,7 @@ def handlemessage(self, msg: Any) -> Any: else: super().handlemessage(msg) + class Palos(ba.Actor): def __init__(self, team: int = 0, position: Sequence[float] = (0.0, 1.0, 0.0)): @@ -604,17 +617,17 @@ def __init__(self, team: int = 0, self.no_collision.add_actions( actions=(('modify_part_collision', 'collide', False))) - # + # self.collision = ba.Material() self.collision.add_actions( actions=(('modify_part_collision', 'collide', True))) # Spawn just above the provided point. self._spawn_pos = (position[0], position[2]+2.5, position[2]) - + model = ba.getmodel('flagPole') tex = ba.gettexture('flagPoleColor') - + pmats = [self.no_collision] self.node = ba.newnode('prop', delegate=self, @@ -633,34 +646,35 @@ def __init__(self, team: int = 0, ba.animate(self.node, 'model_scale', {0: scale}) self.loc = ba.newnode('locator', - owner=self.node, - attrs={'shape': 'circle', - 'position': position, - 'color': (1,1,0), - 'opacity': 1.0, - 'draw_beauty': False, - 'additive': True}) + owner=self.node, + attrs={'shape': 'circle', + 'position': position, + 'color': (1, 1, 0), + 'opacity': 1.0, + 'draw_beauty': False, + 'additive': True}) self._y = _y = 0.30 _x = -0.25 if team == 1 else 0.25 _pos = (position[0]+_x, position[1]-1.5 + _y, position[2]) self.region = ba.newnode('region', - attrs={ - 'position': _pos, - 'scale': (0.4, 8, 0.4), - 'type': 'box', - 'materials': [self.collision]}) + attrs={ + 'position': _pos, + 'scale': (0.4, 8, 0.4), + 'type': 'box', + 'materials': [self.collision]}) self.region.connectattr('position', self.node, 'position') _y = self._y position = self._pos if team == 0: pos = (position[0]-0.8, position[1] + 2.0 + _y, position[2]) - else: pos = (position[0]+0.8, position[1] + 2.0 + _y, position[2]) - + else: + pos = (position[0]+0.8, position[1] + 2.0 + _y, position[2]) + if self.aro is None: self.aro = Aro(team, pos).autoretain() - + if self.cua is None: pos = (position[0], position[1] + 1.8 + _y, position[2]-1.4) self.cua = Cuadro(team, pos).autoretain() @@ -670,7 +684,8 @@ def handlemessage(self, msg: Any) -> Any: if self.node.exists(): self.node.delete() else: - super().handlemessage(msg) + super().handlemessage(msg) + class BasketMap(maps.FootballStadium): name = 'BasketBall Stadium' @@ -682,7 +697,7 @@ def get_play_types(cls) -> List[str]: def __init__(self) -> None: super().__init__() - + gnode = ba.getactivity().globalsnode gnode.tint = [(0.806, 0.8, 1.0476), (1.3, 1.2, 1.0)][0] gnode.ambient_color = (1.3, 1.2, 1.0) @@ -691,13 +706,14 @@ def __init__(self) -> None: gnode.vr_camera_offset = (0, -0.8, -1.1) gnode.vr_near_clip = 0.5 + class BasketMapV2(maps.HockeyStadium): name = 'BasketBall Stadium V2' def __init__(self) -> None: super().__init__() - - shared = SharedObjects.get() + + shared = SharedObjects.get() self.node.materials = [shared.footing_material] self.node.collide_model = ba.getcollidemodel('footballStadiumCollide') self.node.model = None @@ -705,13 +721,13 @@ def __init__(self) -> None: self.floor.reflection = 'soft' self.floor.reflection_scale = [1.6] self.floor.color = (1.1, 0.05, 0.8) - + self.background = ba.newnode('terrain', - attrs={'model': ba.getmodel('thePadBG'), - 'lighting': False, - 'background': True, - 'color': (1.0, 0.2, 1.0), - 'color_texture': ba.gettexture('menuBG')}) + attrs={'model': ba.getmodel('thePadBG'), + 'lighting': False, + 'background': True, + 'color': (1.0, 0.2, 1.0), + 'color_texture': ba.gettexture('menuBG')}) gnode = ba.getactivity().globalsnode gnode.floor_reflection = True @@ -729,26 +745,27 @@ def __init__(self) -> None: self.collision = ba.Material() self.collision.add_actions( actions=(('modify_part_collision', 'collide', True))) - + self.regions: List[ba.Node] = [ ba.newnode('region', - attrs={'position': (12.676897048950195, 0.2997918128967285, 5.583303928375244), - 'scale': (1.01, 12, 28), - 'type': 'box', - 'materials': [self.collision]}), - + attrs={'position': (12.676897048950195, 0.2997918128967285, 5.583303928375244), + 'scale': (1.01, 12, 28), + 'type': 'box', + 'materials': [self.collision]}), + ba.newnode('region', - attrs={'position': (11.871315956115723, 0.29975247383117676, 5.711406707763672), - 'scale': (50, 12, 0.9), - 'type': 'box', - 'materials': [self.collision]}), - + attrs={'position': (11.871315956115723, 0.29975247383117676, 5.711406707763672), + 'scale': (50, 12, 0.9), + 'type': 'box', + 'materials': [self.collision]}), + ba.newnode('region', - attrs={'position': (-12.776557922363281, 0.30036890506744385, 4.96237850189209), - 'scale': (1.01, 12, 28), - 'type': 'box', - 'materials': [self.collision]}), - ] + attrs={'position': (-12.776557922363281, 0.30036890506744385, 4.96237850189209), + 'scale': (1.01, 12, 28), + 'type': 'box', + 'materials': [self.collision]}), + ] + ba._map.register_map(BasketMap) -ba._map.register_map(BasketMapV2) \ No newline at end of file +ba._map.register_map(BasketMapV2) diff --git a/plugins/minigames/Boxing.py b/plugins/minigames/Boxing.py index 0a6a4b21..35a7c759 100644 --- a/plugins/minigames/Boxing.py +++ b/plugins/minigames/Boxing.py @@ -11,230 +11,230 @@ from bastd.game.deathmatch import DeathMatchGame if TYPE_CHECKING: - from typing import Any, Sequence + from typing import Any, Sequence lang = ba.app.lang.language if lang == 'Spanish': - name = 'Super Boxeo' - description = ('¡Sin bombas!\n' - '¡Noquea a los enemigos con tus propias manos!\n') - super_jump_text = 'Super Salto' - enable_powerups = 'Habilitar Potenciadores' + name = 'Super Boxeo' + description = ('¡Sin bombas!\n' + '¡Noquea a los enemigos con tus propias manos!\n') + super_jump_text = 'Super Salto' + enable_powerups = 'Habilitar Potenciadores' else: - name = 'Super Boxing' - description = ('No bombs!\n' - 'Knock out your enemies using your bare hands!\n') - super_jump_text = 'Super Jump' - enable_powerups = 'Enable Powerups' + name = 'Super Boxing' + description = ('No bombs!\n' + 'Knock out your enemies using your bare hands!\n') + super_jump_text = 'Super Jump' + enable_powerups = 'Enable Powerups' class NewPlayerSpaz(PlayerSpaz): - def __init__(self, - player: ba.Player, - color: Sequence[float] = (1.0, 1.0, 1.0), - highlight: Sequence[float] = (0.5, 0.5, 0.5), - character: str = 'Spaz', - powerups_expire: bool = True, - super_jump: bool = False): - super().__init__(player=player, - color=color, - highlight=highlight, - character=character, - powerups_expire=powerups_expire) - from bastd.gameutils import SharedObjects - shared = SharedObjects.get() - self._super_jump = super_jump - self.jump_mode = False - self.super_jump_material = ba.Material() - self.super_jump_material.add_actions( - conditions=('they_have_material', shared.footing_material), - actions=( - ('call', 'at_connect', ba.Call(self.jump_state, True)), - ('call', 'at_disconnect', ba.Call(self.jump_state, False)) - ), - ) - self.node.roller_materials += (self.super_jump_material, ) - - def jump_state(self, mode: bool) -> None: - self.jump_mode = mode - - def on_jump_press(self) -> None: - """ - Called to 'press jump' on this spaz; - used by player or AI connections. - """ - if not self.node: - return - t_ms = ba.time(timeformat=ba.TimeFormat.MILLISECONDS) - assert isinstance(t_ms, int) - if t_ms - self.last_jump_time_ms >= self._jump_cooldown: - self.node.jump_pressed = True - self.last_jump_time_ms = t_ms - if self._player.is_alive() and self.jump_mode and ( - self._super_jump): - def do_jump(): - self.node.handlemessage( - 'impulse', - self.node.position[0], - self.node.position[1], - self.node.position[2], - 0, 0, 0, 150, 150, 0, 0, 0, 1, 0 - ) - ba.timer(0.0, do_jump) - ba.timer(0.1, do_jump) - ba.timer(0.2, do_jump) - self._turbo_filter_add_press('jump') + def __init__(self, + player: ba.Player, + color: Sequence[float] = (1.0, 1.0, 1.0), + highlight: Sequence[float] = (0.5, 0.5, 0.5), + character: str = 'Spaz', + powerups_expire: bool = True, + super_jump: bool = False): + super().__init__(player=player, + color=color, + highlight=highlight, + character=character, + powerups_expire=powerups_expire) + from bastd.gameutils import SharedObjects + shared = SharedObjects.get() + self._super_jump = super_jump + self.jump_mode = False + self.super_jump_material = ba.Material() + self.super_jump_material.add_actions( + conditions=('they_have_material', shared.footing_material), + actions=( + ('call', 'at_connect', ba.Call(self.jump_state, True)), + ('call', 'at_disconnect', ba.Call(self.jump_state, False)) + ), + ) + self.node.roller_materials += (self.super_jump_material, ) + + def jump_state(self, mode: bool) -> None: + self.jump_mode = mode + + def on_jump_press(self) -> None: + """ + Called to 'press jump' on this spaz; + used by player or AI connections. + """ + if not self.node: + return + t_ms = ba.time(timeformat=ba.TimeFormat.MILLISECONDS) + assert isinstance(t_ms, int) + if t_ms - self.last_jump_time_ms >= self._jump_cooldown: + self.node.jump_pressed = True + self.last_jump_time_ms = t_ms + if self._player.is_alive() and self.jump_mode and ( + self._super_jump): + def do_jump(): + self.node.handlemessage( + 'impulse', + self.node.position[0], + self.node.position[1], + self.node.position[2], + 0, 0, 0, 150, 150, 0, 0, 0, 1, 0 + ) + ba.timer(0.0, do_jump) + ba.timer(0.1, do_jump) + ba.timer(0.2, do_jump) + self._turbo_filter_add_press('jump') # ba_meta export game class BoxingGame(DeathMatchGame): - name = name - description = description - - @classmethod - def get_available_settings( - cls, sessiontype: type[ba.Session] - ) -> list[ba.Setting]: - settings = [ - ba.IntSetting( - 'Kills to Win Per Player', - 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', 4.0), - ], - default=1.0, - ), - ba.BoolSetting(super_jump_text, default=False), - ba.BoolSetting(enable_powerups, default=False), - ba.BoolSetting('Epic Mode', default=False), - ] - - # In teams mode, a suicide gives a point to the other team, but in - # free-for-all it subtracts from your own score. By default we clamp - # this at zero to benefit new players, but pro players might like to - # be able to go negative. (to avoid a strategy of just - # suiciding until you get a good drop) - if issubclass(sessiontype, ba.FreeForAllSession): - settings.append( - ba.BoolSetting('Allow Negative Scores', default=False) - ) - - return settings - - def __init__(self, settings: dict): - super().__init__(settings) - self._scoreboard = Scoreboard() - self._score_to_win: int | None = None - self._dingsound = ba.getsound('dingSmall') - self._epic_mode = bool(settings['Epic Mode']) - self._kills_to_win_per_player = int(settings['Kills to Win Per Player']) - self._time_limit = float(settings['Time Limit']) - self._allow_negative_scores = bool( - settings.get('Allow Negative Scores', False) - ) - self._super_jump = bool(settings[super_jump_text]) - self._enable_powerups = bool(settings[enable_powerups]) - - # Base class overrides. - self.slow_motion = self._epic_mode - self.default_music = ( - ba.MusicType.EPIC if self._epic_mode else ba.MusicType.TO_THE_DEATH - ) - - def on_begin(self) -> None: - ba.TeamGameActivity.on_begin(self) - self.setup_standard_time_limit(self._time_limit) - if self._enable_powerups: - self.setup_standard_powerup_drops() - - # Base kills needed to win on the size of the largest team. - self._score_to_win = self._kills_to_win_per_player * max( - 1, max(len(t.players) for t in self.teams) - ) - self._update_scoreboard() - - def _standard_drop_powerup(self, index: int, expire: bool = True) -> None: - # pylint: disable=cyclic-import - from bastd.actor.powerupbox import PowerupBox, PowerupBoxFactory - - PowerupBox( - position=self.map.powerup_spawn_points[index], - poweruptype=PowerupBoxFactory.get().get_random_powerup_type( - excludetypes=['triple_bombs','ice_bombs','impact_bombs', - 'land_mines','sticky_bombs','punch'] - ), - expire=expire, - ).autoretain() - - def spawn_player(self, player: Player) -> ba.Actor: - import random - from ba import _math - from ba._gameutils import animate - from ba._coopsession import CoopSession - - if isinstance(self.session, ba.DualTeamSession): - position = self.map.get_start_position(player.team.id) - else: - # otherwise do free-for-all spawn locations - position = self.map.get_ffa_start_position(self.players) - angle = None - name = player.getname() - color = player.color - highlight = player.highlight - - light_color = _math.normalized_color(color) - display_color = ba.safecolor(color, target_intensity=0.75) - - spaz = NewPlayerSpaz(color=color, - highlight=highlight, - character=player.character, - player=player, - super_jump=self._super_jump) - - player.actor = spaz - assert spaz.node - - spaz.node.name = name - spaz.node.name_color = display_color - - # Move to the stand position and add a flash of light. - spaz.handlemessage( - ba.StandMessage( - position, - angle if angle is not None else random.uniform(0, 360))) - ba.playsound(self._spawn_sound, 1, position=spaz.node.position) - light = ba.newnode('light', attrs={'color': light_color}) - spaz.node.connectattr('position', light, 'position') - animate(light, 'intensity', {0: 0, 0.25: 1, 0.5: 0}) - ba.timer(0.5, light.delete) - - # custom - spaz.connect_controls_to_player(enable_bomb=False) - spaz.equip_boxing_gloves() - - return spaz + name = name + description = description + + @classmethod + def get_available_settings( + cls, sessiontype: type[ba.Session] + ) -> list[ba.Setting]: + settings = [ + ba.IntSetting( + 'Kills to Win Per Player', + 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', 4.0), + ], + default=1.0, + ), + ba.BoolSetting(super_jump_text, default=False), + ba.BoolSetting(enable_powerups, default=False), + ba.BoolSetting('Epic Mode', default=False), + ] + + # In teams mode, a suicide gives a point to the other team, but in + # free-for-all it subtracts from your own score. By default we clamp + # this at zero to benefit new players, but pro players might like to + # be able to go negative. (to avoid a strategy of just + # suiciding until you get a good drop) + if issubclass(sessiontype, ba.FreeForAllSession): + settings.append( + ba.BoolSetting('Allow Negative Scores', default=False) + ) + + return settings + + def __init__(self, settings: dict): + super().__init__(settings) + self._scoreboard = Scoreboard() + self._score_to_win: int | None = None + self._dingsound = ba.getsound('dingSmall') + self._epic_mode = bool(settings['Epic Mode']) + self._kills_to_win_per_player = int(settings['Kills to Win Per Player']) + self._time_limit = float(settings['Time Limit']) + self._allow_negative_scores = bool( + settings.get('Allow Negative Scores', False) + ) + self._super_jump = bool(settings[super_jump_text]) + self._enable_powerups = bool(settings[enable_powerups]) + + # Base class overrides. + self.slow_motion = self._epic_mode + self.default_music = ( + ba.MusicType.EPIC if self._epic_mode else ba.MusicType.TO_THE_DEATH + ) + + def on_begin(self) -> None: + ba.TeamGameActivity.on_begin(self) + self.setup_standard_time_limit(self._time_limit) + if self._enable_powerups: + self.setup_standard_powerup_drops() + + # Base kills needed to win on the size of the largest team. + self._score_to_win = self._kills_to_win_per_player * max( + 1, max(len(t.players) for t in self.teams) + ) + self._update_scoreboard() + + def _standard_drop_powerup(self, index: int, expire: bool = True) -> None: + # pylint: disable=cyclic-import + from bastd.actor.powerupbox import PowerupBox, PowerupBoxFactory + + PowerupBox( + position=self.map.powerup_spawn_points[index], + poweruptype=PowerupBoxFactory.get().get_random_powerup_type( + excludetypes=['triple_bombs', 'ice_bombs', 'impact_bombs', + 'land_mines', 'sticky_bombs', 'punch'] + ), + expire=expire, + ).autoretain() + + def spawn_player(self, player: Player) -> ba.Actor: + import random + from ba import _math + from ba._gameutils import animate + from ba._coopsession import CoopSession + + if isinstance(self.session, ba.DualTeamSession): + position = self.map.get_start_position(player.team.id) + else: + # otherwise do free-for-all spawn locations + position = self.map.get_ffa_start_position(self.players) + angle = None + name = player.getname() + color = player.color + highlight = player.highlight + + light_color = _math.normalized_color(color) + display_color = ba.safecolor(color, target_intensity=0.75) + + spaz = NewPlayerSpaz(color=color, + highlight=highlight, + character=player.character, + player=player, + super_jump=self._super_jump) + + player.actor = spaz + assert spaz.node + + spaz.node.name = name + spaz.node.name_color = display_color + + # Move to the stand position and add a flash of light. + spaz.handlemessage( + ba.StandMessage( + position, + angle if angle is not None else random.uniform(0, 360))) + ba.playsound(self._spawn_sound, 1, position=spaz.node.position) + light = ba.newnode('light', attrs={'color': light_color}) + spaz.node.connectattr('position', light, 'position') + animate(light, 'intensity', {0: 0, 0.25: 1, 0.5: 0}) + ba.timer(0.5, light.delete) + + # custom + spaz.connect_controls_to_player(enable_bomb=False) + spaz.equip_boxing_gloves() + + return spaz diff --git a/plugins/minigames/MeteorShower.py b/plugins/minigames/MeteorShower.py index 149f2a91..0f87f397 100644 --- a/plugins/minigames/MeteorShower.py +++ b/plugins/minigames/MeteorShower.py @@ -11,396 +11,396 @@ from bastd.actor.onscreentimer import OnScreenTimer if TYPE_CHECKING: - from typing import Any, Sequence + from typing import Any, Sequence lang = ba.app.lang.language if lang == 'Spanish': - name = 'Lluvia de Meteoritos v2' - bomb_type = 'Tipo de Bomba' - ice = 'hielo' - sticky = 'pegajosa' - impact = 'insta-bomba' - land_mine = 'mina terrestre' - random_bomb = 'aleatoria' - normal_rain = 'Lluvia Normal' - frozen_rain = 'Lluvia Congelada' - sticky_rain = 'Lluvia Pegajosa' - impact_rain = 'Lluvia de Impacto' - mine_rain = 'Lluvia de Minas' - tnt_rain = 'Lluvia de TNT' - random_rain = 'Lluvia Aleatoria' + name = 'Lluvia de Meteoritos v2' + bomb_type = 'Tipo de Bomba' + ice = 'hielo' + sticky = 'pegajosa' + impact = 'insta-bomba' + land_mine = 'mina terrestre' + random_bomb = 'aleatoria' + normal_rain = 'Lluvia Normal' + frozen_rain = 'Lluvia Congelada' + sticky_rain = 'Lluvia Pegajosa' + impact_rain = 'Lluvia de Impacto' + mine_rain = 'Lluvia de Minas' + tnt_rain = 'Lluvia de TNT' + random_rain = 'Lluvia Aleatoria' else: - name = 'Meteor Shower v2' - bomb_type = 'Bomb Type' - ice = 'ice' - sticky = 'sticky' - impact = 'impact' - land_mine = 'land mine' - random_bomb = 'random' - normal_rain = 'Normal Rain' - frozen_rain = 'Frozen Rain' - sticky_rain = 'Sticky Rain' - impact_rain = 'Impact Rain' - mine_rain = 'Mine Rain' - tnt_rain = 'TNT Rain' - random_rain = 'Random Rain' + name = 'Meteor Shower v2' + bomb_type = 'Bomb Type' + ice = 'ice' + sticky = 'sticky' + impact = 'impact' + land_mine = 'land mine' + random_bomb = 'random' + normal_rain = 'Normal Rain' + frozen_rain = 'Frozen Rain' + sticky_rain = 'Sticky Rain' + impact_rain = 'Impact Rain' + mine_rain = 'Mine Rain' + tnt_rain = 'TNT Rain' + random_rain = 'Random Rain' class Player(ba.Player['Team']): - """Our player type for this game.""" + """Our player type for this game.""" - def __init__(self) -> None: - super().__init__() - self.death_time: float | None = None + def __init__(self) -> None: + super().__init__() + self.death_time: float | None = None class Team(ba.Team[Player]): - """Our team type for this game.""" + """Our team type for this game.""" # ba_meta export game class MeteorShowerv2Game(ba.TeamGameActivity[Player, Team]): - """Minigame involving dodging falling bombs.""" - - name = name - description = 'Dodge the falling bombs.' - scoreconfig = ba.ScoreConfig( - label='Survived', scoretype=ba.ScoreType.MILLISECONDS, version='B' - ) - - # Print messages when players die (since its meaningful in this game). - announce_player_deaths = True - - # Don't allow joining after we start - # (would enable leave/rejoin tomfoolery). - allow_mid_activity_joins = False - - @classmethod - def get_available_settings( - cls, sessiontype: type[ba.Session] - ) -> list[ba.Setting]: - settings = [ - ba.IntChoiceSetting( - bomb_type, - choices=[ - ('normal', 0), - (ice, 1), - (sticky, 2), - (impact, 3), - (land_mine, 4), - ('tnt', 5), - (random_bomb, 6) - ], - default=0, - ), - ba.BoolSetting('Epic Mode', default=False), - ] - return settings - - # We're currently hard-coded for one map. - @classmethod - def get_supported_maps(cls, sessiontype: type[ba.Session]) -> list[str]: - return ['Rampage'] - - # We support teams, free-for-all, and co-op sessions. - @classmethod - def supports_session_type(cls, sessiontype: type[ba.Session]) -> bool: - return ( - issubclass(sessiontype, ba.DualTeamSession) - or issubclass(sessiontype, ba.FreeForAllSession) - or issubclass(sessiontype, ba.CoopSession) - ) - - def __init__(self, settings: dict): - super().__init__(settings) - btype = int(settings[bomb_type]) - if btype == 0: - newbtype = 'normal' - elif btype == 1: - newbtype = 'ice' - elif btype == 2: - newbtype = 'sticky' - elif btype == 3: - newbtype = 'impact' - elif btype == 4: - newbtype = 'land_mine' - elif btype == 5: - newbtype = 'tnt' - else: - newbtype = 'random' - self._bomb_type = newbtype - self._epic_mode = settings.get('Epic Mode', False) - self._last_player_death_time: float | None = None - self._meteor_time = 2.0 - self._timer: OnScreenTimer | None = None - - # Some base class overrides: - self.default_music = ( - ba.MusicType.EPIC if self._epic_mode else ba.MusicType.SURVIVAL - ) - if self._epic_mode: - self.slow_motion = True - - def on_begin(self) -> None: - super().on_begin() - - # Drop a wave every few seconds.. and every so often drop the time - # between waves ..lets have things increase faster if we have fewer - # players. - delay = 5.0 if len(self.players) > 2 else 2.5 - if self._epic_mode: - delay *= 0.25 - ba.timer(delay, self._decrement_meteor_time, repeat=True) - - # Kick off the first wave in a few seconds. - delay = 3.0 - if self._epic_mode: - delay *= 0.25 - ba.timer(delay, self._set_meteor_timer) - - self._timer = OnScreenTimer() - self._timer.start() - - # Check for immediate end (if we've only got 1 player, etc). - ba.timer(5.0, self._check_end_game) - - def on_player_leave(self, player: Player) -> None: - # Augment default behavior. - super().on_player_leave(player) - - # A departing player may trigger game-over. - self._check_end_game() - - # overriding the default character spawning.. - def spawn_player(self, player: Player) -> ba.Actor: - spaz = self.spawn_player_spaz(player) - - # Let's reconnect this player's controls to this - # spaz but *without* the ability to attack or pick stuff up. - spaz.connect_controls_to_player( - enable_punch=False, enable_bomb=False, enable_pickup=False - ) - - # Also lets have them make some noise when they die. - spaz.play_big_death_sound = True - return spaz - - # Various high-level game events come through this method. - def handlemessage(self, msg: Any) -> Any: - if isinstance(msg, ba.PlayerDiedMessage): - - # Augment standard behavior. - super().handlemessage(msg) - - curtime = ba.time() - - # Record the player's moment of death. - # assert isinstance(msg.spaz.player - msg.getplayer(Player).death_time = curtime - - # In co-op mode, end the game the instant everyone dies - # (more accurate looking). - # In teams/ffa, allow a one-second fudge-factor so we can - # get more draws if players die basically at the same time. - if isinstance(self.session, ba.CoopSession): - # Teams will still show up if we check now.. check in - # the next cycle. - ba.pushcall(self._check_end_game) - - # Also record this for a final setting of the clock. - self._last_player_death_time = curtime - else: - ba.timer(1.0, self._check_end_game) - - else: - # Default handler: - return super().handlemessage(msg) - return None - - def _check_end_game(self) -> None: - living_team_count = 0 - for team in self.teams: - for player in team.players: - if player.is_alive(): - living_team_count += 1 - break - - # In co-op, we go till everyone is dead.. otherwise we go - # until one team remains. - if isinstance(self.session, ba.CoopSession): - if living_team_count <= 0: - self.end_game() - else: - if living_team_count <= 1: - self.end_game() - - def _set_meteor_timer(self) -> None: - ba.timer( - (1.0 + 0.2 * random.random()) * self._meteor_time, - self._drop_bomb_cluster, - ) - - def _drop_bomb_cluster(self) -> None: - - # Random note: code like this is a handy way to plot out extents - # and debug things. - loc_test = False - if loc_test: - ba.newnode('locator', attrs={'position': (8, 6, -5.5)}) - ba.newnode('locator', attrs={'position': (8, 6, -2.3)}) - ba.newnode('locator', attrs={'position': (-7.3, 6, -5.5)}) - ba.newnode('locator', attrs={'position': (-7.3, 6, -2.3)}) - - # Drop several bombs in series. - delay = 0.0 - for _i in range(random.randrange(1, 3)): - # Drop them somewhere within our bounds with velocity pointing - # toward the opposite side. - pos = ( - -7.3 + 15.3 * random.random(), - 11, - -5.57 + 2.1 * random.random(), - ) - dropdir = -1.0 if pos[0] > 0 else 1.0 - vel = ( - (-5.0 + random.random() * 30.0) * dropdir, - random.uniform(-3.066, -4.12), - 0, - ) - ba.timer(delay, ba.Call(self._drop_bomb, pos, vel)) - delay += 0.1 - self._set_meteor_timer() - - def _drop_bomb( - self, position: Sequence[float], velocity: Sequence[float] - ) -> None: - if self._bomb_type == 'tnt': - bomb_type = random.choice(['tnt','tnt','tnt','tnt','impact']) - elif self._bomb_type == 'land_mine': - bomb_type = random.choice([ - 'land_mine','land_mine','land_mine','land_mine','impact']) - elif self._bomb_type == 'random': - bomb_type = random.choice([ - 'normal','ice','sticky','impact','land_mine','tnt']) - else: - bomb_type = self._bomb_type - Bomb(position=position, - velocity=velocity, - bomb_type=bomb_type).autoretain() - - def _decrement_meteor_time(self) -> None: - self._meteor_time = max(0.01, self._meteor_time * 0.9) - - def end_game(self) -> None: - cur_time = ba.time() - assert self._timer is not None - start_time = self._timer.getstarttime() - - # Mark death-time as now for any still-living players - # and award players points for how long they lasted. - # (these per-player scores are only meaningful in team-games) - for team in self.teams: - for player in team.players: - survived = False - - # Throw an extra fudge factor in so teams that - # didn't die come out ahead of teams that did. - if player.death_time is None: - survived = True - player.death_time = cur_time + 1 - - # Award a per-player score depending on how many seconds - # they lasted (per-player scores only affect teams mode; - # everywhere else just looks at the per-team score). - score = int(player.death_time - self._timer.getstarttime()) - if survived: - score += 50 # A bit extra for survivors. - self.stats.player_scored(player, score, screenmessage=False) - - # Stop updating our time text, and set the final time to match - # exactly when our last guy died. - self._timer.stop(endtime=self._last_player_death_time) - - # Ok now calc game results: set a score for each team and then tell - # the game to end. - results = ba.GameResults() - - # Remember that 'free-for-all' mode is simply a special form - # of 'teams' mode where each player gets their own team, so we can - # just always deal in teams and have all cases covered. - for team in self.teams: - - # Set the team score to the max time survived by any player on - # that team. - longest_life = 0.0 - for player in team.players: - assert player.death_time is not None - longest_life = max(longest_life, player.death_time - start_time) - - # Submit the score value in milliseconds. - results.set_team_score(team, int(1000.0 * longest_life)) - - self.end(results=results) + """Minigame involving dodging falling bombs.""" + + name = name + description = 'Dodge the falling bombs.' + scoreconfig = ba.ScoreConfig( + label='Survived', scoretype=ba.ScoreType.MILLISECONDS, version='B' + ) + + # Print messages when players die (since its meaningful in this game). + announce_player_deaths = True + + # Don't allow joining after we start + # (would enable leave/rejoin tomfoolery). + allow_mid_activity_joins = False + + @classmethod + def get_available_settings( + cls, sessiontype: type[ba.Session] + ) -> list[ba.Setting]: + settings = [ + ba.IntChoiceSetting( + bomb_type, + choices=[ + ('normal', 0), + (ice, 1), + (sticky, 2), + (impact, 3), + (land_mine, 4), + ('tnt', 5), + (random_bomb, 6) + ], + default=0, + ), + ba.BoolSetting('Epic Mode', default=False), + ] + return settings + + # We're currently hard-coded for one map. + @classmethod + def get_supported_maps(cls, sessiontype: type[ba.Session]) -> list[str]: + return ['Rampage'] + + # We support teams, free-for-all, and co-op sessions. + @classmethod + def supports_session_type(cls, sessiontype: type[ba.Session]) -> bool: + return ( + issubclass(sessiontype, ba.DualTeamSession) + or issubclass(sessiontype, ba.FreeForAllSession) + or issubclass(sessiontype, ba.CoopSession) + ) + + def __init__(self, settings: dict): + super().__init__(settings) + btype = int(settings[bomb_type]) + if btype == 0: + newbtype = 'normal' + elif btype == 1: + newbtype = 'ice' + elif btype == 2: + newbtype = 'sticky' + elif btype == 3: + newbtype = 'impact' + elif btype == 4: + newbtype = 'land_mine' + elif btype == 5: + newbtype = 'tnt' + else: + newbtype = 'random' + self._bomb_type = newbtype + self._epic_mode = settings.get('Epic Mode', False) + self._last_player_death_time: float | None = None + self._meteor_time = 2.0 + self._timer: OnScreenTimer | None = None + + # Some base class overrides: + self.default_music = ( + ba.MusicType.EPIC if self._epic_mode else ba.MusicType.SURVIVAL + ) + if self._epic_mode: + self.slow_motion = True + + def on_begin(self) -> None: + super().on_begin() + + # Drop a wave every few seconds.. and every so often drop the time + # between waves ..lets have things increase faster if we have fewer + # players. + delay = 5.0 if len(self.players) > 2 else 2.5 + if self._epic_mode: + delay *= 0.25 + ba.timer(delay, self._decrement_meteor_time, repeat=True) + + # Kick off the first wave in a few seconds. + delay = 3.0 + if self._epic_mode: + delay *= 0.25 + ba.timer(delay, self._set_meteor_timer) + + self._timer = OnScreenTimer() + self._timer.start() + + # Check for immediate end (if we've only got 1 player, etc). + ba.timer(5.0, self._check_end_game) + + def on_player_leave(self, player: Player) -> None: + # Augment default behavior. + super().on_player_leave(player) + + # A departing player may trigger game-over. + self._check_end_game() + + # overriding the default character spawning.. + def spawn_player(self, player: Player) -> ba.Actor: + spaz = self.spawn_player_spaz(player) + + # Let's reconnect this player's controls to this + # spaz but *without* the ability to attack or pick stuff up. + spaz.connect_controls_to_player( + enable_punch=False, enable_bomb=False, enable_pickup=False + ) + + # Also lets have them make some noise when they die. + spaz.play_big_death_sound = True + return spaz + + # Various high-level game events come through this method. + def handlemessage(self, msg: Any) -> Any: + if isinstance(msg, ba.PlayerDiedMessage): + + # Augment standard behavior. + super().handlemessage(msg) + + curtime = ba.time() + + # Record the player's moment of death. + # assert isinstance(msg.spaz.player + msg.getplayer(Player).death_time = curtime + + # In co-op mode, end the game the instant everyone dies + # (more accurate looking). + # In teams/ffa, allow a one-second fudge-factor so we can + # get more draws if players die basically at the same time. + if isinstance(self.session, ba.CoopSession): + # Teams will still show up if we check now.. check in + # the next cycle. + ba.pushcall(self._check_end_game) + + # Also record this for a final setting of the clock. + self._last_player_death_time = curtime + else: + ba.timer(1.0, self._check_end_game) + + else: + # Default handler: + return super().handlemessage(msg) + return None + + def _check_end_game(self) -> None: + living_team_count = 0 + for team in self.teams: + for player in team.players: + if player.is_alive(): + living_team_count += 1 + break + + # In co-op, we go till everyone is dead.. otherwise we go + # until one team remains. + if isinstance(self.session, ba.CoopSession): + if living_team_count <= 0: + self.end_game() + else: + if living_team_count <= 1: + self.end_game() + + def _set_meteor_timer(self) -> None: + ba.timer( + (1.0 + 0.2 * random.random()) * self._meteor_time, + self._drop_bomb_cluster, + ) + + def _drop_bomb_cluster(self) -> None: + + # Random note: code like this is a handy way to plot out extents + # and debug things. + loc_test = False + if loc_test: + ba.newnode('locator', attrs={'position': (8, 6, -5.5)}) + ba.newnode('locator', attrs={'position': (8, 6, -2.3)}) + ba.newnode('locator', attrs={'position': (-7.3, 6, -5.5)}) + ba.newnode('locator', attrs={'position': (-7.3, 6, -2.3)}) + + # Drop several bombs in series. + delay = 0.0 + for _i in range(random.randrange(1, 3)): + # Drop them somewhere within our bounds with velocity pointing + # toward the opposite side. + pos = ( + -7.3 + 15.3 * random.random(), + 11, + -5.57 + 2.1 * random.random(), + ) + dropdir = -1.0 if pos[0] > 0 else 1.0 + vel = ( + (-5.0 + random.random() * 30.0) * dropdir, + random.uniform(-3.066, -4.12), + 0, + ) + ba.timer(delay, ba.Call(self._drop_bomb, pos, vel)) + delay += 0.1 + self._set_meteor_timer() + + def _drop_bomb( + self, position: Sequence[float], velocity: Sequence[float] + ) -> None: + if self._bomb_type == 'tnt': + bomb_type = random.choice(['tnt', 'tnt', 'tnt', 'tnt', 'impact']) + elif self._bomb_type == 'land_mine': + bomb_type = random.choice([ + 'land_mine', 'land_mine', 'land_mine', 'land_mine', 'impact']) + elif self._bomb_type == 'random': + bomb_type = random.choice([ + 'normal', 'ice', 'sticky', 'impact', 'land_mine', 'tnt']) + else: + bomb_type = self._bomb_type + Bomb(position=position, + velocity=velocity, + bomb_type=bomb_type).autoretain() + + def _decrement_meteor_time(self) -> None: + self._meteor_time = max(0.01, self._meteor_time * 0.9) + + def end_game(self) -> None: + cur_time = ba.time() + assert self._timer is not None + start_time = self._timer.getstarttime() + + # Mark death-time as now for any still-living players + # and award players points for how long they lasted. + # (these per-player scores are only meaningful in team-games) + for team in self.teams: + for player in team.players: + survived = False + + # Throw an extra fudge factor in so teams that + # didn't die come out ahead of teams that did. + if player.death_time is None: + survived = True + player.death_time = cur_time + 1 + + # Award a per-player score depending on how many seconds + # they lasted (per-player scores only affect teams mode; + # everywhere else just looks at the per-team score). + score = int(player.death_time - self._timer.getstarttime()) + if survived: + score += 50 # A bit extra for survivors. + self.stats.player_scored(player, score, screenmessage=False) + + # Stop updating our time text, and set the final time to match + # exactly when our last guy died. + self._timer.stop(endtime=self._last_player_death_time) + + # Ok now calc game results: set a score for each team and then tell + # the game to end. + results = ba.GameResults() + + # Remember that 'free-for-all' mode is simply a special form + # of 'teams' mode where each player gets their own team, so we can + # just always deal in teams and have all cases covered. + for team in self.teams: + + # Set the team score to the max time survived by any player on + # that team. + longest_life = 0.0 + for player in team.players: + assert player.death_time is not None + longest_life = max(longest_life, player.death_time - start_time) + + # Submit the score value in milliseconds. + results.set_team_score(team, int(1000.0 * longest_life)) + + self.end(results=results) # ba_meta export plugin class MeteorShowerv2Coop(ba.Plugin): - def on_app_running(self) -> None: - ba.app.add_coop_practice_level( - ba.Level( - normal_rain, - gametype=MeteorShowerv2Game, - settings={bomb_type: 0}, - preview_texture_name='rampagePreview', - ) - ) - ba.app.add_coop_practice_level( - ba.Level( - frozen_rain, - gametype=MeteorShowerv2Game, - settings={bomb_type: 1}, - preview_texture_name='rampagePreview', - ) - ) - ba.app.add_coop_practice_level( - ba.Level( - sticky_rain, - gametype=MeteorShowerv2Game, - settings={bomb_type: 2}, - preview_texture_name='rampagePreview', - ) - ) - ba.app.add_coop_practice_level( - ba.Level( - impact_rain, - gametype=MeteorShowerv2Game, - settings={bomb_type: 3}, - preview_texture_name='rampagePreview', - ) - ) - ba.app.add_coop_practice_level( - ba.Level( - mine_rain, - gametype=MeteorShowerv2Game, - settings={bomb_type: 4}, - preview_texture_name='rampagePreview', - ) - ) - ba.app.add_coop_practice_level( - ba.Level( - tnt_rain, - gametype=MeteorShowerv2Game, - settings={bomb_type: 5}, - preview_texture_name='rampagePreview', - ) - ) - ba.app.add_coop_practice_level( - ba.Level( - random_rain, - gametype=MeteorShowerv2Game, - settings={bomb_type: 6}, - preview_texture_name='rampagePreview', - ) - ) + def on_app_running(self) -> None: + ba.app.add_coop_practice_level( + ba.Level( + normal_rain, + gametype=MeteorShowerv2Game, + settings={bomb_type: 0}, + preview_texture_name='rampagePreview', + ) + ) + ba.app.add_coop_practice_level( + ba.Level( + frozen_rain, + gametype=MeteorShowerv2Game, + settings={bomb_type: 1}, + preview_texture_name='rampagePreview', + ) + ) + ba.app.add_coop_practice_level( + ba.Level( + sticky_rain, + gametype=MeteorShowerv2Game, + settings={bomb_type: 2}, + preview_texture_name='rampagePreview', + ) + ) + ba.app.add_coop_practice_level( + ba.Level( + impact_rain, + gametype=MeteorShowerv2Game, + settings={bomb_type: 3}, + preview_texture_name='rampagePreview', + ) + ) + ba.app.add_coop_practice_level( + ba.Level( + mine_rain, + gametype=MeteorShowerv2Game, + settings={bomb_type: 4}, + preview_texture_name='rampagePreview', + ) + ) + ba.app.add_coop_practice_level( + ba.Level( + tnt_rain, + gametype=MeteorShowerv2Game, + settings={bomb_type: 5}, + preview_texture_name='rampagePreview', + ) + ) + ba.app.add_coop_practice_level( + ba.Level( + random_rain, + gametype=MeteorShowerv2Game, + settings={bomb_type: 6}, + preview_texture_name='rampagePreview', + ) + ) diff --git a/plugins/minigames/SimonSays.py b/plugins/minigames/SimonSays.py index 151963d8..ad3ac276 100644 --- a/plugins/minigames/SimonSays.py +++ b/plugins/minigames/SimonSays.py @@ -1,4 +1,4 @@ -#SimonSays +# SimonSays # you had really better do what Simon says... # ba_meta require api 7 from __future__ import annotations @@ -12,6 +12,7 @@ import ba import random + class CustomText(ba.Actor): """Text that pops up above a position to denote something special. @@ -39,7 +40,7 @@ def __init__(self, 'in_world': True, 'shadow': 1.0, 'flatness': 1.0, - 'h_align': 'center'},delegate=self) + 'h_align': 'center'}, delegate=self) lifespan = duration ba.animate( self.node, 'scale', { @@ -83,6 +84,7 @@ def __init__(self, self._combine.connectattr('output', self.node, 'color') self._die_timer = ba.Timer( lifespan, ba.WeakCall(self.handlemessage, ba.DieMessage())) + def handlemessage(self, msg: Any) -> Any: assert not self.expired if isinstance(msg, ba.DieMessage): @@ -91,11 +93,14 @@ def handlemessage(self, msg: Any) -> Any: else: super().handlemessage(msg) + class Player(ba.Player['Team']): """Our player type for this game.""" + def __init__(self) -> None: self.score = 0 + class Team(ba.Team[Player]): """Our team type for this game.""" @@ -103,30 +108,33 @@ def __init__(self) -> None: self.score = 0 # ba_meta export game + + class SimonSays(ba.TeamGameActivity[Player, Team]): name = "Simon Says" description = "You have to better do what Simon says!" + @classmethod def get_available_settings(cls, sessiontype: Type[ba.Session]) -> List[ba.Setting]: settings = [ - ba.BoolSetting("Epic Mode", default=False), - ba.BoolSetting("Enable Jumping", default=False), - ba.BoolSetting("Enable Punching", default=False), - ba.BoolSetting("Enable Picking Up", default=False), - ba.IntChoiceSetting("Timer Speed", - choices=[("Snaily", 1200), - ("Slow", 900), - ("Normal", 655), - ("Fast", 544), - ("Turbo", 460)], default=655), - - ba.FloatChoiceSetting("Text Duration", - choices=[("Slow", 2.5), - ("Normal", 1.5), - ("Mediocre", 1.0), - ("Quick", 0.75)], default=1.5)] + ba.BoolSetting("Epic Mode", default=False), + ba.BoolSetting("Enable Jumping", default=False), + ba.BoolSetting("Enable Punching", default=False), + ba.BoolSetting("Enable Picking Up", default=False), + ba.IntChoiceSetting("Timer Speed", + choices=[("Snaily", 1200), + ("Slow", 900), + ("Normal", 655), + ("Fast", 544), + ("Turbo", 460)], default=655), + + ba.FloatChoiceSetting("Text Duration", + choices=[("Slow", 2.5), + ("Normal", 1.5), + ("Mediocre", 1.0), + ("Quick", 0.75)], default=1.5)] return settings - + @classmethod def get_supported_maps(cls, sessiontype: Type[ba.Session]) -> List[str]: return ["Courtyard"] @@ -149,53 +157,54 @@ def __init__(self, settings: dict): self.counter_loop = None self.time = 5000 self._r1 = 2 - self.ct_text = ba.newnode('text',attrs={ - 'in_world': True, - 'text':'......', - 'shadow': 1.0, - 'color': (1.0,1.0,1.0), - 'flatness': 0.5, - 'position': (-5.627144702, 3.3275475, -9.572879116), - 'scale': 0.05}) - self.n1 = ba.newnode('locator',attrs={'shape':'circle','position':(-4,0,-6), - 'color':(1,0,0),'opacity':0.5, - 'draw_beauty':True,'additive':True}) - self.n2 = ba.newnode('locator',attrs={'shape':'circle','position':(0,0,-6), - 'color':(0,1,0),'opacity':0.5, - 'draw_beauty':True,'additive':True}) - self.n3 = ba.newnode('locator',attrs={'shape':'circle','position':(4,0,-6), - 'color':(0,0,1),'opacity':0.5, - 'draw_beauty':True,'additive':True}) - self.n4 = ba.newnode('locator',attrs={'shape':'circle','position':(-4,0,-2), - 'color':(1,1,0),'opacity':0.5, - 'draw_beauty':True,'additive':True}) - self.n5 = ba.newnode('locator',attrs={'shape':'circle','position':(0,0,-2), - 'color':(0,1,1),'opacity':0.5, - 'draw_beauty':True,'additive':True}) - self.n6 = ba.newnode('locator',attrs={'shape':'circle','position':(4,0,-2), - 'color':(1,0,1),'opacity':0.5, - 'draw_beauty':True,'additive':True}) - self.n7 = ba.newnode('locator',attrs={'shape':'circle','position':(-4,0,2), - 'color':(.5,.5,.5),'opacity':0.5, - 'draw_beauty':True,'additive':True}) - self.n8 = ba.newnode('locator',attrs={'shape':'circle','position':(0,0,2), - 'color':(.5,.325,0),'opacity':0.5, - 'draw_beauty':True,'additive':True}) - self.n9 = ba.newnode('locator',attrs={'shape':'circle','position':(4,0,2), - 'color':(1,1,1),'opacity':0.5, - 'draw_beauty':True,'additive':True}) - self.options = ["red", "green", "blue", "yellow", "teal", "purple", "gray", "orange", "white", "top", "bottom", "middle row", "left", "right", "center column", "outside"] + self.ct_text = ba.newnode('text', attrs={ + 'in_world': True, + 'text': '......', + 'shadow': 1.0, + 'color': (1.0, 1.0, 1.0), + 'flatness': 0.5, + 'position': (-5.627144702, 3.3275475, -9.572879116), + 'scale': 0.05}) + self.n1 = ba.newnode('locator', attrs={'shape': 'circle', 'position': (-4, 0, -6), + 'color': (1, 0, 0), 'opacity': 0.5, + 'draw_beauty': True, 'additive': True}) + self.n2 = ba.newnode('locator', attrs={'shape': 'circle', 'position': (0, 0, -6), + 'color': (0, 1, 0), 'opacity': 0.5, + 'draw_beauty': True, 'additive': True}) + self.n3 = ba.newnode('locator', attrs={'shape': 'circle', 'position': (4, 0, -6), + 'color': (0, 0, 1), 'opacity': 0.5, + 'draw_beauty': True, 'additive': True}) + self.n4 = ba.newnode('locator', attrs={'shape': 'circle', 'position': (-4, 0, -2), + 'color': (1, 1, 0), 'opacity': 0.5, + 'draw_beauty': True, 'additive': True}) + self.n5 = ba.newnode('locator', attrs={'shape': 'circle', 'position': (0, 0, -2), + 'color': (0, 1, 1), 'opacity': 0.5, + 'draw_beauty': True, 'additive': True}) + self.n6 = ba.newnode('locator', attrs={'shape': 'circle', 'position': (4, 0, -2), + 'color': (1, 0, 1), 'opacity': 0.5, + 'draw_beauty': True, 'additive': True}) + self.n7 = ba.newnode('locator', attrs={'shape': 'circle', 'position': (-4, 0, 2), + 'color': (.5, .5, .5), 'opacity': 0.5, + 'draw_beauty': True, 'additive': True}) + self.n8 = ba.newnode('locator', attrs={'shape': 'circle', 'position': (0, 0, 2), + 'color': (.5, .325, 0), 'opacity': 0.5, + 'draw_beauty': True, 'additive': True}) + self.n9 = ba.newnode('locator', attrs={'shape': 'circle', 'position': (4, 0, 2), + 'color': (1, 1, 1), 'opacity': 0.5, + 'draw_beauty': True, 'additive': True}) + self.options = ["red", "green", "blue", "yellow", "teal", "purple", "gray", "orange", + "white", "top", "bottom", "middle row", "left", "right", "center column", "outside"] self.default_music = ba.MusicType.FLAG_CATCHER - + def get_instance_description(self) -> str: return 'Follow the commands... but only when \"Simon says!"' def on_player_join(self, player: Player) -> None: if self.has_begun(): ba.screenmessage( - ba.Lstr(resource = 'playerDelayedJoinText', - subs = [('${PLAYER}', player.getname(full=True))]), - color=(0, 1, 0),) + ba.Lstr(resource='playerDelayedJoinText', + subs=[('${PLAYER}', player.getname(full=True))]), + color=(0, 1, 0),) return else: self.spawn_player(player) @@ -203,119 +212,147 @@ def on_player_join(self, player: Player) -> None: def on_begin(self) -> None: super().on_begin() s = self.settings - _gameutils.animate_array(self.n1,'size',1,{0:[0.0],0.2:[self._r1*2.0]}) - _gameutils.animate_array(self.n2,'size',1,{0:[0.0],0.2:[self._r1*2.0]}) - _gameutils.animate_array(self.n3,'size',1,{0:[0.0],0.2:[self._r1*2.0]}) - _gameutils.animate_array(self.n4,'size',1,{0:[0.0],0.2:[self._r1*2.0]}) - _gameutils.animate_array(self.n5,'size',1,{0:[0.0],0.2:[self._r1*2.0]}) - _gameutils.animate_array(self.n6,'size',1,{0:[0.0],0.2:[self._r1*2.0]}) - _gameutils.animate_array(self.n7,'size',1,{0:[0.0],0.2:[self._r1*2.0]}) - _gameutils.animate_array(self.n8,'size',1,{0:[0.0],0.2:[self._r1*2.0]}) - _gameutils.animate_array(self.n9,'size',1,{0:[0.0],0.2:[self._r1*2.0]}) + _gameutils.animate_array(self.n1, 'size', 1, {0: [0.0], 0.2: [self._r1*2.0]}) + _gameutils.animate_array(self.n2, 'size', 1, {0: [0.0], 0.2: [self._r1*2.0]}) + _gameutils.animate_array(self.n3, 'size', 1, {0: [0.0], 0.2: [self._r1*2.0]}) + _gameutils.animate_array(self.n4, 'size', 1, {0: [0.0], 0.2: [self._r1*2.0]}) + _gameutils.animate_array(self.n5, 'size', 1, {0: [0.0], 0.2: [self._r1*2.0]}) + _gameutils.animate_array(self.n6, 'size', 1, {0: [0.0], 0.2: [self._r1*2.0]}) + _gameutils.animate_array(self.n7, 'size', 1, {0: [0.0], 0.2: [self._r1*2.0]}) + _gameutils.animate_array(self.n8, 'size', 1, {0: [0.0], 0.2: [self._r1*2.0]}) + _gameutils.animate_array(self.n9, 'size', 1, {0: [0.0], 0.2: [self._r1*2.0]}) for team in self.teams: team.score = 0 for player in self.players: player.score = 0 # check for immediate end if theres only 1 player if len(self.players) == 1: - ba.timer(4000, lambda: self.check_end(),timeformat=ba.TimeFormat.MILLISECONDS) + ba.timer(4000, lambda: self.check_end(), timeformat=ba.TimeFormat.MILLISECONDS) else: ba.timer(6000, self.call_round, timeformat=ba.TimeFormat.MILLISECONDS) def spawn_player(self, player: PlayerType) -> ba.Actor: assert player - spaz = self.spawn_player_spaz(player, position=(0 + random.uniform(-3.6, 3.6), 2.9, -2 + random.uniform(-3.6, 3.6))) + spaz = self.spawn_player_spaz(player, position=( + 0 + random.uniform(-3.6, 3.6), 2.9, -2 + random.uniform(-3.6, 3.6))) assert spaz.node spaz.connect_controls_to_player( - enable_bomb=False, - enable_run = True, - enable_punch = self.settings["Enable Punching"], - enable_pickup = self.settings["Enable Picking Up"], - enable_jump = self.settings["Enable Jumping"]) + enable_bomb=False, + enable_run=True, + enable_punch=self.settings["Enable Punching"], + enable_pickup=self.settings["Enable Picking Up"], + enable_jump=self.settings["Enable Jumping"]) def call_round(self) -> None: - if self.ended: return + if self.ended: + return self.round_num += 1 self.num = random.randint(0, 15) self.numa = self.num self.simon = random.choice([True, False]) - false_prefix = random.choices(['Simon say r', 'Simon said r', 'Simon r', 'Simons says r', 'Simons r', 'R'], weights=[35,45,45,39,49,100])[0] + false_prefix = random.choices(['Simon say r', 'Simon said r', 'Simon r', + 'Simons says r', 'Simons r', 'R'], weights=[35, 45, 45, 39, 49, 100])[0] if self.numa < 9: - if not self.simon: line = false_prefix + "un to the " + self.options[self.numa] + " circle!" - else: line = "Run to the " + self.options[self.numa] + " circle!" + if not self.simon: + line = false_prefix + "un to the " + self.options[self.numa] + " circle!" + else: + line = "Run to the " + self.options[self.numa] + " circle!" elif self.numa < 15: - if not self.simon: line = false_prefix + "un to the " + self.options[self.numa] + "!" - else: line = "Run to the " + self.options[self.numa] + "!" + if not self.simon: + line = false_prefix + "un to the " + self.options[self.numa] + "!" + else: + line = "Run to the " + self.options[self.numa] + "!" else: - if not self.simon: line = false_prefix + "un outside of the circles!" - else: line = "Run outside of the circles!" - + if not self.simon: + line = false_prefix + "un outside of the circles!" + else: + line = "Run outside of the circles!" if self.simon: - line = "Simon says " + line[0].lower() + line[1:] + line = "Simon says " + line[0].lower() + line[1:] self.text = CustomText(line, - position=(0, 5, -4), - color=(0.68, 0.95, 1.12), - random_offset=0.5, - offset=(0, 0, 0), - duration=self.lifespan, - scale=2.0).autoretain() + position=(0, 5, -4), + color=(0.68, 0.95, 1.12), + random_offset=0.5, + offset=(0, 0, 0), + duration=self.lifespan, + scale=2.0).autoretain() self.now = 6 + def dummy_check(): - self.string = "...." - self.check_round() + self.string = "...." + self.check_round() + def set_counter(): - self.now = self.now - 1 - if self.now == 0: - self.string = "0" - self.ct_text.text = self.string - self.counter_loop = None - ba.timer(1, dummy_check, timeformat=ba.TimeFormat.MILLISECONDS) - else: - self.ct_text.text = str(self.now) - ba.playsound(ba.getsound('tick')) - self.counter_loop = ba.Timer(self.speed, set_counter ,timeformat=ba.TimeFormat.MILLISECONDS,repeat=True) + self.now = self.now - 1 + if self.now == 0: + self.string = "0" + self.ct_text.text = self.string + self.counter_loop = None + ba.timer(1, dummy_check, timeformat=ba.TimeFormat.MILLISECONDS) + else: + self.ct_text.text = str(self.now) + ba.playsound(ba.getsound('tick')) + self.counter_loop = ba.Timer(self.speed, set_counter, + timeformat=ba.TimeFormat.MILLISECONDS, repeat=True) def check_round(self) -> None: - if self.ended: return + if self.ended: + return for player in self.players: if player.is_alive(): - safe = True if self.options[self.numa] in self.in_circle(player.actor.node.position_center) else False + safe = True if self.options[self.numa] in self.in_circle( + player.actor.node.position_center) else False if ((self.simon and safe == False) or ((not self.simon) and safe == True)): player.team.score = self.round_num player.actor.handlemessage(ba.DieMessage()) ba.timer(1633, self.call_round, timeformat=ba.TimeFormat.MILLISECONDS) - def in_circle(self, pos) -> None: circles = [] x = pos[0] z = pos[2] - if (x + 4) ** 2 + (z + 6) ** 2 < 4: circles.append("red") - elif (x) ** 2 + (z + 6) ** 2 < 4: circles.append("green") - elif (x - 4) ** 2 + (z + 6) ** 2 < 4: circles.append("blue") - elif (x + 4) ** 2 + (z + 2) ** 2 < 4: circles.append("yellow") - elif (x) ** 2 + (z + 2) ** 2 < 4: circles.append("teal") - elif (x - 4) ** 2 + (z + 2) ** 2 < 4: circles.append("purple") - elif (x + 4) ** 2 + (z - 2) ** 2 < 4: circles.append("gray") - elif (x) ** 2 + (z - 2) ** 2 < 4: circles.append("orange") - elif (x - 4) ** 2 + (z - 2) ** 2 < 4: circles.append("white") - else: circles.append("outside") - if x < -2: circles.append("left") - if x > 2: circles.append("right") - if x > -2 and x < 2: circles.append("center column") - if z > 0: circles.append("bottom") - if z < -4: circles.append("top") - if z < 0 and z > -4: circles.append("middle row") + if (x + 4) ** 2 + (z + 6) ** 2 < 4: + circles.append("red") + elif (x) ** 2 + (z + 6) ** 2 < 4: + circles.append("green") + elif (x - 4) ** 2 + (z + 6) ** 2 < 4: + circles.append("blue") + elif (x + 4) ** 2 + (z + 2) ** 2 < 4: + circles.append("yellow") + elif (x) ** 2 + (z + 2) ** 2 < 4: + circles.append("teal") + elif (x - 4) ** 2 + (z + 2) ** 2 < 4: + circles.append("purple") + elif (x + 4) ** 2 + (z - 2) ** 2 < 4: + circles.append("gray") + elif (x) ** 2 + (z - 2) ** 2 < 4: + circles.append("orange") + elif (x - 4) ** 2 + (z - 2) ** 2 < 4: + circles.append("white") + else: + circles.append("outside") + if x < -2: + circles.append("left") + if x > 2: + circles.append("right") + if x > -2 and x < 2: + circles.append("center column") + if z > 0: + circles.append("bottom") + if z < -4: + circles.append("top") + if z < 0 and z > -4: + circles.append("middle row") return circles def handlemessage(self, msg) -> None: if isinstance(msg, ba.PlayerDiedMessage): - self.check_end() + self.check_end() else: - super().handlemessage(msg) + super().handlemessage(msg) def end_game(self) -> None: self.ended = True @@ -327,7 +364,7 @@ def end_game(self) -> None: def check_end(self) -> None: i = 0 for player in self.players: - if player.is_alive(): - i += 1 - if i <= 2 : - ba.timer(0.6, lambda: self.end_game()) + if player.is_alive(): + i += 1 + if i <= 2: + ba.timer(0.6, lambda: self.end_game()) diff --git a/plugins/minigames/SquidRace.py b/plugins/minigames/SquidRace.py index c13276a2..d8cd54be 100644 --- a/plugins/minigames/SquidRace.py +++ b/plugins/minigames/SquidRace.py @@ -30,6 +30,7 @@ def handlemessage(self, msg: Any) -> Any: else: return super().handlemessage(msg) + @dataclass class RaceMine: """Holds info about a mine on the track.""" @@ -223,7 +224,7 @@ def on_transition_in(self) -> None: ('modify_part_collision', 'physical', False), ('call', 'at_connect', self._handle_race_point_collide), - )) + )) for rpt in pts: self._regions.append(RaceRegion(rpt, len(self._regions))) @@ -271,7 +272,7 @@ def _handle_race_point_collide(self) -> None: translate=('statements', 'Killing ${NAME} for' ' skipping part of the track!'), subs=[('${NAME}', player.getname(full=True))]), - color=(1, 0, 0)) + color=(1, 0, 0)) else: # If this player is in first, note that this is the # front-most race-point. @@ -397,7 +398,7 @@ def on_player_leave(self, player: Player) -> None: '${TEAM} is disqualified because ${PLAYER} left'), subs=[('${TEAM}', player.team.name), ('${PLAYER}', player.getname(full=True))]), - color=(1, 1, 0)) + color=(1, 1, 0)) player.team.finished = True player.team.time = None player.team.lap = 0 @@ -535,7 +536,7 @@ def on_begin(self) -> None: self._squidgame_countdown() def _squidgame_countdown(self) -> None: - self._countdown_timer = 80 * self._laps # 80 + self._countdown_timer = 80 * self._laps # 80 ba.newnode( 'image', attrs={ @@ -552,7 +553,7 @@ def _squidgame_countdown(self) -> None: 'color': (1.0, 0.0, 0.0), 'attach': 'topCenter', 'position': (-220, -38), - 'scale':(155, 65), + 'scale': (155, 65), 'texture': ba.gettexture('uiAtlas'), 'model_transparent': ba.getmodel('meterTransparent')}) self._sgcountdown_text = ba.newnode( @@ -615,9 +616,9 @@ def do_ticks(): self._tick_timer = ba.timer(1.0, do_ticks, repeat=True) def _start_squid_game(self) -> None: - easy = [4.5,5,5.5,6] - normal = [4,4.5,5] - hard = [3,3.5,4] + easy = [4.5, 5, 5.5, 6] + normal = [4, 4.5, 5] + hard = [3, 3.5, 4] random_number = random.choice( hard if self._sq_mode == 'Hard' else normal if self._sq_mode == 'Normal' else easy) @@ -665,18 +666,18 @@ def _start_delete(self) -> None: posy = float("%.1f" % player.customdata['position'][2]) posx_list = [ - round(posx,1),round(posx+0.1,1),round(posx+0.2,1), - round(posx-0.1,1),round(posx-0.2,1)] + round(posx, 1), round(posx+0.1, 1), round(posx+0.2, 1), + round(posx-0.1, 1), round(posx-0.2, 1)] current_posx = float("%.1f" % player.actor.node.position[0]) posz_list = [ - round(posz,1),round(posz+0.1,1),round(posz+0.2,1), - round(posz-0.1,1),round(posz-0.2,1)] + round(posz, 1), round(posz+0.1, 1), round(posz+0.2, 1), + round(posz-0.1, 1), round(posz-0.2, 1)] current_posz = float("%.1f" % player.actor.node.position[1]) posy_list = [ - round(posy,1),round(posy+0.1,1),round(posy+0.2,1), - round(posy-0.1,1),round(posy-0.2,1)] + round(posy, 1), round(posy+0.1, 1), round(posy+0.2, 1), + round(posy-0.1, 1), round(posy-0.2, 1)] current_posy = float("%.1f" % player.actor.node.position[2]) if not (current_posx in posx_list) or not ( diff --git a/plugins/minigames/ZombieHorde.py b/plugins/minigames/ZombieHorde.py index 673c9f51..afb48f3b 100644 --- a/plugins/minigames/ZombieHorde.py +++ b/plugins/minigames/ZombieHorde.py @@ -65,7 +65,7 @@ def handlemessage(self, m: Any) -> Any: if not playa is None: if opposingnode._source_player.lives > 0: return True - except Exception: + except Exception: pass if (opposingnode.getnodetype() == 'spaz' @@ -82,6 +82,7 @@ def handlemessage(self, m: Any) -> Any: return super().handlemessage(m) return None + class PlayerZombie(PlayerSpaz): def handlemessage(self, m: Any) -> Any: if isinstance(m, ba.HitMessage): @@ -101,6 +102,7 @@ def handlemessage(self, m: Any) -> Any: else: super().handlemessage(m) + class zBotSet(SpazBotSet): def start_moving(self) -> None: """Start processing bot AI updates so they start doing their thing.""" @@ -139,6 +141,7 @@ def zUpdate(self) -> None: bot.set_player_points(player_pts) bot.update_ai() + class Team(ba.Team[Player]): """Our team type for this game.""" @@ -242,8 +245,8 @@ def __init__(self, settings: dict): activity = ba.getactivity() my_factory = SpazFactory.get() - appears = ['Kronk','Zoe','Pixel','Agent Johnson', - 'Bones','Frosty','Kronk2'] + appears = ['Kronk', 'Zoe', 'Pixel', 'Agent Johnson', + 'Bones', 'Frosty', 'Kronk2'] myAppear = copy.copy(ba.app.spaz_appearances['Kronk']) myAppear.name = 'Kronk2' ba.app.spaz_appearances['Kronk2'] = myAppear @@ -252,7 +255,7 @@ def __init__(self, settings: dict): med = my_factory.spaz_media med['Kronk2']['head_model'] = med['Zoe']['head_model'] med['Kronk2']['color_texture'] = med['Agent Johnson']['color_texture'] - med['Kronk2']['color_mask_texture']=med['Pixel']['color_mask_texture'] + med['Kronk2']['color_mask_texture'] = med['Pixel']['color_mask_texture'] med['Kronk2']['torso_model'] = med['Bones']['torso_model'] med['Kronk2']['pelvis_model'] = med['Pixel']['pelvis_model'] med['Kronk2']['upper_arm_model'] = med['Frosty']['upper_arm_model'] @@ -351,9 +354,9 @@ def on_begin(self) -> None: self._bots = zBotSet() - #Set colors and character for ToughGuyBot to be zombie - setattr(BrawlerBot, 'color', (0.4,0.1,0.05)) - setattr(BrawlerBot, 'highlight', (0.2,0.4,0.3)) + # Set colors and character for ToughGuyBot to be zombie + setattr(BrawlerBot, 'color', (0.4, 0.1, 0.05)) + setattr(BrawlerBot, 'highlight', (0.2, 0.4, 0.3)) setattr(BrawlerBot, 'character', 'Kronk2') # start some timers to spawn bots thePt = self.map.get_ffa_start_position(self.players) @@ -434,7 +437,6 @@ def _update_icons(self) -> None: icon.update_for_lives() xval += x_offs - def _get_spawn_point(self, player: Player) -> ba.Vec3 | None: del player # Unused. @@ -612,7 +614,7 @@ def _print_lives(self, player: Player) -> None: try: pos = player.actor.node.position except Exception as e: - print('EXC getting player pos in bsElim',e) + print('EXC getting player pos in bsElim', e) return if player.lives > 0: popuptext.PopupText('x' + str(player.lives - 1), @@ -692,7 +694,8 @@ def handlemessage(self, msg: Any) -> Any: elif isinstance(msg, SpazBotDiedMessage): self._onSpazBotDied(msg) - super().handlemessage(msg)#bs.PopupText("died",position=self._position,color=popupColor,scale=popupScale).autoRetain() + # bs.PopupText("died",position=self._position,color=popupColor,scale=popupScale).autoRetain() + super().handlemessage(msg) else: super().handlemessage(msg) @@ -734,15 +737,15 @@ def _update(self) -> None: self._round_end_timer = ba.Timer(0.5, self.end_game) def spawn_zombie(self) -> None: - #We need a Z height... + # We need a Z height... thePt = list(self.get_random_point_in_play()) thePt2 = self.map.get_ffa_start_position(self.players) thePt[1] = thePt2[1] ba.timer(0.1, ba.Call( self._bots.spawn_bot, BrawlerBot, pos=thePt, spawn_time=1.0)) - def _onSpazBotDied(self,DeathMsg) -> None: - #Just in case we are over max... + def _onSpazBotDied(self, DeathMsg) -> None: + # Just in case we are over max... if len(self._bots.get_living_bots()) < self._max_zombies: self.zombieQ += 1 @@ -762,37 +765,38 @@ def get_random_point_in_play(self) -> None: myMap = self.map.getname() if myMap == 'Doom Shroom': while True: - x = random.uniform(-1.0,1.0) - y = random.uniform(-1.0,1.0) - if x*x+y*y < 1.0: break - return ((8.0*x,8.0,-3.5+5.0*y)) + x = random.uniform(-1.0, 1.0) + y = random.uniform(-1.0, 1.0) + if x*x+y*y < 1.0: + break + return ((8.0*x, 8.0, -3.5+5.0*y)) elif myMap == 'Rampage': - x = random.uniform(-6.0,7.0) - y = random.uniform(-6.0,-2.5) + x = random.uniform(-6.0, 7.0) + y = random.uniform(-6.0, -2.5) return ((x, 8.0, y)) elif myMap == 'Hockey Stadium': - x = random.uniform(-11.5,11.5) - y = random.uniform(-4.5,4.5) + x = random.uniform(-11.5, 11.5) + y = random.uniform(-4.5, 4.5) return ((x, 5.0, y)) elif myMap == 'Courtyard': - x = random.uniform(-4.3,4.3) - y = random.uniform(-4.4,0.3) + x = random.uniform(-4.3, 4.3) + y = random.uniform(-4.4, 0.3) return ((x, 8.0, y)) elif myMap == 'Crag Castle': - x = random.uniform(-6.7,8.0) - y = random.uniform(-6.0,0.0) + x = random.uniform(-6.7, 8.0) + y = random.uniform(-6.0, 0.0) return ((x, 12.0, y)) elif myMap == 'Big G': - x = random.uniform(-8.7,8.0) - y = random.uniform(-7.5,6.5) + x = random.uniform(-8.7, 8.0) + y = random.uniform(-7.5, 6.5) return ((x, 8.0, y)) elif myMap == 'Football Stadium': - x = random.uniform(-12.5,12.5) - y = random.uniform(-5.0,5.5) + x = random.uniform(-12.5, 12.5) + y = random.uniform(-5.0, 5.5) return ((x, 8.0, y)) else: - x = random.uniform(-5.0,5.0) - y = random.uniform(-6.0,0.0) + x = random.uniform(-5.0, 5.0) + y = random.uniform(-6.0, 0.0) return ((x, 8.0, y)) def _update_scoreboard(self) -> None: From 9bf4def90bec16d9c1a3fa8724451e6662636186 Mon Sep 17 00:00:00 2001 From: Loup <90267658+Loup-Garou911XD@users.noreply.github.com> Date: Thu, 3 Nov 2022 23:02:32 +0530 Subject: [PATCH 0208/1464] Added SimonSays, SquidRace, BasketBomb, Boxing, MeteorShower, ZombieHorde --- plugins/minigames.json | 107 +++++++++++++++++++++++++++++++++-------- 1 file changed, 86 insertions(+), 21 deletions(-) diff --git a/plugins/minigames.json b/plugins/minigames.json index 989ca69c..dda48e2b 100644 --- a/plugins/minigames.json +++ b/plugins/minigames.json @@ -2,7 +2,91 @@ "name": "Minigames", "description": "Minigames", "plugins_base_url": "http://github.com/bombsquad-community/plugin-manager/{content_type}/{tag}/plugins/minigames", - "plugins": { + "plugins": { + "SimonSays": { + "description": "You better do what Simon says", + "external_url": "", + "authors": [ + { + "name": "Unknown", + "email": null, + "discord": null + } + ], + "versions": { + "1.0.0": null + } + }, + "SquidRace": { + "description": "Race inspired by the squid games", + "external_url": "https://youtube.com/c/JoseANG3LYT", + "authors": [ + { + "name": "JoseAng3l", + "email": null, + "discord": "! JoseANG3L#0268" + } + ], + "versions": { + "1.0.0": null + } + }, + "ZombieHorde": { + "description": "Fight or defend against horde of zombies", + "external_url": "https://youtube.com/c/JoseANG3LYT", + "authors": [ + { + "name": "JoseAng3l", + "email": null, + "discord": "! JoseANG3L#0268" + } + ], + "versions": { + "1.0.0": null + } + }, + "MeteorShower": { + "description": "MeteorShower with many different bombs", + "external_url": "https://youtube.com/c/JoseANG3LYT", + "authors": [ + { + "name": "JoseAng3l", + "email": null, + "discord": "! JoseANG3L#0268" + } + ], + "versions": { + "1.0.0": null + } + }, + "Boxing": { + "description": "Simple boxing minigame", + "external_url": "https://youtube.com/c/JoseANG3LYT", + "authors": [ + { + "name": "JoseAng3l", + "email": null, + "discord": "! JoseANG3L#0268" + } + ], + "versions": { + "1.0.0": null + } + }, + "BasketBomb": { + "description": "Score all the baskets and be the MVP.", + "external_url": "", + "authors": [ + { + "name": "Unknown", + "email": null, + "discord": null + } + ], + "versions": { + "1.0.0": null + } + }, "ultimate_last_stand": { "description": "Bring Last Stand minigame into team fight and FFA.", "external_url": "", @@ -97,25 +181,6 @@ "md5sum": "c84b7f415de5d3e9189ee73fc0e3ce93" } } - }, - "soccer": { - "description": "Shoot the ball in left or right edge of the map to score", - "external_url": "", - "authors": [ - { - "name": "Stary_Agent", - "email": "", - "discord": "" - } - ], - "versions": { - "1.0.0": { - "api_version": 7, - "commit_sha": "e59073b", - "released_on": "02-11-2022", - "md5sum": "ceb7ac417c85396722fa9f7fee3cfc01" - } - } } } -} \ No newline at end of file +} From 0359fe13a10dbd3e4b8495ed163e6b55b555ca1c Mon Sep 17 00:00:00 2001 From: Loup <90267658+Loup-Garou911XD@users.noreply.github.com> Date: Thu, 3 Nov 2022 23:06:11 +0530 Subject: [PATCH 0209/1464] Update mood_light.py --- plugins/utilities/mood_light.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/plugins/utilities/mood_light.py b/plugins/utilities/mood_light.py index 733adef6..c29425d0 100644 --- a/plugins/utilities/mood_light.py +++ b/plugins/utilities/mood_light.py @@ -278,6 +278,9 @@ def __init__(self): def on_app_running(self): _ba.show_progress_bar() + + def on_plugin_manager_prompt(self): + SettingWindow() def has_settings_ui(self): return True From b1e668ad6168f9289af17d4e6e87a513790d6cdb Mon Sep 17 00:00:00 2001 From: Loup-Garou911XD Date: Thu, 3 Nov 2022 17:36:35 +0000 Subject: [PATCH 0210/1464] [ci] auto-format --- plugins/utilities/mood_light.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/utilities/mood_light.py b/plugins/utilities/mood_light.py index c29425d0..dabd85e8 100644 --- a/plugins/utilities/mood_light.py +++ b/plugins/utilities/mood_light.py @@ -278,7 +278,7 @@ def __init__(self): def on_app_running(self): _ba.show_progress_bar() - + def on_plugin_manager_prompt(self): SettingWindow() From 7d3d1170fa4bdff77bf21c288ee621522ec94192 Mon Sep 17 00:00:00 2001 From: Loup <90267658+Loup-Garou911XD@users.noreply.github.com> Date: Thu, 3 Nov 2022 23:11:55 +0530 Subject: [PATCH 0211/1464] Rename QuickCustonGame.py to QuickCustomGame.py Did a oopsies --- plugins/utilities/{QuickCustonGame.py => QuickCustomGame.py} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename plugins/utilities/{QuickCustonGame.py => QuickCustomGame.py} (100%) diff --git a/plugins/utilities/QuickCustonGame.py b/plugins/utilities/QuickCustomGame.py similarity index 100% rename from plugins/utilities/QuickCustonGame.py rename to plugins/utilities/QuickCustomGame.py From cbca3a67edb7472412b675711a5fc1b39cb5c330 Mon Sep 17 00:00:00 2001 From: Loup-Garou911XD Date: Thu, 3 Nov 2022 17:42:19 +0000 Subject: [PATCH 0212/1464] [ci] apply-version-metadata --- plugins/minigames.json | 80 +++++++++++++++++++++++++++++------------- plugins/utilities.json | 55 +++++++++++++++++++++-------- 2 files changed, 95 insertions(+), 40 deletions(-) diff --git a/plugins/minigames.json b/plugins/minigames.json index dda48e2b..d1897ccb 100644 --- a/plugins/minigames.json +++ b/plugins/minigames.json @@ -2,75 +2,100 @@ "name": "Minigames", "description": "Minigames", "plugins_base_url": "http://github.com/bombsquad-community/plugin-manager/{content_type}/{tag}/plugins/minigames", - "plugins": { + "plugins": { "SimonSays": { - "description": "You better do what Simon says", + "description": "You better do what Simon says", "external_url": "", "authors": [ { "name": "Unknown", "email": null, - "discord": null + "discord": null } ], - "versions": { - "1.0.0": null + "versions": { + "1.0.0": { + "api_version": 7, + "commit_sha": "7d3d117", + "released_on": "03-11-2022", + "md5sum": "def39482b339095a7affb574af829ea0" + } } }, "SquidRace": { - "description": "Race inspired by the squid games", + "description": "Race inspired by the squid games", "external_url": "https://youtube.com/c/JoseANG3LYT", "authors": [ { "name": "JoseAng3l", "email": null, - "discord": "! JoseANG3L#0268" + "discord": "! JoseANG3L#0268" } ], - "versions": { - "1.0.0": null + "versions": { + "1.0.0": { + "api_version": 7, + "commit_sha": "7d3d117", + "released_on": "03-11-2022", + "md5sum": "7ec43481e6b35b4da4f6425977ee0004" + } } }, "ZombieHorde": { - "description": "Fight or defend against horde of zombies", + "description": "Fight or defend against horde of zombies", "external_url": "https://youtube.com/c/JoseANG3LYT", "authors": [ { "name": "JoseAng3l", "email": null, - "discord": "! JoseANG3L#0268" + "discord": "! JoseANG3L#0268" } ], - "versions": { - "1.0.0": null + "versions": { + "1.0.0": { + "api_version": 7, + "commit_sha": "7d3d117", + "released_on": "03-11-2022", + "md5sum": "671e7b98a9d3eb0aeb7e47448db25af9" + } } - }, + }, "MeteorShower": { - "description": "MeteorShower with many different bombs", + "description": "MeteorShower with many different bombs", "external_url": "https://youtube.com/c/JoseANG3LYT", "authors": [ { "name": "JoseAng3l", "email": null, - "discord": "! JoseANG3L#0268" + "discord": "! JoseANG3L#0268" } ], - "versions": { - "1.0.0": null + "versions": { + "1.0.0": { + "api_version": 7, + "commit_sha": "7d3d117", + "released_on": "03-11-2022", + "md5sum": "1ce8c1a3f3ec240af39b7a73375e7891" + } } }, "Boxing": { - "description": "Simple boxing minigame", + "description": "Simple boxing minigame", "external_url": "https://youtube.com/c/JoseANG3LYT", "authors": [ { "name": "JoseAng3l", "email": null, - "discord": "! JoseANG3L#0268" + "discord": "! JoseANG3L#0268" } ], - "versions": { - "1.0.0": null + "versions": { + "1.0.0": { + "api_version": 7, + "commit_sha": "7d3d117", + "released_on": "03-11-2022", + "md5sum": "c1b615df09886ba05622c4e8b4f6be40" + } } }, "BasketBomb": { @@ -83,8 +108,13 @@ "discord": null } ], - "versions": { - "1.0.0": null + "versions": { + "1.0.0": { + "api_version": 7, + "commit_sha": "7d3d117", + "released_on": "03-11-2022", + "md5sum": "7ec87edbdd5183ec4b2daffad0019820" + } } }, "ultimate_last_stand": { @@ -183,4 +213,4 @@ } } } -} +} \ No newline at end of file diff --git a/plugins/utilities.json b/plugins/utilities.json index f62619e6..1bfdc3b5 100644 --- a/plugins/utilities.json +++ b/plugins/utilities.json @@ -4,31 +4,41 @@ "plugins_base_url": "http://github.com/bombsquad-community/plugin-manager/{content_type}/{tag}/plugins/utilities", "plugins": { "CustomDeath": { - "description": "Characters turn to Bones after death", + "description": "Characters turn to Bones after death", "external_url": "https://youtube.com/c/JoseANG3LYT", "authors": [ { "name": "JoseAng3l", "email": null, - "discord": "! JoseANG3L#0268" + "discord": "! JoseANG3L#0268" } ], - "versions": { - "1.0.0": null + "versions": { + "1.0.0": { + "api_version": 7, + "commit_sha": "7d3d117", + "released_on": "03-11-2022", + "md5sum": "7b1941512532321eec18140087569215" + } } }, "MaxPlayers": { - "description": "Increase the max player limit of 8 players", + "description": "Increase the max player limit of 8 players", "external_url": "https://youtube.com/c/JoseANG3LYT", "authors": [ { "name": "JoseAng3l", "email": null, - "discord": "! JoseANG3L#0268" + "discord": "! JoseANG3L#0268" } ], - "versions": { - "1.0.0": null + "versions": { + "1.0.0": { + "api_version": 7, + "commit_sha": "7d3d117", + "released_on": "03-11-2022", + "md5sum": "f5e129f009e9732b3179c7edaf75478e" + } } }, "QuickCustomGame": { @@ -41,8 +51,13 @@ "discord": "! JoseANG3L#0268" } ], - "versions": { - "1.0.0": null + "versions": { + "1.0.0": { + "api_version": 7, + "commit_sha": "7d3d117", + "released_on": "03-11-2022", + "md5sum": "b691e35afb17cd3b5f6fe21c0194567d" + } } }, "RandomColors": { @@ -55,8 +70,13 @@ "discord": "! JoseANG3L#0268" } ], - "versions": { - "1.0.0": null + "versions": { + "1.0.0": { + "api_version": 7, + "commit_sha": "7d3d117", + "released_on": "03-11-2022", + "md5sum": "0c351a0aebed77c3771053cde0c18d7b" + } } }, "chat_cmd": { @@ -74,8 +94,13 @@ "discord": null } ], - "versions": { - "1.0.0": null + "versions": { + "1.0.0": { + "api_version": 7, + "commit_sha": "7d3d117", + "released_on": "03-11-2022", + "md5sum": "c84d9a1c9e63e77949134020e1f11834" + } } }, "mood_light": { @@ -379,4 +404,4 @@ } } } -} +} \ No newline at end of file From 8ea35e72ee445dc11b6aec0a9d1db3b3157cc57d Mon Sep 17 00:00:00 2001 From: Loup <90267658+Loup-Garou911XD@users.noreply.github.com> Date: Sat, 5 Nov 2022 03:44:32 +0530 Subject: [PATCH 0213/1464] Fixed "Restart level" sending when not playing --- plugins/utilities/mood_light.py | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/plugins/utilities/mood_light.py b/plugins/utilities/mood_light.py index dabd85e8..91eb528e 100644 --- a/plugins/utilities/mood_light.py +++ b/plugins/utilities/mood_light.py @@ -17,12 +17,12 @@ def Print(*args): - out = " ".join(args) + out = " ".join(str(args)) ba.screenmessage(out) def cprint(*args): - out = "\n".join(args) + out = "\n".join(str(args)) _ba.chatmessage(out) @@ -237,7 +237,9 @@ def on_enableButton_press(self): loop = True label = "DISABLE" color = (1, 0, 0) - Print("Restart level to enable") + in_game = not isinstance(_ba.get_foreground_host_session(), mainmenu.MainMenuSession) + if in_game: + Print("Restart level to apply") ba.app.config["moodlightEnabled"] = loop ba.app.config.commit() ba.buttonwidget(edit=self.enable_button, label=label, color=color) From 490b857e80d5ca981f79356da1515919e440bce7 Mon Sep 17 00:00:00 2001 From: Loup <90267658+Loup-Garou911XD@users.noreply.github.com> Date: Sat, 5 Nov 2022 03:52:08 +0530 Subject: [PATCH 0214/1464] Bumped version --- plugins/utilities.json | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/plugins/utilities.json b/plugins/utilities.json index 1bfdc3b5..123a7803 100644 --- a/plugins/utilities.json +++ b/plugins/utilities.json @@ -114,6 +114,7 @@ } ], "versions": { + "1.2.2": null, "1.2.1": { "api_version": 7, "commit_sha": "1a56b57", @@ -404,4 +405,4 @@ } } } -} \ No newline at end of file +} From 87f0e52decaf6a5852ee545b8efad5151da36860 Mon Sep 17 00:00:00 2001 From: Loup-Garou911XD Date: Fri, 4 Nov 2022 22:22:32 +0000 Subject: [PATCH 0215/1464] [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 123a7803..c146ec6d 100644 --- a/plugins/utilities.json +++ b/plugins/utilities.json @@ -114,7 +114,12 @@ } ], "versions": { - "1.2.2": null, + "1.2.2": { + "api_version": 7, + "commit_sha": "490b857", + "released_on": "04-11-2022", + "md5sum": "cb367f877d6360a0e41941b1d0396a9b" + }, "1.2.1": { "api_version": 7, "commit_sha": "1a56b57", @@ -405,4 +410,4 @@ } } } -} +} \ No newline at end of file From 9c35e39a707c01cc93c5a9cb69358ea988a5344e Mon Sep 17 00:00:00 2001 From: Loup <90267658+Loup-Garou911XD@users.noreply.github.com> Date: Sat, 5 Nov 2022 16:40:42 +0530 Subject: [PATCH 0216/1464] Fixed Print and cprint function --- plugins/utilities/mood_light.py | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/plugins/utilities/mood_light.py b/plugins/utilities/mood_light.py index 91eb528e..f1a83049 100644 --- a/plugins/utilities/mood_light.py +++ b/plugins/utilities/mood_light.py @@ -17,12 +17,18 @@ def Print(*args): - out = " ".join(str(args)) + out="" + for arg in args: + a=str(arg) + out += a ba.screenmessage(out) def cprint(*args): - out = "\n".join(str(args)) + out="" + for arg in args: + a=str(arg) + out += a _ba.chatmessage(out) From 3a901be3f3eae63b4f0104c1347c22e08265b381 Mon Sep 17 00:00:00 2001 From: Loup-Garou911XD Date: Sat, 5 Nov 2022 11:11:05 +0000 Subject: [PATCH 0217/1464] [ci] auto-format --- plugins/utilities/mood_light.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/plugins/utilities/mood_light.py b/plugins/utilities/mood_light.py index f1a83049..225df54b 100644 --- a/plugins/utilities/mood_light.py +++ b/plugins/utilities/mood_light.py @@ -17,17 +17,17 @@ def Print(*args): - out="" + out = "" for arg in args: - a=str(arg) + a = str(arg) out += a ba.screenmessage(out) def cprint(*args): - out="" + out = "" for arg in args: - a=str(arg) + a = str(arg) out += a _ba.chatmessage(out) From 4aa9052094a9fafbc7ff65a529649fe74b5bb172 Mon Sep 17 00:00:00 2001 From: Loup <90267658+Loup-Garou911XD@users.noreply.github.com> Date: Sat, 5 Nov 2022 18:34:33 +0530 Subject: [PATCH 0218/1464] Readded accidentally removed data --- plugins/minigames.json | 21 ++++++++++++++++++++- 1 file changed, 20 insertions(+), 1 deletion(-) diff --git a/plugins/minigames.json b/plugins/minigames.json index d1897ccb..a86f4dd0 100644 --- a/plugins/minigames.json +++ b/plugins/minigames.json @@ -3,6 +3,25 @@ "description": "Minigames", "plugins_base_url": "http://github.com/bombsquad-community/plugin-manager/{content_type}/{tag}/plugins/minigames", "plugins": { + "soccer": { + "description": "Shoot the ball in left or right edge of the map to score", + "external_url": "", + "authors": [ + { + "name": "Stary_Agent", + "email": "", + "discord": "" + } + ], + "versions": { + "1.0.0": { + "api_version": 7, + "commit_sha": "e59073b", + "released_on": "02-11-2022", + "md5sum": "ceb7ac417c85396722fa9f7fee3cfc01" + } + } + }, "SimonSays": { "description": "You better do what Simon says", "external_url": "", @@ -213,4 +232,4 @@ } } } -} \ No newline at end of file +} From d6def17e7ecadc06ddf263229fd34aea1f10f4a5 Mon Sep 17 00:00:00 2001 From: Loup-Garou911XD Date: Sat, 5 Nov 2022 13:04:53 +0000 Subject: [PATCH 0219/1464] [ci] apply-version-metadata --- plugins/minigames.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/minigames.json b/plugins/minigames.json index a86f4dd0..7b016560 100644 --- a/plugins/minigames.json +++ b/plugins/minigames.json @@ -232,4 +232,4 @@ } } } -} +} \ No newline at end of file From d64237a5cd2e7373c5f2487d277fd4dc177349f3 Mon Sep 17 00:00:00 2001 From: Loup <90267658+Loup-Garou911XD@users.noreply.github.com> Date: Mon, 7 Nov 2022 00:15:03 +0530 Subject: [PATCH 0220/1464] Add files via upload --- plugins/utilities/custom_death.py | 40 +++ plugins/utilities/max_players.py | 368 ++++++++++++++++++++++++ plugins/utilities/quick_custom_game.py | 381 +++++++++++++++++++++++++ plugins/utilities/random_colors.py | 48 ++++ 4 files changed, 837 insertions(+) create mode 100644 plugins/utilities/custom_death.py create mode 100644 plugins/utilities/max_players.py create mode 100644 plugins/utilities/quick_custom_game.py create mode 100644 plugins/utilities/random_colors.py diff --git a/plugins/utilities/custom_death.py b/plugins/utilities/custom_death.py new file mode 100644 index 00000000..b3730e12 --- /dev/null +++ b/plugins/utilities/custom_death.py @@ -0,0 +1,40 @@ +# ba_meta require api 7 +# (see https://ballistica.net/wiki/meta-tag-system) + +from __future__ import annotations + +from typing import TYPE_CHECKING + +import ba +from bastd.actor.spaz import Spaz + +if TYPE_CHECKING: + from typing import Any + + +Spaz.oldhandlemessage = Spaz.handlemessage + + +def handlemessage(self, msg: Any) -> Any: + if isinstance(msg, ba.DieMessage): + if self.node: + self.node.color_texture = ba.gettexture('bonesColor') + self.node.color_mask_texture = ba.gettexture('bonesColorMask') + self.node.head_model = ba.getmodel('bonesHead') + self.node.torso_model = ba.getmodel('bonesTorso') + self.node.pelvis_model = ba.getmodel('bonesPelvis') + self.node.upper_arm_model = ba.getmodel('bonesUpperArm') + self.node.forearm_model = ba.getmodel('bonesForeArm') + self.node.hand_model = ba.getmodel('bonesHand') + self.node.upper_leg_model = ba.getmodel('bonesUpperLeg') + self.node.lower_leg_model = ba.getmodel('bonesLowerLeg') + self.node.toes_model = ba.getmodel('bonesToes') + self.node.style = 'bones' + self.oldhandlemessage(msg) + else: + return self.oldhandlemessage(msg) + + +# ba_meta export plugin +class CustomDeath(ba.Plugin): + Spaz.handlemessage = handlemessage diff --git a/plugins/utilities/max_players.py b/plugins/utilities/max_players.py new file mode 100644 index 00000000..6d6257a4 --- /dev/null +++ b/plugins/utilities/max_players.py @@ -0,0 +1,368 @@ +"""===========MAX_PLAYERS===========""" + +# ba_meta require api 7 +# (see https://ballistica.net/wiki/meta-tag-system) + +from __future__ import annotations +from typing import TYPE_CHECKING + +import ba +import _ba +from ba._session import Session +from ba._coopsession import CoopSession, TEAM_COLORS, TEAM_NAMES +from ba._multiteamsession import MultiTeamSession +from bastd.ui.gather import GatherWindow +from bastd.ui.popup import PopupWindow + +if TYPE_CHECKING: + from typing import List, Any, Optional, Sequence + + +cfg = ba.app.config +cmp = {'coop_max_players': 4, + 'teams_max_players': 8, + 'ffa_max_players': 8} + +lang = ba.app.lang.language +if lang == 'Spanish': + title_text = 'Máximo de Jugadores' + title_short_text = 'Jugadores' + coop_text = 'Cooperativo' + teams_text = 'Equipos' + ffa_text = 'Todos Contra Todos' +else: + title_text = 'Max Players' + title_short_text = 'Players' + coop_text = 'Co-op' + teams_text = 'Teams' + ffa_text = 'FFA' + + +class ConfigNumberEdit: + + def __init__(self, + parent: ba.Widget, + position: Tuple[float, float], + value: int, + config: str, + text: str): + self._increment = 1 + self._minval = 1 + self._maxval = 100 + self._value = value + self._config = config + + textscale = 1.0 + self.nametext = ba.textwidget( + parent=parent, + position=(position[0], position[1]), + size=(100, 30), + text=text, + maxwidth=150, + color=(0.8, 0.8, 0.8, 1.0), + h_align='left', + v_align='center', + scale=textscale) + self.valuetext = ba.textwidget( + parent=parent, + position=(position[0]+150, position[1]), + size=(60, 28), + editable=False, + color=(0.3, 1.0, 0.3, 1.0), + h_align='right', + v_align='center', + text=str(value), + padding=2) + self.minusbutton = ba.buttonwidget( + parent=parent, + position=(position[0]+240, position[1]), + size=(28, 28), + label='-', + autoselect=True, + on_activate_call=ba.Call(self._down), + repeat=True) + self.plusbutton = ba.buttonwidget( + parent=parent, + position=(position[0]+290, position[1]), + size=(28, 28), + label='+', + autoselect=True, + on_activate_call=ba.Call(self._up), + repeat=True) + + def _up(self) -> None: + self._value = min(self._maxval, self._value + self._increment) + self._update_display() + + def _down(self) -> None: + self._value = max(self._minval, self._value - self._increment) + self._update_display() + + def _update_display(self) -> None: + ba.textwidget(edit=self.valuetext, text=str(self._value)) + cfg['Config Max Players'][self._config] = self._value + cfg.apply_and_commit() + + +class SettingsMaxPlayers(PopupWindow): + + def __init__(self): + # pylint: disable=too-many-locals + uiscale = ba.app.ui.uiscale + self._transitioning_out = False + self._width = 400 + self._height = 220 + bg_color = (0.5, 0.4, 0.6) + + # creates our _root_widget + PopupWindow.__init__(self, + position=(0.0, 0.0), + size=(self._width, self._height), + scale=1.2, + bg_color=bg_color) + + self._cancel_button = ba.buttonwidget( + parent=self.root_widget, + position=(25, self._height - 40), + size=(50, 50), + scale=0.58, + label='', + color=bg_color, + on_activate_call=self._on_cancel_press, + autoselect=True, + icon=ba.gettexture('crossOut'), + iconscale=1.2) + ba.containerwidget(edit=self.root_widget, + cancel_button=self._cancel_button) + + ba.textwidget( + parent=self.root_widget, + position=(self._width * 0.5, self._height - 30), + size=(0, 0), + h_align='center', + v_align='center', + scale=0.8, + text=title_text, + maxwidth=200, + color=ba.app.ui.title_color) + + posx = 33 + posy = self._height + + # co-op + ConfigNumberEdit(parent=self.root_widget, + position=(posx, posy*0.6), + value=cfg['Config Max Players']['coop_max_players'], + config='coop_max_players', + text=coop_text) + + # teams + ConfigNumberEdit(parent=self.root_widget, + position=(posx, posy*0.38), + value=cfg['Config Max Players']['teams_max_players'], + config='teams_max_players', + text=teams_text) + + # ffa + ConfigNumberEdit(parent=self.root_widget, + position=(posx, posy*0.16), + value=cfg['Config Max Players']['ffa_max_players'], + config='ffa_max_players', + text=ffa_text) + + def _on_cancel_press(self) -> None: + self._transition_out() + + def _transition_out(self) -> None: + if not self._transitioning_out: + self._transitioning_out = True + ba.containerwidget(edit=self.root_widget, transition='out_scale') + + def on_popup_cancel(self) -> None: + ba.playsound(ba.getsound('swish')) + self._transition_out() + + +def __init__(self) -> None: + """Instantiate a co-op mode session.""" + # pylint: disable=cyclic-import + from ba._campaign import getcampaign + from bastd.activity.coopjoin import CoopJoinActivity + + _ba.increment_analytics_count('Co-op session start') + app = _ba.app + + # If they passed in explicit min/max, honor that. + # Otherwise defer to user overrides or defaults. + if 'min_players' in app.coop_session_args: + min_players = app.coop_session_args['min_players'] + else: + min_players = 1 + if 'max_players' in app.coop_session_args: + max_players = app.coop_session_args['max_players'] + else: + max_players = app.config.get( + 'Coop Game Max Players', + cfg['Config Max Players']['coop_max_players']) + + # print('FIXME: COOP SESSION WOULD CALC DEPS.') + depsets: Sequence[ba.DependencySet] = [] + + Session.__init__(self, + depsets, + team_names=TEAM_NAMES, + team_colors=TEAM_COLORS, + min_players=min_players, + max_players=max_players) + + # Tournament-ID if we correspond to a co-op tournament (otherwise None) + self.tournament_id: Optional[str] = ( + app.coop_session_args.get('tournament_id')) + + self.campaign = getcampaign(app.coop_session_args['campaign']) + self.campaign_level_name: str = app.coop_session_args['level'] + + self._ran_tutorial_activity = False + self._tutorial_activity: Optional[ba.Activity] = None + self._custom_menu_ui: List[Dict[str, Any]] = [] + + # Start our joining screen. + self.setactivity(_ba.newactivity(CoopJoinActivity)) + + self._next_game_instance: Optional[ba.GameActivity] = None + self._next_game_level_name: Optional[str] = None + self._update_on_deck_game_instances() + + +def get_max_players(self) -> int: + """Return max number of ba.Players allowed to join the game at once.""" + if self.use_teams: + return _ba.app.config.get( + 'Team Game Max Players', + cfg['Config Max Players']['teams_max_players']) + return _ba.app.config.get( + 'Free-for-All Max Players', + cfg['Config Max Players']['ffa_max_players']) + + +GatherWindow.__old_init__ = GatherWindow.__init__ + + +def __gather_init__(self, + transition: Optional[str] = 'in_right', + origin_widget: ba.Widget = None): + self.__old_init__(transition, origin_widget) + + def _do_max_players(): + SettingsMaxPlayers() + self._max_players_button = ba.buttonwidget( + parent=self._root_widget, + position=(self._width*0.72, self._height*0.91), + size=(220, 60), + scale=1.0, + color=(0.6, 0.0, 0.9), + icon=ba.gettexture('usersButton'), + iconscale=1.5, + autoselect=True, + label=title_short_text, + button_type='regular', + on_activate_call=_do_max_players) + + +def _save_state(self) -> None: + try: + for tab in self._tabs.values(): + tab.save_state() + + sel = self._root_widget.get_selected_child() + selected_tab_ids = [ + tab_id for tab_id, tab in self._tab_row.tabs.items() + if sel == tab.button + ] + if sel == self._back_button: + sel_name = 'Back' + elif sel == self._max_players_button: + sel_name = 'Max Players' + elif selected_tab_ids: + assert len(selected_tab_ids) == 1 + sel_name = f'Tab:{selected_tab_ids[0].value}' + elif sel == self._tab_container: + sel_name = 'TabContainer' + else: + raise ValueError(f'unrecognized selection: \'{sel}\'') + ba.app.ui.window_states[type(self)] = { + 'sel_name': sel_name, + } + except Exception: + ba.print_exception(f'Error saving state for {self}.') + + +def _restore_state(self) -> None: + from efro.util import enum_by_value + try: + for tab in self._tabs.values(): + tab.restore_state() + + sel: Optional[ba.Widget] + winstate = ba.app.ui.window_states.get(type(self), {}) + sel_name = winstate.get('sel_name', None) + assert isinstance(sel_name, (str, type(None))) + current_tab = self.TabID.ABOUT + gather_tab_val = ba.app.config.get('Gather Tab') + try: + stored_tab = enum_by_value(self.TabID, gather_tab_val) + if stored_tab in self._tab_row.tabs: + current_tab = stored_tab + except ValueError: + pass + self._set_tab(current_tab) + if sel_name == 'Back': + sel = self._back_button + elif sel_name == 'Max Players': + sel = self._back_button + elif sel_name == 'TabContainer': + sel = self._tab_container + elif isinstance(sel_name, str) and sel_name.startswith('Tab:'): + try: + sel_tab_id = enum_by_value(self.TabID, + sel_name.split(':')[-1]) + except ValueError: + sel_tab_id = self.TabID.ABOUT + sel = self._tab_row.tabs[sel_tab_id].button + else: + sel = self._tab_row.tabs[current_tab].button + ba.containerwidget(edit=self._root_widget, selected_child=sel) + except Exception: + ba.print_exception('Error restoring gather-win state.') + +# ba_meta export plugin + + +class MaxPlayersPlugin(ba.Plugin): + + def has_settings_ui(self) -> bool: + return True + + def show_settings_ui(self, source_widget: ba.Widget | None) -> None: + SettingsMaxPlayers() + + if 'Config Max Players' in ba.app.config: + old_config = ba.app.config['Config Max Players'] + for setting in cmp: + if setting not in old_config: + ba.app.config['Config Max Players'].update({setting: cmp[setting]}) + remove_list = [] + for setting in old_config: + if setting not in cmp: + remove_list.append(setting) + for element in remove_list: + ba.app.config['Config Max Players'].pop(element) + else: + ba.app.config['Config Max Players'] = cmp + ba.app.config.apply_and_commit() + + CoopSession.__init__ = __init__ + MultiTeamSession.get_max_players = get_max_players + GatherWindow.__init__ = __gather_init__ + GatherWindow._save_state = _save_state + GatherWindow._restore_state = _restore_state diff --git a/plugins/utilities/quick_custom_game.py b/plugins/utilities/quick_custom_game.py new file mode 100644 index 00000000..259dff2b --- /dev/null +++ b/plugins/utilities/quick_custom_game.py @@ -0,0 +1,381 @@ +# ba_meta require api 7 +# (see https://ballistica.net/wiki/meta-tag-system) + +from __future__ import annotations + +from typing import TYPE_CHECKING + +import ba +import _ba +from bastd.ui.play import PlayWindow +from bastd.ui.playlist.addgame import PlaylistAddGameWindow +from ba._freeforallsession import FreeForAllSession +from bastd.activity.multiteamjoin import MultiTeamJoinActivity + +if TYPE_CHECKING: + pass + + +lang = ba.app.lang.language + +if lang == 'Spanish': + custom_txt = 'personalizar...' +else: + custom_txt = 'custom...' + + +if 'quick_game_button' in ba.app.config: + config = ba.app.config['quick_game_button'] +else: + config = {'selected': None, 'config': None} + ba.app.config['quick_game_button'] = config + ba.app.config.commit() + + +def start_game(session: ba.Session, fadeout: bool = True): + def callback(): + if fadeout: + _ba.unlock_all_input() + try: + _ba.new_host_session(session) + except Exception: + from bastd import mainmenu + ba.print_exception('exception running session', session) + + # Drop back into a main menu session. + _ba.new_host_session(mainmenu.MainMenuSession) + + if fadeout: + _ba.fade_screen(False, time=0.25, endcall=callback) + _ba.lock_all_input() + else: + callback() + + +class SimplePlaylist: + + def __init__(self, + settings: dict, + gametype: type[ba.GameActivity]): + self.settings = settings + self.gametype = gametype + + def pull_next(self) -> None: + if 'map' not in self.settings['settings']: + settings = dict( + map=self.settings['map'], **self.settings['settings']) + else: + settings = self.settings['settings'] + return dict(resolved_type=self.gametype, settings=settings) + + +class CustomSession(FreeForAllSession): + + def __init__(self, *args, **kwargs): + # pylint: disable=cyclic-import + self.use_teams = False + self._tutorial_activity_instance = None + ba.Session.__init__(self, depsets=[], + team_names=None, + team_colors=None, + min_players=1, + max_players=self.get_max_players()) + + self._series_length = 1 + self._ffa_series_length = 1 + + # Which game activity we're on. + self._game_number = 0 + self._playlist = SimplePlaylist(self._config, self._gametype) + config['selected'] = self._gametype.__name__ + config['config'] = self._config + ba.app.config.commit() + + # Get a game on deck ready to go. + self._current_game_spec: Optional[Dict[str, Any]] = None + self._next_game_spec: Dict[str, Any] = self._playlist.pull_next() + self._next_game: Type[ba.GameActivity] = ( + self._next_game_spec['resolved_type']) + + # Go ahead and instantiate the next game we'll + # use so it has lots of time to load. + self._instantiate_next_game() + + # Start in our custom join screen. + self.setactivity(_ba.newactivity(MultiTeamJoinActivity)) + + +class SelectGameWindow(PlaylistAddGameWindow): + + def __init__(self, transition: str = 'in_right'): + class EditController: + _sessiontype = ba.FreeForAllSession + + def get_session_type(self) -> Type[ba.Session]: + return self._sessiontype + + self._editcontroller = EditController() + self._r = 'addGameWindow' + uiscale = ba.app.ui.uiscale + self._width = 750 if uiscale is ba.UIScale.SMALL else 650 + x_inset = 50 if uiscale is ba.UIScale.SMALL else 0 + self._height = (346 if uiscale is ba.UIScale.SMALL else + 380 if uiscale is ba.UIScale.MEDIUM else 440) + top_extra = 30 if uiscale is ba.UIScale.SMALL else 20 + self._scroll_width = 210 + + self._root_widget = ba.containerwidget( + size=(self._width, self._height + top_extra), + transition=transition, + scale=(2.17 if uiscale is ba.UIScale.SMALL else + 1.5 if uiscale is ba.UIScale.MEDIUM else 1.0), + stack_offset=(0, 1) if uiscale is ba.UIScale.SMALL else (0, 0)) + + self._back_button = ba.buttonwidget(parent=self._root_widget, + position=(58 + x_inset, + self._height - 53), + size=(165, 70), + scale=0.75, + text_scale=1.2, + label=ba.Lstr(resource='backText'), + autoselect=True, + button_type='back', + on_activate_call=self._back) + self._select_button = select_button = ba.buttonwidget( + parent=self._root_widget, + position=(self._width - (172 + x_inset), self._height - 50), + autoselect=True, + size=(160, 60), + scale=0.75, + text_scale=1.2, + label=ba.Lstr(resource='selectText'), + on_activate_call=self._add) + + if ba.app.ui.use_toolbars: + ba.widget(edit=select_button, + right_widget=_ba.get_special_widget('party_button')) + + ba.textwidget(parent=self._root_widget, + position=(self._width * 0.5, self._height - 28), + size=(0, 0), + scale=1.0, + text=ba.Lstr(resource=self._r + '.titleText'), + h_align='center', + color=ba.app.ui.title_color, + maxwidth=250, + v_align='center') + v = self._height - 64 + + self._selected_title_text = ba.textwidget( + parent=self._root_widget, + position=(x_inset + self._scroll_width + 50 + 30, v - 15), + size=(0, 0), + scale=1.0, + color=(0.7, 1.0, 0.7, 1.0), + maxwidth=self._width - self._scroll_width - 150 - x_inset * 2, + h_align='left', + v_align='center') + v -= 30 + + self._selected_description_text = ba.textwidget( + parent=self._root_widget, + position=(x_inset + self._scroll_width + 50 + 30, v), + size=(0, 0), + scale=0.7, + color=(0.5, 0.8, 0.5, 1.0), + maxwidth=self._width - self._scroll_width - 150 - x_inset * 2, + h_align='left') + + scroll_height = self._height - 100 + + v = self._height - 60 + + self._scrollwidget = ba.scrollwidget(parent=self._root_widget, + position=(x_inset + 61, + v - scroll_height), + size=(self._scroll_width, + scroll_height), + highlight=False) + ba.widget(edit=self._scrollwidget, + up_widget=self._back_button, + left_widget=self._back_button, + right_widget=select_button) + self._column: Optional[ba.Widget] = None + + v -= 35 + ba.containerwidget(edit=self._root_widget, + cancel_button=self._back_button, + start_button=select_button) + self._selected_game_type: Optional[Type[ba.GameActivity]] = None + + ba.containerwidget(edit=self._root_widget, + selected_child=self._scrollwidget) + + self._game_types: list[type[ba.GameActivity]] = [] + + # Get actual games loading in the bg. + ba.app.meta.load_exported_classes(ba.GameActivity, + self._on_game_types_loaded, + completion_cb_in_bg_thread=True) + + # Refresh with our initial empty list. We'll refresh again once + # game loading is complete. + self._refresh() + + if config['selected']: + for gt in self._game_types: + if gt.__name__ == config['selected']: + self._refresh(selected=gt) + self._set_selected_game_type(gt) + + def _refresh(self, + select_get_more_games_button: bool = False, + selected: bool = None) -> None: + # from ba.internal import get_game_types + + if self._column is not None: + self._column.delete() + + self._column = ba.columnwidget(parent=self._scrollwidget, + border=2, + margin=0) + + for i, gametype in enumerate(self._game_types): + + def _doit() -> None: + if self._select_button: + ba.timer(0.1, + self._select_button.activate, + timetype=ba.TimeType.REAL) + + txt = ba.textwidget(parent=self._column, + position=(0, 0), + size=(self._width - 88, 24), + text=gametype.get_display_string(), + h_align='left', + v_align='center', + color=(0.8, 0.8, 0.8, 1.0), + maxwidth=self._scroll_width * 0.8, + on_select_call=ba.Call( + self._set_selected_game_type, gametype), + always_highlight=True, + selectable=True, + on_activate_call=_doit) + if i == 0: + ba.widget(edit=txt, up_widget=self._back_button) + + self._get_more_games_button = ba.buttonwidget( + parent=self._column, + autoselect=True, + label=ba.Lstr(resource=self._r + '.getMoreGamesText'), + color=(0.54, 0.52, 0.67), + textcolor=(0.7, 0.65, 0.7), + on_activate_call=self._on_get_more_games_press, + size=(178, 50)) + if select_get_more_games_button: + ba.containerwidget(edit=self._column, + selected_child=self._get_more_games_button, + visible_child=self._get_more_games_button) + + def _add(self) -> None: + _ba.lock_all_input() # Make sure no more commands happen. + ba.timer(0.1, _ba.unlock_all_input, timetype=ba.TimeType.REAL) + gameconfig = {} + if config['selected'] == self._selected_game_type.__name__: + if config['config']: + gameconfig = config['config'] + if 'map' in gameconfig: + gameconfig['settings']['map'] = gameconfig.pop('map') + self._selected_game_type.create_settings_ui( + self._editcontroller.get_session_type(), + gameconfig, + self._edit_game_done) + + def _edit_game_done(self, config: Optional[Dict[str, Any]]) -> None: + if config: + CustomSession._config = config + CustomSession._gametype = self._selected_game_type + start_game(CustomSession) + else: + ba.app.ui.clear_main_menu_window(transition='out_right') + ba.app.ui.set_main_menu_window( + SelectGameWindow(transition='in_left').get_root_widget()) + + def _back(self) -> None: + ba.containerwidget(edit=self._root_widget, transition='out_right') + ba.app.ui.set_main_menu_window( + PlayWindow(transition='in_left').get_root_widget()) + + +PlayWindow._old_init = PlayWindow.__init__ + + +def __init__(self, *args, **kwargs): + self._old_init() + + width = 800 + height = 550 + + def do_quick_game() -> None: + self._save_state() + ba.containerwidget(edit=self._root_widget, transition='out_left') + ba.app.ui.set_main_menu_window( + SelectGameWindow().get_root_widget()) + + self._quick_game_button = ba.buttonwidget( + parent=self._root_widget, + position=(width - 55 - 120, height - 132), + autoselect=True, + size=(120, 60), + scale=1.1, + text_scale=1.2, + label=custom_txt, + on_activate_call=do_quick_game, + color=(0.54, 0.52, 0.67), + textcolor=(0.7, 0.65, 0.7)) + + self._restore_state() + + +def states(self) -> None: + return { + 'Team Games': self._teams_button, + 'Co-op Games': self._coop_button, + 'Free-for-All Games': self._free_for_all_button, + 'Back': self._back_button, + 'Quick Game': self._quick_game_button + } + + +def _save_state(self) -> None: + swapped = {v: k for k, v in states(self).items()} + if self._root_widget.get_selected_child() in swapped: + ba.app.ui.window_states[ + self.__class__.__name__] = swapped[ + self._root_widget.get_selected_child()] + else: + ba.print_exception(f'Error saving state for {self}.') + + +def _restore_state(self) -> None: + if not hasattr(self, '_quick_game_button'): + return # ensure that our monkey patched init ran + if self.__class__.__name__ not in ba.app.ui.window_states: + ba.containerwidget(edit=self._root_widget, + selected_child=self._coop_button) + return + sel = states(self).get( + ba.app.ui.window_states[self.__class__.__name__], None) + if sel: + ba.containerwidget(edit=self._root_widget, selected_child=sel) + else: + ba.containerwidget(edit=self._root_widget, + selected_child=self._coop_button) + ba.print_exception(f'Error restoring state for {self}.') + + +# ba_meta export plugin +class QuickGamePlugin(ba.Plugin): + PlayWindow.__init__ = __init__ + PlayWindow._save_state = _save_state + PlayWindow._restore_state = _restore_state diff --git a/plugins/utilities/random_colors.py b/plugins/utilities/random_colors.py new file mode 100644 index 00000000..3ea0ba6e --- /dev/null +++ b/plugins/utilities/random_colors.py @@ -0,0 +1,48 @@ +# ba_meta require api 7 +# (see https://ballistica.net/wiki/meta-tag-system) + +from __future__ import annotations + +from typing import TYPE_CHECKING + +import ba +import random +from bastd.actor import bomb + +if TYPE_CHECKING: + from typing import Sequence + + +class NewBlast(bomb.Blast): + def __init__( + self, + position: Sequence[float] = (0.0, 1.0, 0.0), + velocity: Sequence[float] = (0.0, 0.0, 0.0), + blast_radius: float = 2.0, + blast_type: str = 'normal', + source_player: ba.Player | None = None, + hit_type: str = 'explosion', + hit_subtype: str = 'normal', + ): + super().__init__(position, velocity, blast_radius, blast_type, + source_player, hit_type, hit_subtype) + scorch_radius = light_radius = self.radius + if self.blast_type == 'tnt': + scorch_radius *= 1.15 + scorch = ba.newnode( + 'scorch', + attrs={ + 'position': position, + 'size': scorch_radius * 0.5, + 'big': (self.blast_type == 'tnt'), + }, + ) + random_color = (random.random(), random.random(), random.random()) + scorch.color = ba.safecolor(random_color) + ba.animate(scorch, 'presence', {3.000: 1, 13.000: 0}) + ba.timer(13.0, scorch.delete) + + +# ba_meta export plugin +class RandomColorsPlugin(ba.Plugin): + bomb.Blast = NewBlast From 8a8c6210960917dc50807d030624af9d9da26b4c Mon Sep 17 00:00:00 2001 From: Loup <90267658+Loup-Garou911XD@users.noreply.github.com> Date: Mon, 7 Nov 2022 00:22:02 +0530 Subject: [PATCH 0221/1464] Update utilities.json --- plugins/utilities.json | 24 +++++++++++++++++++----- 1 file changed, 19 insertions(+), 5 deletions(-) diff --git a/plugins/utilities.json b/plugins/utilities.json index c146ec6d..9b67e84b 100644 --- a/plugins/utilities.json +++ b/plugins/utilities.json @@ -3,7 +3,21 @@ "description": "Utilities", "plugins_base_url": "http://github.com/bombsquad-community/plugin-manager/{content_type}/{tag}/plugins/utilities", "plugins": { - "CustomDeath": { + "share_replay": { + "description": "Export replays to mods folder and share them with friends or have a backup", + "external_url": null, + "authors": [ + { + "name": "LoupGarou", + "email": "LoupGarou5418@outlook.com", + "discord": "ʟօʊքɢǟʀօʊ#3063" + } + ], + "versions": { + "1.0.0":null + } + }, + "custom_death": { "description": "Characters turn to Bones after death", "external_url": "https://youtube.com/c/JoseANG3LYT", "authors": [ @@ -22,7 +36,7 @@ } } }, - "MaxPlayers": { + "max_players": { "description": "Increase the max player limit of 8 players", "external_url": "https://youtube.com/c/JoseANG3LYT", "authors": [ @@ -41,7 +55,7 @@ } } }, - "QuickCustomGame": { + "quick_custom_game": { "description": "Quckly create a custom game with any gamemode", "external_url": "https://youtube.com/c/JoseANG3LYT", "authors": [ @@ -60,7 +74,7 @@ } } }, - "RandomColors": { + "random_colors": { "description": "Creates patches of random color after bomb explosions", "external_url": "https://youtube.com/c/JoseANG3LYT", "authors": [ @@ -410,4 +424,4 @@ } } } -} \ No newline at end of file +} From ed06dac4b8464dacb5c6f3fe5b62b482c55f1b8e Mon Sep 17 00:00:00 2001 From: Loup <90267658+Loup-Garou911XD@users.noreply.github.com> Date: Mon, 7 Nov 2022 00:22:59 +0530 Subject: [PATCH 0222/1464] Delete CustomDeath.py --- plugins/utilities/CustomDeath.py | 40 -------------------------------- 1 file changed, 40 deletions(-) delete mode 100644 plugins/utilities/CustomDeath.py diff --git a/plugins/utilities/CustomDeath.py b/plugins/utilities/CustomDeath.py deleted file mode 100644 index b3730e12..00000000 --- a/plugins/utilities/CustomDeath.py +++ /dev/null @@ -1,40 +0,0 @@ -# ba_meta require api 7 -# (see https://ballistica.net/wiki/meta-tag-system) - -from __future__ import annotations - -from typing import TYPE_CHECKING - -import ba -from bastd.actor.spaz import Spaz - -if TYPE_CHECKING: - from typing import Any - - -Spaz.oldhandlemessage = Spaz.handlemessage - - -def handlemessage(self, msg: Any) -> Any: - if isinstance(msg, ba.DieMessage): - if self.node: - self.node.color_texture = ba.gettexture('bonesColor') - self.node.color_mask_texture = ba.gettexture('bonesColorMask') - self.node.head_model = ba.getmodel('bonesHead') - self.node.torso_model = ba.getmodel('bonesTorso') - self.node.pelvis_model = ba.getmodel('bonesPelvis') - self.node.upper_arm_model = ba.getmodel('bonesUpperArm') - self.node.forearm_model = ba.getmodel('bonesForeArm') - self.node.hand_model = ba.getmodel('bonesHand') - self.node.upper_leg_model = ba.getmodel('bonesUpperLeg') - self.node.lower_leg_model = ba.getmodel('bonesLowerLeg') - self.node.toes_model = ba.getmodel('bonesToes') - self.node.style = 'bones' - self.oldhandlemessage(msg) - else: - return self.oldhandlemessage(msg) - - -# ba_meta export plugin -class CustomDeath(ba.Plugin): - Spaz.handlemessage = handlemessage From 8b3e6a8d8418c774d0d4f07f8d6517a2d91fb1dc Mon Sep 17 00:00:00 2001 From: Loup <90267658+Loup-Garou911XD@users.noreply.github.com> Date: Mon, 7 Nov 2022 00:23:12 +0530 Subject: [PATCH 0223/1464] Delete MaxPlayers.py --- plugins/utilities/MaxPlayers.py | 368 -------------------------------- 1 file changed, 368 deletions(-) delete mode 100644 plugins/utilities/MaxPlayers.py diff --git a/plugins/utilities/MaxPlayers.py b/plugins/utilities/MaxPlayers.py deleted file mode 100644 index 6d6257a4..00000000 --- a/plugins/utilities/MaxPlayers.py +++ /dev/null @@ -1,368 +0,0 @@ -"""===========MAX_PLAYERS===========""" - -# ba_meta require api 7 -# (see https://ballistica.net/wiki/meta-tag-system) - -from __future__ import annotations -from typing import TYPE_CHECKING - -import ba -import _ba -from ba._session import Session -from ba._coopsession import CoopSession, TEAM_COLORS, TEAM_NAMES -from ba._multiteamsession import MultiTeamSession -from bastd.ui.gather import GatherWindow -from bastd.ui.popup import PopupWindow - -if TYPE_CHECKING: - from typing import List, Any, Optional, Sequence - - -cfg = ba.app.config -cmp = {'coop_max_players': 4, - 'teams_max_players': 8, - 'ffa_max_players': 8} - -lang = ba.app.lang.language -if lang == 'Spanish': - title_text = 'Máximo de Jugadores' - title_short_text = 'Jugadores' - coop_text = 'Cooperativo' - teams_text = 'Equipos' - ffa_text = 'Todos Contra Todos' -else: - title_text = 'Max Players' - title_short_text = 'Players' - coop_text = 'Co-op' - teams_text = 'Teams' - ffa_text = 'FFA' - - -class ConfigNumberEdit: - - def __init__(self, - parent: ba.Widget, - position: Tuple[float, float], - value: int, - config: str, - text: str): - self._increment = 1 - self._minval = 1 - self._maxval = 100 - self._value = value - self._config = config - - textscale = 1.0 - self.nametext = ba.textwidget( - parent=parent, - position=(position[0], position[1]), - size=(100, 30), - text=text, - maxwidth=150, - color=(0.8, 0.8, 0.8, 1.0), - h_align='left', - v_align='center', - scale=textscale) - self.valuetext = ba.textwidget( - parent=parent, - position=(position[0]+150, position[1]), - size=(60, 28), - editable=False, - color=(0.3, 1.0, 0.3, 1.0), - h_align='right', - v_align='center', - text=str(value), - padding=2) - self.minusbutton = ba.buttonwidget( - parent=parent, - position=(position[0]+240, position[1]), - size=(28, 28), - label='-', - autoselect=True, - on_activate_call=ba.Call(self._down), - repeat=True) - self.plusbutton = ba.buttonwidget( - parent=parent, - position=(position[0]+290, position[1]), - size=(28, 28), - label='+', - autoselect=True, - on_activate_call=ba.Call(self._up), - repeat=True) - - def _up(self) -> None: - self._value = min(self._maxval, self._value + self._increment) - self._update_display() - - def _down(self) -> None: - self._value = max(self._minval, self._value - self._increment) - self._update_display() - - def _update_display(self) -> None: - ba.textwidget(edit=self.valuetext, text=str(self._value)) - cfg['Config Max Players'][self._config] = self._value - cfg.apply_and_commit() - - -class SettingsMaxPlayers(PopupWindow): - - def __init__(self): - # pylint: disable=too-many-locals - uiscale = ba.app.ui.uiscale - self._transitioning_out = False - self._width = 400 - self._height = 220 - bg_color = (0.5, 0.4, 0.6) - - # creates our _root_widget - PopupWindow.__init__(self, - position=(0.0, 0.0), - size=(self._width, self._height), - scale=1.2, - bg_color=bg_color) - - self._cancel_button = ba.buttonwidget( - parent=self.root_widget, - position=(25, self._height - 40), - size=(50, 50), - scale=0.58, - label='', - color=bg_color, - on_activate_call=self._on_cancel_press, - autoselect=True, - icon=ba.gettexture('crossOut'), - iconscale=1.2) - ba.containerwidget(edit=self.root_widget, - cancel_button=self._cancel_button) - - ba.textwidget( - parent=self.root_widget, - position=(self._width * 0.5, self._height - 30), - size=(0, 0), - h_align='center', - v_align='center', - scale=0.8, - text=title_text, - maxwidth=200, - color=ba.app.ui.title_color) - - posx = 33 - posy = self._height - - # co-op - ConfigNumberEdit(parent=self.root_widget, - position=(posx, posy*0.6), - value=cfg['Config Max Players']['coop_max_players'], - config='coop_max_players', - text=coop_text) - - # teams - ConfigNumberEdit(parent=self.root_widget, - position=(posx, posy*0.38), - value=cfg['Config Max Players']['teams_max_players'], - config='teams_max_players', - text=teams_text) - - # ffa - ConfigNumberEdit(parent=self.root_widget, - position=(posx, posy*0.16), - value=cfg['Config Max Players']['ffa_max_players'], - config='ffa_max_players', - text=ffa_text) - - def _on_cancel_press(self) -> None: - self._transition_out() - - def _transition_out(self) -> None: - if not self._transitioning_out: - self._transitioning_out = True - ba.containerwidget(edit=self.root_widget, transition='out_scale') - - def on_popup_cancel(self) -> None: - ba.playsound(ba.getsound('swish')) - self._transition_out() - - -def __init__(self) -> None: - """Instantiate a co-op mode session.""" - # pylint: disable=cyclic-import - from ba._campaign import getcampaign - from bastd.activity.coopjoin import CoopJoinActivity - - _ba.increment_analytics_count('Co-op session start') - app = _ba.app - - # If they passed in explicit min/max, honor that. - # Otherwise defer to user overrides or defaults. - if 'min_players' in app.coop_session_args: - min_players = app.coop_session_args['min_players'] - else: - min_players = 1 - if 'max_players' in app.coop_session_args: - max_players = app.coop_session_args['max_players'] - else: - max_players = app.config.get( - 'Coop Game Max Players', - cfg['Config Max Players']['coop_max_players']) - - # print('FIXME: COOP SESSION WOULD CALC DEPS.') - depsets: Sequence[ba.DependencySet] = [] - - Session.__init__(self, - depsets, - team_names=TEAM_NAMES, - team_colors=TEAM_COLORS, - min_players=min_players, - max_players=max_players) - - # Tournament-ID if we correspond to a co-op tournament (otherwise None) - self.tournament_id: Optional[str] = ( - app.coop_session_args.get('tournament_id')) - - self.campaign = getcampaign(app.coop_session_args['campaign']) - self.campaign_level_name: str = app.coop_session_args['level'] - - self._ran_tutorial_activity = False - self._tutorial_activity: Optional[ba.Activity] = None - self._custom_menu_ui: List[Dict[str, Any]] = [] - - # Start our joining screen. - self.setactivity(_ba.newactivity(CoopJoinActivity)) - - self._next_game_instance: Optional[ba.GameActivity] = None - self._next_game_level_name: Optional[str] = None - self._update_on_deck_game_instances() - - -def get_max_players(self) -> int: - """Return max number of ba.Players allowed to join the game at once.""" - if self.use_teams: - return _ba.app.config.get( - 'Team Game Max Players', - cfg['Config Max Players']['teams_max_players']) - return _ba.app.config.get( - 'Free-for-All Max Players', - cfg['Config Max Players']['ffa_max_players']) - - -GatherWindow.__old_init__ = GatherWindow.__init__ - - -def __gather_init__(self, - transition: Optional[str] = 'in_right', - origin_widget: ba.Widget = None): - self.__old_init__(transition, origin_widget) - - def _do_max_players(): - SettingsMaxPlayers() - self._max_players_button = ba.buttonwidget( - parent=self._root_widget, - position=(self._width*0.72, self._height*0.91), - size=(220, 60), - scale=1.0, - color=(0.6, 0.0, 0.9), - icon=ba.gettexture('usersButton'), - iconscale=1.5, - autoselect=True, - label=title_short_text, - button_type='regular', - on_activate_call=_do_max_players) - - -def _save_state(self) -> None: - try: - for tab in self._tabs.values(): - tab.save_state() - - sel = self._root_widget.get_selected_child() - selected_tab_ids = [ - tab_id for tab_id, tab in self._tab_row.tabs.items() - if sel == tab.button - ] - if sel == self._back_button: - sel_name = 'Back' - elif sel == self._max_players_button: - sel_name = 'Max Players' - elif selected_tab_ids: - assert len(selected_tab_ids) == 1 - sel_name = f'Tab:{selected_tab_ids[0].value}' - elif sel == self._tab_container: - sel_name = 'TabContainer' - else: - raise ValueError(f'unrecognized selection: \'{sel}\'') - ba.app.ui.window_states[type(self)] = { - 'sel_name': sel_name, - } - except Exception: - ba.print_exception(f'Error saving state for {self}.') - - -def _restore_state(self) -> None: - from efro.util import enum_by_value - try: - for tab in self._tabs.values(): - tab.restore_state() - - sel: Optional[ba.Widget] - winstate = ba.app.ui.window_states.get(type(self), {}) - sel_name = winstate.get('sel_name', None) - assert isinstance(sel_name, (str, type(None))) - current_tab = self.TabID.ABOUT - gather_tab_val = ba.app.config.get('Gather Tab') - try: - stored_tab = enum_by_value(self.TabID, gather_tab_val) - if stored_tab in self._tab_row.tabs: - current_tab = stored_tab - except ValueError: - pass - self._set_tab(current_tab) - if sel_name == 'Back': - sel = self._back_button - elif sel_name == 'Max Players': - sel = self._back_button - elif sel_name == 'TabContainer': - sel = self._tab_container - elif isinstance(sel_name, str) and sel_name.startswith('Tab:'): - try: - sel_tab_id = enum_by_value(self.TabID, - sel_name.split(':')[-1]) - except ValueError: - sel_tab_id = self.TabID.ABOUT - sel = self._tab_row.tabs[sel_tab_id].button - else: - sel = self._tab_row.tabs[current_tab].button - ba.containerwidget(edit=self._root_widget, selected_child=sel) - except Exception: - ba.print_exception('Error restoring gather-win state.') - -# ba_meta export plugin - - -class MaxPlayersPlugin(ba.Plugin): - - def has_settings_ui(self) -> bool: - return True - - def show_settings_ui(self, source_widget: ba.Widget | None) -> None: - SettingsMaxPlayers() - - if 'Config Max Players' in ba.app.config: - old_config = ba.app.config['Config Max Players'] - for setting in cmp: - if setting not in old_config: - ba.app.config['Config Max Players'].update({setting: cmp[setting]}) - remove_list = [] - for setting in old_config: - if setting not in cmp: - remove_list.append(setting) - for element in remove_list: - ba.app.config['Config Max Players'].pop(element) - else: - ba.app.config['Config Max Players'] = cmp - ba.app.config.apply_and_commit() - - CoopSession.__init__ = __init__ - MultiTeamSession.get_max_players = get_max_players - GatherWindow.__init__ = __gather_init__ - GatherWindow._save_state = _save_state - GatherWindow._restore_state = _restore_state From 9f817d8ee8422feb02bd6437177768c9a7485236 Mon Sep 17 00:00:00 2001 From: Loup <90267658+Loup-Garou911XD@users.noreply.github.com> Date: Mon, 7 Nov 2022 00:23:27 +0530 Subject: [PATCH 0224/1464] Delete QuickCustomGame.py --- plugins/utilities/QuickCustomGame.py | 381 --------------------------- 1 file changed, 381 deletions(-) delete mode 100644 plugins/utilities/QuickCustomGame.py diff --git a/plugins/utilities/QuickCustomGame.py b/plugins/utilities/QuickCustomGame.py deleted file mode 100644 index 259dff2b..00000000 --- a/plugins/utilities/QuickCustomGame.py +++ /dev/null @@ -1,381 +0,0 @@ -# ba_meta require api 7 -# (see https://ballistica.net/wiki/meta-tag-system) - -from __future__ import annotations - -from typing import TYPE_CHECKING - -import ba -import _ba -from bastd.ui.play import PlayWindow -from bastd.ui.playlist.addgame import PlaylistAddGameWindow -from ba._freeforallsession import FreeForAllSession -from bastd.activity.multiteamjoin import MultiTeamJoinActivity - -if TYPE_CHECKING: - pass - - -lang = ba.app.lang.language - -if lang == 'Spanish': - custom_txt = 'personalizar...' -else: - custom_txt = 'custom...' - - -if 'quick_game_button' in ba.app.config: - config = ba.app.config['quick_game_button'] -else: - config = {'selected': None, 'config': None} - ba.app.config['quick_game_button'] = config - ba.app.config.commit() - - -def start_game(session: ba.Session, fadeout: bool = True): - def callback(): - if fadeout: - _ba.unlock_all_input() - try: - _ba.new_host_session(session) - except Exception: - from bastd import mainmenu - ba.print_exception('exception running session', session) - - # Drop back into a main menu session. - _ba.new_host_session(mainmenu.MainMenuSession) - - if fadeout: - _ba.fade_screen(False, time=0.25, endcall=callback) - _ba.lock_all_input() - else: - callback() - - -class SimplePlaylist: - - def __init__(self, - settings: dict, - gametype: type[ba.GameActivity]): - self.settings = settings - self.gametype = gametype - - def pull_next(self) -> None: - if 'map' not in self.settings['settings']: - settings = dict( - map=self.settings['map'], **self.settings['settings']) - else: - settings = self.settings['settings'] - return dict(resolved_type=self.gametype, settings=settings) - - -class CustomSession(FreeForAllSession): - - def __init__(self, *args, **kwargs): - # pylint: disable=cyclic-import - self.use_teams = False - self._tutorial_activity_instance = None - ba.Session.__init__(self, depsets=[], - team_names=None, - team_colors=None, - min_players=1, - max_players=self.get_max_players()) - - self._series_length = 1 - self._ffa_series_length = 1 - - # Which game activity we're on. - self._game_number = 0 - self._playlist = SimplePlaylist(self._config, self._gametype) - config['selected'] = self._gametype.__name__ - config['config'] = self._config - ba.app.config.commit() - - # Get a game on deck ready to go. - self._current_game_spec: Optional[Dict[str, Any]] = None - self._next_game_spec: Dict[str, Any] = self._playlist.pull_next() - self._next_game: Type[ba.GameActivity] = ( - self._next_game_spec['resolved_type']) - - # Go ahead and instantiate the next game we'll - # use so it has lots of time to load. - self._instantiate_next_game() - - # Start in our custom join screen. - self.setactivity(_ba.newactivity(MultiTeamJoinActivity)) - - -class SelectGameWindow(PlaylistAddGameWindow): - - def __init__(self, transition: str = 'in_right'): - class EditController: - _sessiontype = ba.FreeForAllSession - - def get_session_type(self) -> Type[ba.Session]: - return self._sessiontype - - self._editcontroller = EditController() - self._r = 'addGameWindow' - uiscale = ba.app.ui.uiscale - self._width = 750 if uiscale is ba.UIScale.SMALL else 650 - x_inset = 50 if uiscale is ba.UIScale.SMALL else 0 - self._height = (346 if uiscale is ba.UIScale.SMALL else - 380 if uiscale is ba.UIScale.MEDIUM else 440) - top_extra = 30 if uiscale is ba.UIScale.SMALL else 20 - self._scroll_width = 210 - - self._root_widget = ba.containerwidget( - size=(self._width, self._height + top_extra), - transition=transition, - scale=(2.17 if uiscale is ba.UIScale.SMALL else - 1.5 if uiscale is ba.UIScale.MEDIUM else 1.0), - stack_offset=(0, 1) if uiscale is ba.UIScale.SMALL else (0, 0)) - - self._back_button = ba.buttonwidget(parent=self._root_widget, - position=(58 + x_inset, - self._height - 53), - size=(165, 70), - scale=0.75, - text_scale=1.2, - label=ba.Lstr(resource='backText'), - autoselect=True, - button_type='back', - on_activate_call=self._back) - self._select_button = select_button = ba.buttonwidget( - parent=self._root_widget, - position=(self._width - (172 + x_inset), self._height - 50), - autoselect=True, - size=(160, 60), - scale=0.75, - text_scale=1.2, - label=ba.Lstr(resource='selectText'), - on_activate_call=self._add) - - if ba.app.ui.use_toolbars: - ba.widget(edit=select_button, - right_widget=_ba.get_special_widget('party_button')) - - ba.textwidget(parent=self._root_widget, - position=(self._width * 0.5, self._height - 28), - size=(0, 0), - scale=1.0, - text=ba.Lstr(resource=self._r + '.titleText'), - h_align='center', - color=ba.app.ui.title_color, - maxwidth=250, - v_align='center') - v = self._height - 64 - - self._selected_title_text = ba.textwidget( - parent=self._root_widget, - position=(x_inset + self._scroll_width + 50 + 30, v - 15), - size=(0, 0), - scale=1.0, - color=(0.7, 1.0, 0.7, 1.0), - maxwidth=self._width - self._scroll_width - 150 - x_inset * 2, - h_align='left', - v_align='center') - v -= 30 - - self._selected_description_text = ba.textwidget( - parent=self._root_widget, - position=(x_inset + self._scroll_width + 50 + 30, v), - size=(0, 0), - scale=0.7, - color=(0.5, 0.8, 0.5, 1.0), - maxwidth=self._width - self._scroll_width - 150 - x_inset * 2, - h_align='left') - - scroll_height = self._height - 100 - - v = self._height - 60 - - self._scrollwidget = ba.scrollwidget(parent=self._root_widget, - position=(x_inset + 61, - v - scroll_height), - size=(self._scroll_width, - scroll_height), - highlight=False) - ba.widget(edit=self._scrollwidget, - up_widget=self._back_button, - left_widget=self._back_button, - right_widget=select_button) - self._column: Optional[ba.Widget] = None - - v -= 35 - ba.containerwidget(edit=self._root_widget, - cancel_button=self._back_button, - start_button=select_button) - self._selected_game_type: Optional[Type[ba.GameActivity]] = None - - ba.containerwidget(edit=self._root_widget, - selected_child=self._scrollwidget) - - self._game_types: list[type[ba.GameActivity]] = [] - - # Get actual games loading in the bg. - ba.app.meta.load_exported_classes(ba.GameActivity, - self._on_game_types_loaded, - completion_cb_in_bg_thread=True) - - # Refresh with our initial empty list. We'll refresh again once - # game loading is complete. - self._refresh() - - if config['selected']: - for gt in self._game_types: - if gt.__name__ == config['selected']: - self._refresh(selected=gt) - self._set_selected_game_type(gt) - - def _refresh(self, - select_get_more_games_button: bool = False, - selected: bool = None) -> None: - # from ba.internal import get_game_types - - if self._column is not None: - self._column.delete() - - self._column = ba.columnwidget(parent=self._scrollwidget, - border=2, - margin=0) - - for i, gametype in enumerate(self._game_types): - - def _doit() -> None: - if self._select_button: - ba.timer(0.1, - self._select_button.activate, - timetype=ba.TimeType.REAL) - - txt = ba.textwidget(parent=self._column, - position=(0, 0), - size=(self._width - 88, 24), - text=gametype.get_display_string(), - h_align='left', - v_align='center', - color=(0.8, 0.8, 0.8, 1.0), - maxwidth=self._scroll_width * 0.8, - on_select_call=ba.Call( - self._set_selected_game_type, gametype), - always_highlight=True, - selectable=True, - on_activate_call=_doit) - if i == 0: - ba.widget(edit=txt, up_widget=self._back_button) - - self._get_more_games_button = ba.buttonwidget( - parent=self._column, - autoselect=True, - label=ba.Lstr(resource=self._r + '.getMoreGamesText'), - color=(0.54, 0.52, 0.67), - textcolor=(0.7, 0.65, 0.7), - on_activate_call=self._on_get_more_games_press, - size=(178, 50)) - if select_get_more_games_button: - ba.containerwidget(edit=self._column, - selected_child=self._get_more_games_button, - visible_child=self._get_more_games_button) - - def _add(self) -> None: - _ba.lock_all_input() # Make sure no more commands happen. - ba.timer(0.1, _ba.unlock_all_input, timetype=ba.TimeType.REAL) - gameconfig = {} - if config['selected'] == self._selected_game_type.__name__: - if config['config']: - gameconfig = config['config'] - if 'map' in gameconfig: - gameconfig['settings']['map'] = gameconfig.pop('map') - self._selected_game_type.create_settings_ui( - self._editcontroller.get_session_type(), - gameconfig, - self._edit_game_done) - - def _edit_game_done(self, config: Optional[Dict[str, Any]]) -> None: - if config: - CustomSession._config = config - CustomSession._gametype = self._selected_game_type - start_game(CustomSession) - else: - ba.app.ui.clear_main_menu_window(transition='out_right') - ba.app.ui.set_main_menu_window( - SelectGameWindow(transition='in_left').get_root_widget()) - - def _back(self) -> None: - ba.containerwidget(edit=self._root_widget, transition='out_right') - ba.app.ui.set_main_menu_window( - PlayWindow(transition='in_left').get_root_widget()) - - -PlayWindow._old_init = PlayWindow.__init__ - - -def __init__(self, *args, **kwargs): - self._old_init() - - width = 800 - height = 550 - - def do_quick_game() -> None: - self._save_state() - ba.containerwidget(edit=self._root_widget, transition='out_left') - ba.app.ui.set_main_menu_window( - SelectGameWindow().get_root_widget()) - - self._quick_game_button = ba.buttonwidget( - parent=self._root_widget, - position=(width - 55 - 120, height - 132), - autoselect=True, - size=(120, 60), - scale=1.1, - text_scale=1.2, - label=custom_txt, - on_activate_call=do_quick_game, - color=(0.54, 0.52, 0.67), - textcolor=(0.7, 0.65, 0.7)) - - self._restore_state() - - -def states(self) -> None: - return { - 'Team Games': self._teams_button, - 'Co-op Games': self._coop_button, - 'Free-for-All Games': self._free_for_all_button, - 'Back': self._back_button, - 'Quick Game': self._quick_game_button - } - - -def _save_state(self) -> None: - swapped = {v: k for k, v in states(self).items()} - if self._root_widget.get_selected_child() in swapped: - ba.app.ui.window_states[ - self.__class__.__name__] = swapped[ - self._root_widget.get_selected_child()] - else: - ba.print_exception(f'Error saving state for {self}.') - - -def _restore_state(self) -> None: - if not hasattr(self, '_quick_game_button'): - return # ensure that our monkey patched init ran - if self.__class__.__name__ not in ba.app.ui.window_states: - ba.containerwidget(edit=self._root_widget, - selected_child=self._coop_button) - return - sel = states(self).get( - ba.app.ui.window_states[self.__class__.__name__], None) - if sel: - ba.containerwidget(edit=self._root_widget, selected_child=sel) - else: - ba.containerwidget(edit=self._root_widget, - selected_child=self._coop_button) - ba.print_exception(f'Error restoring state for {self}.') - - -# ba_meta export plugin -class QuickGamePlugin(ba.Plugin): - PlayWindow.__init__ = __init__ - PlayWindow._save_state = _save_state - PlayWindow._restore_state = _restore_state From ba47887e8b4d360a41569b3a0978c7bb7d85d1ab Mon Sep 17 00:00:00 2001 From: Loup <90267658+Loup-Garou911XD@users.noreply.github.com> Date: Mon, 7 Nov 2022 00:23:37 +0530 Subject: [PATCH 0225/1464] Delete RandomColors.py --- plugins/utilities/RandomColors.py | 48 ------------------------------- 1 file changed, 48 deletions(-) delete mode 100644 plugins/utilities/RandomColors.py diff --git a/plugins/utilities/RandomColors.py b/plugins/utilities/RandomColors.py deleted file mode 100644 index 3ea0ba6e..00000000 --- a/plugins/utilities/RandomColors.py +++ /dev/null @@ -1,48 +0,0 @@ -# ba_meta require api 7 -# (see https://ballistica.net/wiki/meta-tag-system) - -from __future__ import annotations - -from typing import TYPE_CHECKING - -import ba -import random -from bastd.actor import bomb - -if TYPE_CHECKING: - from typing import Sequence - - -class NewBlast(bomb.Blast): - def __init__( - self, - position: Sequence[float] = (0.0, 1.0, 0.0), - velocity: Sequence[float] = (0.0, 0.0, 0.0), - blast_radius: float = 2.0, - blast_type: str = 'normal', - source_player: ba.Player | None = None, - hit_type: str = 'explosion', - hit_subtype: str = 'normal', - ): - super().__init__(position, velocity, blast_radius, blast_type, - source_player, hit_type, hit_subtype) - scorch_radius = light_radius = self.radius - if self.blast_type == 'tnt': - scorch_radius *= 1.15 - scorch = ba.newnode( - 'scorch', - attrs={ - 'position': position, - 'size': scorch_radius * 0.5, - 'big': (self.blast_type == 'tnt'), - }, - ) - random_color = (random.random(), random.random(), random.random()) - scorch.color = ba.safecolor(random_color) - ba.animate(scorch, 'presence', {3.000: 1, 13.000: 0}) - ba.timer(13.0, scorch.delete) - - -# ba_meta export plugin -class RandomColorsPlugin(ba.Plugin): - bomb.Blast = NewBlast From 7c52e529443ba914515c33d42d4ec34e40c39cad Mon Sep 17 00:00:00 2001 From: Loup <90267658+Loup-Garou911XD@users.noreply.github.com> Date: Mon, 7 Nov 2022 00:26:16 +0530 Subject: [PATCH 0226/1464] Add files via upload --- plugins/utilities/share_replay.py | 186 ++++++++++++++++++++++++++++++ 1 file changed, 186 insertions(+) create mode 100644 plugins/utilities/share_replay.py diff --git a/plugins/utilities/share_replay.py b/plugins/utilities/share_replay.py new file mode 100644 index 00000000..584803f1 --- /dev/null +++ b/plugins/utilities/share_replay.py @@ -0,0 +1,186 @@ +# 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 +from shutil import copy,copytree +import ba +import _ba +from bastd.ui.watch import WatchWindow as ww +from bastd.ui.popup import PopupWindow + +#mod by ʟօʊքɢǟʀօʊ +#export replays to mods folder and share with your friends or have a backup + +def Print(*args,color=None,top=None): + out="" + for arg in args: + a=str(arg) + out += a + ba.screenmessage(out,color=color,top=top) + +def cprint(*args): + out="" + for arg in args: + a=str(arg) + out += a + _ba.chatmessage(out) + +internal_dir="/data/data/net.froemling.bombsquad/files/bombsquad_config/replays" +external_dir="/storage/emulated/0/Android/data/net.froemling.bombsquad/files/mods/replays" +#colors +pink=(1,0.2,0.8) +green=(0.4,1,0.4) +red=(1,0,0) + +try: + mkdir(external_dir) + Print("You are ready to share replays",color=pink) +except FileExistsError: + pass + +class Help(PopupWindow): + def __init__(self): + uiscale = ba.app.ui.uiscale + self.width = 800 + self.height = 300 + + PopupWindow.__init__(self, + position=(0.0, 0.0), + size=(self.width, self.height), + scale=1.2,) + + 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•Importing replay and other features comming in v1.2") + + def close(self): + ba.playsound(ba.getsound('swish')) + ba.containerwidget(edit=self.root_widget, transition="out_right",) + + +class SettingWindow(): + def __init__(self): + self.draw_ui() + self.selected_widget = None + self.selected_name= None + + def on_select_text(self,widget,name): + if self.selected_widget is not None: + ba.textwidget(edit=self.selected_widget,color=(1,1,1)) + ba.textwidget(edit=widget,color=(1,1,0)) + self.selected_name = name + self.selected_widget = widget + + 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() + + ba.textwidget( + parent=self.root, + size=(200, 100), + position=(150, 550), + scale=2, + selectable=False, + h_align="center", + v_align="center", + text="ShareReplay", + color=green) + + ba.buttonwidget( + parent=self.root, + position=(400,580), + size=(35,35), + label="Help", + on_activate_call=Help) + + ba.buttonwidget( + parent=self.root, + position=(770, 460), + size=(90, 70), + scale=1.5, + label="EXPORT", + on_activate_call=self.export) + + self.close_button = ba.buttonwidget( + parent=self.root, + position=(820, 590), + size=(35, 35), + icon=ba.gettexture("crossOut"), + icon_color=(1, 0.2, 0.2), + scale=2, + color=(1, 0.2, 0.2), + extra_touch_border_scale=3, + on_activate_call=self.close) + + scroll=ba.scrollwidget( + parent=self.root, + size=(500,400), + position=(200,150)) + self.scroll=ba.columnwidget(parent=scroll,size=(500,900),selection_loops_to_parent=True,single_depth=True) + + height=900 + for i in listdir(internal_dir): + height-=40 + a=i + i = ba.textwidget( + parent=self.scroll, + size=(500,50), + text= i.split(".")[0], + position=(10,height), + selectable=True, + max_chars=40, + click_activate=True,) + + ba.textwidget(edit=i,on_activate_call=ba.Call(self.on_select_text,i,a)) + + + def export(self): + if self.selected_name is None: + Print("Select a replay",color=red) + return + copy(internal_dir+"/"+self.selected_name,external_dir+"/"+self.selected_name) + Print(self.selected_name[0:-4]+" exported", top=True,color=pink)#image={"texture":ba.gettexture("bombColor"),"tint_texture":None,"tint_color":None,"tint2_color":None}) + + def close(self): + ba.playsound(ba.getsound('swish')) + ba.containerwidget(edit=self.root, transition="out_right",) + + +# ++++++++++++++++for keyboard navigation++++++++++++++++ + + #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__ + +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="SHARE REPLAY", + on_activate_call=SettingWindow) + + +# ba_meta export plugin + +class main(ba.Plugin): + def on_app_running(self): + + ww.__init__=new_init + + def has_settings_ui(self): + return True + + def show_settings_ui(self,button): + SettingWindow() + + \ No newline at end of file From 32c6b8361ce61903423c2d334f2f58de3962182d Mon Sep 17 00:00:00 2001 From: Loup-Garou911XD Date: Sun, 6 Nov 2022 18:56:47 +0000 Subject: [PATCH 0227/1464] [ci] auto-format --- plugins/utilities/share_replay.py | 158 ++++++++++++++++-------------- 1 file changed, 82 insertions(+), 76 deletions(-) diff --git a/plugins/utilities/share_replay.py b/plugins/utilities/share_replay.py index 584803f1..61a00298 100644 --- a/plugins/utilities/share_replay.py +++ b/plugins/utilities/share_replay.py @@ -3,58 +3,63 @@ 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 -from shutil import copy,copytree + +from os import listdir, mkdir +from shutil import copy, copytree import ba import _ba from bastd.ui.watch import WatchWindow as ww from bastd.ui.popup import PopupWindow -#mod by ʟօʊքɢǟʀօʊ -#export replays to mods folder and share with your friends or have a backup +# mod by ʟօʊքɢǟʀօʊ +# export replays to mods folder and share with your friends or have a backup + -def Print(*args,color=None,top=None): - out="" +def Print(*args, color=None, top=None): + out = "" for arg in args: - a=str(arg) + a = str(arg) out += a - ba.screenmessage(out,color=color,top=top) + ba.screenmessage(out, color=color, top=top) + def cprint(*args): - out="" + out = "" for arg in args: - a=str(arg) + a = str(arg) out += a _ba.chatmessage(out) - -internal_dir="/data/data/net.froemling.bombsquad/files/bombsquad_config/replays" -external_dir="/storage/emulated/0/Android/data/net.froemling.bombsquad/files/mods/replays" -#colors -pink=(1,0.2,0.8) -green=(0.4,1,0.4) -red=(1,0,0) + + +internal_dir = "/data/data/net.froemling.bombsquad/files/bombsquad_config/replays" +external_dir = "/storage/emulated/0/Android/data/net.froemling.bombsquad/files/mods/replays" +# colors +pink = (1, 0.2, 0.8) +green = (0.4, 1, 0.4) +red = (1, 0, 0) try: mkdir(external_dir) - Print("You are ready to share replays",color=pink) + Print("You are ready to share replays", color=pink) except FileExistsError: pass - + + class Help(PopupWindow): def __init__(self): uiscale = ba.app.ui.uiscale self.width = 800 self.height = 300 - + PopupWindow.__init__(self, position=(0.0, 0.0), size=(self.width, self.height), scale=1.2,) - - 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•Importing replay and other features comming in v1.2") - + + 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•Importing replay and other features comming in v1.2") + def close(self): ba.playsound(ba.getsound('swish')) ba.containerwidget(edit=self.root_widget, transition="out_right",) @@ -64,18 +69,19 @@ class SettingWindow(): def __init__(self): self.draw_ui() self.selected_widget = None - self.selected_name= None - - def on_select_text(self,widget,name): - if self.selected_widget is not None: - ba.textwidget(edit=self.selected_widget,color=(1,1,1)) - ba.textwidget(edit=widget,color=(1,1,0)) + self.selected_name = None + + def on_select_text(self, widget, name): + if self.selected_widget is not None: + ba.textwidget(edit=self.selected_widget, color=(1, 1, 1)) + ba.textwidget(edit=widget, color=(1, 1, 0)) self.selected_name = name self.selected_widget = widget - + 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.root = ba.Window(ba.containerwidget( + size=(900, 670), on_outside_click_call=self.close, transition="in_right")).get_root_widget() ba.textwidget( parent=self.root, @@ -87,14 +93,14 @@ def draw_ui(self): v_align="center", text="ShareReplay", color=green) - + ba.buttonwidget( parent=self.root, - position=(400,580), - size=(35,35), + position=(400, 580), + size=(35, 35), label="Help", on_activate_call=Help) - + ba.buttonwidget( parent=self.root, position=(770, 460), @@ -102,7 +108,7 @@ def draw_ui(self): scale=1.5, label="EXPORT", on_activate_call=self.export) - + self.close_button = ba.buttonwidget( parent=self.root, position=(820, 590), @@ -113,51 +119,53 @@ def draw_ui(self): color=(1, 0.2, 0.2), extra_touch_border_scale=3, on_activate_call=self.close) - - scroll=ba.scrollwidget( + + scroll = ba.scrollwidget( parent=self.root, - size=(500,400), - position=(200,150)) - self.scroll=ba.columnwidget(parent=scroll,size=(500,900),selection_loops_to_parent=True,single_depth=True) - - height=900 + size=(500, 400), + position=(200, 150)) + self.scroll = ba.columnwidget(parent=scroll, size=( + 500, 900), selection_loops_to_parent=True, single_depth=True) + + height = 900 for i in listdir(internal_dir): - height-=40 - a=i + height -= 40 + a = i i = ba.textwidget( - parent=self.scroll, - size=(500,50), - text= i.split(".")[0], - position=(10,height), + parent=self.scroll, + size=(500, 50), + text=i.split(".")[0], + position=(10, height), selectable=True, max_chars=40, click_activate=True,) - - ba.textwidget(edit=i,on_activate_call=ba.Call(self.on_select_text,i,a)) - - + + ba.textwidget(edit=i, on_activate_call=ba.Call(self.on_select_text, i, a)) + def export(self): - if self.selected_name is None: - Print("Select a replay",color=red) - return - copy(internal_dir+"/"+self.selected_name,external_dir+"/"+self.selected_name) - Print(self.selected_name[0:-4]+" exported", top=True,color=pink)#image={"texture":ba.gettexture("bombColor"),"tint_texture":None,"tint_color":None,"tint2_color":None}) - + if self.selected_name is None: + Print("Select a replay", color=red) + return + copy(internal_dir+"/"+self.selected_name, external_dir+"/"+self.selected_name) + # image={"texture":ba.gettexture("bombColor"),"tint_texture":None,"tint_color":None,"tint2_color":None}) + Print(self.selected_name[0:-4]+" exported", top=True, color=pink) + def close(self): ba.playsound(ba.getsound('swish')) - ba.containerwidget(edit=self.root, transition="out_right",) - + ba.containerwidget(edit=self.root, transition="out_right",) + # ++++++++++++++++for keyboard navigation++++++++++++++++ - #ba.widget(edit=self.enable_button, up_widget=decrease_button, down_widget=self.lower_text,left_widget=save_button, right_widget=save_button) + #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__ +ww.__old_init__ = ww.__init__ + -def new_init(self,transition="in_right",origin_widget=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), @@ -168,19 +176,17 @@ def new_init(self,transition="in_right",origin_widget=None): iconscale=1.5, label="SHARE REPLAY", on_activate_call=SettingWindow) - - + + # ba_meta export plugin class main(ba.Plugin): def on_app_running(self): - - ww.__init__=new_init - + + ww.__init__ = new_init + def has_settings_ui(self): return True - - def show_settings_ui(self,button): + + def show_settings_ui(self, button): SettingWindow() - - \ No newline at end of file From fbb965d0ac22633186bc3d2bae39c141900240a6 Mon Sep 17 00:00:00 2001 From: Loup-Garou911XD Date: Sun, 6 Nov 2022 18:56:49 +0000 Subject: [PATCH 0228/1464] [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 9b67e84b..3643231a 100644 --- a/plugins/utilities.json +++ b/plugins/utilities.json @@ -14,7 +14,12 @@ } ], "versions": { - "1.0.0":null + "1.0.0": { + "api_version": 7, + "commit_sha": "32c6b83", + "released_on": "06-11-2022", + "md5sum": "b652c675e61332a9e7714342ee83bfce" + } } }, "custom_death": { @@ -424,4 +429,4 @@ } } } -} +} \ No newline at end of file From 34bbd7c8db653159e4e5dc11469ec288aa9d2a24 Mon Sep 17 00:00:00 2001 From: Loup <90267658+Loup-Garou911XD@users.noreply.github.com> Date: Mon, 7 Nov 2022 00:30:48 +0530 Subject: [PATCH 0229/1464] Rename MeteorShower.py to meteor_shower.py --- plugins/minigames/{MeteorShower.py => meteor_shower.py} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename plugins/minigames/{MeteorShower.py => meteor_shower.py} (100%) diff --git a/plugins/minigames/MeteorShower.py b/plugins/minigames/meteor_shower.py similarity index 100% rename from plugins/minigames/MeteorShower.py rename to plugins/minigames/meteor_shower.py From 3901d684043b67bc4ef1aa657839b8f0ef56fc23 Mon Sep 17 00:00:00 2001 From: Loup <90267658+Loup-Garou911XD@users.noreply.github.com> Date: Mon, 7 Nov 2022 00:34:27 +0530 Subject: [PATCH 0230/1464] Rename ZombieHorde.py to zombie_horde.py --- plugins/minigames/{ZombieHorde.py => zombie_horde.py} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename plugins/minigames/{ZombieHorde.py => zombie_horde.py} (100%) diff --git a/plugins/minigames/ZombieHorde.py b/plugins/minigames/zombie_horde.py similarity index 100% rename from plugins/minigames/ZombieHorde.py rename to plugins/minigames/zombie_horde.py From faba93cfe1bd531bf35707691e33b3040878592a Mon Sep 17 00:00:00 2001 From: Loup <90267658+Loup-Garou911XD@users.noreply.github.com> Date: Mon, 7 Nov 2022 00:35:20 +0530 Subject: [PATCH 0231/1464] Rename SquidRace.py to squid_race.py --- plugins/minigames/{SquidRace.py => squid_race.py} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename plugins/minigames/{SquidRace.py => squid_race.py} (100%) diff --git a/plugins/minigames/SquidRace.py b/plugins/minigames/squid_race.py similarity index 100% rename from plugins/minigames/SquidRace.py rename to plugins/minigames/squid_race.py From 3dc9404e58c26315dd62f6404e31b46c372db252 Mon Sep 17 00:00:00 2001 From: Loup <90267658+Loup-Garou911XD@users.noreply.github.com> Date: Mon, 7 Nov 2022 00:36:04 +0530 Subject: [PATCH 0232/1464] Rename SimonSays.py to simon_says.py --- plugins/minigames/{SimonSays.py => simon_says.py} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename plugins/minigames/{SimonSays.py => simon_says.py} (100%) diff --git a/plugins/minigames/SimonSays.py b/plugins/minigames/simon_says.py similarity index 100% rename from plugins/minigames/SimonSays.py rename to plugins/minigames/simon_says.py From b2028d6e31c9d75637b28037b1213f8c6b602e8d Mon Sep 17 00:00:00 2001 From: Loup <90267658+Loup-Garou911XD@users.noreply.github.com> Date: Mon, 7 Nov 2022 00:36:47 +0530 Subject: [PATCH 0233/1464] Rename Boxing.py to boxing.py --- plugins/minigames/{Boxing.py => boxing.py} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename plugins/minigames/{Boxing.py => boxing.py} (100%) diff --git a/plugins/minigames/Boxing.py b/plugins/minigames/boxing.py similarity index 100% rename from plugins/minigames/Boxing.py rename to plugins/minigames/boxing.py From 6f33276807595c9221c8438facba78fd53ba09e4 Mon Sep 17 00:00:00 2001 From: Loup <90267658+Loup-Garou911XD@users.noreply.github.com> Date: Mon, 7 Nov 2022 00:37:24 +0530 Subject: [PATCH 0234/1464] Rename BasketBomb.py to basket_bomb.py --- plugins/minigames/{BasketBomb.py => basket_bomb.py} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename plugins/minigames/{BasketBomb.py => basket_bomb.py} (100%) diff --git a/plugins/minigames/BasketBomb.py b/plugins/minigames/basket_bomb.py similarity index 100% rename from plugins/minigames/BasketBomb.py rename to plugins/minigames/basket_bomb.py From e3d7d310fa07a1ae817e6e940030e29aa1d3d086 Mon Sep 17 00:00:00 2001 From: Loup <90267658+Loup-Garou911XD@users.noreply.github.com> Date: Mon, 7 Nov 2022 00:39:40 +0530 Subject: [PATCH 0235/1464] Update minigames.json --- plugins/minigames.json | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/plugins/minigames.json b/plugins/minigames.json index 7b016560..7136458f 100644 --- a/plugins/minigames.json +++ b/plugins/minigames.json @@ -22,7 +22,7 @@ } } }, - "SimonSays": { + "simon_says": { "description": "You better do what Simon says", "external_url": "", "authors": [ @@ -41,7 +41,7 @@ } } }, - "SquidRace": { + "squid_race": { "description": "Race inspired by the squid games", "external_url": "https://youtube.com/c/JoseANG3LYT", "authors": [ @@ -60,7 +60,7 @@ } } }, - "ZombieHorde": { + "zombie_horde": { "description": "Fight or defend against horde of zombies", "external_url": "https://youtube.com/c/JoseANG3LYT", "authors": [ @@ -79,7 +79,7 @@ } } }, - "MeteorShower": { + "meteor_shower": { "description": "MeteorShower with many different bombs", "external_url": "https://youtube.com/c/JoseANG3LYT", "authors": [ @@ -98,7 +98,7 @@ } } }, - "Boxing": { + "boxing": { "description": "Simple boxing minigame", "external_url": "https://youtube.com/c/JoseANG3LYT", "authors": [ @@ -117,7 +117,7 @@ } } }, - "BasketBomb": { + "basket_bomb": { "description": "Score all the baskets and be the MVP.", "external_url": "", "authors": [ @@ -232,4 +232,4 @@ } } } -} \ No newline at end of file +} From 56c5e0dca6412120eb54d440c99d88c070d6892b Mon Sep 17 00:00:00 2001 From: Loup-Garou911XD Date: Sun, 6 Nov 2022 19:10:08 +0000 Subject: [PATCH 0236/1464] [ci] apply-version-metadata --- plugins/minigames.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/minigames.json b/plugins/minigames.json index 7136458f..3dc129ed 100644 --- a/plugins/minigames.json +++ b/plugins/minigames.json @@ -232,4 +232,4 @@ } } } -} +} \ No newline at end of file From 23eb66093cfa8e00a1a6509af2c1d08bfa15a942 Mon Sep 17 00:00:00 2001 From: Loup <90267658+Loup-Garou911XD@users.noreply.github.com> Date: Mon, 7 Nov 2022 01:18:24 +0530 Subject: [PATCH 0237/1464] Update utilities.json --- plugins/utilities.json | 57 ++++++------------------------------------ 1 file changed, 8 insertions(+), 49 deletions(-) diff --git a/plugins/utilities.json b/plugins/utilities.json index 3643231a..5336f993 100644 --- a/plugins/utilities.json +++ b/plugins/utilities.json @@ -14,12 +14,7 @@ } ], "versions": { - "1.0.0": { - "api_version": 7, - "commit_sha": "32c6b83", - "released_on": "06-11-2022", - "md5sum": "b652c675e61332a9e7714342ee83bfce" - } + "1.0.0":null } }, "custom_death": { @@ -33,12 +28,7 @@ } ], "versions": { - "1.0.0": { - "api_version": 7, - "commit_sha": "7d3d117", - "released_on": "03-11-2022", - "md5sum": "7b1941512532321eec18140087569215" - } + "1.0.0":null } }, "max_players": { @@ -52,12 +42,7 @@ } ], "versions": { - "1.0.0": { - "api_version": 7, - "commit_sha": "7d3d117", - "released_on": "03-11-2022", - "md5sum": "f5e129f009e9732b3179c7edaf75478e" - } + "1.0.0":null } }, "quick_custom_game": { @@ -71,12 +56,7 @@ } ], "versions": { - "1.0.0": { - "api_version": 7, - "commit_sha": "7d3d117", - "released_on": "03-11-2022", - "md5sum": "b691e35afb17cd3b5f6fe21c0194567d" - } + "1.0.0":null } }, "random_colors": { @@ -90,12 +70,7 @@ } ], "versions": { - "1.0.0": { - "api_version": 7, - "commit_sha": "7d3d117", - "released_on": "03-11-2022", - "md5sum": "0c351a0aebed77c3771053cde0c18d7b" - } + "1.0.0":null } }, "chat_cmd": { @@ -114,12 +89,7 @@ } ], "versions": { - "1.0.0": { - "api_version": 7, - "commit_sha": "7d3d117", - "released_on": "03-11-2022", - "md5sum": "c84d9a1c9e63e77949134020e1f11834" - } + "1.0.0":null } }, "mood_light": { @@ -133,18 +103,7 @@ } ], "versions": { - "1.2.2": { - "api_version": 7, - "commit_sha": "490b857", - "released_on": "04-11-2022", - "md5sum": "cb367f877d6360a0e41941b1d0396a9b" - }, - "1.2.1": { - "api_version": 7, - "commit_sha": "1a56b57", - "released_on": "28-10-2022", - "md5sum": "81414a2b497da3d2340a4d7eb004336c" - }, + "1.2.1":null "1.2.0": { "api_version": 7, "commit_sha": "d838115", @@ -429,4 +388,4 @@ } } } -} \ No newline at end of file +} From e7d612d0bf72ff57e91fdc1b5fd1e7798b8f0b2c Mon Sep 17 00:00:00 2001 From: Loup <90267658+Loup-Garou911XD@users.noreply.github.com> Date: Mon, 7 Nov 2022 01:21:10 +0530 Subject: [PATCH 0238/1464] Update minigames.json --- plugins/minigames.json | 44 +++++++----------------------------------- 1 file changed, 7 insertions(+), 37 deletions(-) diff --git a/plugins/minigames.json b/plugins/minigames.json index 3dc129ed..3fd30233 100644 --- a/plugins/minigames.json +++ b/plugins/minigames.json @@ -33,12 +33,7 @@ } ], "versions": { - "1.0.0": { - "api_version": 7, - "commit_sha": "7d3d117", - "released_on": "03-11-2022", - "md5sum": "def39482b339095a7affb574af829ea0" - } + "1.0.0":null } }, "squid_race": { @@ -52,12 +47,7 @@ } ], "versions": { - "1.0.0": { - "api_version": 7, - "commit_sha": "7d3d117", - "released_on": "03-11-2022", - "md5sum": "7ec43481e6b35b4da4f6425977ee0004" - } + "1.0.0":null } }, "zombie_horde": { @@ -71,12 +61,7 @@ } ], "versions": { - "1.0.0": { - "api_version": 7, - "commit_sha": "7d3d117", - "released_on": "03-11-2022", - "md5sum": "671e7b98a9d3eb0aeb7e47448db25af9" - } + "1.0.0":null } }, "meteor_shower": { @@ -90,12 +75,7 @@ } ], "versions": { - "1.0.0": { - "api_version": 7, - "commit_sha": "7d3d117", - "released_on": "03-11-2022", - "md5sum": "1ce8c1a3f3ec240af39b7a73375e7891" - } + "1.0.0":null } }, "boxing": { @@ -109,12 +89,7 @@ } ], "versions": { - "1.0.0": { - "api_version": 7, - "commit_sha": "7d3d117", - "released_on": "03-11-2022", - "md5sum": "c1b615df09886ba05622c4e8b4f6be40" - } + "1.0.0":null } }, "basket_bomb": { @@ -128,12 +103,7 @@ } ], "versions": { - "1.0.0": { - "api_version": 7, - "commit_sha": "7d3d117", - "released_on": "03-11-2022", - "md5sum": "7ec87edbdd5183ec4b2daffad0019820" - } + "1.0.0":null } }, "ultimate_last_stand": { @@ -232,4 +202,4 @@ } } } -} \ No newline at end of file +} From ef99b13364f6bf8f353694e16a96f6390c020d2c Mon Sep 17 00:00:00 2001 From: Loup <90267658+Loup-Garou911XD@users.noreply.github.com> Date: Mon, 7 Nov 2022 02:53:57 +0530 Subject: [PATCH 0239/1464] Add files via upload --- plugins/utilities/share_replay.py | 162 ++++++++++++++---------------- 1 file changed, 78 insertions(+), 84 deletions(-) diff --git a/plugins/utilities/share_replay.py b/plugins/utilities/share_replay.py index 61a00298..fb49c40a 100644 --- a/plugins/utilities/share_replay.py +++ b/plugins/utilities/share_replay.py @@ -3,63 +3,58 @@ 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 -from shutil import copy, copytree + +from os import listdir,mkdir +from shutil import copy,copytree import ba import _ba from bastd.ui.watch import WatchWindow as ww from bastd.ui.popup import PopupWindow -# mod by ʟօʊքɢǟʀօʊ -# export replays to mods folder and share with your friends or have a backup - +#mod by ʟօʊքɢǟʀօʊ +#export replays to mods folder and share with your friends or have a backup -def Print(*args, color=None, top=None): - out = "" +def Print(*args,color=None,top=None): + out="" for arg in args: - a = str(arg) + a=str(arg) out += a - ba.screenmessage(out, color=color, top=top) - + ba.screenmessage(out,color=color,top=top) def cprint(*args): - out = "" + out="" for arg in args: - a = str(arg) + a=str(arg) out += a _ba.chatmessage(out) - - -internal_dir = "/data/data/net.froemling.bombsquad/files/bombsquad_config/replays" -external_dir = "/storage/emulated/0/Android/data/net.froemling.bombsquad/files/mods/replays" -# colors -pink = (1, 0.2, 0.8) -green = (0.4, 1, 0.4) -red = (1, 0, 0) + +internal_dir="/data/data/net.froemling.bombsquad/files/bombsquad_config/replays" +external_dir="/storage/emulated/0/Android/data/net.froemling.bombsquad/files/mods/replays" +#colors +pink=(1,0.2,0.8) +green=(0.4,1,0.4) +red=(1,0,0) try: mkdir(external_dir) - Print("You are ready to share replays", color=pink) + Print("You are ready to share replays",color=pink) except FileExistsError: pass - - + class Help(PopupWindow): def __init__(self): uiscale = ba.app.ui.uiscale self.width = 800 self.height = 300 - + PopupWindow.__init__(self, position=(0.0, 0.0), size=(self.width, self.height), scale=1.2,) - - 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•Importing replay and other features comming in v1.2") - + + 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•Importing replay and other features comming in v1.2") + def close(self): ba.playsound(ba.getsound('swish')) ba.containerwidget(edit=self.root_widget, transition="out_right",) @@ -69,19 +64,18 @@ class SettingWindow(): def __init__(self): self.draw_ui() self.selected_widget = None - self.selected_name = None - - def on_select_text(self, widget, name): - if self.selected_widget is not None: - ba.textwidget(edit=self.selected_widget, color=(1, 1, 1)) - ba.textwidget(edit=widget, color=(1, 1, 0)) + self.selected_name= None + + def on_select_text(self,widget,name): + if self.selected_widget is not None: + ba.textwidget(edit=self.selected_widget,color=(1,1,1)) + ba.textwidget(edit=widget,color=(1,1,0)) self.selected_name = name self.selected_widget = widget - + 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.root=ba.Window(ba.containerwidget(size=(900, 670),on_outside_click_call=self.close,transition="in_right")).get_root_widget() ba.textwidget( parent=self.root, @@ -93,14 +87,14 @@ def draw_ui(self): v_align="center", text="ShareReplay", color=green) - + ba.buttonwidget( parent=self.root, - position=(400, 580), - size=(35, 35), + position=(400,580), + size=(35,35), label="Help", on_activate_call=Help) - + ba.buttonwidget( parent=self.root, position=(770, 460), @@ -108,64 +102,62 @@ def draw_ui(self): scale=1.5, label="EXPORT", on_activate_call=self.export) - + self.close_button = ba.buttonwidget( parent=self.root, position=(820, 590), size=(35, 35), - icon=ba.gettexture("crossOut"), - icon_color=(1, 0.2, 0.2), + texture=ba.gettexture("crossOut"), + label="", scale=2, color=(1, 0.2, 0.2), extra_touch_border_scale=3, on_activate_call=self.close) - - scroll = ba.scrollwidget( + + scroll=ba.scrollwidget( parent=self.root, - size=(500, 400), - position=(200, 150)) - self.scroll = ba.columnwidget(parent=scroll, size=( - 500, 900), selection_loops_to_parent=True, single_depth=True) - - height = 900 + size=(500,400), + position=(200,150)) + self.scroll=ba.columnwidget(parent=scroll,size=(500,900),selection_loops_to_parent=True,single_depth=True) + + height=900 for i in listdir(internal_dir): - height -= 40 - a = i + height-=40 + a=i i = ba.textwidget( - parent=self.scroll, - size=(500, 50), - text=i.split(".")[0], - position=(10, height), + parent=self.scroll, + size=(500,50), + text= i.split(".")[0], + position=(10,height), selectable=True, max_chars=40, click_activate=True,) - - ba.textwidget(edit=i, on_activate_call=ba.Call(self.on_select_text, i, a)) - + + ba.textwidget(edit=i,on_activate_call=ba.Call(self.on_select_text,i,a)) + + def export(self): - if self.selected_name is None: - Print("Select a replay", color=red) - return - copy(internal_dir+"/"+self.selected_name, external_dir+"/"+self.selected_name) - # image={"texture":ba.gettexture("bombColor"),"tint_texture":None,"tint_color":None,"tint2_color":None}) - Print(self.selected_name[0:-4]+" exported", top=True, color=pink) - + if self.selected_name is None: + Print("Select a replay",color=red) + return + copy(internal_dir+"/"+self.selected_name,external_dir+"/"+self.selected_name) + Print(self.selected_name[0:-4]+" exported", top=True,color=pink)#image={"texture":ba.gettexture("bombColor"),"tint_texture":None,"tint_color":None,"tint2_color":None}) + def close(self): ba.playsound(ba.getsound('swish')) - ba.containerwidget(edit=self.root, transition="out_right",) - + ba.containerwidget(edit=self.root, transition="out_right",) + # ++++++++++++++++for keyboard navigation++++++++++++++++ - #ba.widget(edit=self.enable_button, up_widget=decrease_button, down_widget=self.lower_text,left_widget=save_button, right_widget=save_button) + #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__ - +ww.__old_init__=ww.__init__ -def new_init(self, transition="in_right", origin_widget=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), @@ -176,17 +168,19 @@ def new_init(self, transition="in_right", origin_widget=None): iconscale=1.5, label="SHARE REPLAY", on_activate_call=SettingWindow) - - + + # ba_meta export plugin class main(ba.Plugin): def on_app_running(self): - - ww.__init__ = new_init - + + ww.__init__=new_init + def has_settings_ui(self): return True - - def show_settings_ui(self, button): + + def show_settings_ui(self,button): SettingWindow() + + \ No newline at end of file From e788b41b740d6fce4eb403c6e81271ee65de05b7 Mon Sep 17 00:00:00 2001 From: Loup-Garou911XD Date: Sun, 6 Nov 2022 21:24:27 +0000 Subject: [PATCH 0240/1464] [ci] auto-format --- plugins/utilities/share_replay.py | 160 ++++++++++++++++-------------- 1 file changed, 83 insertions(+), 77 deletions(-) diff --git a/plugins/utilities/share_replay.py b/plugins/utilities/share_replay.py index fb49c40a..fe665696 100644 --- a/plugins/utilities/share_replay.py +++ b/plugins/utilities/share_replay.py @@ -3,58 +3,63 @@ 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 -from shutil import copy,copytree + +from os import listdir, mkdir +from shutil import copy, copytree import ba import _ba from bastd.ui.watch import WatchWindow as ww from bastd.ui.popup import PopupWindow -#mod by ʟօʊքɢǟʀօʊ -#export replays to mods folder and share with your friends or have a backup +# mod by ʟօʊքɢǟʀօʊ +# export replays to mods folder and share with your friends or have a backup + -def Print(*args,color=None,top=None): - out="" +def Print(*args, color=None, top=None): + out = "" for arg in args: - a=str(arg) + a = str(arg) out += a - ba.screenmessage(out,color=color,top=top) + ba.screenmessage(out, color=color, top=top) + def cprint(*args): - out="" + out = "" for arg in args: - a=str(arg) + a = str(arg) out += a _ba.chatmessage(out) - -internal_dir="/data/data/net.froemling.bombsquad/files/bombsquad_config/replays" -external_dir="/storage/emulated/0/Android/data/net.froemling.bombsquad/files/mods/replays" -#colors -pink=(1,0.2,0.8) -green=(0.4,1,0.4) -red=(1,0,0) + + +internal_dir = "/data/data/net.froemling.bombsquad/files/bombsquad_config/replays" +external_dir = "/storage/emulated/0/Android/data/net.froemling.bombsquad/files/mods/replays" +# colors +pink = (1, 0.2, 0.8) +green = (0.4, 1, 0.4) +red = (1, 0, 0) try: mkdir(external_dir) - Print("You are ready to share replays",color=pink) + Print("You are ready to share replays", color=pink) except FileExistsError: pass - + + class Help(PopupWindow): def __init__(self): uiscale = ba.app.ui.uiscale self.width = 800 self.height = 300 - + PopupWindow.__init__(self, position=(0.0, 0.0), size=(self.width, self.height), scale=1.2,) - - 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•Importing replay and other features comming in v1.2") - + + 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•Importing replay and other features comming in v1.2") + def close(self): ba.playsound(ba.getsound('swish')) ba.containerwidget(edit=self.root_widget, transition="out_right",) @@ -64,18 +69,19 @@ class SettingWindow(): def __init__(self): self.draw_ui() self.selected_widget = None - self.selected_name= None - - def on_select_text(self,widget,name): - if self.selected_widget is not None: - ba.textwidget(edit=self.selected_widget,color=(1,1,1)) - ba.textwidget(edit=widget,color=(1,1,0)) + self.selected_name = None + + def on_select_text(self, widget, name): + if self.selected_widget is not None: + ba.textwidget(edit=self.selected_widget, color=(1, 1, 1)) + ba.textwidget(edit=widget, color=(1, 1, 0)) self.selected_name = name self.selected_widget = widget - + 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.root = ba.Window(ba.containerwidget( + size=(900, 670), on_outside_click_call=self.close, transition="in_right")).get_root_widget() ba.textwidget( parent=self.root, @@ -87,14 +93,14 @@ def draw_ui(self): v_align="center", text="ShareReplay", color=green) - + ba.buttonwidget( parent=self.root, - position=(400,580), - size=(35,35), + position=(400, 580), + size=(35, 35), label="Help", on_activate_call=Help) - + ba.buttonwidget( parent=self.root, position=(770, 460), @@ -102,62 +108,64 @@ def draw_ui(self): scale=1.5, label="EXPORT", on_activate_call=self.export) - + self.close_button = ba.buttonwidget( parent=self.root, position=(820, 590), size=(35, 35), texture=ba.gettexture("crossOut"), - label="", + label="", scale=2, color=(1, 0.2, 0.2), extra_touch_border_scale=3, on_activate_call=self.close) - - scroll=ba.scrollwidget( + + scroll = ba.scrollwidget( parent=self.root, - size=(500,400), - position=(200,150)) - self.scroll=ba.columnwidget(parent=scroll,size=(500,900),selection_loops_to_parent=True,single_depth=True) - - height=900 + size=(500, 400), + position=(200, 150)) + self.scroll = ba.columnwidget(parent=scroll, size=( + 500, 900), selection_loops_to_parent=True, single_depth=True) + + height = 900 for i in listdir(internal_dir): - height-=40 - a=i + height -= 40 + a = i i = ba.textwidget( - parent=self.scroll, - size=(500,50), - text= i.split(".")[0], - position=(10,height), + parent=self.scroll, + size=(500, 50), + text=i.split(".")[0], + position=(10, height), selectable=True, max_chars=40, click_activate=True,) - - ba.textwidget(edit=i,on_activate_call=ba.Call(self.on_select_text,i,a)) - - + + ba.textwidget(edit=i, on_activate_call=ba.Call(self.on_select_text, i, a)) + def export(self): - if self.selected_name is None: - Print("Select a replay",color=red) - return - copy(internal_dir+"/"+self.selected_name,external_dir+"/"+self.selected_name) - Print(self.selected_name[0:-4]+" exported", top=True,color=pink)#image={"texture":ba.gettexture("bombColor"),"tint_texture":None,"tint_color":None,"tint2_color":None}) - + if self.selected_name is None: + Print("Select a replay", color=red) + return + copy(internal_dir+"/"+self.selected_name, external_dir+"/"+self.selected_name) + # image={"texture":ba.gettexture("bombColor"),"tint_texture":None,"tint_color":None,"tint2_color":None}) + Print(self.selected_name[0:-4]+" exported", top=True, color=pink) + def close(self): ba.playsound(ba.getsound('swish')) - ba.containerwidget(edit=self.root, transition="out_right",) - + ba.containerwidget(edit=self.root, transition="out_right",) + # ++++++++++++++++for keyboard navigation++++++++++++++++ - #ba.widget(edit=self.enable_button, up_widget=decrease_button, down_widget=self.lower_text,left_widget=save_button, right_widget=save_button) + #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__ +ww.__old_init__ = ww.__init__ + -def new_init(self,transition="in_right",origin_widget=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), @@ -168,19 +176,17 @@ def new_init(self,transition="in_right",origin_widget=None): iconscale=1.5, label="SHARE REPLAY", on_activate_call=SettingWindow) - - + + # ba_meta export plugin class main(ba.Plugin): def on_app_running(self): - - ww.__init__=new_init - + + ww.__init__ = new_init + def has_settings_ui(self): return True - - def show_settings_ui(self,button): + + def show_settings_ui(self, button): SettingWindow() - - \ No newline at end of file From 5ea82551d15bd952ea02067326eb953900fa7cf7 Mon Sep 17 00:00:00 2001 From: Loup <90267658+Loup-Garou911XD@users.noreply.github.com> Date: Mon, 7 Nov 2022 21:56:22 +0530 Subject: [PATCH 0241/1464] Fixed utilities.json --- plugins/utilities.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/utilities.json b/plugins/utilities.json index 5336f993..b80c1494 100644 --- a/plugins/utilities.json +++ b/plugins/utilities.json @@ -103,7 +103,7 @@ } ], "versions": { - "1.2.1":null + "1.2.1":null, "1.2.0": { "api_version": 7, "commit_sha": "d838115", From 77b702d66f3123b0c32ba9cc9cb4d78270c5a99d Mon Sep 17 00:00:00 2001 From: Loup-Garou911XD Date: Mon, 7 Nov 2022 16:26:45 +0000 Subject: [PATCH 0242/1464] [ci] apply-version-metadata --- plugins/minigames.json | 44 ++++++++++++++++++++++++++++++------ plugins/utilities.json | 51 +++++++++++++++++++++++++++++++++++------- 2 files changed, 80 insertions(+), 15 deletions(-) diff --git a/plugins/minigames.json b/plugins/minigames.json index 3fd30233..dd9c5a90 100644 --- a/plugins/minigames.json +++ b/plugins/minigames.json @@ -33,7 +33,12 @@ } ], "versions": { - "1.0.0":null + "1.0.0": { + "api_version": 7, + "commit_sha": "5ea8255", + "released_on": "07-11-2022", + "md5sum": "def39482b339095a7affb574af829ea0" + } } }, "squid_race": { @@ -47,7 +52,12 @@ } ], "versions": { - "1.0.0":null + "1.0.0": { + "api_version": 7, + "commit_sha": "5ea8255", + "released_on": "07-11-2022", + "md5sum": "7ec43481e6b35b4da4f6425977ee0004" + } } }, "zombie_horde": { @@ -61,7 +71,12 @@ } ], "versions": { - "1.0.0":null + "1.0.0": { + "api_version": 7, + "commit_sha": "5ea8255", + "released_on": "07-11-2022", + "md5sum": "671e7b98a9d3eb0aeb7e47448db25af9" + } } }, "meteor_shower": { @@ -75,7 +90,12 @@ } ], "versions": { - "1.0.0":null + "1.0.0": { + "api_version": 7, + "commit_sha": "5ea8255", + "released_on": "07-11-2022", + "md5sum": "1ce8c1a3f3ec240af39b7a73375e7891" + } } }, "boxing": { @@ -89,7 +109,12 @@ } ], "versions": { - "1.0.0":null + "1.0.0": { + "api_version": 7, + "commit_sha": "5ea8255", + "released_on": "07-11-2022", + "md5sum": "c1b615df09886ba05622c4e8b4f6be40" + } } }, "basket_bomb": { @@ -103,7 +128,12 @@ } ], "versions": { - "1.0.0":null + "1.0.0": { + "api_version": 7, + "commit_sha": "5ea8255", + "released_on": "07-11-2022", + "md5sum": "7ec87edbdd5183ec4b2daffad0019820" + } } }, "ultimate_last_stand": { @@ -202,4 +232,4 @@ } } } -} +} \ No newline at end of file diff --git a/plugins/utilities.json b/plugins/utilities.json index b80c1494..abe05054 100644 --- a/plugins/utilities.json +++ b/plugins/utilities.json @@ -14,7 +14,12 @@ } ], "versions": { - "1.0.0":null + "1.0.0": { + "api_version": 7, + "commit_sha": "5ea8255", + "released_on": "07-11-2022", + "md5sum": "4e160ffde7ea194eea0b8bf2abdfba8e" + } } }, "custom_death": { @@ -28,7 +33,12 @@ } ], "versions": { - "1.0.0":null + "1.0.0": { + "api_version": 7, + "commit_sha": "5ea8255", + "released_on": "07-11-2022", + "md5sum": "7b1941512532321eec18140087569215" + } } }, "max_players": { @@ -42,7 +52,12 @@ } ], "versions": { - "1.0.0":null + "1.0.0": { + "api_version": 7, + "commit_sha": "5ea8255", + "released_on": "07-11-2022", + "md5sum": "f5e129f009e9732b3179c7edaf75478e" + } } }, "quick_custom_game": { @@ -56,7 +71,12 @@ } ], "versions": { - "1.0.0":null + "1.0.0": { + "api_version": 7, + "commit_sha": "5ea8255", + "released_on": "07-11-2022", + "md5sum": "b691e35afb17cd3b5f6fe21c0194567d" + } } }, "random_colors": { @@ -70,7 +90,12 @@ } ], "versions": { - "1.0.0":null + "1.0.0": { + "api_version": 7, + "commit_sha": "5ea8255", + "released_on": "07-11-2022", + "md5sum": "0c351a0aebed77c3771053cde0c18d7b" + } } }, "chat_cmd": { @@ -89,7 +114,12 @@ } ], "versions": { - "1.0.0":null + "1.0.0": { + "api_version": 7, + "commit_sha": "5ea8255", + "released_on": "07-11-2022", + "md5sum": "c84d9a1c9e63e77949134020e1f11834" + } } }, "mood_light": { @@ -103,7 +133,12 @@ } ], "versions": { - "1.2.1":null, + "1.2.1": { + "api_version": 7, + "commit_sha": "5ea8255", + "released_on": "07-11-2022", + "md5sum": "ee8eede4a6c47535ab831abd0111aab0" + }, "1.2.0": { "api_version": 7, "commit_sha": "d838115", @@ -388,4 +423,4 @@ } } } -} +} \ No newline at end of file From a47c5e7d1fafd16d51fd281520de3685c3537c6a Mon Sep 17 00:00:00 2001 From: Loup <90267658+Loup-Garou911XD@users.noreply.github.com> Date: Tue, 8 Nov 2022 01:27:06 +0530 Subject: [PATCH 0243/1464] Add files via upload --- plugins/utilities/share_replay.py | 164 ++++++++++++++---------------- 1 file changed, 79 insertions(+), 85 deletions(-) diff --git a/plugins/utilities/share_replay.py b/plugins/utilities/share_replay.py index fe665696..449ca3e4 100644 --- a/plugins/utilities/share_replay.py +++ b/plugins/utilities/share_replay.py @@ -3,63 +3,58 @@ 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 shutil import copy,copytree -from os import listdir, mkdir -from shutil import copy, copytree import ba import _ba from bastd.ui.watch import WatchWindow as ww from bastd.ui.popup import PopupWindow -# mod by ʟօʊքɢǟʀօʊ -# export replays to mods folder and share with your friends or have a backup +#mod by ʟօʊքɢǟʀօʊ +#export replays to mods folder and share with your friends or have a backup - -def Print(*args, color=None, top=None): - out = "" +def Print(*args,color=None,top=None): + out="" for arg in args: - a = str(arg) + a=str(arg) out += a - ba.screenmessage(out, color=color, top=top) - + ba.screenmessage(out,color=color,top=top) def cprint(*args): - out = "" + out="" for arg in args: - a = str(arg) + a=str(arg) out += a _ba.chatmessage(out) +internal_dir=path.join("ba_data","..","..","..","files", "bombsquad_config","replays" + sep) +external_dir=path.join(_ba.env()["python_directory_user"],"replays"+sep) -internal_dir = "/data/data/net.froemling.bombsquad/files/bombsquad_config/replays" -external_dir = "/storage/emulated/0/Android/data/net.froemling.bombsquad/files/mods/replays" -# colors -pink = (1, 0.2, 0.8) -green = (0.4, 1, 0.4) -red = (1, 0, 0) +#colors +pink=(1,0.2,0.8) +green=(0.4,1,0.4) +red=(1,0,0) -try: +if not path.exists(external_dir): mkdir(external_dir) - Print("You are ready to share replays", color=pink) -except FileExistsError: - pass - - + Print("You are ready to share replays",color=pink) + class Help(PopupWindow): def __init__(self): uiscale = ba.app.ui.uiscale self.width = 800 self.height = 300 - + PopupWindow.__init__(self, position=(0.0, 0.0), size=(self.width, self.height), scale=1.2,) - - 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•Importing replay and other features comming in v1.2") - + + 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•Importing replay and other features comming in v1.2") + def close(self): ba.playsound(ba.getsound('swish')) ba.containerwidget(edit=self.root_widget, transition="out_right",) @@ -69,19 +64,18 @@ class SettingWindow(): def __init__(self): self.draw_ui() self.selected_widget = None - self.selected_name = None - - def on_select_text(self, widget, name): - if self.selected_widget is not None: - ba.textwidget(edit=self.selected_widget, color=(1, 1, 1)) - ba.textwidget(edit=widget, color=(1, 1, 0)) + self.selected_name= None + + def on_select_text(self,widget,name): + if self.selected_widget is not None: + ba.textwidget(edit=self.selected_widget,color=(1,1,1)) + ba.textwidget(edit=widget,color=(1,1,0)) self.selected_name = name self.selected_widget = widget - + 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.root=ba.Window(ba.containerwidget(size=(900, 670),on_outside_click_call=self.close,transition="in_right")).get_root_widget() ba.textwidget( parent=self.root, @@ -93,14 +87,15 @@ def draw_ui(self): v_align="center", text="ShareReplay", color=green) - + ba.buttonwidget( parent=self.root, - position=(400, 580), - size=(35, 35), - label="Help", + position=(400,580), + size=(35,35), + texture=ba.gettexture("achievementEmpty"), + label="", on_activate_call=Help) - + ba.buttonwidget( parent=self.root, position=(770, 460), @@ -108,64 +103,62 @@ def draw_ui(self): scale=1.5, label="EXPORT", on_activate_call=self.export) - + self.close_button = ba.buttonwidget( parent=self.root, position=(820, 590), size=(35, 35), texture=ba.gettexture("crossOut"), - label="", + label="", scale=2, color=(1, 0.2, 0.2), extra_touch_border_scale=3, on_activate_call=self.close) - - scroll = ba.scrollwidget( + + scroll=ba.scrollwidget( parent=self.root, - size=(500, 400), - position=(200, 150)) - self.scroll = ba.columnwidget(parent=scroll, size=( - 500, 900), selection_loops_to_parent=True, single_depth=True) - - height = 900 + size=(500,400), + position=(200,150)) + self.scroll=ba.columnwidget(parent=scroll,size=(500,900),selection_loops_to_parent=True,single_depth=True) + + height=900 for i in listdir(internal_dir): - height -= 40 - a = i + height-=40 + a=i i = ba.textwidget( - parent=self.scroll, - size=(500, 50), - text=i.split(".")[0], - position=(10, height), + parent=self.scroll, + size=(500,50), + text= i.split(".")[0], + position=(10,height), selectable=True, max_chars=40, click_activate=True,) - - ba.textwidget(edit=i, on_activate_call=ba.Call(self.on_select_text, i, a)) - + + ba.textwidget(edit=i,on_activate_call=ba.Call(self.on_select_text,i,a)) + + def export(self): - if self.selected_name is None: - Print("Select a replay", color=red) - return - copy(internal_dir+"/"+self.selected_name, external_dir+"/"+self.selected_name) - # image={"texture":ba.gettexture("bombColor"),"tint_texture":None,"tint_color":None,"tint2_color":None}) - Print(self.selected_name[0:-4]+" exported", top=True, color=pink) - + if self.selected_name is None: + Print("Select a replay",color=red) + return + copy(internal_dir+"/"+self.selected_name,external_dir+"/"+self.selected_name) + Print(self.selected_name[0:-4]+" exported", top=True,color=pink)#image={"texture":ba.gettexture("bombColor"),"tint_texture":None,"tint_color":None,"tint2_color":None}) + def close(self): ba.playsound(ba.getsound('swish')) - ba.containerwidget(edit=self.root, transition="out_right",) - + ba.containerwidget(edit=self.root, transition="out_right",) + # ++++++++++++++++for keyboard navigation++++++++++++++++ - #ba.widget(edit=self.enable_button, up_widget=decrease_button, down_widget=self.lower_text,left_widget=save_button, right_widget=save_button) + #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__ +ww.__old_init__=ww.__init__ - -def new_init(self, transition="in_right", origin_widget=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), @@ -176,17 +169,18 @@ def new_init(self, transition="in_right", origin_widget=None): iconscale=1.5, label="SHARE REPLAY", on_activate_call=SettingWindow) - - + + # ba_meta export plugin -class main(ba.Plugin): +class Loup(ba.Plugin): def on_app_running(self): - - ww.__init__ = new_init - + ww.__init__=new_init + def has_settings_ui(self): return True - - def show_settings_ui(self, button): + + def show_settings_ui(self,button): SettingWindow() + + \ No newline at end of file From 7f155a07d7455f4738d42a2d5e21a5c83d23f427 Mon Sep 17 00:00:00 2001 From: Loup-Garou911XD Date: Mon, 7 Nov 2022 19:58:27 +0000 Subject: [PATCH 0244/1464] [ci] auto-format --- plugins/utilities/share_replay.py | 156 ++++++++++++++++-------------- 1 file changed, 81 insertions(+), 75 deletions(-) diff --git a/plugins/utilities/share_replay.py b/plugins/utilities/share_replay.py index 449ca3e4..705b587b 100644 --- a/plugins/utilities/share_replay.py +++ b/plugins/utilities/share_replay.py @@ -3,58 +3,63 @@ 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 shutil import copy,copytree + +from os import listdir, mkdir, path, sep +from shutil import copy, copytree import ba import _ba from bastd.ui.watch import WatchWindow as ww from bastd.ui.popup import PopupWindow -#mod by ʟօʊքɢǟʀօʊ -#export replays to mods folder and share with your friends or have a backup +# mod by ʟօʊքɢǟʀօʊ +# export replays to mods folder and share with your friends or have a backup + -def Print(*args,color=None,top=None): - out="" +def Print(*args, color=None, top=None): + out = "" for arg in args: - a=str(arg) + a = str(arg) out += a - ba.screenmessage(out,color=color,top=top) + ba.screenmessage(out, color=color, top=top) + def cprint(*args): - out="" + out = "" for arg in args: - a=str(arg) + a = str(arg) out += a _ba.chatmessage(out) -internal_dir=path.join("ba_data","..","..","..","files", "bombsquad_config","replays" + 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) +internal_dir = path.join("ba_data", "..", "..", "..", "files", "bombsquad_config", "replays" + 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) if not path.exists(external_dir): mkdir(external_dir) - Print("You are ready to share replays",color=pink) - + Print("You are ready to share replays", color=pink) + + class Help(PopupWindow): def __init__(self): uiscale = ba.app.ui.uiscale self.width = 800 self.height = 300 - + PopupWindow.__init__(self, position=(0.0, 0.0), size=(self.width, self.height), scale=1.2,) - - 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•Importing replay and other features comming in v1.2") - + + 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•Importing replay and other features comming in v1.2") + def close(self): ba.playsound(ba.getsound('swish')) ba.containerwidget(edit=self.root_widget, transition="out_right",) @@ -64,18 +69,19 @@ class SettingWindow(): def __init__(self): self.draw_ui() self.selected_widget = None - self.selected_name= None - - def on_select_text(self,widget,name): - if self.selected_widget is not None: - ba.textwidget(edit=self.selected_widget,color=(1,1,1)) - ba.textwidget(edit=widget,color=(1,1,0)) + self.selected_name = None + + def on_select_text(self, widget, name): + if self.selected_widget is not None: + ba.textwidget(edit=self.selected_widget, color=(1, 1, 1)) + ba.textwidget(edit=widget, color=(1, 1, 0)) self.selected_name = name self.selected_widget = widget - + 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.root = ba.Window(ba.containerwidget( + size=(900, 670), on_outside_click_call=self.close, transition="in_right")).get_root_widget() ba.textwidget( parent=self.root, @@ -87,15 +93,15 @@ def draw_ui(self): v_align="center", text="ShareReplay", color=green) - + ba.buttonwidget( parent=self.root, - position=(400,580), - size=(35,35), + position=(400, 580), + size=(35, 35), texture=ba.gettexture("achievementEmpty"), label="", on_activate_call=Help) - + ba.buttonwidget( parent=self.root, position=(770, 460), @@ -103,62 +109,64 @@ def draw_ui(self): scale=1.5, label="EXPORT", on_activate_call=self.export) - + self.close_button = ba.buttonwidget( parent=self.root, position=(820, 590), size=(35, 35), texture=ba.gettexture("crossOut"), - label="", + label="", scale=2, color=(1, 0.2, 0.2), extra_touch_border_scale=3, on_activate_call=self.close) - - scroll=ba.scrollwidget( + + scroll = ba.scrollwidget( parent=self.root, - size=(500,400), - position=(200,150)) - self.scroll=ba.columnwidget(parent=scroll,size=(500,900),selection_loops_to_parent=True,single_depth=True) - - height=900 + size=(500, 400), + position=(200, 150)) + self.scroll = ba.columnwidget(parent=scroll, size=( + 500, 900), selection_loops_to_parent=True, single_depth=True) + + height = 900 for i in listdir(internal_dir): - height-=40 - a=i + height -= 40 + a = i i = ba.textwidget( - parent=self.scroll, - size=(500,50), - text= i.split(".")[0], - position=(10,height), + parent=self.scroll, + size=(500, 50), + text=i.split(".")[0], + position=(10, height), selectable=True, max_chars=40, click_activate=True,) - - ba.textwidget(edit=i,on_activate_call=ba.Call(self.on_select_text,i,a)) - - + + ba.textwidget(edit=i, on_activate_call=ba.Call(self.on_select_text, i, a)) + def export(self): - if self.selected_name is None: - Print("Select a replay",color=red) - return - copy(internal_dir+"/"+self.selected_name,external_dir+"/"+self.selected_name) - Print(self.selected_name[0:-4]+" exported", top=True,color=pink)#image={"texture":ba.gettexture("bombColor"),"tint_texture":None,"tint_color":None,"tint2_color":None}) - + if self.selected_name is None: + Print("Select a replay", color=red) + return + copy(internal_dir+"/"+self.selected_name, external_dir+"/"+self.selected_name) + # image={"texture":ba.gettexture("bombColor"),"tint_texture":None,"tint_color":None,"tint2_color":None}) + Print(self.selected_name[0:-4]+" exported", top=True, color=pink) + def close(self): ba.playsound(ba.getsound('swish')) - ba.containerwidget(edit=self.root, transition="out_right",) - + ba.containerwidget(edit=self.root, transition="out_right",) + # ++++++++++++++++for keyboard navigation++++++++++++++++ - #ba.widget(edit=self.enable_button, up_widget=decrease_button, down_widget=self.lower_text,left_widget=save_button, right_widget=save_button) + #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__ +ww.__old_init__ = ww.__init__ + -def new_init(self,transition="in_right",origin_widget=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), @@ -169,18 +177,16 @@ def new_init(self,transition="in_right",origin_widget=None): iconscale=1.5, label="SHARE REPLAY", on_activate_call=SettingWindow) - - + + # ba_meta export plugin class Loup(ba.Plugin): def on_app_running(self): - ww.__init__=new_init - + ww.__init__ = new_init + def has_settings_ui(self): return True - - def show_settings_ui(self,button): + + def show_settings_ui(self, button): SettingWindow() - - \ No newline at end of file From 1f973f5228d1604fbbdc541c7a14658ccb3135f1 Mon Sep 17 00:00:00 2001 From: Loup <90267658+Loup-Garou911XD@users.noreply.github.com> Date: Tue, 8 Nov 2022 02:50:09 +0530 Subject: [PATCH 0245/1464] Update utilities.json --- plugins/utilities.json | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/plugins/utilities.json b/plugins/utilities.json index 5336f993..9f0930c2 100644 --- a/plugins/utilities.json +++ b/plugins/utilities.json @@ -23,7 +23,7 @@ "authors": [ { "name": "JoseAng3l", - "email": null, + "email": "", "discord": "! JoseANG3L#0268" } ], @@ -37,7 +37,7 @@ "authors": [ { "name": "JoseAng3l", - "email": null, + "email": "", "discord": "! JoseANG3L#0268" } ], @@ -51,7 +51,7 @@ "authors": [ { "name": "JoseAng3l", - "email": null, + "email": "", "discord": "! JoseANG3L#0268" } ], @@ -65,7 +65,7 @@ "authors": [ { "name": "JoseAng3l", - "email": null, + "email": "", "discord": "! JoseANG3L#0268" } ], @@ -79,12 +79,12 @@ "authors": [ { "name": "IM_NOT_PRANAV#7874", - "email": null, + "email": "", "discord": "IM_NOT_PRANAV#7874" }, { "name": "FireFighter1037 ", - "email": null, + "email": "", "discord": null } ], From a44841424f5ab0eb4262744dcdc7ff29dfeb3463 Mon Sep 17 00:00:00 2001 From: Loup <90267658+Loup-Garou911XD@users.noreply.github.com> Date: Tue, 8 Nov 2022 02:55:39 +0530 Subject: [PATCH 0246/1464] Update minigames.json --- plugins/minigames.json | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/plugins/minigames.json b/plugins/minigames.json index 3fd30233..ea9f0ea6 100644 --- a/plugins/minigames.json +++ b/plugins/minigames.json @@ -28,7 +28,7 @@ "authors": [ { "name": "Unknown", - "email": null, + "email": "", "discord": null } ], @@ -42,7 +42,7 @@ "authors": [ { "name": "JoseAng3l", - "email": null, + "email": "", "discord": "! JoseANG3L#0268" } ], @@ -56,7 +56,7 @@ "authors": [ { "name": "JoseAng3l", - "email": null, + "email": "", "discord": "! JoseANG3L#0268" } ], @@ -70,7 +70,7 @@ "authors": [ { "name": "JoseAng3l", - "email": null, + "email": "", "discord": "! JoseANG3L#0268" } ], @@ -84,7 +84,7 @@ "authors": [ { "name": "JoseAng3l", - "email": null, + "email": "", "discord": "! JoseANG3L#0268" } ], @@ -98,7 +98,7 @@ "authors": [ { "name": "Unknown", - "email": null, + "email": "", "discord": null } ], From 2fda676de9afcff6a644bf680d8f257600938b54 Mon Sep 17 00:00:00 2001 From: Loup <90267658+Loup-Garou911XD@users.noreply.github.com> Date: Tue, 8 Nov 2022 03:03:15 +0530 Subject: [PATCH 0247/1464] Update utilities.json --- plugins/utilities.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/utilities.json b/plugins/utilities.json index 9f0930c2..db81c115 100644 --- a/plugins/utilities.json +++ b/plugins/utilities.json @@ -103,7 +103,7 @@ } ], "versions": { - "1.2.1":null + "1.2.1":null, "1.2.0": { "api_version": 7, "commit_sha": "d838115", From d5324a768ae37549dcebc240ddf2ca731251d8fc Mon Sep 17 00:00:00 2001 From: Loup-Garou911XD Date: Mon, 7 Nov 2022 21:33:46 +0000 Subject: [PATCH 0248/1464] [ci] apply-version-metadata --- plugins/minigames.json | 44 ++++++++++++++++++++++++++++++------ plugins/utilities.json | 51 +++++++++++++++++++++++++++++++++++------- 2 files changed, 80 insertions(+), 15 deletions(-) diff --git a/plugins/minigames.json b/plugins/minigames.json index ea9f0ea6..71af6c30 100644 --- a/plugins/minigames.json +++ b/plugins/minigames.json @@ -33,7 +33,12 @@ } ], "versions": { - "1.0.0":null + "1.0.0": { + "api_version": 7, + "commit_sha": "2fda676", + "released_on": "07-11-2022", + "md5sum": "def39482b339095a7affb574af829ea0" + } } }, "squid_race": { @@ -47,7 +52,12 @@ } ], "versions": { - "1.0.0":null + "1.0.0": { + "api_version": 7, + "commit_sha": "2fda676", + "released_on": "07-11-2022", + "md5sum": "7ec43481e6b35b4da4f6425977ee0004" + } } }, "zombie_horde": { @@ -61,7 +71,12 @@ } ], "versions": { - "1.0.0":null + "1.0.0": { + "api_version": 7, + "commit_sha": "2fda676", + "released_on": "07-11-2022", + "md5sum": "671e7b98a9d3eb0aeb7e47448db25af9" + } } }, "meteor_shower": { @@ -75,7 +90,12 @@ } ], "versions": { - "1.0.0":null + "1.0.0": { + "api_version": 7, + "commit_sha": "2fda676", + "released_on": "07-11-2022", + "md5sum": "1ce8c1a3f3ec240af39b7a73375e7891" + } } }, "boxing": { @@ -89,7 +109,12 @@ } ], "versions": { - "1.0.0":null + "1.0.0": { + "api_version": 7, + "commit_sha": "2fda676", + "released_on": "07-11-2022", + "md5sum": "c1b615df09886ba05622c4e8b4f6be40" + } } }, "basket_bomb": { @@ -103,7 +128,12 @@ } ], "versions": { - "1.0.0":null + "1.0.0": { + "api_version": 7, + "commit_sha": "2fda676", + "released_on": "07-11-2022", + "md5sum": "7ec87edbdd5183ec4b2daffad0019820" + } } }, "ultimate_last_stand": { @@ -202,4 +232,4 @@ } } } -} +} \ No newline at end of file diff --git a/plugins/utilities.json b/plugins/utilities.json index db81c115..1588313c 100644 --- a/plugins/utilities.json +++ b/plugins/utilities.json @@ -14,7 +14,12 @@ } ], "versions": { - "1.0.0":null + "1.0.0": { + "api_version": 7, + "commit_sha": "2fda676", + "released_on": "07-11-2022", + "md5sum": "d475487c221d78c7f1278410d5ce229e" + } } }, "custom_death": { @@ -28,7 +33,12 @@ } ], "versions": { - "1.0.0":null + "1.0.0": { + "api_version": 7, + "commit_sha": "2fda676", + "released_on": "07-11-2022", + "md5sum": "7b1941512532321eec18140087569215" + } } }, "max_players": { @@ -42,7 +52,12 @@ } ], "versions": { - "1.0.0":null + "1.0.0": { + "api_version": 7, + "commit_sha": "2fda676", + "released_on": "07-11-2022", + "md5sum": "f5e129f009e9732b3179c7edaf75478e" + } } }, "quick_custom_game": { @@ -56,7 +71,12 @@ } ], "versions": { - "1.0.0":null + "1.0.0": { + "api_version": 7, + "commit_sha": "2fda676", + "released_on": "07-11-2022", + "md5sum": "b691e35afb17cd3b5f6fe21c0194567d" + } } }, "random_colors": { @@ -70,7 +90,12 @@ } ], "versions": { - "1.0.0":null + "1.0.0": { + "api_version": 7, + "commit_sha": "2fda676", + "released_on": "07-11-2022", + "md5sum": "0c351a0aebed77c3771053cde0c18d7b" + } } }, "chat_cmd": { @@ -89,7 +114,12 @@ } ], "versions": { - "1.0.0":null + "1.0.0": { + "api_version": 7, + "commit_sha": "2fda676", + "released_on": "07-11-2022", + "md5sum": "c84d9a1c9e63e77949134020e1f11834" + } } }, "mood_light": { @@ -103,7 +133,12 @@ } ], "versions": { - "1.2.1":null, + "1.2.1": { + "api_version": 7, + "commit_sha": "2fda676", + "released_on": "07-11-2022", + "md5sum": "ee8eede4a6c47535ab831abd0111aab0" + }, "1.2.0": { "api_version": 7, "commit_sha": "d838115", @@ -388,4 +423,4 @@ } } } -} +} \ No newline at end of file From 09962e81197b99b99992050ce202f604e5165510 Mon Sep 17 00:00:00 2001 From: Loup <90267658+Loup-Garou911XD@users.noreply.github.com> Date: Tue, 8 Nov 2022 03:32:00 +0530 Subject: [PATCH 0249/1464] Update utilities.json --- plugins/utilities.json | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/plugins/utilities.json b/plugins/utilities.json index 62b0fcfd..c772acba 100644 --- a/plugins/utilities.json +++ b/plugins/utilities.json @@ -81,9 +81,7 @@ "versions": { "1.0.0": { "api_version": 7, -<< "commit_sha": "2fda676", -== "released_on": "07-11-2022", "md5sum": "b691e35afb17cd3b5f6fe21c0194567d" } @@ -438,4 +436,4 @@ } } } -} \ No newline at end of file +} From c485ea1f3a279ed1881e575372373bdeb9491308 Mon Sep 17 00:00:00 2001 From: Loup-Garou911XD Date: Mon, 7 Nov 2022 22:02:24 +0000 Subject: [PATCH 0250/1464] [ci] apply-version-metadata --- plugins/minigames.json | 12 ------------ plugins/utilities.json | 15 +-------------- 2 files changed, 1 insertion(+), 26 deletions(-) diff --git a/plugins/minigames.json b/plugins/minigames.json index db951135..71af6c30 100644 --- a/plugins/minigames.json +++ b/plugins/minigames.json @@ -35,9 +35,7 @@ "versions": { "1.0.0": { "api_version": 7, - "commit_sha": "2fda676", - "released_on": "07-11-2022", "md5sum": "def39482b339095a7affb574af829ea0" } @@ -56,9 +54,7 @@ "versions": { "1.0.0": { "api_version": 7, - "commit_sha": "2fda676", - "released_on": "07-11-2022", "md5sum": "7ec43481e6b35b4da4f6425977ee0004" } @@ -77,9 +73,7 @@ "versions": { "1.0.0": { "api_version": 7, - "commit_sha": "2fda676", - "released_on": "07-11-2022", "md5sum": "671e7b98a9d3eb0aeb7e47448db25af9" } @@ -98,9 +92,7 @@ "versions": { "1.0.0": { "api_version": 7, - "commit_sha": "2fda676", - "released_on": "07-11-2022", "md5sum": "1ce8c1a3f3ec240af39b7a73375e7891" } @@ -119,9 +111,7 @@ "versions": { "1.0.0": { "api_version": 7, - "commit_sha": "2fda676", - "released_on": "07-11-2022", "md5sum": "c1b615df09886ba05622c4e8b4f6be40" } @@ -140,9 +130,7 @@ "versions": { "1.0.0": { "api_version": 7, - "commit_sha": "2fda676", - "released_on": "07-11-2022", "md5sum": "7ec87edbdd5183ec4b2daffad0019820" } diff --git a/plugins/utilities.json b/plugins/utilities.json index c772acba..1588313c 100644 --- a/plugins/utilities.json +++ b/plugins/utilities.json @@ -16,11 +16,9 @@ "versions": { "1.0.0": { "api_version": 7, - "commit_sha": "2fda676", "released_on": "07-11-2022", "md5sum": "d475487c221d78c7f1278410d5ce229e" - } } }, @@ -37,9 +35,7 @@ "versions": { "1.0.0": { "api_version": 7, - "commit_sha": "2fda676", - "released_on": "07-11-2022", "md5sum": "7b1941512532321eec18140087569215" } @@ -58,11 +54,7 @@ "versions": { "1.0.0": { "api_version": 7, - "commit_sha": "2fda676", - - - "released_on": "07-11-2022", "md5sum": "f5e129f009e9732b3179c7edaf75478e" } @@ -100,9 +92,7 @@ "versions": { "1.0.0": { "api_version": 7, - "commit_sha": "2fda676", - "released_on": "07-11-2022", "md5sum": "0c351a0aebed77c3771053cde0c18d7b" } @@ -127,7 +117,6 @@ "1.0.0": { "api_version": 7, "commit_sha": "2fda676", - "released_on": "07-11-2022", "md5sum": "c84d9a1c9e63e77949134020e1f11834" } @@ -146,9 +135,7 @@ "versions": { "1.2.1": { "api_version": 7, - "commit_sha": "2fda676", - "released_on": "07-11-2022", "md5sum": "ee8eede4a6c47535ab831abd0111aab0" }, @@ -436,4 +423,4 @@ } } } -} +} \ No newline at end of file From f68c48d24711199b760ed8bb1f41096a11fab62a Mon Sep 17 00:00:00 2001 From: Rikko Date: Tue, 8 Nov 2022 03:47:33 +0530 Subject: [PATCH 0251/1464] Correct meta entries --- plugins/minigames.json | 4 ++-- plugins/utilities.json | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/plugins/minigames.json b/plugins/minigames.json index 71af6c30..210e4fe8 100644 --- a/plugins/minigames.json +++ b/plugins/minigames.json @@ -29,7 +29,7 @@ { "name": "Unknown", "email": "", - "discord": null + "discord": "" } ], "versions": { @@ -124,7 +124,7 @@ { "name": "Unknown", "email": "", - "discord": null + "discord": "" } ], "versions": { diff --git a/plugins/utilities.json b/plugins/utilities.json index 1588313c..4f69da83 100644 --- a/plugins/utilities.json +++ b/plugins/utilities.json @@ -5,7 +5,7 @@ "plugins": { "share_replay": { "description": "Export replays to mods folder and share them with friends or have a backup", - "external_url": null, + "external_url": "", "authors": [ { "name": "LoupGarou", @@ -110,7 +110,7 @@ { "name": "FireFighter1037 ", "email": "", - "discord": null + "discord": "" } ], "versions": { From 1fb3293358da4da08eaf48723f250c1a30742797 Mon Sep 17 00:00:00 2001 From: TheMikirog Date: Sun, 13 Nov 2022 19:41:14 +0100 Subject: [PATCH 0252/1464] Utility minigames --- plugins/utilities/bomb_radius_visualizer.py | 85 +++++++++++++ plugins/utilities/quickturn.py | 133 ++++++++++++++++++++ plugins/utilities/ragdoll-b-gone.py | 110 ++++++++++++++++ 3 files changed, 328 insertions(+) create mode 100644 plugins/utilities/bomb_radius_visualizer.py create mode 100644 plugins/utilities/quickturn.py create mode 100644 plugins/utilities/ragdoll-b-gone.py diff --git a/plugins/utilities/bomb_radius_visualizer.py b/plugins/utilities/bomb_radius_visualizer.py new file mode 100644 index 00000000..cc5beb54 --- /dev/null +++ b/plugins/utilities/bomb_radius_visualizer.py @@ -0,0 +1,85 @@ +# ba_meta require api 7 + +""" + Bomb Radius Visualizer by TheMikirog + + With this cutting edge technology, you precisely know + how close to the bomb you can tread. Supports modified blast radius values! +""" + +from __future__ import annotations + +from typing import TYPE_CHECKING + +# Let's import everything we need and nothing more. +import ba +import bastd +from bastd.actor.bomb import Bomb + +if TYPE_CHECKING: + pass + +# ba_meta export plugin +class BombRadiusVisualizer(ba.Plugin): + + # We use a decorator to add extra code to existing code, increasing mod compatibility. + # Here I'm defining a new bomb init function that'll be replaced. + def new_bomb_init(func): + # This function will return our wrapper function, which is going to take the original function's base arguments. + # Yes, in Python functions are objects that can be passed as arguments. It's bonkers. + # arg[0] is "self" in our original bomb init function. + # We're working kind of blindly here, so it's good to have the original function + # open in a second window for argument reference. + 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) + + # Let's make a new node that's just a circle. It's the some one used in the Target Practice minigame. + # This is going to make a slightly opaque red circle, signifying damaging area. + # We aren't defining the size, because we're gonna animate it shortly after. + args[0].radius_visualizer = ba.newnode('locator', + owner=args[0].node, # Remove itself when the bomb node dies. + attrs={ + 'shape': 'circle', + 'color': (1, 0, 0), + 'opacity':0.05, + 'draw_beauty': False, + 'additive': False + }) + # Let's connect our circle to the bomb. + args[0].node.connectattr('position', args[0].radius_visualizer, 'position') + + # Let's do a fancy animation of that red circle growing into shape like a cartoon. + # We're gonna read our bomb's blast radius and use it to decide the size of our circle. + ba.animate_array(args[0].radius_visualizer, 'size', 1, { + 0.0: [0.0], + 0.2: [args[0].blast_radius * 2.2], + 0.25: [args[0].blast_radius * 2.0] + }) + + # Let's do a second circle, this time just the outline to where the damaging area ends. + args[0].radius_visualizer_circle = ba.newnode('locator', + owner=args[0].node, # Remove itself when the bomb node dies. + attrs={ + 'shape': 'circleOutline', + 'size':[args[0].blast_radius * 2.0], # Here's that bomb's blast radius value again! + 'color': (1, 1, 0), + 'draw_beauty': False, + 'additive': True + }) + # Attach the circle to the bomb. + args[0].node.connectattr('position', args[0].radius_visualizer_circle, 'position') + + # Let's animate that circle too, but this time let's do the opacity. + ba.animate( + args[0].radius_visualizer_circle, 'opacity', { + 0: 0.0, + 0.4: 0.1 + }) + return wrapper + + # Finally we """travel through the game files""" to replace the function we want with our own version. + # We transplant the old function's arguments into our version. + bastd.actor.bomb.Bomb.__init__ = new_bomb_init(bastd.actor.bomb.Bomb.__init__) + \ No newline at end of file diff --git a/plugins/utilities/quickturn.py b/plugins/utilities/quickturn.py new file mode 100644 index 00000000..eff5fd5b --- /dev/null +++ b/plugins/utilities/quickturn.py @@ -0,0 +1,133 @@ +""" + Quickturn by TheMikirog + + Super Smash Bros Melee's wavedash mechanic ported and tuned for BombSquad. + + Sharp turns while running (releasing run button, changing direction, holding run again) are much faster with this mod, allowing for more dynamic, aggressive play. + Version 3 + +""" + +# ba_meta require api 7 + +from __future__ import annotations + +from typing import TYPE_CHECKING + +import ba +import math +import bastd +from bastd.actor.spaz import Spaz + +if TYPE_CHECKING: + pass + +# ba_meta export plugin +class Quickturn(ba.Plugin): + + class FootConnectMessage: + """Spaz started touching the ground""" + + class FootDisconnectMessage: + """Spaz stopped touching the ground""" + + def wavedash(self) -> None: + if not self.node: + return + + isMoving = abs(self.node.move_up_down) >= 0.5 or abs(self.node.move_left_right) >= 0.5 + + if self._dead or not self.grounded or not isMoving: + return + + if self.node.knockout > 0.0 or self.frozen or self.node.hold_node: + return + + t_ms = ba.time(timeformat=ba.TimeFormat.MILLISECONDS) + assert isinstance(t_ms, int) + + if t_ms - self.last_wavedash_time_ms >= self._wavedash_cooldown: + + move = [self.node.move_left_right, -self.node.move_up_down] + vel = [self.node.velocity[0], self.node.velocity[2]] + + move_length = math.hypot(move[0], move[1]) + vel_length = math.hypot(vel[0], vel[1]) + if vel_length < 0.6: return + move_norm = [m/move_length for m in move] + vel_norm = [v/vel_length for v in vel] + dot = sum(x*y for x,y in zip(move_norm,vel_norm)) + turn_power = min(round(math.acos(dot) / math.pi,2)*1.3,1) + + + # https://easings.net/#easeInOutQuart + if turn_power < 0.55: + turn_power = 8 * turn_power * turn_power * turn_power * turn_power + else: + turn_power = 0.55 - pow(-2 * turn_power + 2, 4) / 2 + if turn_power < 0.1: return + + boost_power = math.sqrt(math.pow(vel[0],2) + math.pow(vel[1],2)) * 8 + boost_power = min(pow(boost_power,8),160) + + self.last_wavedash_time_ms = t_ms + + # FX + ba.emitfx(position=self.node.position, + velocity=(vel[0]*0.5,-1,vel[1]*0.5), + chunk_type='spark', + count=5, + scale=boost_power / 160 * turn_power, + spread=0.25); + + # Boost itself + pos = self.node.position + for i in range(6): + self.node.handlemessage('impulse',pos[0],0.2+pos[1]+i*0.1,pos[2], + 0,0,0, + boost_power * turn_power, + boost_power * turn_power,0,0, + move[0],0,move[1]) + + def new_spaz_init(func): + def wrapper(*args, **kwargs): + + func(*args, **kwargs) + + # args[0] = self + args[0]._wavedash_cooldown = 170 + args[0].last_wavedash_time_ms = -9999 + args[0].grounded = 0 + + return wrapper + bastd.actor.spaz.Spaz.__init__ = new_spaz_init(bastd.actor.spaz.Spaz.__init__) + + def new_factory(func): + def wrapper(*args, **kwargs): + func(*args, **kwargs) + + args[0].roller_material.add_actions( + conditions=('they_have_material', bastd.gameutils.SharedObjects.get().footing_material), + actions=(('message', 'our_node', 'at_connect', Quickturn.FootConnectMessage), + ('message', 'our_node', 'at_disconnect', Quickturn.FootDisconnectMessage))) + return wrapper + bastd.actor.spazfactory.SpazFactory.__init__ = new_factory(bastd.actor.spazfactory.SpazFactory.__init__) + + def new_handlemessage(func): + def wrapper(*args, **kwargs): + if args[1] == Quickturn.FootConnectMessage: + args[0].grounded += 1 + elif args[1] == Quickturn.FootDisconnectMessage: + if args[0].grounded > 0: args[0].grounded -= 1 + + func(*args, **kwargs) + return wrapper + bastd.actor.spaz.Spaz.handlemessage = new_handlemessage(bastd.actor.spaz.Spaz.handlemessage) + + def new_on_run(func): + def wrapper(*args, **kwargs): + if args[0]._last_run_value < args[1] and args[1] > 0.8: + Quickturn.wavedash(args[0]) + func(*args, **kwargs) + return wrapper + bastd.actor.spaz.Spaz.on_run = new_on_run(bastd.actor.spaz.Spaz.on_run) \ No newline at end of file diff --git a/plugins/utilities/ragdoll-b-gone.py b/plugins/utilities/ragdoll-b-gone.py new file mode 100644 index 00000000..86bb44d6 --- /dev/null +++ b/plugins/utilities/ragdoll-b-gone.py @@ -0,0 +1,110 @@ +# ba_meta require api 7 + +""" + Ragdoll-B-Gone by TheMikirog + + Removes ragdolls. + Thanos snaps those pesky feet-tripping body sacks out of existence. + Literally that's it. + + Heavily commented for easy modding learning! + +""" + +from __future__ import annotations + +from typing import TYPE_CHECKING + +# Let's import everything we need and nothing more. +import ba +import bastd +import random +from bastd.actor.spaz import Spaz +from bastd.actor.spazfactory import SpazFactory + +if TYPE_CHECKING: + pass + +# ba_meta export plugin +class RagdollBGone(ba.Plugin): + + # We use a decorator to add extra code to existing code, increasing mod compatibility. + # Any gameplay altering mod should master the decorator! + # Here I'm defining a new handlemessage function that'll be replaced. + def new_handlemessage(func): + # This function will return our wrapper function, which is going to take the original function's base arguments. + # Yes, in Python functions are objects that can be passed as arguments. It's bonkers. + # arg[0] is "self", args[1] is "msg" in our original handlemessage function. + # We're working kind of blindly here, so it's good to have the original function + # open in a second window for argument reference. + def wrapper(*args, **kwargs): + if isinstance(args[1], ba.DieMessage): # Replace Spaz death behavior + + # Here we play the gamey death noise in Co-op. + if not args[1].immediate: + if args[0].play_big_death_sound and not args[0]._dead: + ba.playsound(SpazFactory.get().single_player_death_sound) + + # If our Spaz dies by falling out of the map, we want to keep the ragdoll. + # Ragdolls don't impact gameplay if Spaz dies this way, so it's fine if we leave the behavior as is. + if args[1].how == ba.DeathType.FALL: + # The next two properties are all built-in, so their behavior can't be edited directly without touching the C++ layer. + # We can change their values though! + # "hurt" property is basically the health bar above the player and the blinking when low on health. + # 1.0 means empty health bar and the fastest blinking in the west. + args[0].node.hurt = 1.0 + # Make our Spaz close their eyes permanently and then make their body disintegrate. + # Again, this behavior is built in. We can only trigger it by setting "dead" to True. + args[0].node.dead = True + # After the death animation ends (which is around 2 seconds) let's remove the Spaz our of existence. + ba.timer(2.0, args[0].node.delete) + else: + # Here's our new behavior! + # The idea is to remove the Spaz node and make some sparks for extra flair. + # First we see if that node even exists, just in case. + if args[0].node: + # Make sure Spaz isn't dead, so we can perform the removal. + if not args[0]._dead: + # Run this next piece of code 4 times. + # "i" will start at 0 and becomes higher each iteration until it reaches 3. + for i in range(4): + # XYZ position of our sparks, we'll take the Spaz position as a base. + pos = (args[0].node.position[0], + # Let's spread the sparks across the body, assuming Spaz is standing straight. + # We're gonna change the Y axis position, which is height. + args[0].node.position[1] + i * 0.2, + args[0].node.position[2]) + # This function allows us to spawn particles like sparks and bomb shrapnel. + # We're gonna use sparks here. + ba.emitfx(position = pos, # Here we place our edited position. + velocity=args[0].node.velocity, + count=random.randrange(2, 5), # Random amount of sparks between 2 and 5 + scale=3.0, + spread=0.2, + chunk_type='spark') + + # Make a Spaz death noise if we're not gibbed. + if not args[0].shattered: + death_sounds = args[0].node.death_sounds # Get our Spaz's death noises, these change depending on character skins + sound = death_sounds[random.randrange(len(death_sounds))] # Pick a random death noise + ba.playsound(sound, position=args[0].node.position) # Play the sound where our Spaz is + # Delete our Spaz node immediately. + # Removing stuff is weird and prone to errors, so we're gonna delay it. + ba.timer(0.001, args[0].node.delete) + + # Let's mark our Spaz as dead, so he can't die again. + # Notice how we're targeting the Spaz and not it's node. + # "self.node" is a visual representation of the character while "self" is his game logic. + args[0]._dead = True + args[0].hitpoints = 0 # Set his health to zero. This value is independent from the health bar above his head. + return + + # Worry no longer! We're not gonna remove all the base game code! + # Here's where we bring it all back. + # If I wanted to add extra code at the end of the base game's behavior, I would just put that at the beginning of my function. + func(*args, **kwargs) + return wrapper + + # Finally we """travel through the game files""" to replace the function we want with our own version. + # We transplant the old function's arguments into our version. + bastd.actor.spaz.Spaz.handlemessage = new_handlemessage(bastd.actor.spaz.Spaz.handlemessage) From 0d8acc84bea0a4f08331ec68b85a0c4e456afb67 Mon Sep 17 00:00:00 2001 From: TheMikirog Date: Sun, 13 Nov 2022 19:41:42 +0100 Subject: [PATCH 0253/1464] Added Hot Potato minigame --- plugins/minigames/hot_potato.py | 1017 +++++++++++++++++++++++++++++++ 1 file changed, 1017 insertions(+) create mode 100644 plugins/minigames/hot_potato.py diff --git a/plugins/minigames/hot_potato.py b/plugins/minigames/hot_potato.py new file mode 100644 index 00000000..e2af100c --- /dev/null +++ b/plugins/minigames/hot_potato.py @@ -0,0 +1,1017 @@ +""" + + Hot Potato by TheMikirog#1984 + +""" + +# ba_meta require api 7 + +from __future__ import annotations + +from typing import TYPE_CHECKING + +# Define only what we need and nothing more +import ba +from bastd.actor.spaz import SpazFactory +from bastd.actor.spaz import PickupMessage +from bastd.actor.spaz import BombDiedMessage +from bastd.actor.playerspaz import PlayerSpaz +from bastd.actor.bomb import Bomb +from bastd.actor.bomb import Blast +from enum import Enum +import random + +if TYPE_CHECKING: + pass + +# Let's define stun times for falling. +# First element is stun for the first fall, second element is stun for the second fall and so on. +# If we fall more than the amount of elements on this list, we'll use the last entry. +FALL_PENALTIES = [1.5, + 2.5, + 3.5, + 5.0, + 6.0, + 7.0, + 8.0, + 9.0, + 10.0] + +RED_COLOR = (1.0, 0.2, 0.2) +YELLOW_COLOR = (1.0, 1.0, 0.2) + + +# The player in Hot Potato can be in one of these states: +class PlayerState(Enum): + # REGULAR - the state all players start in. + REGULAR = 0 + # MARKED - when a player is marked, they'll be eliminated when the timer hits zero. + # Marked players pass the mark to REGULAR or STUNNED players by harming or grabbing other players. + # MARKED players respawn instantly if they somehow get knocked off the map. + MARKED = 1 + # ELIMINATED - a player is eliminated if the timer runs out during the MARKED state or they leave the game. + # These players can't win and won't respawn. + ELIMINATED = 2 + # STUNNED - if a REGULAR player falls out of the map, they'll receive the STUNNED state. + # STUNNED players are incapable of all movement and actions. + # STUNNED players can still get MARKED, but can't be punched, grabbed or knocked around by REGULAR players. + # STUNNED players will go back to the REGULAR state after several seconds. + # The time it takes to go back to the REGULAR state gets more severe the more times the player dies by falling off the map. + STUNNED = 3 + +# To make the game easier to parse, I added Elimination style icons to the bottom of the screen. +# Here's the behavior of each icon. +class Icon(ba.Actor): + """Creates in in-game icon on screen.""" + + def __init__(self, + player: Player, + position: tuple[float, float], + scale: float, + name_scale: float = 1.0, + name_maxwidth: float = 100.0, + shadow: float = 1.0): + super().__init__() + + # Define the player this icon belongs to + self._player = player + self._name_scale = name_scale + + self._outline_tex = ba.gettexture('characterIconMask') + + # Character portrait + icon = player.get_icon() + self.node = ba.newnode('image', + delegate=self, + attrs={ + 'texture': icon['texture'], + 'tint_texture': icon['tint_texture'], + 'tint_color': icon['tint_color'], + 'vr_depth': 400, + 'tint2_color': icon['tint2_color'], + 'mask_texture': self._outline_tex, + 'opacity': 1.0, + 'absolute_scale': True, + 'attach': 'bottomCenter' + }) + # Player name + self._name_text = ba.newnode( + 'text', + owner=self.node, + attrs={ + 'text': ba.Lstr(value=player.getname()), + 'color': ba.safecolor(player.team.color), + 'h_align': 'center', + 'v_align': 'center', + 'vr_depth': 410, + 'maxwidth': name_maxwidth, + 'shadow': shadow, + 'flatness': 1.0, + 'h_attach': 'center', + 'v_attach': 'bottom' + }) + # Status text (such as Marked!, Stunned! and You're Out!) + self._marked_text = ba.newnode( + 'text', + owner=self.node, + attrs={ + 'text': '', + 'color': (1, 0.1, 0.0), + 'h_align': 'center', + 'v_align': 'center', + 'vr_depth': 430, + 'shadow': 1.0, + 'flatness': 1.0, + 'h_attach': 'center', + 'v_attach': 'bottom' + }) + # Status icon overlaying the character portrait + self._marked_icon = ba.newnode( + 'text', + owner=self.node, + attrs={ + 'text': ba.charstr(ba.SpecialChar.HAL), + 'color': (1, 1, 1), + 'h_align': 'center', + 'v_align': 'center', + 'vr_depth': 430, + 'shadow': 0.0, + 'opacity': 0.0, + 'flatness': 1.0, + 'scale': 2.1, + 'h_attach': 'center', + 'v_attach': 'bottom' + }) + self.set_marked_icon(player.state) + self.set_position_and_scale(position, scale) + + # Change our icon's appearance depending on the player state. + def set_marked_icon(self, type: PlayerState) -> None: + pos = self.node.position + # Regular players get no icons or status text + if type is PlayerState.REGULAR: + self._marked_icon.text = '' + self._marked_text.text = '' + self._marked_icon.opacity = 0.0 + self._name_text.flatness = 1.0 + assert self.node + self.node.color = (1.0, 1.0, 1.0) + # Marked players get ALL of the attention - red portrait, red text and icon overlaying the portrait + elif type is PlayerState.MARKED: + self._marked_icon.text = ba.charstr(ba.SpecialChar.HAL) + self._marked_icon.position = (pos[0] - 1, pos[1] - 13) + self._marked_icon.opacity = 1.0 + self._marked_text.text = 'Marked!' + self._marked_text.color = (1.0, 0.0, 0.0) + self._name_text.flatness = 0.0 + assert self.node + self.node.color = (1.0, 0.2, 0.2) + # Stunned players are just as important - yellow portrait, yellow text and moon icon. + elif type is PlayerState.STUNNED: + self._marked_icon.text = ba.charstr(ba.SpecialChar.MOON) + self._marked_icon.position = (pos[0] - 2, pos[1] - 12) + self._marked_icon.opacity = 1.0 + self._marked_text.text = 'Stunned!' + self._marked_text.color = (1.0, 1.0, 0.0) + assert self.node + self.node.color = (0.75, 0.75, 0.0) + # Eliminated players get special treatment. + # We make the portrait semi-transparent, while adding some visual flair with an fading skull icon and text. + elif type is PlayerState.ELIMINATED: + self._marked_icon.text = ba.charstr(ba.SpecialChar.SKULL) + self._marked_icon.position = (pos[0] - 2, pos[1] - 12) + self._marked_text.text = 'You\'re Out!' + self._marked_text.color = (0.5, 0.5, 0.5) + + # Animate text and icon + animation_end_time = 1.5 if bool(self.activity.settings['Epic Mode']) else 3.0 + ba.animate(self._marked_icon,'opacity', { + 0: 1.0, + animation_end_time: 0.0}) + ba.animate(self._marked_text,'opacity', { + 0: 1.0, + animation_end_time: 0.0}) + + self._name_text.opacity = 0.2 + assert self.node + self.node.color = (0.7, 0.3, 0.3) + self.node.opacity = 0.2 + else: + # If we beef something up, let the game know we made a mess in the code by providing a non-existant state. + raise Exception("invalid PlayerState type") + + # Set where our icon is positioned on the screen and how big it is. + def set_position_and_scale(self, position: tuple[float, float], + scale: float) -> None: + """(Re)position the icon.""" + assert self.node + self.node.position = position + self.node.scale = [70.0 * scale] + self._name_text.position = (position[0], position[1] + scale * 52.0) + self._name_text.scale = 1.0 * scale * self._name_scale + self._marked_text.position = (position[0], position[1] - scale * 52.0) + self._marked_text.scale = 0.8 * scale + +# This gamemode heavily relies on edited player behavior. +# We need that amount of control, so we're gonna create our own class and use the original PlayerSpaz as our blueprint. +class PotatoPlayerSpaz(PlayerSpaz): + + def __init__(self, *args, **kwargs): + + super().__init__(*args, **kwargs) # unchanged Spaz __init__ code goes here + self.dropped_bombs = [] # we use this to track bombs thrown by the player + + # Define a marked light + self.marked_light = ba.newnode('light', + owner=self.node, + attrs={'position':self.node.position, + 'radius':0.15, + 'intensity':0.0, + 'height_attenuated':False, + 'color': (1.0, 0.0, 0.0)}) + + # Pulsing red light when the player is Marked + ba.animate(self.marked_light,'radius',{ + 0: 0.1, + 0.3: 0.15, + 0.6: 0.1}, + loop = True) + self.node.connectattr('position_center',self.marked_light,'position') + + # Marked timer. It should be above our head, so we attach the text to the offset that's attached to the player. + self.marked_timer_offset = ba.newnode('math', owner = self.node, attrs = { + 'input1': (0, 1.2, 0), + 'operation': 'add'}) + self.node.connectattr('torso_position', self.marked_timer_offset, 'input2') + + self.marked_timer_text = ba.newnode('text', owner = self.node, attrs = { + 'text': '', + 'in_world': True, + 'shadow': 0.4, + 'color': (RED_COLOR[0], RED_COLOR[1], RED_COLOR[2], 0.0), + 'flatness': 0, + 'scale': 0.02, + 'h_align': 'center'}) + self.marked_timer_offset.connectattr('output', self.marked_timer_text, 'position') + + # Modified behavior when dropping bombs + def drop_bomb(self) -> stdbomb.Bomb | None: + # The original function returns the Bomb the player created. + # This is super helpful for us, since all we need is to mark the bombs red + # if they belong to the Marked player and nothing else. + bomb = super().drop_bomb() + # Let's make sure the player actually created a new bomb + if bomb: + # Add our bomb to the list of our tracked bombs + self.dropped_bombs.append(bomb) + # Bring a light + bomb.bomb_marked_light = ba.newnode('light', + owner=bomb.node, + attrs={'position':bomb.node.position, + 'radius':0.04, + 'intensity':0.0, + 'height_attenuated':False, + 'color': (1.0, 0.0, 0.0)}) + # Attach the light to the bomb + bomb.node.connectattr('position',bomb.bomb_marked_light,'position') + # Let's adjust all lights for all bombs that we own. + self.set_bombs_marked() + # When the bomb physics node dies, call a function. + bomb.node.add_death_action( + ba.WeakCall(self.bomb_died, bomb)) + + + # Here's the function that gets called when one of the player's bombs dies. + # We reference the player's dropped_bombs list and remove the bomb that died. + def bomb_died(self, bomb): + self.dropped_bombs.remove(bomb) + + # Go through all the bombs this player has in the world. + # Paint them red if the owner is marked, turn off the light otherwise. + # We need this light to inform the player about bombs YOU DON'T want to get hit by. + def set_bombs_marked(self): + for bomb in self.dropped_bombs: + bomb.bomb_marked_light.intensity = 20.0 if self._player.state == PlayerState.MARKED else 0.0 + + # Since our gamemode relies heavily on players passing the mark to other players + # we need to have access to this message. This gets called when the player takes damage for any reason. + def handlemessage(self, msg): + if isinstance(msg, ba.HitMessage): + # This is basically the same HitMessage code as in the original Spaz. + # The only difference is that there is no health bar and you can't die with punches or bombs. + # Also some useless or redundant code was removed. + # I'm still gonna comment all of it since we're here. + if not self.node: + return None + + # If the attacker is marked, pass that mark to us. + self.activity.pass_mark(msg._source_player, self._player) + + # When stun timer runs out, we explode. Let's make sure our own explosion does throw us around. + if msg.hit_type == 'stun_blast' and msg._source_player == self.source_player: return True + # If the attacker is healthy and we're stunned, do a flash and play a sound, then ignore the rest of the code. + if self.source_player.state == PlayerState.STUNNED and msg._source_player != PlayerState.MARKED: + self.node.handlemessage('flash') + ba.playsound(SpazFactory.get().block_sound, + 1.0, + position=self.node.position) + return True + + # Here's all the damage and force calculations unchanged from the source. + mag = msg.magnitude * self.impact_scale + velocity_mag = msg.velocity_magnitude * self.impact_scale + damage_scale = 0.22 + + # We use them to apply a physical force to the player. + # Normally this is also used for damage, but we we're not gonna do it. + # We're still gonna calculate it, because it's still responsible for knockback. + 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], mag, + velocity_mag, msg.radius, 0, msg.force_direction[0], + msg.force_direction[1], msg.force_direction[2]) + damage = int(damage_scale * self.node.damage) + self.node.handlemessage('hurt_sound') # That's how we play spaz node's hurt sound + + # Play punch impact sounds based on damage if it was a punch. + # We don't show damage percentages, because it's irrelevant. + if msg.hit_type == 'punch': + self.on_punched(damage) + + if damage >= 500: + sounds = SpazFactory.get().punch_sound_strong + sound = sounds[random.randrange(len(sounds))] + elif damage >= 100: + sound = SpazFactory.get().punch_sound + else: + sound = SpazFactory.get().punch_sound_weak + ba.playsound(sound, 1.0, position=self.node.position) + + # Throw up some chunks. + assert msg.force_direction is not None + ba.emitfx(position=msg.pos, + velocity=(msg.force_direction[0] * 0.5, + msg.force_direction[1] * 0.5, + msg.force_direction[2] * 0.5), + count=min(10, 1 + int(damage * 0.0025)), + scale=0.3, + spread=0.03) + + ba.emitfx(position=msg.pos, + chunk_type='sweat', + velocity=(msg.force_direction[0] * 1.3, + msg.force_direction[1] * 1.3 + 5.0, + msg.force_direction[2] * 1.3), + count=min(30, 1 + int(damage * 0.04)), + scale=0.9, + spread=0.28) + + # Momentary flash. This spawns around where the Spaz's punch would be (we're kind of guessing here). + hurtiness = damage * 0.003 + punchpos = (msg.pos[0] + msg.force_direction[0] * 0.02, + msg.pos[1] + msg.force_direction[1] * 0.02, + msg.pos[2] + msg.force_direction[2] * 0.02) + flash_color = (1.0, 0.8, 0.4) + light = ba.newnode( + 'light', + attrs={ + 'position': punchpos, + 'radius': 0.12 + hurtiness * 0.12, + 'intensity': 0.3 * (1.0 + 1.0 * hurtiness), + 'height_attenuated': False, + 'color': flash_color + }) + ba.timer(0.06, light.delete) + + flash = ba.newnode('flash', + attrs={ + 'position': punchpos, + 'size': 0.17 + 0.17 * hurtiness, + 'color': flash_color + }) + ba.timer(0.06, flash.delete) + + # Physics collision particles. + if msg.hit_type == 'impact': + assert msg.force_direction is not None + ba.emitfx(position=msg.pos, + velocity=(msg.force_direction[0] * 2.0, + msg.force_direction[1] * 2.0, + msg.force_direction[2] * 2.0), + count=min(10, 1 + int(damage * 0.01)), + scale=0.4, + spread=0.1) + + # Briefly flash when hit. + # We shouldn't play this if we're dead. + if self.hitpoints > 0: + + self.node.handlemessage('flash') + + # If we're holding something, drop it. + if damage > 0.0 and self.node.hold_node: + self.node.hold_node = None + # If we get grabbed, this function is called. + # We want to pass along the mark with grabs too. + elif isinstance(msg, PickupMessage): + # Make sure our body exists. + if not self.node: + return None + + # Let's get all collision data if we can. Otherwise cancel. + try: + collision = ba.getcollision() + opposingnode = collision.opposingnode + except ba.NotFoundError: + return True + + # Our grabber needs to be a Spaz + if opposingnode.getnodetype() == 'spaz': + # Disallow grabbing if a healthy player tries to grab us and we're stunned. + # If they're marked, continue with our scheduled program. + # It's the same sound and flashing behavior as hitting a stunned player as a healthy player. + if (opposingnode.source_player.state == PlayerState.STUNNED and self.source_player.state != PlayerState.MARKED): + opposingnode.handlemessage('flash') + ba.playsound(SpazFactory.get().block_sound, + 1.0, + position=opposingnode.position) + return True + # If they're marked and we're healthy or stunned, pass that mark along to us. + elif opposingnode.source_player.state in [PlayerState.REGULAR, PlayerState.STUNNED] and self.source_player.state == PlayerState.MARKED: + self.activity.pass_mark(self.source_player, opposingnode.source_player) + + # Our work is done. Continue with the rest of the grabbing behavior as usual. + super().handlemessage(msg) + # Dying is important in this gamemode and as such we need to address this behavior. + elif isinstance(msg, ba.DieMessage): + + # If a player left the game, inform our gamemode logic. + if msg.how == ba.DeathType.LEFT_GAME: + self.activity.player_left(self.source_player) + + # If a MARKED or STUNNED player dies, hide the text from the previous spaz. + if self.source_player.state in [PlayerState.MARKED, PlayerState.STUNNED]: + self.marked_timer_text.color = (self.marked_timer_text.color[0], + self.marked_timer_text.color[1], + self.marked_timer_text.color[2], + 0.0) + ba.animate(self.marked_light,'intensity',{ + 0: self.marked_light.intensity, + 0.5: 0.0}) + + # Continue with the rest of the behavior. + super().handlemessage(msg) + # If a message is something we haven't modified yet, let's pass it along to the original. + else: super().handlemessage(msg) + +# A concept of a player is very useful to reference if we don't have a player character present (maybe they died). +class Player(ba.Player['Team']): + """Our player type for this game.""" + + def __init__(self) -> None: + # Most of these are self explanatory. + self.icon: Icon = None + self.fall_times: int = 0 + self.state: PlayerState = PlayerState.REGULAR + self.stunned_time_remaining = None + # These are references to timers responsible for handling stunned behavior. + self.stunned_timer = None + self.stunned_update_timer = None + + # If we're stunned, a timer calls this every 0.1 seconds. + def stunned_timer_tick(self) -> None: + # Decrease our time remaining then change the text displayed above the Spaz's head + self.stunned_time_remaining -= 0.1 + self.stunned_time_remaining = max(0.0, self.stunned_time_remaining) + self.actor.marked_timer_text.text = str(round(self.stunned_time_remaining, 2)) + + # When stun time is up, call this function. + def stun_remove(self) -> None: + # Let's proceed only if we're stunned + if self.state != PlayerState.STUNNED: return + # Do an explosion where we're standing. Normally it would throw us around, but we dealt + # with this issue in PlayerSpaz's edited HitMessage in line 312. + Blast(position=self.actor.node.position, + velocity=self.actor.node.velocity, + blast_radius=2.5, + hit_type='stun_blast', # This hit type allows us to ignore our own stun blast explosions. + source_player=self).autoretain() + # Let's switch our state back to healthy. + self.set_state(PlayerState.REGULAR) + + # States are a key part of this gamemode and a lot of logic has to be done to acknowledge these state changes. + def set_state(self, state: PlayerState) -> None: + # Let's remember our old state before we change it. + old_state = self.state + + # If we just became stunned, do all of this: + if old_state != PlayerState.STUNNED and state == PlayerState.STUNNED: + self.actor.disconnect_controls_from_player() # Disallow all movement and actions + # Let's set our stun time based on the amount of times we fell out of the map. + if self.fall_times < len(FALL_PENALTIES): + stun_time = FALL_PENALTIES[self.fall_times] + else: + stun_time = FALL_PENALTIES[len(FALL_PENALTIES) - 1] + + self.stunned_time_remaining = stun_time # Set our stun time remaining + self.stunned_timer = ba.Timer(stun_time + 0.1, ba.Call(self.stun_remove)) # Remove our stun once the time is up + self.stunned_update_timer = ba.Timer(0.1, ba.Call(self.stunned_timer_tick), repeat = True) # Call a function every 0.1 seconds + self.fall_times += 1 # Increase the amount of times we fell by one + self.actor.marked_timer_text.text = str(stun_time) # Change the text above the Spaz's head to total stun time + + # If we were stunned, but now we're not, let's reconnect our controls. + # CODING CHALLENGE: to punch or bomb immediately after the stun ends, you need to + # time the button press frame-perfectly in order for it to work. + # What if we could press the button shortly before stun ends to do the action as soon as possible? + # If you're feeling up to the challenge, feel free to implement that! + if old_state == PlayerState.STUNNED and state != PlayerState.STUNNED: + self.actor.connect_controls_to_player() + + # When setting a state that is not STUNNED, clear all timers. + if state != PlayerState.STUNNED: + self.stunned_timer = None + self.stunned_update_timer = None + + # Here's all the light and text colors that we set depending on the state. + if state == PlayerState.MARKED: + self.actor.marked_light.intensity = 1.5 + self.actor.marked_light.color = (1.0, 0.0, 0.0) + self.actor.marked_timer_text.color = (RED_COLOR[0], + RED_COLOR[1], + RED_COLOR[2], + 1.0) + elif state == PlayerState.STUNNED: + self.actor.marked_light.intensity = 0.5 + self.actor.marked_light.color = (1.0, 1.0, 0.0) + self.actor.marked_timer_text.color = (YELLOW_COLOR[0], + YELLOW_COLOR[1], + YELLOW_COLOR[2], + 1.0) + else: + self.actor.marked_light.intensity = 0.0 + self.actor.marked_timer_text.text = '' + + self.state = state + self.actor.set_bombs_marked() # Light our bombs red if we're Marked, removes the light otherwise + self.icon.set_marked_icon(state) # Update our icon + + +# ba_meta export game +class HotPotato(ba.TeamGameActivity[Player, ba.Team]): + + # Let's define the basics like the name of the game, description and some tips that should appear at the start of a match. + name = 'Hot Potato' + description = ('A random player gets marked.\n' + 'Pass the mark to other players.\n' + 'Marked player gets eliminated when time runs out.\n' + 'Last one standing wins!') + tips = [ + 'You can pass the mark not only with punches and grabs, but bombs as well.', + 'If you\'re not marked, DON\'T fall off the map!\nEach fall will be punished with immobility.', + 'Falling can be a good escape strategy, but don\'t over rely on it.\nYou\'ll be defenseless if you respawn!', + 'Stunned players are immune to healthy players, but not to Marked players!', + 'Each fall when not Marked increases your time spent stunned.', + 'Try throwing healthy players off the map to make their timers\nlonger the next time they get stunned.', + 'Marked players don\'t get stunned when falling off the map.', + 'For total disrespect, try throwing the Marked player off the map\nwithout getting marked yourself!', + 'Feeling evil? Throw healthy players towards the Marked player!', + 'Red bombs belong to the Marked player!\nWatch out for those!', + 'Stunned players explode when their stun timer runs out.\nIf that time is close to zero, keep your distance!' + ] + + # We're gonna distribute end of match session scores based on who dies first and who survives. + # First place gets most points, then second, then third. + scoreconfig = ba.ScoreConfig(label='Place', + scoretype=ba.ScoreType.POINTS, + lower_is_better=True) + + # These variables are self explanatory too. + show_kill_points = False + allow_mid_activity_joins = False + + # Let's define some settings the user can mess around with to fit their needs. + available_settings = [ + ba.IntSetting('Elimination Timer', + min_value=5, + default=15, + increment=1, + ), + ba.BoolSetting('Marked Players use Impact Bombs', default=False), + ba.BoolSetting('Epic Mode', default=False), + ] + + # Hot Potato is strictly a Free-For-All gamemode, so only picking the gamemode in FFA playlists. + @classmethod + def supports_session_type(cls, sessiontype: type[ba.Session]) -> bool: + return issubclass(sessiontype, ba.FreeForAllSession) + + # Most maps should work in Hot Potato. Generally maps marked as 'melee' are the most versatile map types of them all. + # As the name implies, fisticuffs are common forms of engagement. + @classmethod + def get_supported_maps(cls, sessiontype: type[ba.Session]) -> list[str]: + return ba.getmaps('melee') + + # Here we define everything the gamemode needs, like sounds and settings. + def __init__(self, settings: dict): + super().__init__(settings) + self.settings = settings + + # Let's define all of the sounds we need. + self._tick_sound = ba.getsound('tick') + self._player_eliminated_sound = ba.getsound('playerDeath') + # These next sounds are arrays instead of single sounds. + # We'll use that fact later. + self._danger_tick_sounds = [ba.getsound('orchestraHit'), + ba.getsound('orchestraHit2'), + ba.getsound('orchestraHit3')] + self._marked_sounds = [ba.getsound('powerdown01'), + ba.getsound('activateBeep'), + ba.getsound('hiss')] + + # Normally play KOTH music, but switch to Epic music if we're in slow motion. + self._epic_mode = bool(settings['Epic Mode']) + self.slow_motion = self._epic_mode + self.default_music = (ba.MusicType.EPIC if self._epic_mode else + ba.MusicType.SCARY) + + # This description appears below the title card after it comes crashing when the game begins. + def get_instance_description(self) -> str | Sequence: + return 'Pass the mark to someone else before you explode!' + + # This is the tiny text that is displayed in the corner during the game as a quick reminder of the objective. + def get_instance_description_short(self) -> str | Sequence: + return 'pass the mark' + + # Set up our player every time they join. + # Because you can't join mid-match, this will always be called at the beginning of the game. + def on_player_join(self, player: Player) -> None: + + player.state = PlayerState.REGULAR + player.fall_times = 0 + + # Create our icon and spawn. + if not self.has_begun(): + player.icon = Icon(player, position=(0, 50), scale=0.8) + self.spawn_player(player) + + # Returns every single marked player. + # This piece of info is used excensively in this gamemode, so it's advantageous to have a function to cut on + # work and make the gamemode easier to maintain + def get_marked_players(self) -> Sequence[ba.Player]: + marked_players = [] + for p in self.players: + if p.state == PlayerState.MARKED: + marked_players.append(p) + return marked_players + + # Marks a player. This sets their state, spawns some particles and sets the timer text above their heads. + def mark(self, target: Player) -> None: + target.set_state(PlayerState.MARKED) + + ba.emitfx(position=target.actor.node.position, + velocity=target.actor.node.velocity, + chunk_type='spark', + count=int(20.0+random.random()*20), + scale=1.0, + spread=1.0); + if bool(self.settings['Marked Players use Impact Bombs']): + target.actor.bomb_type = 'impact' + target.actor.marked_timer_text.text = str(self.elimination_timer_display) + + # Removes the mark from the player. This restores the player to its initial state. + def remove_mark(self, target: Player) -> None: + if target.state != PlayerState.MARKED: + return + + target.actor.bomb_type = 'normal' + + target.set_state(PlayerState.REGULAR) + target.actor.marked_timer_text.text = '' + + # Pass the mark from one player to another. + # This is more desirable than calling mark and remove_mark functions constantly and gives us + # more control over the mark spreading mechanic. + def pass_mark(self, marked_player: Player, hit_player: Player) -> None: + # Make sure both players meet the requirements + if not marked_player or not hit_player: return + if marked_player.state == PlayerState.MARKED and hit_player.state != PlayerState.MARKED: + self.mark(hit_player) + self.remove_mark(marked_player) + + # This function is called every second a marked player exists. + def _eliminate_tick(self) -> None: + marked_players = self.get_marked_players() + marked_player_amount = len(marked_players) + + # If there is no marked players, raise an exception. + # This is used for debugging purposes, which lets us know we messed up somewhere else in the code. + if len(self.get_marked_players()) == 0: + raise Exception("no marked players!") + + self.elimination_timer_display -= 1 # Decrease our timer by one second. + if self.elimination_timer_display > 1: + sound_volume = 1.0 / marked_player_amount + + for target in marked_players: + ba.playsound(self._tick_sound, sound_volume, target.actor.node.position) + target.actor.marked_timer_text.text = str(self.elimination_timer_display) + + # When counting down 3, 2, 1 play some dramatic sounds + if self.elimination_timer_display <= 3: + # We store our dramatic sounds in an array, so we target a specific element on the array + # depending on time remaining. Arrays start at index 0, so we need to decrease + # our variable by 1 to get the element index. + ba.playsound(self._danger_tick_sounds[self.elimination_timer_display - 1], 1.5) + else: + # Elimination timer is up! Let's eliminate all marked players. + self._eliminate_marked_players() + + # This function explodes all marked players + def _eliminate_marked_players(self) -> None: + self.marked_tick_timer = None + for target in self.get_marked_players(): + target.set_state(PlayerState.ELIMINATED) + target.actor.marked_timer_text.text = '' + + Blast(position=target.actor.node.position, + velocity=target.actor.node.velocity, + blast_radius=3.0, + source_player=target).autoretain() + ba.emitfx(position=target.actor.node.position, + velocity=target.actor.node.velocity, + count=int(16.0+random.random()*60), + scale=1.5, + spread=2, + chunk_type='spark') + target.actor.handlemessage(ba.DieMessage(how='marked_elimination')) + target.actor.shatter(extreme=True) + + self.match_placement.append(target.team) + + ba.playsound(self._player_eliminated_sound, 1.0) + + # Let the gamemode know a Marked + self.marked_players_died() + + # This function should be called when a Marked player dies, like when timer runs out or they leave the game. + def marked_players_died(self) -> bool: + alive_players = self.get_alive_players() + # Is there only one player remaining? Or none at all? Let's end the gamemode + if len(alive_players) < 2: + if len(alive_players) == 1: + self.match_placement.append(alive_players[0].team) # Let's add our lone survivor to the match placement list. + # Wait a while to let this sink in before we announce our victor. + self._end_game_timer = ba.Timer(1.25, ba.Call(self.end_game)) + else: + # There's still players remaining, so let's wait a while before marking a new player. + self.new_mark_timer = ba.Timer(2.0 if self.slow_motion else 4.0, ba.Call(self.new_mark)) + + # Another extensively used function that returns all alive players. + def get_alive_players(self) -> Sequence[ba.Player]: + alive_players = [] + for player in self.players: + if player.state == PlayerState.ELIMINATED: continue # Ignore players who have been eliminated + if player.is_alive(): + alive_players.append(player) + return alive_players + + # This function is called every time we want to start a new "round" by marking a random player. + def new_mark(self) -> None: + + # Don't mark a new player if we've already announced a victor. + if self.has_ended(): + return + + possible_targets = self.get_alive_players() + all_victims = [] + # Let's mark TWO players at once if there's 6 or more players. Helps with the pacing. + multi_choice = len(possible_targets) > 5 + + if multi_choice: + # Pick our first victim at random. + first_victim = random.choice(possible_targets) + all_victims.append(first_victim) + possible_targets.remove(first_victim) + # Let's pick our second victim, but this time excluding the player we picked earlier. + all_victims.append(random.choice(possible_targets)) + else: + # Pick one victim at random. + all_victims = [random.choice(possible_targets)] + + self.elimination_timer_display = self.settings['Elimination Timer'] # Set time until marked players explode + self.marked_tick_timer = ba.Timer(1.0, ba.Call(self._eliminate_tick), repeat=True) # Set a timer that calls _eliminate_tick every second + # Mark all chosen victims and play a sound + for new_victim in all_victims: + # _marked_sounds is an array. + # To make a nice marked sound effect, I play multiple sounds at once + # All of them are contained in the array. + for sound in self._marked_sounds: + ba.playsound(sound, 1.0, new_victim.actor.node.position) + self.mark(new_victim) + + # This function is called the gamemode first loads. + def on_begin(self) -> None: + super().on_begin() # Do standard gamemode on_begin behavior + + self.elimination_timer_display = 0 + self.match_placement = [] + + # End the game if there's only one player + if len(self.players) < 2: + self.match_placement.append(self.players[0].team) + self._round_end_timer = ba.Timer(0.5, self.end_game) + else: + # Pick a random player(s) to get marked + self.new_mark_timer = ba.Timer(2.0 if self.slow_motion else 5.2, ba.Call(self.new_mark)) + + self._update_icons() # Create player state icons + + # This function creates and positions player state icons + def _update_icons(self): + count = len(self.teams) + x_offs = 100 + xval = x_offs * (count - 1) * -0.5 + # FUN FACT: In FFA games, every player belongs to a one-player team. + for team in self.teams: + if len(team.players) == 1: + player = team.players[0] + player.icon.set_position_and_scale((xval, 50), 0.8) + xval += x_offs + + # Hot Potato can be a bit much, so I opted to show gameplay tips at the start of the match. + # However because I put player state icons, the tips overlay the icons. + # I'm gonna modify this function to move the tip text above the icons. + def _show_tip(self) -> None: + + from ba._gameutils import animate, GameTip + from ba._generated.enums import SpecialChar + from ba._language import Lstr + + # If there's any tips left on the list, display one. + if self.tips: + tip = self.tips.pop(random.randrange(len(self.tips))) + tip_title = Lstr(value='${A}:', + subs=[('${A}', Lstr(resource='tipText'))]) + icon: ba.Texture | None = None + sound: ba.Sound | None = None + if isinstance(tip, GameTip): + icon = tip.icon + sound = tip.sound + tip = tip.text + assert isinstance(tip, str) + + # Do a few substitutions. + tip_lstr = Lstr(translate=('tips', tip), + subs=[('${PICKUP}', + ba.charstr(SpecialChar.TOP_BUTTON))]) + base_position = (75, 50) + tip_scale = 0.8 + tip_title_scale = 1.2 + vrmode = ba.app.vr_mode + + t_offs = -350.0 + height_offs = 100.0 + tnode = ba.newnode('text', + attrs={ + 'text': tip_lstr, + 'scale': tip_scale, + 'maxwidth': 900, + 'position': (base_position[0] + t_offs, + base_position[1] + height_offs), + 'h_align': 'left', + 'vr_depth': 300, + 'shadow': 1.0 if vrmode else 0.5, + 'flatness': 1.0 if vrmode else 0.5, + 'v_align': 'center', + 'v_attach': 'bottom' + }) + t2pos = (base_position[0] + t_offs - (20 if icon is None else 82), + base_position[1] + 2 + height_offs) + t2node = ba.newnode('text', + owner=tnode, + attrs={ + 'text': tip_title, + 'scale': tip_title_scale, + 'position': t2pos, + 'h_align': 'right', + 'vr_depth': 300, + 'shadow': 1.0 if vrmode else 0.5, + 'flatness': 1.0 if vrmode else 0.5, + 'maxwidth': 140, + 'v_align': 'center', + 'v_attach': 'bottom' + }) + if icon is not None: + ipos = (base_position[0] + t_offs - 40, base_position[1] + 1 + height_offs) + img = ba.newnode('image', + attrs={ + 'texture': icon, + 'position': ipos, + 'scale': (50, 50), + 'opacity': 1.0, + 'vr_depth': 315, + 'color': (1, 1, 1), + 'absolute_scale': True, + 'attach': 'bottomCenter' + }) + animate(img, 'opacity', {0: 0, 1.0: 1, 4.0: 1, 5.0: 0}) + ba.timer(5.0, img.delete) + if sound is not None: + ba.playsound(sound) + + combine = ba.newnode('combine', + owner=tnode, + attrs={ + 'input0': 1.0, + 'input1': 0.8, + 'input2': 1.0, + 'size': 4 + }) + combine.connectattr('output', tnode, 'color') + combine.connectattr('output', t2node, 'color') + animate(combine, 'input3', {0: 0, 1.0: 1, 4.0: 1, 5.0: 0}) + ba.timer(5.0, tnode.delete) + + # This function is called when a player leaves the game. + # This is only called when the player already joined with a character. + def player_left(self, player: Player) -> None: + # If the leaving player is marked, remove the mark + if player.state == PlayerState.MARKED: + self.remove_mark(player) + + # If the leaving player is stunned, remove all stun timers + elif player.state == PlayerState.STUNNED: + player.stunned_timer = None + player.stunned_update_timer = None + + if len(self.get_marked_players()) == len(self.get_alive_players()): + for i in self.get_marked_players(): + self.remove_mark(i) + + if len(self.get_marked_players()) == 0: + self.marked_tick_timer = None + self.marked_players_died() + + player.set_state(PlayerState.ELIMINATED) + + def spawn_player(self, player: Player) -> ba.Actor: + position = self.map.get_ffa_start_position(self.players) + position = (position[0], + position[1] - 0.3, + position[2]) + + name = player.getname() + + light_color = ba.normalized_color(player.color) + display_color = ba.safecolor(player.color, target_intensity=0.75) + + spaz = PotatoPlayerSpaz(color=player.color, + highlight=player.highlight, + character=player.character, + player=player) + spaz.node.invincible = False + player.actor = spaz + + spaz.node.name = name + spaz.node.name_color = display_color + spaz.connect_controls_to_player() + + # move to the stand position and add a flash of light + spaz.handlemessage(ba.StandMessage(position, random.uniform(0, 360))) + t = ba.time(ba.TimeType.BASE) + ba.playsound(self._spawn_sound, 1.0, position=spaz.node.position) + light = ba.newnode('light', attrs={'color': light_color}) + spaz.node.connectattr('position', light, 'position') + ba.animate(light, 'intensity', {0: 0, + 0.25: 1, + 0.5: 0}) + ba.timer(0.5, light.delete) + + def handlemessage(self, msg: Any) -> Any: + if isinstance(msg, ba.PlayerDiedMessage): + super().handlemessage(msg) + player = msg.getplayer(Player) + + # If a player gets eliminated, don't respawn + if msg.how == 'marked_elimination': return + + self.spawn_player(player) + + # If a REGULAR player dies, they respawn STUNNED. + # If a STUNNED player dies, reapply all visual effects. + if player.state in [PlayerState.REGULAR, PlayerState.STUNNED]: + player.set_state(PlayerState.STUNNED) + + # If a MARKED player falls off the map, apply the MARKED effects on the new spaz that respawns. + if player.state == PlayerState.MARKED: + self.mark(player) + + def end_game(self) -> None: + if self.has_ended(): + return + results = ba.GameResults() + self.match_placement.reverse() + for team in self.teams: + results.set_team_score(team, self.match_placement.index(team) + 1) + self.end(results=results) From f7ac41b33d24385fac3a87ffb126bc32834d3ecd Mon Sep 17 00:00:00 2001 From: TheMikirog Date: Sun, 13 Nov 2022 20:44:32 +0100 Subject: [PATCH 0254/1464] Update hot_potato.py --- plugins/minigames/hot_potato.py | 43 ++++++++++++++++++++++++--------- 1 file changed, 32 insertions(+), 11 deletions(-) diff --git a/plugins/minigames/hot_potato.py b/plugins/minigames/hot_potato.py index e2af100c..bb2376e8 100644 --- a/plugins/minigames/hot_potato.py +++ b/plugins/minigames/hot_potato.py @@ -1,6 +1,15 @@ """ Hot Potato by TheMikirog#1984 + + A random player(s) gets Marked. + They will die if they don't pass the mark to other players. + After they die, another random player gets Marked. + Last player standing wins! + + Heavily commented for easy modding learning! + + No Rights Reserved """ @@ -404,7 +413,7 @@ def handlemessage(self, msg): spread=0.1) # Briefly flash when hit. - # We shouldn't play this if we're dead. + # We shouldn't do this if we're dead. if self.hitpoints > 0: self.node.handlemessage('flash') @@ -810,7 +819,7 @@ def new_mark(self) -> None: ba.playsound(sound, 1.0, new_victim.actor.node.position) self.mark(new_victim) - # This function is called the gamemode first loads. + # This function is called when the gamemode first loads. def on_begin(self) -> None: super().on_begin() # Do standard gamemode on_begin behavior @@ -822,7 +831,7 @@ def on_begin(self) -> None: self.match_placement.append(self.players[0].team) self._round_end_timer = ba.Timer(0.5, self.end_game) else: - # Pick a random player(s) to get marked + # Pick random player(s) to get marked self.new_mark_timer = ba.Timer(2.0 if self.slow_motion else 5.2, ba.Call(self.new_mark)) self._update_icons() # Create player state icons @@ -861,7 +870,7 @@ def _show_tip(self) -> None: tip = tip.text assert isinstance(tip, str) - # Do a few substitutions. + # Do a few replacements. tip_lstr = Lstr(translate=('tips', tip), subs=[('${PICKUP}', ba.charstr(SpecialChar.TOP_BUTTON))]) @@ -955,10 +964,11 @@ def player_left(self, player: Player) -> None: player.set_state(PlayerState.ELIMINATED) + # This function is called every time a player spawns def spawn_player(self, player: Player) -> ba.Actor: position = self.map.get_ffa_start_position(self.players) position = (position[0], - position[1] - 0.3, + position[1] - 0.3, # Move the spawn a bit lower position[2]) name = player.getname() @@ -966,18 +976,19 @@ def spawn_player(self, player: Player) -> ba.Actor: light_color = ba.normalized_color(player.color) display_color = ba.safecolor(player.color, target_intensity=0.75) + # Here we actually crate the player character spaz = PotatoPlayerSpaz(color=player.color, highlight=player.highlight, character=player.character, player=player) - spaz.node.invincible = False - player.actor = spaz + spaz.node.invincible = False # Immediately turn off invincibility + player.actor = spaz # Assign player character to the owner spaz.node.name = name spaz.node.name_color = display_color spaz.connect_controls_to_player() - # move to the stand position and add a flash of light + # Move to the stand position and add a flash of light spaz.handlemessage(ba.StandMessage(position, random.uniform(0, 360))) t = ba.time(ba.TimeType.BASE) ba.playsound(self._spawn_sound, 1.0, position=spaz.node.position) @@ -988,15 +999,17 @@ def spawn_player(self, player: Player) -> ba.Actor: 0.5: 0}) ba.timer(0.5, light.delete) + # Game reacts to various events def handlemessage(self, msg: Any) -> Any: + # This is called if the player dies. if isinstance(msg, ba.PlayerDiedMessage): - super().handlemessage(msg) + super().handlemessage(msg) # player = msg.getplayer(Player) # If a player gets eliminated, don't respawn if msg.how == 'marked_elimination': return - self.spawn_player(player) + self.spawn_player(player) # Spawn a new player character # If a REGULAR player dies, they respawn STUNNED. # If a STUNNED player dies, reapply all visual effects. @@ -1007,11 +1020,19 @@ def handlemessage(self, msg: Any) -> Any: if player.state == PlayerState.MARKED: self.mark(player) + # This is called when we want to end the game and announce a victor def end_game(self) -> None: + # Proceed only if the game hasn't ended yet. if self.has_ended(): return results = ba.GameResults() + # By this point our match placement list should be filled with all players. + # Players that died/left earliest should be the first entries. + # We're gonna use array indexes to decide match placements. + # Because of that, we're gonna flip the order of our array, so the last entries are first. self.match_placement.reverse() for team in self.teams: + # Use each player's index in the array for our scoring + # 0 is the first index, so we add 1 to the score. results.set_team_score(team, self.match_placement.index(team) + 1) - self.end(results=results) + self.end(results=results) # Standard game ending behavior From 73b367940393da16601baffe75b928b21c2d53a2 Mon Sep 17 00:00:00 2001 From: TheMikirog Date: Sun, 13 Nov 2022 20:44:55 +0100 Subject: [PATCH 0255/1464] Update ragdoll-b-gone.py --- plugins/utilities/ragdoll-b-gone.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/plugins/utilities/ragdoll-b-gone.py b/plugins/utilities/ragdoll-b-gone.py index 86bb44d6..f496d626 100644 --- a/plugins/utilities/ragdoll-b-gone.py +++ b/plugins/utilities/ragdoll-b-gone.py @@ -8,6 +8,8 @@ Literally that's it. Heavily commented for easy modding learning! + + No Rights Reserved """ From 1884d9d6de27c07c77e9634c363e3c3bb45be8d4 Mon Sep 17 00:00:00 2001 From: TheMikirog Date: Sun, 13 Nov 2022 20:45:11 +0100 Subject: [PATCH 0256/1464] Update quickturn.py --- plugins/utilities/quickturn.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/plugins/utilities/quickturn.py b/plugins/utilities/quickturn.py index eff5fd5b..684ac1bd 100644 --- a/plugins/utilities/quickturn.py +++ b/plugins/utilities/quickturn.py @@ -6,6 +6,7 @@ Sharp turns while running (releasing run button, changing direction, holding run again) are much faster with this mod, allowing for more dynamic, aggressive play. Version 3 + No Rights Reserved """ # ba_meta require api 7 @@ -130,4 +131,4 @@ def wrapper(*args, **kwargs): Quickturn.wavedash(args[0]) func(*args, **kwargs) return wrapper - bastd.actor.spaz.Spaz.on_run = new_on_run(bastd.actor.spaz.Spaz.on_run) \ No newline at end of file + bastd.actor.spaz.Spaz.on_run = new_on_run(bastd.actor.spaz.Spaz.on_run) From fbf3e373bd1795734cb3af4b4ab7ac0def05013b Mon Sep 17 00:00:00 2001 From: TheMikirog Date: Sun, 13 Nov 2022 20:45:31 +0100 Subject: [PATCH 0257/1464] Update bomb_radius_visualizer.py --- plugins/utilities/bomb_radius_visualizer.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/plugins/utilities/bomb_radius_visualizer.py b/plugins/utilities/bomb_radius_visualizer.py index cc5beb54..e2c15299 100644 --- a/plugins/utilities/bomb_radius_visualizer.py +++ b/plugins/utilities/bomb_radius_visualizer.py @@ -5,6 +5,10 @@ With this cutting edge technology, you precisely know how close to the bomb you can tread. Supports modified blast radius values! + + Heavily commented for easy modding learning! + + No Rights Reserved """ from __future__ import annotations @@ -82,4 +86,4 @@ def wrapper(*args, **kwargs): # Finally we """travel through the game files""" to replace the function we want with our own version. # We transplant the old function's arguments into our version. bastd.actor.bomb.Bomb.__init__ = new_bomb_init(bastd.actor.bomb.Bomb.__init__) - \ No newline at end of file + From 973c3b514bf09d5b15b17715902ef75fc5cfc934 Mon Sep 17 00:00:00 2001 From: TheMikirog Date: Sun, 13 Nov 2022 20:48:26 +0100 Subject: [PATCH 0258/1464] Update minigames.json --- plugins/minigames.json | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/plugins/minigames.json b/plugins/minigames.json index 989ca69c..78e87192 100644 --- a/plugins/minigames.json +++ b/plugins/minigames.json @@ -116,6 +116,20 @@ "md5sum": "ceb7ac417c85396722fa9f7fee3cfc01" } } + } + "hot_potato": { + "description": "Pass the mark to someone else before you explode!, + "external_url": "", + "authors": [ + { + "name": "TheMikirog", + "email": "", + "discord": "TheMikirog#1984" + } + ], + "versions": { + "1.0.0": null + } } } -} \ No newline at end of file +} From 5fed0e124acb101ec18394b3defc98b702689a0b Mon Sep 17 00:00:00 2001 From: TheMikirog Date: Sun, 13 Nov 2022 20:51:30 +0100 Subject: [PATCH 0259/1464] Update utilities.json --- plugins/utilities.json | 44 +++++++++++++++++++++++++++++++++++++++++- 1 file changed, 43 insertions(+), 1 deletion(-) diff --git a/plugins/utilities.json b/plugins/utilities.json index 63413f65..66b285c1 100644 --- a/plugins/utilities.json +++ b/plugins/utilities.json @@ -296,6 +296,48 @@ "md5sum": "7da7fae6ddf2560789bbef56f4ff5bd6" } } + } + "quickturn": { + "description": "Sharp turns while running (releasing run button, changing direction, holding run again) are much faster with this mod, allowing for more dynamic, aggressive play.", + "external_url": "", + "authors": [ + { + "name": "TheMikirog", + "email": "", + "discord": "TheMikirog#1984" + } + ], + "versions": { + "3.0.0": null + } + } + "ragdoll_b_gone": { + "description": "Removes ragdolls. Thanos snaps those pesky feet-tripping body sacks out of existence.", + "external_url": "", + "authors": [ + { + "name": "TheMikirog", + "email": "", + "discord": "TheMikirog#1984" + } + ], + "versions": { + "1.0.0": null + } + } + "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!", + "external_url": "", + "authors": [ + { + "name": "TheMikirog", + "email": "", + "discord": "TheMikirog#1984" + } + ], + "versions": { + "1.0.0": null + } } } -} \ No newline at end of file +} From cd4f18d201c36abce46f0c0d137e8abbea24d2a0 Mon Sep 17 00:00:00 2001 From: TheMikirog Date: Sun, 13 Nov 2022 20:53:12 +0100 Subject: [PATCH 0260/1464] Update utilities.json --- plugins/utilities.json | 131 +---------------------------------------- 1 file changed, 3 insertions(+), 128 deletions(-) diff --git a/plugins/utilities.json b/plugins/utilities.json index 04535247..7a21c278 100644 --- a/plugins/utilities.json +++ b/plugins/utilities.json @@ -3,125 +3,6 @@ "description": "Utilities", "plugins_base_url": "http://github.com/bombsquad-community/plugin-manager/{content_type}/{tag}/plugins/utilities", "plugins": { - "share_replay": { - "description": "Export replays to mods folder and share them with friends or have a backup", - "external_url": "", - "authors": [ - { - "name": "LoupGarou", - "email": "LoupGarou5418@outlook.com", - "discord": "ʟօʊքɢǟʀօʊ#3063" - } - ], - "versions": { - "1.0.0": { - "api_version": 7, - "commit_sha": "2fda676", - "released_on": "07-11-2022", - "md5sum": "d475487c221d78c7f1278410d5ce229e" - } - } - }, - "custom_death": { - "description": "Characters turn to Bones after death", - "external_url": "https://youtube.com/c/JoseANG3LYT", - "authors": [ - { - "name": "JoseAng3l", - "email": "", - "discord": "! JoseANG3L#0268" - } - ], - "versions": { - "1.0.0": { - "api_version": 7, - "commit_sha": "2fda676", - "released_on": "07-11-2022", - "md5sum": "7b1941512532321eec18140087569215" - } - } - }, - "max_players": { - "description": "Increase the max player limit of 8 players", - "external_url": "https://youtube.com/c/JoseANG3LYT", - "authors": [ - { - "name": "JoseAng3l", - "email": "", - "discord": "! JoseANG3L#0268" - } - ], - "versions": { - "1.0.0": { - "api_version": 7, - "commit_sha": "2fda676", - "released_on": "07-11-2022", - "md5sum": "f5e129f009e9732b3179c7edaf75478e" - } - } - }, - "quick_custom_game": { - "description": "Quckly create a custom game with any gamemode", - "external_url": "https://youtube.com/c/JoseANG3LYT", - "authors": [ - { - "name": "JoseAng3l", - "email": "", - "discord": "! JoseANG3L#0268" - } - ], - "versions": { - "1.0.0": { - "api_version": 7, - "commit_sha": "2fda676", - "released_on": "07-11-2022", - "md5sum": "b691e35afb17cd3b5f6fe21c0194567d" - } - } - }, - "random_colors": { - "description": "Creates patches of random color after bomb explosions", - "external_url": "https://youtube.com/c/JoseANG3LYT", - "authors": [ - { - "name": "JoseAng3l", - "email": "", - "discord": "! JoseANG3L#0268" - } - ], - "versions": { - "1.0.0": { - "api_version": 7, - "commit_sha": "2fda676", - "released_on": "07-11-2022", - "md5sum": "0c351a0aebed77c3771053cde0c18d7b" - } - } - }, - "chat_cmd": { - "description": "chatcmd for a beutiful game - BombSquad OwO,type /help in chat for more info", - "external_url": "", - "authors": [ - { - "name": "IM_NOT_PRANAV#7874", - "email": "", - "discord": "IM_NOT_PRANAV#7874" - }, - { - "name": "FireFighter1037 ", - "email": "", - "discord": "" - } - ], - "versions": { - "1.0.0": { - "api_version": 7, - "commit_sha": "2fda676", - "released_on": "07-11-2022", - "md5sum": "c84d9a1c9e63e77949134020e1f11834" - } - } - }, "mood_light": { "description": "Dynamic lighting in co-op games (adjustable using \"ml\" chat command)", "external_url": "", @@ -133,12 +14,6 @@ } ], "versions": { - "1.2.1": { - "api_version": 7, - "commit_sha": "2fda676", - "released_on": "07-11-2022", - "md5sum": "ee8eede4a6c47535ab831abd0111aab0" - }, "1.2.0": { "api_version": 7, "commit_sha": "d838115", @@ -422,7 +297,7 @@ } } } - "quickturn": { + "quickturn": { "description": "Sharp turns while running (releasing run button, changing direction, holding run again) are much faster with this mod, allowing for more dynamic, aggressive play.", "external_url": "", "authors": [ @@ -436,7 +311,7 @@ "3.0.0": null } } - "ragdoll_b_gone": { + "ragdoll_b_gone": { "description": "Removes ragdolls. Thanos snaps those pesky feet-tripping body sacks out of existence.", "external_url": "", "authors": [ @@ -450,7 +325,7 @@ "1.0.0": null } } - "bomb_radius_visualizer": { + "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!", "external_url": "", "authors": [ From d4027a6d42a0be3e9cb875a9b8029722503b0b0a Mon Sep 17 00:00:00 2001 From: TheMikirog Date: Sun, 13 Nov 2022 20:53:49 +0100 Subject: [PATCH 0261/1464] Update minigames.json --- plugins/minigames.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/minigames.json b/plugins/minigames.json index b90a41ea..3749fb72 100644 --- a/plugins/minigames.json +++ b/plugins/minigames.json @@ -231,7 +231,7 @@ } } } - "hot_potato": { + "hot_potato": { "description": "Pass the mark to someone else before you explode!, "external_url": "", "authors": [ From 20b99396fad1cb833982b60f0f2338e1b8f0d016 Mon Sep 17 00:00:00 2001 From: TheMikirog Date: Sun, 13 Nov 2022 21:02:08 +0100 Subject: [PATCH 0262/1464] Update minigames.json From 02cb7871ee59dcc548da75579f08ebf3ad7ff8fa Mon Sep 17 00:00:00 2001 From: TheMikirog Date: Sun, 13 Nov 2022 21:03:41 +0100 Subject: [PATCH 0263/1464] Update utilities.json --- plugins/utilities.json | 125 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 125 insertions(+) diff --git a/plugins/utilities.json b/plugins/utilities.json index 7a21c278..1f054239 100644 --- a/plugins/utilities.json +++ b/plugins/utilities.json @@ -3,6 +3,125 @@ "description": "Utilities", "plugins_base_url": "http://github.com/bombsquad-community/plugin-manager/{content_type}/{tag}/plugins/utilities", "plugins": { + "share_replay": { + "description": "Export replays to mods folder and share them with friends or have a backup", + "external_url": "", + "authors": [ + { + "name": "LoupGarou", + "email": "LoupGarou5418@outlook.com", + "discord": "ʟօʊքɢǟʀօʊ#3063" + } + ], + "versions": { + "1.0.0": { + "api_version": 7, + "commit_sha": "2fda676", + "released_on": "07-11-2022", + "md5sum": "d475487c221d78c7f1278410d5ce229e" + } + } + }, + "custom_death": { + "description": "Characters turn to Bones after death", + "external_url": "https://youtube.com/c/JoseANG3LYT", + "authors": [ + { + "name": "JoseAng3l", + "email": "", + "discord": "! JoseANG3L#0268" + } + ], + "versions": { + "1.0.0": { + "api_version": 7, + "commit_sha": "2fda676", + "released_on": "07-11-2022", + "md5sum": "7b1941512532321eec18140087569215" + } + } + }, + "max_players": { + "description": "Increase the max player limit of 8 players", + "external_url": "https://youtube.com/c/JoseANG3LYT", + "authors": [ + { + "name": "JoseAng3l", + "email": "", + "discord": "! JoseANG3L#0268" + } + ], + "versions": { + "1.0.0": { + "api_version": 7, + "commit_sha": "2fda676", + "released_on": "07-11-2022", + "md5sum": "f5e129f009e9732b3179c7edaf75478e" + } + } + }, + "quick_custom_game": { + "description": "Quckly create a custom game with any gamemode", + "external_url": "https://youtube.com/c/JoseANG3LYT", + "authors": [ + { + "name": "JoseAng3l", + "email": "", + "discord": "! JoseANG3L#0268" + } + ], + "versions": { + "1.0.0": { + "api_version": 7, + "commit_sha": "2fda676", + "released_on": "07-11-2022", + "md5sum": "b691e35afb17cd3b5f6fe21c0194567d" + } + } + }, + "random_colors": { + "description": "Creates patches of random color after bomb explosions", + "external_url": "https://youtube.com/c/JoseANG3LYT", + "authors": [ + { + "name": "JoseAng3l", + "email": "", + "discord": "! JoseANG3L#0268" + } + ], + "versions": { + "1.0.0": { + "api_version": 7, + "commit_sha": "2fda676", + "released_on": "07-11-2022", + "md5sum": "0c351a0aebed77c3771053cde0c18d7b" + } + } + }, + "chat_cmd": { + "description": "chatcmd for a beutiful game - BombSquad OwO,type /help in chat for more info", + "external_url": "", + "authors": [ + { + "name": "IM_NOT_PRANAV#7874", + "email": "", + "discord": "IM_NOT_PRANAV#7874" + }, + { + "name": "FireFighter1037 ", + "email": "", + "discord": "" + } + ], + "versions": { + "1.0.0": { + "api_version": 7, + "commit_sha": "2fda676", + "released_on": "07-11-2022", + "md5sum": "c84d9a1c9e63e77949134020e1f11834" + } + } + }, "mood_light": { "description": "Dynamic lighting in co-op games (adjustable using \"ml\" chat command)", "external_url": "", @@ -14,6 +133,12 @@ } ], "versions": { + "1.2.1": { + "api_version": 7, + "commit_sha": "2fda676", + "released_on": "07-11-2022", + "md5sum": "ee8eede4a6c47535ab831abd0111aab0" + }, "1.2.0": { "api_version": 7, "commit_sha": "d838115", From 05d2f1a4f792c1353cfce25d74038338dec7d889 Mon Sep 17 00:00:00 2001 From: TheMikirog Date: Sun, 13 Nov 2022 20:06:02 +0000 Subject: [PATCH 0264/1464] [ci] auto-format --- plugins/minigames/hot_potato.py | 447 ++++++++++---------- plugins/utilities/bomb_radius_visualizer.py | 54 +-- plugins/utilities/quickturn.py | 84 ++-- plugins/utilities/ragdoll-b-gone.py | 51 ++- 4 files changed, 336 insertions(+), 300 deletions(-) diff --git a/plugins/minigames/hot_potato.py b/plugins/minigames/hot_potato.py index bb2376e8..d2615b46 100644 --- a/plugins/minigames/hot_potato.py +++ b/plugins/minigames/hot_potato.py @@ -32,24 +32,24 @@ if TYPE_CHECKING: pass - + # Let's define stun times for falling. # First element is stun for the first fall, second element is stun for the second fall and so on. # If we fall more than the amount of elements on this list, we'll use the last entry. -FALL_PENALTIES = [1.5, +FALL_PENALTIES = [1.5, 2.5, 3.5, - 5.0, - 6.0, - 7.0, - 8.0, + 5.0, + 6.0, + 7.0, + 8.0, 9.0, 10.0] - + RED_COLOR = (1.0, 0.2, 0.2) YELLOW_COLOR = (1.0, 1.0, 0.2) - - + + # The player in Hot Potato can be in one of these states: class PlayerState(Enum): # REGULAR - the state all players start in. @@ -70,6 +70,8 @@ class PlayerState(Enum): # To make the game easier to parse, I added Elimination style icons to the bottom of the screen. # Here's the behavior of each icon. + + class Icon(ba.Actor): """Creates in in-game icon on screen.""" @@ -85,7 +87,7 @@ def __init__(self, # Define the player this icon belongs to self._player = player self._name_scale = name_scale - + self._outline_tex = ba.gettexture('characterIconMask') # Character portrait @@ -153,7 +155,7 @@ def __init__(self, }) self.set_marked_icon(player.state) self.set_position_and_scale(position, scale) - + # Change our icon's appearance depending on the player state. def set_marked_icon(self, type: PlayerState) -> None: pos = self.node.position @@ -191,16 +193,16 @@ def set_marked_icon(self, type: PlayerState) -> None: self._marked_icon.position = (pos[0] - 2, pos[1] - 12) self._marked_text.text = 'You\'re Out!' self._marked_text.color = (0.5, 0.5, 0.5) - + # Animate text and icon animation_end_time = 1.5 if bool(self.activity.settings['Epic Mode']) else 3.0 - ba.animate(self._marked_icon,'opacity', { + ba.animate(self._marked_icon, 'opacity', { 0: 1.0, animation_end_time: 0.0}) - ba.animate(self._marked_text,'opacity', { + ba.animate(self._marked_text, 'opacity', { 0: 1.0, animation_end_time: 0.0}) - + self._name_text.opacity = 0.2 assert self.node self.node.color = (0.7, 0.3, 0.3) @@ -223,50 +225,52 @@ def set_position_and_scale(self, position: tuple[float, float], # This gamemode heavily relies on edited player behavior. # We need that amount of control, so we're gonna create our own class and use the original PlayerSpaz as our blueprint. + + class PotatoPlayerSpaz(PlayerSpaz): def __init__(self, *args, **kwargs): - super().__init__(*args, **kwargs) # unchanged Spaz __init__ code goes here - self.dropped_bombs = [] # we use this to track bombs thrown by the player - + super().__init__(*args, **kwargs) # unchanged Spaz __init__ code goes here + self.dropped_bombs = [] # we use this to track bombs thrown by the player + # Define a marked light self.marked_light = ba.newnode('light', - owner=self.node, - attrs={'position':self.node.position, - 'radius':0.15, - 'intensity':0.0, - 'height_attenuated':False, - 'color': (1.0, 0.0, 0.0)}) - + owner=self.node, + attrs={'position': self.node.position, + 'radius': 0.15, + 'intensity': 0.0, + 'height_attenuated': False, + 'color': (1.0, 0.0, 0.0)}) + # Pulsing red light when the player is Marked - ba.animate(self.marked_light,'radius',{ + ba.animate(self.marked_light, 'radius', { 0: 0.1, 0.3: 0.15, 0.6: 0.1}, - loop = True) - self.node.connectattr('position_center',self.marked_light,'position') - + loop=True) + self.node.connectattr('position_center', self.marked_light, 'position') + # Marked timer. It should be above our head, so we attach the text to the offset that's attached to the player. - self.marked_timer_offset = ba.newnode('math', owner = self.node, attrs = { + self.marked_timer_offset = ba.newnode('math', owner=self.node, attrs={ 'input1': (0, 1.2, 0), 'operation': 'add'}) self.node.connectattr('torso_position', self.marked_timer_offset, 'input2') - - self.marked_timer_text = ba.newnode('text', owner = self.node, attrs = { - 'text': '', - 'in_world': True, - 'shadow': 0.4, - 'color': (RED_COLOR[0], RED_COLOR[1], RED_COLOR[2], 0.0), - 'flatness': 0, - 'scale': 0.02, - 'h_align': 'center'}) + + self.marked_timer_text = ba.newnode('text', owner=self.node, attrs={ + 'text': '', + 'in_world': True, + 'shadow': 0.4, + 'color': (RED_COLOR[0], RED_COLOR[1], RED_COLOR[2], 0.0), + 'flatness': 0, + 'scale': 0.02, + 'h_align': 'center'}) self.marked_timer_offset.connectattr('output', self.marked_timer_text, 'position') - + # Modified behavior when dropping bombs def drop_bomb(self) -> stdbomb.Bomb | None: # The original function returns the Bomb the player created. - # This is super helpful for us, since all we need is to mark the bombs red + # This is super helpful for us, since all we need is to mark the bombs red # if they belong to the Marked player and nothing else. bomb = super().drop_bomb() # Let's make sure the player actually created a new bomb @@ -275,33 +279,33 @@ def drop_bomb(self) -> stdbomb.Bomb | None: self.dropped_bombs.append(bomb) # Bring a light bomb.bomb_marked_light = ba.newnode('light', - owner=bomb.node, - attrs={'position':bomb.node.position, - 'radius':0.04, - 'intensity':0.0, - 'height_attenuated':False, - 'color': (1.0, 0.0, 0.0)}) + owner=bomb.node, + attrs={'position': bomb.node.position, + 'radius': 0.04, + 'intensity': 0.0, + 'height_attenuated': False, + 'color': (1.0, 0.0, 0.0)}) # Attach the light to the bomb - bomb.node.connectattr('position',bomb.bomb_marked_light,'position') + bomb.node.connectattr('position', bomb.bomb_marked_light, 'position') # Let's adjust all lights for all bombs that we own. self.set_bombs_marked() # When the bomb physics node dies, call a function. bomb.node.add_death_action( ba.WeakCall(self.bomb_died, bomb)) - - + # Here's the function that gets called when one of the player's bombs dies. # We reference the player's dropped_bombs list and remove the bomb that died. + def bomb_died(self, bomb): self.dropped_bombs.remove(bomb) - + # Go through all the bombs this player has in the world. # Paint them red if the owner is marked, turn off the light otherwise. # We need this light to inform the player about bombs YOU DON'T want to get hit by. def set_bombs_marked(self): for bomb in self.dropped_bombs: bomb.bomb_marked_light.intensity = 20.0 if self._player.state == PlayerState.MARKED else 0.0 - + # Since our gamemode relies heavily on players passing the mark to other players # we need to have access to this message. This gets called when the player takes damage for any reason. def handlemessage(self, msg): @@ -312,12 +316,13 @@ def handlemessage(self, msg): # I'm still gonna comment all of it since we're here. if not self.node: return None - + # If the attacker is marked, pass that mark to us. self.activity.pass_mark(msg._source_player, self._player) - + # When stun timer runs out, we explode. Let's make sure our own explosion does throw us around. - if msg.hit_type == 'stun_blast' and msg._source_player == self.source_player: return True + if msg.hit_type == 'stun_blast' and msg._source_player == self.source_player: + return True # If the attacker is healthy and we're stunned, do a flash and play a sound, then ignore the rest of the code. if self.source_player.state == PlayerState.STUNNED and msg._source_player != PlayerState.MARKED: self.node.handlemessage('flash') @@ -325,7 +330,7 @@ def handlemessage(self, msg): 1.0, position=self.node.position) return True - + # Here's all the damage and force calculations unchanged from the source. mag = msg.magnitude * self.impact_scale velocity_mag = msg.velocity_magnitude * self.impact_scale @@ -341,8 +346,8 @@ def handlemessage(self, msg): velocity_mag, msg.radius, 0, msg.force_direction[0], msg.force_direction[1], msg.force_direction[2]) damage = int(damage_scale * self.node.damage) - self.node.handlemessage('hurt_sound') # That's how we play spaz node's hurt sound - + self.node.handlemessage('hurt_sound') # That's how we play spaz node's hurt sound + # Play punch impact sounds based on damage if it was a punch. # We don't show damage percentages, because it's irrelevant. if msg.hit_type == 'punch': @@ -411,7 +416,7 @@ def handlemessage(self, msg): count=min(10, 1 + int(damage * 0.01)), scale=0.4, spread=0.1) - + # Briefly flash when hit. # We shouldn't do this if we're dead. if self.hitpoints > 0: @@ -427,14 +432,14 @@ def handlemessage(self, msg): # Make sure our body exists. if not self.node: return None - + # Let's get all collision data if we can. Otherwise cancel. try: collision = ba.getcollision() opposingnode = collision.opposingnode except ba.NotFoundError: return True - + # Our grabber needs to be a Spaz if opposingnode.getnodetype() == 'spaz': # Disallow grabbing if a healthy player tries to grab us and we're stunned. @@ -449,32 +454,35 @@ def handlemessage(self, msg): # If they're marked and we're healthy or stunned, pass that mark along to us. elif opposingnode.source_player.state in [PlayerState.REGULAR, PlayerState.STUNNED] and self.source_player.state == PlayerState.MARKED: self.activity.pass_mark(self.source_player, opposingnode.source_player) - + # Our work is done. Continue with the rest of the grabbing behavior as usual. super().handlemessage(msg) # Dying is important in this gamemode and as such we need to address this behavior. elif isinstance(msg, ba.DieMessage): - + # If a player left the game, inform our gamemode logic. if msg.how == ba.DeathType.LEFT_GAME: self.activity.player_left(self.source_player) - + # If a MARKED or STUNNED player dies, hide the text from the previous spaz. if self.source_player.state in [PlayerState.MARKED, PlayerState.STUNNED]: self.marked_timer_text.color = (self.marked_timer_text.color[0], self.marked_timer_text.color[1], self.marked_timer_text.color[2], 0.0) - ba.animate(self.marked_light,'intensity',{ - 0: self.marked_light.intensity, - 0.5: 0.0}) - + ba.animate(self.marked_light, 'intensity', { + 0: self.marked_light.intensity, + 0.5: 0.0}) + # Continue with the rest of the behavior. super().handlemessage(msg) # If a message is something we haven't modified yet, let's pass it along to the original. - else: super().handlemessage(msg) - + else: + super().handlemessage(msg) + # A concept of a player is very useful to reference if we don't have a player character present (maybe they died). + + class Player(ba.Player['Team']): """Our player type for this game.""" @@ -487,61 +495,66 @@ def __init__(self) -> None: # These are references to timers responsible for handling stunned behavior. self.stunned_timer = None self.stunned_update_timer = None - + # If we're stunned, a timer calls this every 0.1 seconds. def stunned_timer_tick(self) -> None: - # Decrease our time remaining then change the text displayed above the Spaz's head + # Decrease our time remaining then change the text displayed above the Spaz's head self.stunned_time_remaining -= 0.1 self.stunned_time_remaining = max(0.0, self.stunned_time_remaining) self.actor.marked_timer_text.text = str(round(self.stunned_time_remaining, 2)) - + # When stun time is up, call this function. def stun_remove(self) -> None: # Let's proceed only if we're stunned - if self.state != PlayerState.STUNNED: return - # Do an explosion where we're standing. Normally it would throw us around, but we dealt + if self.state != PlayerState.STUNNED: + return + # Do an explosion where we're standing. Normally it would throw us around, but we dealt # with this issue in PlayerSpaz's edited HitMessage in line 312. Blast(position=self.actor.node.position, velocity=self.actor.node.velocity, blast_radius=2.5, - hit_type='stun_blast', # This hit type allows us to ignore our own stun blast explosions. + # This hit type allows us to ignore our own stun blast explosions. + hit_type='stun_blast', source_player=self).autoretain() # Let's switch our state back to healthy. self.set_state(PlayerState.REGULAR) - + # States are a key part of this gamemode and a lot of logic has to be done to acknowledge these state changes. def set_state(self, state: PlayerState) -> None: # Let's remember our old state before we change it. old_state = self.state - + # If we just became stunned, do all of this: if old_state != PlayerState.STUNNED and state == PlayerState.STUNNED: - self.actor.disconnect_controls_from_player() # Disallow all movement and actions + self.actor.disconnect_controls_from_player() # Disallow all movement and actions # Let's set our stun time based on the amount of times we fell out of the map. if self.fall_times < len(FALL_PENALTIES): stun_time = FALL_PENALTIES[self.fall_times] else: stun_time = FALL_PENALTIES[len(FALL_PENALTIES) - 1] - - self.stunned_time_remaining = stun_time # Set our stun time remaining - self.stunned_timer = ba.Timer(stun_time + 0.1, ba.Call(self.stun_remove)) # Remove our stun once the time is up - self.stunned_update_timer = ba.Timer(0.1, ba.Call(self.stunned_timer_tick), repeat = True) # Call a function every 0.1 seconds - self.fall_times += 1 # Increase the amount of times we fell by one - self.actor.marked_timer_text.text = str(stun_time) # Change the text above the Spaz's head to total stun time - + + self.stunned_time_remaining = stun_time # Set our stun time remaining + # Remove our stun once the time is up + self.stunned_timer = ba.Timer(stun_time + 0.1, ba.Call(self.stun_remove)) + self.stunned_update_timer = ba.Timer(0.1, ba.Call( + self.stunned_timer_tick), repeat=True) # Call a function every 0.1 seconds + self.fall_times += 1 # Increase the amount of times we fell by one + # Change the text above the Spaz's head to total stun time + self.actor.marked_timer_text.text = str(stun_time) + # If we were stunned, but now we're not, let's reconnect our controls. - # CODING CHALLENGE: to punch or bomb immediately after the stun ends, you need to + # CODING CHALLENGE: to punch or bomb immediately after the stun ends, you need to # time the button press frame-perfectly in order for it to work. # What if we could press the button shortly before stun ends to do the action as soon as possible? # If you're feeling up to the challenge, feel free to implement that! if old_state == PlayerState.STUNNED and state != PlayerState.STUNNED: self.actor.connect_controls_to_player() - + # When setting a state that is not STUNNED, clear all timers. if state != PlayerState.STUNNED: self.stunned_timer = None self.stunned_update_timer = None - + # Here's all the light and text colors that we set depending on the state. if state == PlayerState.MARKED: self.actor.marked_light.intensity = 1.5 @@ -560,11 +573,11 @@ def set_state(self, state: PlayerState) -> None: else: self.actor.marked_light.intensity = 0.0 self.actor.marked_timer_text.text = '' - + self.state = state - self.actor.set_bombs_marked() # Light our bombs red if we're Marked, removes the light otherwise - self.icon.set_marked_icon(state) # Update our icon - + self.actor.set_bombs_marked() # Light our bombs red if we're Marked, removes the light otherwise + self.icon.set_marked_icon(state) # Update our icon + # ba_meta export game class HotPotato(ba.TeamGameActivity[Player, ba.Team]): @@ -588,28 +601,28 @@ class HotPotato(ba.TeamGameActivity[Player, ba.Team]): 'Red bombs belong to the Marked player!\nWatch out for those!', 'Stunned players explode when their stun timer runs out.\nIf that time is close to zero, keep your distance!' ] - + # We're gonna distribute end of match session scores based on who dies first and who survives. # First place gets most points, then second, then third. scoreconfig = ba.ScoreConfig(label='Place', scoretype=ba.ScoreType.POINTS, lower_is_better=True) - + # These variables are self explanatory too. show_kill_points = False allow_mid_activity_joins = False - + # Let's define some settings the user can mess around with to fit their needs. available_settings = [ ba.IntSetting('Elimination Timer', - min_value=5, - default=15, - increment=1, - ), + min_value=5, + default=15, + increment=1, + ), ba.BoolSetting('Marked Players use Impact Bombs', default=False), ba.BoolSetting('Epic Mode', default=False), ] - + # Hot Potato is strictly a Free-For-All gamemode, so only picking the gamemode in FFA playlists. @classmethod def supports_session_type(cls, sessiontype: type[ba.Session]) -> bool: @@ -620,12 +633,12 @@ def supports_session_type(cls, sessiontype: type[ba.Session]) -> bool: @classmethod def get_supported_maps(cls, sessiontype: type[ba.Session]) -> list[str]: return ba.getmaps('melee') - + # Here we define everything the gamemode needs, like sounds and settings. def __init__(self, settings: dict): super().__init__(settings) self.settings = settings - + # Let's define all of the sounds we need. self._tick_sound = ba.getsound('tick') self._player_eliminated_sound = ba.getsound('playerDeath') @@ -637,13 +650,13 @@ def __init__(self, settings: dict): self._marked_sounds = [ba.getsound('powerdown01'), ba.getsound('activateBeep'), ba.getsound('hiss')] - + # Normally play KOTH music, but switch to Epic music if we're in slow motion. self._epic_mode = bool(settings['Epic Mode']) self.slow_motion = self._epic_mode self.default_music = (ba.MusicType.EPIC if self._epic_mode else ba.MusicType.SCARY) - + # This description appears below the title card after it comes crashing when the game begins. def get_instance_description(self) -> str | Sequence: return 'Pass the mark to someone else before you explode!' @@ -651,11 +664,11 @@ def get_instance_description(self) -> str | Sequence: # This is the tiny text that is displayed in the corner during the game as a quick reminder of the objective. def get_instance_description_short(self) -> str | Sequence: return 'pass the mark' - + # Set up our player every time they join. # Because you can't join mid-match, this will always be called at the beginning of the game. def on_player_join(self, player: Player) -> None: - + player.state = PlayerState.REGULAR player.fall_times = 0 @@ -663,7 +676,7 @@ def on_player_join(self, player: Player) -> None: if not self.has_begun(): player.icon = Icon(player, position=(0, 50), scale=0.8) self.spawn_player(player) - + # Returns every single marked player. # This piece of info is used excensively in this gamemode, so it's advantageous to have a function to cut on # work and make the gamemode easier to maintain @@ -673,76 +686,77 @@ def get_marked_players(self) -> Sequence[ba.Player]: if p.state == PlayerState.MARKED: marked_players.append(p) return marked_players - + # Marks a player. This sets their state, spawns some particles and sets the timer text above their heads. def mark(self, target: Player) -> None: target.set_state(PlayerState.MARKED) - + ba.emitfx(position=target.actor.node.position, velocity=target.actor.node.velocity, chunk_type='spark', count=int(20.0+random.random()*20), scale=1.0, - spread=1.0); + spread=1.0) if bool(self.settings['Marked Players use Impact Bombs']): target.actor.bomb_type = 'impact' target.actor.marked_timer_text.text = str(self.elimination_timer_display) - + # Removes the mark from the player. This restores the player to its initial state. def remove_mark(self, target: Player) -> None: - if target.state != PlayerState.MARKED: + if target.state != PlayerState.MARKED: return - + target.actor.bomb_type = 'normal' - + target.set_state(PlayerState.REGULAR) target.actor.marked_timer_text.text = '' - + # Pass the mark from one player to another. # This is more desirable than calling mark and remove_mark functions constantly and gives us # more control over the mark spreading mechanic. def pass_mark(self, marked_player: Player, hit_player: Player) -> None: # Make sure both players meet the requirements - if not marked_player or not hit_player: return + if not marked_player or not hit_player: + return if marked_player.state == PlayerState.MARKED and hit_player.state != PlayerState.MARKED: self.mark(hit_player) self.remove_mark(marked_player) - + # This function is called every second a marked player exists. def _eliminate_tick(self) -> None: marked_players = self.get_marked_players() marked_player_amount = len(marked_players) - + # If there is no marked players, raise an exception. # This is used for debugging purposes, which lets us know we messed up somewhere else in the code. if len(self.get_marked_players()) == 0: raise Exception("no marked players!") - - self.elimination_timer_display -= 1 # Decrease our timer by one second. + + self.elimination_timer_display -= 1 # Decrease our timer by one second. if self.elimination_timer_display > 1: sound_volume = 1.0 / marked_player_amount - + for target in marked_players: ba.playsound(self._tick_sound, sound_volume, target.actor.node.position) target.actor.marked_timer_text.text = str(self.elimination_timer_display) - + # When counting down 3, 2, 1 play some dramatic sounds if self.elimination_timer_display <= 3: # We store our dramatic sounds in an array, so we target a specific element on the array - # depending on time remaining. Arrays start at index 0, so we need to decrease + # depending on time remaining. Arrays start at index 0, so we need to decrease # our variable by 1 to get the element index. ba.playsound(self._danger_tick_sounds[self.elimination_timer_display - 1], 1.5) else: # Elimination timer is up! Let's eliminate all marked players. self._eliminate_marked_players() - + # This function explodes all marked players def _eliminate_marked_players(self) -> None: self.marked_tick_timer = None for target in self.get_marked_players(): target.set_state(PlayerState.ELIMINATED) target.actor.marked_timer_text.text = '' - + Blast(position=target.actor.node.position, velocity=target.actor.node.velocity, blast_radius=3.0, @@ -755,48 +769,50 @@ def _eliminate_marked_players(self) -> None: chunk_type='spark') target.actor.handlemessage(ba.DieMessage(how='marked_elimination')) target.actor.shatter(extreme=True) - + self.match_placement.append(target.team) - + ba.playsound(self._player_eliminated_sound, 1.0) - - # Let the gamemode know a Marked + + # Let the gamemode know a Marked self.marked_players_died() - + # This function should be called when a Marked player dies, like when timer runs out or they leave the game. def marked_players_died(self) -> bool: alive_players = self.get_alive_players() # Is there only one player remaining? Or none at all? Let's end the gamemode if len(alive_players) < 2: if len(alive_players) == 1: - self.match_placement.append(alive_players[0].team) # Let's add our lone survivor to the match placement list. + # Let's add our lone survivor to the match placement list. + self.match_placement.append(alive_players[0].team) # Wait a while to let this sink in before we announce our victor. self._end_game_timer = ba.Timer(1.25, ba.Call(self.end_game)) else: # There's still players remaining, so let's wait a while before marking a new player. self.new_mark_timer = ba.Timer(2.0 if self.slow_motion else 4.0, ba.Call(self.new_mark)) - + # Another extensively used function that returns all alive players. def get_alive_players(self) -> Sequence[ba.Player]: alive_players = [] for player in self.players: - if player.state == PlayerState.ELIMINATED: continue # Ignore players who have been eliminated + if player.state == PlayerState.ELIMINATED: + continue # Ignore players who have been eliminated if player.is_alive(): alive_players.append(player) return alive_players - + # This function is called every time we want to start a new "round" by marking a random player. def new_mark(self) -> None: - + # Don't mark a new player if we've already announced a victor. if self.has_ended(): return - + possible_targets = self.get_alive_players() all_victims = [] # Let's mark TWO players at once if there's 6 or more players. Helps with the pacing. multi_choice = len(possible_targets) > 5 - + if multi_choice: # Pick our first victim at random. first_victim = random.choice(possible_targets) @@ -807,9 +823,11 @@ def new_mark(self) -> None: else: # Pick one victim at random. all_victims = [random.choice(possible_targets)] - - self.elimination_timer_display = self.settings['Elimination Timer'] # Set time until marked players explode - self.marked_tick_timer = ba.Timer(1.0, ba.Call(self._eliminate_tick), repeat=True) # Set a timer that calls _eliminate_tick every second + + # Set time until marked players explode + self.elimination_timer_display = self.settings['Elimination Timer'] + # Set a timer that calls _eliminate_tick every second + self.marked_tick_timer = ba.Timer(1.0, ba.Call(self._eliminate_tick), repeat=True) # Mark all chosen victims and play a sound for new_victim in all_victims: # _marked_sounds is an array. @@ -818,14 +836,14 @@ def new_mark(self) -> None: for sound in self._marked_sounds: ba.playsound(sound, 1.0, new_victim.actor.node.position) self.mark(new_victim) - + # This function is called when the gamemode first loads. def on_begin(self) -> None: - super().on_begin() # Do standard gamemode on_begin behavior - + super().on_begin() # Do standard gamemode on_begin behavior + self.elimination_timer_display = 0 self.match_placement = [] - + # End the game if there's only one player if len(self.players) < 2: self.match_placement.append(self.players[0].team) @@ -833,9 +851,9 @@ def on_begin(self) -> None: else: # Pick random player(s) to get marked self.new_mark_timer = ba.Timer(2.0 if self.slow_motion else 5.2, ba.Call(self.new_mark)) - - self._update_icons() # Create player state icons - + + self._update_icons() # Create player state icons + # This function creates and positions player state icons def _update_icons(self): count = len(self.teams) @@ -847,12 +865,12 @@ def _update_icons(self): player = team.players[0] player.icon.set_position_and_scale((xval, 50), 0.8) xval += x_offs - + # Hot Potato can be a bit much, so I opted to show gameplay tips at the start of the match. # However because I put player state icons, the tips overlay the icons. # I'm gonna modify this function to move the tip text above the icons. def _show_tip(self) -> None: - + from ba._gameutils import animate, GameTip from ba._generated.enums import SpecialChar from ba._language import Lstr @@ -882,61 +900,61 @@ def _show_tip(self) -> None: t_offs = -350.0 height_offs = 100.0 tnode = ba.newnode('text', + attrs={ + 'text': tip_lstr, + 'scale': tip_scale, + 'maxwidth': 900, + 'position': (base_position[0] + t_offs, + base_position[1] + height_offs), + 'h_align': 'left', + 'vr_depth': 300, + 'shadow': 1.0 if vrmode else 0.5, + 'flatness': 1.0 if vrmode else 0.5, + 'v_align': 'center', + 'v_attach': 'bottom' + }) + t2pos = (base_position[0] + t_offs - (20 if icon is None else 82), + base_position[1] + 2 + height_offs) + t2node = ba.newnode('text', + owner=tnode, attrs={ - 'text': tip_lstr, - 'scale': tip_scale, - 'maxwidth': 900, - 'position': (base_position[0] + t_offs, - base_position[1] + height_offs), - 'h_align': 'left', + 'text': tip_title, + 'scale': tip_title_scale, + 'position': t2pos, + 'h_align': 'right', 'vr_depth': 300, 'shadow': 1.0 if vrmode else 0.5, 'flatness': 1.0 if vrmode else 0.5, + 'maxwidth': 140, 'v_align': 'center', 'v_attach': 'bottom' }) - t2pos = (base_position[0] + t_offs - (20 if icon is None else 82), - base_position[1] + 2 + height_offs) - t2node = ba.newnode('text', - owner=tnode, - attrs={ - 'text': tip_title, - 'scale': tip_title_scale, - 'position': t2pos, - 'h_align': 'right', - 'vr_depth': 300, - 'shadow': 1.0 if vrmode else 0.5, - 'flatness': 1.0 if vrmode else 0.5, - 'maxwidth': 140, - 'v_align': 'center', - 'v_attach': 'bottom' - }) if icon is not None: ipos = (base_position[0] + t_offs - 40, base_position[1] + 1 + height_offs) img = ba.newnode('image', - attrs={ - 'texture': icon, - 'position': ipos, - 'scale': (50, 50), - 'opacity': 1.0, - 'vr_depth': 315, - 'color': (1, 1, 1), - 'absolute_scale': True, - 'attach': 'bottomCenter' - }) + attrs={ + 'texture': icon, + 'position': ipos, + 'scale': (50, 50), + 'opacity': 1.0, + 'vr_depth': 315, + 'color': (1, 1, 1), + 'absolute_scale': True, + 'attach': 'bottomCenter' + }) animate(img, 'opacity', {0: 0, 1.0: 1, 4.0: 1, 5.0: 0}) ba.timer(5.0, img.delete) if sound is not None: ba.playsound(sound) combine = ba.newnode('combine', - owner=tnode, - attrs={ - 'input0': 1.0, - 'input1': 0.8, - 'input2': 1.0, - 'size': 4 - }) + owner=tnode, + attrs={ + 'input0': 1.0, + 'input1': 0.8, + 'input2': 1.0, + 'size': 4 + }) combine.connectattr('output', tnode, 'color') combine.connectattr('output', t2node, 'color') animate(combine, 'input3', {0: 0, 1.0: 1, 4.0: 1, 5.0: 0}) @@ -948,78 +966,79 @@ def player_left(self, player: Player) -> None: # If the leaving player is marked, remove the mark if player.state == PlayerState.MARKED: self.remove_mark(player) - + # If the leaving player is stunned, remove all stun timers elif player.state == PlayerState.STUNNED: player.stunned_timer = None player.stunned_update_timer = None - + if len(self.get_marked_players()) == len(self.get_alive_players()): for i in self.get_marked_players(): self.remove_mark(i) - + if len(self.get_marked_players()) == 0: self.marked_tick_timer = None self.marked_players_died() - + player.set_state(PlayerState.ELIMINATED) - + # This function is called every time a player spawns def spawn_player(self, player: Player) -> ba.Actor: position = self.map.get_ffa_start_position(self.players) position = (position[0], - position[1] - 0.3, # Move the spawn a bit lower + position[1] - 0.3, # Move the spawn a bit lower position[2]) - + name = player.getname() - + light_color = ba.normalized_color(player.color) display_color = ba.safecolor(player.color, target_intensity=0.75) - + # Here we actually crate the player character spaz = PotatoPlayerSpaz(color=player.color, highlight=player.highlight, character=player.character, player=player) - spaz.node.invincible = False # Immediately turn off invincibility - player.actor = spaz # Assign player character to the owner - + spaz.node.invincible = False # Immediately turn off invincibility + player.actor = spaz # Assign player character to the owner + spaz.node.name = name spaz.node.name_color = display_color spaz.connect_controls_to_player() - + # Move to the stand position and add a flash of light spaz.handlemessage(ba.StandMessage(position, random.uniform(0, 360))) t = ba.time(ba.TimeType.BASE) ba.playsound(self._spawn_sound, 1.0, position=spaz.node.position) light = ba.newnode('light', attrs={'color': light_color}) spaz.node.connectattr('position', light, 'position') - ba.animate(light, 'intensity', {0: 0, - 0.25: 1, + ba.animate(light, 'intensity', {0: 0, + 0.25: 1, 0.5: 0}) ba.timer(0.5, light.delete) - + # Game reacts to various events def handlemessage(self, msg: Any) -> Any: # This is called if the player dies. if isinstance(msg, ba.PlayerDiedMessage): - super().handlemessage(msg) # + super().handlemessage(msg) player = msg.getplayer(Player) - + # If a player gets eliminated, don't respawn - if msg.how == 'marked_elimination': return - - self.spawn_player(player) # Spawn a new player character - + if msg.how == 'marked_elimination': + return + + self.spawn_player(player) # Spawn a new player character + # If a REGULAR player dies, they respawn STUNNED. # If a STUNNED player dies, reapply all visual effects. if player.state in [PlayerState.REGULAR, PlayerState.STUNNED]: player.set_state(PlayerState.STUNNED) - + # If a MARKED player falls off the map, apply the MARKED effects on the new spaz that respawns. if player.state == PlayerState.MARKED: self.mark(player) - + # This is called when we want to end the game and announce a victor def end_game(self) -> None: # Proceed only if the game hasn't ended yet. @@ -1035,4 +1054,4 @@ def end_game(self) -> None: # Use each player's index in the array for our scoring # 0 is the first index, so we add 1 to the score. results.set_team_score(team, self.match_placement.index(team) + 1) - self.end(results=results) # Standard game ending behavior + self.end(results=results) # Standard game ending behavior diff --git a/plugins/utilities/bomb_radius_visualizer.py b/plugins/utilities/bomb_radius_visualizer.py index e2c15299..994ccef4 100644 --- a/plugins/utilities/bomb_radius_visualizer.py +++ b/plugins/utilities/bomb_radius_visualizer.py @@ -22,38 +22,41 @@ if TYPE_CHECKING: pass - + # ba_meta export plugin + + class BombRadiusVisualizer(ba.Plugin): - + # We use a decorator to add extra code to existing code, increasing mod compatibility. # Here I'm defining a new bomb init function that'll be replaced. def new_bomb_init(func): # This function will return our wrapper function, which is going to take the original function's base arguments. # Yes, in Python functions are objects that can be passed as arguments. It's bonkers. # arg[0] is "self" in our original bomb init function. - # We're working kind of blindly here, so it's good to have the original function + # We're working kind of blindly here, so it's good to have the original function # open in a second window for argument reference. 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) - + # Let's make a new node that's just a circle. It's the some one used in the Target Practice minigame. # This is going to make a slightly opaque red circle, signifying damaging area. # We aren't defining the size, because we're gonna animate it shortly after. args[0].radius_visualizer = ba.newnode('locator', - owner=args[0].node, # Remove itself when the bomb node dies. - attrs={ - 'shape': 'circle', - 'color': (1, 0, 0), - 'opacity':0.05, - 'draw_beauty': False, - 'additive': False - }) + # Remove itself when the bomb node dies. + owner=args[0].node, + attrs={ + 'shape': 'circle', + 'color': (1, 0, 0), + 'opacity': 0.05, + 'draw_beauty': False, + 'additive': False + }) # Let's connect our circle to the bomb. args[0].node.connectattr('position', args[0].radius_visualizer, 'position') - + # Let's do a fancy animation of that red circle growing into shape like a cartoon. # We're gonna read our bomb's blast radius and use it to decide the size of our circle. ba.animate_array(args[0].radius_visualizer, 'size', 1, { @@ -61,20 +64,22 @@ def wrapper(*args, **kwargs): 0.2: [args[0].blast_radius * 2.2], 0.25: [args[0].blast_radius * 2.0] }) - + # Let's do a second circle, this time just the outline to where the damaging area ends. args[0].radius_visualizer_circle = ba.newnode('locator', - owner=args[0].node, # Remove itself when the bomb node dies. - attrs={ - 'shape': 'circleOutline', - 'size':[args[0].blast_radius * 2.0], # Here's that bomb's blast radius value again! - 'color': (1, 1, 0), - 'draw_beauty': False, - 'additive': True - }) + # Remove itself when the bomb node dies. + owner=args[0].node, + attrs={ + 'shape': 'circleOutline', + # Here's that bomb's blast radius value again! + 'size': [args[0].blast_radius * 2.0], + 'color': (1, 1, 0), + 'draw_beauty': False, + 'additive': True + }) # Attach the circle to the bomb. args[0].node.connectattr('position', args[0].radius_visualizer_circle, 'position') - + # Let's animate that circle too, but this time let's do the opacity. ba.animate( args[0].radius_visualizer_circle, 'opacity', { @@ -82,8 +87,7 @@ def wrapper(*args, **kwargs): 0.4: 0.1 }) return wrapper - + # Finally we """travel through the game files""" to replace the function we want with our own version. # We transplant the old function's arguments into our version. bastd.actor.bomb.Bomb.__init__ = new_bomb_init(bastd.actor.bomb.Bomb.__init__) - diff --git a/plugins/utilities/quickturn.py b/plugins/utilities/quickturn.py index 684ac1bd..976c905f 100644 --- a/plugins/utilities/quickturn.py +++ b/plugins/utilities/quickturn.py @@ -24,107 +24,113 @@ pass # ba_meta export plugin + + class Quickturn(ba.Plugin): class FootConnectMessage: """Spaz started touching the ground""" - + class FootDisconnectMessage: """Spaz stopped touching the ground""" - + def wavedash(self) -> None: if not self.node: return isMoving = abs(self.node.move_up_down) >= 0.5 or abs(self.node.move_left_right) >= 0.5 - + if self._dead or not self.grounded or not isMoving: return - + if self.node.knockout > 0.0 or self.frozen or self.node.hold_node: return - + t_ms = ba.time(timeformat=ba.TimeFormat.MILLISECONDS) assert isinstance(t_ms, int) - + if t_ms - self.last_wavedash_time_ms >= self._wavedash_cooldown: - + move = [self.node.move_left_right, -self.node.move_up_down] vel = [self.node.velocity[0], self.node.velocity[2]] - + move_length = math.hypot(move[0], move[1]) vel_length = math.hypot(vel[0], vel[1]) - if vel_length < 0.6: return + if vel_length < 0.6: + return move_norm = [m/move_length for m in move] vel_norm = [v/vel_length for v in vel] - dot = sum(x*y for x,y in zip(move_norm,vel_norm)) - turn_power = min(round(math.acos(dot) / math.pi,2)*1.3,1) - - + dot = sum(x*y for x, y in zip(move_norm, vel_norm)) + turn_power = min(round(math.acos(dot) / math.pi, 2)*1.3, 1) + # https://easings.net/#easeInOutQuart if turn_power < 0.55: turn_power = 8 * turn_power * turn_power * turn_power * turn_power else: turn_power = 0.55 - pow(-2 * turn_power + 2, 4) / 2 - if turn_power < 0.1: return - - boost_power = math.sqrt(math.pow(vel[0],2) + math.pow(vel[1],2)) * 8 - boost_power = min(pow(boost_power,8),160) - + if turn_power < 0.1: + return + + boost_power = math.sqrt(math.pow(vel[0], 2) + math.pow(vel[1], 2)) * 8 + boost_power = min(pow(boost_power, 8), 160) + self.last_wavedash_time_ms = t_ms - + # FX ba.emitfx(position=self.node.position, - velocity=(vel[0]*0.5,-1,vel[1]*0.5), + velocity=(vel[0]*0.5, -1, vel[1]*0.5), chunk_type='spark', count=5, scale=boost_power / 160 * turn_power, - spread=0.25); - + spread=0.25) + # Boost itself pos = self.node.position for i in range(6): - self.node.handlemessage('impulse',pos[0],0.2+pos[1]+i*0.1,pos[2], - 0,0,0, - boost_power * turn_power, - boost_power * turn_power,0,0, - move[0],0,move[1]) - + self.node.handlemessage('impulse', pos[0], 0.2+pos[1]+i*0.1, pos[2], + 0, 0, 0, + boost_power * turn_power, + boost_power * turn_power, 0, 0, + move[0], 0, move[1]) + def new_spaz_init(func): def wrapper(*args, **kwargs): func(*args, **kwargs) - + # args[0] = self args[0]._wavedash_cooldown = 170 args[0].last_wavedash_time_ms = -9999 args[0].grounded = 0 - + return wrapper bastd.actor.spaz.Spaz.__init__ = new_spaz_init(bastd.actor.spaz.Spaz.__init__) - + def new_factory(func): def wrapper(*args, **kwargs): func(*args, **kwargs) args[0].roller_material.add_actions( - conditions=('they_have_material', bastd.gameutils.SharedObjects.get().footing_material), - actions=(('message', 'our_node', 'at_connect', Quickturn.FootConnectMessage), - ('message', 'our_node', 'at_disconnect', Quickturn.FootDisconnectMessage))) + conditions=('they_have_material', + bastd.gameutils.SharedObjects.get().footing_material), + actions=(('message', 'our_node', 'at_connect', Quickturn.FootConnectMessage), + ('message', 'our_node', 'at_disconnect', Quickturn.FootDisconnectMessage))) return wrapper - bastd.actor.spazfactory.SpazFactory.__init__ = new_factory(bastd.actor.spazfactory.SpazFactory.__init__) - + bastd.actor.spazfactory.SpazFactory.__init__ = new_factory( + bastd.actor.spazfactory.SpazFactory.__init__) + def new_handlemessage(func): def wrapper(*args, **kwargs): if args[1] == Quickturn.FootConnectMessage: args[0].grounded += 1 elif args[1] == Quickturn.FootDisconnectMessage: - if args[0].grounded > 0: args[0].grounded -= 1 - + if args[0].grounded > 0: + args[0].grounded -= 1 + func(*args, **kwargs) return wrapper bastd.actor.spaz.Spaz.handlemessage = new_handlemessage(bastd.actor.spaz.Spaz.handlemessage) - + def new_on_run(func): def wrapper(*args, **kwargs): if args[0]._last_run_value < args[1] and args[1] > 0.8: diff --git a/plugins/utilities/ragdoll-b-gone.py b/plugins/utilities/ragdoll-b-gone.py index f496d626..7b8190db 100644 --- a/plugins/utilities/ragdoll-b-gone.py +++ b/plugins/utilities/ragdoll-b-gone.py @@ -28,6 +28,8 @@ pass # ba_meta export plugin + + class RagdollBGone(ba.Plugin): # We use a decorator to add extra code to existing code, increasing mod compatibility. @@ -37,23 +39,23 @@ def new_handlemessage(func): # This function will return our wrapper function, which is going to take the original function's base arguments. # Yes, in Python functions are objects that can be passed as arguments. It's bonkers. # arg[0] is "self", args[1] is "msg" in our original handlemessage function. - # We're working kind of blindly here, so it's good to have the original function + # We're working kind of blindly here, so it's good to have the original function # open in a second window for argument reference. def wrapper(*args, **kwargs): - if isinstance(args[1], ba.DieMessage): # Replace Spaz death behavior - + if isinstance(args[1], ba.DieMessage): # Replace Spaz death behavior + # Here we play the gamey death noise in Co-op. if not args[1].immediate: if args[0].play_big_death_sound and not args[0]._dead: ba.playsound(SpazFactory.get().single_player_death_sound) - + # If our Spaz dies by falling out of the map, we want to keep the ragdoll. # Ragdolls don't impact gameplay if Spaz dies this way, so it's fine if we leave the behavior as is. - if args[1].how == ba.DeathType.FALL: - # The next two properties are all built-in, so their behavior can't be edited directly without touching the C++ layer. - # We can change their values though! - # "hurt" property is basically the health bar above the player and the blinking when low on health. - # 1.0 means empty health bar and the fastest blinking in the west. + if args[1].how == ba.DeathType.FALL: + # The next two properties are all built-in, so their behavior can't be edited directly without touching the C++ layer. + # We can change their values though! + # "hurt" property is basically the health bar above the player and the blinking when low on health. + # 1.0 means empty health bar and the fastest blinking in the west. args[0].node.hurt = 1.0 # Make our Spaz close their eyes permanently and then make their body disintegrate. # Again, this behavior is built in. We can only trigger it by setting "dead" to True. @@ -78,29 +80,34 @@ def wrapper(*args, **kwargs): args[0].node.position[2]) # This function allows us to spawn particles like sparks and bomb shrapnel. # We're gonna use sparks here. - ba.emitfx(position = pos, # Here we place our edited position. - velocity=args[0].node.velocity, - count=random.randrange(2, 5), # Random amount of sparks between 2 and 5 - scale=3.0, - spread=0.2, - chunk_type='spark') - + ba.emitfx(position=pos, # Here we place our edited position. + velocity=args[0].node.velocity, + # Random amount of sparks between 2 and 5 + count=random.randrange(2, 5), + scale=3.0, + spread=0.2, + chunk_type='spark') + # Make a Spaz death noise if we're not gibbed. if not args[0].shattered: - death_sounds = args[0].node.death_sounds # Get our Spaz's death noises, these change depending on character skins - sound = death_sounds[random.randrange(len(death_sounds))] # Pick a random death noise - ba.playsound(sound, position=args[0].node.position) # Play the sound where our Spaz is + # Get our Spaz's death noises, these change depending on character skins + death_sounds = args[0].node.death_sounds + # Pick a random death noise + sound = death_sounds[random.randrange(len(death_sounds))] + # Play the sound where our Spaz is + ba.playsound(sound, position=args[0].node.position) # Delete our Spaz node immediately. # Removing stuff is weird and prone to errors, so we're gonna delay it. ba.timer(0.001, args[0].node.delete) - + # Let's mark our Spaz as dead, so he can't die again. # Notice how we're targeting the Spaz and not it's node. # "self.node" is a visual representation of the character while "self" is his game logic. args[0]._dead = True - args[0].hitpoints = 0 # Set his health to zero. This value is independent from the health bar above his head. + # Set his health to zero. This value is independent from the health bar above his head. + args[0].hitpoints = 0 return - + # Worry no longer! We're not gonna remove all the base game code! # Here's where we bring it all back. # If I wanted to add extra code at the end of the base game's behavior, I would just put that at the beginning of my function. From 7fbf551a29c3e87aad5a1cf285e52ccadaea02b8 Mon Sep 17 00:00:00 2001 From: TheMikirog Date: Sun, 13 Nov 2022 22:37:42 +0100 Subject: [PATCH 0265/1464] Fixed nasty Hot Potato bug --- plugins/minigames/hot_potato.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/plugins/minigames/hot_potato.py b/plugins/minigames/hot_potato.py index d2615b46..cc309e09 100644 --- a/plugins/minigames/hot_potato.py +++ b/plugins/minigames/hot_potato.py @@ -734,6 +734,7 @@ def _eliminate_tick(self) -> None: self.elimination_timer_display -= 1 # Decrease our timer by one second. if self.elimination_timer_display > 1: + self.elimination_timer_display -= 1 # Decrease our timer by one second. sound_volume = 1.0 / marked_player_amount for target in marked_players: @@ -748,6 +749,7 @@ def _eliminate_tick(self) -> None: ba.playsound(self._danger_tick_sounds[self.elimination_timer_display - 1], 1.5) else: # Elimination timer is up! Let's eliminate all marked players. + self.elimination_timer_display -= 1 # Decrease our timer by one second. self._eliminate_marked_players() # This function explodes all marked players From b6e28849abd0855599ddbd759cb8af18a0425213 Mon Sep 17 00:00:00 2001 From: TheMikirog Date: Sun, 13 Nov 2022 21:38:17 +0000 Subject: [PATCH 0266/1464] [ci] auto-format --- plugins/minigames/hot_potato.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/plugins/minigames/hot_potato.py b/plugins/minigames/hot_potato.py index cc309e09..2eed1dc8 100644 --- a/plugins/minigames/hot_potato.py +++ b/plugins/minigames/hot_potato.py @@ -734,7 +734,7 @@ def _eliminate_tick(self) -> None: self.elimination_timer_display -= 1 # Decrease our timer by one second. if self.elimination_timer_display > 1: - self.elimination_timer_display -= 1 # Decrease our timer by one second. + self.elimination_timer_display -= 1 # Decrease our timer by one second. sound_volume = 1.0 / marked_player_amount for target in marked_players: @@ -749,7 +749,7 @@ def _eliminate_tick(self) -> None: ba.playsound(self._danger_tick_sounds[self.elimination_timer_display - 1], 1.5) else: # Elimination timer is up! Let's eliminate all marked players. - self.elimination_timer_display -= 1 # Decrease our timer by one second. + self.elimination_timer_display -= 1 # Decrease our timer by one second. self._eliminate_marked_players() # This function explodes all marked players From 0841b9e9f6f6b07d742cd2de30fb54e0d3564a1e Mon Sep 17 00:00:00 2001 From: Rikko Date: Mon, 14 Nov 2022 06:18:03 -0800 Subject: [PATCH 0267/1464] Correct metadata typos --- plugins/minigames.json | 4 ++-- plugins/utilities.json | 6 +++--- plugins/utilities/{ragdoll-b-gone.py => ragdoll_b_gone.py} | 0 3 files changed, 5 insertions(+), 5 deletions(-) rename plugins/utilities/{ragdoll-b-gone.py => ragdoll_b_gone.py} (100%) diff --git a/plugins/minigames.json b/plugins/minigames.json index 3749fb72..b2be088f 100644 --- a/plugins/minigames.json +++ b/plugins/minigames.json @@ -230,9 +230,9 @@ "md5sum": "c84b7f415de5d3e9189ee73fc0e3ce93" } } - } + }, "hot_potato": { - "description": "Pass the mark to someone else before you explode!, + "description": "Pass the mark to someone else before you explode!", "external_url": "", "authors": [ { diff --git a/plugins/utilities.json b/plugins/utilities.json index 1f054239..d0275877 100644 --- a/plugins/utilities.json +++ b/plugins/utilities.json @@ -421,7 +421,7 @@ "md5sum": "7da7fae6ddf2560789bbef56f4ff5bd6" } } - } + }, "quickturn": { "description": "Sharp turns while running (releasing run button, changing direction, holding run again) are much faster with this mod, allowing for more dynamic, aggressive play.", "external_url": "", @@ -435,7 +435,7 @@ "versions": { "3.0.0": null } - } + }, "ragdoll_b_gone": { "description": "Removes ragdolls. Thanos snaps those pesky feet-tripping body sacks out of existence.", "external_url": "", @@ -449,7 +449,7 @@ "versions": { "1.0.0": null } - } + }, "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!", "external_url": "", diff --git a/plugins/utilities/ragdoll-b-gone.py b/plugins/utilities/ragdoll_b_gone.py similarity index 100% rename from plugins/utilities/ragdoll-b-gone.py rename to plugins/utilities/ragdoll_b_gone.py From 1d5387d6dc8b19165d98859c948549699e6343bf Mon Sep 17 00:00:00 2001 From: Rikko Date: Mon, 14 Nov 2022 06:20:49 -0800 Subject: [PATCH 0268/1464] [ci]: apply-metadata --- plugins/minigames.json | 9 +++++++-- plugins/utilities.json | 23 +++++++++++++++++++---- 2 files changed, 26 insertions(+), 6 deletions(-) diff --git a/plugins/minigames.json b/plugins/minigames.json index b2be088f..4bfc4962 100644 --- a/plugins/minigames.json +++ b/plugins/minigames.json @@ -242,8 +242,13 @@ } ], "versions": { - "1.0.0": null + "1.0.0": { + "api_version": 7, + "commit_sha": "0841b9e", + "released_on": "14-11-2022", + "md5sum": "ec3980f3f3a5da96c27f4cbd61f98550" + } } } } -} +} \ No newline at end of file diff --git a/plugins/utilities.json b/plugins/utilities.json index d0275877..f5dc9fb1 100644 --- a/plugins/utilities.json +++ b/plugins/utilities.json @@ -433,7 +433,12 @@ } ], "versions": { - "3.0.0": null + "3.0.0": { + "api_version": 7, + "commit_sha": "0841b9e", + "released_on": "14-11-2022", + "md5sum": "417cd87c17034b4eac8bc301d294d708" + } } }, "ragdoll_b_gone": { @@ -447,7 +452,12 @@ } ], "versions": { - "1.0.0": null + "1.0.0": { + "api_version": 7, + "commit_sha": "0841b9e", + "released_on": "14-11-2022", + "md5sum": "dccb150ef67440f1db7e39884bd856b3" + } } }, "bomb_radius_visualizer": { @@ -461,8 +471,13 @@ } ], "versions": { - "1.0.0": null + "1.0.0": { + "api_version": 7, + "commit_sha": "0841b9e", + "released_on": "14-11-2022", + "md5sum": "6213bc2573cb83f8bf72030604801f5a" + } } } } -} +} \ No newline at end of file From 083e60aa65fdf13fb8544ccc1d1c94627e739d83 Mon Sep 17 00:00:00 2001 From: Loup <90267658+Loup-Garou911XD@users.noreply.github.com> Date: Sat, 19 Nov 2022 01:50:31 +0530 Subject: [PATCH 0269/1464] Add files via upload --- plugins/utilities/share_replay.py | 199 +++++++++++++++++++++++------- 1 file changed, 155 insertions(+), 44 deletions(-) diff --git a/plugins/utilities/share_replay.py b/plugins/utilities/share_replay.py index 705b587b..f550fa90 100644 --- a/plugins/utilities/share_replay.py +++ b/plugins/utilities/share_replay.py @@ -15,7 +15,6 @@ # mod by ʟօʊքɢǟʀօʊ # export replays to mods folder and share with your friends or have a backup - def Print(*args, color=None, top=None): out = "" for arg in args: @@ -23,7 +22,6 @@ def Print(*args, color=None, top=None): out += a ba.screenmessage(out, color=color, top=top) - def cprint(*args): out = "" for arg in args: @@ -31,24 +29,27 @@ def cprint(*args): out += a _ba.chatmessage(out) - +title="SHARE REPLAY" internal_dir = path.join("ba_data", "..", "..", "..", "files", "bombsquad_config", "replays" + 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) 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 = 800 + self.width = 1000 self.height = 300 PopupWindow.__init__(self, @@ -58,7 +59,24 @@ def __init__(self): 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•Importing replay and other features comming in v1.2") + 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") + + def close(self): + ba.playsound(ba.getsound('swish')) + ba.containerwidget(edit=self.root_widget, transition="out_right",) + +class SyncConfirmation(PopupWindow): + def __init__(self): + uiscale = ba.app.ui.uiscale + self.width = 1000#h-hhhhhhhhhhh-----to completeh-hh-hhhhh- + self.height = 300 + PopupWindow.__init__(self, + position=(0.0, 0.0), + size=(self.width, self.height), + scale=1.2,) + ba.containerwidget(edit=self.root_widget, on_outside_click_call=self.close) + ba.buttonwidget(parent=self.root_widget,label="cancel",size=e) + ba.buttonwidget(parent=self.root_widget,label="continue") def close(self): ba.playsound(ba.getsound('swish')) @@ -67,17 +85,56 @@ def close(self): class SettingWindow(): def __init__(self): + global internal self.draw_ui() - self.selected_widget = None self.selected_name = None - - def on_select_text(self, widget, name): - if self.selected_widget is not None: - ba.textwidget(edit=self.selected_widget, color=(1, 1, 1)) + internal=True + self.on_tab_select(internal) + + 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 - self.selected_widget = widget - + self.selected_name=name + + + def on_tab_select(self,_internal): + global internal + internal=_internal + if internal==True: + dir_list=listdir(internal_dir) + ba.buttonwidget(edit=self.share_button,label="Export",icon=ba.gettexture("upButton"),) + sel=self.internal_tab + unsel=self.external_tab + else: + dir_list=listdir(external_dir) + ba.buttonwidget(edit=self.share_button,label="Import",icon=ba.gettexture("downButton"),) + sel= self.external_tab + unsel= self.internal_tab + + ba.buttonwidget(edit=sel,texture=ba.gettexture("circleShadow")) + ba.buttonwidget(edit=unsel,texture=ba.gettexture("nub")) + + dir_list=sorted(dir_list) + existing_widgets=self.scroll2.get_children() + if existing_widgets: + for i in existing_widgets: + i.delete() + height = 900 + 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, + 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( @@ -91,28 +148,71 @@ def draw_ui(self): selectable=False, h_align="center", v_align="center", - text="ShareReplay", + text=title, color=green) ba.buttonwidget( parent=self.root, - position=(400, 580), + position=(450, 580), size=(35, 35), texture=ba.gettexture("achievementEmpty"), label="", on_activate_call=Help) - - ba.buttonwidget( + + internal_tab_pos=85,400 + internal_tab_size=120,80 + external_tab_pos=85,300 + external_tab_size=120,80 + + self.internal_tab=ba.buttonwidget( + parent=self.root, + position=internal_tab_pos, + size=internal_tab_size, + button_type="square", + label="internal", + text_scale=2, + color=blue, + texture=ba.gettexture("circleShadow")) + + self.external_tab=ba.buttonwidget( + parent=self.root, + position=external_tab_pos, + size=external_tab_size, + button_type="square", + label="external", + text_scale=2, + color=blue, + texture=ba.gettexture("nub")) + + ba.buttonwidget(edit=self.internal_tab,on_activate_call=ba.Call(self.on_tab_select,True)) + ba.buttonwidget(edit=self.external_tab,on_activate_call=ba.Call(self.on_tab_select,False)) + + + self.share_button=ba.buttonwidget( parent=self.root, - position=(770, 460), - size=(90, 70), + position=(720, 400), + size=(110, 50), scale=1.5, + button_type="square", label="EXPORT", - on_activate_call=self.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) self.close_button = ba.buttonwidget( parent=self.root, - position=(820, 590), + position=(800, 590), size=(35, 35), texture=ba.gettexture("crossOut"), label="", @@ -124,33 +224,41 @@ def draw_ui(self): scroll = ba.scrollwidget( parent=self.root, size=(500, 400), - position=(200, 150)) - self.scroll = ba.columnwidget(parent=scroll, size=( - 500, 900), selection_loops_to_parent=True, single_depth=True) - - height = 900 - for i in listdir(internal_dir): - height -= 40 - a = i - i = ba.textwidget( - parent=self.scroll, - size=(500, 50), - text=i.split(".")[0], - position=(10, height), - selectable=True, - max_chars=40, - click_activate=True,) - - ba.textwidget(edit=i, on_activate_call=ba.Call(self.on_select_text, i, a)) - - def export(self): + position=(200, 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 - copy(internal_dir+"/"+self.selected_name, external_dir+"/"+self.selected_name) + if 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) + for i in internal_list: + copy(internal_dir+sep+i, external_dir+sep+i) + for i in external_list: + if i in internal_list: + pass + else: + 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) + cprint(internal_dir+self.selected_name) Print(self.selected_name[0:-4]+" exported", top=True, color=pink) - + + def importx(self): + copy(external_dir+self.selected_name, internal_dir+self.selected_name) + cprint(external_dir+self.selected_name) + Print(self.selected_name[0:-4]+" imported", top=True, color=green) + def close(self): ba.playsound(ba.getsound('swish')) ba.containerwidget(edit=self.root, transition="out_right",) @@ -175,7 +283,7 @@ def new_init(self, transition="in_right", origin_widget=None): color=green, icon=ba.gettexture('usersButton'), iconscale=1.5, - label="SHARE REPLAY", + label=title, on_activate_call=SettingWindow) @@ -190,3 +298,6 @@ def has_settings_ui(self): def show_settings_ui(self, button): SettingWindow() + + def on_plugin_manager_prompt(self): + SettingWindow() From a0b3f419514dd320682ca58bff7c3e047ae32b28 Mon Sep 17 00:00:00 2001 From: Loup <90267658+Loup-Garou911XD@users.noreply.github.com> Date: Sat, 19 Nov 2022 02:15:34 +0530 Subject: [PATCH 0270/1464] Add files via upload --- plugins/utilities/share_replay.py | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/plugins/utilities/share_replay.py b/plugins/utilities/share_replay.py index f550fa90..2b43983b 100644 --- a/plugins/utilities/share_replay.py +++ b/plugins/utilities/share_replay.py @@ -68,15 +68,17 @@ def close(self): class SyncConfirmation(PopupWindow): def __init__(self): uiscale = ba.app.ui.uiscale - self.width = 1000#h-hhhhhhhhhhh-----to completeh-hh-hhhhh- + self.width = 600 self.height = 300 PopupWindow.__init__(self, position=(0.0, 0.0), size=(self.width, self.height), scale=1.2,) ba.containerwidget(edit=self.root_widget, on_outside_click_call=self.close) - ba.buttonwidget(parent=self.root_widget,label="cancel",size=e) - ba.buttonwidget(parent=self.root_widget,label="continue") + ba.textwidget(parent=self.root_widget, position=(30, self.height * 0.8), + text=" Are you sure you want to continue\n\nWARNING:replays with same name in mods folder\n will be overwritten") + ba.buttonwidget(parent=self.root_widget,label="CANCEL",size=(200,80),color=red,position=(80,50),on_activate_call=self.close) + ba.buttonwidget(parent=self.root_widget,label="continue",size=(200,80),position=(300,50),on_activate_call=SettingWindow.sync) def close(self): ba.playsound(ba.getsound('swish')) @@ -104,12 +106,12 @@ def on_tab_select(self,_internal): internal=_internal if internal==True: dir_list=listdir(internal_dir) - ba.buttonwidget(edit=self.share_button,label="Export",icon=ba.gettexture("upButton"),) + ba.buttonwidget(edit=self.share_button,label="EXPORT",icon=ba.gettexture("upButton"),) sel=self.internal_tab unsel=self.external_tab else: dir_list=listdir(external_dir) - ba.buttonwidget(edit=self.share_button,label="Import",icon=ba.gettexture("downButton"),) + ba.buttonwidget(edit=self.share_button,label="IMPORT",icon=ba.gettexture("downButton"),) sel= self.external_tab unsel= self.internal_tab @@ -169,7 +171,7 @@ def draw_ui(self): position=internal_tab_pos, size=internal_tab_size, button_type="square", - label="internal", + label="INTERNAL", text_scale=2, color=blue, texture=ba.gettexture("circleShadow")) @@ -179,7 +181,7 @@ def draw_ui(self): position=external_tab_pos, size=external_tab_size, button_type="square", - label="external", + label="EXTERNAL", text_scale=2, color=blue, texture=ba.gettexture("nub")) @@ -208,7 +210,7 @@ def draw_ui(self): label="SYNC", text_scale=2, icon=ba.gettexture("ouyaYButton"), - on_activate_call=self.sync) + on_activate_call=SyncConfirmation) self.close_button = ba.buttonwidget( parent=self.root, @@ -237,7 +239,7 @@ def share(self): # image={"texture":ba.gettexture("bombColor"),"tint_texture":None,"tint_color":None,"tint2_color":None}) - def sync(self): + def sync(self=""): internal_list=listdir(internal_dir) external_list=listdir(external_dir) for i in internal_list: @@ -250,13 +252,11 @@ def sync(self): Print("Synced all replays",color=pink) def export(self): - copy(internal_dir+self.selected_name, external_dir+self.selected_name) - cprint(internal_dir+self.selected_name) + copy(internal_dir+self.selected_name, external_dir+self.selected_name) Print(self.selected_name[0:-4]+" exported", top=True, color=pink) def importx(self): copy(external_dir+self.selected_name, internal_dir+self.selected_name) - cprint(external_dir+self.selected_name) Print(self.selected_name[0:-4]+" imported", top=True, color=green) def close(self): From 8d11b3433ff0b80f4a1f74e7835f7764d176812e Mon Sep 17 00:00:00 2001 From: Loup <90267658+Loup-Garou911XD@users.noreply.github.com> Date: Sat, 19 Nov 2022 02:18:38 +0530 Subject: [PATCH 0271/1464] Update utilities.json --- plugins/utilities.json | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/plugins/utilities.json b/plugins/utilities.json index f5dc9fb1..ed51f331 100644 --- a/plugins/utilities.json +++ b/plugins/utilities.json @@ -14,6 +14,7 @@ } ], "versions": { + "1.1.0":null, "1.0.0": { "api_version": 7, "commit_sha": "2fda676", @@ -480,4 +481,4 @@ } } } -} \ No newline at end of file +} From 79a8b525322554e35d997f08eeff4d251f40fec0 Mon Sep 17 00:00:00 2001 From: Loup-Garou911XD Date: Fri, 18 Nov 2022 20:50:28 +0000 Subject: [PATCH 0272/1464] [ci] auto-format --- plugins/utilities/share_replay.py | 170 ++++++++++++++++-------------- 1 file changed, 88 insertions(+), 82 deletions(-) diff --git a/plugins/utilities/share_replay.py b/plugins/utilities/share_replay.py index 2b43983b..34d58a0e 100644 --- a/plugins/utilities/share_replay.py +++ b/plugins/utilities/share_replay.py @@ -15,6 +15,7 @@ # mod by ʟօʊքɢǟʀօʊ # export replays to mods folder and share with your friends or have a backup + def Print(*args, color=None, top=None): out = "" for arg in args: @@ -22,6 +23,7 @@ def Print(*args, color=None, top=None): out += a ba.screenmessage(out, color=color, top=top) + def cprint(*args): out = "" for arg in args: @@ -29,7 +31,8 @@ def cprint(*args): out += a _ba.chatmessage(out) -title="SHARE REPLAY" + +title = "SHARE REPLAY" internal_dir = path.join("ba_data", "..", "..", "..", "files", "bombsquad_config", "replays" + sep) external_dir = path.join(_ba.env()["python_directory_user"], "replays"+sep) @@ -38,14 +41,13 @@ def cprint(*args): pink = (1, 0.2, 0.8) green = (0.4, 1, 0.4) red = (1, 0, 0) -blue=(0.26, 0.65,0.94) +blue = (0.26, 0.65, 0.94) 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 @@ -64,7 +66,8 @@ def __init__(self): def close(self): ba.playsound(ba.getsound('swish')) ba.containerwidget(edit=self.root_widget, transition="out_right",) - + + class SyncConfirmation(PopupWindow): def __init__(self): uiscale = ba.app.ui.uiscale @@ -77,8 +80,10 @@ def __init__(self): ba.containerwidget(edit=self.root_widget, on_outside_click_call=self.close) ba.textwidget(parent=self.root_widget, position=(30, self.height * 0.8), text=" Are you sure you want to continue\n\nWARNING:replays with same name in mods folder\n will be overwritten") - ba.buttonwidget(parent=self.root_widget,label="CANCEL",size=(200,80),color=red,position=(80,50),on_activate_call=self.close) - ba.buttonwidget(parent=self.root_widget,label="continue",size=(200,80),position=(300,50),on_activate_call=SettingWindow.sync) + ba.buttonwidget(parent=self.root_widget, label="CANCEL", size=(200, 80), + color=red, position=(80, 50), on_activate_call=self.close) + ba.buttonwidget(parent=self.root_widget, label="continue", size=(200, 80), + position=(300, 50), on_activate_call=SettingWindow.sync) def close(self): ba.playsound(ba.getsound('swish')) @@ -90,53 +95,53 @@ def __init__(self): global internal self.draw_ui() self.selected_name = None - internal=True + internal = True self.on_tab_select(internal) - - def on_select_text(self, widget,name): - existing_widgets=self.scroll2.get_children() + + 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=i, color=(1, 1, 1)) ba.textwidget(edit=widget, color=(1, 1, 0)) - self.selected_name=name - - - def on_tab_select(self,_internal): - global internal - internal=_internal - if internal==True: - dir_list=listdir(internal_dir) - ba.buttonwidget(edit=self.share_button,label="EXPORT",icon=ba.gettexture("upButton"),) - sel=self.internal_tab - unsel=self.external_tab - else: - dir_list=listdir(external_dir) - ba.buttonwidget(edit=self.share_button,label="IMPORT",icon=ba.gettexture("downButton"),) - sel= self.external_tab - unsel= self.internal_tab - - ba.buttonwidget(edit=sel,texture=ba.gettexture("circleShadow")) - ba.buttonwidget(edit=unsel,texture=ba.gettexture("nub")) - - dir_list=sorted(dir_list) - existing_widgets=self.scroll2.get_children() - if existing_widgets: - for i in existing_widgets: - i.delete() - height = 900 - 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, - click_activate=True,) - ba.textwidget(edit=i, on_activate_call=ba.Call(self.on_select_text, i , a)) - + self.selected_name = name + + def on_tab_select(self, _internal): + global internal + internal = _internal + if internal == True: + dir_list = listdir(internal_dir) + ba.buttonwidget(edit=self.share_button, label="EXPORT", icon=ba.gettexture("upButton"),) + sel = self.internal_tab + unsel = self.external_tab + else: + dir_list = listdir(external_dir) + ba.buttonwidget(edit=self.share_button, label="IMPORT", + icon=ba.gettexture("downButton"),) + sel = self.external_tab + unsel = self.internal_tab + + ba.buttonwidget(edit=sel, texture=ba.gettexture("circleShadow")) + ba.buttonwidget(edit=unsel, texture=ba.gettexture("nub")) + + dir_list = sorted(dir_list) + existing_widgets = self.scroll2.get_children() + if existing_widgets: + for i in existing_widgets: + i.delete() + height = 900 + 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, + 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( @@ -160,13 +165,13 @@ def draw_ui(self): texture=ba.gettexture("achievementEmpty"), label="", on_activate_call=Help) - - internal_tab_pos=85,400 - internal_tab_size=120,80 - external_tab_pos=85,300 - external_tab_size=120,80 - - self.internal_tab=ba.buttonwidget( + + internal_tab_pos = 85, 400 + internal_tab_size = 120, 80 + external_tab_pos = 85, 300 + external_tab_size = 120, 80 + + self.internal_tab = ba.buttonwidget( parent=self.root, position=internal_tab_pos, size=internal_tab_size, @@ -175,8 +180,8 @@ def draw_ui(self): text_scale=2, color=blue, texture=ba.gettexture("circleShadow")) - - self.external_tab=ba.buttonwidget( + + self.external_tab = ba.buttonwidget( parent=self.root, position=external_tab_pos, size=external_tab_size, @@ -185,12 +190,11 @@ def draw_ui(self): text_scale=2, color=blue, texture=ba.gettexture("nub")) - - ba.buttonwidget(edit=self.internal_tab,on_activate_call=ba.Call(self.on_tab_select,True)) - ba.buttonwidget(edit=self.external_tab,on_activate_call=ba.Call(self.on_tab_select,False)) - - - self.share_button=ba.buttonwidget( + + ba.buttonwidget(edit=self.internal_tab, on_activate_call=ba.Call(self.on_tab_select, True)) + ba.buttonwidget(edit=self.external_tab, on_activate_call=ba.Call(self.on_tab_select, False)) + + self.share_button = ba.buttonwidget( parent=self.root, position=(720, 400), size=(110, 50), @@ -200,8 +204,8 @@ def draw_ui(self): text_scale=2, icon=ba.gettexture("upButton"), on_activate_call=self.share) - - sync_button=ba.buttonwidget( + + sync_button = ba.buttonwidget( parent=self.root, position=(720, 300), size=(110, 50), @@ -228,20 +232,22 @@ def draw_ui(self): size=(500, 400), position=(200, 100),) self.scroll2 = ba.columnwidget(parent=scroll, size=( - 500, 900)) - + 500, 900)) + def share(self): if self.selected_name is None: Print("Select a replay", color=red) return - if internal:self.export() - else:self.importx() - + if 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) + internal_list = listdir(internal_dir) + external_list = listdir(external_dir) for i in internal_list: copy(internal_dir+sep+i, external_dir+sep+i) for i in external_list: @@ -249,16 +255,16 @@ def sync(self=""): pass else: copy(external_dir+sep+i, internal_dir+sep+i) - Print("Synced all replays",color=pink) - + Print("Synced all replays", color=pink) + def export(self): - copy(internal_dir+self.selected_name, external_dir+self.selected_name) + copy(internal_dir+self.selected_name, external_dir+self.selected_name) Print(self.selected_name[0:-4]+" exported", top=True, color=pink) - + 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) - + Print(self.selected_name[0:-4]+" imported", top=True, color=green) + def close(self): ba.playsound(ba.getsound('swish')) ba.containerwidget(edit=self.root, transition="out_right",) @@ -298,6 +304,6 @@ def has_settings_ui(self): def show_settings_ui(self, button): SettingWindow() - + def on_plugin_manager_prompt(self): SettingWindow() From 78c4b223897f206fab07e1d6d884143420ba4a24 Mon Sep 17 00:00:00 2001 From: Loup-Garou911XD Date: Fri, 18 Nov 2022 20:50:30 +0000 Subject: [PATCH 0273/1464] [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 ed51f331..9e008362 100644 --- a/plugins/utilities.json +++ b/plugins/utilities.json @@ -14,7 +14,12 @@ } ], "versions": { - "1.1.0":null, + "1.1.0": { + "api_version": 7, + "commit_sha": "79a8b52", + "released_on": "18-11-2022", + "md5sum": "a68184081983346d3eb51c9c85b73796" + }, "1.0.0": { "api_version": 7, "commit_sha": "2fda676", @@ -481,4 +486,4 @@ } } } -} +} \ No newline at end of file From bc15767e5dc0282373a960b6f104ca299f262a38 Mon Sep 17 00:00:00 2001 From: Loup <90267658+Loup-Garou911XD@users.noreply.github.com> Date: Sat, 19 Nov 2022 08:44:56 +0530 Subject: [PATCH 0274/1464] UI improvements --- plugins/utilities/share_replay.py | 215 +++++++++++++++--------------- 1 file changed, 107 insertions(+), 108 deletions(-) diff --git a/plugins/utilities/share_replay.py b/plugins/utilities/share_replay.py index 34d58a0e..b63b1b02 100644 --- a/plugins/utilities/share_replay.py +++ b/plugins/utilities/share_replay.py @@ -15,7 +15,6 @@ # mod by ʟօʊքɢǟʀօʊ # export replays to mods folder and share with your friends or have a backup - def Print(*args, color=None, top=None): out = "" for arg in args: @@ -23,7 +22,6 @@ def Print(*args, color=None, top=None): out += a ba.screenmessage(out, color=color, top=top) - def cprint(*args): out = "" for arg in args: @@ -31,23 +29,26 @@ def cprint(*args): out += a _ba.chatmessage(out) - -title = "SHARE REPLAY" +title="SHARE REPLAY" internal_dir = path.join("ba_data", "..", "..", "..", "files", "bombsquad_config", "replays" + sep) external_dir = path.join(_ba.env()["python_directory_user"], "replays"+sep) +tab_sel_texture=ba.gettexture("buttonSquare") +tab_unsel_texture=ba.gettexture("chestIconEmpty") # 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=(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 @@ -66,8 +67,7 @@ def __init__(self): def close(self): ba.playsound(ba.getsound('swish')) ba.containerwidget(edit=self.root_widget, transition="out_right",) - - + class SyncConfirmation(PopupWindow): def __init__(self): uiscale = ba.app.ui.uiscale @@ -77,13 +77,14 @@ def __init__(self): position=(0.0, 0.0), size=(self.width, self.height), scale=1.2,) - ba.containerwidget(edit=self.root_widget, on_outside_click_call=self.close) + ba.textwidget(parent=self.root_widget, position=(30, self.height * 0.8), text=" Are you sure you want to continue\n\nWARNING:replays with same name in mods folder\n will be overwritten") - ba.buttonwidget(parent=self.root_widget, label="CANCEL", size=(200, 80), - color=red, position=(80, 50), on_activate_call=self.close) - ba.buttonwidget(parent=self.root_widget, label="continue", size=(200, 80), - position=(300, 50), on_activate_call=SettingWindow.sync) + cancel=ba.buttonwidget(parent=self.root_widget,label=ba.Lstr(resource='cancelText'),size=(200,80),position=(80,50),on_activate_call=self.close) + + ba.buttonwidget(parent=self.root_widget,label=ba.Lstr(resource='okText'),size=(200,80),position=(300,50),color=green,on_activate_call=SettingWindow.sync) + + ba.containerwidget(edit=self.root_widget, on_outside_click_call=self.close,cancel_button=cancel) def close(self): ba.playsound(ba.getsound('swish')) @@ -94,63 +95,73 @@ class SettingWindow(): def __init__(self): global internal self.draw_ui() + ba.containerwidget(edit=self.root,cancel_button=self.close_button) self.selected_name = None - internal = True + internal=True self.on_tab_select(internal) - - def on_select_text(self, widget, name): - existing_widgets = self.scroll2.get_children() + + 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=i,color=(1,1,1)) ba.textwidget(edit=widget, color=(1, 1, 0)) - self.selected_name = name - - def on_tab_select(self, _internal): - global internal - internal = _internal - if internal == True: - dir_list = listdir(internal_dir) - ba.buttonwidget(edit=self.share_button, label="EXPORT", icon=ba.gettexture("upButton"),) - sel = self.internal_tab - unsel = self.external_tab - else: - dir_list = listdir(external_dir) - ba.buttonwidget(edit=self.share_button, label="IMPORT", - icon=ba.gettexture("downButton"),) - sel = self.external_tab - unsel = self.internal_tab - - ba.buttonwidget(edit=sel, texture=ba.gettexture("circleShadow")) - ba.buttonwidget(edit=unsel, texture=ba.gettexture("nub")) - - dir_list = sorted(dir_list) - existing_widgets = self.scroll2.get_children() - if existing_widgets: - for i in existing_widgets: - i.delete() - height = 900 - 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, - click_activate=True,) - ba.textwidget(edit=i, on_activate_call=ba.Call(self.on_select_text, i, a)) - + self.selected_name=name + + + def on_tab_select(self,_internal): + global internal + internal=_internal + if internal==True: + dir_list=listdir(internal_dir) + ba.buttonwidget(edit=self.share_button,label="EXPORT",icon=ba.gettexture("upButton"),) + sel=self.internal_tab + unsel=self.external_tab + else: + dir_list=listdir(external_dir) + ba.buttonwidget(edit=self.share_button,label="IMPORT",icon=ba.gettexture("downButton"),) + sel= self.external_tab + unsel= self.internal_tab + + ba.buttonwidget(edit=sel,texture=tab_sel_texture,color=blue,size=(120,80)) + ba.buttonwidget(edit=unsel,texture=tab_unsel_texture,color=blue,size=(120,100)) + + dir_list=sorted(dir_list) + existing_widgets=self.scroll2.get_children() + if existing_widgets: + for i in existing_widgets: + i.delete() + height = 900 + 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, + 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=(150, 550), + position=(350, 550), scale=2, selectable=False, h_align="center", @@ -160,28 +171,28 @@ def draw_ui(self): ba.buttonwidget( parent=self.root, - position=(450, 580), + position=(650, 580), size=(35, 35), texture=ba.gettexture("achievementEmpty"), label="", on_activate_call=Help) - - internal_tab_pos = 85, 400 - internal_tab_size = 120, 80 - external_tab_pos = 85, 300 - external_tab_size = 120, 80 - - self.internal_tab = ba.buttonwidget( + + internal_tab_pos=85,400 + internal_tab_size=120,80 + external_tab_pos=85,300 + external_tab_size=120,80 + + self.internal_tab=ba.buttonwidget( parent=self.root, position=internal_tab_pos, size=internal_tab_size, button_type="square", label="INTERNAL", text_scale=2, - color=blue, - texture=ba.gettexture("circleShadow")) - - self.external_tab = ba.buttonwidget( + color=blue_highlight, + texture=tab_sel_texture) + + self.external_tab=ba.buttonwidget( parent=self.root, position=external_tab_pos, size=external_tab_size, @@ -189,12 +200,13 @@ def draw_ui(self): label="EXTERNAL", text_scale=2, color=blue, - texture=ba.gettexture("nub")) - - ba.buttonwidget(edit=self.internal_tab, on_activate_call=ba.Call(self.on_tab_select, True)) - ba.buttonwidget(edit=self.external_tab, on_activate_call=ba.Call(self.on_tab_select, False)) - - self.share_button = ba.buttonwidget( + texture=tab_unsel_texture) + + ba.buttonwidget(edit=self.internal_tab,on_activate_call=ba.Call(self.on_tab_select,True)) + ba.buttonwidget(edit=self.external_tab,on_activate_call=ba.Call(self.on_tab_select,False)) + + + self.share_button=ba.buttonwidget( parent=self.root, position=(720, 400), size=(110, 50), @@ -204,8 +216,8 @@ def draw_ui(self): text_scale=2, icon=ba.gettexture("upButton"), on_activate_call=self.share) - - sync_button = ba.buttonwidget( + + sync_button=ba.buttonwidget( parent=self.root, position=(720, 300), size=(110, 50), @@ -214,40 +226,27 @@ def draw_ui(self): label="SYNC", text_scale=2, icon=ba.gettexture("ouyaYButton"), - on_activate_call=SyncConfirmation) - - self.close_button = ba.buttonwidget( - parent=self.root, - position=(800, 590), - size=(35, 35), - texture=ba.gettexture("crossOut"), - label="", - scale=2, - color=(1, 0.2, 0.2), - extra_touch_border_scale=3, - on_activate_call=self.close) + on_activate_call=SyncConfirmation) scroll = ba.scrollwidget( parent=self.root, size=(500, 400), position=(200, 100),) self.scroll2 = ba.columnwidget(parent=scroll, size=( - 500, 900)) - + 500, 900)) + def share(self): if self.selected_name is None: Print("Select a replay", color=red) return - if internal: - self.export() - else: - self.importx() - + if 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) + internal_list=listdir(internal_dir) + external_list=listdir(external_dir) for i in internal_list: copy(internal_dir+sep+i, external_dir+sep+i) for i in external_list: @@ -255,21 +254,21 @@ def sync(self=""): pass else: copy(external_dir+sep+i, internal_dir+sep+i) - Print("Synced all replays", color=pink) - + Print("Synced all replays",color=pink) + def export(self): - copy(internal_dir+self.selected_name, external_dir+self.selected_name) + copy(internal_dir+self.selected_name, external_dir+self.selected_name) Print(self.selected_name[0:-4]+" exported", top=True, color=pink) - + 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) - + Print(self.selected_name[0:-4]+" imported", top=True, color=green) + def close(self): ba.playsound(ba.getsound('swish')) ba.containerwidget(edit=self.root, transition="out_right",) - + # ++++++++++++++++for keyboard navigation++++++++++++++++ #ba.widget(edit=self.enable_button, up_widget=decrease_button, down_widget=self.lower_text,left_widget=save_button, right_widget=save_button) @@ -304,6 +303,6 @@ def has_settings_ui(self): def show_settings_ui(self, button): SettingWindow() - + def on_plugin_manager_prompt(self): SettingWindow() From 95bc8cc9f0c7a2ccf723e778ff4c949e71f65529 Mon Sep 17 00:00:00 2001 From: Loup-Garou911XD Date: Sat, 19 Nov 2022 03:15:25 +0000 Subject: [PATCH 0275/1464] [ci] auto-format --- plugins/utilities/share_replay.py | 197 ++++++++++++++++-------------- 1 file changed, 102 insertions(+), 95 deletions(-) diff --git a/plugins/utilities/share_replay.py b/plugins/utilities/share_replay.py index b63b1b02..203a4ccc 100644 --- a/plugins/utilities/share_replay.py +++ b/plugins/utilities/share_replay.py @@ -15,6 +15,7 @@ # mod by ʟօʊքɢǟʀօʊ # export replays to mods folder and share with your friends or have a backup + def Print(*args, color=None, top=None): out = "" for arg in args: @@ -22,6 +23,7 @@ def Print(*args, color=None, top=None): out += a ba.screenmessage(out, color=color, top=top) + def cprint(*args): out = "" for arg in args: @@ -29,26 +31,26 @@ def cprint(*args): out += a _ba.chatmessage(out) -title="SHARE REPLAY" + +title = "SHARE REPLAY" internal_dir = path.join("ba_data", "..", "..", "..", "files", "bombsquad_config", "replays" + sep) external_dir = path.join(_ba.env()["python_directory_user"], "replays"+sep) -tab_sel_texture=ba.gettexture("buttonSquare") -tab_unsel_texture=ba.gettexture("chestIconEmpty") +tab_sel_texture = ba.gettexture("buttonSquare") +tab_unsel_texture = ba.gettexture("chestIconEmpty") # 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) +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 @@ -67,7 +69,8 @@ def __init__(self): def close(self): ba.playsound(ba.getsound('swish')) ba.containerwidget(edit=self.root_widget, transition="out_right",) - + + class SyncConfirmation(PopupWindow): def __init__(self): uiscale = ba.app.ui.uiscale @@ -77,14 +80,17 @@ def __init__(self): position=(0.0, 0.0), size=(self.width, self.height), scale=1.2,) - + ba.textwidget(parent=self.root_widget, position=(30, self.height * 0.8), text=" Are you sure you want to continue\n\nWARNING:replays with same name in mods folder\n will be overwritten") - cancel=ba.buttonwidget(parent=self.root_widget,label=ba.Lstr(resource='cancelText'),size=(200,80),position=(80,50),on_activate_call=self.close) - - ba.buttonwidget(parent=self.root_widget,label=ba.Lstr(resource='okText'),size=(200,80),position=(300,50),color=green,on_activate_call=SettingWindow.sync) - - ba.containerwidget(edit=self.root_widget, on_outside_click_call=self.close,cancel_button=cancel) + cancel = ba.buttonwidget(parent=self.root_widget, label=ba.Lstr( + resource='cancelText'), size=(200, 80), position=(80, 50), on_activate_call=self.close) + + ba.buttonwidget(parent=self.root_widget, label=ba.Lstr(resource='okText'), size=( + 200, 80), position=(300, 50), color=green, on_activate_call=SettingWindow.sync) + + ba.containerwidget(edit=self.root_widget, + on_outside_click_call=self.close, cancel_button=cancel) def close(self): ba.playsound(ba.getsound('swish')) @@ -95,69 +101,69 @@ class SettingWindow(): def __init__(self): global internal self.draw_ui() - ba.containerwidget(edit=self.root,cancel_button=self.close_button) + ba.containerwidget(edit=self.root, cancel_button=self.close_button) self.selected_name = None - internal=True + internal = True self.on_tab_select(internal) - - def on_select_text(self, widget,name): - existing_widgets=self.scroll2.get_children() + + 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=i, color=(1, 1, 1)) ba.textwidget(edit=widget, color=(1, 1, 0)) - self.selected_name=name - - - def on_tab_select(self,_internal): - global internal - internal=_internal - if internal==True: - dir_list=listdir(internal_dir) - ba.buttonwidget(edit=self.share_button,label="EXPORT",icon=ba.gettexture("upButton"),) - sel=self.internal_tab - unsel=self.external_tab - else: - dir_list=listdir(external_dir) - ba.buttonwidget(edit=self.share_button,label="IMPORT",icon=ba.gettexture("downButton"),) - sel= self.external_tab - unsel= self.internal_tab - - ba.buttonwidget(edit=sel,texture=tab_sel_texture,color=blue,size=(120,80)) - ba.buttonwidget(edit=unsel,texture=tab_unsel_texture,color=blue,size=(120,100)) - - dir_list=sorted(dir_list) - existing_widgets=self.scroll2.get_children() - if existing_widgets: - for i in existing_widgets: - i.delete() - height = 900 - 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, - click_activate=True,) - ba.textwidget(edit=i, on_activate_call=ba.Call(self.on_select_text, i , a)) - + self.selected_name = name + + def on_tab_select(self, _internal): + global internal + internal = _internal + if internal == True: + dir_list = listdir(internal_dir) + ba.buttonwidget(edit=self.share_button, label="EXPORT", icon=ba.gettexture("upButton"),) + sel = self.internal_tab + unsel = self.external_tab + else: + dir_list = listdir(external_dir) + ba.buttonwidget(edit=self.share_button, label="IMPORT", + icon=ba.gettexture("downButton"),) + sel = self.external_tab + unsel = self.internal_tab + + ba.buttonwidget(edit=sel, texture=tab_sel_texture, color=blue, size=(120, 80)) + ba.buttonwidget(edit=unsel, texture=tab_unsel_texture, color=blue, size=(120, 100)) + + dir_list = sorted(dir_list) + existing_widgets = self.scroll2.get_children() + if existing_widgets: + for i in existing_widgets: + i.delete() + height = 900 + 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, + 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), + label=ba.charstr(ba.SpecialChar.BACK), scale=1.5, on_activate_call=self.close) - + ba.textwidget( parent=self.root, size=(200, 100), @@ -176,13 +182,13 @@ def draw_ui(self): texture=ba.gettexture("achievementEmpty"), label="", on_activate_call=Help) - - internal_tab_pos=85,400 - internal_tab_size=120,80 - external_tab_pos=85,300 - external_tab_size=120,80 - - self.internal_tab=ba.buttonwidget( + + internal_tab_pos = 85, 400 + internal_tab_size = 120, 80 + external_tab_pos = 85, 300 + external_tab_size = 120, 80 + + self.internal_tab = ba.buttonwidget( parent=self.root, position=internal_tab_pos, size=internal_tab_size, @@ -191,8 +197,8 @@ def draw_ui(self): text_scale=2, color=blue_highlight, texture=tab_sel_texture) - - self.external_tab=ba.buttonwidget( + + self.external_tab = ba.buttonwidget( parent=self.root, position=external_tab_pos, size=external_tab_size, @@ -201,12 +207,11 @@ def draw_ui(self): text_scale=2, color=blue, texture=tab_unsel_texture) - - ba.buttonwidget(edit=self.internal_tab,on_activate_call=ba.Call(self.on_tab_select,True)) - ba.buttonwidget(edit=self.external_tab,on_activate_call=ba.Call(self.on_tab_select,False)) - - - self.share_button=ba.buttonwidget( + + ba.buttonwidget(edit=self.internal_tab, on_activate_call=ba.Call(self.on_tab_select, True)) + ba.buttonwidget(edit=self.external_tab, on_activate_call=ba.Call(self.on_tab_select, False)) + + self.share_button = ba.buttonwidget( parent=self.root, position=(720, 400), size=(110, 50), @@ -216,8 +221,8 @@ def draw_ui(self): text_scale=2, icon=ba.gettexture("upButton"), on_activate_call=self.share) - - sync_button=ba.buttonwidget( + + sync_button = ba.buttonwidget( parent=self.root, position=(720, 300), size=(110, 50), @@ -226,27 +231,29 @@ def draw_ui(self): label="SYNC", text_scale=2, icon=ba.gettexture("ouyaYButton"), - on_activate_call=SyncConfirmation) + on_activate_call=SyncConfirmation) scroll = ba.scrollwidget( parent=self.root, size=(500, 400), position=(200, 100),) self.scroll2 = ba.columnwidget(parent=scroll, size=( - 500, 900)) - + 500, 900)) + def share(self): if self.selected_name is None: Print("Select a replay", color=red) return - if internal:self.export() - else:self.importx() - + if 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) + internal_list = listdir(internal_dir) + external_list = listdir(external_dir) for i in internal_list: copy(internal_dir+sep+i, external_dir+sep+i) for i in external_list: @@ -254,21 +261,21 @@ def sync(self=""): pass else: copy(external_dir+sep+i, internal_dir+sep+i) - Print("Synced all replays",color=pink) - + Print("Synced all replays", color=pink) + def export(self): - copy(internal_dir+self.selected_name, external_dir+self.selected_name) + copy(internal_dir+self.selected_name, external_dir+self.selected_name) Print(self.selected_name[0:-4]+" exported", top=True, color=pink) - + 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) - + Print(self.selected_name[0:-4]+" imported", top=True, color=green) + def close(self): ba.playsound(ba.getsound('swish')) ba.containerwidget(edit=self.root, transition="out_right",) - + # ++++++++++++++++for keyboard navigation++++++++++++++++ #ba.widget(edit=self.enable_button, up_widget=decrease_button, down_widget=self.lower_text,left_widget=save_button, right_widget=save_button) @@ -303,6 +310,6 @@ def has_settings_ui(self): def show_settings_ui(self, button): SettingWindow() - + def on_plugin_manager_prompt(self): SettingWindow() From 77f92a5cb2e6f20e66a154f144ee0dc203ac0441 Mon Sep 17 00:00:00 2001 From: Loup <90267658+Loup-Garou911XD@users.noreply.github.com> Date: Sat, 19 Nov 2022 08:49:52 +0530 Subject: [PATCH 0276/1464] Remove v1.1.0 meta --- plugins/utilities.json | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/plugins/utilities.json b/plugins/utilities.json index 9e008362..2ce76049 100644 --- a/plugins/utilities.json +++ b/plugins/utilities.json @@ -14,12 +14,7 @@ } ], "versions": { - "1.1.0": { - "api_version": 7, - "commit_sha": "79a8b52", - "released_on": "18-11-2022", - "md5sum": "a68184081983346d3eb51c9c85b73796" - }, + "1.1.0": null, "1.0.0": { "api_version": 7, "commit_sha": "2fda676", @@ -486,4 +481,4 @@ } } } -} \ No newline at end of file +} From c382fdb3390221f9f4445959b52e0e9670a44bfb Mon Sep 17 00:00:00 2001 From: Loup-Garou911XD Date: Sat, 19 Nov 2022 03:20:19 +0000 Subject: [PATCH 0277/1464] [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 2ce76049..c62857bb 100644 --- a/plugins/utilities.json +++ b/plugins/utilities.json @@ -14,7 +14,12 @@ } ], "versions": { - "1.1.0": null, + "1.1.0": { + "api_version": 7, + "commit_sha": "77f92a5", + "released_on": "19-11-2022", + "md5sum": "07eaf53c99b938e08383d09f1cdd01ab" + }, "1.0.0": { "api_version": 7, "commit_sha": "2fda676", @@ -481,4 +486,4 @@ } } } -} +} \ No newline at end of file From 37dfd46953581d4fc853fc409f2d50445d7bec70 Mon Sep 17 00:00:00 2001 From: Ayush Saini <36878972+imayushsaini@users.noreply.github.com> Date: Sat, 26 Nov 2022 18:01:28 +0530 Subject: [PATCH 0278/1464] added auto stunt plugin --- plugins/utilities.json | 14 + plugins/utilities/auto_stunt.py | 537 ++++++++++++++++++++++++++++++++ 2 files changed, 551 insertions(+) create mode 100644 plugins/utilities/auto_stunt.py diff --git a/plugins/utilities.json b/plugins/utilities.json index f5dc9fb1..c64ba2d2 100644 --- a/plugins/utilities.json +++ b/plugins/utilities.json @@ -302,6 +302,20 @@ } } }, + "auto_stunt": { + "description": "auto stunts, learn stunts, mirror your player, bro elimination mini game", + "external_url": "https://www.youtube.com/watch?v=DXZeWrTCZlI", + "authors": [ + { + "name": "Mr.Smoothy", + "email": "smoothy@bombsquad.ga", + "discord": "mr.smoothy#5824" + } + ], + "versions": { + "1.0.0": null + } + }, "server_switch": { "description": "Let you switch between recents servers", "external_url": "https://www.youtube.com/watch?v=QrES1jQGXF0", diff --git a/plugins/utilities/auto_stunt.py b/plugins/utilities/auto_stunt.py new file mode 100644 index 00000000..6a997b0b --- /dev/null +++ b/plugins/utilities/auto_stunt.py @@ -0,0 +1,537 @@ +# ba_meta require api 7 +# AutoStunt mod by - Mr.Smoothy x Rikko +# https://discord.gg/ucyaesh +# https://bombsquad.ga +# Dont modify redistribute this plugin , if want to use features of this plugin in your mod write logic in seprate file +# and import this as module. +# If want to contribute in this original module, raise PR on github https://github.com/bombsquad-community/plugin-manager + +import ba +import _ba +import bastd +from bastd.actor.text import Text +from bastd.actor.image import Image +from bastd.actor import spaz +from bastd.actor import playerspaz +from bastd.gameutils import SharedObjects +from bastd.actor.powerupbox import PowerupBoxFactory +from bastd.actor.spazfactory import SpazFactory +from bastd.game.elimination import EliminationGame +import math +import json +import os + +from typing import Optional + +CONTROLS_CENTER = (0, 0) +CONTROLS_SCALE = 1 + +BASE_STUNTS_DIRECTORY = os.path.join(_ba.env()["python_directory_user"], "CustomStunts") +PLAYERS_STUNT_INFO = {} + +STUNT_CACHE = {} +original_on_begin = ba._activity.Activity.on_begin +original_chatmessage = _ba.chatmessage + + +class ControlsUI: + def on_jump_press(activity): + print("jumped pressed in UI control") + print(activity._jump_image.node.color) + activity._jump_image.node.color = list(channel * 2 for channel in activity._jump_image.node.color[:3]) + [1] + print(activity._jump_image.node.color) + + def on_jump_release(activity): + activity._jump_image.node.color = list(channel * 0.5 for channel in activity._jump_image.node.color[:3]) + [1] + + def on_pickup_press(activity): + activity._pickup_image.node.color = list(channel * 2 for channel in activity._pickup_image.node.color[:3]) + [1] + + def on_pickup_release(activity): + activity._pickup_image.node.color = list(channel * 0.5 for channel in activity._pickup_image.node.color[:3]) + [1] + + def on_punch_press(activity): + activity._punch_image.node.color = list(channel * 2 for channel in activity._punch_image.node.color[:3]) + [1] + + def on_punch_release(activity): + activity._punch_image.node.color = list(channel * 0.5 for channel in activity._punch_image.node.color[:3]) + [1] + + def on_bomb_press(activity): + activity._bomb_image.node.color = list(channel * 2 for channel in activity._bomb_image.node.color[:3]) + [1] + + def on_bomb_release(activity): + activity._bomb_image.node.color = list(channel * 0.5 for channel in activity._bomb_image.node.color[:3]) + [1] + + def on_move_ud(activity,value): + activity.set_stick_image_position(activity,x=activity.stick_image_position_x,y=value) + + def on_move_lr(activity,value): + activity.set_stick_image_position(activity,x=value,y=activity.stick_image_position_y) + + def display(activity): + activity._jump_image.node.color = list(activity._jump_image.node.color[:3]) + [1] + activity._pickup_image.node.color = list(activity._pickup_image.node.color[:3]) + [1] + activity._punch_image.node.color = list(activity._punch_image.node.color[:3]) + [1] + activity._bomb_image.node.color = list(activity._bomb_image.node.color[:3]) + [1] + activity._stick_base_image.opacity = 1.0 + activity._stick_nub_image.opacity = 1.0 + + def hide(activity): + activity._jump_image.node.color = list(activity._jump_image.node.color[:3]) + [0] + activity._pickup_image.node.color = list(activity._pickup_image.node.color[:3]) + [0] + activity._punch_image.node.color = list(activity._punch_image.node.color[:3]) + [0] + activity._bomb_image.node.color = list(activity._bomb_image.node.color[:3]) + [0] + activity._stick_base_image.opacity = 0.0 + activity._stick_nub_image.opacity = 0.0 + + +CONTROLS_UI_MAP = { + "JUMP_PRESS": ControlsUI.on_jump_press, + "JUMP_RELEASE": ControlsUI.on_jump_release, + "PICKUP_PRESS": ControlsUI.on_pickup_press, + "PICKUP_RELEASE": ControlsUI.on_pickup_release, + "PUNCH_PRESS": ControlsUI.on_punch_press, + "PUNCH_RELEASE": ControlsUI.on_punch_release, + "BOMB_PRESS": ControlsUI.on_bomb_press, + "BOMB_RELEASE": ControlsUI.on_bomb_release, + "UP_DOWN": ControlsUI.on_move_ud, + "LEFT_RIGHT": ControlsUI.on_move_lr +} +class NewSpaz(bastd.actor.spaz.Spaz): + def __init__(self, *args, **kwargs): + super().__init__(*args, **kwargs) + self.move_map = { + "UP_DOWN": self.on_move_up_down, + "LEFT_RIGHT": self.on_move_left_right, + "HOLD_POSITION": self.on_hold_position_press, + "HOLD_RELEASE": self.on_hold_position_release, + "JUMP_PRESS": self.on_jump_press, + "JUMP_RELEASE": self.on_jump_release, + "PICKUP_PRESS": self.on_pickup_press, + "PICKUP_RELEASE": self.on_pickup_release, + "PUNCH_PRESS": self.on_punch_press, + "PUNCH_RELEASE": self.on_punch_release, + "BOMB_PRESS": self.on_bomb_press, + "BOMB_RELEASE": self.on_bomb_release, + "RUN": self.on_run, + } + +class NewPlayerSpaz(bastd.actor.playerspaz.PlayerSpaz): + def __init__(self, *args, **kwargs): + super().__init__(*args, **kwargs) + self.move_map = { + "UP_DOWN": self.on_move_up_down, + "LEFT_RIGHT": self.on_move_left_right, + "HOLD_POSITION": self.on_hold_position_press, + "HOLD_RELEASE": self.on_hold_position_release, + "JUMP_PRESS": self.on_jump_press, + "JUMP_RELEASE": self.on_jump_release, + "PICKUP_PRESS": self.on_pickup_press, + "PICKUP_RELEASE": self.on_pickup_release, + "PUNCH_PRESS": self.on_punch_press, + "PUNCH_RELEASE": self.on_punch_release, + "BOMB_PRESS": self.on_bomb_press, + "BOMB_RELEASE": self.on_bomb_release, + "RUN": self.on_run, + } + self.mirror_spaz = [] + self.source_player.in_replay = False + self.source_player.mirror_mode = False + + + def _handle_action(self, action, value: Optional[float] = None) -> None: + if self.source_player.sessionplayer in PLAYERS_STUNT_INFO: + PLAYERS_STUNT_INFO[self.source_player.sessionplayer].append({ + "time": ba.time() - self.source_player.recording_start_time, + "move": { + "action": action, + "value": value, + } + }) + elif self.source_player.in_replay: + ui_activation = CONTROLS_UI_MAP.get(action) + if ui_activation: + if action in ["UP_DOWN","LEFT_RIGHT"]: + ui_activation(self.source_player.actor._activity(),value) + else: + ui_activation(self.source_player.actor._activity()) + elif self.source_player.mirror_mode: + for mspaz in self.mirror_spaz: + if mspaz and mspaz.node.exists(): + if action in ["UP_DOWN","LEFT_RIGHT","RUN"]: + mspaz.move_map[action](value) + else: + mspaz.move_map[action]() + + + + + def on_move_up_down(self, value: float, *args, **kwargs) -> None: + self._handle_action("UP_DOWN", value) + super().on_move_up_down(value, *args, **kwargs) + + def on_move_left_right(self, value: float, *args, **kwargs) -> None: + self._handle_action("LEFT_RIGHT", value) + super().on_move_left_right(value, *args, **kwargs) + + def on_hold_position_press(self, *args, **kwargs) -> None: + self._handle_action("HOLD_POSITION") + super().on_hold_position_press(*args, **kwargs) + + def on_hold_position_release(self, *args, **kwargs) -> None: + self._handle_action("HOLD_RELEASE") + super().on_hold_position_release(*args, **kwargs) + + def on_jump_press(self, *args, **kwargs) -> None: + self._handle_action("JUMP_PRESS") + super().on_jump_press(*args, **kwargs) + + def on_jump_release(self, *args, **kwargs) -> None: + self._handle_action("JUMP_RELEASE") + super().on_jump_release(*args, **kwargs) + + def on_pickup_press(self, *args, **kwargs) -> None: + self._handle_action("PICKUP_PRESS") + super().on_pickup_press(*args, **kwargs) + + def on_pickup_release(self, *args, **kwargs) -> None: + self._handle_action("PICKUP_RELEASE") + super().on_pickup_release(*args, **kwargs) + + def on_punch_press(self, *args, **kwargs) -> None: + self._handle_action("PUNCH_PRESS") + super().on_punch_press(*args, **kwargs) + + def on_punch_release(self, *args, **kwargs) -> None: + self._handle_action("PUNCH_RELEASE") + super().on_punch_release(*args, **kwargs) + + def on_bomb_press(self, *args, **kwargs) -> None: + self._handle_action("BOMB_PRESS") + super().on_bomb_press(*args, **kwargs) + + def on_bomb_release(self, *args, **kwargs) -> None: + self._handle_action("BOMB_RELEASE") + super().on_bomb_release(*args, **kwargs) + + def on_run(self, value: float, *args, **kwargs) -> None: + self._handle_action("RUN", value) + super().on_run(value, *args, **kwargs) + + +def handle_player_replay_end(player): + player.in_replay = False + ControlsUI.hide(player.actor._activity()) + + +def get_player_from_client_id(client_id, activity=None): + activity = activity or _ba.get_foreground_host_activity() + for player in activity.players: + if player.sessionplayer.inputdevice.client_id == client_id: + return player + raise ba.SessionPlayerNotFound() + +def mirror(clieid): + player = get_player_from_client_id(clieid) + spawn_mirror_spaz(player) + +def capture(player): + with ba.Context(player.actor._activity()): + player.recording_start_time = ba.time() + PLAYERS_STUNT_INFO[player.sessionplayer] = [] + + +def save(player, stunt_name): + stunt_path = f"{os.path.join(BASE_STUNTS_DIRECTORY, stunt_name)}.json" + os.makedirs(BASE_STUNTS_DIRECTORY, exist_ok=True) + with open(stunt_path, "w") as fout: + json.dump(PLAYERS_STUNT_INFO[player.sessionplayer], fout, indent=2) + del PLAYERS_STUNT_INFO[player.sessionplayer] + + +def replay(player, stunt_name): + stunt_path = f"{os.path.join(BASE_STUNTS_DIRECTORY, stunt_name)}.json" + if stunt_name in STUNT_CACHE: + stunt = STUNT_CACHE[stunt_name] + else: + try: + with open(stunt_path, "r") as fin: + stunt = json.load(fin) + STUNT_CACHE[stunt_name] = stunt + except: + ba.screenmessage(f"{stunt_name} doesn't exists") + return + player.in_replay = True + with ba.Context(player.actor._activity()): + ControlsUI.display(player.actor._activity()) + for move in stunt: + value = move["move"]["value"] + if value is None: + ba.timer( + move["time"], + ba.Call(player.actor.move_map[move["move"]["action"]]) + ) + else: + ba.timer( + move["time"], + ba.Call(player.actor.move_map[move["move"]["action"]], move["move"]["value"]) + ) + last_move_time = move["time"] + time_to_hide_controls = last_move_time + 1 + ba.timer(time_to_hide_controls, ba.Call(handle_player_replay_end, player)) + +def spawn_mirror_spaz(player): + player.mirror_mode = True + with ba.Context(player.actor._activity()): + bot=spaz.Spaz(player.color,player.highlight,character=player.character).autoretain() + bot.handlemessage(ba.StandMessage((player.actor.node.position[0], player.actor.node.position[1], player.actor.node.position[2]+1), 93)) + bot.node.name = player.actor.node.name + bot.node.name_color = player.actor.node.name_color + player.actor.mirror_spaz.append(bot) + +def ghost(player, stunt_name): + stunt_path = f"{os.path.join(BASE_STUNTS_DIRECTORY, stunt_name)}.json" + if stunt_name in STUNT_CACHE: + stunt = STUNT_CACHE[stunt_name] + else: + try: + with open(stunt_path, "r") as fin: + stunt = json.load(fin) + STUNT_CACHE[stunt_name] = stunt + except: + ba.screenmessage(f"{stunt_name} doesn't exists") + return + player.in_replay = True + + + with ba.Context(player.actor._activity()): + bot=spaz.Spaz((1,0,0),character="Spaz").autoretain() + bot.handlemessage(ba.StandMessage(player.actor.node.position,93)) + give_ghost_power(bot) + ControlsUI.display(player.actor._activity()) + for move in stunt: + value = move["move"]["value"] + if value is None: + ba.timer( + move["time"], + ba.Call(bot.move_map[move["move"]["action"]]) + ) + ui_activation = CONTROLS_UI_MAP.get(move["move"]["action"]) + if ui_activation: + ba.timer( + move["time"], + ba.Call(ui_activation,player.actor._activity()) + ) + else: + ba.timer( + move["time"], + ba.Call(bot.move_map[move["move"]["action"]], move["move"]["value"]) + ) + ui_activation = CONTROLS_UI_MAP.get(move["move"]["action"]) + + if ui_activation: + ba.timer( + move["time"], + ba.Call(ui_activation,player.actor._activity(), move["move"]["value"] ) + ) + last_move_time = move["time"] + time_to_hide_controls = last_move_time + 1 + ba.timer(time_to_hide_controls, ba.Call(handle_player_replay_end, player)) + ba.timer(time_to_hide_controls, ba.Call(bot.node.delete)) + +def give_ghost_power(spaz): + spaz.node.invincible = True + shared = SharedObjects.get() + factory = SpazFactory.get() + ghost=ba.Material() + # smoothy hecks + ghost.add_actions( + conditions=(('they_have_material', factory.spaz_material), 'or', + ('they_have_material', shared.player_material), 'or', + ('they_have_material', shared.attack_material), 'or', + ('they_have_material', shared.pickup_material), 'or', + ('they_have_material', PowerupBoxFactory.get().powerup_accept_material)), + actions=( + ('modify_part_collision', 'collide', False), + ('modify_part_collision', 'physical', False) + )) + mats=list(spaz.node.materials) + roller=list(spaz.node.roller_materials) + ext=list(spaz.node.extras_material) + pick=list(spaz.node.pickup_materials) + punch=list(spaz.node.punch_materials) + + mats.append(ghost) + roller.append(ghost) + ext.append(ghost) + pick.append(ghost) + punch.append(ghost) + + spaz.node.materials=tuple(mats) + spaz.node.roller_materials=tuple(roller) + spaz.node.extras_material=tuple(ext) + spaz.node.pickup_materials=tuple(pick) + spaz.node.punch_materials=tuple(pick) + + +def new_chatmessage(msg): + if not msg.startswith("*"): + return original_chatmessage(msg) + + stripped_msg = msg[1:] + msg_splits = stripped_msg.split(maxsplit=3) + command = msg_splits[0] + + client_id = -1 + player = get_player_from_client_id(client_id) + + if command == "start": + capture(player) + _ba.chatmessage("Recording started for {}.".format( + player.getname(), + )) + return original_chatmessage(msg) + + stunt_name = " ".join(msg_splits[1:]) + + if command == "save": + if len(msg_splits) < 2: + ba.screenmessage("Enter name of stunt eg : *save bombjump") + return original_chatmessage(msg) + save(player, stunt_name) + _ba.chatmessage('Recording "{}" by {} saved.'.format( + stunt_name, + player.getname(), + )) + elif command == "stunt": + if len(msg_splits) < 2: + ba.screenmessage("Enter name of stunt eg : *stunt bombjump") + return original_chatmessage(msg) + replay(player, stunt_name) + _ba.chatmessage('Replaying "{}" on {}.'.format( + stunt_name, + player.getname(), + )) + elif command == "learn": + if len(msg_splits) < 2: + ba.screenmessage("Enter name of stunt eg : *learn bombjump") + return original_chatmessage(msg) + ghost(player, stunt_name) + _ba.chatmessage('Replaying "{}" on {}.'.format( + stunt_name, + player.getname(), + )) + elif command == "mirror": + spawn_mirror_spaz(player) + return original_chatmessage(msg) + +def set_stick_image_position(self, x: float, y: float) -> None: + + # Clamp this to a circle. + len_squared = x * x + y * y + if len_squared > 1.0: + length = math.sqrt(len_squared) + mult = 1.0 / length + x *= mult + y *= mult + + self.stick_image_position_x = x + self.stick_image_position_y = y + offs = 50.0 + assert self._scale is not None + p = [ + self._stick_nub_position[0] + x * offs * 0.6, + self._stick_nub_position[1] + y * offs * 0.6 + ] + c = list(self._stick_nub_image_color) + if abs(x) > 0.1 or abs(y) > 0.1: + c[0] *= 2.0 + c[1] *= 4.0 + c[2] *= 2.0 + assert self._stick_nub_image is not None + self._stick_nub_image.position = p + self._stick_nub_image.color = c + c = list(self._stick_base_image_color) + if abs(x) > 0.1 or abs(y) > 0.1: + c[0] *= 1.5 + c[1] *= 1.5 + c[2] *= 1.5 + assert self._stick_base_image is not None + self._stick_base_image.color = c + +def on_begin(self, *args, **kwargs) -> None: + self._jump_image = Image( + ba.gettexture('buttonJump'), + position=(385,160), + scale=(50,50), + color=[0.1,0.45,0.1,0] + ) + self._pickup_image = Image( + ba.gettexture('buttonPickUp'), + position=(385,240), + scale=(50,50), + color=[0,0.35,0,0] + ) + self._punch_image = Image( + ba.gettexture('buttonPunch'), + position=(345,200), + scale=(50,50), + color=[0.45,0.45,0,0] + ) + self._bomb_image = Image( + ba.gettexture('buttonBomb'), + position=(425,200), + scale=(50,50), + color=[0.45,0.1,0.1,0] + ) + self.stick_image_position_x = self.stick_image_position_y = 0.0 + self._stick_base_position = p = (-328,200) + self._stick_base_image_color = c2 = (0.25, 0.25, 0.25, 1.0) + self._stick_base_image = ba.newnode( + 'image', + attrs={ + 'texture': ba.gettexture('nub'), + 'absolute_scale': True, + 'vr_depth': -40, + 'position': p, + 'scale': ( 220.0*0.6, 220.0*0.6), + 'color': c2 + }) + self._stick_nub_position = p = (-328, 200) + self._stick_nub_image_color = c3 = (0.4, 0.4, 0.4, 1.0) + self._stick_nub_image = ba.newnode('image', + attrs={ + 'texture': ba.gettexture('nub'), + 'absolute_scale': True, + 'position': p, + 'scale': (110*0.6, 110*0.66), + 'color': c3 + }) + self._stick_base_image.opacity = 0.0 + self._stick_nub_image.opacity = 0.0 + self.set_stick_image_position = set_stick_image_position + return original_on_begin(self, *args, **kwargs) + + +# ba_meta export plugin +class byHeySmoothy(ba.Plugin): + def on_app_running(self): + _ba.set_party_icon_always_visible(True) + ba._activity.Activity.on_begin = on_begin + _ba.chatmessage = new_chatmessage + bastd.actor.playerspaz.PlayerSpaz = NewPlayerSpaz + bastd.actor.spaz.Spaz = NewSpaz + + + + +# lets define a sample elimination game that can use super power of this plugin + +# ba_meta export game +class BroEliminaition(EliminationGame): + name = 'BroElimination' + description = 'Elimination Game with dual character control' + + def spawn_player(self, player) -> ba.Actor: + super().spawn_player(player) + spawn_mirror_spaz(player) \ No newline at end of file From 7bc4d9e3f32362051ea570dab849c17f4cb799c5 Mon Sep 17 00:00:00 2001 From: imayushsaini Date: Sat, 26 Nov 2022 12:33:00 +0000 Subject: [PATCH 0279/1464] [ci] auto-format --- plugins/utilities/auto_stunt.py | 234 +++++++++++++++++--------------- 1 file changed, 123 insertions(+), 111 deletions(-) diff --git a/plugins/utilities/auto_stunt.py b/plugins/utilities/auto_stunt.py index 6a997b0b..fba522d1 100644 --- a/plugins/utilities/auto_stunt.py +++ b/plugins/utilities/auto_stunt.py @@ -1,5 +1,5 @@ # ba_meta require api 7 -# AutoStunt mod by - Mr.Smoothy x Rikko +# AutoStunt mod by - Mr.Smoothy x Rikko # https://discord.gg/ucyaesh # https://bombsquad.ga # Dont modify redistribute this plugin , if want to use features of this plugin in your mod write logic in seprate file @@ -38,35 +38,43 @@ class ControlsUI: def on_jump_press(activity): print("jumped pressed in UI control") print(activity._jump_image.node.color) - activity._jump_image.node.color = list(channel * 2 for channel in activity._jump_image.node.color[:3]) + [1] + activity._jump_image.node.color = list( + channel * 2 for channel in activity._jump_image.node.color[:3]) + [1] print(activity._jump_image.node.color) def on_jump_release(activity): - activity._jump_image.node.color = list(channel * 0.5 for channel in activity._jump_image.node.color[:3]) + [1] + activity._jump_image.node.color = list( + channel * 0.5 for channel in activity._jump_image.node.color[:3]) + [1] def on_pickup_press(activity): - activity._pickup_image.node.color = list(channel * 2 for channel in activity._pickup_image.node.color[:3]) + [1] + activity._pickup_image.node.color = list( + channel * 2 for channel in activity._pickup_image.node.color[:3]) + [1] def on_pickup_release(activity): - activity._pickup_image.node.color = list(channel * 0.5 for channel in activity._pickup_image.node.color[:3]) + [1] + activity._pickup_image.node.color = list( + channel * 0.5 for channel in activity._pickup_image.node.color[:3]) + [1] def on_punch_press(activity): - activity._punch_image.node.color = list(channel * 2 for channel in activity._punch_image.node.color[:3]) + [1] + activity._punch_image.node.color = list( + channel * 2 for channel in activity._punch_image.node.color[:3]) + [1] def on_punch_release(activity): - activity._punch_image.node.color = list(channel * 0.5 for channel in activity._punch_image.node.color[:3]) + [1] + activity._punch_image.node.color = list( + channel * 0.5 for channel in activity._punch_image.node.color[:3]) + [1] def on_bomb_press(activity): - activity._bomb_image.node.color = list(channel * 2 for channel in activity._bomb_image.node.color[:3]) + [1] + activity._bomb_image.node.color = list( + channel * 2 for channel in activity._bomb_image.node.color[:3]) + [1] def on_bomb_release(activity): - activity._bomb_image.node.color = list(channel * 0.5 for channel in activity._bomb_image.node.color[:3]) + [1] - - def on_move_ud(activity,value): - activity.set_stick_image_position(activity,x=activity.stick_image_position_x,y=value) - - def on_move_lr(activity,value): - activity.set_stick_image_position(activity,x=value,y=activity.stick_image_position_y) + activity._bomb_image.node.color = list( + channel * 0.5 for channel in activity._bomb_image.node.color[:3]) + [1] + + def on_move_ud(activity, value): + activity.set_stick_image_position(activity, x=activity.stick_image_position_x, y=value) + + def on_move_lr(activity, value): + activity.set_stick_image_position(activity, x=value, y=activity.stick_image_position_y) def display(activity): activity._jump_image.node.color = list(activity._jump_image.node.color[:3]) + [1] @@ -97,6 +105,8 @@ def hide(activity): "UP_DOWN": ControlsUI.on_move_ud, "LEFT_RIGHT": ControlsUI.on_move_lr } + + class NewSpaz(bastd.actor.spaz.Spaz): def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) @@ -116,6 +126,7 @@ def __init__(self, *args, **kwargs): "RUN": self.on_run, } + class NewPlayerSpaz(bastd.actor.playerspaz.PlayerSpaz): def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) @@ -137,7 +148,6 @@ def __init__(self, *args, **kwargs): self.mirror_spaz = [] self.source_player.in_replay = False self.source_player.mirror_mode = False - def _handle_action(self, action, value: Optional[float] = None) -> None: if self.source_player.sessionplayer in PLAYERS_STUNT_INFO: @@ -151,20 +161,17 @@ def _handle_action(self, action, value: Optional[float] = None) -> None: elif self.source_player.in_replay: ui_activation = CONTROLS_UI_MAP.get(action) if ui_activation: - if action in ["UP_DOWN","LEFT_RIGHT"]: - ui_activation(self.source_player.actor._activity(),value) + if action in ["UP_DOWN", "LEFT_RIGHT"]: + ui_activation(self.source_player.actor._activity(), value) else: ui_activation(self.source_player.actor._activity()) elif self.source_player.mirror_mode: for mspaz in self.mirror_spaz: if mspaz and mspaz.node.exists(): - if action in ["UP_DOWN","LEFT_RIGHT","RUN"]: + if action in ["UP_DOWN", "LEFT_RIGHT", "RUN"]: mspaz.move_map[action](value) else: mspaz.move_map[action]() - - - def on_move_up_down(self, value: float, *args, **kwargs) -> None: self._handle_action("UP_DOWN", value) @@ -231,10 +238,12 @@ def get_player_from_client_id(client_id, activity=None): return player raise ba.SessionPlayerNotFound() + def mirror(clieid): player = get_player_from_client_id(clieid) spawn_mirror_spaz(player) + def capture(player): with ba.Context(player.actor._activity()): player.recording_start_time = ba.time() @@ -280,15 +289,18 @@ def replay(player, stunt_name): time_to_hide_controls = last_move_time + 1 ba.timer(time_to_hide_controls, ba.Call(handle_player_replay_end, player)) + def spawn_mirror_spaz(player): player.mirror_mode = True with ba.Context(player.actor._activity()): - bot=spaz.Spaz(player.color,player.highlight,character=player.character).autoretain() - bot.handlemessage(ba.StandMessage((player.actor.node.position[0], player.actor.node.position[1], player.actor.node.position[2]+1), 93)) + bot = spaz.Spaz(player.color, player.highlight, character=player.character).autoretain() + bot.handlemessage(ba.StandMessage( + (player.actor.node.position[0], player.actor.node.position[1], player.actor.node.position[2]+1), 93)) bot.node.name = player.actor.node.name bot.node.name_color = player.actor.node.name_color player.actor.mirror_spaz.append(bot) + def ghost(player, stunt_name): stunt_path = f"{os.path.join(BASE_STUNTS_DIRECTORY, stunt_name)}.json" if stunt_name in STUNT_CACHE: @@ -302,11 +314,10 @@ def ghost(player, stunt_name): ba.screenmessage(f"{stunt_name} doesn't exists") return player.in_replay = True - with ba.Context(player.actor._activity()): - bot=spaz.Spaz((1,0,0),character="Spaz").autoretain() - bot.handlemessage(ba.StandMessage(player.actor.node.position,93)) + bot = spaz.Spaz((1, 0, 0), character="Spaz").autoretain() + bot.handlemessage(ba.StandMessage(player.actor.node.position, 93)) give_ghost_power(bot) ControlsUI.display(player.actor._activity()) for move in stunt: @@ -320,7 +331,7 @@ def ghost(player, stunt_name): if ui_activation: ba.timer( move["time"], - ba.Call(ui_activation,player.actor._activity()) + ba.Call(ui_activation, player.actor._activity()) ) else: ba.timer( @@ -332,34 +343,35 @@ def ghost(player, stunt_name): if ui_activation: ba.timer( move["time"], - ba.Call(ui_activation,player.actor._activity(), move["move"]["value"] ) + ba.Call(ui_activation, player.actor._activity(), move["move"]["value"]) ) last_move_time = move["time"] time_to_hide_controls = last_move_time + 1 ba.timer(time_to_hide_controls, ba.Call(handle_player_replay_end, player)) ba.timer(time_to_hide_controls, ba.Call(bot.node.delete)) + def give_ghost_power(spaz): spaz.node.invincible = True shared = SharedObjects.get() factory = SpazFactory.get() - ghost=ba.Material() + ghost = ba.Material() # smoothy hecks ghost.add_actions( - conditions=(('they_have_material', factory.spaz_material), 'or', - ('they_have_material', shared.player_material), 'or', - ('they_have_material', shared.attack_material), 'or', - ('they_have_material', shared.pickup_material), 'or', - ('they_have_material', PowerupBoxFactory.get().powerup_accept_material)), - actions=( + conditions=(('they_have_material', factory.spaz_material), 'or', + ('they_have_material', shared.player_material), 'or', + ('they_have_material', shared.attack_material), 'or', + ('they_have_material', shared.pickup_material), 'or', + ('they_have_material', PowerupBoxFactory.get().powerup_accept_material)), + actions=( ('modify_part_collision', 'collide', False), ('modify_part_collision', 'physical', False) - )) - mats=list(spaz.node.materials) - roller=list(spaz.node.roller_materials) - ext=list(spaz.node.extras_material) - pick=list(spaz.node.pickup_materials) - punch=list(spaz.node.punch_materials) + )) + mats = list(spaz.node.materials) + roller = list(spaz.node.roller_materials) + ext = list(spaz.node.extras_material) + pick = list(spaz.node.pickup_materials) + punch = list(spaz.node.punch_materials) mats.append(ghost) roller.append(ghost) @@ -367,13 +379,13 @@ def give_ghost_power(spaz): pick.append(ghost) punch.append(ghost) - spaz.node.materials=tuple(mats) - spaz.node.roller_materials=tuple(roller) - spaz.node.extras_material=tuple(ext) - spaz.node.pickup_materials=tuple(pick) - spaz.node.punch_materials=tuple(pick) + spaz.node.materials = tuple(mats) + spaz.node.roller_materials = tuple(roller) + spaz.node.extras_material = tuple(ext) + spaz.node.pickup_materials = tuple(pick) + spaz.node.punch_materials = tuple(pick) + - def new_chatmessage(msg): if not msg.startswith("*"): return original_chatmessage(msg) @@ -425,88 +437,90 @@ def new_chatmessage(msg): spawn_mirror_spaz(player) return original_chatmessage(msg) + def set_stick_image_position(self, x: float, y: float) -> None: - # Clamp this to a circle. - len_squared = x * x + y * y - if len_squared > 1.0: - length = math.sqrt(len_squared) - mult = 1.0 / length - x *= mult - y *= mult - - self.stick_image_position_x = x - self.stick_image_position_y = y - offs = 50.0 - assert self._scale is not None - p = [ - self._stick_nub_position[0] + x * offs * 0.6, - self._stick_nub_position[1] + y * offs * 0.6 - ] - c = list(self._stick_nub_image_color) - if abs(x) > 0.1 or abs(y) > 0.1: - c[0] *= 2.0 - c[1] *= 4.0 - c[2] *= 2.0 - assert self._stick_nub_image is not None - self._stick_nub_image.position = p - self._stick_nub_image.color = c - c = list(self._stick_base_image_color) - if abs(x) > 0.1 or abs(y) > 0.1: - c[0] *= 1.5 - c[1] *= 1.5 - c[2] *= 1.5 - assert self._stick_base_image is not None - self._stick_base_image.color = c + # Clamp this to a circle. + len_squared = x * x + y * y + if len_squared > 1.0: + length = math.sqrt(len_squared) + mult = 1.0 / length + x *= mult + y *= mult + + self.stick_image_position_x = x + self.stick_image_position_y = y + offs = 50.0 + assert self._scale is not None + p = [ + self._stick_nub_position[0] + x * offs * 0.6, + self._stick_nub_position[1] + y * offs * 0.6 + ] + c = list(self._stick_nub_image_color) + if abs(x) > 0.1 or abs(y) > 0.1: + c[0] *= 2.0 + c[1] *= 4.0 + c[2] *= 2.0 + assert self._stick_nub_image is not None + self._stick_nub_image.position = p + self._stick_nub_image.color = c + c = list(self._stick_base_image_color) + if abs(x) > 0.1 or abs(y) > 0.1: + c[0] *= 1.5 + c[1] *= 1.5 + c[2] *= 1.5 + assert self._stick_base_image is not None + self._stick_base_image.color = c + def on_begin(self, *args, **kwargs) -> None: self._jump_image = Image( ba.gettexture('buttonJump'), - position=(385,160), - scale=(50,50), - color=[0.1,0.45,0.1,0] + position=(385, 160), + scale=(50, 50), + color=[0.1, 0.45, 0.1, 0] ) self._pickup_image = Image( ba.gettexture('buttonPickUp'), - position=(385,240), - scale=(50,50), - color=[0,0.35,0,0] + position=(385, 240), + scale=(50, 50), + color=[0, 0.35, 0, 0] ) self._punch_image = Image( ba.gettexture('buttonPunch'), - position=(345,200), - scale=(50,50), - color=[0.45,0.45,0,0] + position=(345, 200), + scale=(50, 50), + color=[0.45, 0.45, 0, 0] ) self._bomb_image = Image( ba.gettexture('buttonBomb'), - position=(425,200), - scale=(50,50), - color=[0.45,0.1,0.1,0] + position=(425, 200), + scale=(50, 50), + color=[0.45, 0.1, 0.1, 0] ) self.stick_image_position_x = self.stick_image_position_y = 0.0 - self._stick_base_position = p = (-328,200) + self._stick_base_position = p = (-328, 200) self._stick_base_image_color = c2 = (0.25, 0.25, 0.25, 1.0) self._stick_base_image = ba.newnode( - 'image', - attrs={ - 'texture': ba.gettexture('nub'), - 'absolute_scale': True, - 'vr_depth': -40, - 'position': p, - 'scale': ( 220.0*0.6, 220.0*0.6), - 'color': c2 - }) + 'image', + attrs={ + 'texture': ba.gettexture('nub'), + 'absolute_scale': True, + 'vr_depth': -40, + 'position': p, + 'scale': (220.0*0.6, 220.0*0.6), + 'color': c2 + }) self._stick_nub_position = p = (-328, 200) self._stick_nub_image_color = c3 = (0.4, 0.4, 0.4, 1.0) self._stick_nub_image = ba.newnode('image', - attrs={ - 'texture': ba.gettexture('nub'), - 'absolute_scale': True, - 'position': p, - 'scale': (110*0.6, 110*0.66), - 'color': c3 - }) + attrs={ + 'texture': ba.gettexture('nub'), + 'absolute_scale': True, + 'position': p, + 'scale': (110*0.6, 110*0.66), + 'color': c3 + }) self._stick_base_image.opacity = 0.0 self._stick_nub_image.opacity = 0.0 self.set_stick_image_position = set_stick_image_position @@ -523,8 +537,6 @@ def on_app_running(self): bastd.actor.spaz.Spaz = NewSpaz - - # lets define a sample elimination game that can use super power of this plugin # ba_meta export game @@ -534,4 +546,4 @@ class BroEliminaition(EliminationGame): def spawn_player(self, player) -> ba.Actor: super().spawn_player(player) - spawn_mirror_spaz(player) \ No newline at end of file + spawn_mirror_spaz(player) From 6d4e1b6d91270ce4f539532957bbb31d1ee8e2f9 Mon Sep 17 00:00:00 2001 From: imayushsaini Date: Sat, 26 Nov 2022 12:33:01 +0000 Subject: [PATCH 0280/1464] [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 c64ba2d2..0b010ad5 100644 --- a/plugins/utilities.json +++ b/plugins/utilities.json @@ -313,7 +313,12 @@ } ], "versions": { - "1.0.0": null + "1.0.0": { + "api_version": 7, + "commit_sha": "7bc4d9e", + "released_on": "26-11-2022", + "md5sum": "0ef6342b43ca82cdfbb6276d6119a488" + } } }, "server_switch": { From 432c7a664e7c1fc989031a6d2a3399cc992039a1 Mon Sep 17 00:00:00 2001 From: Ayush Saini <36878972+imayushsaini@users.noreply.github.com> Date: Sat, 26 Nov 2022 18:04:59 +0530 Subject: [PATCH 0281/1464] removing logs print --- plugins/utilities/auto_stunt.py | 3 --- 1 file changed, 3 deletions(-) diff --git a/plugins/utilities/auto_stunt.py b/plugins/utilities/auto_stunt.py index 6a997b0b..91eb4ded 100644 --- a/plugins/utilities/auto_stunt.py +++ b/plugins/utilities/auto_stunt.py @@ -36,10 +36,7 @@ class ControlsUI: def on_jump_press(activity): - print("jumped pressed in UI control") - print(activity._jump_image.node.color) activity._jump_image.node.color = list(channel * 2 for channel in activity._jump_image.node.color[:3]) + [1] - print(activity._jump_image.node.color) def on_jump_release(activity): activity._jump_image.node.color = list(channel * 0.5 for channel in activity._jump_image.node.color[:3]) + [1] From dd7e00220c4e2600497b7a97cfbf891bc7ab12fe Mon Sep 17 00:00:00 2001 From: imayushsaini Date: Sat, 26 Nov 2022 12:36:30 +0000 Subject: [PATCH 0282/1464] [ci] auto-format --- plugins/utilities/auto_stunt.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/plugins/utilities/auto_stunt.py b/plugins/utilities/auto_stunt.py index 7ba8c98c..0b4ca11c 100644 --- a/plugins/utilities/auto_stunt.py +++ b/plugins/utilities/auto_stunt.py @@ -35,9 +35,10 @@ class ControlsUI: - + def on_jump_press(activity): - activity._jump_image.node.color = list(channel * 2 for channel in activity._jump_image.node.color[:3]) + [1] + activity._jump_image.node.color = list( + channel * 2 for channel in activity._jump_image.node.color[:3]) + [1] def on_jump_release(activity): activity._jump_image.node.color = list( From 6acdea837271401d63f791e20aba749020705946 Mon Sep 17 00:00:00 2001 From: Ayush Saini <36878972+imayushsaini@users.noreply.github.com> Date: Sat, 26 Nov 2022 18:10:23 +0530 Subject: [PATCH 0283/1464] resetting meta --- plugins/utilities.json | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/plugins/utilities.json b/plugins/utilities.json index 0b010ad5..c64ba2d2 100644 --- a/plugins/utilities.json +++ b/plugins/utilities.json @@ -313,12 +313,7 @@ } ], "versions": { - "1.0.0": { - "api_version": 7, - "commit_sha": "7bc4d9e", - "released_on": "26-11-2022", - "md5sum": "0ef6342b43ca82cdfbb6276d6119a488" - } + "1.0.0": null } }, "server_switch": { From 530adf99de5aa9e4364fdb81bdbdc0491fc459ef Mon Sep 17 00:00:00 2001 From: imayushsaini Date: Sat, 26 Nov 2022 12:41:10 +0000 Subject: [PATCH 0284/1464] [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 c64ba2d2..7478c974 100644 --- a/plugins/utilities.json +++ b/plugins/utilities.json @@ -313,7 +313,12 @@ } ], "versions": { - "1.0.0": null + "1.0.0": { + "api_version": 7, + "commit_sha": "6acdea8", + "released_on": "26-11-2022", + "md5sum": "3ced6731c0cbe79c972e7d1c7478ce16" + } } }, "server_switch": { From 3d5e24d49592de642e61f8b444e6aec0bfabf0f1 Mon Sep 17 00:00:00 2001 From: ! Freaku <92618708+Freaku17@users.noreply.github.com> Date: Wed, 30 Nov 2022 18:31:00 +0530 Subject: [PATCH 0285/1464] Switching to HTTPS (1/6 commits) --- plugin_manager.py | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/plugin_manager.py b/plugin_manager.py index e1db5b8a..2db4eae8 100644 --- a/plugin_manager.py +++ b/plugin_manager.py @@ -21,11 +21,8 @@ PLUGIN_MANAGER_VERSION = "0.1.7" -REPOSITORY_URL = "http://github.com/bombsquad-community/plugin-manager" +REPOSITORY_URL = "https://github.com/bombsquad-community/plugin-manager" CURRENT_TAG = "main" -# XXX: Using https with `ba.open_url` seems to trigger a pop-up dialog box on -# Android currently (v1.7.6) and won't open the actual URL in a web-browser. -# Let's fallback to http for now until this gets resolved. INDEX_META = "{repository_url}/{content_type}/{tag}/index.json" HEADERS = { "User-Agent": _env["user_agent_string"], @@ -36,7 +33,7 @@ "plugin_entry_points": re.compile(b"(ba_meta export plugin\n+class )(.*)\\("), "minigames": re.compile(b"(ba_meta export game\n+class )(.*)\\("), } -DISCORD_URL = "http://ballistica.net/discord" +DISCORD_URL = "https://ballistica.net/discord" _CACHE = {} From ed9271ebf50845982e6594bccd074471e57fd412 Mon Sep 17 00:00:00 2001 From: ! Freaku <92618708+Freaku17@users.noreply.github.com> Date: Wed, 30 Nov 2022 18:31:55 +0530 Subject: [PATCH 0286/1464] Switching to HTTPS (2/6) --- index.json | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/index.json b/index.json index e4e02ca9..471641af 100644 --- a/index.json +++ b/index.json @@ -1,5 +1,5 @@ { - "plugin_manager_url": "http://github.com/bombsquad-community/plugin-manager/{content_type}/{tag}/plugin_manager.py", + "plugin_manager_url": "https://github.com/bombsquad-community/plugin-manager/{content_type}/{tag}/plugin_manager.py", "versions": { "0.1.7": { "api_version": 7, @@ -27,9 +27,9 @@ } }, "categories": [ - "http://github.com/bombsquad-community/plugin-manager/{content_type}/{tag}/plugins/utilities.json", - "http://github.com/bombsquad-community/plugin-manager/{content_type}/{tag}/plugins/minigames.json", - "http://github.com/bombsquad-community/plugin-manager/{content_type}/{tag}/plugins/maps.json" + "https://github.com/bombsquad-community/plugin-manager/{content_type}/{tag}/plugins/utilities.json", + "https://github.com/bombsquad-community/plugin-manager/{content_type}/{tag}/plugins/minigames.json", + "https://github.com/bombsquad-community/plugin-manager/{content_type}/{tag}/plugins/maps.json" ], - "external_source_url": "http://github.com/{repository}/{content_type}/{tag}/category.json" -} \ No newline at end of file + "external_source_url": "https://github.com/{repository}/{content_type}/{tag}/category.json" +} From 1fe32a559d7bc6301e126ac6a1a517329e228f91 Mon Sep 17 00:00:00 2001 From: ! Freaku <92618708+Freaku17@users.noreply.github.com> Date: Wed, 30 Nov 2022 18:33:01 +0530 Subject: [PATCH 0287/1464] Switching to HTTPS (3/6) --- plugins/utilities.json | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/plugins/utilities.json b/plugins/utilities.json index f9fea7d7..48eefbe2 100644 --- a/plugins/utilities.json +++ b/plugins/utilities.json @@ -1,7 +1,7 @@ { "name": "Utilities", "description": "Utilities", - "plugins_base_url": "http://github.com/bombsquad-community/plugin-manager/{content_type}/{tag}/plugins/utilities", + "plugins_base_url": "https://github.com/bombsquad-community/plugin-manager/{content_type}/{tag}/plugins/utilities", "plugins": { "share_replay": { "description": "Export replays to mods folder and share them with friends or have a backup", @@ -161,7 +161,7 @@ }, "colorscheme": { "description": "Create custom UI colorschemes!", - "external_url": "http://www.youtube.com/watch?v=qatwWrBAvjc", + "external_url": "https://www.youtube.com/watch?v=qatwWrBAvjc", "authors": [ { "name": "Rikko", @@ -505,4 +505,4 @@ } } } -} \ No newline at end of file +} From 86bad1191a27573e19d97dda6526e1211488c453 Mon Sep 17 00:00:00 2001 From: ! Freaku <92618708+Freaku17@users.noreply.github.com> Date: Wed, 30 Nov 2022 18:33:39 +0530 Subject: [PATCH 0288/1464] Switching to HTTPS (4/6) --- plugins/minigames.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/plugins/minigames.json b/plugins/minigames.json index 4bfc4962..043ab546 100644 --- a/plugins/minigames.json +++ b/plugins/minigames.json @@ -1,7 +1,7 @@ { "name": "Minigames", "description": "Minigames", - "plugins_base_url": "http://github.com/bombsquad-community/plugin-manager/{content_type}/{tag}/plugins/minigames", + "plugins_base_url": "https://github.com/bombsquad-community/plugin-manager/{content_type}/{tag}/plugins/minigames", "plugins": { "soccer": { "description": "Shoot the ball in left or right edge of the map to score", @@ -251,4 +251,4 @@ } } } -} \ No newline at end of file +} From f9a429bfd9e1a540b73cd2c990a2fe3e0432539b Mon Sep 17 00:00:00 2001 From: ! Freaku <92618708+Freaku17@users.noreply.github.com> Date: Wed, 30 Nov 2022 18:34:29 +0530 Subject: [PATCH 0289/1464] Switching to HTTPS (5/6) --- plugins/maps.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/maps.json b/plugins/maps.json index 4aa26119..055d4b84 100644 --- a/plugins/maps.json +++ b/plugins/maps.json @@ -1,6 +1,6 @@ { "name": "Maps", "description": "Maps", - "plugins_base_url": "http://github.com/bombsquad-community/plugin-manager/{content_type}/{tag}/plugins/maps", + "plugins_base_url": "https://github.com/bombsquad-community/plugin-manager/{content_type}/{tag}/plugins/maps", "plugins": {} } From c1feee14ec81657029f00ccf9ca5afcfd998424d Mon Sep 17 00:00:00 2001 From: ! Freaku <92618708+Freaku17@users.noreply.github.com> Date: Wed, 30 Nov 2022 18:35:17 +0530 Subject: [PATCH 0290/1464] Switching to HTTPS (6/6) --- test/test_checks.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/test_checks.py b/test/test_checks.py index cddc1be1..a862f8f8 100644 --- a/test/test_checks.py +++ b/test/test_checks.py @@ -95,7 +95,7 @@ def setUp(self): def test_keys(self): self.assertEqual(self.content["name"], self.name) self.assertTrue(isinstance(self.content["description"], str)) - self.assertTrue(self.content["plugins_base_url"].startswith("http")) + self.assertTrue(self.content["plugins_base_url"].startswith("https")) self.assertTrue(isinstance(self.content["plugins"], dict)) def test_versions_order(self): From db3d79df5425198fe21b423069b84d53fbc0c267 Mon Sep 17 00:00:00 2001 From: Freaku17 Date: Wed, 30 Nov 2022 13:09:12 +0000 Subject: [PATCH 0291/1464] [ci] apply-version-metadata --- index.json | 2 +- plugins/minigames.json | 2 +- plugins/utilities.json | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/index.json b/index.json index 471641af..7236d714 100644 --- a/index.json +++ b/index.json @@ -32,4 +32,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/plugins/minigames.json b/plugins/minigames.json index 043ab546..b1fb800e 100644 --- a/plugins/minigames.json +++ b/plugins/minigames.json @@ -251,4 +251,4 @@ } } } -} +} \ No newline at end of file diff --git a/plugins/utilities.json b/plugins/utilities.json index 48eefbe2..42002717 100644 --- a/plugins/utilities.json +++ b/plugins/utilities.json @@ -505,4 +505,4 @@ } } } -} +} \ No newline at end of file From 54478c61851e082b06deb1ee085d0323157befe6 Mon Sep 17 00:00:00 2001 From: Rikko Date: Wed, 30 Nov 2022 19:58:38 +0530 Subject: [PATCH 0292/1464] Release v0.1.8 --- index.json | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/index.json b/index.json index 7236d714..01079d92 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.1.8": null, "0.1.7": { "api_version": 7, "commit_sha": "2fe966c", @@ -32,4 +33,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 31877d41994f6db031e084df8380b5a8a7451216 Mon Sep 17 00:00:00 2001 From: rikkolovescats Date: Wed, 30 Nov 2022 14:29:27 +0000 Subject: [PATCH 0293/1464] [ci] apply-version-metadata --- index.json | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/index.json b/index.json index 01079d92..1efd5227 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.1.8": null, + "0.1.8": { + "api_version": 7, + "commit_sha": "54478c6", + "released_on": "30-11-2022", + "md5sum": "2c67cd2405e4e34e1a3b6dfc30c8dc74" + }, "0.1.7": { "api_version": 7, "commit_sha": "2fe966c", @@ -33,4 +38,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 bbce3bdb7b2de54939b1982ed8927aa08a1730ce Mon Sep 17 00:00:00 2001 From: Rikko Date: Wed, 30 Nov 2022 20:00:44 +0530 Subject: [PATCH 0294/1464] Bump source to v0.1.8 --- index.json | 9 ++------- plugin_manager.py | 2 +- 2 files changed, 3 insertions(+), 8 deletions(-) diff --git a/index.json b/index.json index 1efd5227..01079d92 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.1.8": { - "api_version": 7, - "commit_sha": "54478c6", - "released_on": "30-11-2022", - "md5sum": "2c67cd2405e4e34e1a3b6dfc30c8dc74" - }, + "0.1.8": null, "0.1.7": { "api_version": 7, "commit_sha": "2fe966c", @@ -38,4 +33,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 2db4eae8..cd794df2 100644 --- a/plugin_manager.py +++ b/plugin_manager.py @@ -20,7 +20,7 @@ _uiscale = ba.app.ui.uiscale -PLUGIN_MANAGER_VERSION = "0.1.7" +PLUGIN_MANAGER_VERSION = "0.1.8" REPOSITORY_URL = "https://github.com/bombsquad-community/plugin-manager" CURRENT_TAG = "main" INDEX_META = "{repository_url}/{content_type}/{tag}/index.json" From 41f96ac428ec983b3a9a7e727fc7d498e7a6ab11 Mon Sep 17 00:00:00 2001 From: rikkolovescats Date: Wed, 30 Nov 2022 14:31:25 +0000 Subject: [PATCH 0295/1464] [ci] apply-version-metadata --- index.json | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/index.json b/index.json index 01079d92..33245fb8 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.1.8": null, + "0.1.8": { + "api_version": 7, + "commit_sha": "bbce3bd", + "released_on": "30-11-2022", + "md5sum": "0218c7d6b08896f18479467fdd45aa27" + }, "0.1.7": { "api_version": 7, "commit_sha": "2fe966c", @@ -33,4 +38,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 0b499f92fe63d64c90bc8763c3a93cf3c4f44191 Mon Sep 17 00:00:00 2001 From: Rikko Date: Sat, 3 Dec 2022 21:04:51 +0530 Subject: [PATCH 0296/1464] Plugin search now works on author names, description --- index.json | 3 ++- plugin_manager.py | 36 +++++++++++++++++++++++------------- 2 files changed, 25 insertions(+), 14 deletions(-) diff --git a/index.json b/index.json index 33245fb8..da678bcc 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.1.9": null, "0.1.8": { "api_version": 7, "commit_sha": "bbce3bd", @@ -38,4 +39,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 cd794df2..4f6a21b7 100644 --- a/plugin_manager.py +++ b/plugin_manager.py @@ -20,7 +20,7 @@ _uiscale = ba.app.ui.uiscale -PLUGIN_MANAGER_VERSION = "0.1.8" +PLUGIN_MANAGER_VERSION = "0.1.9" REPOSITORY_URL = "https://github.com/bombsquad-community/plugin-manager" CURRENT_TAG = "main" INDEX_META = "{repository_url}/{content_type}/{tag}/index.json" @@ -1441,9 +1441,9 @@ def draw_search_bar(self): self._last_filter_text = None self._last_filter_plugins = [] loop = asyncio.get_event_loop() - loop.create_task(self.process_search_filter()) + loop.create_task(self.process_search_term()) - async def process_search_filter(self): + async def process_search_term(self): while True: await asyncio.sleep(0.2) try: @@ -1454,7 +1454,7 @@ async def process_search_filter(self): if self.selected_category is None: continue try: - await self.draw_plugin_names(self.selected_category, search_filter=filter_text) + await self.draw_plugin_names(self.selected_category, search_term=filter_text) except CategoryDoesNotExistError: pass # XXX: This may be more efficient, but we need a way to get a plugin's textwidget @@ -1515,6 +1515,16 @@ def draw_refresh_icon(self): texture=ba.gettexture("replayIcon"), draw_controller=controller_button) + def search_term_filterer(self, plugin, search_term): + if search_term in plugin.name: + return True + if search_term in plugin.info["description"].lower(): + return True + for author in plugin.info["authors"]: + if search_term in author["name"].lower(): + return True + return False + # async def draw_plugin_names(self, category): # for plugin in self._columnwidget.get_children(): # plugin.delete() @@ -1524,8 +1534,9 @@ def draw_refresh_icon(self): # await asyncio.gather(*plugin_names_to_draw) # XXX: Not sure if this is the best way to handle search filters. - async def draw_plugin_names(self, category, search_filter=""): - to_draw_plugin_names = (search_filter, category) != (self._last_filter_text, + async def draw_plugin_names(self, category, search_term=""): + # Re-draw plugin list UI if either search term or category was switched. + to_draw_plugin_names = (search_term, category) != (self._last_filter_text, self.selected_category) if not to_draw_plugin_names: return @@ -1535,18 +1546,17 @@ async def draw_plugin_names(self, category, search_filter=""): except (KeyError, AttributeError): raise CategoryDoesNotExistError(f"{category} does not exist.") - if search_filter: - plugins = [] - for plugin in category_plugins: - if search_filter in plugin.name: - plugins.append(plugin) + if search_term: + search_term_filterer = lambda plugin: self.search_term_filterer(plugin, search_term) + plugins = filter(search_term_filterer, category_plugins) else: plugins = category_plugins if plugins == self._last_filter_plugins: + # Plugins names to draw on UI are already drawn. return - self._last_filter_text = search_filter + self._last_filter_text = search_term self._last_filter_plugins = plugins plugin_names_to_draw = tuple(self.draw_plugin_name(plugin) for plugin in plugins) @@ -1613,7 +1623,7 @@ def show_categories_window(self): async def select_category(self, category): self.plugins_in_current_view.clear() self.draw_category_selection_button(post_label=category) - await self.draw_plugin_names(category, search_filter=self._last_filter_text) + await self.draw_plugin_names(category, search_term=self._last_filter_text) self.selected_category = category def cleanup(self): From 09b6832007b1639377a4293ed88af0af02a67e51 Mon Sep 17 00:00:00 2001 From: rikkolovescats Date: Sat, 3 Dec 2022 15:37:23 +0000 Subject: [PATCH 0297/1464] [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 4f6a21b7..749e46a4 100644 --- a/plugin_manager.py +++ b/plugin_manager.py @@ -1537,7 +1537,7 @@ def search_term_filterer(self, plugin, search_term): async def draw_plugin_names(self, category, search_term=""): # Re-draw plugin list UI if either search term or category was switched. to_draw_plugin_names = (search_term, category) != (self._last_filter_text, - self.selected_category) + self.selected_category) if not to_draw_plugin_names: return @@ -1547,7 +1547,7 @@ async def draw_plugin_names(self, category, search_term=""): raise CategoryDoesNotExistError(f"{category} does not exist.") if search_term: - search_term_filterer = lambda plugin: self.search_term_filterer(plugin, search_term) + def search_term_filterer(plugin): return self.search_term_filterer(plugin, search_term) plugins = filter(search_term_filterer, category_plugins) else: plugins = category_plugins From a1ecf74e1235852e494970713d12c7bcf4ce18c1 Mon Sep 17 00:00:00 2001 From: rikkolovescats Date: Sat, 3 Dec 2022 15:37:24 +0000 Subject: [PATCH 0298/1464] [ci] apply-version-metadata --- index.json | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/index.json b/index.json index da678bcc..d2dd7bd8 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.1.9": null, + "0.1.9": { + "api_version": 7, + "commit_sha": "09b6832", + "released_on": "03-12-2022", + "md5sum": "2582a1b8448b84d17b739caeeaad51e1" + }, "0.1.8": { "api_version": 7, "commit_sha": "bbce3bd", @@ -39,4 +44,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 b4e71a7529c36d554024baca1ac395b47949d2ec Mon Sep 17 00:00:00 2001 From: Rikko Date: Sat, 3 Dec 2022 21:14:35 +0530 Subject: [PATCH 0299/1464] Update CHANGELOG.md --- CHANGELOG.md | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index ed4f1f91..c43cf27b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,12 @@ ## Plugin Manager (dd-mm-yyyy) +### 0.1.9 (03-12-2022) + +- Search now filters on author names and plugin description. + +### 0.1.8 (30-11-2022) + +- Use HTTPS for all network requests (now that the Android bug has been resolved as of v1.7.11). ### 0.1.7 (03-10-2022) From fed7c24251372a0a266b9946eb263e24663c1a85 Mon Sep 17 00:00:00 2001 From: Rikko Date: Sat, 3 Dec 2022 21:18:02 +0530 Subject: [PATCH 0300/1464] Rename plugin random_colors to a more descriptive name --- plugins/utilities.json | 4 ++-- .../{random_colors.py => colored_bomb_explosion_patches.py} | 0 2 files changed, 2 insertions(+), 2 deletions(-) rename plugins/utilities/{random_colors.py => colored_bomb_explosion_patches.py} (100%) diff --git a/plugins/utilities.json b/plugins/utilities.json index 42002717..dd045e72 100644 --- a/plugins/utilities.json +++ b/plugins/utilities.json @@ -85,7 +85,7 @@ } } }, - "random_colors": { + "colored_bomb_explosion_patches": { "description": "Creates patches of random color after bomb explosions", "external_url": "https://youtube.com/c/JoseANG3LYT", "authors": [ @@ -505,4 +505,4 @@ } } } -} \ No newline at end of file +} diff --git a/plugins/utilities/random_colors.py b/plugins/utilities/colored_bomb_explosion_patches.py similarity index 100% rename from plugins/utilities/random_colors.py rename to plugins/utilities/colored_bomb_explosion_patches.py From 7e9136a0ab1bd033f8ad94437c88b45f2f24d2d0 Mon Sep 17 00:00:00 2001 From: rikkolovescats Date: Sat, 3 Dec 2022 15:48:41 +0000 Subject: [PATCH 0301/1464] [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 dd045e72..f6ca2865 100644 --- a/plugins/utilities.json +++ b/plugins/utilities.json @@ -505,4 +505,4 @@ } } } -} +} \ No newline at end of file From 3a90d47038105f821e4e1ea2469af6542917bdd4 Mon Sep 17 00:00:00 2001 From: Rikko Date: Sat, 3 Dec 2022 21:20:31 +0530 Subject: [PATCH 0302/1464] Update commit sha --- plugins/utilities.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/plugins/utilities.json b/plugins/utilities.json index f6ca2865..01028314 100644 --- a/plugins/utilities.json +++ b/plugins/utilities.json @@ -98,7 +98,7 @@ "versions": { "1.0.0": { "api_version": 7, - "commit_sha": "2fda676", + "commit_sha": "fed7c24", "released_on": "07-11-2022", "md5sum": "0c351a0aebed77c3771053cde0c18d7b" } @@ -505,4 +505,4 @@ } } } -} \ No newline at end of file +} From 89a4422019f61b6cab7bee2db141fb34c40f518c Mon Sep 17 00:00:00 2001 From: rikkolovescats Date: Sat, 3 Dec 2022 15:51:04 +0000 Subject: [PATCH 0303/1464] [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 01028314..cc85ca10 100644 --- a/plugins/utilities.json +++ b/plugins/utilities.json @@ -505,4 +505,4 @@ } } } -} +} \ No newline at end of file From 0e63428bba9542b3dba1662deebc26d5baaf9ee1 Mon Sep 17 00:00:00 2001 From: Loup <90267658+Loup-Garou911XD@users.noreply.github.com> Date: Sun, 4 Dec 2022 00:27:03 +0530 Subject: [PATCH 0304/1464] Updated utilities.json for share replay 1.2.0 --- plugins/utilities.json | 6 ++ plugins/utilities/share_replay.py | 108 +++++++++--------------------- 2 files changed, 36 insertions(+), 78 deletions(-) diff --git a/plugins/utilities.json b/plugins/utilities.json index cc85ca10..31195fae 100644 --- a/plugins/utilities.json +++ b/plugins/utilities.json @@ -14,6 +14,12 @@ } ], "versions": { + "1.2.0": { + "api_version": 7, + "commit_sha": "9a899d0", + "released_on": "04-12-2022", + "md5sum": "f74e2bb80a62bef20f491377324ffbeb" + }, "1.1.0": { "api_version": 7, "commit_sha": "77f92a5", diff --git a/plugins/utilities/share_replay.py b/plugins/utilities/share_replay.py index 203a4ccc..1a394939 100644 --- a/plugins/utilities/share_replay.py +++ b/plugins/utilities/share_replay.py @@ -9,6 +9,9 @@ import ba 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.popup import PopupWindow @@ -33,12 +36,9 @@ def cprint(*args): title = "SHARE REPLAY" -internal_dir = path.join("ba_data", "..", "..", "..", "files", "bombsquad_config", "replays" + sep) +internal_dir = _ba.get_replays_dir()+sep external_dir = path.join(_ba.env()["python_directory_user"], "replays"+sep) -tab_sel_texture = ba.gettexture("buttonSquare") -tab_unsel_texture = ba.gettexture("chestIconEmpty") - # colors pink = (1, 0.2, 0.8) green = (0.4, 1, 0.4) @@ -64,33 +64,7 @@ def __init__(self): 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") - - def close(self): - ba.playsound(ba.getsound('swish')) - ba.containerwidget(edit=self.root_widget, transition="out_right",) - - -class SyncConfirmation(PopupWindow): - def __init__(self): - uiscale = ba.app.ui.uiscale - self.width = 600 - self.height = 300 - PopupWindow.__init__(self, - position=(0.0, 0.0), - size=(self.width, self.height), - scale=1.2,) - - ba.textwidget(parent=self.root_widget, position=(30, self.height * 0.8), - text=" Are you sure you want to continue\n\nWARNING:replays with same name in mods folder\n will be overwritten") - cancel = ba.buttonwidget(parent=self.root_widget, label=ba.Lstr( - resource='cancelText'), size=(200, 80), position=(80, 50), on_activate_call=self.close) - - ba.buttonwidget(parent=self.root_widget, label=ba.Lstr(resource='okText'), size=( - 200, 80), position=(300, 50), color=green, on_activate_call=SettingWindow.sync) - - ba.containerwidget(edit=self.root_widget, - on_outside_click_call=self.close, cancel_button=cancel) + 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)") def close(self): ba.playsound(ba.getsound('swish')) @@ -99,12 +73,20 @@ def close(self): class SettingWindow(): def __init__(self): - global internal self.draw_ui() ba.containerwidget(edit=self.root, cancel_button=self.close_button) self.selected_name = None - internal = True - self.on_tab_select(internal) + # 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" + + 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() @@ -113,30 +95,23 @@ def on_select_text(self, widget, name): ba.textwidget(edit=widget, color=(1, 1, 0)) self.selected_name = name - def on_tab_select(self, _internal): - global internal - internal = _internal - if internal == True: + 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"),) - sel = self.internal_tab - unsel = self.external_tab else: dir_list = listdir(external_dir) ba.buttonwidget(edit=self.share_button, label="IMPORT", icon=ba.gettexture("downButton"),) - sel = self.external_tab - unsel = self.internal_tab - - ba.buttonwidget(edit=sel, texture=tab_sel_texture, color=blue, size=(120, 80)) - ba.buttonwidget(edit=unsel, texture=tab_unsel_texture, color=blue, size=(120, 100)) - + 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 @@ -147,6 +122,7 @@ def on_tab_select(self, _internal): 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)) @@ -183,33 +159,9 @@ def draw_ui(self): label="", on_activate_call=Help) - internal_tab_pos = 85, 400 - internal_tab_size = 120, 80 - external_tab_pos = 85, 300 - external_tab_size = 120, 80 - - self.internal_tab = ba.buttonwidget( - parent=self.root, - position=internal_tab_pos, - size=internal_tab_size, - button_type="square", - label="INTERNAL", - text_scale=2, - color=blue_highlight, - texture=tab_sel_texture) - - self.external_tab = ba.buttonwidget( - parent=self.root, - position=external_tab_pos, - size=external_tab_size, - button_type="square", - label="EXTERNAL", - text_scale=2, - color=blue, - texture=tab_unsel_texture) - - ba.buttonwidget(edit=self.internal_tab, on_activate_call=ba.Call(self.on_tab_select, True)) - ba.buttonwidget(edit=self.external_tab, on_activate_call=ba.Call(self.on_tab_select, False)) + 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, @@ -231,12 +183,12 @@ def draw_ui(self): label="SYNC", text_scale=2, icon=ba.gettexture("ouyaYButton"), - on_activate_call=SyncConfirmation) + on_activate_call=self.sync_confirmation) scroll = ba.scrollwidget( parent=self.root, - size=(500, 400), - position=(200, 100),) + size=(600, 400), + position=(100, 100),) self.scroll2 = ba.columnwidget(parent=scroll, size=( 500, 900)) @@ -244,14 +196,14 @@ def share(self): if self.selected_name is None: Print("Select a replay", color=red) return - if internal: + 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=""): + def sync(self): internal_list = listdir(internal_dir) external_list = listdir(external_dir) for i in internal_list: From f07d2f8228116ea27197872a493e5257758fb8ff Mon Sep 17 00:00:00 2001 From: Loup <90267658+Loup-Garou911XD@users.noreply.github.com> Date: Sun, 4 Dec 2022 19:51:29 +0530 Subject: [PATCH 0305/1464] Removed meta for 1.2.0 --- plugins/utilities.json | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/plugins/utilities.json b/plugins/utilities.json index 31195fae..d6834105 100644 --- a/plugins/utilities.json +++ b/plugins/utilities.json @@ -14,12 +14,7 @@ } ], "versions": { - "1.2.0": { - "api_version": 7, - "commit_sha": "9a899d0", - "released_on": "04-12-2022", - "md5sum": "f74e2bb80a62bef20f491377324ffbeb" - }, + "1.2.0": null, "1.1.0": { "api_version": 7, "commit_sha": "77f92a5", @@ -511,4 +506,4 @@ } } } -} \ No newline at end of file +} From 70db2075f85a6eccde21e753f4fb8556db21ca0b Mon Sep 17 00:00:00 2001 From: Loup-Garou911XD Date: Sun, 4 Dec 2022 14:21:50 +0000 Subject: [PATCH 0306/1464] [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 d6834105..840222b4 100644 --- a/plugins/utilities.json +++ b/plugins/utilities.json @@ -14,7 +14,12 @@ } ], "versions": { - "1.2.0": null, + "1.2.0": { + "api_version": 7, + "commit_sha": "f07d2f8", + "released_on": "04-12-2022", + "md5sum": "f74e2bb80a62bef20f491377324ffbeb" + }, "1.1.0": { "api_version": 7, "commit_sha": "77f92a5", @@ -506,4 +511,4 @@ } } } -} +} \ No newline at end of file From 0d03b1beced75d9e4822d41c119ddce2b102effe Mon Sep 17 00:00:00 2001 From: Loup <90267658+Loup-Garou911XD@users.noreply.github.com> Date: Mon, 5 Dec 2022 13:16:01 +0530 Subject: [PATCH 0307/1464] Added discord and GitHub textures on button --- index.json | 6 ++++++ plugin_manager.py | 55 +++++++++++++++++++++++++++++++---------------- 2 files changed, 43 insertions(+), 18 deletions(-) diff --git a/index.json b/index.json index d2dd7bd8..8ebb3fd0 100644 --- a/index.json +++ b/index.json @@ -1,6 +1,12 @@ { "plugin_manager_url": "https://github.com/bombsquad-community/plugin-manager/{content_type}/{tag}/plugin_manager.py", "versions": { + "0.1.10": { + "api_version": 7, + "commit_sha": "21e58a1", + "released_on": "05-12-2022", + "md5sum": "d6c963bf62e5bfdcd3d83ff44b58f855" + }, "0.1.9": { "api_version": 7, "commit_sha": "09b6832", diff --git a/plugin_manager.py b/plugin_manager.py index 749e46a4..9e32364a 100644 --- a/plugin_manager.py +++ b/plugin_manager.py @@ -20,7 +20,7 @@ _uiscale = ba.app.ui.uiscale -PLUGIN_MANAGER_VERSION = "0.1.9" +PLUGIN_MANAGER_VERSION = "0.1.10" REPOSITORY_URL = "https://github.com/bombsquad-community/plugin-manager" CURRENT_TAG = "main" INDEX_META = "{repository_url}/{content_type}/{tag}/index.json" @@ -1665,10 +1665,12 @@ async def draw_ui(self): width = 380 * s height = 150 + 150 * s color = (0.9, 0.9, 0.9) + discord_bg_color = ba.normalized_color((88, 101, 242)) + github_bg_color = (0.2, 0.2, 0.2) text_scale = 0.7 * s self._transition_out = 'out_scale' transition = 'in_scale' - button_size = (60 * s, 32 * s) + button_size = (32 * s, 32 * s) # index = await self._plugin_manager.get_index() self._root_widget = ba.containerwidget(size=(width, height), # parent=_ba.get_special_widget( @@ -1727,23 +1729,40 @@ async def draw_ui(self): maxwidth=width * 0.95) pos -= 75 - ba.buttonwidget(parent=self._root_widget, - position=((width * 0.20) - button_size[0] / 2, pos), - size=button_size, - on_activate_call=lambda: ba.open_url(DISCORD_URL), - textcolor=b_text_color, - button_type='square', - text_scale=1, - label='Discord') + self.discord_button = ba.buttonwidget(parent=self._root_widget, + position=((width * 0.20) - button_size[0] / 2, pos), + size=button_size, + on_activate_call=lambda: ba.open_url(DISCORD_URL), + textcolor=b_text_color, + color=discord_bg_color, + button_type='square', + text_scale=1, + label="") + + ba.imagewidget(parent=self._root_widget, + position=((width * 0.20)+0.5 - button_size[0] / 2, pos), + size=button_size, + texture=ba.gettexture("discordLogo"), + color=(10, 10, 10), + draw_controller=self.discord_button) + + self.github_button = ba.buttonwidget(parent=self._root_widget, + position=((width * 0.49) - button_size[0] / 2, pos), + size=button_size, + on_activate_call=lambda: ba.open_url(REPOSITORY_URL), + textcolor=b_text_color, + color=github_bg_color, + button_type='square', + text_scale=1, + label='') + + ba.imagewidget(parent=self._root_widget, + position=((width * 0.49) + 0.5 - button_size[0] / 2, pos), + size=button_size, + texture=ba.gettexture("githubLogo"), + color=(1, 1, 1), + draw_controller=self.github_button) - ba.buttonwidget(parent=self._root_widget, - position=((width * 0.49) - button_size[0] / 2, pos), - size=button_size, - on_activate_call=lambda: ba.open_url(REPOSITORY_URL), - textcolor=b_text_color, - button_type='square', - text_scale=1, - label='GitHub') ba.containerwidget(edit=self._root_widget, on_cancel_call=self._ok) From 7700ee1a7dde8ad5e92cb341faa3644866daf6f2 Mon Sep 17 00:00:00 2001 From: Loup <90267658+Loup-Garou911XD@users.noreply.github.com> Date: Mon, 5 Dec 2022 17:34:45 +0530 Subject: [PATCH 0308/1464] Removed metadata for v0.1.10 --- index.json | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/index.json b/index.json index 8ebb3fd0..5de1fc61 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.1.10": { - "api_version": 7, - "commit_sha": "21e58a1", - "released_on": "05-12-2022", - "md5sum": "d6c963bf62e5bfdcd3d83ff44b58f855" - }, + "0.1.10": null, "0.1.9": { "api_version": 7, "commit_sha": "09b6832", @@ -50,4 +45,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 eb20b171a5554faffd96c9d8fde3f347ddeb44b8 Mon Sep 17 00:00:00 2001 From: Loup-Garou911XD Date: Mon, 5 Dec 2022 12:05:13 +0000 Subject: [PATCH 0309/1464] [ci] apply-version-metadata --- index.json | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/index.json b/index.json index 5de1fc61..d4118fc5 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.1.10": null, + "0.1.10": { + "api_version": 7, + "commit_sha": "7700ee1", + "released_on": "05-12-2022", + "md5sum": "d6c963bf62e5bfdcd3d83ff44b58f855" + }, "0.1.9": { "api_version": 7, "commit_sha": "09b6832", @@ -45,4 +50,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 e122d0f709deb916ce26e83b206b80b3f3a879f0 Mon Sep 17 00:00:00 2001 From: Rikko Date: Mon, 5 Dec 2022 20:55:07 +0530 Subject: [PATCH 0310/1464] Slight color changes --- index.json | 9 ++------- plugin_manager.py | 10 +++++++--- 2 files changed, 9 insertions(+), 10 deletions(-) diff --git a/index.json b/index.json index d4118fc5..5de1fc61 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.1.10": { - "api_version": 7, - "commit_sha": "7700ee1", - "released_on": "05-12-2022", - "md5sum": "d6c963bf62e5bfdcd3d83ff44b58f855" - }, + "0.1.10": null, "0.1.9": { "api_version": 7, "commit_sha": "09b6832", @@ -50,4 +45,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 9e32364a..1ee0277c 100644 --- a/plugin_manager.py +++ b/plugin_manager.py @@ -1665,8 +1665,12 @@ async def draw_ui(self): width = 380 * s height = 150 + 150 * s color = (0.9, 0.9, 0.9) - discord_bg_color = ba.normalized_color((88, 101, 242)) - github_bg_color = (0.2, 0.2, 0.2) + + # Subtracting the default bluish-purple color from the texture, so it's as close + # as to white as possible. + discord_fg_color = (10 - 0.32, 10 - 0.39, 10 - 0.96) + discord_bg_color = (0.525, 0.595, 1.458) + github_bg_color = (0.23, 0.23, 0.23) text_scale = 0.7 * s self._transition_out = 'out_scale' transition = 'in_scale' @@ -1743,7 +1747,7 @@ async def draw_ui(self): position=((width * 0.20)+0.5 - button_size[0] / 2, pos), size=button_size, texture=ba.gettexture("discordLogo"), - color=(10, 10, 10), + color=discord_fg_color, draw_controller=self.discord_button) self.github_button = ba.buttonwidget(parent=self._root_widget, From dca85dc1a2f81c1d2497b82541b0848d99ea1ba1 Mon Sep 17 00:00:00 2001 From: rikkolovescats Date: Mon, 5 Dec 2022 15:25:59 +0000 Subject: [PATCH 0311/1464] [ci] apply-version-metadata --- index.json | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/index.json b/index.json index 5de1fc61..319c43a0 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.1.10": null, + "0.1.10": { + "api_version": 7, + "commit_sha": "e122d0f", + "released_on": "05-12-2022", + "md5sum": "6e1ea3e593f1230e527c583e16d96595" + }, "0.1.9": { "api_version": 7, "commit_sha": "09b6832", @@ -45,4 +50,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 6b7307a8c56417f399a718c92e89cedc379edd1a Mon Sep 17 00:00:00 2001 From: Rikko Date: Mon, 5 Dec 2022 21:09:01 +0530 Subject: [PATCH 0312/1464] Yay, i taught it to sort! --- test/test_checks.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/test/test_checks.py b/test/test_checks.py index a862f8f8..d338419d 100644 --- a/test/test_checks.py +++ b/test/test_checks.py @@ -7,6 +7,8 @@ import os import pathlib +from distutils.version import StrictVersion + import unittest @@ -31,7 +33,7 @@ def test_versions_order(self): versions = list(self.content["versions"].items()) sorted_versions = sorted( versions, - key=lambda version: version[0], + key=lambda version: StrictVersion(version[0]), reverse=True, ) assert sorted_versions == versions @@ -103,7 +105,7 @@ def test_versions_order(self): versions = list(plugin_metadata["versions"].items()) sorted_versions = sorted( versions, - key=lambda version: version[0], + key=lambda version: StrictVersion(version[0]), reverse=True, ) self.assertEqual(sorted_versions, versions) From 6aa0f6f677bc13a7b378cd60e1076f4febeb74c9 Mon Sep 17 00:00:00 2001 From: ! Freaku <92618708+Freaku17@users.noreply.github.com> Date: Mon, 5 Dec 2022 21:39:08 +0530 Subject: [PATCH 0313/1464] Replace `on_plugin_manager_prompt` to default plugin setting ui --- plugin_manager.py | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/plugin_manager.py b/plugin_manager.py index 1ee0277c..adc48a2a 100644 --- a/plugin_manager.py +++ b/plugin_manager.py @@ -20,7 +20,7 @@ _uiscale = ba.app.ui.uiscale -PLUGIN_MANAGER_VERSION = "0.1.10" +PLUGIN_MANAGER_VERSION = "0.2.0" REPOSITORY_URL = "https://github.com/bombsquad-community/plugin-manager" CURRENT_TAG = "main" INDEX_META = "{repository_url}/{content_type}/{tag}/index.json" @@ -364,13 +364,13 @@ def _set_content(self, content): def has_settings(self): for plugin_entry_point, plugin_class in ba.app.plugins.active_plugins.items(): if plugin_entry_point.startswith(self._entry_point_initials): - return hasattr(plugin_class, "on_plugin_manager_prompt") + return hasattr(plugin_class, "has_settings_ui") return False - def launch_settings(self): + def launch_settings(self, source_widget): for plugin_entry_point, plugin_class in ba.app.plugins.active_plugins.items(): if plugin_entry_point.startswith(self._entry_point_initials): - return plugin_class.on_plugin_manager_prompt() + return plugin_class.show_settings_ui(source_widget) async def get_content(self): if self._content is None: @@ -851,8 +851,10 @@ async def draw_ui(self): size=(40, 40), button_type="square", label="", - color=(0, 0.75, 0.75), - on_activate_call=self.settings) + color=(0, 0.75, 0.75),) + ba.buttonwidget( + edit=settings_button, + on_activate_call=ba.Call(self.settings, settings_button),) ba.imagewidget(parent=self._root_widget, position=(settings_pos_x, settings_pos_y), size=(40, 40), @@ -883,8 +885,8 @@ def wrapper(self, *args, **kwargs): return wrapper - def settings(self): - self.local_plugin.launch_settings() + def settings(self, source_widget): + self.local_plugin.launch_settings(source_widget) @button def disable(self) -> None: From 51614b7fa1fa4e280d8f1c31a2a6dacf77c6ebae Mon Sep 17 00:00:00 2001 From: ! Freaku <92618708+Freaku17@users.noreply.github.com> Date: Mon, 5 Dec 2022 21:41:03 +0530 Subject: [PATCH 0314/1464] Remove old functions used in plugins --- plugins/utilities/colorscheme.py | 5 ++++- plugins/utilities/mood_light.py | 2 +- plugins/utilities/share_replay.py | 3 --- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/plugins/utilities/colorscheme.py b/plugins/utilities/colorscheme.py index 6e427173..bd4e4c5f 100644 --- a/plugins/utilities/colorscheme.py +++ b/plugins/utilities/colorscheme.py @@ -445,5 +445,8 @@ class Main(ba.Plugin): def on_app_running(self): load_plugin() - def on_plugin_manager_prompt(self): + def has_settings_ui(self): + return True + + def show_settings_ui(self, source_widget): launch_colorscheme_selection_window() diff --git a/plugins/utilities/mood_light.py b/plugins/utilities/mood_light.py index 225df54b..cb94021f 100644 --- a/plugins/utilities/mood_light.py +++ b/plugins/utilities/mood_light.py @@ -287,7 +287,7 @@ def __init__(self): def on_app_running(self): _ba.show_progress_bar() - def on_plugin_manager_prompt(self): + def show_settings_ui(self, source_widget): SettingWindow() def has_settings_ui(self): diff --git a/plugins/utilities/share_replay.py b/plugins/utilities/share_replay.py index 1a394939..99098164 100644 --- a/plugins/utilities/share_replay.py +++ b/plugins/utilities/share_replay.py @@ -262,6 +262,3 @@ def has_settings_ui(self): def show_settings_ui(self, button): SettingWindow() - - def on_plugin_manager_prompt(self): - SettingWindow() From 536ed382ad301a0249ccddd9d0f116fb5b1d9e05 Mon Sep 17 00:00:00 2001 From: ! Freaku <92618708+Freaku17@users.noreply.github.com> Date: Mon, 5 Dec 2022 21:41:45 +0530 Subject: [PATCH 0315/1464] Update utilities.json --- plugins/utilities.json | 3 +++ 1 file changed, 3 insertions(+) diff --git a/plugins/utilities.json b/plugins/utilities.json index 840222b4..f29e12dd 100644 --- a/plugins/utilities.json +++ b/plugins/utilities.json @@ -14,6 +14,7 @@ } ], "versions": { + "1.2.1": null, "1.2.0": { "api_version": 7, "commit_sha": "f07d2f8", @@ -145,6 +146,7 @@ } ], "versions": { + "1.2.2": null, "1.2.1": { "api_version": 7, "commit_sha": "2fda676", @@ -181,6 +183,7 @@ } ], "versions": { + "1.2.3": null, "1.2.2": { "api_version": 7, "commit_sha": "a6d1a43", From 1d5f0a742223bf8c3e647c09e7d7d4b171487cad Mon Sep 17 00:00:00 2001 From: ! Freaku <92618708+Freaku17@users.noreply.github.com> Date: Mon, 5 Dec 2022 21:42:01 +0530 Subject: [PATCH 0316/1464] Update index.json --- index.json | 1 + 1 file changed, 1 insertion(+) diff --git a/index.json b/index.json index 319c43a0..e864e580 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.0": null, "0.1.10": { "api_version": 7, "commit_sha": "e122d0f", From 7753b87d7fcb8df726e4268992094e7b4c3fcb59 Mon Sep 17 00:00:00 2001 From: ! Freaku <92618708+Freaku17@users.noreply.github.com> Date: Mon, 5 Dec 2022 21:43:11 +0530 Subject: [PATCH 0317/1464] Update CHANGELOG.md --- CHANGELOG.md | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index c43cf27b..63fb9e3d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,13 @@ ## Plugin Manager (dd-mm-yyyy) +### 0.2.0 (05-12-2022) + +- Removed `on_plugin_manager_prompt` and replaced it with the in-game's plugin settings ui + +### 0.1.10 (05-12-2022) + +- Added Discord and Github textures on buttons + ### 0.1.9 (03-12-2022) - Search now filters on author names and plugin description. From 38c79385b3d1b77ae3ae89afdf1f72024838599c Mon Sep 17 00:00:00 2001 From: Freaku17 Date: Mon, 5 Dec 2022 16:14:33 +0000 Subject: [PATCH 0318/1464] [ci] apply-version-metadata --- index.json | 7 ++++++- plugins/utilities.json | 21 ++++++++++++++++++--- 2 files changed, 24 insertions(+), 4 deletions(-) diff --git a/index.json b/index.json index e864e580..c9f331b7 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.0": null, + "0.2.0": { + "api_version": 7, + "commit_sha": "7753b87", + "released_on": "05-12-2022", + "md5sum": "ee88d457a66ac0689624f6dc72d27c1c" + }, "0.1.10": { "api_version": 7, "commit_sha": "e122d0f", diff --git a/plugins/utilities.json b/plugins/utilities.json index f29e12dd..d58ff2da 100644 --- a/plugins/utilities.json +++ b/plugins/utilities.json @@ -14,7 +14,12 @@ } ], "versions": { - "1.2.1": null, + "1.2.1": { + "api_version": 7, + "commit_sha": "7753b87", + "released_on": "05-12-2022", + "md5sum": "7ab5c7ebd43ebd929866fccb82cd5a45" + }, "1.2.0": { "api_version": 7, "commit_sha": "f07d2f8", @@ -146,7 +151,12 @@ } ], "versions": { - "1.2.2": null, + "1.2.2": { + "api_version": 7, + "commit_sha": "7753b87", + "released_on": "05-12-2022", + "md5sum": "c6e5366b446e265c623e34010d5c40c7" + }, "1.2.1": { "api_version": 7, "commit_sha": "2fda676", @@ -183,7 +193,12 @@ } ], "versions": { - "1.2.3": null, + "1.2.3": { + "api_version": 7, + "commit_sha": "7753b87", + "released_on": "05-12-2022", + "md5sum": "659794e1fa1e87cf9768899519994eac" + }, "1.2.2": { "api_version": 7, "commit_sha": "a6d1a43", From df9a29f5c220eab56d8cdddcc950fd3864a24b8c Mon Sep 17 00:00:00 2001 From: ! Freaku <92618708+Freaku17@users.noreply.github.com> Date: Mon, 5 Dec 2022 22:03:13 +0530 Subject: [PATCH 0319/1464] Fixing a bug --- plugin_manager.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/plugin_manager.py b/plugin_manager.py index adc48a2a..921983d3 100644 --- a/plugin_manager.py +++ b/plugin_manager.py @@ -364,8 +364,7 @@ def _set_content(self, content): def has_settings(self): for plugin_entry_point, plugin_class in ba.app.plugins.active_plugins.items(): if plugin_entry_point.startswith(self._entry_point_initials): - return hasattr(plugin_class, "has_settings_ui") - return False + return plugin_class.has_settings_ui() def launch_settings(self, source_widget): for plugin_entry_point, plugin_class in ba.app.plugins.active_plugins.items(): From d321df7dafc3a58b79cb0d49d945bef4640254c7 Mon Sep 17 00:00:00 2001 From: ! Freaku <92618708+Freaku17@users.noreply.github.com> Date: Mon, 5 Dec 2022 22:04:12 +0530 Subject: [PATCH 0320/1464] Update index.json --- index.json | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/index.json b/index.json index c9f331b7..9579cd0a 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.0": { - "api_version": 7, - "commit_sha": "7753b87", - "released_on": "05-12-2022", - "md5sum": "ee88d457a66ac0689624f6dc72d27c1c" - }, + "0.2.0": null}, "0.1.10": { "api_version": 7, "commit_sha": "e122d0f", @@ -56,4 +51,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 bd9dc14a8ac57c8a495d9702ef1fc2a64b63fcce Mon Sep 17 00:00:00 2001 From: ! Freaku <92618708+Freaku17@users.noreply.github.com> Date: Mon, 5 Dec 2022 22:04:34 +0530 Subject: [PATCH 0321/1464] Update index.json --- index.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/index.json b/index.json index 9579cd0a..4ad42bc4 100644 --- a/index.json +++ b/index.json @@ -1,7 +1,7 @@ { "plugin_manager_url": "https://github.com/bombsquad-community/plugin-manager/{content_type}/{tag}/plugin_manager.py", "versions": { - "0.2.0": null}, + "0.2.0": null, "0.1.10": { "api_version": 7, "commit_sha": "e122d0f", From bde4df0e4cf05ece4d37c35e58fb93bebad2c983 Mon Sep 17 00:00:00 2001 From: Freaku17 Date: Mon, 5 Dec 2022 16:34:59 +0000 Subject: [PATCH 0322/1464] [ci] apply-version-metadata --- index.json | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/index.json b/index.json index 4ad42bc4..15e80967 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.0": null, + "0.2.0": { + "api_version": 7, + "commit_sha": "bd9dc14", + "released_on": "05-12-2022", + "md5sum": "3633c9c58037cbad7d2942858270c4ae" + }, "0.1.10": { "api_version": 7, "commit_sha": "e122d0f", @@ -51,4 +56,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 4f545393be9311dbbe65caccbdfb89691c659f5d Mon Sep 17 00:00:00 2001 From: ! Freaku <92618708+Freaku17@users.noreply.github.com> Date: Mon, 5 Dec 2022 22:16:21 +0530 Subject: [PATCH 0323/1464] Update README.md --- README.md | 11 +---------- 1 file changed, 1 insertion(+), 10 deletions(-) diff --git a/README.md b/README.md index bae5dfd5..bedb6728 100644 --- a/README.md +++ b/README.md @@ -57,10 +57,7 @@ There are two different ways the plugin manager can be installed: - New plugins are accepted through a [pull request](../../compare). Add your plugin in the minigames, utilities, or the category directory you feel is the most relevant to the type of plugin you're submitting, [here](plugins). Then add an entry to the category's JSON metadata file. -- Plugin manager will also show and execute the settings icon if your `ba.Plugin` export class has a method named - `on_plugin_manager_prompt`; check out the - [colorscheme](https://github.com/bombsquad-community/plugin-manager/blob/f24f0ca5ded427f6041795021f1af2e6a08b6ce9/plugins/utilities/colorscheme.py#L419-L420) - plugin as an example and its behaviour when the settings icon is tapped via the plugin manager in-game. +- Plugin manager will also show and execute the settings icon if your `ba.Plugin` class has methods `has_settings_ui` and `show_settings_ui`. #### Example: @@ -73,9 +70,6 @@ import ba class Main(ba.Plugin): def on_app_running(self): ba.screenmessage("Hi! I am a sample plugin!") - - def on_plugin_manager_prompt(self): - ba.screenmessage("You tapped my settings from the Plugin Manager Window!") ``` You'll have to fork this repository and add your `sample_plugin.py` plugin file into the appropriate directory, which for @@ -137,9 +131,6 @@ index ebb7dcc..da2b312 100644 def on_app_running(self): ba.screenmessage("Hi! I am a sample plugin!") + ba.screenmessage("Hey! This is my new screenmessage!") - - def on_plugin_manager_prompt(self): - ba.screenmessage("You tapped my settings from the Plugin Manager Window!") ``` To name this new version as `1.1.0`, add `"1.1.0": null,` just above the previous plugin version in `utilities.json`: From c872c320c677676766b0d31cce3eacda6c5be95e Mon Sep 17 00:00:00 2001 From: Rikko Date: Mon, 5 Dec 2022 22:47:33 +0530 Subject: [PATCH 0324/1464] Clarify `has_settings_ui` and `show_settings_ui` --- README.md | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index bedb6728..84fc3760 100644 --- a/README.md +++ b/README.md @@ -28,7 +28,7 @@ There are two different ways the plugin manager can be installed: 1. Download [plugin_manager.py](https://raw.githubusercontent.com/bombsquad-community/plugin-manager/main/plugin_manager.py) to your mods directory (check it out by going into your game's Settings -> Advanced -> Show Mods Folder). This is the - recommended way (see below). + recommended way (read next method to know why). 2. Another way is to add [plugin_manager.py](https://raw.githubusercontent.com/bombsquad-community/plugin-manager/main/plugin_manager.py) @@ -57,7 +57,7 @@ There are two different ways the plugin manager can be installed: - New plugins are accepted through a [pull request](../../compare). Add your plugin in the minigames, utilities, or the category directory you feel is the most relevant to the type of plugin you're submitting, [here](plugins). Then add an entry to the category's JSON metadata file. -- Plugin manager will also show and execute the settings icon if your `ba.Plugin` class has methods `has_settings_ui` and `show_settings_ui`. +- Plugin manager will also show and execute the settings icon if your `ba.Plugin` class has methods `has_settings_ui` and `show_settings_ui`; check out the [colorscheme](https://github.com/bombsquad-community/plugin-manager/blob/eb163cf86014b2a057c4a048dcfa3d5b540b7fe1/plugins/utilities/colorscheme.py#L448-L452) plugin for an example. #### Example: @@ -70,6 +70,12 @@ import ba class Main(ba.Plugin): def on_app_running(self): ba.screenmessage("Hi! I am a sample plugin!") + + def has_settings_ui(self): + return True + + def show_settings_ui(self, source_widget): + ba.screenmessage("You tapped my settings!") ``` You'll have to fork this repository and add your `sample_plugin.py` plugin file into the appropriate directory, which for @@ -130,6 +136,12 @@ index ebb7dcc..da2b312 100644 class Main(ba.Plugin): def on_app_running(self): ba.screenmessage("Hi! I am a sample plugin!") + + def has_settings_ui(self): + return True + + def show_settings_ui(self, source_widget): +- ba.screenmessage("You tapped my settings!") + ba.screenmessage("Hey! This is my new screenmessage!") ``` From a36eaf2002863fc619ce6c37a0761a4cb471cb02 Mon Sep 17 00:00:00 2001 From: Ayush Saini <36878972+imayushsaini@users.noreply.github.com> Date: Fri, 9 Dec 2022 11:41:50 +0530 Subject: [PATCH 0325/1464] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 84fc3760..9b04627a 100644 --- a/README.md +++ b/README.md @@ -26,7 +26,7 @@ which makes further modding of your game more convenient by providing easier acc There are two different ways the plugin manager can be installed: -1. Download [plugin_manager.py](https://raw.githubusercontent.com/bombsquad-community/plugin-manager/main/plugin_manager.py) +1. [Download Plugin Manager.py](https://bombsquad-community.github.io/bombsquad-web/pluginmanager) to your mods directory (check it out by going into your game's Settings -> Advanced -> Show Mods Folder). This is the recommended way (read next method to know why). From 97625cdd4a5aa58b8b039eee37d2916dcf0d18b9 Mon Sep 17 00:00:00 2001 From: Cross Joy <87638792+CrossJoy@users.noreply.github.com> Date: Wed, 14 Dec 2022 20:49:23 +0800 Subject: [PATCH 0326/1464] Add files via upload --- plugins/utilities/practice_tools.py | 2227 +++++++++++++++++++++++++++ 1 file changed, 2227 insertions(+) create mode 100644 plugins/utilities/practice_tools.py diff --git a/plugins/utilities/practice_tools.py b/plugins/utilities/practice_tools.py new file mode 100644 index 00000000..803b0f94 --- /dev/null +++ b/plugins/utilities/practice_tools.py @@ -0,0 +1,2227 @@ +"""Practice Tools Mod: V1.0 +Made by Cross Joy""" + +# If anyone who want to help me on giving suggestion/ fix bugs/ creating PR, +# Can visit my github https://github.com/CrossJoy/Bombsquad-Modding + +# You can contact me through discord: +# My Discord Id: Cross Joy#0721 +# My BS Discord Server: https://discord.gg/JyBY6haARJ + +# Some support will be much appreciated. :') +# Support link: https://www.buymeacoffee.com/CrossJoy + + +# ---------------------------------------------------------------------------- +# Powerful and comprehensive tools for practice purpose. + +# Features: +# - Spawn any bot anywhere. +# - Can spawn power up by your own. +# - Bomb radius visualizer. (Thx Mikirog for some of the codes :D ) +# - Bomb Countdown. +# and many more + +# Go explore the tools yourself.:) + +# Practice tabs can be access through party window. +# Coop and local multiplayer compatible. +# Work on any 1.7+ ver. + +# FAQ: +# Can I use it to practice with friends? +# - Yes, but you are the only one can access the practice window. + +# Does it work when I join a public server? +# - Not possible. + +# Can I use it during Coop game? +# - Yes, it works fine. +# ---------------------------------------------------------------------------- + +from __future__ import annotations + +import random +import weakref +from enum import Enum +from typing import TYPE_CHECKING +import ba, _ba +import ba.internal +import bastd +from bastd.actor.powerupbox import PowerupBox +from bastd.actor.spaz import Spaz +from bastd.actor.spazbot import (SpazBotSet, SpazBot, BrawlerBot, TriggerBot, + ChargerBot, StickyBot, ExplodeyBot, BouncyBot, + BomberBotPro, BrawlerBotPro, TriggerBotPro, + ChargerBotPro, BomberBotProShielded, + BrawlerBotProShielded, TriggerBotProShielded, + ChargerBotProShielded) +from bastd.mainmenu import MainMenuSession +from bastd.ui.party import PartyWindow as OriginalPartyWindow +from ba import app, Plugin +from bastd.ui import popup +from bastd.actor.bomb import Bomb +import math + +from bastd.ui.tabs import TabRow + +if TYPE_CHECKING: + from typing import Any, Sequence, Callable, Optional + +try: + if ba.app.config.get("bombCountdown") is None: + ba.app.config["bombCountdown"] = False + else: + ba.app.config.get("bombCountdown") +except: + ba.app.config["bombCountdown"] = False + +try: + if ba.app.config.get("bombRadiusVisual") is None: + ba.app.config["bombRadiusVisual"] = False + else: + ba.app.config.get("bombRadiusVisual") +except: + ba.app.config["bombRadiusVisual"] = False + +try: + if ba.app.config.get("stopBots") is None: + ba.app.config["stopBots"] = False + else: + ba.app.config.get("stopBots") +except: + ba.app.config["stopBots"] = False + +try: + if ba.app.config.get("stopBots") is None: + ba.app.config["stopBots"] = False + else: + ba.app.config.get("stopBots") +except: + ba.app.config["stopBots"] = False + +try: + if ba.app.config.get("immortalDummy") is None: + ba.app.config["immortalDummy"] = False + else: + ba.app.config.get("immortalDummy") +except: + ba.app.config["immortalDummy"] = False + +try: + if ba.app.config.get("invincible") is None: + ba.app.config["invincible"] = False + else: + ba.app.config.get("invincible") +except: + ba.app.config["invincible"] = False + +_ba.set_party_icon_always_visible(True) + + +def is_game_version_lower_than(version): + """ + Returns a boolean value indicating whether the current game + version is lower than the passed version. Useful for addressing + any breaking changes within game versions. + """ + game_version = tuple(map(int, ba.app.version.split("."))) + version = tuple(map(int, version.split("."))) + return game_version < version + + +if is_game_version_lower_than("1.7.7"): + ba_internal = _ba +else: + ba_internal = ba.internal + + +class PartyWindow(ba.Window): + _redefine_methods = ['__init__'] + + def __init__(self, *args, **kwargs): + getattr(self, '__init___old')(*args, **kwargs) + + self.bg_color = (.5, .5, .5) + + self._edit_movements_button = ba.buttonwidget( + parent=self._root_widget, + scale=0.7, + position=(360, self._height - 47), + # (self._width - 80, self._height - 47) + size=(100, 50), + label='Practice', + autoselect=True, + button_type='square', + on_activate_call=ba.Call(doTestButton, self), + color=self.bg_color, + iconscale=1.2) + + +def redefine(obj: object, name: str, new: callable, + new_name: str = None) -> None: + if not new_name: + new_name = name + '_old' + if hasattr(obj, name): + setattr(obj, new_name, getattr(obj, name)) + setattr(obj, name, new) + + +def redefine_class(original_cls: object, cls: object) -> None: + for method in cls._redefine_methods: + redefine(original_cls, method, getattr(cls, method)) + + +def main(plugin: Plugin) -> None: + print(f'Plugins Tools v{plugin.__version__}') + app.practice_tool = plugin + redefine_class(OriginalPartyWindow, PartyWindow) + + +# ba_meta require api 7 +# ba_meta export plugin +class Practice(Plugin): + __version__ = '1.0' + + def on_app_running(self) -> None: + """Plugin start point.""" + + if app.build_number < 20427: + ba.screenmessage( + 'ok', + color=(.8, .1, .1)) + raise RuntimeError( + 'sad') + + return main(self) + + def new_bomb_init(func): + def setting(*args, **kwargs): + func(*args, **kwargs) + + bomb_type = args[0].bomb_type + fuse_bomb = ('land_mine', 'tnt', 'impact') + + if ba.app.config.get("bombRadiusVisual"): + args[0].radius_visualizer = ba.newnode('locator', + owner=args[0].node, + # Remove itself when the bomb node dies. + attrs={ + 'shape': 'circle', + 'color': (1, 0, 0), + 'opacity': 0.05, + 'draw_beauty': False, + 'additive': False + }) + args[0].node.connectattr('position', args[0].radius_visualizer, + 'position') + + ba.animate_array(args[0].radius_visualizer, 'size', 1, { + 0.0: [0.0], + 0.2: [args[0].blast_radius * 2.2], + 0.25: [args[0].blast_radius * 2.0] + }) + + args[0].radius_visualizer_circle = ba.newnode( + 'locator', + owner=args[ + 0].node, + # Remove itself when the bomb node dies. + attrs={ + 'shape': 'circleOutline', + 'size': [ + args[ + 0].blast_radius * 2.0], + # Here's that bomb's blast radius value again! + 'color': ( + 1, 1, 0), + 'draw_beauty': False, + 'additive': True + }) + args[0].node.connectattr('position', + args[0].radius_visualizer_circle, + 'position') + + ba.animate( + args[0].radius_visualizer_circle, 'opacity', { + 0: 0.0, + 0.4: 0.1 + }) + + if bomb_type == 'tnt': + args[0].fatal = ba.newnode('locator', + owner=args[0].node, + # Remove itself when the bomb node dies. + attrs={ + 'shape': 'circle', + 'color': ( + 0.7, 0, 0), + 'opacity': 0.10, + 'draw_beauty': False, + 'additive': False + }) + args[0].node.connectattr('position', + args[0].fatal, + 'position') + + ba.animate_array(args[0].fatal, 'size', 1, { + 0.0: [0.0], + 0.2: [args[0].blast_radius * 2.2 * 0.7], + 0.25: [args[0].blast_radius * 2.0 * 0.7] + }) + + if ba.app.config.get( + "bombCountdown") and bomb_type not in fuse_bomb: + color = (1.0, 1.0, 0.0) + count_bomb(*args, count='3', color=color) + color = (1.0, 0.5, 0.0) + ba.timer(1, ba.Call(count_bomb, *args, count='2', color=color)) + color = (1.0, 0.15, 0.15) + ba.timer(2, ba.Call(count_bomb, *args, count='1', color=color)) + + return setting + + bastd.actor.bomb.Bomb.__init__ = new_bomb_init( + bastd.actor.bomb.Bomb.__init__) + + +Spaz._pm2_spz_old = Spaz.__init__ + + +def _init_spaz_(self, *args, **kwargs): + self._pm2_spz_old(*args, **kwargs) + self.bot_radius = ba.newnode('locator', + owner=self.node, + # Remove itself when the bomb node dies. + attrs={ + 'shape': 'circle', + 'color': (0, 0, 1), + 'opacity': 0.0, + 'draw_beauty': False, + 'additive': False + }) + self.node.connectattr('position', + self.bot_radius, + 'position') + + self.radius_visualizer_circle = ba.newnode( + 'locator', + owner=self.node, + # Remove itself when the bomb node dies. + attrs={ + 'shape': 'circleOutline', + 'size': [(self.hitpoints_max - self.hitpoints) * 0.0048], + # Here's that bomb's blast radius value again! + 'color': (0, 1, 1), + 'draw_beauty': False, + 'additive': True + }) + + self.node.connectattr('position', self.radius_visualizer_circle, + 'position') + + self.curse_visualizer = ba.newnode('locator', + owner=self.node, + # Remove itself when the bomb node dies. + attrs={ + 'shape': 'circle', + 'color': (1, 0, 0), + 'size': (0.0, 0.0, 0.0), + 'opacity': 0.05, + 'draw_beauty': False, + 'additive': False + }) + self.node.connectattr('position', self.curse_visualizer, + 'position') + + self.curse_visualizer_circle = ba.newnode( + 'locator', + owner=self.node, + # Remove itself when the bomb node dies. + attrs={ + 'shape': 'circleOutline', + 'size': [3 * 2.0], + # Here's that bomb's blast radius value again! + 'color': ( + 1, 1, 0), + 'opacity': 0.0, + 'draw_beauty': False, + 'additive': True + }) + self.node.connectattr('position', + self.curse_visualizer_circle, + 'position') + + self.curse_visualizer_fatal = ba.newnode('locator', + owner=self.node, + # Remove itself when the bomb node dies. + attrs={ + 'shape': 'circle', + 'color': ( + 0.7, 0, 0), + 'size': (0.0, 0.0, 0.0), + 'opacity': 0.10, + 'draw_beauty': False, + 'additive': False + }) + self.node.connectattr('position', + self.curse_visualizer_fatal, + 'position') + + def invincible() -> None: + for i in _ba.get_foreground_host_activity().players: + try: + if i.node: + if ba.app.config.get("invincible"): + i.actor.node.invincible = True + else: + i.actor.node.invincible = False + except: + pass + + ba.timer(1.001, ba.Call(invincible)) + + +Spaz.__init__ = _init_spaz_ + +Spaz.super_curse = Spaz.curse + + +def new_cursed(self): + self.super_curse() + if ba.app.config.get("bombRadiusVisual"): + + ba.animate_array(self.curse_visualizer, 'size', 1, { + 0.0: [0.0], + 0.2: [3 * 2.2], + 0.5: [3 * 2.0], + 5.0: [3 * 2.0], + 5.1: [0.0], + }) + + ba.animate( + self.curse_visualizer_circle, 'opacity', { + 0: 0.0, + 0.4: 0.1, + 5.0: 0.1, + 5.1: 0.0, + }) + + ba.animate_array(self.curse_visualizer_fatal, 'size', 1, { + 0.0: [0.0], + 0.2: [2.2], + 0.5: [2.0], + 5.0: [2.0], + 5.1: [0.0], + }) + + +Spaz.curse = new_cursed + +Spaz.super_handlemessage = Spaz.handlemessage + + +def bot_handlemessage(self, msg: Any): + + + if isinstance(msg, ba.PowerupMessage): + if msg.poweruptype == 'health': + if ba.app.config.get("bombRadiusVisual"): + if self._cursed: + ba.animate_array(self.curse_visualizer, 'size', 1, { + 0.0: [3 * 2.0], + 0.2: [0.0], + }) + + ba.animate( + self.curse_visualizer_circle, 'opacity', { + 0.0: 0.1, + 0.2: 0.0, + }) + + ba.animate_array(self.curse_visualizer_fatal, 'size', 1, { + 0.0: [2.0], + 0.2: [0.0], + }) + + ba.animate_array(self.bot_radius, 'size', 1, { + 0.0: [0], + 0.25: [0] + }) + ba.animate(self.bot_radius, 'opacity', { + 0.0: 0.00, + 0.25: 0.0 + }) + + ba.animate_array(self.radius_visualizer_circle, 'size', 1, { + 0.0: [0], + 0.25: [0] + }) + + ba.animate( + self.radius_visualizer_circle, 'opacity', { + 0.0: 0.00, + 0.25: 0.0 + }) + + self.super_handlemessage(msg) + + if isinstance(msg, ba.HitMessage): + if self.hitpoints <= 0: + ba.animate(self.bot_radius, 'opacity', { + 0.0: 0.00 + }) + ba.animate( + self.radius_visualizer_circle, 'opacity', { + 0.0: 0.00 + }) + elif ba.app.config.get('bombRadiusVisual'): + + ba.animate_array(self.bot_radius, 'size', 1, { + 0.0: [(self.hitpoints_max - self.hitpoints) * 0.0048], + 0.25: [(self.hitpoints_max - self.hitpoints) * 0.0048] + }) + ba.animate(self.bot_radius, 'opacity', { + 0.0: 0.00, + 0.25: 0.05 + }) + + ba.animate_array(self.radius_visualizer_circle, 'size', 1, { + 0.0: [(self.hitpoints_max - self.hitpoints) * 0.0048], + 0.25: [(self.hitpoints_max - self.hitpoints) * 0.0048] + }) + + ba.animate( + self.radius_visualizer_circle, 'opacity', { + 0.0: 0.00, + 0.25: 0.1 + }) + + + +Spaz.handlemessage = bot_handlemessage + + +def count_bomb(*args, count, color): + text = ba.newnode('math', owner=args[0].node, + attrs={'input1': (0, 0.7, 0), + 'operation': 'add'}) + args[0].node.connectattr('position', text, 'input2') + args[0].spaztext = ba.newnode('text', + owner=args[0].node, + attrs={ + 'text': count, + 'in_world': True, + 'color': color, + 'shadow': 1.0, + 'flatness': 1.0, + 'scale': 0.012, + 'h_align': 'center', + }) + + args[0].node.connectattr('position', args[0].spaztext, + 'position') + ba.animate(args[0].spaztext, 'scale', + {0: 0, 0.3: 0.03, 0.5: 0.025, 0.8: 0.025, 1.0: 0.0}) + + +def doTestButton(self): + if isinstance(_ba.get_foreground_host_session(), MainMenuSession): + ba.screenmessage('Join any map to start using it.', color=(.8, .8, .1)) + return + + if ba.app.config.get("disablePractice"): + ba.containerwidget(edit=self._root_widget, transition='out_left') + ba.Call(PracticeWindow()) + else: + ba.screenmessage('Only works on local games.', color=(.8, .8, .1)) + + +# --------------------------------------------------------------- + + +class NewBotSet(SpazBotSet): + + def __init__(self): + super().__init__() + + def _update(self) -> None: + try: + with ba.Context(_ba.get_foreground_host_activity()): + # Update one of our bot lists each time through. + # First off, remove no-longer-existing bots from the list. + try: + bot_list = self._bot_lists[self._bot_update_list] = ([ + b for b in self._bot_lists[self._bot_update_list] if b + ]) + except Exception: + bot_list = [] + ba.print_exception('Error updating bot list: ' + + str(self._bot_lists[ + self._bot_update_list])) + self._bot_update_list = (self._bot_update_list + + 1) % self._bot_list_count + + # Update our list of player points for the bots to use. + player_pts = [] + for player in ba.getactivity().players: + assert isinstance(player, ba.Player) + try: + # TODO: could use abstracted player.position here so we + # don't have to assume their actor type, but we have no + # abstracted velocity as of yet. + if player.is_alive(): + assert isinstance(player.actor, Spaz) + assert player.actor.node + player_pts.append( + (ba.Vec3(player.actor.node.position), + ba.Vec3( + player.actor.node.velocity))) + except Exception: + ba.print_exception('Error on bot-set _update.') + + for bot in bot_list: + if not ba.app.config.get('stopBots'): + bot.set_player_points(player_pts) + bot.update_ai() + + ba.app.config["disablePractice"] = True + except: + ba.app.config["disablePractice"] = False + + def clear(self) -> None: + """Immediately clear out any bots in the set.""" + with ba.Context(_ba.get_foreground_host_activity()): + # Don't do this if the activity is shutting down or dead. + activity = ba.getactivity(doraise=False) + if activity is None or activity.expired: + return + + for i, bot_list in enumerate(self._bot_lists): + for bot in bot_list: + bot.handlemessage(ba.DieMessage(immediate=True)) + self._bot_lists[i] = [] + + def spawn_bot( + self, + bot_type: type[SpazBot], + pos: Sequence[float], + spawn_time: float = 3.0, + on_spawn_call: Callable[[SpazBot], Any] | None = None) -> None: + """Spawn a bot from this set.""" + from bastd.actor import spawner + spawner.Spawner(pt=pos, + spawn_time=spawn_time, + send_spawn_message=False, + spawn_callback=ba.Call(self._spawn_bot, bot_type, pos, + on_spawn_call)) + self._spawning_count += 1 + + def _spawn_bot(self, bot_type: type[SpazBot], pos: Sequence[float], + on_spawn_call: Callable[[SpazBot], Any] | None) -> None: + spaz = bot_type().autoretain() + ba.playsound(ba.getsound('spawn'), position=pos) + assert spaz.node + spaz.node.handlemessage('flash') + spaz.node.is_area_of_interest = False + spaz.handlemessage(ba.StandMessage(pos, random.uniform(0, 360))) + self.add_bot(spaz) + self._spawning_count -= 1 + if on_spawn_call is not None: + on_spawn_call(spaz) + + +class DummyBotSet(NewBotSet): + + def _update(self) -> None: + + try: + with ba.Context(_ba.get_foreground_host_activity()): + # Update one of our bot lists each time through. + # First off, remove no-longer-existing bots from the list. + try: + bot_list = self._bot_lists[self._bot_update_list] = ([ + b for b in self._bot_lists[self._bot_update_list] if b + ]) + except Exception: + ba.print_exception('Error updating bot list: ' + + str(self._bot_lists[ + self._bot_update_list])) + self._bot_update_list = (self._bot_update_list + + 1) % self._bot_list_count + + + except: + pass + + +class DummyBot(SpazBot): + character = 'Bones' + + def __init__(self): + super().__init__() + if ba.app.config.get('immortalDummy'): + ba.timer(0.2, self.immortal, + repeat=True) + + def immortal(self): + self.hitpoints = self.hitpoints_max = 10000 + ba.emitfx( + position=self.node.position, + count=20, + emit_type='fairydust') + + +# ------------------------------------------------------------------- + +class PracticeTab: + """Defines a tab for use in the gather UI.""" + + def __init__(self, window: PracticeWindow) -> None: + self._window = weakref.ref(window) + + @property + def window(self) -> PracticeWindow: + """The GatherWindow that this tab belongs to.""" + window = self._window() + if window is None: + raise ba.NotFoundError("PracticeTab's window no longer exists.") + return window + + def on_activate( + self, + parent_widget: ba.Widget, + tab_button: ba.Widget, + region_width: float, + region_height: float, + scroll_widget: ba.Widget, + extra_x: float, + ) -> ba.Widget: + """Called when the tab becomes the active one. + + The tab should create and return a container widget covering the + specified region. + """ + raise RuntimeError('Should not get here.') + + def on_deactivate(self) -> None: + """Called when the tab will no longer be the active one.""" + + def save_state(self) -> None: + """Called when the parent window is saving state.""" + + def restore_state(self) -> None: + """Called when the parent window is restoring state.""" + + +def _check_value_change(setting: int, widget: ba.Widget, + value: str) -> None: + ba.textwidget(edit=widget, + text=ba.Lstr(resource='onText') if value else ba.Lstr( + resource='offText')) + + if setting == 0: + if value: + ba.app.config["stopBots"] = True + else: + ba.app.config["stopBots"] = False + elif setting == 1: + if value: + ba.app.config["immortalDummy"] = True + else: + ba.app.config["immortalDummy"] = False + + +class BotsPracticeTab(PracticeTab): + """The about tab in the practice UI""" + + def __init__(self, window: PracticeWindow, + bot1=DummyBotSet(), bot2=NewBotSet()) -> None: + super().__init__(window) + self._container: ba.Widget | None = None + self.count = 1 + self.radius = 0 + self.radius_array = (['Small', 'Medium', 'Big']) + self.parent_widget = None + self.bot1 = bot1 + self.bot2 = bot2 + self.activity = _ba.get_foreground_host_activity() + self.image_array = ( + ['bonesIcon', 'neoSpazIcon', 'kronkIcon', + 'zoeIcon', 'ninjaIcon', 'melIcon', 'jackIcon', 'bunnyIcon', + 'neoSpazIcon', 'kronkIcon', 'zoeIcon', 'ninjaIcon', + 'neoSpazIcon', 'kronkIcon', 'zoeIcon', 'ninjaIcon']) + self.bot_array_name = ( + ['Dummy', 'Bomber', 'Bruiser', + 'Trigger', 'Charger', 'Sticky', + 'Explodey', 'Bouncy', 'Pro Bomber', + 'Pro Brawler', 'Pro Trigger', 'Pro Charger', + 'S.Pro Bomber', 'S.Pro Brawler', + 'S.Pro Trigger', 'S.Pro Charger']) + + self.setting_name = (['Stop Bots', 'Immortal Dummy']) + self.config = (['stopBots', 'immortalDummy']) + + self.bot_array = ( + [DummyBot, SpazBot, BrawlerBot, TriggerBot, + ChargerBot, StickyBot, ExplodeyBot, BouncyBot, + BomberBotPro, BrawlerBotPro, TriggerBotPro, ChargerBotPro, + BomberBotProShielded, BrawlerBotProShielded, + TriggerBotProShielded, ChargerBotProShielded]) + + self._icon_index = self.bot_array_name.index('Dummy') + + def on_activate( + self, + parent_widget: ba.Widget, + tab_button: ba.Widget, + region_width: float, + region_height: float, + scroll_widget: ba.Widget, + extra_x: float, + ) -> ba.Widget: + + b_size_2 = 100 + spacing_h = -50 + mask_texture = ba.gettexture('characterIconMask') + spacing_v = 60 + + self.parent_widget = parent_widget + + self._scroll_width = region_width * 0.8 + self._scroll_height = region_height * 0.6 + self._scroll_position = ((region_width - self._scroll_width) * 0.5, + (region_height - self._scroll_height) * 0.5) + + self._sub_width = self._scroll_width + self._sub_height = 200 + + self.container_h = 600 + bots_height = self.container_h - 50 + + self._subcontainer = ba.containerwidget( + parent=scroll_widget, + size=(self._sub_width, self.container_h), + background=False, + selection_loops_to_parent=True) + + ba.textwidget(parent=self._subcontainer, + position=(self._sub_width * 0.5, + bots_height), + size=(0, 0), + color=(1.0, 1.0, 1.0), + scale=1.3, + h_align='center', + v_align='center', + text='Spawn Bot', + maxwidth=200) + + self._bot_button = bot = ba.buttonwidget( + parent=self._subcontainer, + autoselect=True, + position=(self._sub_width * 0.5 - b_size_2 * 0.5, + bots_height + spacing_h * 3), + on_activate_call=self._bot_window, + size=(b_size_2, b_size_2), + label='', + color=(1, 1, 1), + tint_texture=(ba.gettexture( + self.image_array[self._icon_index] + 'ColorMask')), + tint_color=(0.6, 0.6, 0.6), + tint2_color=(0.1, 0.3, 0.1), + texture=ba.gettexture(self.image_array[self._icon_index]), + mask_texture=mask_texture) + + ba.textwidget( + parent=self._subcontainer, + h_align='center', + v_align='center', + position=(self._sub_width * 0.5, + bots_height + spacing_h * 4 + 10), + size=(0, 0), + draw_controller=bot, + text='Bot Type', + scale=1.0, + color=ba.app.ui.title_color, + maxwidth=130) + + ba.textwidget(parent=self._subcontainer, + position=( + self._sub_width * 0.005, + bots_height + + spacing_h * 7), + size=(100, 30), + text='Count', + h_align='left', + color=(0.8, 0.8, 0.8), + v_align='center', + maxwidth=200) + self.count_text = txt = ba.textwidget(parent=self._subcontainer, + position=( + self._sub_width * 0.85 - spacing_v * 2, + bots_height + + spacing_h * 7), + size=(0, 28), + text=str(self.count), + editable=False, + color=(0.6, 1.0, 0.6), + maxwidth=150, + h_align='center', + v_align='center', + padding=2) + self.button_bot_left = btn1 = ba.buttonwidget( + parent=self._subcontainer, + position=( + self._sub_width * 0.85 - spacing_v - 14, + bots_height + + spacing_h * 7), + size=(28, 28), + label='-', + autoselect=True, + on_activate_call=self.decrease_count, + repeat=True) + self.button_bot_right = btn2 = ba.buttonwidget( + parent=self._subcontainer, + position=( + self._sub_width * 0.85 - 14, + bots_height + + spacing_h * 7), + size=(28, 28), + label='+', + autoselect=True, + on_activate_call=self.increase_count, + repeat=True) + + ba.textwidget(parent=self._subcontainer, + position=( + self._sub_width * 0.005, + bots_height + + spacing_h * 8), + size=(100, 30), + text='Spawn Radius', + h_align='left', + color=(0.8, 0.8, 0.8), + v_align='center', + maxwidth=200) + + self.radius_text = txt = ba.textwidget(parent=self._subcontainer, + position=( + self._sub_width * 0.85 - spacing_v * 2, + bots_height + + spacing_h * 8), + size=(0, 28), + text=self.radius_array[ + self.radius], + editable=False, + color=(0.6, 1.0, 0.6), + maxwidth=50, + h_align='center', + v_align='center', + padding=2) + self.button_bot_left = btn1 = ba.buttonwidget( + parent=self._subcontainer, + position=( + self._sub_width * 0.85 - spacing_v - 14, + bots_height + + spacing_h * 8), + size=(28, 28), + label='-', + autoselect=True, + on_activate_call=self.decrease_radius, + repeat=True) + self.button_bot_right = btn2 = ba.buttonwidget( + parent=self._subcontainer, + position=( + self._sub_width * 0.85 - 14, + bots_height + + spacing_h * 8), + size=(28, 28), + label='+', + autoselect=True, + on_activate_call=self.increase_radius, + repeat=True) + + self.button = ba.buttonwidget( + parent=self._subcontainer, + position=( + self._sub_width * 0.25 - 40, + bots_height + + spacing_h * 6), + size=(80, 50), + autoselect=True, + button_type='square', + label='Spawn', + on_activate_call=self.do_spawn_bot) + + self.button = ba.buttonwidget( + parent=self._subcontainer, + position=( + self._sub_width * 0.75 - 40, + bots_height + + spacing_h * 6), + size=(80, 50), + autoselect=True, + button_type='square', + color=(1, 0.2, 0.2), + label='Clear', + on_activate_call=self.clear_bot) + + i = 0 + for name in self.setting_name: + ba.textwidget(parent=self._subcontainer, + position=(self._sub_width * 0.005, + bots_height + spacing_h * (9 + i)), + size=(100, 30), + text=name, + h_align='left', + color=(0.8, 0.8, 0.8), + v_align='center', + maxwidth=200) + value = ba.app.config.get(self.config[i]) + txt2 = ba.textwidget( + parent=self._subcontainer, + position=(self._sub_width * 0.8 - spacing_v / 2, + bots_height + + spacing_h * (9 + i)), + size=(0, 28), + text=ba.Lstr(resource='onText') if value else ba.Lstr( + resource='offText'), + editable=False, + color=(0.6, 1.0, 0.6), + maxwidth=50, + h_align='right', + v_align='center', + padding=2) + ba.checkboxwidget(parent=self._subcontainer, + text='', + position=(self._sub_width * 0.8 - 15, + bots_height + + spacing_h * (9 + i)), + size=(30, 30), + autoselect=False, + textcolor=(0.8, 0.8, 0.8), + value=value, + on_value_change_call=ba.Call( + _check_value_change, + i, txt2)) + i += 1 + + return self._subcontainer + + def _bot_window(self) -> None: + BotPicker( + parent=self.parent_widget, + delegate=self) + + def increase_count(self): + if self.count < 10: + self.count += 1 + + ba.textwidget(edit=self.count_text, + text=str(self.count)) + + def decrease_count(self): + if self.count > 1: + self.count -= 1 + + ba.textwidget(edit=self.count_text, + text=str(self.count)) + + def increase_radius(self): + if self.radius < 2: + self.radius += 1 + + ba.textwidget(edit=self.radius_text, + text=self.radius_array[self.radius]) + + def decrease_radius(self): + if self.radius > 0: + self.radius -= 1 + + ba.textwidget(edit=self.radius_text, + text=self.radius_array[self.radius]) + + def clear_bot(self): + self.bot1.clear() + self.bot2.clear() + + def do_spawn_bot(self, clid: int = -1) -> None: + with ba.Context(self.activity): + for i in _ba.get_foreground_host_activity().players: + if i.sessionplayer.inputdevice.client_id == clid: + if i.node: + bot_type = self._icon_index + for a in range(self.count): + x = (random.randrange + (-10, 10) / 10) * math.pow(self.radius + 1, 2) + z = (random.randrange + (-10, 10) / 10) * math.pow(self.radius + 1, 2) + pos = (i.node.position[0] + x, + i.node.position[1], + i.node.position[2] + z) + if bot_type == 0: + self.bot1.spawn_bot(self.bot_array[0], + pos=pos, + spawn_time=1.0) + else: + self.bot2.spawn_bot(self.bot_array[bot_type], + pos=pos, + spawn_time=1.0) + break + + def on_bots_picker_pick(self, character: str) -> None: + """A bots has been selected by the picker.""" + if not self.parent_widget: + return + + # The player could have bought a new one while the picker was u + self._icon_index = self.bot_array_name.index( + character) if character in self.bot_array_name else 0 + self._update_character() + + def _update_character(self, change: int = 0) -> None: + if self._bot_button: + if self.bot_array_name[self._icon_index] in ( + 'Pro Bomber', 'Pro Brawler', + 'Pro Trigger', 'Pro Charger', + 'S.Pro Bomber', 'S.Pro Brawler', + 'S.Pro Trigger', 'S.Pro Charger'): + tint1 = (1.0, 0.2, 0.1) + tint2 = (0.6, 0.1, 0.05) + elif self.bot_array_name[self._icon_index] in 'Bouncy': + tint1 = (1, 1, 1) + tint2 = (1.0, 0.5, 0.5) + else: + tint1 = (0.6, 0.6, 0.6) + tint2 = (0.1, 0.3, 0.1) + + if self.bot_array_name[self._icon_index] in ( + 'S.Pro Bomber', 'S.Pro Brawler', + 'S.Pro Trigger', 'S.Pro Charger'): + color = (1.3, 1.2, 3.0) + else: + color = (1.0, 1.0, 1.0) + + ba.buttonwidget( + edit=self._bot_button, + texture=ba.gettexture(self.image_array[self._icon_index]), + tint_texture=(ba.gettexture( + self.image_array[self._icon_index] + 'ColorMask')), + color=color, + tint_color=tint1, + tint2_color=tint2) + + +class PowerUpPracticeTab(PracticeTab): + """The about tab in the practice UI""" + + def __init__(self, window: PracticeWindow) -> None: + super().__init__(window) + self._container: ba.Widget | None = None + self.count = 1 + self.parent_widget = None + self.activity = _ba.get_foreground_host_activity() + + self.power_list = (['Bomb', 'Curse', 'Health', 'IceBombs', + 'ImpactBombs', 'LandMines', 'Punch', + 'Shield', 'StickyBombs']) + + self.power_list_type_name = ( + ['Tripple Bombs', 'Curse', 'Health', 'Ice Bombs', + 'Impact Bombs', 'Land Mines', 'Punch', + 'Shield', 'Sticky Bombs']) + + self.power_list_type = ( + ['triple_bombs', 'curse', 'health', 'ice_bombs', + 'impact_bombs', 'land_mines', 'punch', + 'shield', 'sticky_bombs']) + self._icon_index = self.power_list_type_name.index('Tripple Bombs') + + self.setting_name = (['Bomb Countdown', 'Bomb Radius Visualizer']) + self.config = (['bombCountdown', 'bombRadiusVisual']) + + def on_activate( + self, + parent_widget: ba.Widget, + tab_button: ba.Widget, + region_width: float, + region_height: float, + scroll_widget: ba.Widget, + extra_x: float, + ) -> ba.Widget: + + b_size_2 = 100 + spacing_h = -50 + spacing_v = 60 + + self.parent_widget = parent_widget + + self._scroll_width = region_width * 0.8 + self._scroll_height = region_height * 0.6 + self._scroll_position = ((region_width - self._scroll_width) * 0.5, + (region_height - self._scroll_height) * 0.5) + + self._sub_width = self._scroll_width + self._sub_height = 200 + + self.container_h = 450 + power_height = self.container_h - 50 + + self._subcontainer = ba.containerwidget( + parent=scroll_widget, + size=(self._sub_width, self.container_h), + background=False, + selection_loops_to_parent=True) + + ba.textwidget(parent=self._subcontainer, + position=(self._sub_width * 0.5, + power_height), + size=(0, 0), + color=(1.0, 1.0, 1.0), + scale=1.3, + h_align='center', + v_align='center', + text='Spawn Power Up', + maxwidth=200) + + self._power_button = bot = ba.buttonwidget( + parent=self._subcontainer, + autoselect=True, + position=(self._sub_width * 0.5 - b_size_2 * 0.5, + power_height + spacing_h * 3), + on_activate_call=self._power_window, + size=(b_size_2, b_size_2), + label='', + color=(1, 1, 1), + texture=ba.gettexture('powerup' + + self.power_list[ + self._icon_index])) + + ba.textwidget( + parent=self._subcontainer, + h_align='center', + v_align='center', + position=(self._sub_width * 0.5, + power_height + spacing_h * 4 + 10), + size=(0, 0), + draw_controller=bot, + text='Power Up Type', + scale=1.0, + color=ba.app.ui.title_color, + maxwidth=300) + + self.button = ba.buttonwidget( + parent=self._subcontainer, + position=( + self._sub_width * 0.25 - 40, + power_height + + spacing_h * 6), + size=(80, 50), + autoselect=True, + button_type='square', + label='Spawn', + on_activate_call=self.get_powerup) + + self.button = ba.buttonwidget( + parent=self._subcontainer, + position=( + self._sub_width * 0.75 - 40, + power_height + + spacing_h * 6), + size=(80, 50), + autoselect=True, + button_type='square', + color=(1, 0.2, 0.2), + label='Debuff', + on_activate_call=self.debuff) + + i = 0 + for name in self.setting_name: + ba.textwidget(parent=self._subcontainer, + position=(self._sub_width * 0.005, + power_height + spacing_h * (7 + i)), + size=(100, 30), + text=name, + h_align='left', + color=(0.8, 0.8, 0.8), + v_align='center', + maxwidth=200) + value = ba.app.config.get(self.config[i]) + txt2 = ba.textwidget( + parent=self._subcontainer, + position=(self._sub_width * 0.8 - spacing_v / 2, + power_height + + spacing_h * (7 + i)), + size=(0, 28), + text=ba.Lstr(resource='onText') if value else ba.Lstr( + resource='offText'), + editable=False, + color=(0.6, 1.0, 0.6), + maxwidth=400, + h_align='right', + v_align='center', + padding=2) + ba.checkboxwidget(parent=self._subcontainer, + text='', + position=(self._sub_width * 0.8 - 15, + power_height + + spacing_h * (7 + i)), + size=(30, 30), + autoselect=False, + textcolor=(0.8, 0.8, 0.8), + value=value, + on_value_change_call=ba.Call( + self._check_value_change, + i, txt2)) + i += 1 + + return self._subcontainer + + def debuff(self): + with ba.Context(_ba.get_foreground_host_activity()): + for i in _ba.get_foreground_host_activity().players: + Spaz._gloves_wear_off(i.actor) + Spaz._multi_bomb_wear_off(i.actor) + Spaz._bomb_wear_off(i.actor) + i.actor.shield_hitpoints = 1 + + def get_powerup(self, clid: int = -1) -> None: + with ba.Context(_ba.get_foreground_host_activity()): + for i in _ba.get_foreground_host_activity().players: + if i.sessionplayer.inputdevice.client_id == clid: + if i.node: + x = (random.choice([-7, 7]) / 10) + z = (random.choice([-7, 7]) / 10) + pos = (i.node.position[0] + x, + i.node.position[1], + i.node.position[2] + z) + PowerupBox(position=pos, + poweruptype= + self.power_list_type + [self._icon_index]).autoretain() + + def _power_window(self) -> None: + PowerPicker( + parent=self.parent_widget, + delegate=self) + + def on_power_picker_pick(self, power: str) -> None: + """A power up has been selected by the picker.""" + if not self.parent_widget: + return + + # The player could have bought a new one while the picker was u + self._icon_index = self.power_list.index( + power) if power in self.power_list else 0 + self._update_power() + + def _update_power(self, change: int = 0) -> None: + if self._power_button: + ba.buttonwidget( + edit=self._power_button, + texture=(ba.gettexture('powerup' + + self.power_list[ + self._icon_index]))) + + def _check_value_change(self, setting: int, widget: ba.Widget, + value: str) -> None: + ba.textwidget(edit=widget, + text=ba.Lstr(resource='onText') if value else ba.Lstr( + resource='offText')) + + with ba.Context(self.activity): + if setting == 0: + if value: + ba.app.config["bombCountdown"] = True + else: + ba.app.config["bombCountdown"] = False + elif setting == 1: + if value: + ba.app.config["bombRadiusVisual"] = True + else: + ba.app.config["bombRadiusVisual"] = False + + +class OthersPracticeTab(PracticeTab): + """The about tab in the practice UI""" + + def __init__(self, window: PracticeWindow) -> None: + super().__init__(window) + self._container: ba.Widget | None = None + self.count = 1 + self.parent_widget = None + self.activity = _ba.get_foreground_host_activity() + self.setting_name = (['Pause On Window', 'Invincible']) + self.config = (['pause', 'invincible']) + + def on_activate( + self, + parent_widget: ba.Widget, + tab_button: ba.Widget, + region_width: float, + region_height: float, + scroll_widget: ba.Widget, + extra_x: float, + ) -> ba.Widget: + spacing_v = 60 + spacing_h = -50 + + self.parent_widget = parent_widget + + self._scroll_width = region_width * 0.8 + self._scroll_height = region_height * 0.6 + self._scroll_position = ((region_width - self._scroll_width) * 0.5, + (region_height - self._scroll_height) * 0.5) + + self._sub_width = self._scroll_width + + self.container_h = 300 + other_height = self.container_h - 50 + + self._subcontainer = ba.containerwidget( + parent=scroll_widget, + size=(self._sub_width, self.container_h), + background=False, + selection_loops_to_parent=True) + + ba.textwidget(parent=self._subcontainer, + position=(self._sub_width * 0.5, + other_height), + size=(0, 0), + color=(1.0, 1.0, 1.0), + scale=1.3, + h_align='center', + v_align='center', + text='Others', + maxwidth=200) + + i = 0 + for name in self.setting_name: + ba.textwidget(parent=self._subcontainer, + position=(self._sub_width * 0.005, + other_height + spacing_h * (2 + i)), + size=(100, 30), + text=name, + h_align='left', + color=(0.8, 0.8, 0.8), + v_align='center', + maxwidth=200) + value = ba.app.config.get(self.config[i]) + txt2 = ba.textwidget( + parent=self._subcontainer, + position=(self._sub_width * 0.8 - spacing_v / 2, + other_height + + spacing_h * (2 + i)), + size=(0, 28), + text=ba.Lstr(resource='onText') if value else ba.Lstr( + resource='offText'), + editable=False, + color=(0.6, 1.0, 0.6), + maxwidth=400, + h_align='right', + v_align='center', + padding=2) + ba.checkboxwidget(parent=self._subcontainer, + text='', + position=(self._sub_width * 0.8 - 15, + other_height + + spacing_h * (2 + i)), + size=(30, 30), + autoselect=False, + textcolor=(0.8, 0.8, 0.8), + value=value, + on_value_change_call=ba.Call( + self._check_value_change, + i, txt2)) + i += 1 + + return self._subcontainer + + def _check_value_change(self, setting: int, widget: ba.Widget, + value: str) -> None: + ba.textwidget(edit=widget, + text=ba.Lstr(resource='onText') if value else ba.Lstr( + resource='offText')) + + with ba.Context(self.activity): + if setting == 0: + if value: + ba.app.config["pause"] = True + self.activity.globalsnode.paused = True + else: + ba.app.config["pause"] = False + self.activity.globalsnode.paused = False + elif setting == 1: + if value: + ba.app.config["invincible"] = True + else: + ba.app.config["invincible"] = False + for i in _ba.get_foreground_host_activity().players: + try: + if i.node: + if ba.app.config.get("invincible"): + i.actor.node.invincible = True + else: + i.actor.node.invincible = False + except: + pass + + +class PracticeWindow(ba.Window): + class TabID(Enum): + """Our available tab types.""" + + BOTS = 'bots' + POWERUP = 'power up' + OTHERS = 'others' + + def __del__(self): + _ba.set_party_icon_always_visible(True) + self.activity.globalsnode.paused = False + + def __init__(self, + transition: Optional[str] = 'in_right'): + + self.activity = _ba.get_foreground_host_activity() + _ba.set_party_icon_always_visible(False) + if ba.app.config.get("pause"): + self.activity.globalsnode.paused = True + uiscale = ba.app.ui.uiscale + self.pick = 0 + self._width = 500 + + self._height = (578 if uiscale is ba.UIScale.SMALL else + 670 if uiscale is ba.UIScale.MEDIUM else 800) + extra_x = 100 if uiscale is ba.UIScale.SMALL else 0 + self.extra_x = extra_x + + self._transitioning_out = False + + b_size_2 = 100 + + spacing_h = -50 + spacing = -450 + spacing_v = 60 + self.container_h = 500 + v = self._height - 115.0 + v -= spacing_v * 3.0 + + super().__init__(root_widget=ba.containerwidget( + size=(self._width, self._height), + transition=transition, + scale=(1.3 if uiscale is ba.UIScale.SMALL else + 0.97 if uiscale is ba.UIScale.MEDIUM else 0.8), + stack_offset=(0, -10) if uiscale is ba.UIScale.SMALL else ( + 240, 0) if uiscale is ba.UIScale.MEDIUM else (330, 20))) + + self._sub_height = 200 + + self._scroll_width = self._width * 0.8 + self._scroll_height = self._height * 0.6 + self._scroll_position = ((self._width - self._scroll_width) * 0.5, + (self._height - self._scroll_height) * 0.5) + + self._scrollwidget = ba.scrollwidget(parent=self._root_widget, + size=(self._scroll_width, + self._scroll_height), + color=(0.55, 0.55, 0.55), + highlight=False, + position=self._scroll_position) + + ba.containerwidget(edit=self._scrollwidget, + claims_left_right=True) + + # --------------------------------------------------------- + + x_offs = 100 if uiscale is ba.UIScale.SMALL else 0 + + self._current_tab: PracticeWindow.TabID | None = None + extra_top = 20 if uiscale is ba.UIScale.SMALL else 0 + self._r = 'gatherWindow' + + tabdefs: list[tuple[PracticeWindow.TabID, str]] = [ + (self.TabID.BOTS, 'Bots') + ] + if ba_internal.get_v1_account_misc_read_val( + 'enablePublicParties', True + ): + tabdefs.append( + ( + self.TabID.POWERUP, + 'Power Ups') + ) + tabdefs.append( + (self.TabID.OTHERS, 'Others') + ) + + condensed = uiscale is not ba.UIScale.LARGE + t_offs_y = ( + 0 if not condensed else 25 if uiscale is ba.UIScale.MEDIUM else 17 + ) + + tab_buffer_h = (320 if condensed else 250) + 2 * x_offs + + self._sub_width = self._width * 0.8 + + # On small UI, push our tabs up closer to the top of the screen to + # save a bit of space. + tabs_top_extra = 42 if condensed else 0 + self._tab_row = TabRow( + self._root_widget, + tabdefs, + pos=( + self._width * 0.5 - self._sub_width * 0.5, + self._height * 0.79), + size=(self._sub_width, 50), + on_select_call=ba.WeakCall(self._set_tab), + ) + + # Now instantiate handlers for these tabs. + tabtypes: dict[PracticeWindow.TabID, type[PracticeTab]] = { + self.TabID.BOTS: BotsPracticeTab, + self.TabID.POWERUP: PowerUpPracticeTab, + self.TabID.OTHERS: OthersPracticeTab, + } + self._tabs: dict[PracticeWindow.TabID, PracticeTab] = {} + for tab_id in self._tab_row.tabs: + tabtype = tabtypes.get(tab_id) + if tabtype is not None: + self._tabs[tab_id] = tabtype(self) + + if ba.app.ui.use_toolbars: + ba.widget( + edit=self._tab_row.tabs[tabdefs[-1][0]].button, + right_widget=ba_internal.get_special_widget('party_button'), + ) + if uiscale is ba.UIScale.SMALL: + ba.widget( + edit=self._tab_row.tabs[tabdefs[0][0]].button, + left_widget=ba_internal.get_special_widget('back_button'), + ) + + # ----------------------------------------------------------- + + self._back_button = btn = ba.buttonwidget( + parent=self._root_widget, + autoselect=True, + position=(self._width * 0.15 - 30, + self._height * 0.95 - 30), + size=(60, 60), + scale=1.1, + label=ba.charstr(ba.SpecialChar.BACK), + button_type='backSmall', + on_activate_call=self.close) + ba.containerwidget(edit=self._root_widget, cancel_button=btn) + + ba.textwidget(parent=self._root_widget, + position=(self._width * 0.5, + self._height * 0.95), + size=(0, 0), + color=ba.app.ui.title_color, + scale=1.5, + h_align='center', + v_align='center', + text='Practice Tools', + maxwidth=400) + + self.info_button = ba.buttonwidget( + parent=self._root_widget, + autoselect=True, + position=(self._width * 0.8 - 30, + self._height * 0.15 - 30), + on_activate_call=self._info_window, + size=(60, 60), + label='') + + ba.imagewidget( + parent=self._root_widget, + position=(self._width * 0.8 - 25, + self._height * 0.15 - 25), + size=(50, 50), + draw_controller=self.info_button, + texture=ba.gettexture('achievementEmpty'), + color=(1.0, 1.0, 1.0)) + + self._tab_container: ba.Widget | None = None + + self._restore_state() + + # # ------------------------------------------------------- + + def _info_window(self): + InfoWindow( + parent=self._root_widget) + + def _button(self) -> None: + ba.buttonwidget(edit=None, + color=(0.2, 0.4, 0.8)) + + def close(self) -> None: + """Close the window.""" + ba.containerwidget(edit=self._root_widget, transition='out_right') + + def _set_tab(self, tab_id: TabID) -> None: + if self._current_tab is tab_id: + return + prev_tab_id = self._current_tab + self._current_tab = tab_id + + # We wanna preserve our current tab between runs. + cfg = ba.app.config + cfg['Practice Tab'] = tab_id.value + cfg.commit() + + # Update tab colors based on which is selected. + self._tab_row.update_appearance(tab_id) + + if prev_tab_id is not None: + prev_tab = self._tabs.get(prev_tab_id) + if prev_tab is not None: + prev_tab.on_deactivate() + + # Clear up prev container if it hasn't been done. + if self._tab_container: + self._tab_container.delete() + + tab = self._tabs.get(tab_id) + if tab is not None: + self._tab_container = tab.on_activate( + self._root_widget, + self._tab_row.tabs[tab_id].button, + self._width, + self._height, + self._scrollwidget, + self.extra_x, + ) + return + + def _restore_state(self) -> None: + from efro.util import enum_by_value + + try: + for tab in self._tabs.values(): + tab.restore_state() + + sel: ba.Widget | None + winstate = ba.app.ui.window_states.get(type(self), {}) + sel_name = winstate.get('sel_name', None) + assert isinstance(sel_name, (str, type(None))) + current_tab = self.TabID.BOTS + gather_tab_val = ba.app.config.get('Practice Tab') + try: + stored_tab = enum_by_value(self.TabID, gather_tab_val) + if stored_tab in self._tab_row.tabs: + current_tab = stored_tab + except ValueError: + pass + self._set_tab(current_tab) + if sel_name == 'Back': + sel = self._back_button + elif sel_name == 'TabContainer': + sel = self._tab_container + elif isinstance(sel_name, str) and sel_name.startswith('Tab:'): + try: + sel_tab_id = enum_by_value( + self.TabID, sel_name.split(':')[-1] + ) + except ValueError: + sel_tab_id = self.TabID.BOTS + sel = self._tab_row.tabs[sel_tab_id].button + else: + sel = self._tab_row.tabs[current_tab].button + ba.containerwidget(edit=self._root_widget, selected_child=sel) + except Exception: + ba.print_exception('Error restoring gather-win state.') + + +org_begin = ba._activity.Activity.on_begin + + +def new_begin(self): + """Runs when game is began.""" + _ba.set_party_icon_always_visible(True) + + +ba._activity.Activity.on_begin = new_begin + + +class BotPicker(popup.PopupWindow): + """Popup window for selecting bots to spwan.""" + + def __init__(self, + parent: ba.Widget, + position: tuple[float, float] = (0.0, 0.0), + delegate: Any = None, + scale: float | None = None, + offset: tuple[float, float] = (0.0, 0.0), + selected_character: str | None = None): + del parent # unused here + uiscale = ba.app.ui.uiscale + if scale is None: + scale = (1.85 if uiscale is ba.UIScale.SMALL else + 1.65 if uiscale is ba.UIScale.MEDIUM else 1.23) + + self._delegate = delegate + self._transitioning_out = False + + count = 16 + + columns = 3 + rows = int(math.ceil(float(count) / columns)) + + button_width = 100 + button_height = 100 + button_buffer_h = 10 + button_buffer_v = 15 + + self._width = (10 + columns * (button_width + 2 * button_buffer_h) * + (1.0 / 0.95) * (1.0 / 0.8)) + self._height = self._width * (0.8 + if uiscale is ba.UIScale.SMALL else 1.06) + + self._scroll_width = self._width * 0.8 + self._scroll_height = self._height * 0.8 + self._scroll_position = ((self._width - self._scroll_width) * 0.5, + (self._height - self._scroll_height) * 0.5) + + # creates our _root_widget + popup.PopupWindow.__init__(self, + position=position, + size=(self._width, self._height), + scale=scale, + bg_color=(0.5, 0.5, 0.5), + offset=offset, + focus_position=self._scroll_position, + focus_size=(self._scroll_width, + self._scroll_height)) + + self._scrollwidget = ba.scrollwidget(parent=self.root_widget, + size=(self._scroll_width, + self._scroll_height), + color=(0.55, 0.55, 0.55), + highlight=False, + position=self._scroll_position) + + ba.containerwidget(edit=self._scrollwidget, claims_left_right=True) + + self._sub_width = self._scroll_width * 0.95 + self._sub_height = 5 + rows * (button_height + + 2 * button_buffer_v) + 100 + self._subcontainer = ba.containerwidget(parent=self._scrollwidget, + size=(self._sub_width, + self._sub_height), + background=False) + + mask_texture = ba.gettexture('characterIconMask') + + bot_list = (['bones', 'neoSpaz', 'kronk', 'zoe', + 'ninja', 'mel', 'jack', 'bunny', + 'neoSpaz', 'kronk', 'zoe', + 'ninja', + 'neoSpaz', 'kronk', 'zoe', + 'ninja']) + bot_list_type = (['Dummy', 'Bomber', 'Brawler', 'Trigger', + 'Charger', 'Sticky', 'Explodey', 'Bouncy', + 'Pro Bomber', 'Pro Brawler', 'Pro Trigger', + 'Pro Charger', 'S.Pro Bomber', 'S.Pro Brawler', + 'S.Pro Trigger', 'S.Pro Charger']) + + index = 0 + for y in range(rows): + for x in range(columns): + + if bot_list_type[index] in ('Pro Bomber', 'Pro Brawler', + 'Pro Trigger', 'Pro Charger', + 'S.Pro Bomber', 'S.Pro Brawler', + 'S.Pro Trigger', 'S.Pro Charger'): + tint1 = (1.0, 0.2, 0.1) + tint2 = (0.6, 0.1, 0.05) + elif bot_list_type[index] in 'Bouncy': + tint1 = (1, 1, 1) + tint2 = (1.0, 0.5, 0.5) + else: + tint1 = (0.6, 0.6, 0.6) + tint2 = (0.1, 0.3, 0.1) + + if bot_list_type[index] in ('S.Pro Bomber', 'S.Pro Brawler', + 'S.Pro Trigger', 'S.Pro Charger'): + color = (1.3, 1.2, 3.0) + else: + color = (1.0, 1.0, 1.0) + pos = (x * (button_width + 2 * button_buffer_h) + + button_buffer_h, self._sub_height - (y + 1) * + (button_height + 2 * button_buffer_v) + 12) + btn = ba.buttonwidget( + parent=self._subcontainer, + button_type='square', + position=(pos[0], + pos[1]), + size=(button_width, button_height), + autoselect=True, + texture=ba.gettexture(bot_list[index] + 'Icon'), + tint_texture=ba.gettexture( + bot_list[index] + 'IconColorMask'), + mask_texture=mask_texture, + label='', + color=color, + tint_color=tint1, + tint2_color=tint2, + on_activate_call=ba.Call(self._select_character, + character=bot_list_type[index])) + ba.widget(edit=btn, show_buffer_top=60, show_buffer_bottom=60) + + name = bot_list_type[index] + ba.textwidget(parent=self._subcontainer, + text=name, + position=(pos[0] + button_width * 0.5, + pos[1] - 12), + size=(0, 0), + scale=0.5, + maxwidth=button_width, + draw_controller=btn, + h_align='center', + v_align='center', + color=(0.8, 0.8, 0.8, 0.8)) + + index += 1 + if index >= len(bot_list): + break + if index >= len(bot_list): + break + + def _select_character(self, character: str) -> None: + if self._delegate is not None: + self._delegate.on_bots_picker_pick(character) + self._transition_out() + + def _transition_out(self) -> None: + if not self._transitioning_out: + self._transitioning_out = True + ba.containerwidget(edit=self.root_widget, transition='out_scale') + + def on_popup_cancel(self) -> None: + ba.playsound(ba.getsound('swish')) + self._transition_out() + + +class PowerPicker(popup.PopupWindow): + """Popup window for selecting power up.""" + + def __init__(self, + parent: ba.Widget, + position: tuple[float, float] = (0.0, 0.0), + delegate: Any = None, + scale: float | None = None, + offset: tuple[float, float] = (0.0, 0.0), + selected_character: str | None = None): + del parent # unused here + + if scale is None: + uiscale = ba.app.ui.uiscale + scale = (1.85 if uiscale is ba.UIScale.SMALL else + 1.65 if uiscale is ba.UIScale.MEDIUM else 1.23) + + self._delegate = delegate + self._transitioning_out = False + + count = 7 + + columns = 3 + rows = int(math.ceil(float(count) / columns)) + + button_width = 100 + button_height = 100 + button_buffer_h = 10 + button_buffer_v = 15 + + self._width = (10 + columns * (button_width + 2 * button_buffer_h) * + (1.0 / 0.95) * (1.0 / 0.8)) + self._height = self._width * (0.8 + if uiscale is ba.UIScale.SMALL else 1.06) + + self._scroll_width = self._width * 0.8 + self._scroll_height = self._height * 0.8 + self._scroll_position = ((self._width - self._scroll_width) * 0.5, + (self._height - self._scroll_height) * 0.5) + + # creates our _root_widget + popup.PopupWindow.__init__(self, + position=position, + size=(self._width, self._height), + scale=scale, + bg_color=(0.5, 0.5, 0.5), + offset=offset, + focus_position=self._scroll_position, + focus_size=(self._scroll_width, + self._scroll_height)) + + self._scrollwidget = ba.scrollwidget(parent=self.root_widget, + size=(self._scroll_width, + self._scroll_height), + color=(0.55, 0.55, 0.55), + highlight=False, + position=self._scroll_position) + + ba.containerwidget(edit=self._scrollwidget, claims_left_right=True) + + self._sub_width = self._scroll_width * 0.95 + self._sub_height = 5 + rows * (button_height + + 2 * button_buffer_v) + 100 + self._subcontainer = ba.containerwidget(parent=self._scrollwidget, + size=(self._sub_width, + self._sub_height), + background=False) + + power_list = (['Bomb', 'Curse', 'Health', 'IceBombs', + 'ImpactBombs', 'LandMines', 'Punch', + 'Shield', 'StickyBombs']) + + power_list_type = (['Tripple Bomb', 'Curse', 'Health', 'Ice Bombs', + 'Impact Bombs', 'Land Mines', 'Punch', + 'Shield', 'Sticky Bombs']) + + index = 0 + for y in range(rows): + for x in range(columns): + pos = (x * (button_width + 2 * button_buffer_h) + + button_buffer_h, self._sub_height - (y + 1) * + (button_height + 2 * button_buffer_v) + 12) + btn = ba.buttonwidget( + parent=self._subcontainer, + button_type='square', + position=(pos[0], + pos[1]), + size=(button_width, button_height), + autoselect=True, + texture=ba.gettexture('powerup' + power_list[index]), + label='', + color=(1, 1, 1), + on_activate_call=ba.Call(self._select_power, + power=power_list[index])) + ba.widget(edit=btn, show_buffer_top=60, show_buffer_bottom=60) + + name = power_list_type[index] + ba.textwidget(parent=self._subcontainer, + text=name, + position=(pos[0] + button_width * 0.5, + pos[1] - 12), + size=(0, 0), + scale=0.5, + maxwidth=button_width, + draw_controller=btn, + h_align='center', + v_align='center', + color=(0.8, 0.8, 0.8, 0.8)) + + index += 1 + if index >= len(power_list): + break + if index >= len(power_list): + break + + def _select_power(self, power: str) -> None: + if self._delegate is not None: + self._delegate.on_power_picker_pick(power) + self._transition_out() + + def _transition_out(self) -> None: + if not self._transitioning_out: + self._transitioning_out = True + ba.containerwidget(edit=self.root_widget, transition='out_scale') + + def on_popup_cancel(self) -> None: + ba.playsound(ba.getsound('swish')) + self._transition_out() + + +class InfoWindow(popup.PopupWindow): + """Popup window for Infos.""" + + def __init__(self, + parent: ba.Widget, + position: tuple[float, float] = (0.0, 0.0), + delegate: Any = None, + scale: float | None = None, + offset: tuple[float, float] = (0.0, 0.0), + selected_character: str | None = None): + del parent # unused here + + if scale is None: + uiscale = ba.app.ui.uiscale + scale = (1.85 if uiscale is ba.UIScale.SMALL else + 1.65 if uiscale is ba.UIScale.MEDIUM else 1.23) + + self._delegate = delegate + self._transitioning_out = False + + self._width = 600 + self._height = self._width * (0.6 + if uiscale is ba.UIScale.SMALL else 0.795) + + # creates our _root_widget + popup.PopupWindow.__init__(self, + position=position, + size=(self._width, self._height), + scale=scale, + bg_color=(0.5, 0.5, 0.5), + offset=offset, + focus_size=(self._width, + self._height)) + + ba.textwidget(parent=self.root_widget, + position=(self._width * 0.5, + self._height * 0.9), + size=(0, 0), + color=ba.app.ui.title_color, + scale=1.3, + h_align='center', + v_align='center', + text='About', + maxwidth=200) + + text = ('Practice Tools Mod\n' + 'Made By Cross Joy\n' + 'version 1.0\n' + '\n' + 'Thx to\n' + 'Mikirog for the Bomb radius visualizer mod.\n' + ) + + lines = text.splitlines() + line_height = 16 + scale_t = 0.56 + + voffs = 0 + i = 0 + for line in lines: + i += 1 + if i <= 3: + color = (1.0, 1.0, 1.0, 1.0) + else: + color = (0.4, 1.0, 1.4, 1.0) + + ba.textwidget( + parent=self.root_widget, + padding=4, + color=color, + scale=scale_t, + flatness=1.0, + size=(0, 0), + position=(self._width * 0.5, self._height * 0.8 + voffs), + h_align='center', + v_align='top', + text=line) + voffs -= line_height + + text_spacing = 70 + + self.button_discord = ba.buttonwidget( + parent=self.root_widget, + position=( + self._width * 0.25 - 40, self._height * 0.2 - 40), + size=(80, 80), + autoselect=True, + button_type='square', + color=(0.447, 0.537, 0.854), + label='', + on_activate_call=self._discord) + ba.imagewidget( + parent=self.root_widget, + position=(self._width * 0.25 - 25, + self._height * 0.2 - 25), + size=(50, 50), + draw_controller=self.button_discord, + texture=ba.gettexture('discordLogo'), + color=(5, 5, 5)) + ba.textwidget( + parent=self.root_widget, + position=(self._width * 0.25, + self._height * 0.2 + text_spacing), + size=(0, 0), + scale=0.75, + draw_controller=self.button_discord, + text='Join us. :D', + h_align='center', + v_align='center', + maxwidth=150, + color=(0.447, 0.537, 0.854)) + + self.button_github = ba.buttonwidget( + parent=self.root_widget, + position=( + self._width * 0.5 - 40, self._height * 0.2 - 40), + size=(80, 80), + autoselect=True, + button_type='square', + color=(0.129, 0.122, 0.122), + label='', + on_activate_call=self._github) + ba.imagewidget( + parent=self.root_widget, + position=(self._width * 0.5 - 25, + self._height * 0.2 - 25), + size=(50, 50), + draw_controller=self.button_github, + texture=ba.gettexture('githubLogo'), + color=(1, 1, 1)) + ba.textwidget( + parent=self.root_widget, + position=(self._width * 0.5, + self._height * 0.2 + text_spacing), + size=(0, 0), + scale=0.75, + draw_controller=self.button_github, + text='Found Bugs?', + h_align='center', + v_align='center', + maxwidth=150, + color=(0.129, 0.122, 0.122)) + + self.button_support = ba.buttonwidget( + parent=self.root_widget, + position=( + self._width * 0.75 - 40, self._height * 0.2 - 40), + size=(80, 80), + autoselect=True, + button_type='square', + color=(0.83, 0.69, 0.21), + label='', + on_activate_call=self._support) + ba.imagewidget( + parent=self.root_widget, + position=(self._width * 0.75 - 25, + self._height * 0.2 - 25), + size=(50, 50), + draw_controller=self.button_support, + texture=ba.gettexture('heart'), + color=(1, 1, 1)) + ba.textwidget( + parent=self.root_widget, + position=(self._width * 0.75, + self._height * 0.2 + text_spacing), + size=(0, 0), + scale=0.75, + draw_controller=self.button_support, + text='Support uwu.', + h_align='center', + v_align='center', + maxwidth=150, + color=(0.83, 0.69, 0.21)) + + def _discord(self): + ba.open_url('https://discord.gg/JyBY6haARJ') + + def _github(self): + ba.open_url('https://github.com/CrossJoy/Bombsquad-Modding') + + def _support(self): + ba.open_url('https://www.buymeacoffee.com/CrossJoy') + + def _transition_out(self) -> None: + if not self._transitioning_out: + self._transitioning_out = True + ba.containerwidget(edit=self.root_widget, transition='out_scale') + + def on_popup_cancel(self) -> None: + ba.playsound(ba.getsound('swish')) + self._transition_out() From d5101f63f04a6de7e74a5a380c0cc2497b997f8e Mon Sep 17 00:00:00 2001 From: Cross Joy <87638792+CrossJoy@users.noreply.github.com> Date: Wed, 14 Dec 2022 20:51:18 +0800 Subject: [PATCH 0327/1464] Add files via upload --- plugins/utilities/disco_light.py | 271 +++++++++++++++++++++++++++++++ 1 file changed, 271 insertions(+) create mode 100644 plugins/utilities/disco_light.py diff --git a/plugins/utilities/disco_light.py b/plugins/utilities/disco_light.py new file mode 100644 index 00000000..c9e7fb35 --- /dev/null +++ b/plugins/utilities/disco_light.py @@ -0,0 +1,271 @@ +"""Disco Light Mod: V1.0 +Made by Cross Joy""" + +# If anyone who wanna help me on giving suggestion/ fix bugs/ creating PR, +# Can visit my github https://github.com/CrossJoy/Bombsquad-Modding + +# You can contact me through discord: +# My Discord Id: Cross Joy#0721 +# My BS Discord Server: https://discord.gg/JyBY6haARJ + + +# ---------------------------------------------------------------------------- +# Add disco light into the game, so you can +# play with your friends under the colorful light. :) + +# type '/disco' in your chat box to activate or +# type '/disco off' to deactivate the disco light. + + +# Coop and multiplayer compatible. +# Work on any 1.7 ver. + +# Note: +# The plugin commands only works on the host with the plugin activated. +# Other clients/players can't use the commands. +# ---------------------------------------------------------------------------- + +# ba_meta require api 7 + + +from __future__ import annotations + +from typing import TYPE_CHECKING + +import ba +import _ba +from ba import _gameutils +import random + +from ba import animate + +if TYPE_CHECKING: + from typing import Sequence, Union + +# Check game ver. +def is_game_version_lower_than(version): + """ + Returns a boolean value indicating whether the current game + version is lower than the passed version. Useful for addressing + any breaking changes within game versions. + """ + game_version = tuple(map(int, ba.app.version.split("."))) + version = tuple(map(int, version.split("."))) + return game_version < version + + +if is_game_version_lower_than("1.7.7"): + ba_internal = _ba +else: + ba_internal = ba.internal + + +# Activate disco light. +def start(): + activity = _ba.get_foreground_host_activity() + + with ba.Context(activity): + partyLight(True) + rainbow(activity) + + +# Deactivate disco light. +def stop(): + activity = _ba.get_foreground_host_activity() + + with ba.Context(activity): + partyLight(False) + stop_rainbow(activity) + + +# Create and animate colorful spotlight. +def partyLight(switch=True): + from ba._nodeactor import NodeActor + x_spread = 10 + y_spread = 5 + positions = [[-x_spread, -y_spread], [0, -y_spread], [0, y_spread], + [x_spread, -y_spread], [x_spread, y_spread], + [-x_spread, y_spread]] + times = [0, 2700, 1000, 1800, 500, 1400] + + # Store this on the current activity, so we only have one at a time. + activity = _ba.getactivity() + activity.camera_flash_data = [] # type: ignore + for i in range(6): + r = random.choice([0.5, 1]) + g = random.choice([0.5, 1]) + b = random.choice([0.5, 1]) + light = NodeActor( + _ba.newnode('light', + attrs={ + 'position': (positions[i][0], 0, positions[i][1]), + 'radius': 1.0, + 'lights_volumes': False, + 'height_attenuated': False, + 'color': (r, g, b) + })) + sval = 1.87 + iscale = 1.3 + tcombine = _ba.newnode('combine', + owner=light.node, + attrs={ + 'size': 3, + 'input0': positions[i][0], + 'input1': 0, + 'input2': positions[i][1] + }) + assert light.node + tcombine.connectattr('output', light.node, 'position') + xval = positions[i][0] + yval = positions[i][1] + spd = 1.0 + random.random() + spd2 = 1.0 + random.random() + animate(tcombine, + 'input0', { + 0.0: xval + 0, + 0.069 * spd: xval + 10.0, + 0.143 * spd: xval - 10.0, + 0.201 * spd: xval + 0 + }, + loop=True) + animate(tcombine, + 'input2', { + 0.0: yval + 0, + 0.15 * spd2: yval + 10.0, + 0.287 * spd2: yval - 10.0, + 0.398 * spd2: yval + 0 + }, + loop=True) + animate(light.node, + 'intensity', { + 0.0: 0, + 0.02 * sval: 0, + 0.05 * sval: 0.8 * iscale, + 0.08 * sval: 0, + 0.1 * sval: 0 + }, + loop=True, + offset=times[i]) + if not switch: + _ba.timer(0.1, + light.node.delete) + activity.camera_flash_data.append(light) # type: ignore + + +# Create RGB tint. +def rainbow(self) -> None: + """Create RGB tint.""" + c_existing = self.globalsnode.tint + cnode = _ba.newnode('combine', + attrs={ + 'input0': c_existing[0], + 'input1': c_existing[1], + 'input2': c_existing[2], + 'size': 3 + }) + + _gameutils.animate(cnode, 'input0', + {0.0: 1.0, 1.0: 1.0, 2.0: 1.0, 3.0: 1.0, + 4.0: 0.2, 5.0: 0.1, 6.0: 0.5, + 7.0: 1.0}, loop=True) + + _gameutils.animate(cnode, 'input1', + {0.0: 0.2, 1.0: 0.2, 2.0: 0.5, 3.0: 1.0, + 4.0: 1.0, 5.0: 0.1, 6.0: 0.3, + 7.0: 0.2}, loop=True) + + _gameutils.animate(cnode, 'input2', + {0.0: 0.2, 1.0: 0.2, 2.0: 0.0, 3.0: 0.0, + 4.0: 0.2, 5.0: 1.0, 6.0: 1.0, + 7.0: 0.2}, loop=True) + + cnode.connectattr('output', self.globalsnode, 'tint') + + +# Revert to the original map tint. +def stop_rainbow(self): + """Revert to the original map tint.""" + c_existing = self.globalsnode.tint + map_name = self.map.getname() + tint = check_map_tint(map_name) + + cnode = _ba.newnode('combine', + attrs={ + 'input0': c_existing[0], + 'input1': c_existing[1], + 'input2': c_existing[2], + 'size': 3 + }) + + _gameutils.animate(cnode, 'input0', {0: c_existing[0], 1.0: tint[0]}) + _gameutils.animate(cnode, 'input1', {0: c_existing[1], 1.0: tint[1]}) + _gameutils.animate(cnode, 'input2', {0: c_existing[2], 1.0: tint[2]}) + + cnode.connectattr('output', self.globalsnode, 'tint') + + +# Check map name +def check_map_tint(map_name): + if map_name in 'Hockey Stadium': + tint = (1.2, 1.3, 1.33) + elif map_name in 'Football Stadium': + tint = (1.3, 1.2, 1.0) + elif map_name in 'Bridgit': + tint = (1.1, 1.2, 1.3) + elif map_name in 'Big G': + tint = (1.1, 1.2, 1.3) + elif map_name in 'Roundabout': + tint = (1.0, 1.05, 1.1) + elif map_name in 'Monkey Face': + tint = (1.1, 1.2, 1.2) + elif map_name in 'Zigzag': + tint = (1.0, 1.15, 1.15) + elif map_name in 'The Pad': + tint = (1.1, 1.1, 1.0) + elif map_name in 'Lake Frigid': + tint = (0.8, 0.9, 1.3) + elif map_name in 'Crag Castle': + tint = (1.15, 1.05, 0.75) + elif map_name in 'Tower D': + tint = (1.15, 1.11, 1.03) + elif map_name in 'Happy Thoughts': + tint = (1.3, 1.23, 1.0) + elif map_name in 'Step Right Up': + tint = (1.2, 1.1, 1.0) + elif map_name in 'Doom Shroom': + tint = (0.82, 1.10, 1.15) + elif map_name in 'Courtyard': + tint = (1.2, 1.17, 1.1) + elif map_name in 'Rampage': + tint = (1.2, 1.1, 0.97) + elif map_name in 'Tip Top': + tint = (0.8, 0.9, 1.3) + else: + tint = (1, 1, 1) + + return tint + + +# Get the original game codes. +old_fcm = ba_internal.chatmessage + + +# New chat func to add some commands to activate/deactivate the disco light. +def new_chat_message(msg: Union[str, ba.Lstr], clients: Sequence[int] = None, + sender_override: str = None): + old_fcm(msg, clients, sender_override) + if msg == '/disco': + start() + if msg == '/disco off': + stop() + + +# Replace new chat func to the original game codes. +ba_internal.chatmessage = new_chat_message +if not ba_internal.is_party_icon_visible(): + ba_internal.set_party_icon_always_visible(True) + + +# ba_meta export plugin +class ByCrossJoy(ba.Plugin): + def __init__(self): pass From 507667443cca5bfe5f1fbc477fb703dbed9fc442 Mon Sep 17 00:00:00 2001 From: Cross Joy <87638792+CrossJoy@users.noreply.github.com> Date: Wed, 14 Dec 2022 21:11:38 +0800 Subject: [PATCH 0328/1464] added disco_light and practice_tools --- plugins/utilities.json | 30 +++++++++++++++++++++++++++++- 1 file changed, 29 insertions(+), 1 deletion(-) diff --git a/plugins/utilities.json b/plugins/utilities.json index d58ff2da..8964040a 100644 --- a/plugins/utilities.json +++ b/plugins/utilities.json @@ -527,6 +527,34 @@ "md5sum": "6213bc2573cb83f8bf72030604801f5a" } } + }, + "disco_light": { + "description": "Add disco light into the game.", + "external_url": "", + "authors": [ + { + "name": "Cross Joy", + "email": "cross.joy.official@gmail.com", + "discord": "Cross Joy#0721" + } + ], + "versions": { + "1.0.0": null + } + }, + "practice_tools": { + "description": "Powerful and comprehensive tools for practice purpose. Practice tabs can be access through party window.", + "external_url": "", + "authors": [ + { + "name": "Cross Joy", + "email": "cross.joy.official@gmail.com", + "discord": "Cross Joy#0721" + } + ], + "versions": { + "1.0.0": null + } } } -} \ No newline at end of file +} From 800125c17f8ca1b96789642bb9b41045a9eb059f Mon Sep 17 00:00:00 2001 From: CrossJoy Date: Wed, 14 Dec 2022 13:13:28 +0000 Subject: [PATCH 0329/1464] [ci] auto-format --- plugins/utilities/disco_light.py | 2 + plugins/utilities/practice_tools.py | 159 ++++++++++++++-------------- 2 files changed, 80 insertions(+), 81 deletions(-) diff --git a/plugins/utilities/disco_light.py b/plugins/utilities/disco_light.py index c9e7fb35..b87553b5 100644 --- a/plugins/utilities/disco_light.py +++ b/plugins/utilities/disco_light.py @@ -43,6 +43,8 @@ from typing import Sequence, Union # Check game ver. + + def is_game_version_lower_than(version): """ Returns a boolean value indicating whether the current game diff --git a/plugins/utilities/practice_tools.py b/plugins/utilities/practice_tools.py index 803b0f94..c830adae 100644 --- a/plugins/utilities/practice_tools.py +++ b/plugins/utilities/practice_tools.py @@ -45,7 +45,8 @@ import weakref from enum import Enum from typing import TYPE_CHECKING -import ba, _ba +import ba +import _ba import ba.internal import bastd from bastd.actor.powerupbox import PowerupBox @@ -271,7 +272,7 @@ def setting(*args, **kwargs): }) if ba.app.config.get( - "bombCountdown") and bomb_type not in fuse_bomb: + "bombCountdown") and bomb_type not in fuse_bomb: color = (1.0, 1.0, 0.0) count_bomb(*args, count='3', color=color) color = (1.0, 0.5, 0.0) @@ -353,17 +354,17 @@ def _init_spaz_(self, *args, **kwargs): 'position') self.curse_visualizer_fatal = ba.newnode('locator', - owner=self.node, - # Remove itself when the bomb node dies. - attrs={ - 'shape': 'circle', - 'color': ( - 0.7, 0, 0), - 'size': (0.0, 0.0, 0.0), - 'opacity': 0.10, - 'draw_beauty': False, - 'additive': False - }) + owner=self.node, + # Remove itself when the bomb node dies. + attrs={ + 'shape': 'circle', + 'color': ( + 0.7, 0, 0), + 'size': (0.0, 0.0, 0.0), + 'opacity': 0.10, + 'draw_beauty': False, + 'additive': False + }) self.node.connectattr('position', self.curse_visualizer_fatal, 'position') @@ -423,7 +424,6 @@ def new_cursed(self): def bot_handlemessage(self, msg: Any): - if isinstance(msg, ba.PowerupMessage): if msg.poweruptype == 'health': if ba.app.config.get("bombRadiusVisual"): @@ -498,7 +498,6 @@ def bot_handlemessage(self, msg: Any): }) - Spaz.handlemessage = bot_handlemessage @@ -546,48 +545,48 @@ def __init__(self): super().__init__() def _update(self) -> None: - try: - with ba.Context(_ba.get_foreground_host_activity()): - # Update one of our bot lists each time through. - # First off, remove no-longer-existing bots from the list. + try: + with ba.Context(_ba.get_foreground_host_activity()): + # Update one of our bot lists each time through. + # First off, remove no-longer-existing bots from the list. + try: + bot_list = self._bot_lists[self._bot_update_list] = ([ + b for b in self._bot_lists[self._bot_update_list] if b + ]) + except Exception: + bot_list = [] + ba.print_exception('Error updating bot list: ' + + str(self._bot_lists[ + self._bot_update_list])) + self._bot_update_list = (self._bot_update_list + + 1) % self._bot_list_count + + # Update our list of player points for the bots to use. + player_pts = [] + for player in ba.getactivity().players: + assert isinstance(player, ba.Player) try: - bot_list = self._bot_lists[self._bot_update_list] = ([ - b for b in self._bot_lists[self._bot_update_list] if b - ]) + # TODO: could use abstracted player.position here so we + # don't have to assume their actor type, but we have no + # abstracted velocity as of yet. + if player.is_alive(): + assert isinstance(player.actor, Spaz) + assert player.actor.node + player_pts.append( + (ba.Vec3(player.actor.node.position), + ba.Vec3( + player.actor.node.velocity))) except Exception: - bot_list = [] - ba.print_exception('Error updating bot list: ' + - str(self._bot_lists[ - self._bot_update_list])) - self._bot_update_list = (self._bot_update_list + - 1) % self._bot_list_count - - # Update our list of player points for the bots to use. - player_pts = [] - for player in ba.getactivity().players: - assert isinstance(player, ba.Player) - try: - # TODO: could use abstracted player.position here so we - # don't have to assume their actor type, but we have no - # abstracted velocity as of yet. - if player.is_alive(): - assert isinstance(player.actor, Spaz) - assert player.actor.node - player_pts.append( - (ba.Vec3(player.actor.node.position), - ba.Vec3( - player.actor.node.velocity))) - except Exception: - ba.print_exception('Error on bot-set _update.') - - for bot in bot_list: - if not ba.app.config.get('stopBots'): - bot.set_player_points(player_pts) - bot.update_ai() - - ba.app.config["disablePractice"] = True - except: - ba.app.config["disablePractice"] = False + ba.print_exception('Error on bot-set _update.') + + for bot in bot_list: + if not ba.app.config.get('stopBots'): + bot.set_player_points(player_pts) + bot.update_ai() + + ba.app.config["disablePractice"] = True + except: + ba.app.config["disablePractice"] = False def clear(self) -> None: """Immediately clear out any bots in the set.""" @@ -603,11 +602,11 @@ def clear(self) -> None: self._bot_lists[i] = [] def spawn_bot( - self, - bot_type: type[SpazBot], - pos: Sequence[float], - spawn_time: float = 3.0, - on_spawn_call: Callable[[SpazBot], Any] | None = None) -> None: + self, + bot_type: type[SpazBot], + pos: Sequence[float], + spawn_time: float = 3.0, + on_spawn_call: Callable[[SpazBot], Any] | None = None) -> None: """Spawn a bot from this set.""" from bastd.actor import spawner spawner.Spawner(pt=pos, @@ -635,24 +634,23 @@ class DummyBotSet(NewBotSet): def _update(self) -> None: - try: - with ba.Context(_ba.get_foreground_host_activity()): - # Update one of our bot lists each time through. - # First off, remove no-longer-existing bots from the list. - try: - bot_list = self._bot_lists[self._bot_update_list] = ([ - b for b in self._bot_lists[self._bot_update_list] if b - ]) - except Exception: - ba.print_exception('Error updating bot list: ' + - str(self._bot_lists[ - self._bot_update_list])) - self._bot_update_list = (self._bot_update_list + - 1) % self._bot_list_count - + try: + with ba.Context(_ba.get_foreground_host_activity()): + # Update one of our bot lists each time through. + # First off, remove no-longer-existing bots from the list. + try: + bot_list = self._bot_lists[self._bot_update_list] = ([ + b for b in self._bot_lists[self._bot_update_list] if b + ]) + except Exception: + ba.print_exception('Error updating bot list: ' + + str(self._bot_lists[ + self._bot_update_list])) + self._bot_update_list = (self._bot_update_list + + 1) % self._bot_list_count - except: - pass + except: + pass class DummyBot(SpazBot): @@ -1085,7 +1083,7 @@ def _update_character(self, change: int = 0) -> None: 'Pro Bomber', 'Pro Brawler', 'Pro Trigger', 'Pro Charger', 'S.Pro Bomber', 'S.Pro Brawler', - 'S.Pro Trigger', 'S.Pro Charger'): + 'S.Pro Trigger', 'S.Pro Charger'): tint1 = (1.0, 0.2, 0.1) tint2 = (0.6, 0.1, 0.05) elif self.bot_array_name[self._icon_index] in 'Bouncy': @@ -1097,7 +1095,7 @@ def _update_character(self, change: int = 0) -> None: if self.bot_array_name[self._icon_index] in ( 'S.Pro Bomber', 'S.Pro Brawler', - 'S.Pro Trigger', 'S.Pro Charger'): + 'S.Pro Trigger', 'S.Pro Charger'): color = (1.3, 1.2, 3.0) else: color = (1.0, 1.0, 1.0) @@ -1296,8 +1294,7 @@ def get_powerup(self, clid: int = -1) -> None: i.node.position[1], i.node.position[2] + z) PowerupBox(position=pos, - poweruptype= - self.power_list_type + poweruptype=self.power_list_type [self._icon_index]).autoretain() def _power_window(self) -> None: From b0c06d27f97af55f785830a1ad9475cdd75c6762 Mon Sep 17 00:00:00 2001 From: CrossJoy Date: Wed, 14 Dec 2022 13:13:29 +0000 Subject: [PATCH 0330/1464] [ci] apply-version-metadata --- plugins/utilities.json | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/plugins/utilities.json b/plugins/utilities.json index 8964040a..8737a94a 100644 --- a/plugins/utilities.json +++ b/plugins/utilities.json @@ -539,7 +539,12 @@ } ], "versions": { - "1.0.0": null + "1.0.0": { + "api_version": 7, + "commit_sha": "800125c", + "released_on": "14-12-2022", + "md5sum": "616f31da667ea3663efe449c67a0e032" + } } }, "practice_tools": { @@ -553,8 +558,13 @@ } ], "versions": { - "1.0.0": null + "1.0.0": { + "api_version": 7, + "commit_sha": "800125c", + "released_on": "14-12-2022", + "md5sum": "a04c30c11a43443fe192fe70ad528f22" + } } } } -} +} \ No newline at end of file From 2b4d6df5dc805c14716fdc3a176af9a563fed3af Mon Sep 17 00:00:00 2001 From: Rikko Date: Sat, 17 Dec 2022 20:16:59 +0530 Subject: [PATCH 0331/1464] Lock autopep8 to 2.0.0 --- .github/workflows/ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 2feffb79..621ca6af 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -26,7 +26,7 @@ jobs: - name: Install Dependencies run: | python -m pip install --upgrade pip - pip install autopep8 + pip install autopep8==2.0.0 pip install -r test/pip_reqs.txt - name: Apply AutoPEP8 run: | From 840bedfcef6ed9645ebe070e7db1243b670d216b Mon Sep 17 00:00:00 2001 From: Rikko Date: Sat, 17 Dec 2022 20:10:00 +0530 Subject: [PATCH 0332/1464] Workaround DNS blocks --- plugin_manager.py | 99 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 99 insertions(+) diff --git a/plugin_manager.py b/plugin_manager.py index 921983d3..8b9b2571 100644 --- a/plugin_manager.py +++ b/plugin_manager.py @@ -4,7 +4,11 @@ from bastd.ui import popup import urllib.request +import http.client +import socket +import ssl import json + import os import sys import asyncio @@ -110,6 +114,100 @@ def partial_format(string_template, **kwargs): return string_template +class DNSBlockWorkaround: + """ + Some ISPs put a DNS block on domains that are needed for plugin manager to + work properly. This class stores methods to workaround such blocks by adding + dns.google as a fallback. + + Such as Jio, a pretty popular ISP in India has a DNS block on + raw.githubusercontent.com (sigh..). + + Usage: + ----- + >>> import urllib.request + >>> import http.client + >>> import socket + >>> import ssl + >>> import json + >>> DNSBlockWorkaround.apply() + >>> response = urllib.request.urlopen("https://dnsblockeddomain.com/path/to/resource/") + """ + + _google_dns_cache = {} + + def apply(): + opener = urllib.request.build_opener( + DNSBlockWorkaround._HTTPHandler, + DNSBlockWorkaround._HTTPSHandler, + ) + urllib.request.install_opener(opener) + + def _resolve_using_google_dns(hostname): + response = urllib.request.urlopen(f"https://dns.google/resolve?name={hostname}") + response = response.read() + response = json.loads(response) + resolved_host = response["Answer"][0]["data"] + return resolved_host + + def _resolve_using_system_dns(hostname): + resolved_host = socket.gethostbyname(hostname) + return resolved_host + + def _resolve_with_workaround(hostname): + resolved_host_from_cache = DNSBlockWorkaround._google_dns_cache.get(hostname) + if resolved_host_from_cache: + return resolved_host_from_cache + + resolved_host_by_system_dns = DNSBlockWorkaround._resolve_using_system_dns(hostname) + + if DNSBlockWorkaround._is_blocked(hostname, resolved_host_by_system_dns): + resolved_host = DNSBlockWorkaround._resolve_using_google_dns(hostname) + DNSBlockWorkaround._google_dns_cache[hostname] = resolved_host + else: + resolved_host = resolved_host_by_system_dns + + return resolved_host + + def _is_blocked(hostname, address): + is_blocked = False + if hostname == "raw.githubusercontent.com": + # Jio's DNS server may be blocking it. + is_blocked = address.startswith("49.44.") + + return is_blocked + + class _HTTPConnection(http.client.HTTPConnection): + def connect(self): + host = DNSBlockWorkaround._resolve_with_workaround(self.host) + self.sock = socket.create_connection( + (host, self.port), + self.timeout, + ) + + class _HTTPSConnection(http.client.HTTPSConnection): + def connect(self): + host = DNSBlockWorkaround._resolve_with_workaround(self.host) + sock = socket.create_connection( + (host, self.port), + self.timeout, + ) + context = ssl.SSLContext(ssl.PROTOCOL_TLS_CLIENT) + context.verify_mode = ssl.CERT_REQUIRED + context.check_hostname = True + context.load_default_certs() + sock = context.wrap_socket(sock, server_hostname=self.host) + self.sock = sock + + class _HTTPHandler(urllib.request.HTTPHandler): + def http_open(self, req): + return self.do_open(DNSBlockWorkaround._HTTPConnection, req) + + class _HTTPSHandler(urllib.request.HTTPSHandler): + def https_open(self, req): + return self.do_open(DNSBlockWorkaround._HTTPSConnection, req) + + class StartupTasks: def __init__(self): self.plugin_manager = PluginManager() @@ -2155,6 +2253,7 @@ def on_app_running(self) -> None: """Called when the app is being launched.""" from bastd.ui.settings import allsettings allsettings.AllSettingsWindow = NewAllSettingsWindow + DNSBlockWorkaround.apply() asyncio.set_event_loop(ba._asyncio._asyncio_event_loop) startup_tasks = StartupTasks() loop = asyncio.get_event_loop() From 8ac1032d7147bbf49fd352471df2a659c1e9a9c2 Mon Sep 17 00:00:00 2001 From: Rikko Date: Sat, 17 Dec 2022 20:11:38 +0530 Subject: [PATCH 0333/1464] Release v0.2.1 --- index.json | 3 ++- plugin_manager.py | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/index.json b/index.json index 15e80967..2ba99606 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.1": null, "0.2.0": { "api_version": 7, "commit_sha": "bd9dc14", @@ -56,4 +57,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 8b9b2571..51051adc 100644 --- a/plugin_manager.py +++ b/plugin_manager.py @@ -24,7 +24,7 @@ _uiscale = ba.app.ui.uiscale -PLUGIN_MANAGER_VERSION = "0.2.0" +PLUGIN_MANAGER_VERSION = "0.2.1" REPOSITORY_URL = "https://github.com/bombsquad-community/plugin-manager" CURRENT_TAG = "main" INDEX_META = "{repository_url}/{content_type}/{tag}/index.json" From 6ef738e29a1cc6016246b496c1e5714fbbf42a8a Mon Sep 17 00:00:00 2001 From: rikkolovescats Date: Sat, 17 Dec 2022 14:48:54 +0000 Subject: [PATCH 0334/1464] [ci] apply-version-metadata --- index.json | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/index.json b/index.json index 2ba99606..ae7beedd 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.1": null, + "0.2.1": { + "api_version": 7, + "commit_sha": "8ac1032", + "released_on": "17-12-2022", + "md5sum": "de90e0b02c450f521c9fef4081239eca" + }, "0.2.0": { "api_version": 7, "commit_sha": "bd9dc14", @@ -57,4 +62,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 59974adb993d31ca9c5b90a487e0c88ce724bb4b Mon Sep 17 00:00:00 2001 From: Rikko Date: Sat, 17 Dec 2022 22:28:44 +0530 Subject: [PATCH 0335/1464] 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 51051adc..0b89e5ec 100644 --- a/plugin_manager.py +++ b/plugin_manager.py @@ -1420,7 +1420,6 @@ def __init__(self, transition: str = "in_right", origin_widget: ba.Widget = None ) def _back(self) -> None: - play_sound() from bastd.ui.settings.allsettings import AllSettingsWindow ba.containerwidget(edit=self._root_widget, transition=self._transition_out) From fab37b4eca905d19ebb342614c00b1823699e7e6 Mon Sep 17 00:00:00 2001 From: Loup <90267658+Loup-Garou911XD@users.noreply.github.com> Date: Sat, 17 Dec 2022 23:21:19 +0530 Subject: [PATCH 0336/1464] Added download button in readme --- README.md | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/README.md b/README.md index 9b04627a..d01dd747 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,14 @@ +[![DownloadIcon]][DownloadLink] + [![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 + + +[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@latest/plugin_manager.py + 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. From b91780b6848ef5d52911a9882263fa7dad4e04b0 Mon Sep 17 00:00:00 2001 From: Loup <90267658+Loup-Garou911XD@users.noreply.github.com> Date: Sat, 17 Dec 2022 23:52:14 +0530 Subject: [PATCH 0337/1464] Fixed download url --- README.md | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index d01dd747..019bc370 100644 --- a/README.md +++ b/README.md @@ -1,13 +1,14 @@ [![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 -[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@latest/plugin_manager.py 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. From 0d49b20ac47ea59f5b8bbac2d2a6d5eae30f9db7 Mon Sep 17 00:00:00 2001 From: Loup <90267658+Loup-Garou911XD@users.noreply.github.com> Date: Sat, 17 Dec 2022 23:59:42 +0530 Subject: [PATCH 0338/1464] Removed line breaks --- README.md | 3 --- 1 file changed, 3 deletions(-) diff --git a/README.md b/README.md index 019bc370..b7d90c62 100644 --- a/README.md +++ b/README.md @@ -7,9 +7,6 @@ # plugin-manager - - - 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. From e5c8a8e2a1e4421fc6d4e8772f63f250735a73fa Mon Sep 17 00:00:00 2001 From: Rikko Date: Sun, 18 Dec 2022 03:58:57 +0530 Subject: [PATCH 0339/1464] Update README.md --- README.md | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index b7d90c62..359e776a 100644 --- a/README.md +++ b/README.md @@ -31,9 +31,8 @@ which makes further modding of your game more convenient by providing easier acc There are two different ways the plugin manager can be installed: -1. [Download Plugin Manager.py](https://bombsquad-community.github.io/bombsquad-web/pluginmanager) - to your mods directory (check it out by going into your game's Settings -> Advanced -> Show Mods Folder). This is the - recommended way (read next method to know why). +1. [Download plugin_manager.py][DownloadLink] to your mods directory (check it out by going into your game's + Settings -> Advanced -> Show Mods Folder). This is the recommended way (read next method to know why). 2. Another way is to add [plugin_manager.py](https://raw.githubusercontent.com/bombsquad-community/plugin-manager/main/plugin_manager.py) From 763c1fdb61894a2aacb9b1218d72ea26ec8c6e65 Mon Sep 17 00:00:00 2001 From: Rikko Date: Sun, 18 Dec 2022 04:08:53 +0530 Subject: [PATCH 0340/1464] Add changelog entry for v0.2.1 --- CHANGELOG.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 63fb9e3d..f87732c9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,9 @@ ## Plugin Manager (dd-mm-yyyy) +### 0.2.1 (17-12-2022) + +- Add Google DNS as a fallback for Jio ISP DNS blocking resolution of raw.githubusercontent.com domain. + ### 0.2.0 (05-12-2022) - Removed `on_plugin_manager_prompt` and replaced it with the in-game's plugin settings ui 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 0341/1464] Moved download button --- README.md | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index b7d90c62..6d071095 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 90572f7b5d408078f58d0531181eff1b3f837b21 Mon Sep 17 00:00:00 2001 From: Ayush Saini <36878972+imayushsaini@users.noreply.github.com> Date: Sun, 18 Dec 2022 16:52:31 +0530 Subject: [PATCH 0342/1464] server ip fix in APW,server switch, server banning in easy connect, search by ip --- plugins/utilities/advanced_party_window.py | 23 ++--- plugins/utilities/easy_connect.py | 100 ++++++++++++++++++++- plugins/utilities/server_switch.py | 8 +- 3 files changed, 112 insertions(+), 19 deletions(-) diff --git a/plugins/utilities/advanced_party_window.py b/plugins/utilities/advanced_party_window.py index d3496428..d40b7181 100644 --- a/plugins/utilities/advanced_party_window.py +++ b/plugins/utilities/advanced_party_window.py @@ -42,14 +42,15 @@ import _ba from typing import TYPE_CHECKING, cast import urllib.request +import urllib.parse from _thread import start_new_thread import threading version_str = "7" - +BCSSERVER = 'api2.bombsquad.ga' cache_chat = [] -connect = _ba.connect_to_party -disconnect = _ba.disconnect_from_host +connect = ba.internal.connect_to_party +disconnect = ba.internal.disconnect_from_host unmuted_names = [] smo_mode = 3 f_chat = False @@ -66,6 +67,7 @@ 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() @@ -543,7 +545,7 @@ def __init__(self, origin: Sequence[float] = (0, 0)): size=(20, 5), color=(0.45, 0.63, 0.15), position=(self._width/2 - 20, 50), - text='', + text="Ping:"+str(current_ping)+" ms", selectable=True, autoselect=False, v_align='center') @@ -934,8 +936,8 @@ def _send_chat_message(self) -> None: _ba.chatmessage("script version "+s_v+"- build "+str(s_build)) ba.textwidget(edit=self._text_field, text="") return - elif sendtext == ".ping disabled": - PingThread(ip_add, p_port).start() + elif sendtext == ".ping": + _ba.chatmessage("My ping:"+str(current_ping)) ba.textwidget(edit=self._text_field, text="") return elif sendtext == ".save": @@ -1721,8 +1723,9 @@ def fetchAccountInfo(account, loading_widget): fdata = json.load(f) if account in fdata: servers = fdata[account] - data = urllib.request.urlopen( - f'https://api.bombsquad.ga/player?key={base64.b64encode(account.encode("utf-8")).decode("utf-8")}&base64=true') + 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"] @@ -2172,12 +2175,10 @@ def _on_query_response(self, data): 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: - _ba.connect_to_party = newconnect_to_party + ba.internal.connect_to_party = newconnect_to_party bastd_party.PartyWindow = ModifiedPartyWindow else: print("AdvancePartyWindow only runs with BombSquad version equal or higher than 1.7") diff --git a/plugins/utilities/easy_connect.py b/plugins/utilities/easy_connect.py index e55f1012..3b3a26ef 100644 --- a/plugins/utilities/easy_connect.py +++ b/plugins/utilities/easy_connect.py @@ -45,7 +45,23 @@ from bastd.ui.popup import PopupMenuWindow, PopupWindow from typing import Any, Optional, Dict, List, Tuple, Type, Union, Callable from bastd.ui.gather.publictab import PublicGatherTab - +import json +import urllib.request +import time + + +ENABLE_SERVER_BANNING = True +DEBUG_SERVER_COMMUNICATION = False +DEBUG_PROCESSING = False +""" +This banned servers list is maintained by commmunity , its not official. +Reason for ban can be (not limited to) using abusive server names , using server name of a reputed server/community +without necessary permissions. +Report such case on community discord channels +https://discord.gg/ucyaesh +https://ballistica.net/discord +""" +BCSURL = 'https://bcsserver.bombsquad.ga/bannedservers' def is_game_version_lower_than(version): """ @@ -63,6 +79,23 @@ def is_game_version_lower_than(version): else: ba_internal = ba.internal +def updateBannedServersCache(): + response = None + config = ba.app.config + if not isinstance(config.get('Banned Servers'), list): + config['Banned Servers'] = [] + try: + response = urllib.request.urlopen(BCSURL).read() + data = json.loads(response.decode('utf-8')) + bannedlist = [] + for server in data["servers"]: + bannedlist.append(server["ip"]) + config['Banned Servers'] = bannedlist + config.commit() + print("updated cache") + except Exception as e: + print(e) + class _HostLookupThread(threading.Thread): """Thread to fetch an addr.""" @@ -453,7 +486,6 @@ def popup_menu_selected_choice(self, window: popup.PopupMenu, 'UNKNOWN')) ba.open_url(url) elif choice == 'connect': - PartyQuickConnect(_party.address, _party.port) elif choice == 'save': config = ba.app.config @@ -475,6 +507,63 @@ def popup_menu_selected_choice(self, window: popup.PopupMenu, ba.playsound(ba.getsound('gunCocking')) +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) + + 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.' + ) + def replace(): manualtab.ManualGatherTab._build_favorites_tab = new_build_favorites_tab manualtab.ManualGatherTab._on_favorites_connect_press = new_on_favorites_connect_press @@ -485,6 +574,7 @@ def replace(): publictab.UIRow.on_stats_click = on_stats_click publictab.UIRow.popup_menu_closing = popup_menu_closing publictab.UIRow.popup_menu_selected_choice = popup_menu_selected_choice + publictab.PublicGatherTab._update_party_lists = _update_party_lists class PartyQuickConnect(ba.Window): @@ -601,9 +691,11 @@ def close(self) -> None: self.closed = True ba.containerwidget(edit=self._root_widget, transition='out_scale') -# ba_meta export plugin - +# ba_meta export plugin class InitalRun(ba.Plugin): def __init__(self): replace() + config = ba.app.config + if config["launchCount"]% 5 ==0: + updateBannedServersCache() diff --git a/plugins/utilities/server_switch.py b/plugins/utilities/server_switch.py index 66b90bd2..ecd3c398 100644 --- a/plugins/utilities/server_switch.py +++ b/plugins/utilities/server_switch.py @@ -22,8 +22,8 @@ import bastd.ui.mainmenu as bastd_ui_mainmenu -connect = _ba.connect_to_party -disconnect = _ba.disconnect_from_host +connect = ba.internal.connect_to_party +disconnect = ba.internal.disconnect_from_host server = [] @@ -566,7 +566,7 @@ class bySmoothy(ba.Plugin): def __init__(self): if _ba.env().get("build_number", 0) >= 20577: bastd_ui_mainmenu.MainMenuWindow._refresh_in_game = new_refresh_in_game - _ba.connect_to_party = newconnect_to_party - _ba.disconnect_from_host = newdisconnect_from_host + ba.internal.connect_to_party = newconnect_to_party + ba.internal.disconnect_from_host = newdisconnect_from_host else: print("Server Switch only works on bs 1.7 and above") From f86623a09ad4c5935ed0f7e85d12374b50f29431 Mon Sep 17 00:00:00 2001 From: imayushsaini Date: Sun, 18 Dec 2022 11:24:08 +0000 Subject: [PATCH 0343/1464] [ci] auto-format --- plugins/utilities/advanced_party_window.py | 6 +- plugins/utilities/easy_connect.py | 111 +++++++++++---------- 2 files changed, 61 insertions(+), 56 deletions(-) diff --git a/plugins/utilities/advanced_party_window.py b/plugins/utilities/advanced_party_window.py index d40b7181..8f36b022 100644 --- a/plugins/utilities/advanced_party_window.py +++ b/plugins/utilities/advanced_party_window.py @@ -67,7 +67,7 @@ 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 @@ def _on_query_response(self, data): 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 3b3a26ef..d14745ca 100644 --- a/plugins/utilities/easy_connect.py +++ b/plugins/utilities/easy_connect.py @@ -63,6 +63,7 @@ """ 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 @@ def is_game_version_lower_than(version): 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) - - self._parties_sorted.sort( - key=lambda p: ( - p[1].ping if p[1].ping is not None else 999999.0, - p[1].index, - ) - ) + 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 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 = {} + 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: - 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.' - ) + 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 0344/1464] 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 8737a94a..f9d2b2cc 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 0345/1464] [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 f9d2b2cc..80af302f 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 0346/1464] Updated share_replay to v1.3.0 --- plugins/utilities.json | 3 +- plugins/utilities/share_replay.py | 478 +++++++++++++++++++----------- 2 files changed, 312 insertions(+), 169 deletions(-) diff --git a/plugins/utilities.json b/plugins/utilities.json index 80af302f..d134e88a 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 99098164..f442dcd5 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 @@ 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,193 +60,270 @@ 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) + +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 + + +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 sync(self): + internal_list = listdir(internal_dir) + external_list = listdir(external_dir) + for i in internal_list: + copy(internal_dir+sep+i, external_dir+sep+i) + for i in external_list: + if i in internal_list: + pass + else: + copy(external_dir+sep+i, internal_dir+sep+i) + Print("Synced all replays", 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() + + +class MyTabId(Enum): + INTERNAL = "internal" + EXTERNAL = "external" + SHARE_REPLAYS = "share_replay" + 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,) + 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.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)") + 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 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 ShareTabUi(WatchWindow): + def __init__(self, root_widget=None): + self.tab_id = MyTabId.INTERNAL + self.selected_replay = None - class TabId(Enum): - INTERNAL = "internal" - EXTERNAL = "external" + 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() - 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) + 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, 1, 0)) - self.selected_name = name + 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 - if tab_id == self.TabId.INTERNAL: + t_scale = 1.6 + + if tab_id == MyTabId.INTERNAL: dir_list = listdir(internal_dir) - ba.buttonwidget(edit=self.share_button, label="EXPORT", icon=ba.gettexture("upButton"),) - else: + ba.buttonwidget(edit=self.share_button, label="Export\nReplay") + else: dir_list = listdir(external_dir) - ba.buttonwidget(edit=self.share_button, label="IMPORT", - icon=ba.gettexture("downButton"),) + 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: + if existing_widgets:# deleting textwidgets from old tab for i in existing_widgets: i.delete() - height = 900 - # making textwidgets for all replays - for i in dir_list: - height -= 40 + height = 900 + for i in dir_list:# making textwidgets for all replays + height -= 50 a = i i = ba.textwidget( parent=self.scroll2, - size=(500, 50), + size=(self._my_replays_scroll_width/t_scale, 30), text=i.split(".")[0], - position=(10, height), + position=(20, height), selectable=True, max_chars=40, - corner_scale=1.3, - click_activate=True,) + 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.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) - for i in internal_list: - copy(internal_dir+sep+i, external_dir+sep+i) - for i in external_list: - if i in internal_list: - pass - else: - 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 importx(self): - copy(external_dir+self.selected_name, internal_dir+self.selected_name) - Print(self.selected_name[0:-4]+" imported", top=True, color=green) + + 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 @@ def close(self): #ba.widget(edit=self.enable_button, up_widget=decrease_button, down_widget=self.lower_text,left_widget=save_button, right_widget=save_button) -# -------------------------------------------------------------------------------------------------- +# ---------------------------------------------------------------------------------------------------- + +class ShareTab(WatchWindow): -ww.__old_init__ = ww.__init__ + @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) + self._tab_row.tabs[self.TabID.MY_REPLAYS].button.delete() # deleting old tab button -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) + 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 0347/1464] [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 f442dcd5..cbf94bf7 100644 --- a/plugins/utilities/share_replay.py +++ b/plugins/utilities/share_replay.py @@ -18,7 +18,7 @@ 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 @@ 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 @@ def cprint(*args): 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 @@ def sync(self): 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 @@ def __init__(self, root_widget=None): 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 @@ 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: + 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 @@ def on_tab_select(self, tab_id): 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 + 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 -2 + else 45 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) + 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 @@ def has_settings_ui(self): 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 0348/1464] [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 d134e88a..3eea4a50 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 0349/1464] 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 3eea4a50..cb5357f6 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 00000000..01eb704a --- /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 0350/1464] [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 01eb704a..955b1a2c 100644 --- a/plugins/utilities/random_join.py +++ b/plugins/utilities/random_join.py @@ -6,7 +6,7 @@ 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 decorator(newfunc: 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 @@ def _get_parties_list(self) -> list[PartyEntry]: @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 0351/1464] [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 cb5357f6..8f801afd 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 0352/1464] 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 00000000..b9206107 --- /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 0353/1464] Update utilities.json --- plugins/utilities.json | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/plugins/utilities.json b/plugins/utilities.json index 8f801afd..7951c69b 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 0354/1464] [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 b9206107..263b1b43 100644 --- a/plugins/utilities/autorun.py +++ b/plugins/utilities/autorun.py @@ -26,7 +26,7 @@ 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 @@ """ # 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 @@ def dot(vector_a, vector_b): 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 @@ def normalize(vector): # 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 @@ def spaz_autorun_update(): # 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 @@ def spaz_autorun_update(): # 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 @@ def run_update(self) -> None: # 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 @@ def wrapper(*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): @@ -228,7 +232,7 @@ def wrapper(*args, **kwargs): 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 @@ def wrapper(*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) - + 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 0355/1464] 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 7951c69b..281fdfb8 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 0356/1464] [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 281fdfb8..a16085d6 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 0357/1464] 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 a16085d6..3b525aef 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 0358/1464] 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 00000000..bbcdc99c --- /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 0359/1464] 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 0360/1464] [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 bbcdc99c..50051093 100644 --- a/plugins/utilities/tnt_respawn_text.py +++ b/plugins/utilities/tnt_respawn_text.py @@ -24,7 +24,7 @@ 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 @@ def on_tnt_exploded(self): # 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 @@ def wrapper(*args, **kwargs): 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 @@ def wrapper(*args, **kwargs): # 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 @@ def tnt_callback(): # 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 @@ def wrapper(*args, **kwargs): ) # 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 0361/1464] [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 3b525aef..fee7b87f 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 0362/1464] 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 51051adc..6521b167 100644 --- a/plugin_manager.py +++ b/plugin_manager.py @@ -787,6 +787,23 @@ def __init__(self, plugin, origin_widget, button_callback=lambda: None): 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 0363/1464] [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 6521b167..db7fef63 100644 --- a/plugin_manager.py +++ b/plugin_manager.py @@ -787,7 +787,7 @@ def __init__(self, plugin, origin_widget, button_callback=lambda: None): 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 @@ def partition(string, minimum_character_offset=40): 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 0364/1464] 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 fee7b87f..d2db80c5 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 0365/1464] [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 d2db80c5..57a58b03 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 0366/1464] 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 db7fef63..8854954d 100644 --- a/plugin_manager.py +++ b/plugin_manager.py @@ -788,27 +788,29 @@ def __init__(self, plugin, origin_widget, button_callback=lambda: None): 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 @@ async def draw_ui(self): 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 0367/1464] [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 8854954d..246c29e5 100644 --- a/plugin_manager.py +++ b/plugin_manager.py @@ -790,7 +790,7 @@ def __init__(self, plugin, origin_widget, button_callback=lambda: None): 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 @@ def get_description(minimum_character_offset=40): 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 @@ def get_description(minimum_character_offset=40): 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 0368/1464] get_description as a class method --- plugin_manager.py | 43 ++++++++++++++++++++++++------------------- 1 file changed, 24 insertions(+), 19 deletions(-) diff --git a/plugin_manager.py b/plugin_manager.py index 246c29e5..11539bca 100644 --- a/plugin_manager.py +++ b/plugin_manager.py @@ -788,28 +788,33 @@ def __init__(self, plugin, origin_widget, button_callback=lambda: None): 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) - - partitioned_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_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 @@ def get_description(minimum_character_offset=40): 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 0369/1464] 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 57a58b03..63ac4286 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 0370/1464] [ci] auto-format --- plugin_manager.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/plugin_manager.py b/plugin_manager.py index 11539bca..5c00c250 100644 --- a/plugin_manager.py +++ b/plugin_manager.py @@ -788,7 +788,6 @@ def __init__(self, plugin, origin_widget, button_callback=lambda: None): 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 @@ def get_description(self, minimum_character_offset=40): 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 0371/1464] [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 63ac4286..ad3ad278 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 0372/1464] 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 f87732c9..d0c47810 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 ae7beedd..a0bafaab 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 c29f7f68..16501384 100644 --- a/plugin_manager.py +++ b/plugin_manager.py @@ -24,7 +24,7 @@ _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 0373/1464] [ci] apply-version-metadata --- index.json | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/index.json b/index.json index a0bafaab..7ed3695d 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 0374/1464] ee --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index d0c47810..0a46809f 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 0375/1464] 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 ad3ad278..3dde59ea 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 00000000..b2d1403a --- /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 0376/1464] [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 3dde59ea..c1a86a6d 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 0377/1464] Mention about known 3rd party plugin sources --- README.md | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/README.md b/README.md index c2a3c316..a07a3e54 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 0378/1464] 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 c1a86a6d..6ca1180c 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 00000000..7ccac787 --- /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 0379/1464] [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 7ccac787..909a5df1 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 0380/1464] [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 6ca1180c..00be2248 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 0381/1464] 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 00be2248..8e50073c 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 909a5df1..16b4030f 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 @@ 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 0382/1464] [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 8e50073c..8cf4c619 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 0383/1464] 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 8cf4c619..e7be458a 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 16b4030f..909a5df1 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 @@ 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 0384/1464] [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 e7be458a..bb7270cb 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 0385/1464] 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 bb7270cb..5df193a4 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 909a5df1..00000000 --- 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 0386/1464] [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 5df193a4..c1a86a6d 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 0387/1464] 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 16501384..ccd35f68 100644 --- a/plugin_manager.py +++ b/plugin_manager.py @@ -960,6 +960,35 @@ async def draw_ui(self): 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 0388/1464] 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 ccd35f68..67fe530d 100644 --- a/plugin_manager.py +++ b/plugin_manager.py @@ -962,33 +962,35 @@ async def draw_ui(self): 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 0389/1464] 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 67fe530d..e789d078 100644 --- a/plugin_manager.py +++ b/plugin_manager.py @@ -24,7 +24,7 @@ _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 0390/1464] [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 e789d078..412575cc 100644 --- a/plugin_manager.py +++ b/plugin_manager.py @@ -960,8 +960,8 @@ async def draw_ui(self): 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 0391/1464] 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 0a46809f..26bf6515 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 0392/1464] typo in the changelog --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 26bf6515..6088c33d 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 0393/1464] 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 e789d078..5fdcbe7a 100644 --- a/plugin_manager.py +++ b/plugin_manager.py @@ -960,12 +960,12 @@ async def draw_ui(self): 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 0394/1464] 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 0a46809f..d809d66d 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 0395/1464] 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 16501384..435a0f17 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 @@ def get_description(self, minimum_character_offset=40): 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 @@ async def draw_ui(self): 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 0396/1464] 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 7ed3695d..c2ba40e6 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 435a0f17..9efe976e 100644 --- a/plugin_manager.py +++ b/plugin_manager.py @@ -24,7 +24,7 @@ _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 0397/1464] 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 9efe976e..b97ae1a5 100644 --- a/plugin_manager.py +++ b/plugin_manager.py @@ -813,6 +813,7 @@ def get_description(self, minimum_character_offset=40): 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 @@ async def draw_ui(self): 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 @@ def tutorial_confirm_window(): 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 0398/1464] [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 fde5299e..6fd149e7 100644 --- a/plugin_manager.py +++ b/plugin_manager.py @@ -961,16 +961,15 @@ async def draw_ui(self): 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 0399/1464] [ci] apply-version-metadata --- index.json | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/index.json b/index.json index c2ba40e6..a4c3e4bd 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 0400/1464] 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 d809d66d..74d9aa42 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 a4c3e4bd..604f3155 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 6fd149e7..7225598e 100644 --- a/plugin_manager.py +++ b/plugin_manager.py @@ -24,7 +24,7 @@ _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 0401/1464] [ci] apply-version-metadata --- index.json | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/index.json b/index.json index 604f3155..35df60c2 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 0402/1464] 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 74d9aa42..2900fd83 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 0403/1464] 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 7225598e..2d9e4194 100644 --- a/plugin_manager.py +++ b/plugin_manager.py @@ -816,9 +816,9 @@ async def draw_ui(self): 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 @@ async def draw_ui(self): 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 @@ def tutorial_confirm_window(): 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 0404/1464] Add changelog for 0.3.1 --- CHANGELOG.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 2900fd83..9da65113 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 0405/1464] 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 35df60c2..2eca77df 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 2d9e4194..e5de46ae 100644 --- a/plugin_manager.py +++ b/plugin_manager.py @@ -24,7 +24,7 @@ _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 0406/1464] [ci] apply-version-metadata --- index.json | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/index.json b/index.json index 2eca77df..9987a702 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 0407/1464] 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 e5de46ae..68d77c23 100644 --- a/plugin_manager.py +++ b/plugin_manager.py @@ -817,7 +817,7 @@ async def draw_ui(self): 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 @@ async def draw_ui(self): 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 @@ def tutorial_confirm_window(): 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 0408/1464] reset the hash --- index.json | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/index.json b/index.json index 9987a702..2eca77df 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 0409/1464] [ci] apply-version-metadata --- index.json | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/index.json b/index.json index 2eca77df..f88daf75 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 0410/1464] 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 f88daf75..2eca77df 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 68d77c23..2c4664dd 100644 --- a/plugin_manager.py +++ b/plugin_manager.py @@ -935,8 +935,8 @@ async def draw_ui(self): 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 0411/1464] [ci] apply-version-metadata --- index.json | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/index.json b/index.json index 2eca77df..8805e0fc 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 0412/1464] 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 b1fb800e..bca96356 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 00000000..a918e35a --- /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 0413/1464] [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 a918e35a..66a81c69 100644 --- a/plugins/minigames/hot_bomb.py +++ b/plugins/minigames/hot_bomb.py @@ -11,7 +11,8 @@ 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 @@ 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 @@ def __init__(self, position: Sequence[float] = (0.0, 1.0, 0.0),timer: int = 5,d_ '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 @@ def __init__(self, position: Sequence[float] = (0.0, 1.0, 0.0),timer: int = 5,d_ 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 @@ def _tick(self) -> None: 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 @@ def handlemessage(self, msg: Any) -> Any: 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 @@ def damage(): 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 @@ def drop_bomb(self) -> Optional[Bomb]: 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 @@ def drop_bomb(self) -> Optional[Bomb]: blast_radius=self.blast_radius, source_player=self.source_player, owner=self.node).autoretain() - assert bomb.node if dropping_bomb: @@ -401,24 +411,24 @@ def drop_bomb(self) -> Optional[Bomb]: 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 @@ def handlemessage(self, msg: Any) -> Any: 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 @@ def __init__(self) -> None: 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 @@ def __init__(self) -> None: 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 @@ def get_supported_maps(cls, sessiontype: Type[ba.Session]) -> List[str]: 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 @@ def __init__(self, settings: dict): 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 @@ def __init__(self, settings: dict): 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 @@ def __init__(self, settings: dict): ) 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 @@ def __init__(self, settings: dict): '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 @@ def __init__(self, settings: dict): '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 @@ def __init__(self, settings: dict): ('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 @@ def get_instance_description_short(self) -> Union[str, Sequence]: 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 @@ def _reaction(self): 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 @@ def add_game_complements(self): 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 @@ def add_map_complements(self): } ) - 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 @@ 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) + player = collision.opposingnode.getdelegate(PlayerSpaz, True).getplayer(Player, True) except ba.NotFoundError: return @@ -981,15 +991,15 @@ def _handle_ball_player_collide(self) -> None: 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 @@ def _reset_count(self) -> None: 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 @@ def _handle_score(self,index=0) -> None: # 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 @@ 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 = (-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 @@ def handlemessage(self, msg: Any) -> Any: 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 @@ 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) + 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 @@ def respawn_player(self, 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 @@ def spawn_player_if_exists(self, player: PlayerType) -> None: 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 @@ def __init__(self, position: Sequence[float] = (0, 1, 0), ), ), 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 @@ def _impact(self) -> None: 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 @@ def _explode(self): }, ) 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 @@ def _touch_player(self): 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 @@ def _touch_player(self): 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 @@ def handlemessage(self, msg): 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 @@ def get(cls) -> HealthFactory: activity.customdata[cls._STORENAME] = factory assert isinstance(factory, HealthFactory) return factory - - - + def __init__(self) -> None: """Instantiate a BombFactory. @@ -1416,13 +1430,13 @@ def __init__(self) -> None: 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 @@ def __init__(self) -> None: ) 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 @@ def __init__(self, position: Sequence[float] = (0, 1, 0), '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 @@ def handlemessage(self, msg): 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 @@ def handlemessage(self, msg): 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 @@ def __init__(self, position: Sequence[float] = (0, 1, 0), '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 @@ def handlemessage(self, msg): 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 @@ def __init__(self, position: Sequence[float] = (0, 1, 0), '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 @@ def handlemessage(self, msg): 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 @@ def __init__(self, position: Sequence[float] = (0, 1, 0), '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 0414/1464] [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 bca96356..4be499f4 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 0415/1464] 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 c1a86a6d..33fab5d4 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 0416/1464] 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 2c4664dd..dcd74fcb 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 @@ def get_description(self, minimum_character_offset=40): 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 @@ async def draw_ui(self): 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 @@ async def draw_ui(self): 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 @@ def tutorial_confirm_window(): # 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 @@ async def soft_refresh(self): 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 @@ def delete_selected_source(self): 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 @@ def show_sources_window(self): 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 @@ def show_plugin_window(self, plugin): 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 @@ def soft_refresh(self): 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 @@ async def update(self, to_version=None, commit_sha=None): 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 0417/1464] [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 33fab5d4..b10844ff 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 0418/1464] 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 dcd74fcb..e62b9679 100644 --- a/plugin_manager.py +++ b/plugin_manager.py @@ -26,6 +26,8 @@ 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 @@ def __init__(self, meta_url, is_3rd_party=False): 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 0419/1464] 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 e62b9679..fec10c8a 100644 --- a/plugin_manager.py +++ b/plugin_manager.py @@ -1680,6 +1680,8 @@ def draw_refresh_icon(self): 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 0420/1464] 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 8805e0fc..db12a234 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 fec10c8a..dda2d68a 100644 --- a/plugin_manager.py +++ b/plugin_manager.py @@ -24,7 +24,7 @@ _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 0421/1464] [ci] apply-version-metadata --- index.json | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/index.json b/index.json index db12a234..3a1b0018 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 0422/1464] Update CHANGELOG.md --- CHANGELOG.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 9da65113..52493048 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. From d402b166e32b2cf125b1265d6c91844e6a58c768 Mon Sep 17 00:00:00 2001 From: Ayush Saini <36878972+imayushsaini@users.noreply.github.com> Date: Sat, 6 May 2023 23:10:44 +0530 Subject: [PATCH 0423/1464] added air_soccer, shimla minigames --- plugins/minigames.json | 28 ++ plugins/minigames/air_soccer.py | 639 ++++++++++++++++++++++++++++++++ plugins/minigames/shimla.py | 396 ++++++++++++++++++++ 3 files changed, 1063 insertions(+) create mode 100644 plugins/minigames/air_soccer.py create mode 100644 plugins/minigames/shimla.py diff --git a/plugins/minigames.json b/plugins/minigames.json index b1fb800e..f1109561 100644 --- a/plugins/minigames.json +++ b/plugins/minigames.json @@ -249,6 +249,34 @@ "md5sum": "ec3980f3f3a5da96c27f4cbd61f98550" } } + }, + "shimla": { + "description": "Death match with elevators, 2-D view.", + "external_url": "https://www.youtube.com/channel/UCaQajfKHrTPgiOhuias5iPg", + "authors": [ + { + "name": "Mr.Smoothy", + "email": "smoothy@bombsquad.ga", + "discord": "mr.smoothy#5824" + } + ], + "versions": { + "1.0.0": null + } + }, + "air_soccer": { + "description": "Play soccer while flying in air", + "external_url": "https://youtu.be/j6FFk7E6W_U", + "authors": [ + { + "name": "Mr.Smoothy", + "email": "smoothy@bombsquad.ga", + "discord": "mr.smoothy#5824" + } + ], + "versions": { + "1.0.0": null + } } } } \ No newline at end of file diff --git a/plugins/minigames/air_soccer.py b/plugins/minigames/air_soccer.py new file mode 100644 index 00000000..83ecd46d --- /dev/null +++ b/plugins/minigames/air_soccer.py @@ -0,0 +1,639 @@ +# Released under the MIT License. See LICENSE for details. +# BY Stary_Agent +"""Hockey game and support classes.""" + +# ba_meta require api 7 +# (see https://ballistica.net/wiki/meta-tag-system) + +from __future__ import annotations + +from typing import TYPE_CHECKING + +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 + +if TYPE_CHECKING: + from typing import Any, Sequence, Dict, Type, List, Optional, Union + + +class PuckDiedMessage: + """Inform something that a puck has died.""" + + def __init__(self, puck: Puck): + self.puck = puck + +def create_slope(self): + shared = SharedObjects.get() + x=5 + y=12 + for i in range(0,10): + ba.newnode('region',attrs={'position': (x, y, -5.52),'scale': (0.2,0.1,6),'type': 'box','materials': [shared.footing_material,self._real_wall_material ]}) + x = x+0.3 + y = y+0.1 + +class Puck(ba.Actor): + """A lovely giant hockey puck.""" + + def __init__(self, position: Sequence[float] = (0.0, 13.0, 0.0)): + super().__init__() + shared = SharedObjects.get() + activity = self.getactivity() + + # 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, HockeyGame) + pmats = [shared.object_material, activity.puck_material] + self.node = ba.newnode('prop', + delegate=self, + attrs={ + 'model': activity.puck_model, + 'color_texture': activity.puck_tex, + 'body': 'sphere', + 'reflection': 'soft', + 'reflection_scale': [0.2], + 'gravity_scale':0.3, + 'shadow_size': 0.5, + 'is_area_of_interest': True, + 'position': self._spawn_pos, + 'materials': pmats + }) + ba.animate(self.node, 'model_scale', {0: 0, 0.2: 1.3, 0.26: 1}) + + def handlemessage(self, msg: Any) -> Any: + if isinstance(msg, ba.DieMessage): + assert self.node + self.node.delete() + activity = self._activity() + if activity and not msg.immediate: + activity.handlemessage(PuckDiedMessage(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.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 + else: + 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 + + +# ba_meta export game +class AirSoccerGame(ba.TeamGameActivity[Player, Team]): + """Ice hockey game.""" + + name = 'Epic Air Soccer' + description = 'Score some goals.' + available_settings = [ + ba.IntSetting( + 'Score to Win', + min_value=1, + default=1, + 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.1), + ('Short', 0.5), + ('Normal', 1.0), + ('Long', 2.0), + ('Longer', 4.0), + ], + default=1.0, + ), + ] + 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 ['Creative Thoughts'] + + def __init__(self, settings: dict): + super().__init__(settings) + shared = SharedObjects.get() + self.slow_motion = True + 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.puck_model = ba.getmodel('bomb') + self.puck_tex = ba.gettexture('landMine') + self.puck_scored_tex = ba.gettexture('landMineLit') + self._puck_sound = ba.getsound('metalHit') + self.puck_material = ba.Material() + self.puck_material.add_actions(actions=(('modify_part_collision', + 'friction', 0.5))) + self.puck_material.add_actions(conditions=('they_have_material', + shared.pickup_material), + actions=('modify_part_collision', + 'collide', True)) + self.puck_material.add_actions( + conditions=( + ('we_are_younger_than', 100), + 'and', + ('they_have_material', shared.object_material), + ), + actions=('modify_node_collision', 'collide', False), + ) + self.puck_material.add_actions(conditions=('they_have_material', + shared.footing_material), + actions=('impact_sound', + self._puck_sound, 0.2, 5)) + self._real_wall_material=ba.Material() + self._real_wall_material.add_actions( + + actions=( + ('modify_part_collision', 'collide', True), + ('modify_part_collision', 'physical', True) + + )) + + self._real_wall_material.add_actions( + conditions=('they_have_material', shared.player_material), + actions=( + ('modify_part_collision', 'collide', True), + ('modify_part_collision', 'physical', True) + + )) + self._goal_post_material=ba.Material() + self._goal_post_material.add_actions( + + actions=( + ('modify_part_collision', 'collide', True), + ('modify_part_collision', 'physical', True) + + )) + + self._goal_post_material.add_actions( + conditions=('they_have_material', shared.player_material), + actions=( + ('modify_part_collision', 'collide', False), + ('modify_part_collision', 'physical', False) + + )) + # Keep track of which player last touched the puck + self.puck_material.add_actions( + conditions=('they_have_material', shared.player_material), + actions=(('call', 'at_connect', + self._handle_puck_player_collide), )) + + # We want the puck to kill powerups; not get stopped by them + self.puck_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.puck_material), + actions=(('modify_part_collision', 'collide', + True), ('modify_part_collision', 'physical', False), + ('call', 'at_connect', self._handle_score))) + self._puck_spawn_pos: Optional[Sequence[float]] = None + self._score_regions: Optional[List[ba.NodeActor]] = None + self._puck: Optional[Puck] = 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 'Score a goal.' + return 'Score ${ARG1} goals.', self._score_to_win + + def get_instance_description_short(self) -> Union[str, Sequence]: + if self._score_to_win == 1: + return 'score a goal' + return 'score ${ARG1} goals', self._score_to_win + + def on_begin(self) -> None: + super().on_begin() + + self.setup_standard_time_limit(self._time_limit) + self.setup_standard_powerup_drops() + self._puck_spawn_pos =(0,16.9,-5.5) + self._spawn_puck() + self.make_map() + + # Set up the two score regions. + defs = self.map.defs + self._score_regions = [] + self._score_regions.append( + ba.NodeActor( + ba.newnode('region', + attrs={ + 'position': (17,14.5,-5.52), + 'scale': (1,3,1), + 'type': 'box', + 'materials': [self._score_region_material] + }))) + self._score_regions.append( + ba.NodeActor( + ba.newnode('region', + attrs={ + 'position': (-17,14.5,-5.52), + 'scale': (1,3,1), + 'type': 'box', + 'materials': [self._score_region_material] + }))) + self._update_scoreboard() + ba.playsound(self._chant_sound) + + def on_team_join(self, team: Team) -> None: + self._update_scoreboard() + + def _handle_puck_player_collide(self) -> None: + collision = ba.getcollision() + try: + puck = collision.sourcenode.getdelegate(Puck, True) + player = collision.opposingnode.getdelegate(PlayerSpaz, + True).getplayer( + Player, True) + except ba.NotFoundError: + return + + puck.last_players_to_touch[player.team.id] = player + + def make_map(self): + shared = SharedObjects.get() + _ba.get_foreground_host_activity()._map.leftwall.materials= [shared.footing_material,self._real_wall_material ] + + _ba.get_foreground_host_activity()._map.rightwall.materials=[shared.footing_material,self._real_wall_material ] + + _ba.get_foreground_host_activity()._map.topwall.materials=[shared.footing_material,self._real_wall_material ] + self.floorwall=ba.newnode('region',attrs={'position': (0, 5, -5.52),'scale': (35.4,0.2,2),'type': 'box','materials': [shared.footing_material,self._real_wall_material ]}) + ba.newnode('locator', attrs={'shape':'box', 'position':(0, 5, -5.52), 'color':(0,0,0), 'opacity':1,'draw_beauty':True,'additive':False,'size':(35.4,0.2,2)}) + + + self.create_goal_post(-16.65,12.69) + self.create_goal_post(-16.65,16.69) + + self.create_goal_post(16.65,12.69) + self.create_goal_post(16.65,16.69) + + self.create_static_step(0,16.29) + + self.create_static_step(4.35,11.1) + self.create_static_step(-4.35,11.1) + + self.create_vertical(10, 15.6) + self.create_vertical(-10, 15.6) + + def create_static_step(self,x,y): + floor="" + for i in range(0,7): + floor+="_ " + shared = SharedObjects.get() + step={} + step["r"]=ba.newnode('region',attrs={'position': (x, y, -5.52),'scale': (3,0.1,6),'type': 'box','materials': [shared.footing_material,self._real_wall_material ]}) + ba.newnode('locator', attrs={'shape':'box', 'position':( x, y, -5.52), 'color':(1,1,0), 'opacity':1,'draw_beauty':True,'additive':False,'size':(3,0.1,2)}) + + return step + def create_goal_post(self,x,y): + shared = SharedObjects.get() + if x > 0: + color = (1,0,0) #change to team specific color + else: + color = (0,0,1) + floor="" + for i in range(0,4): + floor+="_ " + ba.newnode('region',attrs={'position': (x-0.2, y, -5.52),'scale': (1.8,0.1,6),'type': 'box','materials': [shared.footing_material,self._goal_post_material]}) + + ba.newnode('locator', attrs={'shape':'box', 'position':( x-0.2, y, -5.52), 'color': color, 'opacity':1,'draw_beauty':True,'additive':False,'size':(1.8,0.1,2)}) + + + def create_vertical(self,x,y): + shared = SharedObjects.get() + floor = "" + for i in range(0,4): + floor +="|\n" + ba.newnode('region',attrs={'position': (x, y, -5.52),'scale': (0.1,2.8,1),'type': 'box','materials': [shared.footing_material,self._real_wall_material ]}) + ba.newnode('locator', attrs={'shape':'box', 'position':( x, y, -5.52), 'color':(1,1,0), 'opacity':1,'draw_beauty':True,'additive':False,'size':(0.1,2.8,2)}) + + + def spawn_player_spaz(self, + player: Player, + position: Sequence[float] = None, + angle: float = None) -> PlayerSpaz: + """Intercept new spazzes and add our team material for them.""" + if player.team.id==0: + position=(-10.75152479, 5.057427485, -5.52) + elif player.team.id==1: + position=(8.75152479, 5.057427485, -5.52) + + + spaz = super().spawn_player_spaz(player, position, angle) + return spaz + + def _kill_puck(self) -> None: + self._puck = None + + def _handle_score(self) -> None: + """A point has been scored.""" + + assert self._puck is not None + assert self._score_regions is not None + + # Our puck might stick around for a second or two + # we don't want it to be able to score again. + if self._puck.scored: + return + + region = ba.getcollision().sourcenode + index = 0 + for index in range(len(self._score_regions)): + if region == self._score_regions[index].node: + break + + for team in self.teams: + if team.id == index: + scoring_team = team + team.score += 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._puck.last_players_to_touch + and self._puck.last_players_to_touch[scoring_team.id]): + self.stats.player_scored( + self._puck.last_players_to_touch[scoring_team.id], + 20, + big_message=True) + + # End game if we won. + if team.score >= self._score_to_win: + self.end_game() + + ba.playsound(self._foghorn_sound) + ba.playsound(self._cheer_sound) + + self._puck.scored = True + + # Change puck texture to something cool + self._puck.node.color_texture = self.puck_scored_tex + # Kill the puck (it'll respawn itself shortly). + ba.timer(1.0, self._kill_puck) + + light = ba.newnode('light', + attrs={ + 'position': ba.getcollision().position, + 'height_attenuated': False, + 'color': (1, 0, 0) + }) + ba.animate(light, 'intensity', {0: 0, 0.5: 1, 1.0: 0}, loop=True) + ba.timer(1.0, light.delete) + + 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): + # Augment standard behavior... + super().handlemessage(msg) + self.respawn_player(msg.getplayer(Player)) + + # Respawn dead pucks. + elif isinstance(msg, PuckDiedMessage): + if not self.has_ended(): + ba.timer(3.0, self._spawn_puck) + else: + super().handlemessage(msg) + + def _flash_puck_spawn(self) -> None: + light = ba.newnode('light', + attrs={ + 'position': self._puck_spawn_pos, + 'height_attenuated': False, + 'color': (1, 0, 0) + }) + ba.animate(light, 'intensity', {0.0: 0, 0.25: 1, 0.5: 0}, loop=True) + ba.timer(1.0, light.delete) + + def _spawn_puck(self) -> None: + ba.playsound(self._swipsound) + ba.playsound(self._whistle_sound) + self._flash_puck_spawn() + assert self._puck_spawn_pos is not None + self._puck = Puck(position=self._puck_spawn_pos) + + +class mapdefs: + points = {} + # noinspection PyDictCreation + boxes = {} + boxes['area_of_interest_bounds'] = (-1.045859963, 12.67722855, + -5.401537075) + (0.0, 0.0, 0.0) + ( + 42.46156851, 20.94044653, 0.6931564611) + points['ffa_spawn1'] = (-9.295167711, 8.010664315, + -5.44451005) + (1.555840357, 1.453808816, 0.1165648888) + points['ffa_spawn2'] = (7.484707127, 8.172681752, -5.614479365) + ( + 1.553861796, 1.453808816, 0.04419853907) + points['ffa_spawn3'] = (9.55724115, 11.30789446, -5.614479365) + ( + 1.337925849, 1.453808816, 0.04419853907) + points['ffa_spawn4'] = (-11.55747023, 10.99170684, -5.614479365) + ( + 1.337925849, 1.453808816, 0.04419853907) + points['ffa_spawn5'] = (-1.878892369, 9.46490571, -5.614479365) + ( + 1.337925849, 1.453808816, 0.04419853907) + points['ffa_spawn6'] = (-0.4912812943, 5.077006397, -5.521672101) + ( + 1.878332089, 1.453808816, 0.007578097856) + points['flag1'] = (-11.75152479, 8.057427485, -5.52) + points['flag2'] = (9.840909039, 8.188634282, -5.52) + points['flag3'] = (-0.2195258696, 5.010273907, -5.52) + points['flag4'] = (-0.04605809154, 12.73369108, -5.52) + points['flag_default'] = (-0.04201942896, 12.72374492, -5.52) + boxes['map_bounds'] = (-0.8748348681, 9.212941713, -5.729538885) + ( + 0.0, 0.0, 0.0) + (42.09666006, 26.19950145, 7.89541168) + points['powerup_spawn1'] = (1.160232442, 6.745963662, -5.469115985) + points['powerup_spawn2'] = (-1.899700206, 10.56447241, -5.505721177) + points['powerup_spawn3'] = (10.56098871, 12.25165669, -5.576232453) + points['powerup_spawn4'] = (-12.33530337, 12.25165669, -5.576232453) + points['spawn1'] = (-9.295167711, 8.010664315, + -5.44451005) + (1.555840357, 1.453808816, 0.1165648888) + points['spawn2'] = (7.484707127, 8.172681752, + -5.614479365) + (1.553861796, 1.453808816, 0.04419853907) + points['spawn_by_flag1'] = (-9.295167711, 8.010664315, -5.44451005) + ( + 1.555840357, 1.453808816, 0.1165648888) + points['spawn_by_flag2'] = (7.484707127, 8.172681752, -5.614479365) + ( + 1.553861796, 1.453808816, 0.04419853907) + points['spawn_by_flag3'] = (-1.45994593, 5.038762459, -5.535288724) + ( + 0.9516389866, 0.6666414677, 0.08607244075) + points['spawn_by_flag4'] = (0.4932087091, 12.74493212, -5.598987003) + ( + 0.5245740665, 0.5245740665, 0.01941146064) +class CreativeThoughts(ba.Map): + """Freaking map by smoothy.""" + + defs = mapdefs + + name = 'Creative Thoughts' + + @classmethod + def get_play_types(cls) -> List[str]: + """Return valid play types for this map.""" + return [ + 'melee', 'keep_away', 'team_flag' + ] + + @classmethod + def get_preview_texture_name(cls) -> str: + return 'alwaysLandPreview' + + @classmethod + def on_preload(cls) -> Any: + data: Dict[str, Any] = { + 'model': ba.getmodel('alwaysLandLevel'), + 'bottom_model': ba.getmodel('alwaysLandLevelBottom'), + 'bgmodel': ba.getmodel('alwaysLandBG'), + 'collide_model': ba.getcollidemodel('alwaysLandLevelCollide'), + 'tex': ba.gettexture('alwaysLandLevelColor'), + 'bgtex': ba.gettexture('alwaysLandBGColor'), + 'vr_fill_mound_model': ba.getmodel('alwaysLandVRFillMound'), + 'vr_fill_mound_tex': ba.gettexture('vrFillMound') + } + return data + + @classmethod + def get_music_type(cls) -> ba.MusicType: + return ba.MusicType.FLYING + + def __init__(self) -> None: + super().__init__(vr_overlay_offset=(0, -3.7, 2.5)) + shared = SharedObjects.get() + self._fake_wall_material=ba.Material() + self._real_wall_material=ba.Material() + self._fake_wall_material.add_actions( + conditions=(('they_are_younger_than',9000),'and',('they_have_material', shared.player_material)), + actions=( + ('modify_part_collision', 'collide', True), + ('modify_part_collision', 'physical', True) + + )) + self._real_wall_material.add_actions( + conditions=('they_have_material', shared.player_material), + actions=( + ('modify_part_collision', 'collide', True), + ('modify_part_collision', 'physical', True) + + )) + self.background = ba.newnode( + 'terrain', + attrs={ + 'model': self.preloaddata['bgmodel'], + 'lighting': False, + 'background': True, + 'color_texture': ba.gettexture("rampageBGColor") + }) + + self.leftwall=ba.newnode('region',attrs={'position': (-17.75152479, 13, -5.52),'scale': (0.1,15.5,2),'type': 'box','materials': [shared.footing_material,self._real_wall_material ]}) + self.rightwall=ba.newnode('region',attrs={'position': (17.75, 13, -5.52),'scale': (0.1,15.5,2),'type': 'box','materials': [shared.footing_material,self._real_wall_material ]}) + self.topwall=ba.newnode('region',attrs={'position': (0, 21.0, -5.52),'scale': (35.4,0.2,2),'type': 'box','materials': [shared.footing_material,self._real_wall_material ]}) + ba.newnode('locator', attrs={'shape':'box', 'position':(-17.75152479, 13, -5.52), 'color':(0,0,0), 'opacity':1,'draw_beauty':True,'additive':False,'size':(0.1,15.5,2)}) + ba.newnode('locator', attrs={'shape':'box', 'position':(17.75, 13, -5.52), 'color':(0,0,0), 'opacity':1,'draw_beauty':True,'additive':False,'size':(0.1,15.5,2)}) + ba.newnode('locator', attrs={'shape':'box', 'position':(0, 21.0, -5.52), 'color':(0,0,0), 'opacity':1,'draw_beauty':True,'additive':False,'size':(35.4,0.2,2)}) + + gnode = ba.getactivity().globalsnode + gnode.happy_thoughts_mode = True + gnode.shadow_offset = (0.0, 8.0, 5.0) + gnode.tint = (1.3, 1.23, 1.0) + gnode.ambient_color = (1.3, 1.23, 1.0) + gnode.vignette_outer = (0.64, 0.59, 0.69) + gnode.vignette_inner = (0.95, 0.95, 0.93) + gnode.vr_near_clip = 1.0 + self.is_flying = True + + # throw out some tips on flying + txt = ba.newnode('text', + attrs={ + 'text': ba.Lstr(resource='pressJumpToFlyText'), + 'scale': 1.2, + 'maxwidth': 800, + 'position': (0, 200), + 'shadow': 0.5, + 'flatness': 0.5, + 'h_align': 'center', + 'v_attach': 'bottom' + }) + cmb = ba.newnode('combine', + owner=txt, + attrs={ + 'size': 4, + 'input0': 0.3, + 'input1': 0.9, + 'input2': 0.0 + }) + ba.animate(cmb, 'input3', {3.0: 0, 4.0: 1, 9.0: 1, 10.0: 0}) + cmb.connectattr('output', txt, 'color') + ba.timer(10.0, txt.delete) + + +try: + ba._map.register_map(CreativeThoughts) +except: + pass \ No newline at end of file diff --git a/plugins/minigames/shimla.py b/plugins/minigames/shimla.py new file mode 100644 index 00000000..6d19656e --- /dev/null +++ b/plugins/minigames/shimla.py @@ -0,0 +1,396 @@ +# Released under the MIT License. See LICENSE for details. +# +"""DeathMatch game and support classes.""" + +# ba_meta require api 7 +# (see https://ballistica.net/wiki/meta-tag-system) + +from __future__ import annotations + +from typing import TYPE_CHECKING + +import ba +import _ba +from bastd.actor.playerspaz import PlayerSpaz +from bastd.actor.scoreboard import Scoreboard +from bastd.gameutils import SharedObjects +from bastd.game.deathmatch import DeathMatchGame, Player, Team +from bastd.gameutils import SharedObjects +if TYPE_CHECKING: + from typing import Any, Sequence, Dict, Type, List, Optional, Union + +# ba_meta export game +class ShimlaGame(DeathMatchGame): + name = 'Shimla' + + @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 ['Creative Thoughts'] + + def __init__(self, settings: dict): + super().__init__(settings) + shared = SharedObjects.get() + self.lifts = {} + self._real_wall_material = ba.Material() + self._real_wall_material.add_actions( + + actions=( + ('modify_part_collision', 'collide', True), + ('modify_part_collision', 'physical', True) + + )) + + self._real_wall_material.add_actions( + conditions=('they_have_material', shared.player_material), + actions=( + ('modify_part_collision', 'collide', True), + ('modify_part_collision', 'physical', True) + + )) + self._lift_material = ba.Material() + self._lift_material.add_actions( + + actions=( + ('modify_part_collision', 'collide', True), + ('modify_part_collision', 'physical', True) + + )) + self._lift_material.add_actions( + conditions=('they_have_material', shared.player_material), + actions=(('call', 'at_connect', self._handle_lift),), + ) + self._lift_material.add_actions( + conditions=('they_have_material', shared.player_material), + actions=(('call', 'at_disconnect', self._handle_lift_disconnect),), + ) + + def on_begin(self): + ba.getactivity().globalsnode.happy_thoughts_mode = False + super().on_begin() + + self.make_map() + ba.timer(2, self.disable_fly) + def disable_fly(self): + activity = _ba.get_foreground_host_activity() + + for players in activity.players: + players.actor.node.fly = False + def spawn_player_spaz( + self, + player: Player, + position: Sequence[float] | None = None, + angle: float | None = None, + ) -> PlayerSpaz: + """Intercept new spazzes and add our team material for them.""" + spaz = super().spawn_player_spaz(player, position, angle) + + spaz.connect_controls_to_player(enable_punch=True, + enable_bomb=True, + enable_pickup=True, + enable_fly=False, + enable_jump=True) + spaz.fly = False + return spaz + + def make_map(self): + shared = SharedObjects.get() + _ba.get_foreground_host_activity()._map.leftwall.materials = [ + shared.footing_material, self._real_wall_material] + + _ba.get_foreground_host_activity()._map.rightwall.materials = [ + shared.footing_material, self._real_wall_material] + + _ba.get_foreground_host_activity()._map.topwall.materials = [ + shared.footing_material, self._real_wall_material] + + self.floorwall1 = ba.newnode('region', attrs={'position': (-10, 5, -5.52), 'scale': + (15, 0.2, 2), 'type': 'box', 'materials': [shared.footing_material, self._real_wall_material]}) + self.floorwall2 = ba.newnode('region', attrs={'position': (10, 5, -5.52), 'scale': ( + 15, 0.2, 2), 'type': 'box', 'materials': [shared.footing_material, self._real_wall_material]}) + + self.wall1 = ba.newnode('region', attrs={'position': (0, 11, -6.90), 'scale': ( + 35.4, 20, 1), 'type': 'box', 'materials': [shared.footing_material, self._real_wall_material]}) + self.wall2 = ba.newnode('region', attrs={'position': (0, 11, -4.14), 'scale': ( + 35.4, 20, 1), 'type': 'box', 'materials': [shared.footing_material, self._real_wall_material]}) + + ba.newnode('locator', attrs={'shape': 'box', 'position': (-10, 5, -5.52), 'color': ( + 0, 0, 0), 'opacity': 1, 'draw_beauty': True, 'additive': False, 'size': (15, 0.2, 2)}) + + ba.newnode('locator', attrs={'shape': 'box', 'position': (10, 5, -5.52), 'color': ( + 0, 0, 0), 'opacity': 1, 'draw_beauty': True, 'additive': False, 'size': (15, 0.2, 2)}) + self.create_lift(-16.65, 8) + + self.create_lift(16.65, 8) + + self.create_static_step(0, 18.29) + self.create_static_step(0, 7) + + self.create_static_step(13, 17) + self.create_static_step(-13, 17) + self.create_slope(8, 15, True) + self.create_slope(-8, 15, False) + self.create_static_step(5, 15) + self.create_static_step(-5, 15) + + self.create_static_step(13, 12) + self.create_static_step(-13, 12) + self.create_slope(8, 10, True) + self.create_slope(-8, 10, False) + self.create_static_step(5, 10) + self.create_static_step(-5, 10) + + def create_static_step(self, x, y): + + shared = SharedObjects.get() + + ba.newnode('region', attrs={'position': (x, y, -5.52), 'scale': (5.5, 0.1, 6), + 'type': 'box', 'materials': [shared.footing_material, self._real_wall_material]}) + ba.newnode('locator', attrs={'shape': 'box', 'position': (x, y, -5.52), 'color': ( + 1, 1, 0), 'opacity': 1, 'draw_beauty': True, 'additive': False, 'size': (5.5, 0.1, 2)}) + + def create_lift(self, x, y): + shared = SharedObjects.get() + color = (0.7, 0.6, 0.5) + + floor = ba.newnode('region', attrs={'position': (x, y, -5.52), 'scale': ( + 1.8, 0.1, 2), 'type': 'box', 'materials': [shared.footing_material, self._real_wall_material ,self._lift_material]}) + + cleaner = ba.newnode('region', attrs={'position': (x, y, -5.52), 'scale': ( + 2, 0.3, 2), 'type': 'box', 'materials': [shared.footing_material, self._real_wall_material]}) + + lift = ba.newnode('locator', attrs={'shape': 'box', 'position': ( + x, y, -5.52), 'color': color, 'opacity': 1, 'draw_beauty': True, 'additive': False, 'size': (1.8, 3.7, 2)}) + + _tcombine = ba.newnode('combine', + owner=floor, + attrs={ + 'input0': x, + 'input2': -5.5, + 'size': 3 + }) + mnode = ba.newnode('math', + owner=lift, + attrs={ + 'input1': (0, 2, 0), + 'operation': 'add' + }) + _tcombine.connectattr('output', mnode, 'input2') + + _cleaner_combine = ba.newnode('combine', + owner=cleaner, + attrs={ + 'input1': 5.6, + 'input2': -5.5, + 'size': 3 + }) + _cleaner_combine.connectattr('output', cleaner, 'position') + ba.animate(_tcombine, 'input1', { + 0: 5.1, + }) + ba.animate(_cleaner_combine, 'input0', { + 0: -19 if x < 0 else 19, + }) + + _tcombine.connectattr('output', floor, 'position') + mnode.connectattr('output', lift, 'position') + self.lifts[floor] = {"state":"origin","lift":_tcombine,"cleaner":_cleaner_combine,'leftLift': x < 0} + + def _handle_lift(self): + region = ba.getcollision().sourcenode + lift = self.lifts[region] + def clean(lift): + ba.animate(lift["cleaner"], 'input0', { + 0: -19 if lift["leftLift"] else 19 , + 2: -16 if lift["leftLift"] else 16, + 4.3: -19 if lift["leftLift"] else 19 + }) + if lift["state"] == "origin": + lift["state"] = "transition" + ba.animate(lift["lift"], 'input1', { + 0: 5.1, + 1.3: 5.1, + 6: 5+12, + 9: 5+12, + 15: 5.1 + }) + ba.timer(16, ba.Call(lambda lift: lift.update({'state': 'end'}), lift)) + ba.timer(12, ba.Call(clean, lift)) + + + def _handle_lift_disconnect(self): + region = ba.getcollision().sourcenode + lift = self.lifts[region] + if lift["state"] == 'end': + lift["state"] = "origin" + + def create_slope(self, x, y, backslash): + shared = SharedObjects.get() + + for i in range(0, 21): + ba.newnode('region', attrs={'position': (x, y, -5.52), 'scale': (0.2, 0.1, 6), + 'type': 'box', 'materials': [shared.footing_material, self._real_wall_material]}) + ba.newnode('locator', attrs={'shape': 'box', 'position': (x, y, -5.52), 'color': ( + 1, 1, 0), 'opacity': 1, 'draw_beauty': True, 'additive': False, 'size': (0.2, 0.1, 2)}) + if backslash: + x = x+0.1 + y = y+0.1 + else: + x = x-0.1 + y = y+0.1 + +class mapdefs: + points = {} + # noinspection PyDictCreation + boxes = {} + boxes['area_of_interest_bounds'] = (-1.045859963, 12.67722855, + -5.401537075) + (0.0, 0.0, 0.0) + ( + 42.46156851, 20.94044653, 0.6931564611) + points['ffa_spawn1'] = (-9.295167711, 8.010664315, + -5.44451005) + (1.555840357, 1.453808816, 0.1165648888) + points['ffa_spawn2'] = (7.484707127, 8.172681752, -5.614479365) + ( + 1.553861796, 1.453808816, 0.04419853907) + points['ffa_spawn3'] = (9.55724115, 11.30789446, -5.614479365) + ( + 1.337925849, 1.453808816, 0.04419853907) + points['ffa_spawn4'] = (-11.55747023, 10.99170684, -5.614479365) + ( + 1.337925849, 1.453808816, 0.04419853907) + points['ffa_spawn5'] = (-1.878892369, 9.46490571, -5.614479365) + ( + 1.337925849, 1.453808816, 0.04419853907) + points['ffa_spawn6'] = (-0.4912812943, 5.077006397, -5.521672101) + ( + 1.878332089, 1.453808816, 0.007578097856) + points['flag1'] = (-11.75152479, 8.057427485, -5.52) + points['flag2'] = (9.840909039, 8.188634282, -5.52) + points['flag3'] = (-0.2195258696, 5.010273907, -5.52) + points['flag4'] = (-0.04605809154, 12.73369108, -5.52) + points['flag_default'] = (-0.04201942896, 12.72374492, -5.52) + boxes['map_bounds'] = (-0.8748348681, 9.212941713, -5.729538885) + ( + 0.0, 0.0, 0.0) + (42.09666006, 26.19950145, 7.89541168) + points['powerup_spawn1'] = (1.160232442, 6.745963662, -5.469115985) + points['powerup_spawn2'] = (-1.899700206, 10.56447241, -5.505721177) + points['powerup_spawn3'] = (10.56098871, 12.25165669, -5.576232453) + points['powerup_spawn4'] = (-12.33530337, 12.25165669, -5.576232453) + points['spawn1'] = (-9.295167711, 8.010664315, + -5.44451005) + (1.555840357, 1.453808816, 0.1165648888) + points['spawn2'] = (7.484707127, 8.172681752, + -5.614479365) + (1.553861796, 1.453808816, 0.04419853907) + points['spawn_by_flag1'] = (-9.295167711, 8.010664315, -5.44451005) + ( + 1.555840357, 1.453808816, 0.1165648888) + points['spawn_by_flag2'] = (7.484707127, 8.172681752, -5.614479365) + ( + 1.553861796, 1.453808816, 0.04419853907) + points['spawn_by_flag3'] = (-1.45994593, 5.038762459, -5.535288724) + ( + 0.9516389866, 0.6666414677, 0.08607244075) + points['spawn_by_flag4'] = (0.4932087091, 12.74493212, -5.598987003) + ( + 0.5245740665, 0.5245740665, 0.01941146064) +class CreativeThoughts(ba.Map): + """Freaking map by smoothy.""" + + defs = mapdefs + + name = 'Creative Thoughts' + + @classmethod + def get_play_types(cls) -> List[str]: + """Return valid play types for this map.""" + return [ + 'melee', 'keep_away', 'team_flag' + ] + + @classmethod + def get_preview_texture_name(cls) -> str: + return 'alwaysLandPreview' + + @classmethod + def on_preload(cls) -> Any: + data: Dict[str, Any] = { + 'model': ba.getmodel('alwaysLandLevel'), + 'bottom_model': ba.getmodel('alwaysLandLevelBottom'), + 'bgmodel': ba.getmodel('alwaysLandBG'), + 'collide_model': ba.getcollidemodel('alwaysLandLevelCollide'), + 'tex': ba.gettexture('alwaysLandLevelColor'), + 'bgtex': ba.gettexture('alwaysLandBGColor'), + 'vr_fill_mound_model': ba.getmodel('alwaysLandVRFillMound'), + 'vr_fill_mound_tex': ba.gettexture('vrFillMound') + } + return data + + @classmethod + def get_music_type(cls) -> ba.MusicType: + return ba.MusicType.FLYING + + def __init__(self) -> None: + super().__init__(vr_overlay_offset=(0, -3.7, 2.5)) + shared = SharedObjects.get() + self._fake_wall_material=ba.Material() + self._real_wall_material=ba.Material() + self._fake_wall_material.add_actions( + conditions=(('they_are_younger_than',9000),'and',('they_have_material', shared.player_material)), + actions=( + ('modify_part_collision', 'collide', True), + ('modify_part_collision', 'physical', True) + + )) + self._real_wall_material.add_actions( + conditions=('they_have_material', shared.player_material), + actions=( + ('modify_part_collision', 'collide', True), + ('modify_part_collision', 'physical', True) + + )) + self.background = ba.newnode( + 'terrain', + attrs={ + 'model': self.preloaddata['bgmodel'], + 'lighting': False, + 'background': True, + 'color_texture': ba.gettexture("rampageBGColor") + }) + + self.leftwall=ba.newnode('region',attrs={'position': (-17.75152479, 13, -5.52),'scale': (0.1,15.5,2),'type': 'box','materials': [shared.footing_material,self._real_wall_material ]}) + self.rightwall=ba.newnode('region',attrs={'position': (17.75, 13, -5.52),'scale': (0.1,15.5,2),'type': 'box','materials': [shared.footing_material,self._real_wall_material ]}) + self.topwall=ba.newnode('region',attrs={'position': (0, 21.0, -5.52),'scale': (35.4,0.2,2),'type': 'box','materials': [shared.footing_material,self._real_wall_material ]}) + ba.newnode('locator', attrs={'shape':'box', 'position':(-17.75152479, 13, -5.52), 'color':(0,0,0), 'opacity':1,'draw_beauty':True,'additive':False,'size':(0.1,15.5,2)}) + ba.newnode('locator', attrs={'shape':'box', 'position':(17.75, 13, -5.52), 'color':(0,0,0), 'opacity':1,'draw_beauty':True,'additive':False,'size':(0.1,15.5,2)}) + ba.newnode('locator', attrs={'shape':'box', 'position':(0, 21.0, -5.52), 'color':(0,0,0), 'opacity':1,'draw_beauty':True,'additive':False,'size':(35.4,0.2,2)}) + + gnode = ba.getactivity().globalsnode + gnode.happy_thoughts_mode = True + gnode.shadow_offset = (0.0, 8.0, 5.0) + gnode.tint = (1.3, 1.23, 1.0) + gnode.ambient_color = (1.3, 1.23, 1.0) + gnode.vignette_outer = (0.64, 0.59, 0.69) + gnode.vignette_inner = (0.95, 0.95, 0.93) + gnode.vr_near_clip = 1.0 + self.is_flying = True + + # throw out some tips on flying + txt = ba.newnode('text', + attrs={ + 'text': ba.Lstr(resource='pressJumpToFlyText'), + 'scale': 1.2, + 'maxwidth': 800, + 'position': (0, 200), + 'shadow': 0.5, + 'flatness': 0.5, + 'h_align': 'center', + 'v_attach': 'bottom' + }) + cmb = ba.newnode('combine', + owner=txt, + attrs={ + 'size': 4, + 'input0': 0.3, + 'input1': 0.9, + 'input2': 0.0 + }) + ba.animate(cmb, 'input3', {3.0: 0, 4.0: 1, 9.0: 1, 10.0: 0}) + cmb.connectattr('output', txt, 'color') + ba.timer(10.0, txt.delete) + + +try: + ba._map.register_map(CreativeThoughts) +except: + pass \ No newline at end of file From 52094fc51bbfca70dbcdd1c841aa4c698191618a Mon Sep 17 00:00:00 2001 From: imayushsaini Date: Sat, 6 May 2023 17:43:30 +0000 Subject: [PATCH 0424/1464] [ci] auto-format --- plugins/minigames/air_soccer.py | 175 ++++++++++++++++++-------------- plugins/minigames/shimla.py | 71 ++++++++----- 2 files changed, 141 insertions(+), 105 deletions(-) diff --git a/plugins/minigames/air_soccer.py b/plugins/minigames/air_soccer.py index 83ecd46d..a089d952 100644 --- a/plugins/minigames/air_soccer.py +++ b/plugins/minigames/air_soccer.py @@ -9,7 +9,8 @@ from typing import TYPE_CHECKING -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 @@ -25,14 +26,17 @@ class PuckDiedMessage: def __init__(self, puck: Puck): self.puck = puck + def create_slope(self): - shared = SharedObjects.get() - x=5 - y=12 - for i in range(0,10): - ba.newnode('region',attrs={'position': (x, y, -5.52),'scale': (0.2,0.1,6),'type': 'box','materials': [shared.footing_material,self._real_wall_material ]}) - x = x+0.3 - y = y+0.1 + shared = SharedObjects.get() + x = 5 + y = 12 + for i in range(0, 10): + ba.newnode('region', attrs={'position': (x, y, -5.52), 'scale': (0.2, 0.1, 6), + 'type': 'box', 'materials': [shared.footing_material, self._real_wall_material]}) + x = x+0.3 + y = y+0.1 + class Puck(ba.Actor): """A lovely giant hockey puck.""" @@ -57,7 +61,7 @@ def __init__(self, position: Sequence[float] = (0.0, 13.0, 0.0)): 'body': 'sphere', 'reflection': 'soft', 'reflection_scale': [0.2], - 'gravity_scale':0.3, + 'gravity_scale': 0.3, 'shadow_size': 0.5, 'is_area_of_interest': True, 'position': self._spawn_pos, @@ -190,7 +194,7 @@ def __init__(self, settings: dict): shared.footing_material), actions=('impact_sound', self._puck_sound, 0.2, 5)) - self._real_wall_material=ba.Material() + self._real_wall_material = ba.Material() self._real_wall_material.add_actions( actions=( @@ -206,7 +210,7 @@ def __init__(self, settings: dict): ('modify_part_collision', 'physical', True) )) - self._goal_post_material=ba.Material() + self._goal_post_material = ba.Material() self._goal_post_material.add_actions( actions=( @@ -261,7 +265,7 @@ def on_begin(self) -> None: self.setup_standard_time_limit(self._time_limit) self.setup_standard_powerup_drops() - self._puck_spawn_pos =(0,16.9,-5.5) + self._puck_spawn_pos = (0, 16.9, -5.5) self._spawn_puck() self.make_map() @@ -272,8 +276,8 @@ def on_begin(self) -> None: ba.NodeActor( ba.newnode('region', attrs={ - 'position': (17,14.5,-5.52), - 'scale': (1,3,1), + 'position': (17, 14.5, -5.52), + 'scale': (1, 3, 1), 'type': 'box', 'materials': [self._score_region_material] }))) @@ -281,8 +285,8 @@ def on_begin(self) -> None: ba.NodeActor( ba.newnode('region', attrs={ - 'position': (-17,14.5,-5.52), - 'scale': (1,3,1), + 'position': (-17, 14.5, -5.52), + 'scale': (1, 3, 1), 'type': 'box', 'materials': [self._score_region_material] }))) @@ -306,72 +310,80 @@ def _handle_puck_player_collide(self) -> None: def make_map(self): shared = SharedObjects.get() - _ba.get_foreground_host_activity()._map.leftwall.materials= [shared.footing_material,self._real_wall_material ] - - _ba.get_foreground_host_activity()._map.rightwall.materials=[shared.footing_material,self._real_wall_material ] - - _ba.get_foreground_host_activity()._map.topwall.materials=[shared.footing_material,self._real_wall_material ] - self.floorwall=ba.newnode('region',attrs={'position': (0, 5, -5.52),'scale': (35.4,0.2,2),'type': 'box','materials': [shared.footing_material,self._real_wall_material ]}) - ba.newnode('locator', attrs={'shape':'box', 'position':(0, 5, -5.52), 'color':(0,0,0), 'opacity':1,'draw_beauty':True,'additive':False,'size':(35.4,0.2,2)}) - - - self.create_goal_post(-16.65,12.69) - self.create_goal_post(-16.65,16.69) - - self.create_goal_post(16.65,12.69) - self.create_goal_post(16.65,16.69) - - self.create_static_step(0,16.29) - - self.create_static_step(4.35,11.1) - self.create_static_step(-4.35,11.1) + _ba.get_foreground_host_activity()._map.leftwall.materials = [ + shared.footing_material, self._real_wall_material] + + _ba.get_foreground_host_activity()._map.rightwall.materials = [ + shared.footing_material, self._real_wall_material] + + _ba.get_foreground_host_activity()._map.topwall.materials = [ + shared.footing_material, self._real_wall_material] + self.floorwall = ba.newnode('region', attrs={'position': (0, 5, -5.52), 'scale': ( + 35.4, 0.2, 2), 'type': 'box', 'materials': [shared.footing_material, self._real_wall_material]}) + ba.newnode('locator', attrs={'shape': 'box', 'position': ( + 0, 5, -5.52), 'color': (0, 0, 0), 'opacity': 1, 'draw_beauty': True, 'additive': False, 'size': (35.4, 0.2, 2)}) + + self.create_goal_post(-16.65, 12.69) + self.create_goal_post(-16.65, 16.69) + + self.create_goal_post(16.65, 12.69) + self.create_goal_post(16.65, 16.69) + + self.create_static_step(0, 16.29) + + self.create_static_step(4.35, 11.1) + self.create_static_step(-4.35, 11.1) self.create_vertical(10, 15.6) self.create_vertical(-10, 15.6) - - def create_static_step(self,x,y): - floor="" - for i in range(0,7): - floor+="_ " + + def create_static_step(self, x, y): + floor = "" + for i in range(0, 7): + floor += "_ " shared = SharedObjects.get() - step={} - step["r"]=ba.newnode('region',attrs={'position': (x, y, -5.52),'scale': (3,0.1,6),'type': 'box','materials': [shared.footing_material,self._real_wall_material ]}) - ba.newnode('locator', attrs={'shape':'box', 'position':( x, y, -5.52), 'color':(1,1,0), 'opacity':1,'draw_beauty':True,'additive':False,'size':(3,0.1,2)}) - + step = {} + step["r"] = ba.newnode('region', attrs={'position': (x, y, -5.52), 'scale': ( + 3, 0.1, 6), 'type': 'box', 'materials': [shared.footing_material, self._real_wall_material]}) + ba.newnode('locator', attrs={'shape': 'box', 'position': ( + x, y, -5.52), 'color': (1, 1, 0), 'opacity': 1, 'draw_beauty': True, 'additive': False, 'size': (3, 0.1, 2)}) + return step - def create_goal_post(self,x,y): + + def create_goal_post(self, x, y): shared = SharedObjects.get() if x > 0: - color = (1,0,0) #change to team specific color + color = (1, 0, 0) # change to team specific color else: - color = (0,0,1) - floor="" - for i in range(0,4): - floor+="_ " - ba.newnode('region',attrs={'position': (x-0.2, y, -5.52),'scale': (1.8,0.1,6),'type': 'box','materials': [shared.footing_material,self._goal_post_material]}) - - ba.newnode('locator', attrs={'shape':'box', 'position':( x-0.2, y, -5.52), 'color': color, 'opacity':1,'draw_beauty':True,'additive':False,'size':(1.8,0.1,2)}) - - - def create_vertical(self,x,y): - shared = SharedObjects.get() + color = (0, 0, 1) floor = "" - for i in range(0,4): - floor +="|\n" - ba.newnode('region',attrs={'position': (x, y, -5.52),'scale': (0.1,2.8,1),'type': 'box','materials': [shared.footing_material,self._real_wall_material ]}) - ba.newnode('locator', attrs={'shape':'box', 'position':( x, y, -5.52), 'color':(1,1,0), 'opacity':1,'draw_beauty':True,'additive':False,'size':(0.1,2.8,2)}) + for i in range(0, 4): + floor += "_ " + ba.newnode('region', attrs={'position': (x-0.2, y, -5.52), 'scale': (1.8, 0.1, 6), + 'type': 'box', 'materials': [shared.footing_material, self._goal_post_material]}) + + ba.newnode('locator', attrs={'shape': 'box', 'position': ( + x-0.2, y, -5.52), 'color': color, 'opacity': 1, 'draw_beauty': True, 'additive': False, 'size': (1.8, 0.1, 2)}) + def create_vertical(self, x, y): + shared = SharedObjects.get() + floor = "" + for i in range(0, 4): + floor += "|\n" + ba.newnode('region', attrs={'position': (x, y, -5.52), 'scale': (0.1, 2.8, 1), + 'type': 'box', 'materials': [shared.footing_material, self._real_wall_material]}) + ba.newnode('locator', attrs={'shape': 'box', 'position': ( + x, y, -5.52), 'color': (1, 1, 0), 'opacity': 1, 'draw_beauty': True, 'additive': False, 'size': (0.1, 2.8, 2)}) def spawn_player_spaz(self, player: Player, position: Sequence[float] = None, angle: float = None) -> PlayerSpaz: """Intercept new spazzes and add our team material for them.""" - if player.team.id==0: - position=(-10.75152479, 5.057427485, -5.52) - elif player.team.id==1: - position=(8.75152479, 5.057427485, -5.52) - + if player.team.id == 0: + position = (-10.75152479, 5.057427485, -5.52) + elif player.team.id == 1: + position = (8.75152479, 5.057427485, -5.52) spaz = super().spawn_player_spaz(player, position, angle) return spaz @@ -456,7 +468,7 @@ def handlemessage(self, msg: Any) -> Any: # Respawn dead players if they're still in the game. if isinstance(msg, ba.PlayerDiedMessage): - # Augment standard behavior... + # Augment standard behavior... super().handlemessage(msg) self.respawn_player(msg.getplayer(Player)) @@ -527,6 +539,8 @@ class mapdefs: 0.9516389866, 0.6666414677, 0.08607244075) points['spawn_by_flag4'] = (0.4932087091, 12.74493212, -5.598987003) + ( 0.5245740665, 0.5245740665, 0.01941146064) + + class CreativeThoughts(ba.Map): """Freaking map by smoothy.""" @@ -566,10 +580,11 @@ def get_music_type(cls) -> ba.MusicType: def __init__(self) -> None: super().__init__(vr_overlay_offset=(0, -3.7, 2.5)) shared = SharedObjects.get() - self._fake_wall_material=ba.Material() - self._real_wall_material=ba.Material() + self._fake_wall_material = ba.Material() + self._real_wall_material = ba.Material() self._fake_wall_material.add_actions( - conditions=(('they_are_younger_than',9000),'and',('they_have_material', shared.player_material)), + conditions=(('they_are_younger_than', 9000), 'and', + ('they_have_material', shared.player_material)), actions=( ('modify_part_collision', 'collide', True), ('modify_part_collision', 'physical', True) @@ -591,12 +606,18 @@ def __init__(self) -> None: 'color_texture': ba.gettexture("rampageBGColor") }) - self.leftwall=ba.newnode('region',attrs={'position': (-17.75152479, 13, -5.52),'scale': (0.1,15.5,2),'type': 'box','materials': [shared.footing_material,self._real_wall_material ]}) - self.rightwall=ba.newnode('region',attrs={'position': (17.75, 13, -5.52),'scale': (0.1,15.5,2),'type': 'box','materials': [shared.footing_material,self._real_wall_material ]}) - self.topwall=ba.newnode('region',attrs={'position': (0, 21.0, -5.52),'scale': (35.4,0.2,2),'type': 'box','materials': [shared.footing_material,self._real_wall_material ]}) - ba.newnode('locator', attrs={'shape':'box', 'position':(-17.75152479, 13, -5.52), 'color':(0,0,0), 'opacity':1,'draw_beauty':True,'additive':False,'size':(0.1,15.5,2)}) - ba.newnode('locator', attrs={'shape':'box', 'position':(17.75, 13, -5.52), 'color':(0,0,0), 'opacity':1,'draw_beauty':True,'additive':False,'size':(0.1,15.5,2)}) - ba.newnode('locator', attrs={'shape':'box', 'position':(0, 21.0, -5.52), 'color':(0,0,0), 'opacity':1,'draw_beauty':True,'additive':False,'size':(35.4,0.2,2)}) + self.leftwall = ba.newnode('region', attrs={'position': (-17.75152479, 13, -5.52), 'scale': ( + 0.1, 15.5, 2), 'type': 'box', 'materials': [shared.footing_material, self._real_wall_material]}) + self.rightwall = ba.newnode('region', attrs={'position': (17.75, 13, -5.52), 'scale': ( + 0.1, 15.5, 2), 'type': 'box', 'materials': [shared.footing_material, self._real_wall_material]}) + self.topwall = ba.newnode('region', attrs={'position': (0, 21.0, -5.52), 'scale': ( + 35.4, 0.2, 2), 'type': 'box', 'materials': [shared.footing_material, self._real_wall_material]}) + ba.newnode('locator', attrs={'shape': 'box', 'position': (-17.75152479, 13, -5.52), 'color': ( + 0, 0, 0), 'opacity': 1, 'draw_beauty': True, 'additive': False, 'size': (0.1, 15.5, 2)}) + ba.newnode('locator', attrs={'shape': 'box', 'position': (17.75, 13, -5.52), 'color': ( + 0, 0, 0), 'opacity': 1, 'draw_beauty': True, 'additive': False, 'size': (0.1, 15.5, 2)}) + ba.newnode('locator', attrs={'shape': 'box', 'position': (0, 21.0, -5.52), 'color': ( + 0, 0, 0), 'opacity': 1, 'draw_beauty': True, 'additive': False, 'size': (35.4, 0.2, 2)}) gnode = ba.getactivity().globalsnode gnode.happy_thoughts_mode = True @@ -636,4 +657,4 @@ def __init__(self) -> None: try: ba._map.register_map(CreativeThoughts) except: - pass \ No newline at end of file + pass diff --git a/plugins/minigames/shimla.py b/plugins/minigames/shimla.py index 6d19656e..da963927 100644 --- a/plugins/minigames/shimla.py +++ b/plugins/minigames/shimla.py @@ -20,6 +20,8 @@ from typing import Any, Sequence, Dict, Type, List, Optional, Union # ba_meta export game + + class ShimlaGame(DeathMatchGame): name = 'Shimla' @@ -71,14 +73,16 @@ def __init__(self, settings: dict): def on_begin(self): ba.getactivity().globalsnode.happy_thoughts_mode = False super().on_begin() - + self.make_map() ba.timer(2, self.disable_fly) + def disable_fly(self): activity = _ba.get_foreground_host_activity() for players in activity.players: players.actor.node.fly = False + def spawn_player_spaz( self, player: Player, @@ -87,13 +91,13 @@ def spawn_player_spaz( ) -> PlayerSpaz: """Intercept new spazzes and add our team material for them.""" spaz = super().spawn_player_spaz(player, position, angle) - + spaz.connect_controls_to_player(enable_punch=True, enable_bomb=True, enable_pickup=True, enable_fly=False, enable_jump=True) - spaz.fly = False + spaz.fly = False return spaz def make_map(self): @@ -106,9 +110,9 @@ def make_map(self): _ba.get_foreground_host_activity()._map.topwall.materials = [ shared.footing_material, self._real_wall_material] - - self.floorwall1 = ba.newnode('region', attrs={'position': (-10, 5, -5.52), 'scale': - (15, 0.2, 2), 'type': 'box', 'materials': [shared.footing_material, self._real_wall_material]}) + + self.floorwall1 = ba.newnode('region', attrs={'position': (-10, 5, -5.52), 'scale': + (15, 0.2, 2), 'type': 'box', 'materials': [shared.footing_material, self._real_wall_material]}) self.floorwall2 = ba.newnode('region', attrs={'position': (10, 5, -5.52), 'scale': ( 15, 0.2, 2), 'type': 'box', 'materials': [shared.footing_material, self._real_wall_material]}) @@ -144,7 +148,7 @@ def make_map(self): self.create_static_step(-5, 10) def create_static_step(self, x, y): - + shared = SharedObjects.get() ba.newnode('region', attrs={'position': (x, y, -5.52), 'scale': (5.5, 0.1, 6), @@ -157,7 +161,7 @@ def create_lift(self, x, y): color = (0.7, 0.6, 0.5) floor = ba.newnode('region', attrs={'position': (x, y, -5.52), 'scale': ( - 1.8, 0.1, 2), 'type': 'box', 'materials': [shared.footing_material, self._real_wall_material ,self._lift_material]}) + 1.8, 0.1, 2), 'type': 'box', 'materials': [shared.footing_material, self._real_wall_material, self._lift_material]}) cleaner = ba.newnode('region', attrs={'position': (x, y, -5.52), 'scale': ( 2, 0.3, 2), 'type': 'box', 'materials': [shared.footing_material, self._real_wall_material]}) @@ -181,13 +185,13 @@ def create_lift(self, x, y): _tcombine.connectattr('output', mnode, 'input2') _cleaner_combine = ba.newnode('combine', - owner=cleaner, - attrs={ - 'input1': 5.6, - 'input2': -5.5, - 'size': 3 - }) - _cleaner_combine.connectattr('output', cleaner, 'position') + owner=cleaner, + attrs={ + 'input1': 5.6, + 'input2': -5.5, + 'size': 3 + }) + _cleaner_combine.connectattr('output', cleaner, 'position') ba.animate(_tcombine, 'input1', { 0: 5.1, }) @@ -197,14 +201,16 @@ def create_lift(self, x, y): _tcombine.connectattr('output', floor, 'position') mnode.connectattr('output', lift, 'position') - self.lifts[floor] = {"state":"origin","lift":_tcombine,"cleaner":_cleaner_combine,'leftLift': x < 0} + self.lifts[floor] = {"state": "origin", "lift": _tcombine, + "cleaner": _cleaner_combine, 'leftLift': x < 0} def _handle_lift(self): region = ba.getcollision().sourcenode lift = self.lifts[region] + def clean(lift): ba.animate(lift["cleaner"], 'input0', { - 0: -19 if lift["leftLift"] else 19 , + 0: -19 if lift["leftLift"] else 19, 2: -16 if lift["leftLift"] else 16, 4.3: -19 if lift["leftLift"] else 19 }) @@ -220,7 +226,6 @@ def clean(lift): ba.timer(16, ba.Call(lambda lift: lift.update({'state': 'end'}), lift)) ba.timer(12, ba.Call(clean, lift)) - def _handle_lift_disconnect(self): region = ba.getcollision().sourcenode lift = self.lifts[region] @@ -242,6 +247,7 @@ def create_slope(self, x, y, backslash): x = x-0.1 y = y+0.1 + class mapdefs: points = {} # noinspection PyDictCreation @@ -284,6 +290,8 @@ class mapdefs: 0.9516389866, 0.6666414677, 0.08607244075) points['spawn_by_flag4'] = (0.4932087091, 12.74493212, -5.598987003) + ( 0.5245740665, 0.5245740665, 0.01941146064) + + class CreativeThoughts(ba.Map): """Freaking map by smoothy.""" @@ -323,10 +331,11 @@ def get_music_type(cls) -> ba.MusicType: def __init__(self) -> None: super().__init__(vr_overlay_offset=(0, -3.7, 2.5)) shared = SharedObjects.get() - self._fake_wall_material=ba.Material() - self._real_wall_material=ba.Material() + self._fake_wall_material = ba.Material() + self._real_wall_material = ba.Material() self._fake_wall_material.add_actions( - conditions=(('they_are_younger_than',9000),'and',('they_have_material', shared.player_material)), + conditions=(('they_are_younger_than', 9000), 'and', + ('they_have_material', shared.player_material)), actions=( ('modify_part_collision', 'collide', True), ('modify_part_collision', 'physical', True) @@ -348,12 +357,18 @@ def __init__(self) -> None: 'color_texture': ba.gettexture("rampageBGColor") }) - self.leftwall=ba.newnode('region',attrs={'position': (-17.75152479, 13, -5.52),'scale': (0.1,15.5,2),'type': 'box','materials': [shared.footing_material,self._real_wall_material ]}) - self.rightwall=ba.newnode('region',attrs={'position': (17.75, 13, -5.52),'scale': (0.1,15.5,2),'type': 'box','materials': [shared.footing_material,self._real_wall_material ]}) - self.topwall=ba.newnode('region',attrs={'position': (0, 21.0, -5.52),'scale': (35.4,0.2,2),'type': 'box','materials': [shared.footing_material,self._real_wall_material ]}) - ba.newnode('locator', attrs={'shape':'box', 'position':(-17.75152479, 13, -5.52), 'color':(0,0,0), 'opacity':1,'draw_beauty':True,'additive':False,'size':(0.1,15.5,2)}) - ba.newnode('locator', attrs={'shape':'box', 'position':(17.75, 13, -5.52), 'color':(0,0,0), 'opacity':1,'draw_beauty':True,'additive':False,'size':(0.1,15.5,2)}) - ba.newnode('locator', attrs={'shape':'box', 'position':(0, 21.0, -5.52), 'color':(0,0,0), 'opacity':1,'draw_beauty':True,'additive':False,'size':(35.4,0.2,2)}) + self.leftwall = ba.newnode('region', attrs={'position': (-17.75152479, 13, -5.52), 'scale': ( + 0.1, 15.5, 2), 'type': 'box', 'materials': [shared.footing_material, self._real_wall_material]}) + self.rightwall = ba.newnode('region', attrs={'position': (17.75, 13, -5.52), 'scale': ( + 0.1, 15.5, 2), 'type': 'box', 'materials': [shared.footing_material, self._real_wall_material]}) + self.topwall = ba.newnode('region', attrs={'position': (0, 21.0, -5.52), 'scale': ( + 35.4, 0.2, 2), 'type': 'box', 'materials': [shared.footing_material, self._real_wall_material]}) + ba.newnode('locator', attrs={'shape': 'box', 'position': (-17.75152479, 13, -5.52), 'color': ( + 0, 0, 0), 'opacity': 1, 'draw_beauty': True, 'additive': False, 'size': (0.1, 15.5, 2)}) + ba.newnode('locator', attrs={'shape': 'box', 'position': (17.75, 13, -5.52), 'color': ( + 0, 0, 0), 'opacity': 1, 'draw_beauty': True, 'additive': False, 'size': (0.1, 15.5, 2)}) + ba.newnode('locator', attrs={'shape': 'box', 'position': (0, 21.0, -5.52), 'color': ( + 0, 0, 0), 'opacity': 1, 'draw_beauty': True, 'additive': False, 'size': (35.4, 0.2, 2)}) gnode = ba.getactivity().globalsnode gnode.happy_thoughts_mode = True @@ -393,4 +408,4 @@ def __init__(self) -> None: try: ba._map.register_map(CreativeThoughts) except: - pass \ No newline at end of file + pass From a579a836c5616348db93b9b01bec9403de9f44bc Mon Sep 17 00:00:00 2001 From: imayushsaini Date: Sat, 6 May 2023 17:43:31 +0000 Subject: [PATCH 0425/1464] [ci] apply-version-metadata --- plugins/minigames.json | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/plugins/minigames.json b/plugins/minigames.json index 5015b1b4..ad74e4a8 100644 --- a/plugins/minigames.json +++ b/plugins/minigames.json @@ -285,7 +285,12 @@ } ], "versions": { - "1.0.0": null + "1.0.0": { + "api_version": 7, + "commit_sha": "52094fc", + "released_on": "06-05-2023", + "md5sum": "d4303c1338df50aa15c718cfd9c4ba0a" + } } }, "air_soccer": { @@ -299,7 +304,12 @@ } ], "versions": { - "1.0.0": null + "1.0.0": { + "api_version": 7, + "commit_sha": "52094fc", + "released_on": "06-05-2023", + "md5sum": "4eb4a07830e4bd52fd19150a593d70c5" + } } } } From 60dee789ae3b5293c4e3f018defb3c9f74955a41 Mon Sep 17 00:00:00 2001 From: Sravan Date: Wed, 10 May 2023 00:43:02 +0530 Subject: [PATCH 0426/1464] Display new plugins details Whenever new plugins get added to the manager, the game displays the count and names of the plugins. --- plugin_manager.py | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/plugin_manager.py b/plugin_manager.py index dda2d68a..8e70caa8 100644 --- a/plugin_manager.py +++ b/plugin_manager.py @@ -268,6 +268,20 @@ async def update_plugins(self): plugins_to_update.append(plugin.update()) await asyncio.gather(*plugins_to_update) + async def get_new_plugins(self): + new_plugins = [] + await self.plugin_manager.setup_index() + current_plugins = ## Need to fetch the current present plugins + all_plugins = await self.plugin_manager.categories["All"].get_plugins() + for plugin in all_plugins: + if plugin not in current_plugins: + new_plugins.append(plugin) + plugin_count = len(new_plugins) + plugin_names = ', '.join(new_plugins) + + print_message = f"{plugin_count} new plugins ({plugin_names}) are available!" + ba.screenmessage(print_message, color=(0, 1, 0)) + async def notify_new_plugins(self): if not ba.app.config["Community Plugin Manager"]["Settings"]["Notify New Plugins"]: return @@ -285,6 +299,7 @@ async def notify_new_plugins(self): if num_of_plugins < new_num_of_plugins: ba.screenmessage("We got new Plugins for you to try!") + await self.get_new_plugins() ba.app.config["Community Plugin Manager"]["Existing Number of Plugins"] = new_num_of_plugins ba.app.config.commit() From 967dd0994d77b75294cd6f77d3d3c94990220e01 Mon Sep 17 00:00:00 2001 From: kingsamurai123 Date: Tue, 9 May 2023 19:18:46 +0000 Subject: [PATCH 0427/1464] [ci] auto-format --- plugin_manager.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugin_manager.py b/plugin_manager.py index 8e70caa8..3c8cce70 100644 --- a/plugin_manager.py +++ b/plugin_manager.py @@ -271,7 +271,7 @@ async def update_plugins(self): async def get_new_plugins(self): new_plugins = [] await self.plugin_manager.setup_index() - current_plugins = ## Need to fetch the current present plugins + current_plugins = # Need to fetch the current present plugins all_plugins = await self.plugin_manager.categories["All"].get_plugins() for plugin in all_plugins: if plugin not in current_plugins: From 59b7bdbdc4be81d46508bc483df12fe2e6f9f013 Mon Sep 17 00:00:00 2001 From: Sravan Date: Thu, 11 May 2023 00:50:42 +0530 Subject: [PATCH 0428/1464] Changed the logic to print new plugins Instead of checking the locally present plugins details. This will print the n latest plugins based on release date. --- plugin_manager.py | 31 ++++++++++++++++++++++--------- 1 file changed, 22 insertions(+), 9 deletions(-) diff --git a/plugin_manager.py b/plugin_manager.py index 8e70caa8..45d2c34e 100644 --- a/plugin_manager.py +++ b/plugin_manager.py @@ -19,6 +19,7 @@ import copy from typing import Union, Optional +from datetime import datetime _env = _ba.env() _uiscale = ba.app.ui.uiscale @@ -268,18 +269,20 @@ async def update_plugins(self): plugins_to_update.append(plugin.update()) await asyncio.gather(*plugins_to_update) - async def get_new_plugins(self): + async def get_new_plugins(self, new_plugin_count): new_plugins = [] + plugin_dictionary = {} await self.plugin_manager.setup_index() - current_plugins = ## Need to fetch the current present plugins all_plugins = await self.plugin_manager.categories["All"].get_plugins() for plugin in all_plugins: - if plugin not in current_plugins: - new_plugins.append(plugin) - plugin_count = len(new_plugins) - plugin_names = ', '.join(new_plugins) - - print_message = f"{plugin_count} new plugins ({plugin_names}) are available!" + date, name = plugin.get_name_and_release_date + plugin_dictionary[date] = name + sorted_dict = dict(sorted(plugin_dictionary.items(), key=lambda x: datetime.strptime(x[0], '%d-%m-%Y'), reverse=True)) + for iterator, value in enumerate(sorted_dict.values()): + if iterator < new_plugin_count: + new_plugins.append(value) + new_plugin_names = ', '.join(new_plugins) + print_message = f"{new_plugin_count} new plugins ({new_plugin_names}) are available!" ba.screenmessage(print_message, color=(0, 1, 0)) async def notify_new_plugins(self): @@ -299,7 +302,7 @@ async def notify_new_plugins(self): if num_of_plugins < new_num_of_plugins: ba.screenmessage("We got new Plugins for you to try!") - await self.get_new_plugins() + await self.get_new_plugins(new_num_of_plugins-num_of_plugins) ba.app.config["Community Plugin Manager"]["Existing Number of Plugins"] = new_num_of_plugins ba.app.config.commit() @@ -704,10 +707,20 @@ def __init__(self, plugin, url, is_3rd_party=False): self._versions = None self._latest_version = None self._latest_compatible_version = None + self._released_on = None + self._latest_plugin_key = None def __repr__(self): return f"" + @property + def get_name_and_release_date(self): + if self._released_on is None: + self._latest_plugin_key = list(self.info["versions"].keys())[0] + self._released_on = self.info["versions"][self._latest_plugin_key] + # self._released_on = sorted(self._released_on, key=self._released_on["released_on"]) + return self._released_on["released_on"], self.name + @property def view_url(self): if self.latest_compatible_version == self.latest_version: From 1eef94f77a4f370053391b9ebe95e0799b298848 Mon Sep 17 00:00:00 2001 From: kingsamurai123 Date: Wed, 10 May 2023 19:26:00 +0000 Subject: [PATCH 0429/1464] [ci] auto-format --- plugin_manager.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/plugin_manager.py b/plugin_manager.py index 45d2c34e..9c3c18e1 100644 --- a/plugin_manager.py +++ b/plugin_manager.py @@ -277,7 +277,8 @@ async def get_new_plugins(self, new_plugin_count): for plugin in all_plugins: date, name = plugin.get_name_and_release_date plugin_dictionary[date] = name - sorted_dict = dict(sorted(plugin_dictionary.items(), key=lambda x: datetime.strptime(x[0], '%d-%m-%Y'), reverse=True)) + sorted_dict = dict(sorted(plugin_dictionary.items(), + key=lambda x: datetime.strptime(x[0], '%d-%m-%Y'), reverse=True)) for iterator, value in enumerate(sorted_dict.values()): if iterator < new_plugin_count: new_plugins.append(value) From 599a215faae178a1866c1142a9a782659c10dff7 Mon Sep 17 00:00:00 2001 From: Sravan Date: Sat, 13 May 2023 13:04:30 +0530 Subject: [PATCH 0430/1464] Changed the key in dictionary to plugin name Removed the extra property from the plugin class and also changed the key to plugin name in the new sorted plugin dictionary to increase the stability. --- plugin_manager.py | 41 ++++++++++++++++++++--------------------- 1 file changed, 20 insertions(+), 21 deletions(-) diff --git a/plugin_manager.py b/plugin_manager.py index 9c3c18e1..0c78a465 100644 --- a/plugin_manager.py +++ b/plugin_manager.py @@ -270,20 +270,29 @@ async def update_plugins(self): await asyncio.gather(*plugins_to_update) async def get_new_plugins(self, new_plugin_count): - new_plugins = [] - plugin_dictionary = {} + valid_new_plugins = [] + plugin_dictionary, sorted_plugins, new_plugins = {}, {}, {} + count = 0 await self.plugin_manager.setup_index() all_plugins = await self.plugin_manager.categories["All"].get_plugins() for plugin in all_plugins: - date, name = plugin.get_name_and_release_date - plugin_dictionary[date] = name - sorted_dict = dict(sorted(plugin_dictionary.items(), - key=lambda x: datetime.strptime(x[0], '%d-%m-%Y'), reverse=True)) - for iterator, value in enumerate(sorted_dict.values()): - if iterator < new_plugin_count: - new_plugins.append(value) - new_plugin_names = ', '.join(new_plugins) - print_message = f"{new_plugin_count} new plugins ({new_plugin_names}) are available!" + plugin_dictionary[plugin.name] = plugin.info + for key, value in plugin_dictionary.items(): + latest_version = max(value['versions'].keys()) + new_plugins[key] = {'released_on': value['versions'][latest_version]['released_on'], + 'api_version': value['versions'][latest_version]['api_version']} + sorted_plugins = dict(sorted(new_plugins.items(), + key=lambda x: datetime.strptime(x[1]['released_on'], '%d-%m-%Y'), + reverse=True)) + + for key, value in sorted_plugins.items(): + if count < new_plugin_count: + valid_new_plugins.append(key) + count += 1 + else: + break + valid_new_plugins = ', '.join(valid_new_plugins) + print_message = f"{new_plugin_count} new plugins ({valid_new_plugins}) are available!" ba.screenmessage(print_message, color=(0, 1, 0)) async def notify_new_plugins(self): @@ -708,20 +717,10 @@ def __init__(self, plugin, url, is_3rd_party=False): self._versions = None self._latest_version = None self._latest_compatible_version = None - self._released_on = None - self._latest_plugin_key = None def __repr__(self): return f"" - @property - def get_name_and_release_date(self): - if self._released_on is None: - self._latest_plugin_key = list(self.info["versions"].keys())[0] - self._released_on = self.info["versions"][self._latest_plugin_key] - # self._released_on = sorted(self._released_on, key=self._released_on["released_on"]) - return self._released_on["released_on"], self.name - @property def view_url(self): if self.latest_compatible_version == self.latest_version: From 0c2b7becaf649219f62b05483971296fd878eb27 Mon Sep 17 00:00:00 2001 From: kingsamurai123 Date: Sat, 13 May 2023 07:36:46 +0000 Subject: [PATCH 0431/1464] [ci] auto-format --- plugin_manager.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/plugin_manager.py b/plugin_manager.py index 0c78a465..8aad6b7c 100644 --- a/plugin_manager.py +++ b/plugin_manager.py @@ -282,7 +282,8 @@ async def get_new_plugins(self, new_plugin_count): new_plugins[key] = {'released_on': value['versions'][latest_version]['released_on'], 'api_version': value['versions'][latest_version]['api_version']} sorted_plugins = dict(sorted(new_plugins.items(), - key=lambda x: datetime.strptime(x[1]['released_on'], '%d-%m-%Y'), + key=lambda x: datetime.strptime( + x[1]['released_on'], '%d-%m-%Y'), reverse=True)) for key, value in sorted_plugins.items(): From ddf150e08b1accfdb8878eaa193e0bff51ce772d Mon Sep 17 00:00:00 2001 From: Sravan Date: Sat, 13 May 2023 17:40:55 +0530 Subject: [PATCH 0432/1464] Added new api version check with that of the game and plugin supported. This checks the game api version and plugin version and only prints screenmessage of only game supported plugins. --- plugin_manager.py | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/plugin_manager.py b/plugin_manager.py index 8aad6b7c..15b40d8e 100644 --- a/plugin_manager.py +++ b/plugin_manager.py @@ -272,7 +272,7 @@ async def update_plugins(self): async def get_new_plugins(self, new_plugin_count): valid_new_plugins = [] plugin_dictionary, sorted_plugins, new_plugins = {}, {}, {} - count = 0 + await self.plugin_manager.setup_index() all_plugins = await self.plugin_manager.categories["All"].get_plugins() for plugin in all_plugins: @@ -287,14 +287,17 @@ async def get_new_plugins(self, new_plugin_count): reverse=True)) for key, value in sorted_plugins.items(): - if count < new_plugin_count: - valid_new_plugins.append(key) - count += 1 + if new_plugin_count > 0: + if ba.app.api_version == value['api_version']: + valid_new_plugins.append(key) + new_plugin_count -= 1 else: break - valid_new_plugins = ', '.join(valid_new_plugins) - print_message = f"{new_plugin_count} new plugins ({valid_new_plugins}) are available!" - ba.screenmessage(print_message, color=(0, 1, 0)) + new_plugin_count = len(valid_new_plugins) + if new_plugin_count: + valid_new_plugins = ', '.join(valid_new_plugins) + print_message = f"{new_plugin_count} new plugins ({valid_new_plugins}) are available!" + ba.screenmessage(print_message, color=(0, 1, 0)) async def notify_new_plugins(self): if not ba.app.config["Community Plugin Manager"]["Settings"]["Notify New Plugins"]: From 263ee994ae0bf2292bde1e255d32091b934b1c3c Mon Sep 17 00:00:00 2001 From: Sravan Date: Sat, 13 May 2023 19:51:45 +0530 Subject: [PATCH 0433/1464] bump to new version Change the version --- index.json | 1 + plugin_manager.py | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/index.json b/index.json index 3a1b0018..7af7823e 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.3" : null, "0.3.2": { "api_version": 7, "commit_sha": "789f95f", diff --git a/plugin_manager.py b/plugin_manager.py index 15b40d8e..3a08922f 100644 --- a/plugin_manager.py +++ b/plugin_manager.py @@ -25,7 +25,7 @@ _uiscale = ba.app.ui.uiscale -PLUGIN_MANAGER_VERSION = "0.3.2" +PLUGIN_MANAGER_VERSION = "0.3.3" 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 54614dee59a09dabd4a071345aaeadb95861ef75 Mon Sep 17 00:00:00 2001 From: Sravan Date: Sat, 13 May 2023 19:52:14 +0530 Subject: [PATCH 0434/1464] Update CHANGELOG Updated changelog with the relevant fixes. --- CHANGELOG.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 52493048..fa2f87a4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,9 @@ ## Plugin Manager (dd-mm-yyyy) +### 0.3.3 (13-05-2023) + +- Print the number and names of the client supported plugins which are newly added to the plugin manager. + ### 0.3.2 (30-04-2023) - Fix sometimes same sound would repeat twice when pressing a button. From 1d9f6e16fea4ae55e85a39772c27fbcab1663324 Mon Sep 17 00:00:00 2001 From: kingsamurai123 Date: Sat, 13 May 2023 14:23:54 +0000 Subject: [PATCH 0435/1464] [ci] apply-version-metadata --- index.json | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/index.json b/index.json index 7af7823e..2e254a46 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.3" : null, + "0.3.3": { + "api_version": 7, + "commit_sha": "54614de", + "released_on": "13-05-2023", + "md5sum": "d55a413b6b2e6b8f15ad3523b224f164" + }, "0.3.2": { "api_version": 7, "commit_sha": "789f95f", From b48119bd366bda32a82a5d72341a8635449289e1 Mon Sep 17 00:00:00 2001 From: Sravan Date: Sat, 13 May 2023 20:32:48 +0530 Subject: [PATCH 0436/1464] updated the screenmessage for new plugins Prints only a single message depending on number of plugins. --- index.json | 7 +------ plugin_manager.py | 6 ++++-- 2 files changed, 5 insertions(+), 8 deletions(-) diff --git a/index.json b/index.json index 2e254a46..80d1a253 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.3": { - "api_version": 7, - "commit_sha": "54614de", - "released_on": "13-05-2023", - "md5sum": "d55a413b6b2e6b8f15ad3523b224f164" - }, + "0.3.3": null, "0.3.2": { "api_version": 7, "commit_sha": "789f95f", diff --git a/plugin_manager.py b/plugin_manager.py index 3a08922f..011a30ce 100644 --- a/plugin_manager.py +++ b/plugin_manager.py @@ -296,7 +296,10 @@ async def get_new_plugins(self, new_plugin_count): new_plugin_count = len(valid_new_plugins) if new_plugin_count: valid_new_plugins = ', '.join(valid_new_plugins) - print_message = f"{new_plugin_count} new plugins ({valid_new_plugins}) are available!" + if new_plugin_count == 1: + print_message = f"{new_plugin_count} new plugin ({valid_new_plugins}) is available!" + else: + print_message = f"{new_plugin_count} new plugins ({valid_new_plugins}) are available!" ba.screenmessage(print_message, color=(0, 1, 0)) async def notify_new_plugins(self): @@ -315,7 +318,6 @@ async def notify_new_plugins(self): new_num_of_plugins = len(await self.plugin_manager.categories["All"].get_plugins()) if num_of_plugins < new_num_of_plugins: - ba.screenmessage("We got new Plugins for you to try!") await self.get_new_plugins(new_num_of_plugins-num_of_plugins) ba.app.config["Community Plugin Manager"]["Existing Number of Plugins"] = new_num_of_plugins ba.app.config.commit() From 7f25f953c0aa884999f28b325080347ea98d61bd Mon Sep 17 00:00:00 2001 From: kingsamurai123 Date: Sat, 13 May 2023 15:05:57 +0000 Subject: [PATCH 0437/1464] [ci] apply-version-metadata --- index.json | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/index.json b/index.json index 80d1a253..4fb34564 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.3": null, + "0.3.3": { + "api_version": 7, + "commit_sha": "b48119b", + "released_on": "13-05-2023", + "md5sum": "611c20732eda494d9ad7090b0bc3df54" + }, "0.3.2": { "api_version": 7, "commit_sha": "789f95f", From 50220336649730625298963060dec467f7c015e2 Mon Sep 17 00:00:00 2001 From: Rikko Date: Sun, 14 May 2023 12:43:41 +0530 Subject: [PATCH 0438/1464] Clarify explicit licensing --- README.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index a07a3e54..e2825f82 100644 --- a/README.md +++ b/README.md @@ -215,4 +215,6 @@ create something similar, with a hope we as a community can continue to keep it - [Plugin manager's source code](plugin_manager.py) is licensed under the MIT license. See [LICENSE](LICENSE) for more information. - Any plugins you submit here are automatically assumed to be licensed under the MIT license, i.e. unless you explicitly - specify a different license while submitting a plugin. + specify a different license in your plugin's source code. See + [this plugin](https://github.com/rikkolovescats/plugin-manager/blob/f29008acdbf54988f3622ae4baa8735d83338bb5/plugins/utilities/store_event_specials.py#L1-L22) + for an example. From 2d74b52d2fd659347eb4e39e2258e8aa44b1c30a Mon Sep 17 00:00:00 2001 From: Rikko Date: Sun, 14 May 2023 15:41:24 +0530 Subject: [PATCH 0439/1464] Optimize new plugin detection mechanism --- CHANGELOG.md | 4 +++ index.json | 3 +- plugin_manager.py | 82 ++++++++++++++++++++++++----------------------- 3 files changed, 48 insertions(+), 41 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index fa2f87a4..ddb321aa 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,9 @@ ## Plugin Manager (dd-mm-yyyy) +### 0.3.4 (14-05-2023) + +- Optimize new plugin detection mechanism. + ### 0.3.3 (13-05-2023) - Print the number and names of the client supported plugins which are newly added to the plugin manager. diff --git a/index.json b/index.json index 4fb34564..92c6165b 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.4": null, "0.3.3": { "api_version": 7, "commit_sha": "b48119b", @@ -92,4 +93,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 011a30ce..fd103501 100644 --- a/plugin_manager.py +++ b/plugin_manager.py @@ -25,7 +25,7 @@ _uiscale = ba.app.ui.uiscale -PLUGIN_MANAGER_VERSION = "0.3.3" +PLUGIN_MANAGER_VERSION = "0.3.4" 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. @@ -269,56 +269,50 @@ async def update_plugins(self): plugins_to_update.append(plugin.update()) await asyncio.gather(*plugins_to_update) - async def get_new_plugins(self, new_plugin_count): - valid_new_plugins = [] - plugin_dictionary, sorted_plugins, new_plugins = {}, {}, {} - - await self.plugin_manager.setup_index() - all_plugins = await self.plugin_manager.categories["All"].get_plugins() - for plugin in all_plugins: - plugin_dictionary[plugin.name] = plugin.info - for key, value in plugin_dictionary.items(): - latest_version = max(value['versions'].keys()) - new_plugins[key] = {'released_on': value['versions'][latest_version]['released_on'], - 'api_version': value['versions'][latest_version]['api_version']} - sorted_plugins = dict(sorted(new_plugins.items(), - key=lambda x: datetime.strptime( - x[1]['released_on'], '%d-%m-%Y'), - reverse=True)) - - for key, value in sorted_plugins.items(): - if new_plugin_count > 0: - if ba.app.api_version == value['api_version']: - valid_new_plugins.append(key) - new_plugin_count -= 1 - else: - break - new_plugin_count = len(valid_new_plugins) - if new_plugin_count: - valid_new_plugins = ', '.join(valid_new_plugins) - if new_plugin_count == 1: - print_message = f"{new_plugin_count} new plugin ({valid_new_plugins}) is available!" - else: - print_message = f"{new_plugin_count} new plugins ({valid_new_plugins}) are available!" - ba.screenmessage(print_message, color=(0, 1, 0)) + @staticmethod + def _is_new_supported_plugin(plugin): + is_an_update = len(plugin.versions) > 1 + if is_an_update: + return False + try: + plugin.latest_compatible_version + except NoCompatibleVersionError: + return False + else: + return True async def notify_new_plugins(self): if not ba.app.config["Community Plugin Manager"]["Settings"]["Notify New Plugins"]: return await self.plugin_manager.setup_index() + new_num_of_plugins = len(await self.plugin_manager.categories["All"].get_plugins()) try: - num_of_plugins = ba.app.config["Community Plugin Manager"]["Existing Number of Plugins"] - except Exception: - ba.app.config["Community Plugin Manager"]["Existing Number of Plugins"] = len(await self.plugin_manager.categories["All"].get_plugins()) - num_of_plugins = ba.app.config["Community Plugin Manager"]["Existing Number of Plugins"] + existing_num_of_plugins = ba.app.config["Community Plugin Manager"]["Existing Number of Plugins"] + except KeyError: + ba.app.config["Community Plugin Manager"]["Existing Number of Plugins"] = new_num_of_plugins ba.app.config.commit() return - new_num_of_plugins = len(await self.plugin_manager.categories["All"].get_plugins()) + if existing_num_of_plugins < new_num_of_plugins: + new_plugin_count = new_num_of_plugins - existing_num_of_plugins + all_plugins = await self.plugin_manager.categories["All"].get_plugins() + new_supported_plugins = list(filter(self._is_new_supported_plugin, all_plugins)) + new_supported_plugins.sort( + key=lambda plugin: plugin.latest_compatible_version.released_on_date, + reverse=True, + ) + new_supported_plugins = new_supported_plugins[:new_plugin_count] + new_supported_plugins_count = len(new_supported_plugins) + if new_supported_plugins_count > 0: + new_supported_plugins = ", ".join(map(str, new_supported_plugins)) + if new_supported_plugins_count == 1: + notification_text = f"{new_supported_plugins_count} new plugin ({new_supported_plugins}) is available!" + else: + notification_text = f"{new_supported_plugins_count} new plugins ({new_supported_plugins}) are available!" + ba.screenmessage(notification_text, color=(0, 1, 0)) - if num_of_plugins < new_num_of_plugins: - await self.get_new_plugins(new_num_of_plugins-num_of_plugins) + if existing_num_of_plugins != new_num_of_plugins: ba.app.config["Community Plugin Manager"]["Existing Number of Plugins"] = new_num_of_plugins ba.app.config.commit() @@ -659,6 +653,7 @@ def __init__(self, plugin, version, tag=None): self.number, info = version self.plugin = plugin self.api_version = info["api_version"] + self.released_on = info["released_on"] self.commit_sha = info["commit_sha"] self.md5sum = info["md5sum"] @@ -675,6 +670,10 @@ def __eq__(self, plugin_version): def __repr__(self): return f"" + @property + def released_on_date(self): + return datetime.strptime(self.released_on, "%d-%m-%Y") + async def _download(self, retries=3): local_plugin = self.plugin.create_local() await local_plugin.set_content_from_network_response( @@ -727,6 +726,9 @@ def __init__(self, plugin, url, is_3rd_party=False): def __repr__(self): return f"" + def __str__(self): + return self.name + @property def view_url(self): if self.latest_compatible_version == self.latest_version: From efc4b75afe3c439895b9d7ea74f1801c171c0627 Mon Sep 17 00:00:00 2001 From: rikkolovescats Date: Sun, 14 May 2023 10:14:36 +0000 Subject: [PATCH 0440/1464] [ci] apply-version-metadata --- index.json | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/index.json b/index.json index 92c6165b..4fbe3858 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.4": null, + "0.3.4": { + "api_version": 7, + "commit_sha": "2d74b52", + "released_on": "14-05-2023", + "md5sum": "7ff90318c4c379f7f0039c13ddaeaef0" + }, "0.3.3": { "api_version": 7, "commit_sha": "b48119b", @@ -93,4 +98,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 4af785998d5e6acb85ccbe6a66b759029293e9f0 Mon Sep 17 00:00:00 2001 From: Loup-Garou911XD Date: Mon, 15 May 2023 15:56:45 +0530 Subject: [PATCH 0441/1464] Added many minigames --- plugins/minigames.json | 149 +++- plugins/minigames/arms_race.py | 194 +++++ plugins/minigames/collector.py | 642 +++++++++++++++++ plugins/minigames/dodge_the_ball.py | 762 ++++++++++++++++++++ plugins/minigames/invisible_one.py | 333 +++++++++ plugins/minigames/last_punch_stand.py | 263 +++++++ plugins/minigames/quake.py | 642 +++++++++++++++++ plugins/minigames/sleep_race.py | 783 ++++++++++++++++++++ plugins/minigames/snake.py | 314 ++++++++ plugins/minigames/ufo_fight.py | 994 ++++++++++++++++++++++++++ plugins/minigames/yeeting_party.py | 222 ++++++ 11 files changed, 5296 insertions(+), 2 deletions(-) create mode 100644 plugins/minigames/arms_race.py create mode 100644 plugins/minigames/collector.py create mode 100644 plugins/minigames/dodge_the_ball.py create mode 100644 plugins/minigames/invisible_one.py create mode 100644 plugins/minigames/last_punch_stand.py create mode 100644 plugins/minigames/quake.py create mode 100644 plugins/minigames/sleep_race.py create mode 100644 plugins/minigames/snake.py create mode 100644 plugins/minigames/ufo_fight.py create mode 100644 plugins/minigames/yeeting_party.py diff --git a/plugins/minigames.json b/plugins/minigames.json index ad74e4a8..0946122a 100644 --- a/plugins/minigames.json +++ b/plugins/minigames.json @@ -311,6 +311,151 @@ "md5sum": "4eb4a07830e4bd52fd19150a593d70c5" } } - } + }, + "arms_race": { + "description": "Upgrade your weapons by eliminating enemies.Win by being first one to kill while cursed", + "external_url": "", + "authors": [ + { + "name": "Freaku", + "email": "", + "discord": "[Just] Freak#4999" + } + ], + "versions": { + "1.0.0": null + } + }, + "collector": { + "description": "Kill your opponents to steal their Capsules.Collect them and score at the Deposist Point!", + "external_url": "", + "authors": [ + { + "name": "TheMikirog", + "email": "", + "discord": "TheMikirog#1984" + }, + { + "name": "JoseAng3l", + "email": "", + "discord": "! JoseANG3L#0268" + } + ], + "versions": { + "1.0.0": null + } + }, + "dodge_the_ball": { + "description": "Survive from shooting balls", + "external_url": "", + "authors": [ + { + "name": "EmperoR", + "email": "", + "discord": "EmperoR#4098" + } + ], + "versions": { + "1.0.0": null + } + }, + "invisible_one": { + "description": "Be the invisible one for a length of time to win.Kill the invisible one to become it.", + "external_url": "", + "authors": [ + { + "name": "itsre3", + "email": "", + "discord": "itsre3#0267" + } + ], + "versions": { + "1.0.0": null + } + }, + "last_punch_stand": { + "description": "", + "external_url": "Last one to punch the spaz when timer ends wins", + "authors": [ + { + "name": "ThePersonMan", + "email": "", + "discord": "ThePersonMan#0276" + } + ], + "versions": { + "1.0.0": null + } + }, + "quake": { + "description": "Kill set number of enemies to win with optional rocket/railgun weapons", + "external_url": "", + "authors": [ + { + "name": "Dliwk", + "email": "", + "discord": "Dliwk#7961" + } + ], + "versions": { + "1.0.0": null + } + }, + "sleep_race": { + "description": "Can you win while sleeping?", + "external_url": "", + "authors": [ + { + "name": "itsre3", + "email": "", + "discord": "itsre3#0267" + } + ], + "versions": { + "1.0.0": null + } + }, + "snake": { + "description": "Survive a set number of mines to win", + "external_url": "", + "authors": [ + { + "name": "Sebastian", + "email": "", + "discord": "SEBASTIAN2059#5751" + } + ], + "versions": { + "1.0.0": null + } + }, + "ufo_fight": { + "description": "Fight the UFO boss!", + "external_url": "", + "authors": [ + { + "name": "Cross Joy", + "email": "cross.joy.official@gmail.com", + "discord": "Cross Joy#0721" + } + ], + "versions": { + "1.0.0": null + } + }, + "yeeting_party": { + "description": "Yeet your enemies out of the map!", + "external_url": "", + "authors": [ + { + "name": "Freaku", + "email": "", + "discord": "[Just] Freak#4999" + } + ], + "versions": { + "1.0.0": null + } + }, } -} \ No newline at end of file +} diff --git a/plugins/minigames/arms_race.py b/plugins/minigames/arms_race.py new file mode 100644 index 00000000..13f32b79 --- /dev/null +++ b/plugins/minigames/arms_race.py @@ -0,0 +1,194 @@ +#Ported by: Freaku / @[Just] Freak#4999 + +#Join BCS: +# https://discord.gg/ucyaesh + + + +# ba_meta require api 7 + +from __future__ import annotations + +from typing import TYPE_CHECKING + +import ba +from bastd.actor.playerspaz import PlayerSpaz + +if TYPE_CHECKING: + from typing import Any, Type, List, Dict, Tuple, Union, Sequence, Optional + + + +class State: + def __init__(self, bomb=None, grab=False, punch=False, curse=False, required=False, final=False, name=''): + self.bomb = bomb + self.grab = grab + self.punch = punch + self.pickup = False + self.curse = curse + self.required = required or final + self.final = final + self.name = name + self.next = None + self.index = None + + def apply(self, spaz): + spaz.disconnect_controls_from_player() + spaz.connect_controls_to_player(enable_punch=self.punch, + enable_bomb=self.bomb, + enable_pickup=self.grab) + if self.curse: + spaz.curse_time = -1 + spaz.curse() + if self.bomb: + spaz.bomb_type = self.bomb + spaz.set_score_text(self.name) + + def get_setting(self): + return (self.name) + + +states = [ State(bomb='normal', name='Basic Bombs'), + State(bomb='ice', name='Frozen Bombs'), + State(bomb='sticky', name='Sticky Bombs'), + State(bomb='impact', name='Impact Bombs'), + State(grab=True, name='Grabbing only'), + State(punch=True, name='Punching only'), + State(curse=True, name='Cursed', final=True) ] + +class Player(ba.Player['Team']): + """Our player type for this game.""" + def __init__(self): + self.state = None + + +class Team(ba.Team[Player]): + """Our team type for this game.""" + + def __init__(self) -> None: + self.score = 0 + + +# ba_meta export game +class ArmsRaceGame(ba.TeamGameActivity[Player, Team]): + """A game type based on acquiring kills.""" + + name = 'Arms Race' + description = 'Upgrade your weapon by eliminating enemies.\nWin the match by being the first player\nto get a kill while cursed.' + + # Print messages when players die since it matters here. + announce_player_deaths = True + + @classmethod + def get_available_settings( + cls, sessiontype: Type[ba.Session]) -> List[ba.Setting]: + settings = [ + 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', 4.0), + ], + default=1.0, + ), + ba.BoolSetting('Epic Mode', default=False)] + for state in states: + if not state.required: + settings.append(ba.BoolSetting(state.get_setting(), default=True)) + + return settings + + @classmethod + def supports_session_type(cls, sessiontype: Type[ba.Session]) -> bool: + return (issubclass(sessiontype, ba.DualTeamSession) + or issubclass(sessiontype, ba.FreeForAllSession)) + + @classmethod + def get_supported_maps(cls, sessiontype: Type[ba.Session]) -> List[str]: + return ba.getmaps('melee') + + def __init__(self, settings: dict): + super().__init__(settings) + self.states = [s for s in states if settings.get(s.name, True)] + for i, state in enumerate(self.states): + if i < len(self.states) and not state.final: + state.next = self.states[i + 1] + state.index = i + self._dingsound = ba.getsound('dingSmall') + self._epic_mode = bool(settings['Epic Mode']) + self._time_limit = float(settings['Time Limit']) + + # Base class overrides. + self.slow_motion = self._epic_mode + self.default_music = (ba.MusicType.EPIC if self._epic_mode else + ba.MusicType.TO_THE_DEATH) + + def get_instance_description(self) -> Union[str, Sequence]: + return 'Upgrade your weapon by eliminating enemies.' + + def get_instance_description_short(self) -> Union[str, Sequence]: + return 'kill ${ARG1} enemies', len(self.states) + + def on_begin(self) -> None: + super().on_begin() + self.setup_standard_time_limit(self._time_limit) + # self.setup_standard_powerup_drops() + + def on_player_join(self, player): + if player.state is None: + player.state = self.states[0] + self.spawn_player(player) + + # overriding the default character spawning.. + def spawn_player(self, player): + if player.state is None: + player.state = self.states[0] + super().spawn_player(player) + player.state.apply(player.actor) + + def isValidKill(self, m): + if m.getkillerplayer(Player) is None: + return False + + if m.getkillerplayer(Player).team is m.getplayer(Player).team: + return False + + return True + + def handlemessage(self, msg: Any) -> Any: + + if isinstance(msg, ba.PlayerDiedMessage): + if self.isValidKill(msg): + self.stats.player_scored(msg.getkillerplayer(Player), 10, kill=True) + if not msg.getkillerplayer(Player).state.final: + msg.getkillerplayer(Player).state = msg.getkillerplayer(Player).state.next + msg.getkillerplayer(Player).state.apply(msg.getkillerplayer(Player).actor) + else: + msg.getkillerplayer(Player).team.score += 1 + self.end_game() + self.respawn_player(msg.getplayer(Player)) + + else: + return super().handlemessage(msg) + return None + + def end_game(self) -> None: + results = ba.GameResults() + for team in self.teams: + results.set_team_score(team, team.score) + self.end(results=results) diff --git a/plugins/minigames/collector.py b/plugins/minigames/collector.py new file mode 100644 index 00000000..1a22bda3 --- /dev/null +++ b/plugins/minigames/collector.py @@ -0,0 +1,642 @@ +# ba_meta require api 7 +# (see https://ballistica.net/wiki/meta-tag-system) + +''' + Gamemode: Collector + Creator: TheMikirog + Website: https://bombsquadjoyride.blogspot.com/ + + This is a gamemode purely made by me just to spite unchallenged modders + out there that put out crap to the market. + We don't want gamemodes that are just the existing ones + with some novelties! Gamers deserve more! + + In this gamemode you have to kill others in order to get their Capsules. + Capsules can be collected and staked in your inventory, + how many as you please. + After you kill an enemy that carries some of them, + they drop a respective amount of Capsules they carried + two more. + Your task is to collect these Capsules, + get to the flag and score them KOTH style. + You can't score if you don't have any Capsules with you. + The first player or team to get to the required ammount wins. + This is a gamemode all about trying to stay alive + and picking your battles in order to win. + A rare skill in BombSquad, where everyone is overly aggressive. +''' + +from __future__ import annotations + +import weakref +from enum import Enum +from typing import TYPE_CHECKING + +import ba +import random +from bastd.actor.flag import Flag +from bastd.actor.popuptext import PopupText +from bastd.actor.playerspaz import PlayerSpaz +from bastd.actor.scoreboard import Scoreboard +from bastd.gameutils import SharedObjects + +if TYPE_CHECKING: + from typing import Any, Sequence + + +lang = ba.app.lang.language +if lang == 'Spanish': + name = 'Coleccionista' + description = ('Elimina a tus oponentes para robar sus cápsulas.\n' + '¡Recolecta y anota en el punto de depósito!') + description_ingame = 'Obtén ${ARG1} cápsulas de tus enemigos.' + description_short = 'colecciona ${ARG1} cápsulas' + tips = [( + '¡Si tu oponente cae fuera del mapa, sus cápsulas desapareceran!\n' + 'No intestes matar a tus enemigos arrojándolos al vacio.'), + 'No te apresures. ¡Puedes perder tus cápsulas rápidamente!', + ('¡No dejes que el jugador con más cápsulas anote!\n' + '¡Intenta atraparlo si puedes!'), + ('¡Las Capsulas de la Suerte te dan 4 cápsulas en lugar de 2' + 'y tienen un 8% de probabilidad de aparecer después de matar'), + ('¡No te quedes en un solo lugar! Muevete más rapido que tu enemigo, ' + '¡con suerte conseguirás algunas cápsulas!'), + ] + capsules_to_win = 'Cápsulas para Ganar' + capsules_death = 'Cápsulas al Morir' + lucky_capsules = 'Cápsulas de la Suerte' + bonus = '¡BONUS!' + full_capacity = '¡Capacidad Completa!' +else: + name = 'Collector' + description = ('Kill your opponents to steal their Capsules.\n' + 'Collect them and score at the Deposit point!') + description_ingame = 'Score ${ARG1} capsules from your enemies.' + description_short = 'collect ${ARG1} capsules' + tips = [( + 'Making you opponent fall down the pit makes his Capsules wasted!\n' + 'Try not to kill enemies by throwing them off the cliff.'), + 'Don\'t be too reckless. You can lose your loot quite quickly!', + ('Don\'t let the leading player score his Capsules ' + 'at the Deposit Point!\nTry to catch him if you can!'), + ('Lucky Capsules give 4 to your inventory and they have 8% chance ' + 'of spawning after kill!'), + ('Don\'t camp in one place! Make your move first, ' + 'so hopefully you get some dough!'), + ] + capsules_to_win = 'Capsules to Win' + capsules_death = 'Capsules on Death' + lucky_capsules = 'Allow Lucky Capsules' + bonus = 'BONUS!' + full_capacity = 'Full Capacity!' + + +class FlagState(Enum): + """States our single flag can be in.""" + + NEW = 0 + UNCONTESTED = 1 + CONTESTED = 2 + HELD = 3 + + +class Player(ba.Player['Team']): + """Our player type for this game.""" + + def __init__(self) -> None: + self.time_at_flag = 0 + self.capsules = 0 + self.light = None + + +class Team(ba.Team[Player]): + """Our team type for this game.""" + + def __init__(self) -> None: + self.score = 0 + + +# ba_meta export game +class CollectorGame(ba.TeamGameActivity[Player, Team]): + + name = name + description = description + tips = tips + + # Print messages when players die since it matters here. + announce_player_deaths = True + + @classmethod + def get_available_settings( + cls, sessiontype: type[ba.Session] + ) -> list[ba.Setting]: + settings = [ + ba.IntSetting( + capsules_to_win, + min_value=1, + default=10, + increment=1, + ), + ba.IntSetting( + capsules_death, + min_value=1, + max_value=10, + default=2, + 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', 4.0), + ], + default=1.0, + ), + ba.BoolSetting(lucky_capsules, default=True), + ba.BoolSetting('Epic Mode', default=False), + ] + return settings + + @classmethod + def supports_session_type(cls, sessiontype: type[ba.Session]) -> bool: + return issubclass(sessiontype, ba.DualTeamSession) or issubclass( + sessiontype, ba.FreeForAllSession + ) + + @classmethod + def get_supported_maps(cls, sessiontype: type[ba.Session]) -> list[str]: + return ba.getmaps('keep_away') + + def __init__(self, settings: dict): + super().__init__(settings) + shared = SharedObjects.get() + self._scoreboard = Scoreboard() + self._score_to_win: int | None = None + self._swipsound = ba.getsound('swip') + self._lucky_sound = ba.getsound('ding') + + self._flag_pos: Sequence[float] | None = None + self._flag_state: FlagState | None = None + self._flag: Flag | None = None + self._flag_light: ba.Node | None = None + self._scoring_team: weakref.ref[Team] | None = None + self._time_limit = float(settings['Time Limit']) + self._epic_mode = bool(settings['Epic Mode']) + + self._capsules_to_win = int(settings[capsules_to_win]) + self._capsules_death = int(settings[capsules_death]) + self._lucky_capsules = bool(settings[lucky_capsules]) + self._capsules: list[Any] = [] + + self._capsule_model = ba.getmodel('bomb') + self._capsule_tex = ba.gettexture('bombColor') + self._capsule_lucky_tex = ba.gettexture('bombStickyColor') + self._collect_sound = ba.getsound('powerup01') + self._lucky_collect_sound = ba.getsound('cashRegister2') + + self._capsule_material = ba.Material() + self._capsule_material.add_actions( + conditions=('they_have_material', shared.player_material), + actions=('call', 'at_connect', self._on_capsule_player_collide), + ) + + self._flag_region_material = ba.Material() + self._flag_region_material.add_actions( + conditions=('they_have_material', shared.player_material), + actions=( + ('modify_part_collision', 'collide', True), + ('modify_part_collision', 'physical', False), + ( + 'call', + 'at_connect', + ba.Call(self._handle_player_flag_region_collide, True), + ), + ( + 'call', + 'at_disconnect', + ba.Call(self._handle_player_flag_region_collide, False), + ), + ), + ) + + # Base class overrides. + self.slow_motion = self._epic_mode + self.default_music = ( + ba.MusicType.EPIC if self._epic_mode else ba.MusicType.SCARY + ) + + def get_instance_description(self) -> str | Sequence: + return description_ingame, self._score_to_win + + def get_instance_description_short(self) -> str | Sequence: + return description_short, self._score_to_win + + def create_team(self, sessionteam: ba.SessionTeam) -> Team: + return Team() + + def on_team_join(self, team: Team) -> None: + self._update_scoreboard() + + def on_begin(self) -> None: + super().on_begin() + shared = SharedObjects.get() + self.setup_standard_time_limit(self._time_limit) + self.setup_standard_powerup_drops() + + # Base kills needed to win on the size of the largest team. + self._score_to_win = self._capsules_to_win * max( + 1, max(len(t.players) for t in self.teams) + ) + self._update_scoreboard() + + if isinstance(self.session, ba.FreeForAllSession): + self._flag_pos = self.map.get_flag_position(random.randint(0, 1)) + else: + self._flag_pos = self.map.get_flag_position(None) + + ba.timer(1.0, self._tick, repeat=True) + self._flag_state = FlagState.NEW + Flag.project_stand(self._flag_pos) + self._flag = Flag( + position=self._flag_pos, touchable=False, color=(1, 1, 1) + ) + self._flag_light = ba.newnode( + 'light', + attrs={ + 'position': self._flag_pos, + 'intensity': 0.2, + 'height_attenuated': False, + 'radius': 0.4, + 'color': (0.2, 0.2, 0.2), + }, + ) + # Flag region. + flagmats = [self._flag_region_material, shared.region_material] + ba.newnode( + 'region', + attrs={ + 'position': self._flag_pos, + 'scale': (1.8, 1.8, 1.8), + 'type': 'sphere', + 'materials': flagmats, + }, + ) + self._update_flag_state() + + def _tick(self) -> None: + self._update_flag_state() + + if self._scoring_team is None: + scoring_team = None + else: + scoring_team = self._scoring_team() + + if not scoring_team: + return + + if isinstance(self.session, ba.FreeForAllSession): + players = self.players + else: + players = scoring_team.players + + for player in players: + if player.time_at_flag > 0: + self.stats.player_scored( + player, 3, screenmessage=False, display=False + ) + if player.capsules > 0: + if self._flag_state != FlagState.HELD: + return + if scoring_team.score >= self._score_to_win: + return + + player.capsules -= 1 + scoring_team.score += 1 + self._handle_capsule_storage(( + self._flag_pos[0], + self._flag_pos[1]+1, + self._flag_pos[2] + ), player) + ba.playsound( + self._collect_sound, + 0.8, + position=self._flag_pos) + + self._update_scoreboard() + if player.capsules > 0: + assert self._flag is not None + self._flag.set_score_text( + str(self._score_to_win - scoring_team.score)) + + # winner + if scoring_team.score >= self._score_to_win: + self.end_game() + + def end_game(self) -> None: + results = ba.GameResults() + for team in self.teams: + results.set_team_score(team, team.score) + self.end(results=results, announce_delay=0) + + def _update_flag_state(self) -> None: + holding_teams = set( + player.team for player in self.players if player.time_at_flag + ) + prev_state = self._flag_state + assert self._flag_light + assert self._flag is not None + assert self._flag.node + if len(holding_teams) > 1: + self._flag_state = FlagState.CONTESTED + self._scoring_team = None + self._flag_light.color = (0.6, 0.6, 0.1) + self._flag.node.color = (1.0, 1.0, 0.4) + elif len(holding_teams) == 1: + holding_team = list(holding_teams)[0] + self._flag_state = FlagState.HELD + self._scoring_team = weakref.ref(holding_team) + self._flag_light.color = ba.normalized_color(holding_team.color) + self._flag.node.color = holding_team.color + else: + self._flag_state = FlagState.UNCONTESTED + self._scoring_team = None + self._flag_light.color = (0.2, 0.2, 0.2) + self._flag.node.color = (1, 1, 1) + if self._flag_state != prev_state: + ba.playsound(self._swipsound) + + def _handle_player_flag_region_collide(self, colliding: bool) -> None: + try: + spaz = ba.getcollision().opposingnode.getdelegate(PlayerSpaz, True) + except ba.NotFoundError: + return + + if not spaz.is_alive(): + return + + player = spaz.getplayer(Player, True) + + # Different parts of us can collide so a single value isn't enough + # also don't count it if we're dead (flying heads shouldn't be able to + # win the game :-) + if colliding and player.is_alive(): + player.time_at_flag += 1 + else: + player.time_at_flag = max(0, player.time_at_flag - 1) + + self._update_flag_state() + + def _update_scoreboard(self) -> None: + for team in self.teams: + self._scoreboard.set_team_value( + team, team.score, self._score_to_win + ) + + def _drop_capsule(self, player: Player) -> None: + pt = player.node.position + + # Throw out capsules that the victim has + 2 more to keep the game running + for i in range(player.capsules + self._capsules_death): + # How far from each other these capsules should spawn + w = 0.6 + # How much these capsules should fly after spawning + s = 0.005 - (player.capsules * 0.01) + self._capsules.append( + Capsule( + position=(pt[0] + random.uniform(-w, w), + pt[1] + 0.75 + random.uniform(-w, w), + pt[2]), + velocity=(random.uniform(-s, s), + random.uniform(-s, s), + random.uniform(-s, s)), + lucky=False)) + if random.randint(1, 12) == 1 and self._lucky_capsules: + # How far from each other these capsules should spawn + w = 0.6 + # How much these capsules should fly after spawning + s = 0.005 + self._capsules.append( + Capsule( + position=(pt[0] + random.uniform(-w, w), + pt[1] + 0.75 + random.uniform(-w, w), + pt[2]), + velocity=(random.uniform(-s, s), + random.uniform(-s, s), + random.uniform(-s, s)), + lucky=True)) + + def _on_capsule_player_collide(self) -> None: + if self.has_ended(): + return + collision = ba.getcollision() + + # Be defensive here; we could be hitting the corpse of a player + # who just left/etc. + try: + capsule = collision.sourcenode.getdelegate(Capsule, True) + player = collision.opposingnode.getdelegate( + PlayerSpaz, True + ).getplayer(Player, True) + except ba.NotFoundError: + return + + if not player.is_alive(): + return + + if capsule.node.color_texture == self._capsule_lucky_tex: + player.capsules += 4 + PopupText( + bonus, + color=(1, 1, 0), + scale=1.5, + position=capsule.node.position + ).autoretain() + ba.playsound( + self._lucky_collect_sound, + 1.0, + position=capsule.node.position) + ba.emitfx( + position=capsule.node.position, + velocity=(0, 0, 0), + count=int(6.4+random.random()*24), + scale=1.2, + spread=2.0, + chunk_type='spark'); + ba.emitfx( + position=capsule.node.position, + velocity=(0, 0, 0), + count=int(4.0+random.random()*6), + emit_type='tendrils'); + else: + player.capsules += 1 + ba.playsound( + self._collect_sound, + 0.6, + position=capsule.node.position) + # create a flash + light = ba.newnode( + 'light', + attrs={ + 'position': capsule.node.position, + 'height_attenuated': False, + 'radius': 0.1, + 'color': (1, 1, 0)}) + + # Create a short text informing about your inventory + self._handle_capsule_storage(player.position, player) + + ba.animate(light, 'intensity', { + 0: 0, + 0.1: 0.5, + 0.2: 0 + }, loop=False) + ba.timer(0.2, light.delete) + capsule.handlemessage(ba.DieMessage()) + + def _update_player_light(self, player: Player, capsules: int) -> None: + if player.light: + intensity = 0.04 * capsules + ba.animate(player.light, 'intensity', { + 0.0: player.light.intensity, + 0.1: intensity + }) + def newintensity(): + player.light.intensity = intensity + ba.timer(0.1, newintensity) + else: + player.light = ba.newnode( + 'light', + attrs={ + 'height_attenuated': False, + 'radius': 0.2, + 'intensity': 0.0, + 'color': (0.2, 1, 0.2) + }) + player.node.connectattr('position', player.light, 'position') + + def _handle_capsule_storage(self, pos: float, player: Player) -> None: + capsules = player.capsules + text = str(capsules) + scale = 1.75 + (0.02 * capsules) + if capsules > 10: + player.capsules = 10 + text = full_capacity + color = (1, 0.85, 0) + elif capsules > 7: + color = (1, 0, 0) + scale = 2.4 + elif capsules > 5: + color = (1, 0.4, 0.4) + scale = 2.1 + elif capsules > 3: + color = (1, 1, 0.4) + scale = 2.0 + else: + color = (1, 1, 1) + scale = 1.9 + PopupText( + text, + color=color, + scale=scale, + position=(pos[0], pos[1]-1, pos[2]) + ).autoretain() + self._update_player_light(player, capsules) + + def handlemessage(self, msg: Any) -> Any: + if isinstance(msg, ba.PlayerDiedMessage): + super().handlemessage(msg) # Augment default. + # No longer can count as time_at_flag once dead. + player = msg.getplayer(Player) + player.time_at_flag = 0 + self._update_flag_state() + self._drop_capsule(player) + player.capsules = 0 + self._update_player_light(player, 0) + self.respawn_player(player) + else: + return super().handlemessage(msg) + + +class Capsule(ba.Actor): + + def __init__(self, + position: Sequence[float] = (0.0, 1.0, 0.0), + velocity: Sequence[float] = (0.0, 0.5, 0.0), + lucky: bool = False): + super().__init__() + shared = SharedObjects.get() + activity = self.getactivity() + + # spawn just above the provided point + self._spawn_pos = (position[0], position[1], position[2]) + + if lucky: + ba.playsound(activity._lucky_sound, 1.0, self._spawn_pos) + + self.node = ba.newnode( + 'prop', + attrs={ + 'model': activity._capsule_model, + 'color_texture': activity._capsule_lucky_tex if lucky else ( + activity._capsule_tex), + 'body': 'crate' if lucky else 'capsule', + 'reflection': 'powerup' if lucky else 'soft', + 'body_scale': 0.65 if lucky else 0.3, + 'density':6.0 if lucky else 4.0, + 'reflection_scale': [0.15], + 'shadow_size': 0.65 if lucky else 0.6, + 'position': self._spawn_pos, + 'velocity': velocity, + 'materials': [ + shared.object_material, activity._capsule_material] + }, + delegate=self) + ba.animate(self.node, 'model_scale', { + 0.0: 0.0, + 0.1: 0.9 if lucky else 0.6, + 0.16: 0.8 if lucky else 0.5 + }) + self._light_capsule = ba.newnode( + 'light', + attrs={ + 'position': self._spawn_pos, + 'height_attenuated': False, + 'radius': 0.5 if lucky else 0.1, + 'color': (0.2, 0.2, 0) if lucky else (0.2, 1, 0.2) + }) + self.node.connectattr('position', self._light_capsule, 'position') + + def handlemessage(self, msg: Any): + if isinstance(msg, ba.DieMessage): + self.node.delete() + ba.animate(self._light_capsule, 'intensity', { + 0: 1.0, + 0.05: 0.0 + }, loop=False) + ba.timer(0.05, self._light_capsule.delete) + elif isinstance(msg, ba.OutOfBoundsMessage): + self.handlemessage(ba.DieMessage()) + elif isinstance(msg, ba.HitMessage): + self.node.handlemessage( + 'impulse', + msg.pos[0], msg.pos[1], msg.pos[2], + msg.velocity[0]/8, msg.velocity[1]/8, msg.velocity[2]/8, + 1.0*msg.magnitude, 1.0*msg.velocity_magnitude, msg.radius, 0, + msg.force_direction[0], msg.force_direction[1], + msg.force_direction[2]) + else: + return super().handlemessage(msg) diff --git a/plugins/minigames/dodge_the_ball.py b/plugins/minigames/dodge_the_ball.py new file mode 100644 index 00000000..d5b1770a --- /dev/null +++ b/plugins/minigames/dodge_the_ball.py @@ -0,0 +1,762 @@ +""" + + DondgeTheBall minigame by EmperoR#4098 + +""" + +# Feel free to edit. + +# ba_meta require api 7 +from __future__ import annotations +from typing import TYPE_CHECKING + +import ba +from random import choice +from enum import Enum +from bastd.actor.bomb import Blast +from bastd.actor.popuptext import PopupText +from bastd.actor.powerupbox import PowerupBox +from bastd.actor.onscreencountdown import OnScreenCountdown +from bastd.gameutils import SharedObjects + +if TYPE_CHECKING: + from typing import NoReturn, Sequence, Any + + +# Type of ball in this game +class BallType(Enum): + """ Types of ball """ + EASY = 0 + # Decrease the next ball shooting speed(not ball speed). + # Ball color is yellow. + MEDIUM = 1 + # increase the next ball shooting speed(not ball speed). + # target the head of player. + # Ball color is purple. + HARD = 2 + # Target player according to player movement (not very accurate). + # Taget: player head. + # increase the next ball speed but less than MEDIUM. + # Ball color is crimson(purple+red = pinky color type). + +# this dict decide the ball_type spawning rate like powerup box +ball_type_dict: dict[BallType, int] = { + BallType.EASY: 3, + BallType.MEDIUM: 2, + BallType.HARD: 1, +}; + +class Ball(ba.Actor): + """ Shooting Ball """ + def __init__(self, + position: Sequence[float], + velocity: Sequence[float], + texture: ba.Texture, + body_scale: float = 1.0, + gravity_scale: float = 1.0, + ) -> NoReturn: + + super().__init__(); + + shared = SharedObjects.get(); + + ball_material = ba.Material(); + ball_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), + ); + + self.node = ba.newnode( + 'prop', + delegate=self, + attrs={ + 'body': 'sphere', + 'position': position, + 'velocity': velocity, + 'body_scale': body_scale, + 'model': ba.getmodel('frostyPelvis'), + 'model_scale': body_scale, + 'color_texture': texture, + 'gravity_scale': gravity_scale, + 'density': 4.0, # increase density of ball so ball collide with player with heavy force. # ammm very bad grammer + 'materials': (ball_material,), + }, + ); + + # die the ball manually incase the ball doesn't fall the outside of the map + ba.timer(2.5, ba.WeakCall(self.handlemessage, ba.DieMessage())); + + # i am not handling anything in this ball Class(except for diemessage). + # all game things and logics going to be in the box class + def handlemessage(self, msg: Any) -> Any: + + if isinstance(msg, ba.DieMessage): + self.node.delete(); + else: + super().handlemessage(msg); + + +class Box(ba.Actor): + """ A box that spawn midle of map as a decoration perpose """ + + def __init__(self, + position: Sequence[float], + velocity: Sequence[float], + ) -> NoReturn: + + super().__init__(); + + shared = SharedObjects.get(); + # self.ball_jump = 0.0; + no_hit_material = ba.Material(); + # we don't need that the box was move and collide with objects. + no_hit_material.add_actions( + conditions=( + ('they_have_material', shared.pickup_material), + 'or', + ('they_have_material', shared.attack_material), + ), + actions=('modify_part_collision', 'collide', False), + ); + + no_hit_material.add_actions( + conditions=( + ('they_have_material', shared.object_material), + 'or', + ('they_dont_have_material', shared.footing_material), + ), + actions=( + ('modify_part_collision', 'collide', False), + ('modify_part_collision', 'physical', False), + ), + ); + + self.node = ba.newnode( + 'prop', + delegate=self, + attrs={ + 'body': 'box', + 'position': position, + 'model': ba.getmodel('powerup'), + 'light_model': ba.getmodel('powerupSimple'), + 'shadow_size': 0.5, + 'body_scale': 1.4, + 'model_scale': 1.4, + 'color_texture': ba.gettexture('landMineLit'), + 'reflection': 'powerup', + 'reflection_scale': [1.0], + 'materials': (no_hit_material,), + }, + ); + # light + self.light = ba.newnode( + "light", + owner = self.node, + attrs={ + 'radius' : 0.2, + 'intensity' : 0.8, + 'color': (0.0, 1.0, 0.0), + } + ); + self.node.connectattr("position", self.light, "position"); + # Drawing circle and circleOutline in radius of 3, + # so player can see that how close he is to the box. + # If player is inside this circle the ball speed will increase. + circle = ba.newnode( + "locator", + owner = self.node, + attrs = { + 'shape': 'circle', + 'color': (1.0, 0.0, 0.0), + 'opacity': 0.1, + 'size': (6.0, 0.0, 6.0), + 'draw_beauty': False, + 'additive': True, + }, + ) + self.node.connectattr("position", circle, "position"); + # also adding a outline cause its look nice. + circle_outline = ba.newnode( + "locator", + owner = self.node, + attrs = { + 'shape': 'circleOutline', + 'color': (1.0, 1.0, 0.0), + 'opacity': 0.1, + 'size': (6.0, 0.0, 6.0), + 'draw_beauty': False, + 'additive': True, + }, + ); + self.node.connectattr("position", circle_outline, "position"); + + # all ball attribute that we need. + self.ball_type: BallType = BallType.EASY; + self.shoot_timer: ba.Timer | None = None; + self.shoot_speed: float = 0.0; + # this force the shoot if player is inside the red circle. + self.force_shoot_speed: float = 0.0; + self.ball_mag = 3000; + self.ball_gravity: float = 1.0; + self.ball_tex: ba.Texture | None = None; + # only for Hard ball_type + self.player_facing_direction: list[float, float] = [0.0, 0.0]; + # ball shoot soound. + self.shoot_sound = ba.getsound('laserReverse'); + + # same as "powerupdist" + self.ball_type_dist: list[BallType] = []; + + for ball in ball_type_dict: + for _ in range(ball_type_dict[ball]): + self.ball_type_dist.append(ball); + + # Here main logic of game goes here. + # like shoot balls, shoot speed, anything we want goes here(except for some thing). + def start_shoot(self) -> NoReturn: + + # getting all allive players in a list. + alive_players_list = self.activity.get_alive_players(); + + # make sure that list is not Empty. + if len(alive_players_list) > 0: + + # choosing a random player from list. + target_player = choice(alive_players_list); + # highlight the target player + self.highlight_target_player(target_player); + + # to finding difference between player and box. + # we just need to subtract player pos and ball pos. + # Same logic as eric applied in Target Practice Gamemode. + difference = ba.Vec3(target_player.position) - ba.Vec3(self.node.position); + + # discard Y position so ball shoot more straight. + difference[1] = 0.0 + + # and now, this length method returns distance in float. + # we're gonna use this value for calculating player analog stick + distance = difference.length(); + + # shoot a random BallType + self.upgrade_ball_type(choice(self.ball_type_dist)); + + # and check the ball_type and upgrade it gravity_scale, texture, next ball speed. + self.check_ball_type(self.ball_type); + + # For HARD ball i am just focusing on player analog stick facing direction. + # Not very accurate and that's we need. + if self.ball_type == BallType.HARD: + self.calculate_player_analog_stick(target_player, distance); + else: + self.player_facing_direction = [0.0, 0.0]; + + pos = self.node.position; + + if self.ball_type == BallType.MEDIUM or self.ball_type == BallType.HARD: + # Target head by increasing Y pos. + # How this work? cause ball gravity_scale is ...... + pos = (pos[0], pos[1]+.25, pos[2]); + + # ball is generating.. + ball = Ball( + position = pos, + velocity = (0.0, 0.0, 0.0), + texture = self.ball_tex, + gravity_scale = self.ball_gravity, + body_scale = 1.0, + ).autoretain(); + + # shoot Animation and sound. + self.shoot_animation(); + + # force the shoot speed if player try to go inside the red circle. + if self.force_shoot_speed != 0.0: + self.shoot_speed = self.force_shoot_speed; + + # push the ball to the player + ball.node.handlemessage( + 'impulse', + self.node.position[0], # ball spawn position X + self.node.position[1], # Y + self.node.position[2], # Z + 0, 0, 0, # velocity x,y,z + self.ball_mag, # magnetude + 0.000, # magnetude velocity + 0.000, # radius + 0.000, # idk + difference[0] + self.player_facing_direction[0], # force direction X + difference[1] , # force direction Y + difference[2] + self.player_facing_direction[1], # force direction Z + ); + # creating our timer and shoot the ball again.(and we create a loop) + self.shoot_timer = ba.Timer(self.shoot_speed, self.start_shoot); + + def upgrade_ball_type(self, ball_type: BallType) -> NoReturn: + + self.ball_type = ball_type; + + def check_ball_type(self, ball_type: BallType) -> NoReturn: + + if ball_type == BallType.EASY: + self.shoot_speed = 0.8; + self.ball_gravity = 1.0; + # next ball shoot speed + self.ball_mag = 3000; + # box light color and ball tex + self.light.color = (1.0, 1.0, 0.0); + self.ball_tex = ba.gettexture('egg4'); + elif ball_type == BallType.MEDIUM: + self.ball_mag = 3000; + # decrease the gravity scale so, ball shoot without falling and straight. + self.ball_gravity = 0.0; + # next ball shoot speed. + self.shoot_speed = 0.4; + # box light color and ball tex. + self.light.color = (1.0, 0.0, 1.0); + self.ball_tex = ba.gettexture('egg3'); + elif ball_type == BallType.HARD: + self.ball_mag = 2500; + self.ball_gravity = 0.0; + # next ball shoot speed. + self.shoot_speed = 0.6; + # box light color and ball tex. + self.light.color = (1.0, 0.2, 1.0); + self.ball_tex = ba.gettexture('egg1'); + + def shoot_animation(self) -> NoReturn: + + ba.animate( + self.node, + "model_scale",{ + 0.00: 1.4, + 0.05: 1.7, + 0.10: 1.4, + } + ); + # playing shoot sound. + ba.playsound(self.shoot_sound, position = self.node.position); + + def highlight_target_player(self, player: ba.Player) -> NoReturn: + + # adding light + light = ba.newnode( + "light", + owner = self.node, + attrs={ + 'radius':0.0, + 'intensity':1.0, + 'color': (1.0, 0.0, 0.0), + } + ); + ba.animate( + light, + "radius",{ + 0.05: 0.02, + 0.10: 0.07, + 0.15: 0.15, + 0.20: 0.13, + 0.25: 0.10, + 0.30: 0.05, + 0.35: 0.02, + 0.40: 0.00, + } + ); + # And a circle outline with ugly animation. + circle_outline = ba.newnode( + "locator", + owner = player.actor.node, + attrs={ + 'shape': 'circleOutline', + 'color': (1.0, 0.0, 0.0), + 'opacity': 1.0, + 'draw_beauty': False, + 'additive': True, + }, + ); + ba.animate_array( + circle_outline, + 'size', + 1, { + 0.05: [0.5], + 0.10: [0.8], + 0.15: [1.5], + 0.20: [2.0], + 0.25: [1.8], + 0.30: [1.3], + 0.35: [0.6], + 0.40: [0.0], + } + ); + + # coonect it and... + player.actor.node.connectattr("position", light, "position"); + player.actor.node.connectattr("position", circle_outline, "position"); + + # immediately delete the node after another player has been targeted. + self.shoot_speed = 0.5 if self.shoot_speed == 0.0 else self.shoot_speed; + ba.timer(self.shoot_speed, light.delete); + ba.timer(self.shoot_speed, circle_outline.delete); + + def calculate_player_analog_stick(self, player:ba.Player, distance: float) -> NoReturn: + # at first i was very confused how i can read the player analog stick \ + # then i saw TheMikirog#1984 autorun plugin code. + # and i got it how analog stick values are works. + # just need to store analog stick facing direction and need some calculation according how far player pushed analog stick. + # Notice that how vertical direction is inverted, so we need to put a minus infront of veriable.(so ball isn't shoot at wrong direction). + self.player_facing_direction[0] = player.actor.node.move_left_right; + self.player_facing_direction[1] = -player.actor.node.move_up_down; + + # if player is too close and the player pushing his analog stick fully the ball shoot's too far away to player. + # so, we need to reduce the value of "self.player_facing_direction" to fix this problem. + if distance <= 3: + self.player_facing_direction[0] = 0.4 if self.player_facing_direction[0] > 0 else -0.4; + self.player_facing_direction[1] = 0.4 if self.player_facing_direction[0] > 0 else -0.4; + # same problem to long distance but in reverse, the ball can't reach to the player, + # its because player analog stick value is between 1 and -1, + # and this value is low to shoot ball forward to Player if player is too far from the box. + # so. let's increase to 1.5 if player pushed analog stick fully. + elif distance > 6.5: + # So many calculation according to how analog stick pushed by player. + # Horizontal(left-right) calculation + if self.player_facing_direction[0] > 0.4: + self.player_facing_direction[0] = 1.5; + elif self.player_facing_direction[0] < -0.4: + self.player_facing_direction[0] = -1.5; + else: + if self.player_facing_direction[0] > 0.0: + self.player_facing_direction[0] = 0.2; + elif self.player_facing_direction[0] < 0.0: + self.player_facing_direction[0] = -0.2; + else: + self.player_facing_direction[0] = 0.0; + + # Vertical(up-down) calculation. + if self.player_facing_direction[1] > 0.4: + self.player_facing_direction[1] = 1.5; + elif self.player_facing_direction[1] < -0.4: + self.player_facing_direction[1] = -1.5; + else: + if self.player_facing_direction[1] > 0.0: + self.player_facing_direction[1] = 0.2; + elif self.player_facing_direction[1] < 0.0: + self.player_facing_direction[1] = -0.2; + else: + self.player_facing_direction[1] = -0.0; + + # if we want stop the ball shootes + def stop_shoot(self) -> NoReturn: + # Kill the timer. + self.shoot_timer = None; + + +class Player(ba.Player['Team']): + """Our player type for this game.""" + + +class Team(ba.Team[Player]): + """Our team type for this game.""" + +# almost 80 % for game we done in box class. +# now remain things, like name, seetings, scoring, cooldonw, +# and main thing don't allow player to camp inside of box are going in this class. + +# ba_meta export game +class DodgeTheBall(ba.TeamGameActivity[Player, Team]): + + # defining name, description and settings.. + name = 'Dodge the ball'; + description = 'Survive from shooting balls'; + + available_settings = [ + ba.IntSetting( + 'Cooldown', + min_value = 20, + default = 45, + increment = 5, + ), + ba.BoolSetting('Epic Mode', default=False) + ] + + # Don't allow joining after we start. + allow_mid_activity_joins = False; + + @classmethod + def supports_session_type(cls, sessiontype: type[ba.Session]) -> bool: + # We support team and ffa sessions. + return issubclass(sessiontype, ba.FreeForAllSession) or issubclass( + sessiontype, ba.DualTeamSession, + ); + + @classmethod + def get_supported_maps(cls, sessiontype: type[ba.Session]) -> list[str]: + # This Game mode need a flat and perfect shape map where can player fall outside map. + # bombsquad have "Doom Shroom" map. + # Not perfect map for this game mode but its fine for this gamemode. + # the problem is that Doom Shroom is not a perfect circle and not flat also. + return ['Doom Shroom']; + + def __init__(self, settings: dict): + super().__init__(settings); + self._epic_mode = bool(settings['Epic Mode']); + self.countdown_time = int(settings['Cooldown']); + + self.check_player_pos_timer: ba.Timer | None = None; + self.shield_drop_timer: ba.Timer | None = None; + # cooldown and Box + self._countdown: OnScreenCountdown | None = None; + self.box: Box | None = None; + + # this lists for scoring. + self.joined_player_list: list[ba.Player] = []; + self.dead_player_list: list[ba.Player] = []; + + # normally play RUN AWAY music cause is match with our gamemode at.. my point, + # but in epic switch to EPIC. + self.slow_motion = self._epic_mode; + self.default_music = ( + ba.MusicType.EPIC if self._epic_mode else ba.MusicType.RUN_AWAY + ); + + def get_instance_description(self) -> str | Sequence: + return 'Keep away as possible as you can'; + + # add a tiny text under our game name. + def get_instance_description_short(self) -> str | Sequence: + return 'Dodge the shooting balls'; + + def on_begin(self) -> NoReturn: + super().on_begin(); + + # spawn our box at middle of the map + self.box = Box( + position=(0.5, 2.7, -3.9), + velocity=(0.0, 0.0, 0.0), + ).autoretain(); + + # create our cooldown + self._countdown = OnScreenCountdown( + duration = self.countdown_time, + endcall = self.play_victory_sound_and_end, + ); + + # and starts the cooldown and shootes. + ba.timer(5.0, self._countdown.start); + ba.timer(5.0, self.box.start_shoot); + + # start checking all player pos. + ba.timer(5.0, self.check_player_pos); + + # drop shield every ten Seconds + # need five seconds delay Because shootes start after 5 seconds. + ba.timer(15.0, self.drop_shield); + + # This function returns all alive players in game. + # i thinck you see this function in Box class. + def get_alive_players(self) -> Sequence[ba.Player]: + + alive_players = []; + + for team in self.teams: + for player in team.players: + if player.is_alive(): + alive_players.append(player); + + return alive_players; + + # let's disallowed camping inside of box by doing a blast and increasing ball shoot speed. + def check_player_pos(self): + + for player in self.get_alive_players(): + + # same logic as applied for the ball + difference = ba.Vec3(player.position) - ba.Vec3(self.box.node.position); + + distance = difference.length(); + + if distance < 3: + self.box.force_shoot_speed = 0.2; + else: + self.box.force_shoot_speed = 0.0; + + if distance < 0.5: + Blast( + position = self.box.node.position, + velocity = self.box.node.velocity, + blast_type = 'normal', + blast_radius = 1.0, + ).autoretain(); + + PopupText( + position = self.box.node.position, + text = 'Keep away from me', + random_offset = 0.0, + scale = 2.0, + color = self.box.light.color, + ).autoretain(); + + # create our timer and start looping it + self.check_player_pos_timer = ba.Timer(0.1, self.check_player_pos); + + # drop useless shield's too give player temptation. + def drop_shield(self) -> NoReturn: + + pos = self.box.node.position; + + PowerupBox( + position = (pos[0] + 4.0, pos[1] + 3.0, pos[2]), + poweruptype = 'shield', + ).autoretain(); + + PowerupBox( + position = (pos[0] - 4.0, pos[1] + 3.0, pos[2]), + poweruptype = 'shield', + ).autoretain(); + + self.shield_drop_timer = ba.Timer(10.0, self.drop_shield); + + # when cooldown time up i don't want that the game end immediately. + def play_victory_sound_and_end(self) -> NoReturn: + + # kill timers + self.box.stop_shoot(); + self.check_player_pos_timer = None + self.shield_drop_timer = None + + ba.timer(2.0, self.end_game); + + # this function runs when A player spawn in map + def spawn_player(self, player: Player) -> NoReturn: + spaz = self.spawn_player_spaz(player); + + # reconnect this player's controls. + # without bomb, punch and pickup. + spaz.connect_controls_to_player( + enable_punch=False, enable_bomb=False, enable_pickup=False, + ); + + # storing all players for ScorinG. + self.joined_player_list.append(player); + + # Also lets have them make some noise when they die. + spaz.play_big_death_sound = True; + + # very helpful function to check end game when player dead or leav. + def _check_end_game(self) -> bool: + + living_team_count = 0 + for team in self.teams: + for player in team.players: + if player.is_alive(): + living_team_count += 1 + break + + if living_team_count <= 0: + # kill the coutdown timer incase the all players dead before game is about to going to be end. + # so, countdown won't call the function. + # FIXE ME: it's that ok to kill this timer? + # self._countdown._timer = None; + self.end_game() + + # this function called when player leave. + def on_player_leave(self, player: Player) -> NoReturn: + # Augment default behavior. + super().on_player_leave(player); + + # checking end game. + self._check_end_game(); + + # this gamemode needs to handle only one msg "PlayerDiedMessage". + def handlemessage(self, msg: Any) -> Any: + + if isinstance(msg, ba.PlayerDiedMessage): + + # Augment standard behavior. + super().handlemessage(msg); + + # and storing the dead player records in our dead_player_list. + self.dead_player_list.append(msg.getplayer(Player)); + + # check the end game. + ba.timer(1.0, self._check_end_game); + + def end_game(self): + # kill timers + self.box.stop_shoot() + self.check_player_pos_timer = None + self.shield_drop_timer = None + + # here the player_dead_list and joined_player_list gonna be very helpful. + for team in self.teams: + for player in team.players: + + # for scoring i am just following the index of the player_dead_list. + # for dead list... + # 0th index player dead first. + # 1st index player dead second. + # and so on... + # i think you got it... maybe + # sometime we also got a empty list + # if we got a empty list that means all players are survived or maybe only one player playing and he/she survived. + if len(self.dead_player_list) > 0: + + for index, dead_player in enumerate(self.dead_player_list): + # if this condition is true we find the dead player \ + # and his index with enumerate function. + if player == dead_player: + # updating with one, because i don't want to give 0 score to first dead player. + index += 1 + break + # and if this statement is true we just find a survived player. + # for survived player i am giving the highest score according to how many players are joined. + elif index == len(self.dead_player_list) - 1: + index = len(self.joined_player_list) + # for survived player i am giving the highest score according to how many players are joined. + else: + index = len(self.joined_player_list) + + # and here i am following Table of 10 for scoring. + # very lazY. + score = int(10 * index) + + self.stats.player_scored(player, score, screenmessage=False) + + # Ok now calc game results: set a score for each team and then tell \ + # the game to end. + results = ba.GameResults() + + # Remember that 'free-for-all' mode is simply a special form \ + # of 'teams' mode where each player gets their own team, so we can \ + # just always deal in teams and have all cases covered. + # hmmm... some eric comments might be helpful to you. + for team in self.teams: + + max_index = 0 + for player in team.players: + # for the team, we choose only one player who survived longest. + # same logic.. + if len(self.dead_player_list) > 0: + for index, dead_player in enumerate(self.dead_player_list): + if player == dead_player: + index += 1 + break + elif index == len(self.dead_player_list) - 1: + index = len(self.joined_player_list) + else: + index = len(self.joined_player_list) + + max_index = max(max_index, index) + # set the team score + results.set_team_score(team, int(10 * max_index)) + # and end the game + self.end(results=results) + + \ No newline at end of file diff --git a/plugins/minigames/invisible_one.py b/plugins/minigames/invisible_one.py new file mode 100644 index 00000000..211a163e --- /dev/null +++ b/plugins/minigames/invisible_one.py @@ -0,0 +1,333 @@ +# Released under the MIT License. See LICENSE for details. +# +# By itsre3 +# =>3<= +# Don't mind my spelling. i realized that they were not correct after making last change and saving +# Besides that, enjoy.......!! +"""Provides the chosen-one mini-game.""" + +# ba_meta require api 7 +# (see https://ballistica.net/wiki/meta-tag-system) + +from __future__ import annotations + +from typing import TYPE_CHECKING + +import ba +from bastd.actor.flag import Flag +from bastd.actor.playerspaz import PlayerSpaz +from bastd.actor.scoreboard import Scoreboard +from bastd.gameutils import SharedObjects + +if TYPE_CHECKING: + from typing import Any, Type, List, Dict, Optional, Sequence, Union + + +class Player(ba.Player['Team']): + """Our player type for this game.""" + + def __init__(self) -> None: + self.chosen_light: Optional[ba.NodeActor] = None + + +class Team(ba.Team[Player]): + """Our team type for this game.""" + + def __init__(self, time_remaining: int) -> None: + self.time_remaining = time_remaining + + +# ba_meta export game +class InvicibleOneGame(ba.TeamGameActivity[Player, Team]): + """ + Game involving trying to remain the one 'invisible one' + for a set length of time while everyone else tries to + kill you and become the invisible one themselves. + """ + + name = 'Invisible One' + description = ('Be the invisible one for a length of time to win.\n' + 'Kill the invisible one to become it.') + available_settings = [ + ba.IntSetting( + 'Invicible One Time', + min_value=10, + default=30, + increment=10, + ), + ba.BoolSetting('Invicible one is lazy', default=True), + ba.BoolSetting('Night mode', default=False), + 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', 4.0), + ], + default=1.0, + ), + ba.BoolSetting('Epic Mode', default=False), + ] + scoreconfig = ba.ScoreConfig(label='Time Held') + + @classmethod + def get_supported_maps(cls, sessiontype: Type[ba.Session]) -> List[str]: + return ba.getmaps('keep_away') + + def __init__(self, settings: dict): + super().__init__(settings) + self._scoreboard = Scoreboard() + self._invicible_one_player: Optional[Player] = None + self._swipsound = ba.getsound('swip') + self._countdownsounds: Dict[int, ba.Sound] = { + 10: ba.getsound('announceTen'), + 9: ba.getsound('announceNine'), + 8: ba.getsound('announceEight'), + 7: ba.getsound('announceSeven'), + 6: ba.getsound('announceSix'), + 5: ba.getsound('announceFive'), + 4: ba.getsound('announceFour'), + 3: ba.getsound('announceThree'), + 2: ba.getsound('announceTwo'), + 1: ba.getsound('announceOne') + } + self._flag_spawn_pos: Optional[Sequence[float]] = None + self._reset_region_material: Optional[ba.Material] = None + self._flag: Optional[Flag] = None + self._reset_region: Optional[ba.Node] = None + self._epic_mode = bool(settings['Epic Mode']) + self._invicible_one_time = int(settings['Invicible One Time']) + self._time_limit = float(settings['Time Limit']) + self._invicible_one_is_lazy = bool(settings['Invicible one is lazy']) + self._night_mode = bool(settings['Night mode']) + + # Base class overrides + self.slow_motion = self._epic_mode + self.default_music = (ba.MusicType.EPIC + if self._epic_mode else ba.MusicType.CHOSEN_ONE) + + def get_instance_description(self) -> Union[str, Sequence]: + return 'Show your invisibility powers.' + + def create_team(self, sessionteam: ba.SessionTeam) -> Team: + return Team(time_remaining=self._invicible_one_time) + + def on_team_join(self, team: Team) -> None: + self._update_scoreboard() + + def on_player_leave(self, player: Player) -> None: + super().on_player_leave(player) + if self._get_invicible_one_player() is player: + self._set_invicible_one_player(None) + + def on_begin(self) -> None: + super().on_begin() + shared = SharedObjects.get() + self.setup_standard_time_limit(self._time_limit) + self.setup_standard_powerup_drops() + self._flag_spawn_pos = self.map.get_flag_position(None) + Flag.project_stand(self._flag_spawn_pos) + self._set_invicible_one_player(None) + if self._night_mode: + gnode = ba.getactivity().globalsnode + gnode.tint = (0.4, 0.4, 0.4) + + pos = self._flag_spawn_pos + ba.timer(1.0, call=self._tick, repeat=True) + + mat = self._reset_region_material = ba.Material() + mat.add_actions( + conditions=( + 'they_have_material', + shared.player_material, + ), + actions=( + ('modify_part_collision', 'collide', True), + ('modify_part_collision', 'physical', False), + ('call', 'at_connect', + ba.WeakCall(self._handle_reset_collide)), + ), + ) + + self._reset_region = ba.newnode('region', + attrs={ + 'position': (pos[0], pos[1] + 0.75, + pos[2]), + 'scale': (0.5, 0.5, 0.5), + 'type': 'sphere', + 'materials': [mat] + }) + + def _get_invicible_one_player(self) -> Optional[Player]: + # Should never return invalid references; return None in that case. + if self._invicible_one_player: + return self._invicible_one_player + return None + + def _handle_reset_collide(self) -> None: + # If we have a chosen one, ignore these. + if self._get_invicible_one_player() is not None: + return + + # Attempt to get a Player controlling a Spaz that we hit. + try: + player = ba.getcollision().opposingnode.getdelegate( + PlayerSpaz, True).getplayer(Player, True) + except ba.NotFoundError: + return + + if player.is_alive(): + self._set_invicible_one_player(player) + + def _flash_flag_spawn(self) -> None: + light = ba.newnode('light', + attrs={ + 'position': self._flag_spawn_pos, + 'color': (1, 1, 1), + 'radius': 0.3, + 'height_attenuated': False + }) + ba.animate(light, 'intensity', {0: 0, 0.25: 0.5, 0.5: 0}, loop=True) + ba.timer(1.0, light.delete) + + def _tick(self) -> None: + + # Give the chosen one points. + player = self._get_invicible_one_player() + if player is not None: + + # This shouldn't happen, but just in case. + if not player.is_alive(): + ba.print_error('got dead player as chosen one in _tick') + self._set_invicible_one_player(None) + else: + scoring_team = player.team + assert self.stats + self.stats.player_scored(player, + 3, + screenmessage=False, + display=False) + + scoring_team.time_remaining = max( + 0, scoring_team.time_remaining - 1) + + + self._update_scoreboard() + + # announce numbers we have sounds for + if scoring_team.time_remaining in self._countdownsounds: + ba.playsound( + self._countdownsounds[scoring_team.time_remaining]) + + # Winner! + if scoring_team.time_remaining <= 0: + self.end_game() + + else: + # (player is None) + # This shouldn't happen, but just in case. + # (Chosen-one player ceasing to exist should + # trigger on_player_leave which resets chosen-one) + if self._invicible_one_player is not None: + ba.print_error('got nonexistent player as chosen one in _tick') + self._set_invicible_one_player(None) + + def end_game(self) -> None: + results = ba.GameResults() + for team in self.teams: + results.set_team_score(team, + self._invicible_one_time - team.time_remaining) + self.end(results=results, announce_delay=0) + + def _set_invicible_one_player(self, player: Optional[Player]) -> None: + existing = self._get_invicible_one_player() + if existing: + existing.chosen_light = None + ba.playsound(self._swipsound) + if not player: + assert self._flag_spawn_pos is not None + self._flag = Flag(color=(1, 0.9, 0.2), + position=self._flag_spawn_pos, + touchable=False) + self._invicible_one_player = None + + # Create a light to highlight the flag; + # this will go away when the flag dies. + ba.newnode('light', + owner=self._flag.node, + attrs={ + 'position': self._flag_spawn_pos, + 'intensity': 0.6, + 'height_attenuated': False, + 'volume_intensity_scale': 0.1, + 'radius': 0.1, + 'color': (1.2, 1.2, 0.4) + }) + + # Also an extra momentary flash. + self._flash_flag_spawn() + else: + if player.actor: + self._flag = None + self._invicible_one_player = player + + if self._invicible_one_is_lazy: + player.actor.connect_controls_to_player(enable_punch = False, enable_pickup = False, enable_bomb = False) + if player.actor.node.torso_model != None: + player.actor.node.color_mask_texture = None + player.actor.node.color_texture = None + player.actor.node.head_model = None + player.actor.node.torso_model = None + player.actor.node.upper_arm_model = None + player.actor.node.forearm_model = None + player.actor.node.pelvis_model = None + player.actor.node.toes_model = None + player.actor.node.upper_leg_model = None + player.actor.node.lower_leg_model = None + player.actor.node.hand_model = None + player.actor.node.style = 'cyborg' + invi_sound = [] + player.actor.node.jump_sounds = invi_sound + player.actor.attack_sounds = invi_sound + player.actor.impact_sounds = invi_sound + player.actor.pickup_sounds = invi_sound + player.actor.death_sounds = invi_sound + player.actor.fall_sounds = invi_sound + + player.actor.node.name = '' + + + def handlemessage(self, msg: Any) -> Any: + if isinstance(msg, ba.PlayerDiedMessage): + # Augment standard behavior. + super().handlemessage(msg) + player = msg.getplayer(Player) + if player is self._get_invicible_one_player(): + killerplayer = msg.getkillerplayer(Player) + self._set_invicible_one_player(None if ( + killerplayer is None or killerplayer is player + or not killerplayer.is_alive()) else killerplayer) + self.respawn_player(player) + else: + super().handlemessage(msg) + + def _update_scoreboard(self) -> None: + for team in self.teams: + self._scoreboard.set_team_value(team, + team.time_remaining, + self._invicible_one_time, + countdown=True) diff --git a/plugins/minigames/last_punch_stand.py b/plugins/minigames/last_punch_stand.py new file mode 100644 index 00000000..878fea97 --- /dev/null +++ b/plugins/minigames/last_punch_stand.py @@ -0,0 +1,263 @@ +# ba_meta require api 7 +from typing import Sequence +import ba, _ba, random +from bastd.actor.spaz import Spaz +from bastd.actor.scoreboard import Scoreboard + +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: + super().__init__() + self.score = 1 + +class ChooseingSpazHitMessage: + def __init__(self, hitter:Player) -> None: + self.hitter = hitter + +class ChooseingSpazDieMessage: + def __init__(self, killer:Player) -> None: + self.killer = killer + +class ChooseingSpaz(Spaz): + def __init__( + self, + pos:Sequence[float], + color: Sequence[float] = (1.0, 1.0, 1.0), + highlight: Sequence[float] = (0.5, 0.5, 0.5), + ): + super().__init__(color, highlight, "Spaz", None, True, True, False, False) + self.last_player_attacked_by = None + self.stand(pos) + self.loc = ba.newnode( + 'locator', + attrs={ + 'shape': 'circleOutline', + 'position': pos, + 'color': color, + 'opacity': 1, + 'draw_beauty': False, + 'additive': True, + }, + ) + self.node.connectattr("position", self.loc, "position") + ba.animate_array(self.loc, "size", 1, keys={0:[0.5,], 1:[2,], 1.5:[0.5]}, loop=True) + + def handlemessage(self, msg): + if isinstance(msg, ba.FreezeMessage): + return + + if isinstance(msg, ba.PowerupMessage): + if not(msg.poweruptype == "health"): + return + + super().handlemessage(msg) + + if isinstance(msg, ba.HitMessage): + self.handlemessage(ba.PowerupMessage("health")) + + player = msg.get_source_player(Player) + if self.is_alive(): + self.activity.handlemessage(ChooseingSpazHitMessage(player)) + self.last_player_attacked_by = player + + + elif isinstance(msg, ba.DieMessage): + player = self.last_player_attacked_by + + if msg.how.value != ba.DeathType.GENERIC.value: + self._dead = True + self.activity.handlemessage(ChooseingSpazDieMessage(player)) + + self.loc.delete() + + + + def stand(self, pos = (0,0,0), angle = 0): + self.handlemessage(ba.StandMessage(pos,angle)) + + def recolor(self, color, highlight = (1,1,1)): + self.node.color = color + self.node.highlight = highlight + self.loc.color = color + +class ChooseBilbord(ba.Actor): + def __init__(self, player:Player, delay = 0.1) -> None: + super().__init__() + + icon = player.get_icon() + self.scale = 100 + + self.node = ba.newnode( + 'image', + delegate=self, + attrs={ + "position":(60,-125), + 'texture': icon['texture'], + 'tint_texture': icon['tint_texture'], + 'tint_color': icon['tint_color'], + 'tint2_color': icon['tint2_color'], + 'opacity': 1.0, + 'absolute_scale': True, + 'attach': "topLeft" + }, + ) + + self.name_node = ba.newnode( + 'text', + owner=self.node, + attrs={ + 'position': (60,-185), + 'text': ba.Lstr(value=player.getname()), + 'color': ba.safecolor(player.team.color), + 'h_align': 'center', + 'v_align': 'center', + 'vr_depth': 410, + 'flatness': 1.0, + 'h_attach': 'left', + 'v_attach': 'top', + 'maxwidth':self.scale + }, + ) + + ba.animate_array(self.node, "scale", keys={0 + delay:[0,0], 0.05 + delay:[self.scale, self.scale]}, size=1) + ba.animate(self.name_node, "scale", {0 + delay:0, 0.07 + delay:1}) + + def handlemessage(self, msg): + super().handlemessage(msg) + if isinstance(msg, ba.DieMessage): + ba.animate_array(self.node, "scale", keys={0:self.node.scale, 0.05:[0,0]}, size=1) + ba.animate(self.name_node, "scale", {0:self.name_node.scale, 0.07:0}) + + def __delete(): + self.node.delete() + self.name_node.delete() + + ba.timer(0.2, __delete) + +# ba_meta export game +class LastPunchStand(ba.TeamGameActivity[Player, Team]): + name = "Last Punch Stand" + description = "Last one punchs the choosing spaz wins" + tips = [ + 'keep punching the choosing spaz to be last punched player at times up!', + 'you can not frezz the choosing spaz', + "evry time you punch the choosing spaz, you will get one point", + ] + + default_music = ba.MusicType.TO_THE_DEATH + + available_settings = [ + ba.FloatSetting("min time limit (in seconds)", 50.0, min_value=30.0), + ba.FloatSetting("max time limit (in seconds)", 160.0, 60), + + ] + + def __init__(self, settings: dict): + super().__init__(settings) + self._min_timelimit = settings["min time limit (in seconds)"] + self._max_timelimit = settings["max time limit (in seconds)"] + if (self._min_timelimit > self._max_timelimit): + self._max_timelimit = self._min_timelimit + + self._choosing_spaz_defcolor = (0.5,0.5,0.5) + self.choosing_spaz = None + self.choosed_player = None + self.times_uped = False + self.scoreboard = Scoreboard() + + def times_up(self): + self.times_uped = True + + for player in self.players: + if self.choosed_player and (player.team.id != self.choosed_player.team.id): + player.actor._cursed = True + player.actor.curse_explode() + + self.end_game() + + def __get_spaz_bot_spawn_point(self): + if len(self.map.tnt_points) > 0: + return self.map.tnt_points[random.randint(0, len(self.map.tnt_points)-1)] + else: + return (0, 6, 0) + + def spaw_bot(self): + "spawns a choosing bot" + + self.choosing_spaz = ChooseingSpaz(self.__get_spaz_bot_spawn_point()) + self.choose_bilbord = None + + def on_begin(self) -> None: + super().on_begin() + time_limit = random.randint(self._min_timelimit, self._max_timelimit) + self.spaw_bot() + ba.timer(time_limit, self.times_up) + + self.setup_standard_powerup_drops(False) + + def end_game(self) -> None: + results = ba.GameResults() + for team in self.teams: + if self.choosed_player and (team.id == self.choosed_player.team.id): team.score += 100 + results.set_team_score(team, team.score) + self.end(results=results) + + def change_choosed_player(self, hitter:Player): + if hitter: + self.choosing_spaz.recolor(hitter.color, hitter.highlight) + self.choosed_player = hitter + hitter.team.score += 1 + self.choose_bilbord = ChooseBilbord(hitter) + self.hide_score_board() + else: + self.choosing_spaz.recolor(self._choosing_spaz_defcolor) + self.choosed_player = None + self.choose_bilbord = None + self.show_score_board() + + def show_score_board(self): + self.scoreboard = Scoreboard() + for team in self.teams: + self.scoreboard.set_team_value(team, team.score) + + def hide_score_board(self): + self.scoreboard = None + + def _watch_dog_(self): + "checks if choosing spaz exists" + #choosing spaz wont respawn if death type if generic + #this becuse we dont want to keep respawn him when he dies because of losing referce + #but sometimes "choosing spaz" dies naturaly and his death type is generic! so it wont respawn back again + #thats why we have this function; to check if spaz exits in the case that he didnt respawned + + if self.choosing_spaz: + if self.choosing_spaz._dead: + self.spaw_bot() + else: + self.spaw_bot() + + def handlemessage(self, msg): + super().handlemessage(msg) + + if isinstance(msg, ChooseingSpazHitMessage): + hitter = msg.hitter + if self.choosing_spaz.node and hitter: + self.change_choosed_player(hitter) + + elif isinstance(msg, ChooseingSpazDieMessage): + self.spaw_bot() + self.change_choosed_player(None) + + elif isinstance(msg, ba.PlayerDiedMessage): + player = msg.getplayer(Player) + if not (self.has_ended() or self.times_uped): + self.respawn_player(player, 0) + + if self.choosed_player and (player.getname(True) == self.choosed_player.getname(True)): + self.change_choosed_player(None) + + self._watch_dog_() \ No newline at end of file diff --git a/plugins/minigames/quake.py b/plugins/minigames/quake.py new file mode 100644 index 00000000..58ef3e35 --- /dev/null +++ b/plugins/minigames/quake.py @@ -0,0 +1,642 @@ +"""Quake Game Activity""" +# ba_meta require api 7 +from __future__ import annotations + +from typing import TYPE_CHECKING + +import random +import enum +import ba, _ba + +from bastd.actor.scoreboard import Scoreboard +from bastd.actor.powerupbox import PowerupBox +from bastd.gameutils import SharedObjects + +#from rocket +from bastd.actor.bomb import Blast + +#from railgun +from bastd.actor.playerspaz import PlayerSpaz +from bastd.actor.spaz import Spaz + + +if TYPE_CHECKING: + from typing import Optional, List, Any, Type, Union, Sequence + + +STORAGE_ATTR_NAME = f'_shared_{__name__}_factory' + + +#+++++++++++++++++++Rocket++++++++++++++++++++++++ +class RocketFactory: + """Quake Rocket factory""" + + def __init__(self) -> None: + self.ball_material = ba.Material() + + self.ball_material.add_actions( + conditions=((('we_are_younger_than', 5), 'or', + ('they_are_younger_than', 5)), 'and', + ('they_have_material', + SharedObjects.get().object_material)), + actions=('modify_node_collision', 'collide', False)) + + self.ball_material.add_actions( + conditions=('they_have_material', + SharedObjects.get().pickup_material), + actions=('modify_part_collision', 'use_node_collide', False)) + + self.ball_material.add_actions(actions=('modify_part_collision', + 'friction', 0)) + + self.ball_material.add_actions( + conditions=(('they_have_material', + SharedObjects.get().footing_material), 'or', + ('they_have_material', + SharedObjects.get().object_material)), + actions=('message', 'our_node', 'at_connect', ImpactMessage())) + + @classmethod + def get(cls): + """Get factory if exists else create new""" + activity = ba.getactivity() + if hasattr(activity, STORAGE_ATTR_NAME): + return getattr(activity, STORAGE_ATTR_NAME) + factory = cls() + setattr(activity, STORAGE_ATTR_NAME, factory) + return factory + + +class RocketLauncher: + """Very dangerous weapon""" + + def __init__(self): + self.last_shot: Optional[int, float] = 0 + + def give(self, spaz: Spaz) -> None: + """Give spaz a rocket launcher""" + spaz.punch_callback = self.shot + self.last_shot = ba.time() + + # FIXME + # noinspection PyUnresolvedReferences + def shot(self, spaz: Spaz) -> None: + """Release a rocket""" + time = ba.time() + if time - self.last_shot > 0.6: + self.last_shot = time + center = spaz.node.position_center + forward = spaz.node.position_forward + direction = [center[0] - forward[0], forward[1] - center[1], + center[2] - forward[2]] + direction[1] = 0.0 + + mag = 10.0 / ba.Vec3(*direction).length() + vel = [v * mag for v in direction] + Rocket(position=spaz.node.position, + velocity=vel, + owner=spaz.getplayer(ba.Player), + source_player=spaz.getplayer(ba.Player), + color=spaz.node.color).autoretain() + + +class ImpactMessage: + """Rocket touched something""" + + +class Rocket(ba.Actor): + """Epic rocket from rocket launcher""" + + def __init__(self, + position=(0, 5, 0), + velocity=(1, 0, 0), + source_player=None, + owner=None, + color=(1.0, 0.2, 0.2)) -> None: + super().__init__() + self.source_player = source_player + self.owner = owner + self._color = color + factory = RocketFactory.get() + + self.node = ba.newnode('prop', + delegate=self, + attrs={ + 'position': position, + 'velocity': velocity, + 'model': ba.getmodel('impactBomb'), + 'body': 'sphere', + 'color_texture': ba.gettexture( + 'bunnyColor'), + 'model_scale': 0.2, + 'is_area_of_interest': True, + 'body_scale': 0.8, + 'materials': [ + SharedObjects.get().object_material, + factory.ball_material] + }) # yapf: disable + self.node.extra_acceleration = (self.node.velocity[0] * 200, 0, + self.node.velocity[2] * 200) + + self._life_timer = ba.Timer( + 5, ba.WeakCall(self.handlemessage, ba.DieMessage())) + + self._emit_timer = ba.Timer(0.001, ba.WeakCall(self.emit), repeat=True) + self.base_pos_y = self.node.position[1] + + ba.camerashake(5.0) + + def emit(self) -> None: + """Emit a trace after rocket""" + ba.emitfx(position=self.node.position, + scale=0.4, + spread=0.01, + chunk_type='spark') + if not self.node: + return + self.node.position = (self.node.position[0], self.base_pos_y, + self.node.position[2]) # ignore y + ba.newnode('explosion', + owner=self.node, + attrs={ + 'position': self.node.position, + 'radius': 0.2, + 'color': self._color + }) + + def handlemessage(self, msg: Any) -> Any: + """Message handling for rocket""" + super().handlemessage(msg) + if isinstance(msg, ImpactMessage): + self.node.handlemessage(ba.DieMessage()) + + elif isinstance(msg, ba.DieMessage): + if self.node: + Blast(position=self.node.position, + blast_radius=2, + source_player=self.source_player) + + self.node.delete() + self._emit_timer = None + + elif isinstance(msg, ba.OutOfBoundsMessage): + self.handlemessage(ba.DieMessage()) + +#-------------------Rocket-------------------------- + + +#++++++++++++++++++Railgun++++++++++++++++++++++++++ +class Railgun: + """Very dangerous weapon""" + + def __init__(self) -> None: + self.last_shot: Optional[int, float] = 0 + + def give(self, spaz: Spaz) -> None: + """Give spaz a railgun""" + spaz.punch_callback = self.shot + self.last_shot = ba.time() + + # FIXME + # noinspection PyUnresolvedReferences + def shot(self, spaz: Spaz) -> None: + """Release a rocket""" + time = ba.time() + if time - self.last_shot > 0.6: + self.last_shot = time + center = spaz.node.position_center + forward = spaz.node.position_forward + direction = [ + center[0] - forward[0], forward[1] - center[1], + center[2] - forward[2] + ] + direction[1] = 0.0 + + RailBullet(position=spaz.node.position, + direction=direction, + owner=spaz.getplayer(ba.Player), + source_player=spaz.getplayer(ba.Player), + color=spaz.node.color).autoretain() + + +class TouchedToSpazMessage: + """I hit!""" + + def __init__(self, spaz) -> None: + self.spaz = spaz + + +class RailBullet(ba.Actor): + """Railgun bullet""" + + def __init__(self, + position=(0, 5, 0), + direction=(0, 2, 0), + source_player=None, + owner=None, + color=(1, 1, 1)) -> None: + super().__init__() + self._color = color + + self.node = ba.newnode('light', + delegate=self, + attrs={ + 'position': position, + 'color': self._color + }) + ba.animate(self.node, 'radius', {0: 0, 0.1: 0.5, 0.5: 0}) + + self.source_player = source_player + self.owner = owner + self._life_timer = ba.Timer( + 0.5, ba.WeakCall(self.handlemessage, ba.DieMessage())) + + pos = position + vel = tuple(i / 5 for i in ba.Vec3(direction).normalized()) + for _ in range(500): # Optimization :( + ba.newnode('explosion', + owner=self.node, + attrs={ + 'position': pos, + 'radius': 0.2, + 'color': self._color + }) + pos = (pos[0] + vel[0], pos[1] + vel[1], pos[2] + vel[2]) + + for node in _ba.getnodes(): + if node and node.getnodetype() == 'spaz': + # pylint: disable=invalid-name + m3 = ba.Vec3(position) + a = ba.Vec3(direction[2], direction[1], direction[0]) + m1 = ba.Vec3(node.position) + # pylint: enable=invalid-name + # distance between node and line + dist = (a * (m1 - m3)).length() / a.length() + if dist < 0.3: + if node and node != self.owner and node.getdelegate( + PlayerSpaz, True).getplayer( + ba.Player, True).team != self.owner.team: + node.handlemessage(ba.FreezeMessage()) + pos = self.node.position + hit_dir = (0, 10, 0) + + node.handlemessage( + ba.HitMessage(pos=pos, + magnitude=50, + velocity_magnitude=50, + radius=0, + srcnode=self.node, + source_player=self.source_player, + force_direction=hit_dir)) + + def handlemessage(self, msg: Any) -> Any: + super().handlemessage(msg) + if isinstance(msg, ba.DieMessage): + if self.node: + self.node.delete() + + elif isinstance(msg, ba.OutOfBoundsMessage): + self.handlemessage(ba.DieMessage()) + +#------------------Railgun------------------------- + +class Player(ba.Player['Team']): + """Our player""" + + +class Team(ba.Team[Player]): + """Our team""" + def __init__(self) -> None: + self.score = 0 + + +class WeaponType(enum.Enum): + """Type of weapon""" + ROCKET = 0 + RAILGUN = 1 + + +class ObstaclesForm(enum.Enum): + """Obstacle form""" + CUBE = 0 + SPHERE = 1 + RANDOM = 2 + + +# ba_meta export game +class QuakeGame(ba.TeamGameActivity[Player, Team]): + """Quake Team Game Activity""" + name = 'Quake' + description = 'Kill a set number of enemies to win.' + available_settings = [ + ba.IntSetting( + 'Kills to Win Per Player', + default=15, + min_value=1, + 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=[('At once', 0.0), ('Shorter', 0.25), ('Short', 0.5), + ('Normal', 1.0), ('Long', 2.0), ('Longer', 4.0)], + default=1.0, + ), + ba.BoolSetting( + 'Speed', + default=True, + ), + ba.BoolSetting( + 'Enable Jump', + default=True, + ), + ba.BoolSetting( + 'Enable Pickup', + default=True, + ), + ba.BoolSetting( + 'Enable Bomb', + default=False, + ), + ba.BoolSetting( + 'Obstacles', + default=True, + ), + ba.IntChoiceSetting( + 'Obstacles Form', + choices=[('Cube', ObstaclesForm.CUBE.value), + ('Sphere', ObstaclesForm.SPHERE.value), + ('Random', ObstaclesForm.RANDOM.value)], + default=0, + ), + ba.IntChoiceSetting( + 'Weapon Type', + choices=[('Rocket', WeaponType.ROCKET.value), + ('Railgun', WeaponType.RAILGUN.value)], + default=WeaponType.ROCKET.value, + ), + ba.BoolSetting( + 'Obstacles Mirror Shots', + default=False, + ), + ba.IntSetting( + 'Obstacles Count', + default=16, + min_value=0, + increment=2, + ), + ba.BoolSetting( + 'Random Obstacles Color', + default=True, + ), + ba.BoolSetting( + 'Epic Mode', + default=False, + ), + ] + + @classmethod + def supports_session_type(cls, sessiontype: Type[ba.Session]) -> bool: + return issubclass(sessiontype, ba.MultiTeamSession) or issubclass( + sessiontype, ba.FreeForAllSession) + + @classmethod + def get_supported_maps(cls, sessiontype: Type[ba.Session]) -> List[str]: + # TODO add more maps + return ['Football Stadium', 'Monkey Face', 'Doom Shroom'] + + def __init__(self, settings) -> None: + super().__init__(settings) + self._epic_mode = self.settings_raw['Epic Mode'] + self._score_to_win = self.settings_raw['Kills to Win Per Player'] + self._time_limit = self.settings_raw['Time Limit'] + self._obstacles_enabled = self.settings_raw['Obstacles'] + self._obstacles_count = self.settings_raw['Obstacles Count'] + self._speed_enabled = self.settings_raw['Speed'] + self._bomb_enabled = self.settings_raw['Enable Bomb'] + self._pickup_enabled = self.settings_raw['Enable Pickup'] + self._jump_enabled = self.settings_raw['Enable Jump'] + self._weapon_type = WeaponType(self.settings_raw['Weapon Type']) + self.default_music = (ba.MusicType.EPIC + if self._epic_mode else ba.MusicType.GRAND_ROMP) + self.slow_motion = self._epic_mode + + self.announce_player_deaths = True + self._scoreboard = Scoreboard() + self._ding_sound = ba.getsound('dingSmall') + + self._shield_dropper: Optional[ba.Timer] = None + + def get_instance_description(self) -> Union[str, Sequence]: + return 'Kill ${ARG1} enemies.', self._score_to_win + + def on_team_join(self, team: Team) -> None: + team.score = 0 + if self.has_begun(): + self._update_scoreboard() + + def on_begin(self) -> None: + ba.TeamGameActivity.on_begin(self) + ba.getactivity().globalsnode.tint = (0.5, 0.7, 1) + self.drop_shield() + self._shield_dropper = ba.Timer(8, + ba.WeakCall(self.drop_shield), + repeat=True) + self.setup_standard_time_limit(self._time_limit) + if self._obstacles_enabled: + count = self._obstacles_count + gamemap = self.map.getname() + for i in range(count): # TODO: tidy up around here + if gamemap == 'Football Stadium': + radius = (random.uniform(-10, 1), + 6, + random.uniform(-4.5, 4.5)) \ + if i > count / 2 else ( + random.uniform(10, 1), 6, random.uniform(-4.5, 4.5)) + else: + radius = (random.uniform(-10, 1), + 6, + random.uniform(-8, 8)) \ + if i > count / 2 else ( + random.uniform(10, 1), 6, random.uniform(-8, 8)) + + Obstacle( + position=radius, + mirror=self.settings_raw['Obstacles Mirror Shots'], + form=self.settings_raw['Obstacles Form']).autoretain() + + self._update_scoreboard() + + def drop_shield(self) -> None: + """Drop a shield powerup in random place""" + # FIXME: should use map defs + shield = PowerupBox(poweruptype='shield', + position=(random.uniform(-10, 10), 6, + random.uniform(-5, 5))).autoretain() + + ba.playsound(self._ding_sound) + + p_light = ba.newnode('light', + owner=shield.node, + attrs={ + 'position': (0, 0, 0), + 'color': (0.3, 0.0, 0.4), + 'radius': 0.3, + 'intensity': 2, + 'volume_intensity_scale': 10.0 + }) + + shield.node.connectattr('position', p_light, 'position') + + ba.animate(p_light, 'intensity', {0: 2, 8: 0}) + + def spawn_player(self, player: Player) -> None: + spaz = self.spawn_player_spaz(player) + if self._weapon_type == WeaponType.ROCKET: + RocketLauncher().give(spaz) + elif self._weapon_type == WeaponType.RAILGUN: + Railgun().give(spaz) + spaz.connect_controls_to_player(enable_jump=self._jump_enabled, + enable_pickup=self._pickup_enabled, + enable_bomb=self._bomb_enabled, + enable_fly=False) + + spaz.node.hockey = self._speed_enabled + spaz.spaz_light = ba.newnode('light', + owner=spaz.node, + attrs={ + 'position': (0, 0, 0), + 'color': spaz.node.color, + 'radius': 0.12, + 'intensity': 1, + 'volume_intensity_scale': 10.0 + }) + + spaz.node.connectattr('position', spaz.spaz_light, 'position') + + def handlemessage(self, msg: Any) -> Any: + if isinstance(msg, ba.PlayerDiedMessage): + ba.TeamGameActivity.handlemessage(self, msg) + player = msg.getplayer(Player) + self.respawn_player(player) + killer = msg.getkillerplayer(Player) + if killer is None: + return + + # handle team-kills + if killer.team is player.team: + # in free-for-all, killing yourself loses you a point + if isinstance(self.session, ba.FreeForAllSession): + new_score = player.team.score - 1 + new_score = max(0, new_score) + player.team.score = new_score + # in teams-mode it gives a point to the other team + else: + ba.playsound(self._ding_sound) + for team in self.teams: + if team is not killer.team: + team.score += 1 + # killing someone on another team nets a kill + else: + killer.team.score += 1 + ba.playsound(self._ding_sound) + # in FFA show our score since its hard to find on + # the scoreboard + assert killer.actor is not None + # noinspection PyUnresolvedReferences + killer.actor.set_score_text(str(killer.team.score) + '/' + + str(self._score_to_win), + color=killer.team.color, + flash=True) + + self._update_scoreboard() + + # if someone has won, set a timer to end shortly + # (allows the dust to clear and draws to occur if + # deaths are close enough) + if any(team.score >= self._score_to_win for team in self.teams): + ba.timer(0.5, self.end_game) + + else: + ba.TeamGameActivity.handlemessage(self, msg) + + def _update_scoreboard(self) -> None: + for team in self.teams: + self._scoreboard.set_team_value(team, team.score, + self._score_to_win) + + def end_game(self) -> None: + results = ba.GameResults() + for team in self.teams: + results.set_team_score(team, team.score) + + self.end(results=results) + + +class Obstacle(ba.Actor): + """Scene object""" + + def __init__(self, + position, + form=ObstaclesForm.CUBE, + mirror=False) -> None: + ba.Actor.__init__(self) + + if form == ObstaclesForm.CUBE: + model = 'tnt' + body = 'crate' + elif form == ObstaclesForm.SPHERE: + model = 'bomb' + body = 'sphere' + else: # ObstaclesForm.RANDOM: + model = random.choice(['tnt', 'bomb']) + body = 'sphere' if model == 'bomb' else 'crate' + + self.node = ba.newnode( + 'prop', + delegate=self, + attrs={ + 'position': + position, + 'model': + ba.getmodel(model), + 'body': + body, + 'body_scale': + 1.3, + 'model_scale': + 1.3, + 'reflection': + 'powerup', + 'reflection_scale': [0.7], + 'color_texture': + ba.gettexture('bunnyColor'), + 'materials': [SharedObjects.get().footing_material] + if mirror else [ + SharedObjects.get().object_material, + SharedObjects.get().footing_material + ] + }) + + def handlemessage(self, msg: Any) -> Any: + if isinstance(msg, ba.DieMessage): + if self.node: + self.node.delete() + + elif isinstance(msg, ba.OutOfBoundsMessage): + if self.node: + self.handlemessage(ba.DieMessage()) + + elif isinstance(msg, ba.HitMessage): + self.node.handlemessage('impulse', msg.pos[0], msg.pos[1], + msg.pos[2], msg.velocity[0], + msg.velocity[1], msg.velocity[2], + msg.magnitude, msg.velocity_magnitude, + msg.radius, 0, msg.velocity[0], + msg.velocity[1], msg.velocity[2]) diff --git a/plugins/minigames/sleep_race.py b/plugins/minigames/sleep_race.py new file mode 100644 index 00000000..6746524f --- /dev/null +++ b/plugins/minigames/sleep_race.py @@ -0,0 +1,783 @@ +# Released under the MIT License. See LICENSE for details. +# y me (: itsre3 +# =>2<= +#BCS RULES +# +"""Defines Race mini-game.""" + +# ba_meta require api 7 +# (see https://ballistica.net/wiki/meta-tag-system) + +from __future__ import annotations + +import random +from typing import TYPE_CHECKING +from dataclasses import dataclass + +import ba, _ba +from bastd.actor.bomb import Bomb +from bastd.actor.playerspaz import PlayerSpaz +from bastd.actor.scoreboard import Scoreboard +from bastd.gameutils import SharedObjects + +if TYPE_CHECKING: + from typing import (Any, Type, Tuple, List, Sequence, Optional, Dict, + Union) + from bastd.actor.onscreentimer import OnScreenTimer + + +@dataclass +class RaceMine: + """Holds info about a mine on the track.""" + point: Sequence[float] + mine: Optional[Bomb] + + +class RaceRegion(ba.Actor): + """Region used to track progress during a race.""" + + def __init__(self, pt: Sequence[float], index: int): + super().__init__() + activity = self.activity + assert isinstance(activity, RaceGame) + self.pos = pt + self.index = index + self.node = ba.newnode( + 'region', + delegate=self, + attrs={ + 'position': pt[:3], + 'scale': (pt[3] * 2.0, pt[4] * 2.0, pt[5] * 2.0), + 'type': 'box', + 'materials': [activity.race_region_material] + }) + + +class Player(ba.Player['Team']): + """Our player type for this game.""" + + def __init__(self) -> None: + self.distance_txt: Optional[ba.Node] = None + self.last_region = 0 + self.lap = 0 + self.distance = 0.0 + self.finished = False + self.rank: Optional[int] = None + + +class Team(ba.Team[Player]): + """Our team type for this game.""" + + def __init__(self) -> None: + self.time: Optional[float] = None + self.lap = 0 + self.finished = False + + +# ba_meta export game +class SleepRaceGame(ba.TeamGameActivity[Player, Team]): + """Game of racing around a track.""" + + name = 'Sleep Race' + description = 'Can you run while sleeping?' + scoreconfig = ba.ScoreConfig(label='Time', + lower_is_better=True, + scoretype=ba.ScoreType.MILLISECONDS) + + @classmethod + def get_available_settings( + cls, sessiontype: Type[ba.Session]) -> List[ba.Setting]: + settings = [ + ba.IntSetting('Laps', min_value=1, default=2, increment=1), + ba.IntChoiceSetting( + 'Time Limit', + default=0, + choices=[ + ('None', 0), + ('1 Minute', 60), + ('2 Minutes', 120), + ('5 Minutes', 300), + ('10 Minutes', 600), + ('20 Minutes', 1200), + ], + ), + ba.IntChoiceSetting( + 'Mine Spawning', + default=4000, + choices=[ + ('No Mines', 0), + ('8 Seconds', 8000), + ('4 Seconds', 4000), + ('2 Seconds', 2000), + ], + ), + ba.IntChoiceSetting( + 'Bomb Spawning', + choices=[ + ('None', 0), + ('8 Seconds', 8000), + ('4 Seconds', 4000), + ('2 Seconds', 2000), + ('1 Second', 1000), + ], + default=2000, + ), + ba.IntChoiceSetting( + 'Knockout Time', + choices=[ + ('8 Seconds', 8000), + ('5 Seconds', 5000), + ], + default=5000, + ), + ba.BoolSetting('Epic Mode', default=False), + ba.BoolSetting('Credits', default=True), + ] + + # We have some specific settings in teams mode. + if issubclass(sessiontype, ba.DualTeamSession): + settings.append( + ba.BoolSetting('Entire Team Must Finish', default=False)) + return settings + + @classmethod + def supports_session_type(cls, sessiontype: Type[ba.Session]) -> bool: + return issubclass(sessiontype, ba.MultiTeamSession) + + @classmethod + def get_supported_maps(cls, sessiontype: Type[ba.Session]) -> List[str]: + return ba.getmaps('race') + + def __init__(self, settings: dict): + self._race_started = False + super().__init__(settings) + self._scoreboard = Scoreboard() + self._score_sound = ba.getsound('score') + self._swipsound = ba.getsound('swip') + self._last_team_time: Optional[float] = None + self._front_race_region: Optional[int] = None + self._nub_tex = ba.gettexture('nub') + self._beep_1_sound = ba.getsound('raceBeep1') + self._beep_2_sound = ba.getsound('raceBeep2') + self.race_region_material: Optional[ba.Material] = None + self._regions: List[RaceRegion] = [] + self._team_finish_pts: Optional[int] = None + self._time_text: Optional[ba.Actor] = None + self._cd_text: Optional[ba.Actor] = None + self._timer: Optional[OnScreenTimer] = None + self._race_mines: Optional[List[RaceMine]] = None + self._race_mine_timer: Optional[ba.Timer] = None + self._scoreboard_timer: Optional[ba.Timer] = None + self._player_order_update_timer: Optional[ba.Timer] = None + self._start_lights: Optional[List[ba.Node]] = None + self._bomb_spawn_timer: Optional[ba.Timer] = None + self._knockout_timer: Optional[ba.Timer] = None + self._laps = int(settings['Laps']) + self._entire_team_must_finish = bool( + settings.get('Entire Team Must Finish', False)) + self._time_limit = float(settings['Time Limit']) + self._mine_spawning = int(settings['Mine Spawning']) + self._bomb_spawning = int(settings['Bomb Spawning']) + self._knockout_time = float(settings['Knockout Time']) + self._epic_mode = bool(settings['Epic Mode']) + self._credits = bool(settings['Credits']) + + # Base class overrides. + self.slow_motion = self._epic_mode + self.default_music = (ba.MusicType.EPIC_RACE + if self._epic_mode else ba.MusicType.RACE) + + def get_instance_description(self) -> Union[str, Sequence]: + if (isinstance(self.session, ba.DualTeamSession) + and self._entire_team_must_finish): + t_str = ' Your entire team has to finish.' + else: + t_str = '' + + if self._laps > 1: + return 'Run ${ARG1} laps.' + t_str, self._laps + return 'Run 1 lap.' + t_str + + def get_instance_description_short(self) -> Union[str, Sequence]: + if self._laps > 1: + return 'run ${ARG1} laps', self._laps + return 'run 1 lap' + + def on_transition_in(self) -> None: + super().on_transition_in() + shared = SharedObjects.get() + pts = self.map.get_def_points('race_point') + mat = self.race_region_material = ba.Material() + mat.add_actions(conditions=('they_have_material', + shared.player_material), + actions=( + ('modify_part_collision', 'collide', True), + ('modify_part_collision', 'physical', False), + ('call', 'at_connect', + self._handle_race_point_collide), + )) + for rpt in pts: + self._regions.append(RaceRegion(rpt, len(self._regions))) + + def _flash_player(self, player: Player, scale: float) -> None: + assert isinstance(player.actor, PlayerSpaz) + assert player.actor.node + pos = player.actor.node.position + light = ba.newnode('light', + attrs={ + 'position': pos, + 'color': (1, 1, 0), + 'height_attenuated': False, + 'radius': 0.4 + }) + ba.timer(0.5, light.delete) + ba.animate(light, 'intensity', {0: 0, 0.1: 1.0 * scale, 0.5: 0}) + + def _handle_race_point_collide(self) -> None: + # FIXME: Tidy this up. + # pylint: disable=too-many-statements + # pylint: disable=too-many-branches + # pylint: disable=too-many-nested-blocks + collision = ba.getcollision() + try: + region = collision.sourcenode.getdelegate(RaceRegion, True) + player = collision.opposingnode.getdelegate(PlayerSpaz, + True).getplayer( + Player, True) + except ba.NotFoundError: + return + + last_region = player.last_region + this_region = region.index + + if last_region != this_region: + + # If a player tries to skip regions, smite them. + # Allow a one region leeway though (its plausible players can get + # blown over a region, etc). + if this_region > last_region + 2: + if player.is_alive(): + assert player.actor + player.actor.handlemessage(ba.DieMessage()) + ba.screenmessage(ba.Lstr( + translate=('statements', 'Killing ${NAME} for' + ' skipping part of the track!'), + subs=[('${NAME}', player.getname(full=True))]), + color=(1, 0, 0)) + else: + # If this player is in first, note that this is the + # front-most race-point. + if player.rank == 0: + self._front_race_region = this_region + + player.last_region = this_region + if last_region >= len(self._regions) - 2 and this_region == 0: + team = player.team + player.lap = min(self._laps, player.lap + 1) + + # In teams mode with all-must-finish on, the team lap + # value is the min of all team players. + # Otherwise its the max. + if isinstance(self.session, ba.DualTeamSession + ) and self._entire_team_must_finish: + team.lap = min([p.lap for p in team.players]) + else: + team.lap = max([p.lap for p in team.players]) + + # A player is finishing. + if player.lap == self._laps: + + # In teams mode, hand out points based on the order + # players come in. + if isinstance(self.session, ba.DualTeamSession): + assert self._team_finish_pts is not None + if self._team_finish_pts > 0: + self.stats.player_scored(player, + self._team_finish_pts, + screenmessage=False) + self._team_finish_pts -= 25 + + # Flash where the player is. + self._flash_player(player, 1.0) + player.finished = True + assert player.actor + player.actor.handlemessage( + ba.DieMessage(immediate=True)) + + # Makes sure noone behind them passes them in rank + # while finishing. + player.distance = 9999.0 + + # If the whole team has finished the race. + if team.lap == self._laps: + ba.playsound(self._score_sound) + player.team.finished = True + assert self._timer is not None + elapsed = ba.time() - self._timer.getstarttime() + self._last_team_time = player.team.time = elapsed + self._check_end_game() + + # Team has yet to finish. + else: + ba.playsound(self._swipsound) + + # They've just finished a lap but not the race. + else: + ba.playsound(self._swipsound) + self._flash_player(player, 0.3) + + # Print their lap number over their head. + try: + assert isinstance(player.actor, PlayerSpaz) + mathnode = ba.newnode('math', + owner=player.actor.node, + attrs={ + 'input1': (0, 1.9, 0), + 'operation': 'add' + }) + player.actor.node.connectattr( + 'torso_position', mathnode, 'input2') + tstr = ba.Lstr(resource='lapNumberText', + subs=[('${CURRENT}', + str(player.lap + 1)), + ('${TOTAL}', str(self._laps)) + ]) + txtnode = ba.newnode('text', + owner=mathnode, + attrs={ + 'text': tstr, + 'in_world': True, + 'color': (1, 1, 0, 1), + 'scale': 0.015, + 'h_align': 'center' + }) + mathnode.connectattr('output', txtnode, 'position') + ba.animate(txtnode, 'scale', { + 0.0: 0, + 0.2: 0.019, + 2.0: 0.019, + 2.2: 0 + }) + ba.timer(2.3, mathnode.delete) + except Exception: + ba.print_exception('Error printing lap.') + + def on_team_join(self, team: Team) -> None: + self._update_scoreboard() + + def on_player_leave(self, player: Player) -> None: + super().on_player_leave(player) + + # A player leaving disqualifies the team if 'Entire Team Must Finish' + # is on (otherwise in teams mode everyone could just leave except the + # leading player to win). + if (isinstance(self.session, ba.DualTeamSession) + and self._entire_team_must_finish): + ba.screenmessage(ba.Lstr( + translate=('statements', + '${TEAM} is disqualified because ${PLAYER} left'), + subs=[('${TEAM}', player.team.name), + ('${PLAYER}', player.getname(full=True))]), + color=(1, 1, 0)) + player.team.finished = True + player.team.time = None + player.team.lap = 0 + ba.playsound(ba.getsound('boo')) + for otherplayer in player.team.players: + otherplayer.lap = 0 + otherplayer.finished = True + try: + if otherplayer.actor is not None: + otherplayer.actor.handlemessage(ba.DieMessage()) + except Exception: + ba.print_exception('Error sending DieMessage.') + + # Defer so team/player lists will be updated. + ba.pushcall(self._check_end_game) + + def _update_scoreboard(self) -> None: + for team in self.teams: + distances = [player.distance for player in team.players] + if not distances: + teams_dist = 0.0 + else: + if (isinstance(self.session, ba.DualTeamSession) + and self._entire_team_must_finish): + teams_dist = min(distances) + else: + teams_dist = max(distances) + self._scoreboard.set_team_value( + team, + teams_dist, + self._laps, + flash=(teams_dist >= float(self._laps)), + show_value=False) + + def on_begin(self) -> None: + from bastd.actor.onscreentimer import OnScreenTimer + super().on_begin() + self.setup_standard_time_limit(self._time_limit) + self.setup_standard_powerup_drops() + self._team_finish_pts = 100 + if self._credits: + self._cd_text = ba.NodeActor( + ba.newnode('text', + attrs={ + 'position': (0, 0), + 'h_attach': 'center', + 'h_align': 'center', + 'maxwidth': 200, + 'shadow': 0.5, + 'vr_depth': 390, + 'scale': 0.6, + 'v_attach': 'bottom', + 'color': (1, 1, 1), + 'text': 'By itsre3' + })) + + + # Throw a timer up on-screen. + self._time_text = ba.NodeActor( + ba.newnode('text', + attrs={ + 'v_attach': 'top', + 'h_attach': 'center', + 'h_align': 'center', + 'color': (1, 1, 0.5, 1), + 'flatness': 0.5, + 'shadow': 0.5, + 'position': (0, -50), + 'scale': 1.4, + 'text': '' + })) + self._timer = OnScreenTimer() + + if self._mine_spawning != 0: + self._race_mines = [ + RaceMine(point=p, mine=None) + for p in self.map.get_def_points('race_mine') + ] + if self._race_mines: + self._race_mine_timer = ba.Timer(0.001 * self._mine_spawning, + self._update_race_mine, + repeat=True) + + self._scoreboard_timer = ba.Timer(0.25, + self._update_scoreboard, + repeat=True) + self._player_order_update_timer = ba.Timer(0.25, + self._update_player_order, + repeat=True) + + if self.slow_motion: + t_scale = 0.4 + light_y = 50 + else: + t_scale = 1.0 + light_y = 150 + lstart = 7.1 * t_scale + inc = 1.25 * t_scale + + ba.timer(lstart, self._do_light_1) + ba.timer(lstart + inc, self._do_light_2) + ba.timer(lstart + 2 * inc, self._do_light_3) + ba.timer(lstart + 3 * inc, self._start_race) + + self._start_lights = [] + for i in range(4): + lnub = ba.newnode('image', + attrs={ + 'texture': ba.gettexture('nub'), + 'opacity': 1.0, + 'absolute_scale': True, + 'position': (-75 + i * 50, light_y), + 'scale': (50, 50), + 'attach': 'center' + }) + ba.animate( + lnub, 'opacity', { + 4.0 * t_scale: 0, + 5.0 * t_scale: 1.0, + 12.0 * t_scale: 1.0, + 12.5 * t_scale: 0.0 + }) + ba.timer(13.0 * t_scale, lnub.delete) + self._start_lights.append(lnub) + + self._start_lights[0].color = (0.2, 0, 0) + self._start_lights[1].color = (0.2, 0, 0) + self._start_lights[2].color = (0.2, 0.05, 0) + self._start_lights[3].color = (0.0, 0.3, 0) + + def _do_light_1(self) -> None: + assert self._start_lights is not None + self._start_lights[0].color = (1.0, 0, 0) + ba.playsound(self._beep_1_sound) + + def _do_light_2(self) -> None: + assert self._start_lights is not None + self._start_lights[1].color = (1.0, 0, 0) + ba.playsound(self._beep_1_sound) + + def _do_light_3(self) -> None: + assert self._start_lights is not None + self._start_lights[2].color = (1.0, 0.3, 0) + ba.playsound(self._beep_1_sound) + + def _start_race(self) -> None: + assert self._start_lights is not None + self._start_lights[3].color = (0.0, 1.0, 0) + ba.playsound(self._beep_2_sound) + for player in self.players: + if player.actor is not None: + try: + assert isinstance(player.actor, PlayerSpaz) + player.actor.connect_controls_to_player() + except Exception: + ba.print_exception('Error in race player connects.') + assert self._timer is not None + self._timer.start() + + if self._bomb_spawning != 0: + self._bomb_spawn_timer = ba.Timer(0.001 * self._bomb_spawning, + self._spawn_bomb, + repeat=True) + + + def knock_players(): + activity = _ba.get_foreground_host_activity() + gnode = ba.getactivity().globalsnode + for players in activity.players: + gnode.tint = (0.5,0.5,0.5) + node = players.actor.node + node.handlemessage('knockout', 600.0) + self.text_offset = ba.newnode('math', + owner=node, + attrs={'input1': (-0.5, 0.5, 0.25), + 'operation': 'add'}) + node.connectattr( + 'torso_position', + self.text_offset, + 'input2') + self.text = ba.newnode('text', + owner=node, + attrs={ + 'h_align': 'right', + 'color': (1.0, 1.0, 1.0), + 'shadow': 1.0, + 'text': 'z z', + 'scale': 0.01, + 'in_world': True}) + self.text_offset.connectattr( + 'output', + self.text, + 'position') + ba.animate(self.text, 'scale', {0: 0.0, 1.0: 0.01}) + ba.timer(2, self.text.delete) + + if self._knockout_time != 0: + knock_time = 0.001 * self._knockout_time + self._knockout_timer = ba.Timer(knock_time, + knock_players, + repeat=True) + + self._race_started = True + + + def _update_player_order(self) -> None: + + # Calc all player distances. + for player in self.players: + pos: Optional[ba.Vec3] + try: + pos = player.position + except ba.NotFoundError: + pos = None + if pos is not None: + r_index = player.last_region + rg1 = self._regions[r_index] + r1pt = ba.Vec3(rg1.pos[:3]) + rg2 = self._regions[0] if r_index == len( + self._regions) - 1 else self._regions[r_index + 1] + r2pt = ba.Vec3(rg2.pos[:3]) + r2dist = (pos - r2pt).length() + amt = 1.0 - (r2dist / (r2pt - r1pt).length()) + amt = player.lap + (r_index + amt) * (1.0 / len(self._regions)) + player.distance = amt + + # Sort players by distance and update their ranks. + p_list = [(player.distance, player) for player in self.players] + + p_list.sort(reverse=True, key=lambda x: x[0]) + for i, plr in enumerate(p_list): + plr[1].rank = i + if plr[1].actor: + node = plr[1].distance_txt + if node: + node.text = str(i + 1) if plr[1].is_alive() else '' + + def _spawn_bomb(self) -> None: + if self._front_race_region is None: + return + region = (self._front_race_region + 3) % len(self._regions) + pos = self._regions[region].pos + + # Don't use the full region so we're less likely to spawn off a cliff. + region_scale = 0.8 + x_range = ((-0.5, 0.5) if pos[3] == 0 else + (-region_scale * pos[3], region_scale * pos[3])) + z_range = ((-0.5, 0.5) if pos[5] == 0 else + (-region_scale * pos[5], region_scale * pos[5])) + pos = (pos[0] + random.uniform(*x_range), pos[1] + 1.0, + pos[2] + random.uniform(*z_range)) + ba.timer(random.uniform(0.0, 2.0), + ba.WeakCall(self._spawn_bomb_at_pos, pos)) + + def _spawn_bomb_at_pos(self, pos: Sequence[float]) -> None: + if self.has_ended(): + return + Bomb(position=pos, bomb_type='normal').autoretain() + + def _make_mine(self, i: int) -> None: + assert self._race_mines is not None + rmine = self._race_mines[i] + rmine.mine = Bomb(position=rmine.point[:3], bomb_type='land_mine') + rmine.mine.arm() + + def _flash_mine(self, i: int) -> None: + assert self._race_mines is not None + rmine = self._race_mines[i] + light = ba.newnode('light', + attrs={ + 'position': rmine.point[:3], + 'color': (1, 0.2, 0.2), + 'radius': 0.1, + 'height_attenuated': False + }) + ba.animate(light, 'intensity', {0.0: 0, 0.1: 1.0, 0.2: 0}, loop=True) + ba.timer(1.0, light.delete) + + def _update_race_mine(self) -> None: + assert self._race_mines is not None + m_index = -1 + rmine = None + for _i in range(3): + m_index = random.randrange(len(self._race_mines)) + rmine = self._race_mines[m_index] + if not rmine.mine: + break + assert rmine is not None + if not rmine.mine: + self._flash_mine(m_index) + ba.timer(0.95, ba.Call(self._make_mine, m_index)) + + def spawn_player(self, player: Player) -> ba.Actor: + if player.team.finished: + # FIXME: This is not type-safe! + # This call is expected to always return an Actor! + # Perhaps we need something like can_spawn_player()... + # noinspection PyTypeChecker + return None # type: ignore + pos = self._regions[player.last_region].pos + + # Don't use the full region so we're less likely to spawn off a cliff. + region_scale = 0.8 + x_range = ((-0.5, 0.5) if pos[3] == 0 else + (-region_scale * pos[3], region_scale * pos[3])) + z_range = ((-0.5, 0.5) if pos[5] == 0 else + (-region_scale * pos[5], region_scale * pos[5])) + pos = (pos[0] + random.uniform(*x_range), pos[1], + pos[2] + random.uniform(*z_range)) + spaz = self.spawn_player_spaz( + player, position=pos, angle=90 if not self._race_started else None) + assert spaz.node + # Prevent controlling of characters before the start of the race. + if not self._race_started: + spaz.disconnect_controls_from_player() + mathnode = ba.newnode('math', + owner=spaz.node, + attrs={ + 'input1': (0, 1.4, 0), + 'operation': 'add' + }) + spaz.node.connectattr('torso_position', mathnode, 'input2') + + distance_txt = ba.newnode('text', + owner=spaz.node, + attrs={ + 'text': '', + 'in_world': True, + 'color': (1, 1, 0.4), + 'scale': 0.02, + 'h_align': 'center' + }) + player.distance_txt = distance_txt + mathnode.connectattr('output', distance_txt, 'position') + + def _check_end_game(self) -> None: + + # If there's no teams left racing, finish. + teams_still_in = len([t for t in self.teams if not t.finished]) + if teams_still_in == 0: + self.end_game() + return + + # Count the number of teams that have completed the race. + teams_completed = len( + [t for t in self.teams if t.finished and t.time is not None]) + + if teams_completed > 0: + session = self.session + + # In teams mode its over as soon as any team finishes the race + + # FIXME: The get_ffa_point_awards code looks dangerous. + if isinstance(session, ba.DualTeamSession): + self.end_game() + else: + # In ffa we keep the race going while there's still any points + # to be handed out. Find out how many points we have to award + # and how many teams have finished, and once that matches + # we're done. + assert isinstance(session, ba.FreeForAllSession) + points_to_award = len(session.get_ffa_point_awards()) + if teams_completed >= points_to_award - teams_completed: + self.end_game() + return + + def end_game(self) -> None: + + # Stop updating our time text, and set it to show the exact last + # finish time if we have one. (so users don't get upset if their + # final time differs from what they see onscreen by a tiny amount) + assert self._timer is not None + if self._timer.has_started(): + self._timer.stop( + endtime=None if self._last_team_time is None else ( + self._timer.getstarttime() + self._last_team_time)) + + results = ba.GameResults() + + for team in self.teams: + if team.time is not None: + # We store time in seconds, but pass a score in milliseconds. + results.set_team_score(team, int(team.time * 1000.0)) + else: + results.set_team_score(team, None) + + # We don't announce a winner in ffa mode since its probably been a + # while since the first place guy crossed the finish line so it seems + # odd to be announcing that now. + self.end(results=results, + announce_winning_team=isinstance(self.session, + ba.DualTeamSession)) + + def handlemessage(self, msg: Any) -> Any: + if isinstance(msg, ba.PlayerDiedMessage): + # Augment default behavior. + super().handlemessage(msg) + player = msg.getplayer(Player) + if not player.finished: + self.respawn_player(player, respawn_time=1) + else: + super().handlemessage(msg) diff --git a/plugins/minigames/snake.py b/plugins/minigames/snake.py new file mode 100644 index 00000000..7252bfcf --- /dev/null +++ b/plugins/minigames/snake.py @@ -0,0 +1,314 @@ +#snake +# Released under the MIT License. See LICENSE for details. +# +"""Snake game by SEBASTIAN2059""" + +# ba_meta require api 7 +# (see https://ballistica.net/wiki/meta-tag-system) + +from __future__ import annotations + +from typing import TYPE_CHECKING + +import ba +from bastd.actor.playerspaz import PlayerSpaz +from bastd.actor.scoreboard import Scoreboard +from bastd.actor import bomb as stdbomb + +if TYPE_CHECKING: + from typing import Any, Type, List, Dict, Tuple, Union, Sequence, Optional + +class ScoreMessage: + """It will help us with the scores.""" + def __init__(self,player: Player): + self.player = player + + def getplayer(self): + return self.player + +class Player(ba.Player['Team']): + """Our player type for this game.""" + def __init__(self) -> None: + + self.mines = [] + self.actived = None + +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': + description = 'Sobrevive a un número determinado de minas para ganar.' + join_description = 'Corre y no te dejes matar.' + view_description = 'sobrevive ${ARG1} minas' + +else: + description = 'Survive a set number of mines to win.' + join_description = "Run and don't get killed." + view_description = 'survive ${ARG1} mines' + +class Custom_Mine(stdbomb.Bomb): + """Custom a mine :)""" + def __init__(self,position,source_player): + stdbomb.Bomb.__init__(self,position=position,bomb_type='land_mine',source_player=source_player) + + def handlemessage(self,msg: Any) -> Any: + if isinstance(msg, ba.HitMessage): + return + else: + super().handlemessage(msg) + +# ba_meta export game +class SnakeGame(ba.TeamGameActivity[Player, Team]): + """A game type based on acquiring kills.""" + + name = 'Snake' + description = description + + # Print messages when players die since it matters here. + announce_player_deaths = True + + @classmethod + def get_available_settings( + cls, sessiontype: Type[ba.Session]) -> List[ba.Setting]: + settings = [ + ba.IntSetting( + 'Score to Win', + min_value=40, + default=80, + increment=5, + ), + 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', 4.0), + ], + default=1.0, + ), + ba.BoolSetting('Epic Mode', default=False), + ] + return settings + + @classmethod + def supports_session_type(cls, sessiontype: Type[ba.Session]) -> bool: + return (issubclass(sessiontype, ba.DualTeamSession) + or issubclass(sessiontype, ba.FreeForAllSession)) + + @classmethod + def get_supported_maps(cls, sessiontype: Type[ba.Session]) -> List[str]: + return ba.getmaps('melee') + + def __init__(self, settings: dict): + super().__init__(settings) + self._scoreboard = Scoreboard() + self._score_to_win: Optional[int] = None + self._dingsound = ba.getsound('dingSmall') + + self._beep_1_sound = ba.getsound('raceBeep1') + self._beep_2_sound = ba.getsound('raceBeep2') + + self._epic_mode = bool(settings['Epic Mode']) + self._kills_to_win_per_player = int( + settings['Score to Win']) + self._time_limit = float(settings['Time Limit']) + + self._started = False + + # Base class overrides. + self.slow_motion = self._epic_mode + self.default_music = (ba.MusicType.EPIC if self._epic_mode else + ba.MusicType.TO_THE_DEATH) + + def get_instance_description(self) -> Union[str, Sequence]: + return join_description + + def get_instance_description_short(self) -> Union[str, Sequence]: + return view_description, self._score_to_win + + def on_team_join(self, team: Team) -> None: + if self.has_begun(): + self._update_scoreboard() + + def on_begin(self) -> None: + super().on_begin() + self.setup_standard_time_limit(self._time_limit) + #self.setup_standard_powerup_drops() + + # Base kills needed to win on the size of the largest team. + self._score_to_win = (self._kills_to_win_per_player * + max(1, max(len(t.players) for t in self.teams))) + self._update_scoreboard() + + + if self.slow_motion: + t_scale = 0.4 + light_y = 50 + else: + t_scale = 1.0 + light_y = 150 + lstart = 7.1 * t_scale + inc = 1.25 * t_scale + + ba.timer(lstart, self._do_light_1) + ba.timer(lstart + inc, self._do_light_2) + ba.timer(lstart + 2 * inc, self._do_light_3) + ba.timer(lstart + 3 * inc, self._start_race) + + self._start_lights = [] + for i in range(4): + lnub = ba.newnode('image', + attrs={ + 'texture': ba.gettexture('nub'), + 'opacity': 1.0, + 'absolute_scale': True, + 'position': (-75 + i * 50, light_y), + 'scale': (50, 50), + 'attach': 'center' + }) + ba.animate( + lnub, 'opacity', { + 4.0 * t_scale: 0, + 5.0 * t_scale: 1.0, + 12.0 * t_scale: 1.0, + 12.5 * t_scale: 0.0 + }) + ba.timer(13.0 * t_scale, lnub.delete) + self._start_lights.append(lnub) + + self._start_lights[0].color = (0.2, 0, 0) + self._start_lights[1].color = (0.2, 0, 0) + self._start_lights[2].color = (0.2, 0.05, 0) + self._start_lights[3].color = (0.0, 0.3, 0) + + def _do_light_1(self) -> None: + assert self._start_lights is not None + self._start_lights[0].color = (1.0, 0, 0) + ba.playsound(self._beep_1_sound) + + def _do_light_2(self) -> None: + assert self._start_lights is not None + self._start_lights[1].color = (1.0, 0, 0) + ba.playsound(self._beep_1_sound) + + def _do_light_3(self) -> None: + assert self._start_lights is not None + self._start_lights[2].color = (1.0, 0.3, 0) + ba.playsound(self._beep_1_sound) + + def _start_race(self) -> None: + assert self._start_lights is not None + self._start_lights[3].color = (0.0, 1.0, 0) + ba.playsound(self._beep_2_sound) + + self._started = True + + for player in self.players: + self.generate_mines(player) + + # overriding the default character spawning.. + def spawn_player(self, player: Player) -> ba.Actor: + spaz = self.spawn_player_spaz(player) + + # Let's reconnect this player's controls to this + # spaz but *without* the ability to attack or pick stuff up. + spaz.connect_controls_to_player(enable_punch=False, + enable_bomb=False, + enable_pickup=False) + + # Also lets have them make some noise when they die. + spaz.play_big_death_sound = True + if self._started: + self.generate_mines(player) + return spaz + + + def generate_mines(self,player: Player): + try: + player.actived = ba.Timer(0.5,ba.Call(self.spawn_mine, player),repeat=True) + except Exception as e: + print('Exception -> '+ str(e)) + + + + def spawn_mine(self,player: Player): + if player.team.score >= self._score_to_win: + return + pos = player.actor.node.position + # mine = stdbomb.Bomb(position=(pos[0], pos[1] + 2.0, pos[2]), + # velocity=(0, 0, 0), + # bomb_type='land_mine', + # #blast_radius=, + # source_player=player.actor.source_player, + # owner=player.actor.node).autoretain() + mine = Custom_Mine(position=(pos[0], pos[1] + 2.0, pos[2]), + source_player=player.actor.source_player) + + def arm(): + mine.arm() + ba.timer(0.5,arm) + + player.mines.append(mine) + if len(player.mines) > 15: + for m in player.mines: + try: + m.node.delete() + except Exception: + pass + player.mines.remove(m) + break + + self.handlemessage(ScoreMessage(player)) + + def handlemessage(self, msg: Any) -> Any: + if isinstance(msg, ba.PlayerDiedMessage): + + # Augment standard behavior. + super().handlemessage(msg) + + player = msg.getplayer(Player) + self.respawn_player(player) + + player.actived = None + + elif isinstance(msg, ScoreMessage): + player = msg.getplayer() + + player.team.score += 1 + self._update_scoreboard() + + assert self._score_to_win is not None + if any(team.score >= self._score_to_win for team in self.teams): + self.end_game() #ba.timer(0.5, self.end_game) + else: + return super().handlemessage(msg) + return None + + def _update_scoreboard(self) -> None: + for team in self.teams: + self._scoreboard.set_team_value(team, team.score, + self._score_to_win) + + def end_game(self) -> None: + results = ba.GameResults() + for team in self.teams: + results.set_team_score(team, team.score) + self.end(results=results) diff --git a/plugins/minigames/ufo_fight.py b/plugins/minigames/ufo_fight.py new file mode 100644 index 00000000..29c45716 --- /dev/null +++ b/plugins/minigames/ufo_fight.py @@ -0,0 +1,994 @@ +"""UFO Boss Fight v1.0: +Made by Cross Joy""" + +# Anyone who wanna help me in giving suggestion/ fix bugs/ by creating PR, +# Can visit my github https://github.com/CrossJoy/Bombsquad-Modding + +# You can contact me through discord: +# My Discord Id: Cross Joy#0721 +# My BS Discord Server: https://discford.gg/JyBY6haARJ + +# ba_meta require api 7 +# (see https://ballistica.net/wiki/meta-tag-system) + +from __future__ import annotations + +import random +from typing import TYPE_CHECKING +import ba, _ba +from bastd.actor.playerspaz import PlayerSpaz +from bastd.actor.spaz import Spaz +from bastd.actor.bomb import Blast, Bomb +from bastd.actor.onscreentimer import OnScreenTimer +from bastd.actor.spazbot import SpazBotSet, StickyBot +from bastd.gameutils import SharedObjects + +if TYPE_CHECKING: + from typing import Any, Sequence, Union, Callable + + +class UFODiedMessage: + ufo: UFO + """The UFO that was killed.""" + + killerplayer: ba.Player | None + """The ba.Player that killed it (or None).""" + + how: ba.DeathType + """The particular type of death.""" + + def __init__( + self, + ufo: UFO, + killerplayer: ba.Player | None, + how: ba.DeathType, + ): + """Instantiate with given values.""" + self.spazbot = ufo + self.killerplayer = killerplayer + self.how = how + + +class RoboBot(StickyBot): + character = 'B-9000' + default_bomb_type = 'land_mine' + color = (0, 0, 0) + highlight = (3, 3, 3) + + + + +class UFO(ba.Actor): + """ + New AI for Boss + """ + + # pylint: disable=too-many-public-methods + # pylint: disable=too-many-locals + + node: ba.Node + + def __init__(self, hitpoints: int = 5000): + + super().__init__() + shared = SharedObjects.get() + + self.update_callback: Callable[[UFO], Any] | None = None + activity = self.activity + assert isinstance(activity, ba.GameActivity) + + self.platform_material = ba.Material() + self.platform_material.add_actions( + conditions=('they_have_material', shared.footing_material), + actions=( + 'modify_part_collision', 'collide', True)) + self.ice_material = ba.Material() + self.ice_material.add_actions( + actions=('modify_part_collision', 'friction', 0.0)) + + self._player_pts: list[tuple[ba.Vec3, ba.Vec3]] | None = None + self._ufo_update_timer: ba.Timer | None = None + self.last_player_attacked_by: ba.Player | None = None + self.last_attacked_time = 0.0 + self.last_attacked_type: tuple[str, str] | None = None + + self.to_target: ba.Vec3 = ba.Vec3(0, 0, 0) + self.dist = (0, 0, 0) + + self._bots = SpazBotSet() + self.frozen = False + self.y_pos = 3 + self.xz_pos = 1 + self.bot_count = 3 + self.bot_dur_froze = False + + self.hitpoints = hitpoints + self.hitpoints_max = hitpoints + self._width = 240 + self._width_max = 240 + self._height = 35 + self._bar_width = 240 + self._bar_height = 35 + self._bar_tex = self._backing_tex = ba.gettexture('bar') + self._cover_tex = ba.gettexture('uiAtlas') + self._model = ba.getmodel('meterTransparent') + self.bar_posx = -120 + + self._last_hit_time: int | None = None + self.impact_scale = 1.0 + self._num_times_hit = 0 + + self._sucker_mat = ba.Material() + + self.ufo_material = ba.Material() + self.ufo_material.add_actions( + conditions=('they_have_material', + shared.player_material), + actions=(('modify_node_collision', 'collide', True), + ('modify_part_collision', 'physical', True))) + + self.ufo_material.add_actions( + conditions=(('they_have_material', + shared.object_material), 'or', + ('they_have_material', + shared.footing_material), 'or', + ('they_have_material', + self.ufo_material)), + actions=('modify_part_collision', 'physical', False)) + + activity = _ba.get_foreground_host_activity() + with ba.Context(activity): + point = activity.map.get_flag_position(None) + boss_spawn_pos = (point[0], point[1] + 1, point[2]) + + self.node = ba.newnode('prop', delegate=self, attrs={ + 'position': boss_spawn_pos, + 'velocity': (2, 0, 0), + 'color_texture': ba.gettexture('achievementFootballShutout'), + 'model': ba.getmodel('landMine'), + # 'light_model': ba.getmodel('powerupSimple'), + 'model_scale': 3.3, + 'body': 'landMine', + 'body_scale': 3.3, + 'gravity_scale': 0.05, + 'density': 1, + 'reflection': 'soft', + 'reflection_scale': [0.25], + 'shadow_size': 0.1, + 'max_speed': 1.5, + 'is_area_of_interest': + True, + 'materials': [shared.footing_material, shared.object_material]}) + + self.holder = ba.newnode('region', attrs={ + 'position': ( + boss_spawn_pos[0], boss_spawn_pos[1] - 0.25, + boss_spawn_pos[2]), + 'scale': [6, 0.1, 2.5 - 0.1], + 'type': 'box', + 'materials': (self.platform_material, self.ice_material, + shared.object_material)}) + + self.suck_anim = ba.newnode('locator', + owner=self.node, + attrs={'shape': 'circleOutline', + 'position': ( + boss_spawn_pos[0], + boss_spawn_pos[1] - 0.25, + boss_spawn_pos[2]), + 'color': (4, 4, 4), + 'opacity': 1.0, + 'draw_beauty': True, + 'additive': True}) + + def suck_anim(): + ba.animate_array(self.suck_anim, 'position', 3, + {0: ( + self.node.position[0], + self.node.position[1] - 5, + self.node.position[2]), + 0.5: ( + self.node.position[ + 0] + self.to_target.x / 2, + self.node.position[ + 1] + self.to_target.y / 2, + self.node.position[ + 2] + self.to_target.z / 2)}) + + self.suck_timer = ba.Timer(0.5, suck_anim, repeat=True) + + self.blocks = [] + + self._sucker_mat.add_actions( + conditions=( + ('they_have_material', shared.player_material) + ), + actions=( + ('modify_part_collision', 'collide', True), + ('modify_part_collision', 'physical', False), + ('call', 'at_connect', self._levitate) + + )) + + # self.sucker = ba.newnode('region', attrs={ + # 'position': ( + # boss_spawn_pos[0], boss_spawn_pos[1] - 2, boss_spawn_pos[2]), + # 'scale': [2, 10, 2], + # 'type': 'box', + # 'materials': self._sucker_mat, }) + + self.suck = ba.newnode('region', + attrs={'position': ( + boss_spawn_pos[0], boss_spawn_pos[1] - 2, + boss_spawn_pos[2]), + 'scale': [1, 10, 1], + 'type': 'box', + 'materials': [self._sucker_mat]}) + + self.node.connectattr('position', self.holder, 'position') + self.node.connectattr('position', self.suck, 'position') + + ba.animate(self.node, 'model_scale', { + 0: 0, + 0.2: self.node.model_scale * 1.1, + 0.26: self.node.model_scale}) + + self.shield_deco = ba.newnode('shield', owner=self.node, + attrs={'color': (4, 4, 4), + 'radius': 1.2}) + self.node.connectattr('position', self.shield_deco, 'position') + self._scoreboard() + self._update() + self.drop_bomb_timer = ba.Timer(1.5, ba.Call(self._drop_bomb), + repeat=True) + + self.drop_bots_timer = ba.Timer(15.0, ba.Call(self._drop_bots), repeat=True) + + def _drop_bots(self) -> None: + p = self.node.position + if not self.frozen: + for i in range(self.bot_count): + ba.timer( + 1.0 + i, + lambda: self._bots.spawn_bot( + RoboBot, pos=(self.node.position[0], + self.node.position[1] - 1, + self.node.position[2]), spawn_time=0.0 + ), + ) + else: + self.bot_dur_froze = True + + def _drop_bomb(self) -> None: + t = self.to_target + p = self.node.position + if not self.frozen: + if abs(self.dist[0]) < 2 and abs(self.dist[2]) < 2: + Bomb(position=(p[0], p[1] - 0.5, p[2]), + velocity=(t[0] * 5, 0, t[2] * 5), + bomb_type='land_mine').autoretain().arm() + elif self.hitpoints > self.hitpoints_max * 3 / 4: + Bomb(position=(p[0], p[1] - 1.5, p[2]), + velocity=(t[0] * 8, 2, t[2] * 8), + bomb_type='normal').autoretain() + elif self.hitpoints > self.hitpoints_max * 1 / 2: + Bomb(position=(p[0], p[1] - 1.5, p[2]), + velocity=(t[0] * 8, 2, t[2] * 8), + bomb_type='ice').autoretain() + + elif self.hitpoints > self.hitpoints_max * 1 / 4: + Bomb(position=(p[0], p[1] - 1.5, p[2]), + velocity=(t[0] * 15, 2, t[2] * 15), + bomb_type='sticky').autoretain() + else: + Bomb(position=(p[0], p[1] - 1.5, p[2]), + velocity=(t[0] * 15, 2, t[2] * 15), + bomb_type='impact').autoretain() + + def _levitate(self): + node = ba.getcollision().opposingnode + if node.exists(): + p = node.getdelegate(Spaz, True) + + def raise_player(player: ba.Player): + if player.is_alive(): + node = player.node + try: + node.handlemessage("impulse", node.position[0], + node.position[1] + .5, + node.position[2], 0, 5, 0, 3, 10, 0, + 0, 0, 5, 0) + + + except: + pass + + if not self.frozen: + for i in range(7): + ba.timer(0.05 + i / 20, ba.Call(raise_player, p)) + + def on_punched(self, damage: int) -> None: + """Called when this spaz gets punched.""" + + def do_damage(self, msg: Any) -> None: + if not self.node: + return None + + + damage = abs(msg.magnitude) + if msg.hit_type == 'explosion': + damage /= 20 + else: + damage /= 5 + + self.hitpoints -= int(damage) + if self.hitpoints <= 0: + self.handlemessage(ba.DieMessage()) + + def _get_target_player_pt(self) -> tuple[ + ba.Vec3 | None, ba.Vec3 | None]: + """Returns the position and velocity of our target. + + Both values will be None in the case of no target. + """ + assert self.node + botpt = ba.Vec3(self.node.position) + closest_dist: float | None = None + closest_vel: ba.Vec3 | None = None + closest: ba.Vec3 | None = None + assert self._player_pts is not None + for plpt, plvel in self._player_pts: + dist = (plpt - botpt).length() + + # Ignore player-points that are significantly below the bot + # (keeps bots from following players off cliffs). + if (closest_dist is None or dist < closest_dist) and ( + plpt[1] > botpt[1] - 5.0 + ): + closest_dist = dist + closest_vel = plvel + closest = plpt + if closest_dist is not None: + assert closest_vel is not None + assert closest is not None + return ( + ba.Vec3(closest[0], closest[1], closest[2]), + ba.Vec3(closest_vel[0], closest_vel[1], closest_vel[2]), + ) + return None, None + + def set_player_points(self, pts: list[tuple[ba.Vec3, ba.Vec3]]) -> None: + """Provide the spaz-bot with the locations of its enemies.""" + self._player_pts = pts + + def exists(self) -> bool: + return bool(self.node) + + def show_damage_count(self, damage: str, position: Sequence[float], + direction: Sequence[float]) -> None: + """Pop up a damage count at a position in space. + + Category: Gameplay Functions + """ + lifespan = 1.0 + app = ba.app + + # FIXME: Should never vary game elements based on local config. + # (connected clients may have differing configs so they won't + # get the intended results). + do_big = app.ui.uiscale is ba.UIScale.SMALL or app.vr_mode + txtnode = ba.newnode('text', + attrs={ + 'text': damage, + 'in_world': True, + 'h_align': 'center', + 'flatness': 1.0, + 'shadow': 1.0 if do_big else 0.7, + 'color': (1, 0.25, 0.25, 1), + 'scale': 0.035 if do_big else 0.03 + }) + # Translate upward. + tcombine = ba.newnode('combine', owner=txtnode, attrs={'size': 3}) + tcombine.connectattr('output', txtnode, 'position') + v_vals = [] + pval = 0.0 + vval = 0.07 + count = 6 + for i in range(count): + v_vals.append((float(i) / count, pval)) + pval += vval + vval *= 0.5 + p_start = position[0] + p_dir = direction[0] + ba.animate(tcombine, 'input0', + {i[0] * lifespan: p_start + p_dir * i[1] + for i in v_vals}) + p_start = position[1] + p_dir = direction[1] + ba.animate(tcombine, 'input1', + {i[0] * lifespan: p_start + p_dir * i[1] + for i in v_vals}) + p_start = position[2] + p_dir = direction[2] + ba.animate(tcombine, 'input2', + {i[0] * lifespan: p_start + p_dir * i[1] + for i in v_vals}) + ba.animate(txtnode, 'opacity', {0.7 * lifespan: 1.0, lifespan: 0.0}) + ba.timer(lifespan, txtnode.delete) + + def _scoreboard(self) -> None: + self._backing = ba.NodeActor( + ba.newnode('image', + attrs={ + 'position': (self.bar_posx + self._width / 2, -100), + 'scale': (self._width, self._height), + 'opacity': 0.7, + 'color': (0.3, + 0.3, + 0.3), + 'vr_depth': -3, + 'attach': 'topCenter', + 'texture': self._backing_tex + })) + self._bar = ba.NodeActor( + ba.newnode('image', + attrs={ + 'opacity': 1.0, + 'color': (0.5, 0.5, 0.5), + 'attach': 'topCenter', + 'texture': self._bar_tex + })) + self._bar_scale = ba.newnode('combine', + owner=self._bar.node, + attrs={ + 'size': 2, + 'input0': self._bar_width, + 'input1': self._bar_height + }) + self._bar_scale.connectattr('output', self._bar.node, 'scale') + self._bar_position = ba.newnode( + 'combine', + owner=self._bar.node, + attrs={ + 'size': 2, + 'input0': self.bar_posx + self._bar_width / 2, + 'input1': -100 + }) + self._bar_position.connectattr('output', self._bar.node, 'position') + self._cover = ba.NodeActor( + ba.newnode('image', + attrs={ + 'position': (self.bar_posx + 120, -100), + 'scale': + (self._width * 1.15, self._height * 1.6), + 'opacity': 1.0, + 'color': (0.3, + 0.3, + 0.3), + 'vr_depth': 2, + 'attach': 'topCenter', + 'texture': self._cover_tex, + 'model_transparent': self._model + })) + self._score_text = ba.NodeActor( + ba.newnode('text', + attrs={ + 'position': (self.bar_posx + 120, -100), + 'h_attach': 'center', + 'v_attach': 'top', + 'h_align': 'center', + 'v_align': 'center', + 'maxwidth': 130, + 'scale': 0.9, + 'text': '', + 'shadow': 0.5, + 'flatness': 1.0, + 'color': (1, 1, 1, 0.8) + })) + + def _update(self) -> None: + self._score_text.node.text = str(self.hitpoints) + self._bar_width = self.hitpoints * self._width_max / self.hitpoints_max + cur_width = self._bar_scale.input0 + ba.animate(self._bar_scale, 'input0', { + 0.0: cur_width, + 0.1: self._bar_width + }) + cur_x = self._bar_position.input0 + + ba.animate(self._bar_position, 'input0', { + 0.0: cur_x, + 0.1: self.bar_posx + self._bar_width / 2 + }) + + if self.hitpoints > self.hitpoints_max * 3 / 4: + ba.animate_array(self.shield_deco, 'color', 3, + {0: self.shield_deco.color, 0.2: (4, 4, 4)}) + elif self.hitpoints > self.hitpoints_max * 1 / 2: + ba.animate_array(self.shield_deco, 'color', 3, + {0: self.shield_deco.color, 0.2: (3, 3, 5)}) + self.bot_count = 4 + + elif self.hitpoints > self.hitpoints_max * 1 / 4: + ba.animate_array(self.shield_deco, 'color', 3, + {0: self.shield_deco.color, 0.2: (1, 5, 1)}) + self.bot_count = 5 + + else: + ba.animate_array(self.shield_deco, 'color', 3, + {0: self.shield_deco.color, 0.2: (5, 0.2, 0.2)}) + self.bot_count = 6 + + + def update_ai(self) -> None: + """Should be called periodically to update the spaz' AI.""" + # pylint: disable=too-many-branches + # pylint: disable=too-many-statements + # pylint: disable=too-many-locals + if self.update_callback is not None: + if self.update_callback(self): + # Bot has been handled. + return + + if not self.node: + return + + pos = self.node.position + our_pos = ba.Vec3(pos[0], pos[1] - self.y_pos, pos[2]) + + target_pt_raw: ba.Vec3 | None + target_vel: ba.Vec3 | None + + target_pt_raw, target_vel = self._get_target_player_pt() + + try: + dist_raw = (target_pt_raw - our_pos).length() + + target_pt = ( + target_pt_raw + target_vel * dist_raw * 0.3 + ) + except: + return + diff = target_pt - our_pos + # self.dist = diff.length() + self.dist = diff + self.to_target = diff.normalized() + + # p = spaz.node.position + # pt = self.getTargetPosition(p) + # pn = self.node.position + # d = [pt[0] - pn[0], pt[1] - pn[1], pt[2] - pn[2]] + # speed = self.getMaxSpeedByDir(d) + # self.node.velocity = (self.to_target.x, self.to_target.y, self.to_target.z) + if self.hitpoints == 0: + setattr(self.node, 'velocity', + (0, self.to_target.y, 0)) + setattr(self.node, 'extra_acceleration', + (0, self.to_target.y * 80 + 70, + 0)) + else: + setattr(self.node, 'velocity', + (self.to_target.x * self.xz_pos, + self.to_target.y, + self.to_target.z * self.xz_pos)) + setattr(self.node, 'extra_acceleration', + (self.to_target.x * self.xz_pos , + self.to_target.y * 80 + 70, + self.to_target.z * self.xz_pos)) + + def on_expire(self) -> None: + super().on_expire() + + # We're being torn down; release our callback(s) so there's + # no chance of them keeping activities or other things alive. + self.update_callback = None + + def animate_model(self) -> None: + if not self.node: + return None + # ba.animate(self.node, 'model_scale', { + # 0: self.node.model_scale, + # 0.08: self.node.model_scale * 0.9, + # 0.15: self.node.model_scale}) + ba.emitfx(position=self.node.position, + velocity=self.node.velocity, + count=int(6 + random.random() * 10), + scale=0.5, + spread=0.4, + chunk_type='metal') + + def handlemessage(self, msg: Any) -> Any: + # pylint: disable=too-many-branches + assert not self.expired + + if isinstance(msg, ba.HitMessage): + # Don't die on punches (that's annoying). + self.animate_model() + if self.hitpoints != 0: + self.do_damage(msg) + # self.show_damage_msg(msg) + self._update() + + elif isinstance(msg, ba.DieMessage): + if self.node: + self.hitpoints = 0 + self.frozen = True + self.suck_timer = False + self.drop_bomb_timer = False + self.drop_bots_timer = False + + p = self.node.position + + for i in range(6): + def ded_explode(count): + p_x = p[0] + random.uniform(-1, 1) + p_z = p[2] + random.uniform(-1, 1) + if count == 5: + Blast( + position=(p[0], p[1], p[2]), + blast_type='tnt', + blast_radius=5.0).autoretain() + else: + Blast( + position=(p_x, p[1], p_z), + blast_radius=2.0).autoretain() + + ba.timer(0 + i, ba.Call(ded_explode, i)) + + ba.timer(5, self.node.delete) + ba.timer(0.1, self.suck.delete) + ba.timer(0.1, self.suck_anim.delete) + + elif isinstance(msg, ba.OutOfBoundsMessage): + activity = _ba.get_foreground_host_activity() + try: + point = activity.map.get_flag_position(None) + boss_spawn_pos = (point[0], point[1] + 1.5, point[2]) + assert self.node + self.node.position = boss_spawn_pos + except: + self.handlemessage(ba.DieMessage()) + + elif isinstance(msg, ba.FreezeMessage): + if not self.frozen: + self.frozen = True + self.y_pos = -1.5 + self.xz_pos = 0.01 + self.node.reflection_scale = [2] + + + def unfrozen(): + self.frozen = False + if self.bot_dur_froze: + ba.timer(0.1, ba.Call(self._drop_bots)) + self.bot_dur_froze = False + self.y_pos = 3 + self.xz_pos = 1 + self.node.reflection_scale = [0.25] + + + ba.timer(5.0, unfrozen) + + else: + super().handlemessage(msg) + + +class UFOSet: + """A container/controller for one or more ba.SpazBots. + + category: Bot Classes + """ + + def __init__(self) -> None: + """Create a bot-set.""" + + # We spread our bots out over a few lists so we can update + # them in a staggered fashion. + self._ufo_bot_list_count = 5 + self._ufo_bot_add_list = 0 + self._ufo_bot_update_list = 0 + self._ufo_bot_lists: list[list[UFO]] = [ + [] for _ in range(self._ufo_bot_list_count) + ] + self._ufo_spawn_sound = ba.getsound('spawn') + self._ufo_spawning_count = 0 + self._ufo_bot_update_timer: ba.Timer | None = None + self.start_moving() + + def _update(self) -> None: + + # Update one of our bot lists each time through. + # First off, remove no-longer-existing bots from the list. + try: + bot_list = self._ufo_bot_lists[self._ufo_bot_update_list] = [ + b for b in self._ufo_bot_lists[self._ufo_bot_update_list] if b + ] + except Exception: + bot_list = [] + ba.print_exception( + 'Error updating bot list: ' + + str(self._ufo_bot_lists[self._ufo_bot_update_list]) + ) + self._bot_update_list = ( + self._ufo_bot_update_list + 1 + ) % self._ufo_bot_list_count + + # Update our list of player points for the bots to use. + player_pts = [] + for player in ba.getactivity().players: + assert isinstance(player, ba.Player) + try: + # TODO: could use abstracted player.position here so we + # don't have to assume their actor type, but we have no + # abstracted velocity as of yet. + if player.is_alive(): + assert isinstance(player.actor, UFO) + assert player.actor.node + player_pts.append( + ( + ba.Vec3(player.actor.node.position), + ba.Vec3(player.actor.node.velocity), + ) + ) + except Exception: + ba.print_exception('Error on bot-set _update.') + + for bot in bot_list: + bot.set_player_points(player_pts) + bot.update_ai() + + def start_moving(self) -> None: + """Start processing bot AI updates so they start doing their thing.""" + self._ufo_bot_update_timer = ba.Timer( + 0.05, ba.WeakCall(self._update), repeat=True + ) + + def spawn_bot( + self, + bot_type: type[UFO], + pos: Sequence[float], + spawn_time: float = 3.0, + on_spawn_call: Callable[[UFO], Any] | None = None, + ) -> None: + """Spawn a bot from this set.""" + from bastd.actor import spawner + + spawner.Spawner( + pt=pos, + spawn_time=spawn_time, + send_spawn_message=False, + spawn_callback=ba.Call( + self._spawn_bot, bot_type, pos, on_spawn_call + ), + ) + self._ufo_spawning_count += 1 + + def _spawn_bot( + self, + bot_type: type[UFO], + pos: Sequence[float], + on_spawn_call: Callable[[UFO], Any] | None, + ) -> None: + spaz = bot_type() + ba.playsound(self._ufo_spawn_sound, position=pos) + assert spaz.node + spaz.node.handlemessage('flash') + spaz.node.is_area_of_interest = False + spaz.handlemessage(ba.StandMessage(pos, random.uniform(0, 360))) + self.add_bot(spaz) + self._ufo_spawning_count -= 1 + if on_spawn_call is not None: + on_spawn_call(spaz) + + def add_bot(self, bot: UFO) -> None: + """Add a ba.SpazBot instance to the set.""" + self._ufo_bot_lists[self._ufo_bot_add_list].append(bot) + self._ufo_bot_add_list = ( + self._ufo_bot_add_list + 1) % self._ufo_bot_list_count + + def have_living_bots(self) -> bool: + """Return whether any bots in the set are alive or spawning.""" + return self._ufo_spawning_count > 0 or any( + any(b.is_alive() for b in l) for l in self._ufo_bot_lists + ) + + def get_living_bots(self) -> list[UFO]: + """Get the living bots in the set.""" + bots: list[UFO] = [] + for botlist in self._ufo_bot_lists: + for bot in botlist: + if bot.is_alive(): + bots.append(bot) + return bots + + def clear(self) -> None: + """Immediately clear out any bots in the set.""" + + # Don't do this if the activity is shutting down or dead. + activity = ba.getactivity(doraise=False) + if activity is None or activity.expired: + return + + for i, bot_list in enumerate(self._ufo_bot_lists): + for bot in bot_list: + bot.handlemessage(ba.DieMessage(immediate=True)) + self._ufo_bot_lists[i] = [] + + +class Player(ba.Player['Team']): + """Our player type for this game.""" + + +class Team(ba.Team[Player]): + """Our team type for this game.""" + + +# ba_meta export game +class UFOightGame(ba.TeamGameActivity[Player, Team]): + """ + A co-op game where you try to defeat UFO Boss + as fast as possible + """ + + name = 'UFO Fight' + description = 'REal Boss Fight?' + scoreconfig = ba.ScoreConfig( + label='Time', scoretype=ba.ScoreType.MILLISECONDS, lower_is_better=True + ) + default_music = ba.MusicType.TO_THE_DEATH + + @classmethod + def get_supported_maps(cls, sessiontype: type[ba.Session]) -> list[str]: + # For now we're hard-coding spawn positions and whatnot + # so we need to be sure to specify that we only support + # a specific map. + return ['Football Stadium'] + + @classmethod + def supports_session_type(cls, sessiontype: type[ba.Session]) -> bool: + # We currently support Co-Op only. + return issubclass(sessiontype, ba.CoopSession) + + # In the constructor we should load any media we need/etc. + # ...but not actually create anything yet. + def __init__(self, settings: dict): + super().__init__(settings) + self._winsound = ba.getsound('score') + self._won = False + self._timer: OnScreenTimer | None = None + self._bots = UFOSet() + self._preset = str(settings['preset']) + self._credit = ba.newnode('text', + attrs={ + 'v_attach': 'bottom', + 'h_align': 'center', + 'color': (0.4, 0.4, 0.4), + 'flatness': 0.5, + 'shadow': 0.5, + 'position': (0, 20), + 'scale': 0.7, + 'text': 'By Cross Joy' + }) + + + + def on_transition_in(self) -> None: + super().on_transition_in() + gnode = ba.getactivity().globalsnode + gnode.tint = (0.42, 0.55, 0.66) + + # Called when our game actually begins. + def on_begin(self) -> None: + super().on_begin() + self.setup_standard_powerup_drops() + + + + # In pro mode there's no powerups. + + # Make our on-screen timer and start it roughly when our bots appear. + self._timer = OnScreenTimer() + ba.timer(4.0, self._timer.start) + + def checker(): + if not self._won: + self.timer = ba.Timer(0.1, self._check_if_won, repeat=True) + + ba.timer(10, checker) + activity = _ba.get_foreground_host_activity() + + point = activity.map.get_flag_position(None) + boss_spawn_pos = (point[0], point[1] + 1.5, point[2]) + + # Spawn some baddies. + ba.timer( + 1.0, + lambda: self._bots.spawn_bot( + UFO, pos=boss_spawn_pos, spawn_time=3.0 + ), + ) + + # Called for each spawning player. + + def _check_if_won(self) -> None: + # Simply end the game if there's no living bots. + # FIXME: Should also make sure all bots have been spawned; + # if spawning is spread out enough that we're able to kill + # all living bots before the next spawns, it would incorrectly + # count as a win. + if not self._bots.have_living_bots(): + self.timer = False + self._won = True + self.end_game() + + # Called for miscellaneous messages. + def handlemessage(self, msg: Any) -> Any: + + # A player has died. + if isinstance(msg, ba.PlayerDiedMessage): + player = msg.getplayer(Player) + self.stats.player_was_killed(player) + ba.timer(0.1, self._checkroundover) + + # A spaz-bot has died. + elif isinstance(msg, UFODiedMessage): + # Unfortunately the ufo will always tell us there are living + # bots if we ask here (the currently-dying bot isn't officially + # marked dead yet) ..so lets push a call into the event loop to + # check once this guy has finished dying. + ba.pushcall(self._check_if_won) + + # Let the base class handle anything we don't. + else: + return super().handlemessage(msg) + return None + + # When this is called, we should fill out results and end the game + # *regardless* of whether is has been won. (this may be called due + # to a tournament ending or other external reason). + + def _checkroundover(self) -> None: + """End the round if conditions are met.""" + if not any(player.is_alive() for player in self.teams[0].players): + self.end_game() + + def end_game(self) -> None: + + # Stop our on-screen timer so players can see what they got. + assert self._timer is not None + self._timer.stop() + + results = ba.GameResults() + + # If we won, set our score to the elapsed time in milliseconds. + # (there should just be 1 team here since this is co-op). + # ..if we didn't win, leave scores as default (None) which means + # we lost. + if self._won: + elapsed_time_ms = int((ba.time() - self._timer.starttime) * 1000.0) + ba.cameraflash() + ba.playsound(self._winsound) + for team in self.teams: + for player in team.players: + if player.actor: + player.actor.handlemessage(ba.CelebrateMessage()) + results.set_team_score(team, elapsed_time_ms) + + # Ends the activity. + self.end(results) + + +# ba_meta export plugin +class MyUFOFightLevel(ba.Plugin): + + def on_app_running(self) -> None: + ba.app.add_coop_practice_level( + ba.Level( + name='The UFO Fight', + displayname='${GAME}', + gametype=UFOightGame, + settings={'preset': 'regular'}, + preview_texture_name='footballStadiumPreview', + ) + ) + diff --git a/plugins/minigames/yeeting_party.py b/plugins/minigames/yeeting_party.py new file mode 100644 index 00000000..8ae67214 --- /dev/null +++ b/plugins/minigames/yeeting_party.py @@ -0,0 +1,222 @@ +#Made by your friend: @[Just] Freak#4999 + +# ba_meta require api 7 +from __future__ import annotations + +from typing import TYPE_CHECKING + +import ba +from bastd.actor.playerspaz import PlayerSpaz +from bastd.actor.scoreboard import Scoreboard + +if TYPE_CHECKING: + from typing import Any, Type, List, Dict, Tuple, Union, Sequence, Optional + + +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 + + +# ba_meta export game +class BoxingGame(ba.TeamGameActivity[Player, Team]): + """A game of yeeting people out of map""" + + name = 'Yeeting Party!' + description = 'Yeet your enemies out of the map' + + # Print messages when players die since it matters here. + announce_player_deaths = True + + @classmethod + def get_available_settings( + cls, sessiontype: Type[ba.Session]) -> List[ba.Setting]: + settings = [ + ba.IntSetting( + 'Kills to Win Per Player', + 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', 4.0), + ], + default=1.0, + ), + ba.BoolSetting('Epic Mode', default=False), + ] + + # In teams mode, a suicide gives a point to the other team, but in + # free-for-all it subtracts from your own score. By default we clamp + # this at zero to benefit new players, but pro players might like to + # be able to go negative. (to avoid a strategy of just + # suiciding until you get a good drop) + if issubclass(sessiontype, ba.FreeForAllSession): + settings.append( + ba.BoolSetting('Allow Negative Scores', default=False)) + + return settings + + @classmethod + def supports_session_type(cls, sessiontype: Type[ba.Session]) -> bool: + return (issubclass(sessiontype, ba.DualTeamSession) + or issubclass(sessiontype, ba.FreeForAllSession)) + + @classmethod + def get_supported_maps(cls, sessiontype: Type[ba.Session]) -> List[str]: + return ['Bridgit', 'Rampage', 'Monkey Face'] + + def __init__(self, settings: dict): + super().__init__(settings) + self._scoreboard = Scoreboard() + self._score_to_win: Optional[int] = None + self._dingsound = ba.getsound('dingSmall') + self._epic_mode = bool(settings['Epic Mode']) + self._kills_to_win_per_player = int( + settings['Kills to Win Per Player']) + self._time_limit = float(settings['Time Limit']) + self._allow_negative_scores = bool( + settings.get('Allow Negative Scores', False)) + + # Base class overrides. + self.slow_motion = self._epic_mode + self.default_music = (ba.MusicType.EPIC if self._epic_mode else + ba.MusicType.TO_THE_DEATH) + + def get_instance_description(self) -> Union[str, Sequence]: + return 'Yeet ${ARG1} enemies out of the map!', self._score_to_win + + def get_instance_description_short(self) -> Union[str, Sequence]: + return 'yeet ${ARG1} enemies', self._score_to_win + + def on_team_join(self, team: Team) -> None: + if self.has_begun(): + self._update_scoreboard() + def getRandomPowerupPoint(self) -> None: + myMap = self.map.getname() + if myMap == 'Doom Shroom': + while True: + x = random.uniform(-1.0,1.0) + y = random.uniform(-1.0,1.0) + if x*x+y*y < 1.0: break + return ((8.0*x,2.5,-3.5+5.0*y)) + elif myMap == 'Rampage': + x = random.uniform(-6.0,7.0) + y = random.uniform(-6.0,-2.5) + return ((x, 5.2, y)) + else: + x = random.uniform(-5.0,5.0) + y = random.uniform(-6.0,0.0) + return ((x, 8.0, y)) + + def on_begin(self) -> None: + super().on_begin() + ba.screenmessage("start Yeeting",color = (0.2,1,1)) + self.setup_standard_time_limit(self._time_limit) + # Base kills needed to win on the size of the largest team. + self._score_to_win = (self._kills_to_win_per_player * + max(1, max(len(t.players) for t in self.teams))) + self._update_scoreboard() + + def spawn_player(self, player: Player) -> ba.Actor: + + spaz = self.spawn_player_spaz(player) + + # Let's reconnect this player's controls to this + # spaz but *without* the ability to attack or pick stuff up. + spaz.connect_controls_to_player(enable_punch=False, + enable_jump=True, + enable_bomb=False, + enable_pickup=True) + return spaz + + def handlemessage(self, msg: Any) -> Any: + + if isinstance(msg, ba.PlayerDiedMessage): + + # Augment standard behavior. + super().handlemessage(msg) + + player = msg.getplayer(Player) + self.respawn_player(player) + + killer = msg.getkillerplayer(Player) + if killer is None: + return None + + # Handle team-kills. + if killer.team is player.team: + + # In free-for-all, killing yourself loses you a point. + if isinstance(self.session, ba.FreeForAllSession): + new_score = player.team.score - 1 + if not self._allow_negative_scores: + new_score = max(0, new_score) + player.team.score = new_score + + # In teams-mode it gives a point to the other team. + else: + ba.playsound(self._dingsound) + for team in self.teams: + if team is not killer.team: + team.score += 1 + + # Killing someone on another team nets a kill. + else: + killer.team.score += 1 + ba.playsound(self._dingsound) + + # In FFA show scores since its hard to find on the scoreboard. + if isinstance(killer.actor, PlayerSpaz) and killer.actor: + killer.actor.set_score_text(str(killer.team.score) + '/' + + str(self._score_to_win), + color=killer.team.color, + flash=True) + + self._update_scoreboard() + + # If someone has won, set a timer to end shortly. + # (allows the dust to clear and draws to occur if deaths are + # close enough) + assert self._score_to_win is not None + if any(team.score >= self._score_to_win for team in self.teams): + ba.timer(0.5, self.end_game) + + else: + return super().handlemessage(msg) + return None + + def _update_scoreboard(self) -> None: + for team in self.teams: + self._scoreboard.set_team_value(team, team.score, + self._score_to_win) + + def end_game(self) -> None: + results = ba.GameResults() + for team in self.teams: + results.set_team_score(team, team.score) + self.end(results=results) From 2ac90c867700e5b6fb1240f14f26c66461c23695 Mon Sep 17 00:00:00 2001 From: Loup-Garou911XD Date: Mon, 15 May 2023 10:58:00 +0000 Subject: [PATCH 0442/1464] [ci] auto-format --- plugins/minigames/arms_race.py | 26 +- plugins/minigames/collector.py | 1149 +++++++++++++------------ plugins/minigames/dodge_the_ball.py | 711 +++++++-------- plugins/minigames/invisible_one.py | 7 +- plugins/minigames/last_punch_stand.py | 451 +++++----- plugins/minigames/quake.py | 25 +- plugins/minigames/sleep_race.py | 52 +- plugins/minigames/snake.py | 93 +- plugins/minigames/ufo_fight.py | 51 +- plugins/minigames/yeeting_party.py | 26 +- 10 files changed, 1301 insertions(+), 1290 deletions(-) diff --git a/plugins/minigames/arms_race.py b/plugins/minigames/arms_race.py index 13f32b79..728f7c0e 100644 --- a/plugins/minigames/arms_race.py +++ b/plugins/minigames/arms_race.py @@ -1,10 +1,9 @@ -#Ported by: Freaku / @[Just] Freak#4999 +# Ported by: Freaku / @[Just] Freak#4999 -#Join BCS: +# Join BCS: # https://discord.gg/ucyaesh - # ba_meta require api 7 from __future__ import annotations @@ -18,7 +17,6 @@ from typing import Any, Type, List, Dict, Tuple, Union, Sequence, Optional - class State: def __init__(self, bomb=None, grab=False, punch=False, curse=False, required=False, final=False, name=''): self.bomb = bomb @@ -35,8 +33,8 @@ def __init__(self, bomb=None, grab=False, punch=False, curse=False, required=Fal def apply(self, spaz): spaz.disconnect_controls_from_player() spaz.connect_controls_to_player(enable_punch=self.punch, - enable_bomb=self.bomb, - enable_pickup=self.grab) + enable_bomb=self.bomb, + enable_pickup=self.grab) if self.curse: spaz.curse_time = -1 spaz.curse() @@ -48,16 +46,18 @@ def get_setting(self): return (self.name) -states = [ State(bomb='normal', name='Basic Bombs'), - State(bomb='ice', name='Frozen Bombs'), - State(bomb='sticky', name='Sticky Bombs'), - State(bomb='impact', name='Impact Bombs'), - State(grab=True, name='Grabbing only'), - State(punch=True, name='Punching only'), - State(curse=True, name='Cursed', final=True) ] +states = [State(bomb='normal', name='Basic Bombs'), + State(bomb='ice', name='Frozen Bombs'), + State(bomb='sticky', name='Sticky Bombs'), + State(bomb='impact', name='Impact Bombs'), + State(grab=True, name='Grabbing only'), + State(punch=True, name='Punching only'), + State(curse=True, name='Cursed', final=True)] + class Player(ba.Player['Team']): """Our player type for this game.""" + def __init__(self): self.state = None diff --git a/plugins/minigames/collector.py b/plugins/minigames/collector.py index 1a22bda3..0f9bbc34 100644 --- a/plugins/minigames/collector.py +++ b/plugins/minigames/collector.py @@ -40,603 +40,604 @@ from bastd.gameutils import SharedObjects if TYPE_CHECKING: - from typing import Any, Sequence + from typing import Any, Sequence lang = ba.app.lang.language if lang == 'Spanish': - name = 'Coleccionista' - description = ('Elimina a tus oponentes para robar sus cápsulas.\n' - '¡Recolecta y anota en el punto de depósito!') - description_ingame = 'Obtén ${ARG1} cápsulas de tus enemigos.' - description_short = 'colecciona ${ARG1} cápsulas' - tips = [( - '¡Si tu oponente cae fuera del mapa, sus cápsulas desapareceran!\n' - 'No intestes matar a tus enemigos arrojándolos al vacio.'), - 'No te apresures. ¡Puedes perder tus cápsulas rápidamente!', - ('¡No dejes que el jugador con más cápsulas anote!\n' - '¡Intenta atraparlo si puedes!'), - ('¡Las Capsulas de la Suerte te dan 4 cápsulas en lugar de 2' - 'y tienen un 8% de probabilidad de aparecer después de matar'), - ('¡No te quedes en un solo lugar! Muevete más rapido que tu enemigo, ' - '¡con suerte conseguirás algunas cápsulas!'), - ] - capsules_to_win = 'Cápsulas para Ganar' - capsules_death = 'Cápsulas al Morir' - lucky_capsules = 'Cápsulas de la Suerte' - bonus = '¡BONUS!' - full_capacity = '¡Capacidad Completa!' + name = 'Coleccionista' + description = ('Elimina a tus oponentes para robar sus cápsulas.\n' + '¡Recolecta y anota en el punto de depósito!') + description_ingame = 'Obtén ${ARG1} cápsulas de tus enemigos.' + description_short = 'colecciona ${ARG1} cápsulas' + tips = [( + '¡Si tu oponente cae fuera del mapa, sus cápsulas desapareceran!\n' + 'No intestes matar a tus enemigos arrojándolos al vacio.'), + 'No te apresures. ¡Puedes perder tus cápsulas rápidamente!', + ('¡No dejes que el jugador con más cápsulas anote!\n' + '¡Intenta atraparlo si puedes!'), + ('¡Las Capsulas de la Suerte te dan 4 cápsulas en lugar de 2' + 'y tienen un 8% de probabilidad de aparecer después de matar'), + ('¡No te quedes en un solo lugar! Muevete más rapido que tu enemigo, ' + '¡con suerte conseguirás algunas cápsulas!'), + ] + capsules_to_win = 'Cápsulas para Ganar' + capsules_death = 'Cápsulas al Morir' + lucky_capsules = 'Cápsulas de la Suerte' + bonus = '¡BONUS!' + full_capacity = '¡Capacidad Completa!' else: - name = 'Collector' - description = ('Kill your opponents to steal their Capsules.\n' - 'Collect them and score at the Deposit point!') - description_ingame = 'Score ${ARG1} capsules from your enemies.' - description_short = 'collect ${ARG1} capsules' - tips = [( - 'Making you opponent fall down the pit makes his Capsules wasted!\n' - 'Try not to kill enemies by throwing them off the cliff.'), - 'Don\'t be too reckless. You can lose your loot quite quickly!', - ('Don\'t let the leading player score his Capsules ' - 'at the Deposit Point!\nTry to catch him if you can!'), - ('Lucky Capsules give 4 to your inventory and they have 8% chance ' - 'of spawning after kill!'), - ('Don\'t camp in one place! Make your move first, ' - 'so hopefully you get some dough!'), - ] - capsules_to_win = 'Capsules to Win' - capsules_death = 'Capsules on Death' - lucky_capsules = 'Allow Lucky Capsules' - bonus = 'BONUS!' - full_capacity = 'Full Capacity!' + name = 'Collector' + description = ('Kill your opponents to steal their Capsules.\n' + 'Collect them and score at the Deposit point!') + description_ingame = 'Score ${ARG1} capsules from your enemies.' + description_short = 'collect ${ARG1} capsules' + tips = [( + 'Making you opponent fall down the pit makes his Capsules wasted!\n' + 'Try not to kill enemies by throwing them off the cliff.'), + 'Don\'t be too reckless. You can lose your loot quite quickly!', + ('Don\'t let the leading player score his Capsules ' + 'at the Deposit Point!\nTry to catch him if you can!'), + ('Lucky Capsules give 4 to your inventory and they have 8% chance ' + 'of spawning after kill!'), + ('Don\'t camp in one place! Make your move first, ' + 'so hopefully you get some dough!'), + ] + capsules_to_win = 'Capsules to Win' + capsules_death = 'Capsules on Death' + lucky_capsules = 'Allow Lucky Capsules' + bonus = 'BONUS!' + full_capacity = 'Full Capacity!' class FlagState(Enum): - """States our single flag can be in.""" + """States our single flag can be in.""" - NEW = 0 - UNCONTESTED = 1 - CONTESTED = 2 - HELD = 3 + NEW = 0 + UNCONTESTED = 1 + CONTESTED = 2 + HELD = 3 class Player(ba.Player['Team']): - """Our player type for this game.""" + """Our player type for this game.""" - def __init__(self) -> None: - self.time_at_flag = 0 - self.capsules = 0 - self.light = None + def __init__(self) -> None: + self.time_at_flag = 0 + self.capsules = 0 + self.light = None class Team(ba.Team[Player]): - """Our team type for this game.""" + """Our team type for this game.""" - def __init__(self) -> None: - self.score = 0 + def __init__(self) -> None: + self.score = 0 # ba_meta export game class CollectorGame(ba.TeamGameActivity[Player, Team]): - name = name - description = description - tips = tips - - # Print messages when players die since it matters here. - announce_player_deaths = True - - @classmethod - def get_available_settings( - cls, sessiontype: type[ba.Session] - ) -> list[ba.Setting]: - settings = [ - ba.IntSetting( - capsules_to_win, - min_value=1, - default=10, - increment=1, - ), - ba.IntSetting( - capsules_death, - min_value=1, - max_value=10, - default=2, - 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', 4.0), - ], - default=1.0, - ), - ba.BoolSetting(lucky_capsules, default=True), - ba.BoolSetting('Epic Mode', default=False), - ] - return settings - - @classmethod - def supports_session_type(cls, sessiontype: type[ba.Session]) -> bool: - return issubclass(sessiontype, ba.DualTeamSession) or issubclass( - sessiontype, ba.FreeForAllSession - ) - - @classmethod - def get_supported_maps(cls, sessiontype: type[ba.Session]) -> list[str]: - return ba.getmaps('keep_away') - - def __init__(self, settings: dict): - super().__init__(settings) - shared = SharedObjects.get() - self._scoreboard = Scoreboard() - self._score_to_win: int | None = None - self._swipsound = ba.getsound('swip') - self._lucky_sound = ba.getsound('ding') - - self._flag_pos: Sequence[float] | None = None - self._flag_state: FlagState | None = None - self._flag: Flag | None = None - self._flag_light: ba.Node | None = None - self._scoring_team: weakref.ref[Team] | None = None - self._time_limit = float(settings['Time Limit']) - self._epic_mode = bool(settings['Epic Mode']) - - self._capsules_to_win = int(settings[capsules_to_win]) - self._capsules_death = int(settings[capsules_death]) - self._lucky_capsules = bool(settings[lucky_capsules]) - self._capsules: list[Any] = [] - - self._capsule_model = ba.getmodel('bomb') - self._capsule_tex = ba.gettexture('bombColor') - self._capsule_lucky_tex = ba.gettexture('bombStickyColor') - self._collect_sound = ba.getsound('powerup01') - self._lucky_collect_sound = ba.getsound('cashRegister2') - - self._capsule_material = ba.Material() - self._capsule_material.add_actions( - conditions=('they_have_material', shared.player_material), - actions=('call', 'at_connect', self._on_capsule_player_collide), - ) - - self._flag_region_material = ba.Material() - self._flag_region_material.add_actions( - conditions=('they_have_material', shared.player_material), - actions=( - ('modify_part_collision', 'collide', True), - ('modify_part_collision', 'physical', False), - ( - 'call', - 'at_connect', - ba.Call(self._handle_player_flag_region_collide, True), - ), - ( - 'call', - 'at_disconnect', - ba.Call(self._handle_player_flag_region_collide, False), - ), - ), - ) - - # Base class overrides. - self.slow_motion = self._epic_mode - self.default_music = ( - ba.MusicType.EPIC if self._epic_mode else ba.MusicType.SCARY - ) - - def get_instance_description(self) -> str | Sequence: - return description_ingame, self._score_to_win - - def get_instance_description_short(self) -> str | Sequence: - return description_short, self._score_to_win - - def create_team(self, sessionteam: ba.SessionTeam) -> Team: - return Team() - - def on_team_join(self, team: Team) -> None: - self._update_scoreboard() - - def on_begin(self) -> None: - super().on_begin() - shared = SharedObjects.get() - self.setup_standard_time_limit(self._time_limit) - self.setup_standard_powerup_drops() - - # Base kills needed to win on the size of the largest team. - self._score_to_win = self._capsules_to_win * max( - 1, max(len(t.players) for t in self.teams) - ) - self._update_scoreboard() - - if isinstance(self.session, ba.FreeForAllSession): - self._flag_pos = self.map.get_flag_position(random.randint(0, 1)) - else: - self._flag_pos = self.map.get_flag_position(None) - - ba.timer(1.0, self._tick, repeat=True) - self._flag_state = FlagState.NEW - Flag.project_stand(self._flag_pos) - self._flag = Flag( - position=self._flag_pos, touchable=False, color=(1, 1, 1) - ) - self._flag_light = ba.newnode( - 'light', - attrs={ - 'position': self._flag_pos, - 'intensity': 0.2, - 'height_attenuated': False, - 'radius': 0.4, - 'color': (0.2, 0.2, 0.2), - }, - ) - # Flag region. - flagmats = [self._flag_region_material, shared.region_material] - ba.newnode( - 'region', - attrs={ - 'position': self._flag_pos, - 'scale': (1.8, 1.8, 1.8), - 'type': 'sphere', - 'materials': flagmats, - }, - ) - self._update_flag_state() - - def _tick(self) -> None: - self._update_flag_state() - - if self._scoring_team is None: - scoring_team = None - else: - scoring_team = self._scoring_team() - - if not scoring_team: - return - - if isinstance(self.session, ba.FreeForAllSession): - players = self.players - else: - players = scoring_team.players - - for player in players: - if player.time_at_flag > 0: - self.stats.player_scored( - player, 3, screenmessage=False, display=False - ) - if player.capsules > 0: - if self._flag_state != FlagState.HELD: - return - if scoring_team.score >= self._score_to_win: - return - - player.capsules -= 1 - scoring_team.score += 1 - self._handle_capsule_storage(( - self._flag_pos[0], - self._flag_pos[1]+1, - self._flag_pos[2] - ), player) - ba.playsound( - self._collect_sound, - 0.8, - position=self._flag_pos) - - self._update_scoreboard() - if player.capsules > 0: - assert self._flag is not None - self._flag.set_score_text( - str(self._score_to_win - scoring_team.score)) - - # winner - if scoring_team.score >= self._score_to_win: - self.end_game() - - def end_game(self) -> None: - results = ba.GameResults() - for team in self.teams: - results.set_team_score(team, team.score) - self.end(results=results, announce_delay=0) - - def _update_flag_state(self) -> None: - holding_teams = set( - player.team for player in self.players if player.time_at_flag - ) - prev_state = self._flag_state - assert self._flag_light - assert self._flag is not None - assert self._flag.node - if len(holding_teams) > 1: - self._flag_state = FlagState.CONTESTED - self._scoring_team = None - self._flag_light.color = (0.6, 0.6, 0.1) - self._flag.node.color = (1.0, 1.0, 0.4) - elif len(holding_teams) == 1: - holding_team = list(holding_teams)[0] - self._flag_state = FlagState.HELD - self._scoring_team = weakref.ref(holding_team) - self._flag_light.color = ba.normalized_color(holding_team.color) - self._flag.node.color = holding_team.color - else: - self._flag_state = FlagState.UNCONTESTED - self._scoring_team = None - self._flag_light.color = (0.2, 0.2, 0.2) - self._flag.node.color = (1, 1, 1) - if self._flag_state != prev_state: - ba.playsound(self._swipsound) - - def _handle_player_flag_region_collide(self, colliding: bool) -> None: - try: - spaz = ba.getcollision().opposingnode.getdelegate(PlayerSpaz, True) - except ba.NotFoundError: - return - - if not spaz.is_alive(): - return - - player = spaz.getplayer(Player, True) - - # Different parts of us can collide so a single value isn't enough - # also don't count it if we're dead (flying heads shouldn't be able to - # win the game :-) - if colliding and player.is_alive(): - player.time_at_flag += 1 - else: - player.time_at_flag = max(0, player.time_at_flag - 1) - - self._update_flag_state() - - def _update_scoreboard(self) -> None: - for team in self.teams: - self._scoreboard.set_team_value( - team, team.score, self._score_to_win - ) - - def _drop_capsule(self, player: Player) -> None: - pt = player.node.position - - # Throw out capsules that the victim has + 2 more to keep the game running - for i in range(player.capsules + self._capsules_death): - # How far from each other these capsules should spawn - w = 0.6 - # How much these capsules should fly after spawning - s = 0.005 - (player.capsules * 0.01) - self._capsules.append( - Capsule( - position=(pt[0] + random.uniform(-w, w), - pt[1] + 0.75 + random.uniform(-w, w), - pt[2]), - velocity=(random.uniform(-s, s), - random.uniform(-s, s), - random.uniform(-s, s)), - lucky=False)) - if random.randint(1, 12) == 1 and self._lucky_capsules: - # How far from each other these capsules should spawn - w = 0.6 - # How much these capsules should fly after spawning - s = 0.005 - self._capsules.append( - Capsule( - position=(pt[0] + random.uniform(-w, w), - pt[1] + 0.75 + random.uniform(-w, w), - pt[2]), - velocity=(random.uniform(-s, s), - random.uniform(-s, s), - random.uniform(-s, s)), - lucky=True)) - - def _on_capsule_player_collide(self) -> None: - if self.has_ended(): - return - collision = ba.getcollision() - - # Be defensive here; we could be hitting the corpse of a player - # who just left/etc. - try: - capsule = collision.sourcenode.getdelegate(Capsule, True) - player = collision.opposingnode.getdelegate( - PlayerSpaz, True - ).getplayer(Player, True) - except ba.NotFoundError: - return - - if not player.is_alive(): - return - - if capsule.node.color_texture == self._capsule_lucky_tex: - player.capsules += 4 - PopupText( - bonus, - color=(1, 1, 0), - scale=1.5, - position=capsule.node.position - ).autoretain() - ba.playsound( - self._lucky_collect_sound, - 1.0, - position=capsule.node.position) - ba.emitfx( - position=capsule.node.position, - velocity=(0, 0, 0), - count=int(6.4+random.random()*24), - scale=1.2, - spread=2.0, - chunk_type='spark'); - ba.emitfx( - position=capsule.node.position, - velocity=(0, 0, 0), - count=int(4.0+random.random()*6), - emit_type='tendrils'); - else: - player.capsules += 1 - ba.playsound( - self._collect_sound, - 0.6, - position=capsule.node.position) - # create a flash - light = ba.newnode( - 'light', - attrs={ - 'position': capsule.node.position, - 'height_attenuated': False, - 'radius': 0.1, - 'color': (1, 1, 0)}) - - # Create a short text informing about your inventory - self._handle_capsule_storage(player.position, player) - - ba.animate(light, 'intensity', { - 0: 0, - 0.1: 0.5, - 0.2: 0 - }, loop=False) - ba.timer(0.2, light.delete) - capsule.handlemessage(ba.DieMessage()) - - def _update_player_light(self, player: Player, capsules: int) -> None: - if player.light: - intensity = 0.04 * capsules - ba.animate(player.light, 'intensity', { - 0.0: player.light.intensity, - 0.1: intensity - }) - def newintensity(): - player.light.intensity = intensity - ba.timer(0.1, newintensity) - else: - player.light = ba.newnode( - 'light', - attrs={ - 'height_attenuated': False, - 'radius': 0.2, - 'intensity': 0.0, - 'color': (0.2, 1, 0.2) - }) - player.node.connectattr('position', player.light, 'position') - - def _handle_capsule_storage(self, pos: float, player: Player) -> None: - capsules = player.capsules - text = str(capsules) - scale = 1.75 + (0.02 * capsules) - if capsules > 10: - player.capsules = 10 - text = full_capacity - color = (1, 0.85, 0) - elif capsules > 7: - color = (1, 0, 0) - scale = 2.4 - elif capsules > 5: - color = (1, 0.4, 0.4) - scale = 2.1 - elif capsules > 3: - color = (1, 1, 0.4) - scale = 2.0 - else: - color = (1, 1, 1) - scale = 1.9 - PopupText( - text, - color=color, - scale=scale, - position=(pos[0], pos[1]-1, pos[2]) - ).autoretain() - self._update_player_light(player, capsules) - - def handlemessage(self, msg: Any) -> Any: - if isinstance(msg, ba.PlayerDiedMessage): - super().handlemessage(msg) # Augment default. - # No longer can count as time_at_flag once dead. - player = msg.getplayer(Player) - player.time_at_flag = 0 - self._update_flag_state() - self._drop_capsule(player) - player.capsules = 0 - self._update_player_light(player, 0) - self.respawn_player(player) - else: - return super().handlemessage(msg) + name = name + description = description + tips = tips + + # Print messages when players die since it matters here. + announce_player_deaths = True + + @classmethod + def get_available_settings( + cls, sessiontype: type[ba.Session] + ) -> list[ba.Setting]: + settings = [ + ba.IntSetting( + capsules_to_win, + min_value=1, + default=10, + increment=1, + ), + ba.IntSetting( + capsules_death, + min_value=1, + max_value=10, + default=2, + 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', 4.0), + ], + default=1.0, + ), + ba.BoolSetting(lucky_capsules, default=True), + ba.BoolSetting('Epic Mode', default=False), + ] + return settings + + @classmethod + def supports_session_type(cls, sessiontype: type[ba.Session]) -> bool: + return issubclass(sessiontype, ba.DualTeamSession) or issubclass( + sessiontype, ba.FreeForAllSession + ) + + @classmethod + def get_supported_maps(cls, sessiontype: type[ba.Session]) -> list[str]: + return ba.getmaps('keep_away') + + def __init__(self, settings: dict): + super().__init__(settings) + shared = SharedObjects.get() + self._scoreboard = Scoreboard() + self._score_to_win: int | None = None + self._swipsound = ba.getsound('swip') + self._lucky_sound = ba.getsound('ding') + + self._flag_pos: Sequence[float] | None = None + self._flag_state: FlagState | None = None + self._flag: Flag | None = None + self._flag_light: ba.Node | None = None + self._scoring_team: weakref.ref[Team] | None = None + self._time_limit = float(settings['Time Limit']) + self._epic_mode = bool(settings['Epic Mode']) + + self._capsules_to_win = int(settings[capsules_to_win]) + self._capsules_death = int(settings[capsules_death]) + self._lucky_capsules = bool(settings[lucky_capsules]) + self._capsules: list[Any] = [] + + self._capsule_model = ba.getmodel('bomb') + self._capsule_tex = ba.gettexture('bombColor') + self._capsule_lucky_tex = ba.gettexture('bombStickyColor') + self._collect_sound = ba.getsound('powerup01') + self._lucky_collect_sound = ba.getsound('cashRegister2') + + self._capsule_material = ba.Material() + self._capsule_material.add_actions( + conditions=('they_have_material', shared.player_material), + actions=('call', 'at_connect', self._on_capsule_player_collide), + ) + + self._flag_region_material = ba.Material() + self._flag_region_material.add_actions( + conditions=('they_have_material', shared.player_material), + actions=( + ('modify_part_collision', 'collide', True), + ('modify_part_collision', 'physical', False), + ( + 'call', + 'at_connect', + ba.Call(self._handle_player_flag_region_collide, True), + ), + ( + 'call', + 'at_disconnect', + ba.Call(self._handle_player_flag_region_collide, False), + ), + ), + ) + + # Base class overrides. + self.slow_motion = self._epic_mode + self.default_music = ( + ba.MusicType.EPIC if self._epic_mode else ba.MusicType.SCARY + ) + + def get_instance_description(self) -> str | Sequence: + return description_ingame, self._score_to_win + + def get_instance_description_short(self) -> str | Sequence: + return description_short, self._score_to_win + + def create_team(self, sessionteam: ba.SessionTeam) -> Team: + return Team() + + def on_team_join(self, team: Team) -> None: + self._update_scoreboard() + + def on_begin(self) -> None: + super().on_begin() + shared = SharedObjects.get() + self.setup_standard_time_limit(self._time_limit) + self.setup_standard_powerup_drops() + + # Base kills needed to win on the size of the largest team. + self._score_to_win = self._capsules_to_win * max( + 1, max(len(t.players) for t in self.teams) + ) + self._update_scoreboard() + + if isinstance(self.session, ba.FreeForAllSession): + self._flag_pos = self.map.get_flag_position(random.randint(0, 1)) + else: + self._flag_pos = self.map.get_flag_position(None) + + ba.timer(1.0, self._tick, repeat=True) + self._flag_state = FlagState.NEW + Flag.project_stand(self._flag_pos) + self._flag = Flag( + position=self._flag_pos, touchable=False, color=(1, 1, 1) + ) + self._flag_light = ba.newnode( + 'light', + attrs={ + 'position': self._flag_pos, + 'intensity': 0.2, + 'height_attenuated': False, + 'radius': 0.4, + 'color': (0.2, 0.2, 0.2), + }, + ) + # Flag region. + flagmats = [self._flag_region_material, shared.region_material] + ba.newnode( + 'region', + attrs={ + 'position': self._flag_pos, + 'scale': (1.8, 1.8, 1.8), + 'type': 'sphere', + 'materials': flagmats, + }, + ) + self._update_flag_state() + + def _tick(self) -> None: + self._update_flag_state() + + if self._scoring_team is None: + scoring_team = None + else: + scoring_team = self._scoring_team() + + if not scoring_team: + return + + if isinstance(self.session, ba.FreeForAllSession): + players = self.players + else: + players = scoring_team.players + + for player in players: + if player.time_at_flag > 0: + self.stats.player_scored( + player, 3, screenmessage=False, display=False + ) + if player.capsules > 0: + if self._flag_state != FlagState.HELD: + return + if scoring_team.score >= self._score_to_win: + return + + player.capsules -= 1 + scoring_team.score += 1 + self._handle_capsule_storage(( + self._flag_pos[0], + self._flag_pos[1]+1, + self._flag_pos[2] + ), player) + ba.playsound( + self._collect_sound, + 0.8, + position=self._flag_pos) + + self._update_scoreboard() + if player.capsules > 0: + assert self._flag is not None + self._flag.set_score_text( + str(self._score_to_win - scoring_team.score)) + + # winner + if scoring_team.score >= self._score_to_win: + self.end_game() + + def end_game(self) -> None: + results = ba.GameResults() + for team in self.teams: + results.set_team_score(team, team.score) + self.end(results=results, announce_delay=0) + + def _update_flag_state(self) -> None: + holding_teams = set( + player.team for player in self.players if player.time_at_flag + ) + prev_state = self._flag_state + assert self._flag_light + assert self._flag is not None + assert self._flag.node + if len(holding_teams) > 1: + self._flag_state = FlagState.CONTESTED + self._scoring_team = None + self._flag_light.color = (0.6, 0.6, 0.1) + self._flag.node.color = (1.0, 1.0, 0.4) + elif len(holding_teams) == 1: + holding_team = list(holding_teams)[0] + self._flag_state = FlagState.HELD + self._scoring_team = weakref.ref(holding_team) + self._flag_light.color = ba.normalized_color(holding_team.color) + self._flag.node.color = holding_team.color + else: + self._flag_state = FlagState.UNCONTESTED + self._scoring_team = None + self._flag_light.color = (0.2, 0.2, 0.2) + self._flag.node.color = (1, 1, 1) + if self._flag_state != prev_state: + ba.playsound(self._swipsound) + + def _handle_player_flag_region_collide(self, colliding: bool) -> None: + try: + spaz = ba.getcollision().opposingnode.getdelegate(PlayerSpaz, True) + except ba.NotFoundError: + return + + if not spaz.is_alive(): + return + + player = spaz.getplayer(Player, True) + + # Different parts of us can collide so a single value isn't enough + # also don't count it if we're dead (flying heads shouldn't be able to + # win the game :-) + if colliding and player.is_alive(): + player.time_at_flag += 1 + else: + player.time_at_flag = max(0, player.time_at_flag - 1) + + self._update_flag_state() + + def _update_scoreboard(self) -> None: + for team in self.teams: + self._scoreboard.set_team_value( + team, team.score, self._score_to_win + ) + + def _drop_capsule(self, player: Player) -> None: + pt = player.node.position + + # Throw out capsules that the victim has + 2 more to keep the game running + for i in range(player.capsules + self._capsules_death): + # How far from each other these capsules should spawn + w = 0.6 + # How much these capsules should fly after spawning + s = 0.005 - (player.capsules * 0.01) + self._capsules.append( + Capsule( + position=(pt[0] + random.uniform(-w, w), + pt[1] + 0.75 + random.uniform(-w, w), + pt[2]), + velocity=(random.uniform(-s, s), + random.uniform(-s, s), + random.uniform(-s, s)), + lucky=False)) + if random.randint(1, 12) == 1 and self._lucky_capsules: + # How far from each other these capsules should spawn + w = 0.6 + # How much these capsules should fly after spawning + s = 0.005 + self._capsules.append( + Capsule( + position=(pt[0] + random.uniform(-w, w), + pt[1] + 0.75 + random.uniform(-w, w), + pt[2]), + velocity=(random.uniform(-s, s), + random.uniform(-s, s), + random.uniform(-s, s)), + lucky=True)) + + def _on_capsule_player_collide(self) -> None: + if self.has_ended(): + return + collision = ba.getcollision() + + # Be defensive here; we could be hitting the corpse of a player + # who just left/etc. + try: + capsule = collision.sourcenode.getdelegate(Capsule, True) + player = collision.opposingnode.getdelegate( + PlayerSpaz, True + ).getplayer(Player, True) + except ba.NotFoundError: + return + + if not player.is_alive(): + return + + if capsule.node.color_texture == self._capsule_lucky_tex: + player.capsules += 4 + PopupText( + bonus, + color=(1, 1, 0), + scale=1.5, + position=capsule.node.position + ).autoretain() + ba.playsound( + self._lucky_collect_sound, + 1.0, + position=capsule.node.position) + ba.emitfx( + position=capsule.node.position, + velocity=(0, 0, 0), + count=int(6.4+random.random()*24), + scale=1.2, + spread=2.0, + chunk_type='spark') + ba.emitfx( + position=capsule.node.position, + velocity=(0, 0, 0), + count=int(4.0+random.random()*6), + emit_type='tendrils') + else: + player.capsules += 1 + ba.playsound( + self._collect_sound, + 0.6, + position=capsule.node.position) + # create a flash + light = ba.newnode( + 'light', + attrs={ + 'position': capsule.node.position, + 'height_attenuated': False, + 'radius': 0.1, + 'color': (1, 1, 0)}) + + # Create a short text informing about your inventory + self._handle_capsule_storage(player.position, player) + + ba.animate(light, 'intensity', { + 0: 0, + 0.1: 0.5, + 0.2: 0 + }, loop=False) + ba.timer(0.2, light.delete) + capsule.handlemessage(ba.DieMessage()) + + def _update_player_light(self, player: Player, capsules: int) -> None: + if player.light: + intensity = 0.04 * capsules + ba.animate(player.light, 'intensity', { + 0.0: player.light.intensity, + 0.1: intensity + }) + + def newintensity(): + player.light.intensity = intensity + ba.timer(0.1, newintensity) + else: + player.light = ba.newnode( + 'light', + attrs={ + 'height_attenuated': False, + 'radius': 0.2, + 'intensity': 0.0, + 'color': (0.2, 1, 0.2) + }) + player.node.connectattr('position', player.light, 'position') + + def _handle_capsule_storage(self, pos: float, player: Player) -> None: + capsules = player.capsules + text = str(capsules) + scale = 1.75 + (0.02 * capsules) + if capsules > 10: + player.capsules = 10 + text = full_capacity + color = (1, 0.85, 0) + elif capsules > 7: + color = (1, 0, 0) + scale = 2.4 + elif capsules > 5: + color = (1, 0.4, 0.4) + scale = 2.1 + elif capsules > 3: + color = (1, 1, 0.4) + scale = 2.0 + else: + color = (1, 1, 1) + scale = 1.9 + PopupText( + text, + color=color, + scale=scale, + position=(pos[0], pos[1]-1, pos[2]) + ).autoretain() + self._update_player_light(player, capsules) + + def handlemessage(self, msg: Any) -> Any: + if isinstance(msg, ba.PlayerDiedMessage): + super().handlemessage(msg) # Augment default. + # No longer can count as time_at_flag once dead. + player = msg.getplayer(Player) + player.time_at_flag = 0 + self._update_flag_state() + self._drop_capsule(player) + player.capsules = 0 + self._update_player_light(player, 0) + self.respawn_player(player) + else: + return super().handlemessage(msg) class Capsule(ba.Actor): - def __init__(self, - position: Sequence[float] = (0.0, 1.0, 0.0), - velocity: Sequence[float] = (0.0, 0.5, 0.0), - lucky: bool = False): - super().__init__() - shared = SharedObjects.get() - activity = self.getactivity() - - # spawn just above the provided point - self._spawn_pos = (position[0], position[1], position[2]) - - if lucky: - ba.playsound(activity._lucky_sound, 1.0, self._spawn_pos) - - self.node = ba.newnode( - 'prop', - attrs={ - 'model': activity._capsule_model, - 'color_texture': activity._capsule_lucky_tex if lucky else ( - activity._capsule_tex), - 'body': 'crate' if lucky else 'capsule', - 'reflection': 'powerup' if lucky else 'soft', - 'body_scale': 0.65 if lucky else 0.3, - 'density':6.0 if lucky else 4.0, - 'reflection_scale': [0.15], - 'shadow_size': 0.65 if lucky else 0.6, - 'position': self._spawn_pos, - 'velocity': velocity, - 'materials': [ - shared.object_material, activity._capsule_material] - }, - delegate=self) - ba.animate(self.node, 'model_scale', { - 0.0: 0.0, - 0.1: 0.9 if lucky else 0.6, - 0.16: 0.8 if lucky else 0.5 - }) - self._light_capsule = ba.newnode( - 'light', - attrs={ - 'position': self._spawn_pos, - 'height_attenuated': False, - 'radius': 0.5 if lucky else 0.1, - 'color': (0.2, 0.2, 0) if lucky else (0.2, 1, 0.2) - }) - self.node.connectattr('position', self._light_capsule, 'position') - - def handlemessage(self, msg: Any): - if isinstance(msg, ba.DieMessage): - self.node.delete() - ba.animate(self._light_capsule, 'intensity', { - 0: 1.0, - 0.05: 0.0 - }, loop=False) - ba.timer(0.05, self._light_capsule.delete) - elif isinstance(msg, ba.OutOfBoundsMessage): - self.handlemessage(ba.DieMessage()) - elif isinstance(msg, ba.HitMessage): - self.node.handlemessage( - 'impulse', - msg.pos[0], msg.pos[1], msg.pos[2], - msg.velocity[0]/8, msg.velocity[1]/8, msg.velocity[2]/8, - 1.0*msg.magnitude, 1.0*msg.velocity_magnitude, msg.radius, 0, - msg.force_direction[0], msg.force_direction[1], - msg.force_direction[2]) - else: - return super().handlemessage(msg) + def __init__(self, + position: Sequence[float] = (0.0, 1.0, 0.0), + velocity: Sequence[float] = (0.0, 0.5, 0.0), + lucky: bool = False): + super().__init__() + shared = SharedObjects.get() + activity = self.getactivity() + + # spawn just above the provided point + self._spawn_pos = (position[0], position[1], position[2]) + + if lucky: + ba.playsound(activity._lucky_sound, 1.0, self._spawn_pos) + + self.node = ba.newnode( + 'prop', + attrs={ + 'model': activity._capsule_model, + 'color_texture': activity._capsule_lucky_tex if lucky else ( + activity._capsule_tex), + 'body': 'crate' if lucky else 'capsule', + 'reflection': 'powerup' if lucky else 'soft', + 'body_scale': 0.65 if lucky else 0.3, + 'density': 6.0 if lucky else 4.0, + 'reflection_scale': [0.15], + 'shadow_size': 0.65 if lucky else 0.6, + 'position': self._spawn_pos, + 'velocity': velocity, + 'materials': [ + shared.object_material, activity._capsule_material] + }, + delegate=self) + ba.animate(self.node, 'model_scale', { + 0.0: 0.0, + 0.1: 0.9 if lucky else 0.6, + 0.16: 0.8 if lucky else 0.5 + }) + self._light_capsule = ba.newnode( + 'light', + attrs={ + 'position': self._spawn_pos, + 'height_attenuated': False, + 'radius': 0.5 if lucky else 0.1, + 'color': (0.2, 0.2, 0) if lucky else (0.2, 1, 0.2) + }) + self.node.connectattr('position', self._light_capsule, 'position') + + def handlemessage(self, msg: Any): + if isinstance(msg, ba.DieMessage): + self.node.delete() + ba.animate(self._light_capsule, 'intensity', { + 0: 1.0, + 0.05: 0.0 + }, loop=False) + ba.timer(0.05, self._light_capsule.delete) + elif isinstance(msg, ba.OutOfBoundsMessage): + self.handlemessage(ba.DieMessage()) + elif isinstance(msg, ba.HitMessage): + self.node.handlemessage( + 'impulse', + msg.pos[0], msg.pos[1], msg.pos[2], + msg.velocity[0]/8, msg.velocity[1]/8, msg.velocity[2]/8, + 1.0*msg.magnitude, 1.0*msg.velocity_magnitude, msg.radius, 0, + msg.force_direction[0], msg.force_direction[1], + msg.force_direction[2]) + else: + return super().handlemessage(msg) diff --git a/plugins/minigames/dodge_the_ball.py b/plugins/minigames/dodge_the_ball.py index d5b1770a..a9501318 100644 --- a/plugins/minigames/dodge_the_ball.py +++ b/plugins/minigames/dodge_the_ball.py @@ -11,7 +11,7 @@ from typing import TYPE_CHECKING import ba -from random import choice +from random import choice from enum import Enum from bastd.actor.bomb import Blast from bastd.actor.popuptext import PopupText @@ -39,28 +39,31 @@ class BallType(Enum): # increase the next ball speed but less than MEDIUM. # Ball color is crimson(purple+red = pinky color type). -# this dict decide the ball_type spawning rate like powerup box + +# this dict decide the ball_type spawning rate like powerup box ball_type_dict: dict[BallType, int] = { BallType.EASY: 3, BallType.MEDIUM: 2, BallType.HARD: 1, -}; +} + class Ball(ba.Actor): """ Shooting Ball """ - def __init__(self, - position: Sequence[float], - velocity: Sequence[float], - texture: ba.Texture, - body_scale: float = 1.0, - gravity_scale: float = 1.0, - ) -> NoReturn: - - super().__init__(); - - shared = SharedObjects.get(); - - ball_material = ba.Material(); + + def __init__(self, + position: Sequence[float], + velocity: Sequence[float], + texture: ba.Texture, + body_scale: float = 1.0, + gravity_scale: float = 1.0, + ) -> NoReturn: + + super().__init__() + + shared = SharedObjects.get() + + ball_material = ba.Material() ball_material.add_actions( conditions=( ( @@ -72,8 +75,8 @@ def __init__(self, ('they_have_material', shared.object_material), ), actions=('modify_node_collision', 'collide', False), - ); - + ) + self.node = ba.newnode( 'prop', delegate=self, @@ -86,37 +89,37 @@ def __init__(self, 'model_scale': body_scale, 'color_texture': texture, 'gravity_scale': gravity_scale, - 'density': 4.0, # increase density of ball so ball collide with player with heavy force. # ammm very bad grammer + 'density': 4.0, # increase density of ball so ball collide with player with heavy force. # ammm very bad grammer 'materials': (ball_material,), - }, - ); - + }, + ) + # die the ball manually incase the ball doesn't fall the outside of the map - ba.timer(2.5, ba.WeakCall(self.handlemessage, ba.DieMessage())); - + ba.timer(2.5, ba.WeakCall(self.handlemessage, ba.DieMessage())) + # i am not handling anything in this ball Class(except for diemessage). # all game things and logics going to be in the box class def handlemessage(self, msg: Any) -> Any: - + if isinstance(msg, ba.DieMessage): - self.node.delete(); + self.node.delete() else: - super().handlemessage(msg); - - + super().handlemessage(msg) + + class Box(ba.Actor): """ A box that spawn midle of map as a decoration perpose """ - - def __init__(self, - position: Sequence[float], - velocity: Sequence[float], - ) -> NoReturn: - - super().__init__(); - - shared = SharedObjects.get(); + + def __init__(self, + position: Sequence[float], + velocity: Sequence[float], + ) -> NoReturn: + + super().__init__() + + shared = SharedObjects.get() # self.ball_jump = 0.0; - no_hit_material = ba.Material(); + no_hit_material = ba.Material() # we don't need that the box was move and collide with objects. no_hit_material.add_actions( conditions=( @@ -125,7 +128,7 @@ def __init__(self, ('they_have_material', shared.attack_material), ), actions=('modify_part_collision', 'collide', False), - ); + ) no_hit_material.add_actions( conditions=( @@ -137,8 +140,8 @@ def __init__(self, ('modify_part_collision', 'collide', False), ('modify_part_collision', 'physical', False), ), - ); - + ) + self.node = ba.newnode( 'prop', delegate=self, @@ -154,26 +157,26 @@ def __init__(self, 'reflection': 'powerup', 'reflection_scale': [1.0], 'materials': (no_hit_material,), - }, - ); + }, + ) # light self.light = ba.newnode( "light", - owner = self.node, + owner=self.node, attrs={ - 'radius' : 0.2, - 'intensity' : 0.8, - 'color': (0.0, 1.0, 0.0), + 'radius': 0.2, + 'intensity': 0.8, + 'color': (0.0, 1.0, 0.0), } - ); - self.node.connectattr("position", self.light, "position"); - # Drawing circle and circleOutline in radius of 3, - # so player can see that how close he is to the box. - # If player is inside this circle the ball speed will increase. + ) + self.node.connectattr("position", self.light, "position") + # Drawing circle and circleOutline in radius of 3, + # so player can see that how close he is to the box. + # If player is inside this circle the ball speed will increase. circle = ba.newnode( "locator", - owner = self.node, - attrs = { + owner=self.node, + attrs={ 'shape': 'circle', 'color': (1.0, 0.0, 0.0), 'opacity': 0.1, @@ -182,12 +185,12 @@ def __init__(self, 'additive': True, }, ) - self.node.connectattr("position", circle, "position"); + self.node.connectattr("position", circle, "position") # also adding a outline cause its look nice. circle_outline = ba.newnode( "locator", - owner = self.node, - attrs = { + owner=self.node, + attrs={ 'shape': 'circleOutline', 'color': (1.0, 1.0, 0.0), 'opacity': 0.1, @@ -195,185 +198,185 @@ def __init__(self, 'draw_beauty': False, 'additive': True, }, - ); - self.node.connectattr("position", circle_outline, "position"); - + ) + self.node.connectattr("position", circle_outline, "position") + # all ball attribute that we need. - self.ball_type: BallType = BallType.EASY; - self.shoot_timer: ba.Timer | None = None; - self.shoot_speed: float = 0.0; + self.ball_type: BallType = BallType.EASY + self.shoot_timer: ba.Timer | None = None + self.shoot_speed: float = 0.0 # this force the shoot if player is inside the red circle. - self.force_shoot_speed: float = 0.0; - self.ball_mag = 3000; - self.ball_gravity: float = 1.0; - self.ball_tex: ba.Texture | None = None; - # only for Hard ball_type - self.player_facing_direction: list[float, float] = [0.0, 0.0]; + self.force_shoot_speed: float = 0.0 + self.ball_mag = 3000 + self.ball_gravity: float = 1.0 + self.ball_tex: ba.Texture | None = None + # only for Hard ball_type + self.player_facing_direction: list[float, float] = [0.0, 0.0] # ball shoot soound. - self.shoot_sound = ba.getsound('laserReverse'); - - # same as "powerupdist" - self.ball_type_dist: list[BallType] = []; + self.shoot_sound = ba.getsound('laserReverse') + + # same as "powerupdist" + self.ball_type_dist: list[BallType] = [] for ball in ball_type_dict: for _ in range(ball_type_dict[ball]): - self.ball_type_dist.append(ball); - + self.ball_type_dist.append(ball) + # Here main logic of game goes here. # like shoot balls, shoot speed, anything we want goes here(except for some thing). def start_shoot(self) -> NoReturn: - + # getting all allive players in a list. - alive_players_list = self.activity.get_alive_players(); - + alive_players_list = self.activity.get_alive_players() + # make sure that list is not Empty. if len(alive_players_list) > 0: - + # choosing a random player from list. - target_player = choice(alive_players_list); - # highlight the target player - self.highlight_target_player(target_player); - + target_player = choice(alive_players_list) + # highlight the target player + self.highlight_target_player(target_player) + # to finding difference between player and box. # we just need to subtract player pos and ball pos. # Same logic as eric applied in Target Practice Gamemode. - difference = ba.Vec3(target_player.position) - ba.Vec3(self.node.position); - + difference = ba.Vec3(target_player.position) - ba.Vec3(self.node.position) + # discard Y position so ball shoot more straight. difference[1] = 0.0 - + # and now, this length method returns distance in float. # we're gonna use this value for calculating player analog stick - distance = difference.length(); - + distance = difference.length() + # shoot a random BallType - self.upgrade_ball_type(choice(self.ball_type_dist)); - + self.upgrade_ball_type(choice(self.ball_type_dist)) + # and check the ball_type and upgrade it gravity_scale, texture, next ball speed. - self.check_ball_type(self.ball_type); - + self.check_ball_type(self.ball_type) + # For HARD ball i am just focusing on player analog stick facing direction. # Not very accurate and that's we need. if self.ball_type == BallType.HARD: - self.calculate_player_analog_stick(target_player, distance); + self.calculate_player_analog_stick(target_player, distance) else: - self.player_facing_direction = [0.0, 0.0]; - - pos = self.node.position; - + self.player_facing_direction = [0.0, 0.0] + + pos = self.node.position + if self.ball_type == BallType.MEDIUM or self.ball_type == BallType.HARD: # Target head by increasing Y pos. # How this work? cause ball gravity_scale is ...... - pos = (pos[0], pos[1]+.25, pos[2]); - + pos = (pos[0], pos[1]+.25, pos[2]) + # ball is generating.. ball = Ball( - position = pos, - velocity = (0.0, 0.0, 0.0), - texture = self.ball_tex, - gravity_scale = self.ball_gravity, - body_scale = 1.0, - ).autoretain(); - + position=pos, + velocity=(0.0, 0.0, 0.0), + texture=self.ball_tex, + gravity_scale=self.ball_gravity, + body_scale=1.0, + ).autoretain() + # shoot Animation and sound. - self.shoot_animation(); - + self.shoot_animation() + # force the shoot speed if player try to go inside the red circle. if self.force_shoot_speed != 0.0: - self.shoot_speed = self.force_shoot_speed; - + self.shoot_speed = self.force_shoot_speed + # push the ball to the player ball.node.handlemessage( - 'impulse', + 'impulse', self.node.position[0], # ball spawn position X self.node.position[1], # Y self.node.position[2], # Z - 0, 0, 0, # velocity x,y,z - self.ball_mag, # magnetude - 0.000, # magnetude velocity + 0, 0, 0, # velocity x,y,z + self.ball_mag, # magnetude + 0.000, # magnetude velocity 0.000, # radius 0.000, # idk - difference[0] + self.player_facing_direction[0], # force direction X - difference[1] , # force direction Y - difference[2] + self.player_facing_direction[1], # force direction Z - ); + difference[0] + self.player_facing_direction[0], # force direction X + difference[1], # force direction Y + difference[2] + self.player_facing_direction[1], # force direction Z + ) # creating our timer and shoot the ball again.(and we create a loop) - self.shoot_timer = ba.Timer(self.shoot_speed, self.start_shoot); - + self.shoot_timer = ba.Timer(self.shoot_speed, self.start_shoot) + def upgrade_ball_type(self, ball_type: BallType) -> NoReturn: - - self.ball_type = ball_type; + + self.ball_type = ball_type def check_ball_type(self, ball_type: BallType) -> NoReturn: - - if ball_type == BallType.EASY: - self.shoot_speed = 0.8; - self.ball_gravity = 1.0; - # next ball shoot speed - self.ball_mag = 3000; - # box light color and ball tex - self.light.color = (1.0, 1.0, 0.0); - self.ball_tex = ba.gettexture('egg4'); - elif ball_type == BallType.MEDIUM: - self.ball_mag = 3000; - # decrease the gravity scale so, ball shoot without falling and straight. - self.ball_gravity = 0.0; - # next ball shoot speed. - self.shoot_speed = 0.4; - # box light color and ball tex. - self.light.color = (1.0, 0.0, 1.0); - self.ball_tex = ba.gettexture('egg3'); - elif ball_type == BallType.HARD: - self.ball_mag = 2500; - self.ball_gravity = 0.0; - # next ball shoot speed. - self.shoot_speed = 0.6; - # box light color and ball tex. - self.light.color = (1.0, 0.2, 1.0); - self.ball_tex = ba.gettexture('egg1'); - + + if ball_type == BallType.EASY: + self.shoot_speed = 0.8 + self.ball_gravity = 1.0 + # next ball shoot speed + self.ball_mag = 3000 + # box light color and ball tex + self.light.color = (1.0, 1.0, 0.0) + self.ball_tex = ba.gettexture('egg4') + elif ball_type == BallType.MEDIUM: + self.ball_mag = 3000 + # decrease the gravity scale so, ball shoot without falling and straight. + self.ball_gravity = 0.0 + # next ball shoot speed. + self.shoot_speed = 0.4 + # box light color and ball tex. + self.light.color = (1.0, 0.0, 1.0) + self.ball_tex = ba.gettexture('egg3') + elif ball_type == BallType.HARD: + self.ball_mag = 2500 + self.ball_gravity = 0.0 + # next ball shoot speed. + self.shoot_speed = 0.6 + # box light color and ball tex. + self.light.color = (1.0, 0.2, 1.0) + self.ball_tex = ba.gettexture('egg1') + def shoot_animation(self) -> NoReturn: - + ba.animate( self.node, - "model_scale",{ + "model_scale", { 0.00: 1.4, 0.05: 1.7, 0.10: 1.4, } - ); + ) # playing shoot sound. - ba.playsound(self.shoot_sound, position = self.node.position); - + ba.playsound(self.shoot_sound, position=self.node.position) + def highlight_target_player(self, player: ba.Player) -> NoReturn: - + # adding light light = ba.newnode( "light", - owner = self.node, + owner=self.node, attrs={ - 'radius':0.0, - 'intensity':1.0, - 'color': (1.0, 0.0, 0.0), + 'radius': 0.0, + 'intensity': 1.0, + 'color': (1.0, 0.0, 0.0), } - ); + ) ba.animate( - light, - "radius",{ - 0.05: 0.02, - 0.10: 0.07, - 0.15: 0.15, - 0.20: 0.13, - 0.25: 0.10, - 0.30: 0.05, - 0.35: 0.02, - 0.40: 0.00, - } - ); + light, + "radius", { + 0.05: 0.02, + 0.10: 0.07, + 0.15: 0.15, + 0.20: 0.13, + 0.25: 0.10, + 0.30: 0.05, + 0.35: 0.02, + 0.40: 0.00, + } + ) # And a circle outline with ugly animation. circle_outline = ba.newnode( "locator", - owner = player.actor.node, + owner=player.actor.node, attrs={ 'shape': 'circleOutline', 'color': (1.0, 0.0, 0.0), @@ -381,82 +384,82 @@ def highlight_target_player(self, player: ba.Player) -> NoReturn: 'draw_beauty': False, 'additive': True, }, - ); + ) ba.animate_array( circle_outline, - 'size', + 'size', 1, { - 0.05: [0.5], - 0.10: [0.8], - 0.15: [1.5], - 0.20: [2.0], - 0.25: [1.8], - 0.30: [1.3], - 0.35: [0.6], - 0.40: [0.0], - } - ); - + 0.05: [0.5], + 0.10: [0.8], + 0.15: [1.5], + 0.20: [2.0], + 0.25: [1.8], + 0.30: [1.3], + 0.35: [0.6], + 0.40: [0.0], + } + ) + # coonect it and... - player.actor.node.connectattr("position", light, "position"); - player.actor.node.connectattr("position", circle_outline, "position"); - + player.actor.node.connectattr("position", light, "position") + player.actor.node.connectattr("position", circle_outline, "position") + # immediately delete the node after another player has been targeted. - self.shoot_speed = 0.5 if self.shoot_speed == 0.0 else self.shoot_speed; - ba.timer(self.shoot_speed, light.delete); - ba.timer(self.shoot_speed, circle_outline.delete); - - def calculate_player_analog_stick(self, player:ba.Player, distance: float) -> NoReturn: + self.shoot_speed = 0.5 if self.shoot_speed == 0.0 else self.shoot_speed + ba.timer(self.shoot_speed, light.delete) + ba.timer(self.shoot_speed, circle_outline.delete) + + def calculate_player_analog_stick(self, player: ba.Player, distance: float) -> NoReturn: # at first i was very confused how i can read the player analog stick \ # then i saw TheMikirog#1984 autorun plugin code. # and i got it how analog stick values are works. # just need to store analog stick facing direction and need some calculation according how far player pushed analog stick. # Notice that how vertical direction is inverted, so we need to put a minus infront of veriable.(so ball isn't shoot at wrong direction). - self.player_facing_direction[0] = player.actor.node.move_left_right; - self.player_facing_direction[1] = -player.actor.node.move_up_down; - + self.player_facing_direction[0] = player.actor.node.move_left_right + self.player_facing_direction[1] = -player.actor.node.move_up_down + # if player is too close and the player pushing his analog stick fully the ball shoot's too far away to player. # so, we need to reduce the value of "self.player_facing_direction" to fix this problem. if distance <= 3: - self.player_facing_direction[0] = 0.4 if self.player_facing_direction[0] > 0 else -0.4; - self.player_facing_direction[1] = 0.4 if self.player_facing_direction[0] > 0 else -0.4; + self.player_facing_direction[0] = 0.4 if self.player_facing_direction[0] > 0 else -0.4 + self.player_facing_direction[1] = 0.4 if self.player_facing_direction[0] > 0 else -0.4 # same problem to long distance but in reverse, the ball can't reach to the player, # its because player analog stick value is between 1 and -1, # and this value is low to shoot ball forward to Player if player is too far from the box. # so. let's increase to 1.5 if player pushed analog stick fully. elif distance > 6.5: # So many calculation according to how analog stick pushed by player. - # Horizontal(left-right) calculation + # Horizontal(left-right) calculation if self.player_facing_direction[0] > 0.4: - self.player_facing_direction[0] = 1.5; + self.player_facing_direction[0] = 1.5 elif self.player_facing_direction[0] < -0.4: - self.player_facing_direction[0] = -1.5; + self.player_facing_direction[0] = -1.5 else: if self.player_facing_direction[0] > 0.0: - self.player_facing_direction[0] = 0.2; + self.player_facing_direction[0] = 0.2 elif self.player_facing_direction[0] < 0.0: - self.player_facing_direction[0] = -0.2; + self.player_facing_direction[0] = -0.2 else: - self.player_facing_direction[0] = 0.0; - + self.player_facing_direction[0] = 0.0 + # Vertical(up-down) calculation. if self.player_facing_direction[1] > 0.4: - self.player_facing_direction[1] = 1.5; + self.player_facing_direction[1] = 1.5 elif self.player_facing_direction[1] < -0.4: - self.player_facing_direction[1] = -1.5; + self.player_facing_direction[1] = -1.5 else: if self.player_facing_direction[1] > 0.0: - self.player_facing_direction[1] = 0.2; + self.player_facing_direction[1] = 0.2 elif self.player_facing_direction[1] < 0.0: - self.player_facing_direction[1] = -0.2; + self.player_facing_direction[1] = -0.2 else: - self.player_facing_direction[1] = -0.0; - + self.player_facing_direction[1] = -0.0 + # if we want stop the ball shootes def stop_shoot(self) -> NoReturn: - # Kill the timer. - self.shoot_timer = None; - + # Kill the timer. + self.shoot_timer = None + class Player(ba.Player['Team']): """Our player type for this game.""" @@ -466,192 +469,194 @@ class Team(ba.Team[Player]): """Our team type for this game.""" # almost 80 % for game we done in box class. -# now remain things, like name, seetings, scoring, cooldonw, +# now remain things, like name, seetings, scoring, cooldonw, # and main thing don't allow player to camp inside of box are going in this class. # ba_meta export game + + class DodgeTheBall(ba.TeamGameActivity[Player, Team]): - + # defining name, description and settings.. - name = 'Dodge the ball'; - description = 'Survive from shooting balls'; - + name = 'Dodge the ball' + description = 'Survive from shooting balls' + available_settings = [ ba.IntSetting( 'Cooldown', - min_value = 20, - default = 45, - increment = 5, + min_value=20, + default=45, + increment=5, ), ba.BoolSetting('Epic Mode', default=False) ] # Don't allow joining after we start. - allow_mid_activity_joins = False; - + allow_mid_activity_joins = False + @classmethod def supports_session_type(cls, sessiontype: type[ba.Session]) -> bool: # We support team and ffa sessions. return issubclass(sessiontype, ba.FreeForAllSession) or issubclass( sessiontype, ba.DualTeamSession, - ); - + ) + @classmethod def get_supported_maps(cls, sessiontype: type[ba.Session]) -> list[str]: # This Game mode need a flat and perfect shape map where can player fall outside map. # bombsquad have "Doom Shroom" map. # Not perfect map for this game mode but its fine for this gamemode. # the problem is that Doom Shroom is not a perfect circle and not flat also. - return ['Doom Shroom']; - + return ['Doom Shroom'] + def __init__(self, settings: dict): - super().__init__(settings); - self._epic_mode = bool(settings['Epic Mode']); - self.countdown_time = int(settings['Cooldown']); - - self.check_player_pos_timer: ba.Timer | None = None; - self.shield_drop_timer: ba.Timer | None = None; + super().__init__(settings) + self._epic_mode = bool(settings['Epic Mode']) + self.countdown_time = int(settings['Cooldown']) + + self.check_player_pos_timer: ba.Timer | None = None + self.shield_drop_timer: ba.Timer | None = None # cooldown and Box - self._countdown: OnScreenCountdown | None = None; - self.box: Box | None = None; - + self._countdown: OnScreenCountdown | None = None + self.box: Box | None = None + # this lists for scoring. - self.joined_player_list: list[ba.Player] = []; - self.dead_player_list: list[ba.Player] = []; - + self.joined_player_list: list[ba.Player] = [] + self.dead_player_list: list[ba.Player] = [] + # normally play RUN AWAY music cause is match with our gamemode at.. my point, # but in epic switch to EPIC. - self.slow_motion = self._epic_mode; + self.slow_motion = self._epic_mode self.default_music = ( ba.MusicType.EPIC if self._epic_mode else ba.MusicType.RUN_AWAY - ); - + ) + def get_instance_description(self) -> str | Sequence: - return 'Keep away as possible as you can'; - + return 'Keep away as possible as you can' + # add a tiny text under our game name. def get_instance_description_short(self) -> str | Sequence: - return 'Dodge the shooting balls'; + return 'Dodge the shooting balls' def on_begin(self) -> NoReturn: - super().on_begin(); - + super().on_begin() + # spawn our box at middle of the map self.box = Box( position=(0.5, 2.7, -3.9), velocity=(0.0, 0.0, 0.0), - ).autoretain(); - - # create our cooldown + ).autoretain() + + # create our cooldown self._countdown = OnScreenCountdown( - duration = self.countdown_time, - endcall = self.play_victory_sound_and_end, - ); - + duration=self.countdown_time, + endcall=self.play_victory_sound_and_end, + ) + # and starts the cooldown and shootes. - ba.timer(5.0, self._countdown.start); - ba.timer(5.0, self.box.start_shoot); - + ba.timer(5.0, self._countdown.start) + ba.timer(5.0, self.box.start_shoot) + # start checking all player pos. - ba.timer(5.0, self.check_player_pos); - + ba.timer(5.0, self.check_player_pos) + # drop shield every ten Seconds # need five seconds delay Because shootes start after 5 seconds. - ba.timer(15.0, self.drop_shield); - + ba.timer(15.0, self.drop_shield) + # This function returns all alive players in game. # i thinck you see this function in Box class. def get_alive_players(self) -> Sequence[ba.Player]: - - alive_players = []; - + + alive_players = [] + for team in self.teams: for player in team.players: if player.is_alive(): - alive_players.append(player); - - return alive_players; - + alive_players.append(player) + + return alive_players + # let's disallowed camping inside of box by doing a blast and increasing ball shoot speed. def check_player_pos(self): - + for player in self.get_alive_players(): - - # same logic as applied for the ball - difference = ba.Vec3(player.position) - ba.Vec3(self.box.node.position); - - distance = difference.length(); - - if distance < 3: - self.box.force_shoot_speed = 0.2; - else: - self.box.force_shoot_speed = 0.0; - - if distance < 0.5: - Blast( - position = self.box.node.position, - velocity = self.box.node.velocity, - blast_type = 'normal', - blast_radius = 1.0, - ).autoretain(); - - PopupText( - position = self.box.node.position, - text = 'Keep away from me', - random_offset = 0.0, - scale = 2.0, - color = self.box.light.color, - ).autoretain(); - + + # same logic as applied for the ball + difference = ba.Vec3(player.position) - ba.Vec3(self.box.node.position) + + distance = difference.length() + + if distance < 3: + self.box.force_shoot_speed = 0.2 + else: + self.box.force_shoot_speed = 0.0 + + if distance < 0.5: + Blast( + position=self.box.node.position, + velocity=self.box.node.velocity, + blast_type='normal', + blast_radius=1.0, + ).autoretain() + + PopupText( + position=self.box.node.position, + text='Keep away from me', + random_offset=0.0, + scale=2.0, + color=self.box.light.color, + ).autoretain() + # create our timer and start looping it - self.check_player_pos_timer = ba.Timer(0.1, self.check_player_pos); - + self.check_player_pos_timer = ba.Timer(0.1, self.check_player_pos) + # drop useless shield's too give player temptation. def drop_shield(self) -> NoReturn: - - pos = self.box.node.position; - - PowerupBox( - position = (pos[0] + 4.0, pos[1] + 3.0, pos[2]), - poweruptype = 'shield', - ).autoretain(); - - PowerupBox( - position = (pos[0] - 4.0, pos[1] + 3.0, pos[2]), - poweruptype = 'shield', - ).autoretain(); - - self.shield_drop_timer = ba.Timer(10.0, self.drop_shield); - + + pos = self.box.node.position + + PowerupBox( + position=(pos[0] + 4.0, pos[1] + 3.0, pos[2]), + poweruptype='shield', + ).autoretain() + + PowerupBox( + position=(pos[0] - 4.0, pos[1] + 3.0, pos[2]), + poweruptype='shield', + ).autoretain() + + self.shield_drop_timer = ba.Timer(10.0, self.drop_shield) + # when cooldown time up i don't want that the game end immediately. def play_victory_sound_and_end(self) -> NoReturn: - + # kill timers - self.box.stop_shoot(); + self.box.stop_shoot() self.check_player_pos_timer = None self.shield_drop_timer = None - ba.timer(2.0, self.end_game); - + ba.timer(2.0, self.end_game) + # this function runs when A player spawn in map def spawn_player(self, player: Player) -> NoReturn: - spaz = self.spawn_player_spaz(player); + spaz = self.spawn_player_spaz(player) # reconnect this player's controls. # without bomb, punch and pickup. spaz.connect_controls_to_player( enable_punch=False, enable_bomb=False, enable_pickup=False, - ); - + ) + # storing all players for ScorinG. - self.joined_player_list.append(player); - + self.joined_player_list.append(player) + # Also lets have them make some noise when they die. - spaz.play_big_death_sound = True; - + spaz.play_big_death_sound = True + # very helpful function to check end game when player dead or leav. def _check_end_game(self) -> bool: - + living_team_count = 0 for team in self.teams: for player in team.players: @@ -669,51 +674,51 @@ def _check_end_game(self) -> bool: # this function called when player leave. def on_player_leave(self, player: Player) -> NoReturn: # Augment default behavior. - super().on_player_leave(player); + super().on_player_leave(player) # checking end game. - self._check_end_game(); + self._check_end_game() # this gamemode needs to handle only one msg "PlayerDiedMessage". def handlemessage(self, msg: Any) -> Any: - + if isinstance(msg, ba.PlayerDiedMessage): # Augment standard behavior. - super().handlemessage(msg); - + super().handlemessage(msg) + # and storing the dead player records in our dead_player_list. - self.dead_player_list.append(msg.getplayer(Player)); - + self.dead_player_list.append(msg.getplayer(Player)) + # check the end game. - ba.timer(1.0, self._check_end_game); - + ba.timer(1.0, self._check_end_game) + def end_game(self): # kill timers self.box.stop_shoot() self.check_player_pos_timer = None self.shield_drop_timer = None - + # here the player_dead_list and joined_player_list gonna be very helpful. for team in self.teams: for player in team.players: - + # for scoring i am just following the index of the player_dead_list. # for dead list... # 0th index player dead first. # 1st index player dead second. # and so on... - # i think you got it... maybe + # i think you got it... maybe # sometime we also got a empty list # if we got a empty list that means all players are survived or maybe only one player playing and he/she survived. if len(self.dead_player_list) > 0: - + for index, dead_player in enumerate(self.dead_player_list): # if this condition is true we find the dead player \ # and his index with enumerate function. if player == dead_player: # updating with one, because i don't want to give 0 score to first dead player. - index += 1 + index += 1 break # and if this statement is true we just find a survived player. # for survived player i am giving the highest score according to how many players are joined. @@ -722,11 +727,11 @@ def end_game(self): # for survived player i am giving the highest score according to how many players are joined. else: index = len(self.joined_player_list) - + # and here i am following Table of 10 for scoring. # very lazY. score = int(10 * index) - + self.stats.player_scored(player, score, screenmessage=False) # Ok now calc game results: set a score for each team and then tell \ @@ -738,25 +743,23 @@ def end_game(self): # just always deal in teams and have all cases covered. # hmmm... some eric comments might be helpful to you. for team in self.teams: - + max_index = 0 for player in team.players: - # for the team, we choose only one player who survived longest. - # same logic.. - if len(self.dead_player_list) > 0: + # for the team, we choose only one player who survived longest. + # same logic.. + if len(self.dead_player_list) > 0: for index, dead_player in enumerate(self.dead_player_list): if player == dead_player: index += 1 break elif index == len(self.dead_player_list) - 1: index = len(self.joined_player_list) - else: + else: index = len(self.joined_player_list) - - max_index = max(max_index, index) + + max_index = max(max_index, index) # set the team score - results.set_team_score(team, int(10 * max_index)) + results.set_team_score(team, int(10 * max_index)) # and end the game self.end(results=results) - - \ No newline at end of file diff --git a/plugins/minigames/invisible_one.py b/plugins/minigames/invisible_one.py index 211a163e..3b9bdd82 100644 --- a/plugins/minigames/invisible_one.py +++ b/plugins/minigames/invisible_one.py @@ -225,7 +225,6 @@ def _tick(self) -> None: scoring_team.time_remaining = max( 0, scoring_team.time_remaining - 1) - self._update_scoreboard() # announce numbers we have sounds for @@ -286,7 +285,8 @@ def _set_invicible_one_player(self, player: Optional[Player]) -> None: self._invicible_one_player = player if self._invicible_one_is_lazy: - player.actor.connect_controls_to_player(enable_punch = False, enable_pickup = False, enable_bomb = False) + player.actor.connect_controls_to_player( + enable_punch=False, enable_pickup=False, enable_bomb=False) if player.actor.node.torso_model != None: player.actor.node.color_mask_texture = None player.actor.node.color_texture = None @@ -307,9 +307,8 @@ def _set_invicible_one_player(self, player: Optional[Player]) -> None: player.actor.pickup_sounds = invi_sound player.actor.death_sounds = invi_sound player.actor.fall_sounds = invi_sound - - player.actor.node.name = '' + player.actor.node.name = '' def handlemessage(self, msg: Any) -> Any: if isinstance(msg, ba.PlayerDiedMessage): diff --git a/plugins/minigames/last_punch_stand.py b/plugins/minigames/last_punch_stand.py index 878fea97..41fe2810 100644 --- a/plugins/minigames/last_punch_stand.py +++ b/plugins/minigames/last_punch_stand.py @@ -1,38 +1,45 @@ # ba_meta require api 7 from typing import Sequence -import ba, _ba, random +import ba +import _ba +import random from bastd.actor.spaz import Spaz from bastd.actor.scoreboard import Scoreboard + class Player(ba.Player['Team']): - """Our player type for this game.""" + """Our player type for this game.""" + class Team(ba.Team[Player]): - """Our team type for this game.""" + """Our team type for this game.""" + + def __init__(self) -> None: + super().__init__() + self.score = 1 - def __init__(self) -> None: - super().__init__() - self.score = 1 class ChooseingSpazHitMessage: - def __init__(self, hitter:Player) -> None: - self.hitter = hitter + def __init__(self, hitter: Player) -> None: + self.hitter = hitter + class ChooseingSpazDieMessage: - def __init__(self, killer:Player) -> None: - self.killer = killer + def __init__(self, killer: Player) -> None: + self.killer = killer + class ChooseingSpaz(Spaz): - def __init__( - self, - pos:Sequence[float], - color: Sequence[float] = (1.0, 1.0, 1.0), - highlight: Sequence[float] = (0.5, 0.5, 0.5), - ): - super().__init__(color, highlight, "Spaz", None, True, True, False, False) - self.last_player_attacked_by = None - self.stand(pos) - self.loc = ba.newnode( + def __init__( + self, + pos: Sequence[float], + color: Sequence[float] = (1.0, 1.0, 1.0), + highlight: Sequence[float] = (0.5, 0.5, 0.5), + ): + super().__init__(color, highlight, "Spaz", None, True, True, False, False) + self.last_player_attacked_by = None + self.stand(pos) + self.loc = ba.newnode( 'locator', attrs={ 'shape': 'circleOutline', @@ -43,221 +50,223 @@ def __init__( 'additive': True, }, ) - self.node.connectattr("position", self.loc, "position") - ba.animate_array(self.loc, "size", 1, keys={0:[0.5,], 1:[2,], 1.5:[0.5]}, loop=True) + self.node.connectattr("position", self.loc, "position") + ba.animate_array(self.loc, "size", 1, keys={0: [0.5,], 1: [2,], 1.5: [0.5]}, loop=True) - def handlemessage(self, msg): - if isinstance(msg, ba.FreezeMessage): - return + def handlemessage(self, msg): + if isinstance(msg, ba.FreezeMessage): + return - if isinstance(msg, ba.PowerupMessage): - if not(msg.poweruptype == "health"): - return + if isinstance(msg, ba.PowerupMessage): + if not (msg.poweruptype == "health"): + return - super().handlemessage(msg) + super().handlemessage(msg) - if isinstance(msg, ba.HitMessage): - self.handlemessage(ba.PowerupMessage("health")) + if isinstance(msg, ba.HitMessage): + self.handlemessage(ba.PowerupMessage("health")) - player = msg.get_source_player(Player) - if self.is_alive(): - self.activity.handlemessage(ChooseingSpazHitMessage(player)) - self.last_player_attacked_by = player + player = msg.get_source_player(Player) + if self.is_alive(): + self.activity.handlemessage(ChooseingSpazHitMessage(player)) + self.last_player_attacked_by = player + elif isinstance(msg, ba.DieMessage): + player = self.last_player_attacked_by - elif isinstance(msg, ba.DieMessage): - player = self.last_player_attacked_by + if msg.how.value != ba.DeathType.GENERIC.value: + self._dead = True + self.activity.handlemessage(ChooseingSpazDieMessage(player)) - if msg.how.value != ba.DeathType.GENERIC.value: - self._dead = True - self.activity.handlemessage(ChooseingSpazDieMessage(player)) + self.loc.delete() - self.loc.delete() + def stand(self, pos=(0, 0, 0), angle=0): + self.handlemessage(ba.StandMessage(pos, angle)) + def recolor(self, color, highlight=(1, 1, 1)): + self.node.color = color + self.node.highlight = highlight + self.loc.color = color - def stand(self, pos = (0,0,0), angle = 0): - self.handlemessage(ba.StandMessage(pos,angle)) +class ChooseBilbord(ba.Actor): + def __init__(self, player: Player, delay=0.1) -> None: + super().__init__() - def recolor(self, color, highlight = (1,1,1)): - self.node.color = color - self.node.highlight = highlight - self.loc.color = color + icon = player.get_icon() + self.scale = 100 -class ChooseBilbord(ba.Actor): - def __init__(self, player:Player, delay = 0.1) -> None: - super().__init__() - - icon = player.get_icon() - self.scale = 100 - - self.node = ba.newnode( - 'image', - delegate=self, - attrs={ - "position":(60,-125), - 'texture': icon['texture'], - 'tint_texture': icon['tint_texture'], - 'tint_color': icon['tint_color'], - 'tint2_color': icon['tint2_color'], - 'opacity': 1.0, - 'absolute_scale': True, - 'attach': "topLeft" - }, - ) - - self.name_node = ba.newnode( - 'text', - owner=self.node, - attrs={ - 'position': (60,-185), - 'text': ba.Lstr(value=player.getname()), - 'color': ba.safecolor(player.team.color), - 'h_align': 'center', - 'v_align': 'center', - 'vr_depth': 410, - 'flatness': 1.0, - 'h_attach': 'left', - 'v_attach': 'top', - 'maxwidth':self.scale - }, - ) - - ba.animate_array(self.node, "scale", keys={0 + delay:[0,0], 0.05 + delay:[self.scale, self.scale]}, size=1) - ba.animate(self.name_node, "scale", {0 + delay:0, 0.07 + delay:1}) - - def handlemessage(self, msg): - super().handlemessage(msg) - if isinstance(msg, ba.DieMessage): - ba.animate_array(self.node, "scale", keys={0:self.node.scale, 0.05:[0,0]}, size=1) - ba.animate(self.name_node, "scale", {0:self.name_node.scale, 0.07:0}) - - def __delete(): - self.node.delete() - self.name_node.delete() - - ba.timer(0.2, __delete) + self.node = ba.newnode( + 'image', + delegate=self, + attrs={ + "position": (60, -125), + 'texture': icon['texture'], + 'tint_texture': icon['tint_texture'], + 'tint_color': icon['tint_color'], + 'tint2_color': icon['tint2_color'], + 'opacity': 1.0, + 'absolute_scale': True, + 'attach': "topLeft" + }, + ) + + self.name_node = ba.newnode( + 'text', + owner=self.node, + attrs={ + 'position': (60, -185), + 'text': ba.Lstr(value=player.getname()), + 'color': ba.safecolor(player.team.color), + 'h_align': 'center', + 'v_align': 'center', + 'vr_depth': 410, + 'flatness': 1.0, + 'h_attach': 'left', + 'v_attach': 'top', + 'maxwidth': self.scale + }, + ) + + ba.animate_array(self.node, "scale", keys={ + 0 + delay: [0, 0], 0.05 + delay: [self.scale, self.scale]}, size=1) + ba.animate(self.name_node, "scale", {0 + delay: 0, 0.07 + delay: 1}) + + def handlemessage(self, msg): + super().handlemessage(msg) + if isinstance(msg, ba.DieMessage): + ba.animate_array(self.node, "scale", keys={0: self.node.scale, 0.05: [0, 0]}, size=1) + ba.animate(self.name_node, "scale", {0: self.name_node.scale, 0.07: 0}) + + def __delete(): + self.node.delete() + self.name_node.delete() + + ba.timer(0.2, __delete) # ba_meta export game + + class LastPunchStand(ba.TeamGameActivity[Player, Team]): - name = "Last Punch Stand" - description = "Last one punchs the choosing spaz wins" - tips = [ - 'keep punching the choosing spaz to be last punched player at times up!', - 'you can not frezz the choosing spaz', - "evry time you punch the choosing spaz, you will get one point", - ] - - default_music = ba.MusicType.TO_THE_DEATH - - available_settings = [ - ba.FloatSetting("min time limit (in seconds)", 50.0, min_value=30.0), - ba.FloatSetting("max time limit (in seconds)", 160.0, 60), - - ] - - def __init__(self, settings: dict): - super().__init__(settings) - self._min_timelimit = settings["min time limit (in seconds)"] - self._max_timelimit = settings["max time limit (in seconds)"] - if (self._min_timelimit > self._max_timelimit): - self._max_timelimit = self._min_timelimit - - self._choosing_spaz_defcolor = (0.5,0.5,0.5) - self.choosing_spaz = None - self.choosed_player = None - self.times_uped = False - self.scoreboard = Scoreboard() - - def times_up(self): - self.times_uped = True - - for player in self.players: - if self.choosed_player and (player.team.id != self.choosed_player.team.id): - player.actor._cursed = True - player.actor.curse_explode() - - self.end_game() - - def __get_spaz_bot_spawn_point(self): - if len(self.map.tnt_points) > 0: - return self.map.tnt_points[random.randint(0, len(self.map.tnt_points)-1)] - else: - return (0, 6, 0) - - def spaw_bot(self): - "spawns a choosing bot" - - self.choosing_spaz = ChooseingSpaz(self.__get_spaz_bot_spawn_point()) - self.choose_bilbord = None - - def on_begin(self) -> None: - super().on_begin() - time_limit = random.randint(self._min_timelimit, self._max_timelimit) - self.spaw_bot() - ba.timer(time_limit, self.times_up) - - self.setup_standard_powerup_drops(False) - - def end_game(self) -> None: - results = ba.GameResults() - for team in self.teams: - if self.choosed_player and (team.id == self.choosed_player.team.id): team.score += 100 - results.set_team_score(team, team.score) - self.end(results=results) - - def change_choosed_player(self, hitter:Player): - if hitter: - self.choosing_spaz.recolor(hitter.color, hitter.highlight) - self.choosed_player = hitter - hitter.team.score += 1 - self.choose_bilbord = ChooseBilbord(hitter) - self.hide_score_board() - else: - self.choosing_spaz.recolor(self._choosing_spaz_defcolor) - self.choosed_player = None - self.choose_bilbord = None - self.show_score_board() - - def show_score_board(self): - self.scoreboard = Scoreboard() - for team in self.teams: - self.scoreboard.set_team_value(team, team.score) - - def hide_score_board(self): - self.scoreboard = None - - def _watch_dog_(self): - "checks if choosing spaz exists" - #choosing spaz wont respawn if death type if generic - #this becuse we dont want to keep respawn him when he dies because of losing referce - #but sometimes "choosing spaz" dies naturaly and his death type is generic! so it wont respawn back again - #thats why we have this function; to check if spaz exits in the case that he didnt respawned - - if self.choosing_spaz: - if self.choosing_spaz._dead: - self.spaw_bot() - else: - self.spaw_bot() - - def handlemessage(self, msg): - super().handlemessage(msg) - - if isinstance(msg, ChooseingSpazHitMessage): - hitter = msg.hitter - if self.choosing_spaz.node and hitter: - self.change_choosed_player(hitter) - - elif isinstance(msg, ChooseingSpazDieMessage): - self.spaw_bot() - self.change_choosed_player(None) - - elif isinstance(msg, ba.PlayerDiedMessage): - player = msg.getplayer(Player) - if not (self.has_ended() or self.times_uped): - self.respawn_player(player, 0) - - if self.choosed_player and (player.getname(True) == self.choosed_player.getname(True)): - self.change_choosed_player(None) - - self._watch_dog_() \ No newline at end of file + name = "Last Punch Stand" + description = "Last one punchs the choosing spaz wins" + tips = [ + 'keep punching the choosing spaz to be last punched player at times up!', + 'you can not frezz the choosing spaz', + "evry time you punch the choosing spaz, you will get one point", + ] + + default_music = ba.MusicType.TO_THE_DEATH + + available_settings = [ + ba.FloatSetting("min time limit (in seconds)", 50.0, min_value=30.0), + ba.FloatSetting("max time limit (in seconds)", 160.0, 60), + + ] + + def __init__(self, settings: dict): + super().__init__(settings) + self._min_timelimit = settings["min time limit (in seconds)"] + self._max_timelimit = settings["max time limit (in seconds)"] + if (self._min_timelimit > self._max_timelimit): + self._max_timelimit = self._min_timelimit + + self._choosing_spaz_defcolor = (0.5, 0.5, 0.5) + self.choosing_spaz = None + self.choosed_player = None + self.times_uped = False + self.scoreboard = Scoreboard() + + def times_up(self): + self.times_uped = True + + for player in self.players: + if self.choosed_player and (player.team.id != self.choosed_player.team.id): + player.actor._cursed = True + player.actor.curse_explode() + + self.end_game() + + def __get_spaz_bot_spawn_point(self): + if len(self.map.tnt_points) > 0: + return self.map.tnt_points[random.randint(0, len(self.map.tnt_points)-1)] + else: + return (0, 6, 0) + + def spaw_bot(self): + "spawns a choosing bot" + + self.choosing_spaz = ChooseingSpaz(self.__get_spaz_bot_spawn_point()) + self.choose_bilbord = None + + def on_begin(self) -> None: + super().on_begin() + time_limit = random.randint(self._min_timelimit, self._max_timelimit) + self.spaw_bot() + ba.timer(time_limit, self.times_up) + + self.setup_standard_powerup_drops(False) + + def end_game(self) -> None: + results = ba.GameResults() + for team in self.teams: + if self.choosed_player and (team.id == self.choosed_player.team.id): + team.score += 100 + results.set_team_score(team, team.score) + self.end(results=results) + + def change_choosed_player(self, hitter: Player): + if hitter: + self.choosing_spaz.recolor(hitter.color, hitter.highlight) + self.choosed_player = hitter + hitter.team.score += 1 + self.choose_bilbord = ChooseBilbord(hitter) + self.hide_score_board() + else: + self.choosing_spaz.recolor(self._choosing_spaz_defcolor) + self.choosed_player = None + self.choose_bilbord = None + self.show_score_board() + + def show_score_board(self): + self.scoreboard = Scoreboard() + for team in self.teams: + self.scoreboard.set_team_value(team, team.score) + + def hide_score_board(self): + self.scoreboard = None + + def _watch_dog_(self): + "checks if choosing spaz exists" + # choosing spaz wont respawn if death type if generic + # this becuse we dont want to keep respawn him when he dies because of losing referce + # but sometimes "choosing spaz" dies naturaly and his death type is generic! so it wont respawn back again + # thats why we have this function; to check if spaz exits in the case that he didnt respawned + + if self.choosing_spaz: + if self.choosing_spaz._dead: + self.spaw_bot() + else: + self.spaw_bot() + + def handlemessage(self, msg): + super().handlemessage(msg) + + if isinstance(msg, ChooseingSpazHitMessage): + hitter = msg.hitter + if self.choosing_spaz.node and hitter: + self.change_choosed_player(hitter) + + elif isinstance(msg, ChooseingSpazDieMessage): + self.spaw_bot() + self.change_choosed_player(None) + + elif isinstance(msg, ba.PlayerDiedMessage): + player = msg.getplayer(Player) + if not (self.has_ended() or self.times_uped): + self.respawn_player(player, 0) + + if self.choosed_player and (player.getname(True) == self.choosed_player.getname(True)): + self.change_choosed_player(None) + + self._watch_dog_() diff --git a/plugins/minigames/quake.py b/plugins/minigames/quake.py index 58ef3e35..e0bb33bf 100644 --- a/plugins/minigames/quake.py +++ b/plugins/minigames/quake.py @@ -6,16 +6,17 @@ import random import enum -import ba, _ba +import ba +import _ba from bastd.actor.scoreboard import Scoreboard from bastd.actor.powerupbox import PowerupBox from bastd.gameutils import SharedObjects -#from rocket +# from rocket from bastd.actor.bomb import Blast -#from railgun +# from railgun from bastd.actor.playerspaz import PlayerSpaz from bastd.actor.spaz import Spaz @@ -27,7 +28,7 @@ STORAGE_ATTR_NAME = f'_shared_{__name__}_factory' -#+++++++++++++++++++Rocket++++++++++++++++++++++++ +# +++++++++++++++++++Rocket++++++++++++++++++++++++ class RocketFactory: """Quake Rocket factory""" @@ -182,10 +183,10 @@ def handlemessage(self, msg: Any) -> Any: elif isinstance(msg, ba.OutOfBoundsMessage): self.handlemessage(ba.DieMessage()) -#-------------------Rocket-------------------------- +# -------------------Rocket-------------------------- -#++++++++++++++++++Railgun++++++++++++++++++++++++++ +# ++++++++++++++++++Railgun++++++++++++++++++++++++++ class Railgun: """Very dangerous weapon""" @@ -298,7 +299,8 @@ def handlemessage(self, msg: Any) -> Any: elif isinstance(msg, ba.OutOfBoundsMessage): self.handlemessage(ba.DieMessage()) -#------------------Railgun------------------------- +# ------------------Railgun------------------------- + class Player(ba.Player['Team']): """Our player""" @@ -306,6 +308,7 @@ class Player(ba.Player['Team']): class Team(ba.Team[Player]): """Our team""" + def __init__(self) -> None: self.score = 0 @@ -618,10 +621,10 @@ def __init__(self, 'color_texture': ba.gettexture('bunnyColor'), 'materials': [SharedObjects.get().footing_material] - if mirror else [ - SharedObjects.get().object_material, - SharedObjects.get().footing_material - ] + if mirror else [ + SharedObjects.get().object_material, + SharedObjects.get().footing_material + ] }) def handlemessage(self, msg: Any) -> Any: diff --git a/plugins/minigames/sleep_race.py b/plugins/minigames/sleep_race.py index 6746524f..104c98ce 100644 --- a/plugins/minigames/sleep_race.py +++ b/plugins/minigames/sleep_race.py @@ -1,7 +1,7 @@ # Released under the MIT License. See LICENSE for details. # y me (: itsre3 # =>2<= -#BCS RULES +# BCS RULES # """Defines Race mini-game.""" @@ -14,7 +14,8 @@ from typing import TYPE_CHECKING from dataclasses import dataclass -import ba, _ba +import ba +import _ba from bastd.actor.bomb import Bomb from bastd.actor.playerspaz import PlayerSpaz from bastd.actor.scoreboard import Scoreboard @@ -215,7 +216,7 @@ def on_transition_in(self) -> None: ('modify_part_collision', 'physical', False), ('call', 'at_connect', self._handle_race_point_collide), - )) + )) for rpt in pts: self._regions.append(RaceRegion(rpt, len(self._regions))) @@ -263,7 +264,7 @@ def _handle_race_point_collide(self) -> None: translate=('statements', 'Killing ${NAME} for' ' skipping part of the track!'), subs=[('${NAME}', player.getname(full=True))]), - color=(1, 0, 0)) + color=(1, 0, 0)) else: # If this player is in first, note that this is the # front-most race-point. @@ -378,7 +379,7 @@ def on_player_leave(self, player: Player) -> None: '${TEAM} is disqualified because ${PLAYER} left'), subs=[('${TEAM}', player.team.name), ('${PLAYER}', player.getname(full=True))]), - color=(1, 1, 0)) + color=(1, 1, 0)) player.team.finished = True player.team.time = None player.team.lap = 0 @@ -435,7 +436,6 @@ def on_begin(self) -> None: 'text': 'By itsre3' })) - # Throw a timer up on-screen. self._time_text = ba.NodeActor( ba.newnode('text', @@ -543,35 +543,34 @@ def _start_race(self) -> None: self._spawn_bomb, repeat=True) - def knock_players(): activity = _ba.get_foreground_host_activity() gnode = ba.getactivity().globalsnode for players in activity.players: - gnode.tint = (0.5,0.5,0.5) + gnode.tint = (0.5, 0.5, 0.5) node = players.actor.node node.handlemessage('knockout', 600.0) self.text_offset = ba.newnode('math', - owner=node, - attrs={'input1': (-0.5, 0.5, 0.25), - 'operation': 'add'}) + owner=node, + attrs={'input1': (-0.5, 0.5, 0.25), + 'operation': 'add'}) node.connectattr( - 'torso_position', - self.text_offset, - 'input2') + 'torso_position', + self.text_offset, + 'input2') self.text = ba.newnode('text', - owner=node, - attrs={ - 'h_align': 'right', - 'color': (1.0, 1.0, 1.0), - 'shadow': 1.0, - 'text': 'z z', - 'scale': 0.01, - 'in_world': True}) + owner=node, + attrs={ + 'h_align': 'right', + 'color': (1.0, 1.0, 1.0), + 'shadow': 1.0, + 'text': 'z z', + 'scale': 0.01, + 'in_world': True}) self.text_offset.connectattr( - 'output', - self.text, - 'position') + 'output', + self.text, + 'position') ba.animate(self.text, 'scale', {0: 0.0, 1.0: 0.01}) ba.timer(2, self.text.delete) @@ -580,9 +579,8 @@ def knock_players(): self._knockout_timer = ba.Timer(knock_time, knock_players, repeat=True) - - self._race_started = True + self._race_started = True def _update_player_order(self) -> None: diff --git a/plugins/minigames/snake.py b/plugins/minigames/snake.py index 7252bfcf..84e912b1 100644 --- a/plugins/minigames/snake.py +++ b/plugins/minigames/snake.py @@ -1,4 +1,4 @@ -#snake +# snake # Released under the MIT License. See LICENSE for details. # """Snake game by SEBASTIAN2059""" @@ -18,50 +18,61 @@ if TYPE_CHECKING: from typing import Any, Type, List, Dict, Tuple, Union, Sequence, Optional + class ScoreMessage: """It will help us with the scores.""" - def __init__(self,player: Player): + + def __init__(self, player: Player): self.player = player - + def getplayer(self): return self.player + class Player(ba.Player['Team']): """Our player type for this game.""" + def __init__(self) -> None: - + self.mines = [] self.actived = None + 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': description = 'Sobrevive a un número determinado de minas para ganar.' join_description = 'Corre y no te dejes matar.' view_description = 'sobrevive ${ARG1} minas' - + else: description = 'Survive a set number of mines to win.' join_description = "Run and don't get killed." view_description = 'survive ${ARG1} mines' + class Custom_Mine(stdbomb.Bomb): """Custom a mine :)""" - def __init__(self,position,source_player): - stdbomb.Bomb.__init__(self,position=position,bomb_type='land_mine',source_player=source_player) - - def handlemessage(self,msg: Any) -> Any: + + def __init__(self, position, source_player): + stdbomb.Bomb.__init__(self, position=position, bomb_type='land_mine', + source_player=source_player) + + def handlemessage(self, msg: Any) -> Any: if isinstance(msg, ba.HitMessage): return else: super().handlemessage(msg) # ba_meta export game + + class SnakeGame(ba.TeamGameActivity[Player, Team]): """A game type based on acquiring kills.""" @@ -122,17 +133,17 @@ def __init__(self, settings: dict): self._scoreboard = Scoreboard() self._score_to_win: Optional[int] = None self._dingsound = ba.getsound('dingSmall') - + self._beep_1_sound = ba.getsound('raceBeep1') self._beep_2_sound = ba.getsound('raceBeep2') - + self._epic_mode = bool(settings['Epic Mode']) self._kills_to_win_per_player = int( settings['Score to Win']) self._time_limit = float(settings['Time Limit']) - + self._started = False - + # Base class overrides. self.slow_motion = self._epic_mode self.default_music = (ba.MusicType.EPIC if self._epic_mode else @@ -151,14 +162,13 @@ def on_team_join(self, team: Team) -> None: def on_begin(self) -> None: super().on_begin() self.setup_standard_time_limit(self._time_limit) - #self.setup_standard_powerup_drops() + # self.setup_standard_powerup_drops() # Base kills needed to win on the size of the largest team. self._score_to_win = (self._kills_to_win_per_player * max(1, max(len(t.players) for t in self.teams))) self._update_scoreboard() - - + if self.slow_motion: t_scale = 0.4 light_y = 50 @@ -220,10 +230,10 @@ def _start_race(self) -> None: ba.playsound(self._beep_2_sound) self._started = True - + for player in self.players: self.generate_mines(player) - + # overriding the default character spawning.. def spawn_player(self, player: Player) -> ba.Actor: spaz = self.spawn_player_spaz(player) @@ -239,33 +249,30 @@ def spawn_player(self, player: Player) -> ba.Actor: if self._started: self.generate_mines(player) return spaz - - - def generate_mines(self,player: Player): + + def generate_mines(self, player: Player): try: - player.actived = ba.Timer(0.5,ba.Call(self.spawn_mine, player),repeat=True) + player.actived = ba.Timer(0.5, ba.Call(self.spawn_mine, player), repeat=True) except Exception as e: - print('Exception -> '+ str(e)) - - - - def spawn_mine(self,player: Player): + print('Exception -> ' + str(e)) + + def spawn_mine(self, player: Player): if player.team.score >= self._score_to_win: return pos = player.actor.node.position # mine = stdbomb.Bomb(position=(pos[0], pos[1] + 2.0, pos[2]), - # velocity=(0, 0, 0), - # bomb_type='land_mine', - # #blast_radius=, - # source_player=player.actor.source_player, - # owner=player.actor.node).autoretain() + # velocity=(0, 0, 0), + # bomb_type='land_mine', + # #blast_radius=, + # source_player=player.actor.source_player, + # owner=player.actor.node).autoretain() mine = Custom_Mine(position=(pos[0], pos[1] + 2.0, pos[2]), - source_player=player.actor.source_player) - + source_player=player.actor.source_player) + def arm(): mine.arm() - ba.timer(0.5,arm) - + ba.timer(0.5, arm) + player.mines.append(mine) if len(player.mines) > 15: for m in player.mines: @@ -275,9 +282,9 @@ def arm(): pass player.mines.remove(m) break - + self.handlemessage(ScoreMessage(player)) - + def handlemessage(self, msg: Any) -> Any: if isinstance(msg, ba.PlayerDiedMessage): @@ -286,18 +293,18 @@ def handlemessage(self, msg: Any) -> Any: player = msg.getplayer(Player) self.respawn_player(player) - + player.actived = None - + elif isinstance(msg, ScoreMessage): player = msg.getplayer() - + player.team.score += 1 self._update_scoreboard() - + assert self._score_to_win is not None if any(team.score >= self._score_to_win for team in self.teams): - self.end_game() #ba.timer(0.5, self.end_game) + self.end_game() # ba.timer(0.5, self.end_game) else: return super().handlemessage(msg) return None diff --git a/plugins/minigames/ufo_fight.py b/plugins/minigames/ufo_fight.py index 29c45716..4823904d 100644 --- a/plugins/minigames/ufo_fight.py +++ b/plugins/minigames/ufo_fight.py @@ -15,7 +15,8 @@ import random from typing import TYPE_CHECKING -import ba, _ba +import ba +import _ba from bastd.actor.playerspaz import PlayerSpaz from bastd.actor.spaz import Spaz from bastd.actor.bomb import Blast, Bomb @@ -56,8 +57,6 @@ class RoboBot(StickyBot): highlight = (3, 3, 3) - - class UFO(ba.Actor): """ New AI for Boss @@ -252,8 +251,8 @@ def _drop_bots(self) -> None: 1.0 + i, lambda: self._bots.spawn_bot( RoboBot, pos=(self.node.position[0], - self.node.position[1] - 1, - self.node.position[2]), spawn_time=0.0 + self.node.position[1] - 1, + self.node.position[2]), spawn_time=0.0 ), ) else: @@ -299,7 +298,6 @@ def raise_player(player: ba.Player): node.position[2], 0, 5, 0, 3, 10, 0, 0, 0, 5, 0) - except: pass @@ -314,7 +312,6 @@ def do_damage(self, msg: Any) -> None: if not self.node: return None - damage = abs(msg.magnitude) if msg.hit_type == 'explosion': damage /= 20 @@ -326,7 +323,7 @@ def do_damage(self, msg: Any) -> None: self.handlemessage(ba.DieMessage()) def _get_target_player_pt(self) -> tuple[ - ba.Vec3 | None, ba.Vec3 | None]: + ba.Vec3 | None, ba.Vec3 | None]: """Returns the position and velocity of our target. Both values will be None in the case of no target. @@ -519,7 +516,6 @@ def _update(self) -> None: {0: self.shield_deco.color, 0.2: (5, 0.2, 0.2)}) self.bot_count = 6 - def update_ai(self) -> None: """Should be called periodically to update the spaz' AI.""" # pylint: disable=too-many-branches @@ -572,9 +568,9 @@ def update_ai(self) -> None: self.to_target.y, self.to_target.z * self.xz_pos)) setattr(self.node, 'extra_acceleration', - (self.to_target.x * self.xz_pos , + (self.to_target.x * self.xz_pos, self.to_target.y * 80 + 70, - self.to_target.z * self.xz_pos)) + self.to_target.z * self.xz_pos)) def on_expire(self) -> None: super().on_expire() @@ -656,7 +652,6 @@ def ded_explode(count): self.xz_pos = 0.01 self.node.reflection_scale = [2] - def unfrozen(): self.frozen = False if self.bot_dur_froze: @@ -666,7 +661,6 @@ def unfrozen(): self.xz_pos = 1 self.node.reflection_scale = [0.25] - ba.timer(5.0, unfrozen) else: @@ -710,8 +704,8 @@ def _update(self) -> None: + str(self._ufo_bot_lists[self._ufo_bot_update_list]) ) self._bot_update_list = ( - self._ufo_bot_update_list + 1 - ) % self._ufo_bot_list_count + self._ufo_bot_update_list + 1 + ) % self._ufo_bot_list_count # Update our list of player points for the bots to use. player_pts = [] @@ -784,7 +778,7 @@ def add_bot(self, bot: UFO) -> None: """Add a ba.SpazBot instance to the set.""" self._ufo_bot_lists[self._ufo_bot_add_list].append(bot) self._ufo_bot_add_list = ( - self._ufo_bot_add_list + 1) % self._ufo_bot_list_count + self._ufo_bot_add_list + 1) % self._ufo_bot_list_count def have_living_bots(self) -> bool: """Return whether any bots in the set are alive or spawning.""" @@ -859,18 +853,16 @@ def __init__(self, settings: dict): self._bots = UFOSet() self._preset = str(settings['preset']) self._credit = ba.newnode('text', - attrs={ - 'v_attach': 'bottom', - 'h_align': 'center', - 'color': (0.4, 0.4, 0.4), - 'flatness': 0.5, - 'shadow': 0.5, - 'position': (0, 20), - 'scale': 0.7, - 'text': 'By Cross Joy' - }) - - + attrs={ + 'v_attach': 'bottom', + 'h_align': 'center', + 'color': (0.4, 0.4, 0.4), + 'flatness': 0.5, + 'shadow': 0.5, + 'position': (0, 20), + 'scale': 0.7, + 'text': 'By Cross Joy' + }) def on_transition_in(self) -> None: super().on_transition_in() @@ -882,8 +874,6 @@ def on_begin(self) -> None: super().on_begin() self.setup_standard_powerup_drops() - - # In pro mode there's no powerups. # Make our on-screen timer and start it roughly when our bots appear. @@ -991,4 +981,3 @@ def on_app_running(self) -> None: preview_texture_name='footballStadiumPreview', ) ) - diff --git a/plugins/minigames/yeeting_party.py b/plugins/minigames/yeeting_party.py index 8ae67214..a5e79a00 100644 --- a/plugins/minigames/yeeting_party.py +++ b/plugins/minigames/yeeting_party.py @@ -1,4 +1,4 @@ -#Made by your friend: @[Just] Freak#4999 +# Made by your friend: @[Just] Freak#4999 # ba_meta require api 7 from __future__ import annotations @@ -116,34 +116,36 @@ def get_instance_description_short(self) -> Union[str, Sequence]: def on_team_join(self, team: Team) -> None: if self.has_begun(): self._update_scoreboard() + def getRandomPowerupPoint(self) -> None: myMap = self.map.getname() if myMap == 'Doom Shroom': while True: - x = random.uniform(-1.0,1.0) - y = random.uniform(-1.0,1.0) - if x*x+y*y < 1.0: break - return ((8.0*x,2.5,-3.5+5.0*y)) + x = random.uniform(-1.0, 1.0) + y = random.uniform(-1.0, 1.0) + if x*x+y*y < 1.0: + break + return ((8.0*x, 2.5, -3.5+5.0*y)) elif myMap == 'Rampage': - x = random.uniform(-6.0,7.0) - y = random.uniform(-6.0,-2.5) + x = random.uniform(-6.0, 7.0) + y = random.uniform(-6.0, -2.5) return ((x, 5.2, y)) else: - x = random.uniform(-5.0,5.0) - y = random.uniform(-6.0,0.0) + x = random.uniform(-5.0, 5.0) + y = random.uniform(-6.0, 0.0) return ((x, 8.0, y)) def on_begin(self) -> None: super().on_begin() - ba.screenmessage("start Yeeting",color = (0.2,1,1)) + ba.screenmessage("start Yeeting", color=(0.2, 1, 1)) self.setup_standard_time_limit(self._time_limit) # Base kills needed to win on the size of the largest team. self._score_to_win = (self._kills_to_win_per_player * max(1, max(len(t.players) for t in self.teams))) self._update_scoreboard() - + def spawn_player(self, player: Player) -> ba.Actor: - + spaz = self.spawn_player_spaz(player) # Let's reconnect this player's controls to this From 721948785c673214345679bd722e5c7ef23ac71d Mon Sep 17 00:00:00 2001 From: Rikko Date: Mon, 15 May 2023 21:38:42 +0530 Subject: [PATCH 0443/1464] Correct JSON fmt --- plugins/minigames.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/minigames.json b/plugins/minigames.json index 0946122a..43bc35f1 100644 --- a/plugins/minigames.json +++ b/plugins/minigames.json @@ -456,6 +456,6 @@ "versions": { "1.0.0": null } - }, + } } } From 499c6890d38166281840544bcb7318d11581ee5e Mon Sep 17 00:00:00 2001 From: rikkolovescats Date: Mon, 15 May 2023 16:09:38 +0000 Subject: [PATCH 0444/1464] [ci] apply-version-metadata --- plugins/minigames.json | 72 +++++++++++++++++++++++++++++++++++------- 1 file changed, 61 insertions(+), 11 deletions(-) diff --git a/plugins/minigames.json b/plugins/minigames.json index 43bc35f1..4251c806 100644 --- a/plugins/minigames.json +++ b/plugins/minigames.json @@ -323,7 +323,12 @@ } ], "versions": { - "1.0.0": null + "1.0.0": { + "api_version": 7, + "commit_sha": "7219487", + "released_on": "15-05-2023", + "md5sum": "1482bb521329ec10ab109d9414c0cc6b" + } } }, "collector": { @@ -342,7 +347,12 @@ } ], "versions": { - "1.0.0": null + "1.0.0": { + "api_version": 7, + "commit_sha": "7219487", + "released_on": "15-05-2023", + "md5sum": "afca5167b564a7f7c0bdc53c3e52d198" + } } }, "dodge_the_ball": { @@ -356,7 +366,12 @@ } ], "versions": { - "1.0.0": null + "1.0.0": { + "api_version": 7, + "commit_sha": "7219487", + "released_on": "15-05-2023", + "md5sum": "6951991607ecef5a6a93cc6eb9e560f5" + } } }, "invisible_one": { @@ -370,7 +385,12 @@ } ], "versions": { - "1.0.0": null + "1.0.0": { + "api_version": 7, + "commit_sha": "7219487", + "released_on": "15-05-2023", + "md5sum": "bc2f85bb6149abbbd496c1b07f3a7189" + } } }, "last_punch_stand": { @@ -384,7 +404,12 @@ } ], "versions": { - "1.0.0": null + "1.0.0": { + "api_version": 7, + "commit_sha": "7219487", + "released_on": "15-05-2023", + "md5sum": "410c3a275970d0c358125dd2edf035e0" + } } }, "quake": { @@ -398,7 +423,12 @@ } ], "versions": { - "1.0.0": null + "1.0.0": { + "api_version": 7, + "commit_sha": "7219487", + "released_on": "15-05-2023", + "md5sum": "a771fb7d37dad80ed29a99bd5ca458d6" + } } }, "sleep_race": { @@ -412,7 +442,12 @@ } ], "versions": { - "1.0.0": null + "1.0.0": { + "api_version": 7, + "commit_sha": "7219487", + "released_on": "15-05-2023", + "md5sum": "c8ea242e4b0b0110541370a2ce1b42fc" + } } }, "snake": { @@ -426,7 +461,12 @@ } ], "versions": { - "1.0.0": null + "1.0.0": { + "api_version": 7, + "commit_sha": "7219487", + "released_on": "15-05-2023", + "md5sum": "cfd9a320ee6fd7b8adb3cae1015c67fa" + } } }, "ufo_fight": { @@ -440,7 +480,12 @@ } ], "versions": { - "1.0.0": null + "1.0.0": { + "api_version": 7, + "commit_sha": "7219487", + "released_on": "15-05-2023", + "md5sum": "81617b130716996368b7d8f20f3a5154" + } } }, "yeeting_party": { @@ -454,8 +499,13 @@ } ], "versions": { - "1.0.0": null + "1.0.0": { + "api_version": 7, + "commit_sha": "7219487", + "released_on": "15-05-2023", + "md5sum": "197a377652ab0c3bfbe1ca07833924b4" + } } } } -} +} \ No newline at end of file From 25c2a85d2f36f82f48ab1fe30b6a889e64ad970e Mon Sep 17 00:00:00 2001 From: Rikko Date: Mon, 15 May 2023 21:43:40 +0530 Subject: [PATCH 0445/1464] Correct a few typos --- plugins/minigames.json | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/plugins/minigames.json b/plugins/minigames.json index 4251c806..9fb0e30d 100644 --- a/plugins/minigames.json +++ b/plugins/minigames.json @@ -313,7 +313,7 @@ } }, "arms_race": { - "description": "Upgrade your weapons by eliminating enemies.Win by being first one to kill while cursed", + "description": "Upgrade your weapons by eliminating enemies. Win by being first one to kill while cursed", "external_url": "", "authors": [ { @@ -332,7 +332,7 @@ } }, "collector": { - "description": "Kill your opponents to steal their Capsules.Collect them and score at the Deposist Point!", + "description": "Kill your opponents to steal their Capsules. Collect them and score at the Deposit Point!", "external_url": "", "authors": [ { @@ -375,7 +375,7 @@ } }, "invisible_one": { - "description": "Be the invisible one for a length of time to win.Kill the invisible one to become it.", + "description": "Be the invisible one for a length of time to win. Kill the invisible one to become it.", "external_url": "", "authors": [ { @@ -508,4 +508,4 @@ } } } -} \ No newline at end of file +} From 635a773053230dcf1a2dfa0bc1a8bca637620c1a Mon Sep 17 00:00:00 2001 From: rikkolovescats Date: Mon, 15 May 2023 16:14:20 +0000 Subject: [PATCH 0446/1464] [ci] apply-version-metadata --- plugins/minigames.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/minigames.json b/plugins/minigames.json index 9fb0e30d..2ce28e70 100644 --- a/plugins/minigames.json +++ b/plugins/minigames.json @@ -508,4 +508,4 @@ } } } -} +} \ No newline at end of file From a36e0289c81ff87381523508b089211cf30338a1 Mon Sep 17 00:00:00 2001 From: Rikko Date: Mon, 15 May 2023 22:22:47 +0530 Subject: [PATCH 0447/1464] Add Mrmaxmeier --- plugins/minigames.json | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/plugins/minigames.json b/plugins/minigames.json index 2ce28e70..9078008c 100644 --- a/plugins/minigames.json +++ b/plugins/minigames.json @@ -316,6 +316,11 @@ "description": "Upgrade your weapons by eliminating enemies. Win by being first one to kill while cursed", "external_url": "", "authors": [ + { + "name": "Mrmaxmeier", + "email": "", + "discord": "" + }, { "name": "Freaku", "email": "", @@ -508,4 +513,4 @@ } } } -} \ No newline at end of file +} From 6495b0a1deeb88b2408b4666cdd43b4d7746b147 Mon Sep 17 00:00:00 2001 From: rikkolovescats Date: Mon, 15 May 2023 16:54:14 +0000 Subject: [PATCH 0448/1464] [ci] apply-version-metadata --- plugins/minigames.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/minigames.json b/plugins/minigames.json index 9078008c..a82912be 100644 --- a/plugins/minigames.json +++ b/plugins/minigames.json @@ -513,4 +513,4 @@ } } } -} +} \ No newline at end of file From 7a91d6bbf50ea78c946ae9329be19a062b436962 Mon Sep 17 00:00:00 2001 From: Rikko Date: Tue, 16 May 2023 01:10:03 +0530 Subject: [PATCH 0449/1464] Refer to sample plugin source template --- README.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index e2825f82..c853fa2e 100644 --- a/README.md +++ b/README.md @@ -174,9 +174,9 @@ That's it! Now you can make a [pull request](../../compare) with both the update - In case your plugin doesn't sit well with our guidelines or you wouldn't want your plugin to be here for some reason, you can create your own GitHub repository and put all your plugins in there. -- Check out https://github.com/rikkolovescats/sahilp-plugins as an example. You can choose to show up plugins from this - repository in your plugin manager by adding `rikkolovescats/sahilp-plugins` as a custom source through the category - selection popup window in-game. +- Check out [bombsquad-community/sample-plugin-source](https://github.com/bombsquad-community/sample-plugin-source) as an example. + You can choose to show up plugins from this repository in your plugin manager by adding `bombsquad-community/sample-plugin-source` + as a custom source through the category selection popup window in-game. #### Known 3rd Party Plugin Sources @@ -184,7 +184,7 @@ That's it! Now you can make a [pull request](../../compare) with both the update 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 + [rikkolovescats/sahilp-plugins](https://github.com/rikkolovescats/sahilp-plugins) ## Tests From 15a2216436878165669cc72411cff9fca878e10e Mon Sep 17 00:00:00 2001 From: Rikko Date: Tue, 16 May 2023 02:50:24 +0530 Subject: [PATCH 0450/1464] Correct minigame metadata --- plugins/minigames.json | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/plugins/minigames.json b/plugins/minigames.json index a82912be..14ed407d 100644 --- a/plugins/minigames.json +++ b/plugins/minigames.json @@ -399,8 +399,8 @@ } }, "last_punch_stand": { - "description": "", - "external_url": "Last one to punch the spaz when timer ends wins", + "description": "Last one to punch the spaz when timer ends wins", + "external_url": "", "authors": [ { "name": "ThePersonMan", @@ -460,7 +460,7 @@ "external_url": "", "authors": [ { - "name": "Sebastian", + "name": "SEBASTIAN2059", "email": "", "discord": "SEBASTIAN2059#5751" } @@ -513,4 +513,4 @@ } } } -} \ No newline at end of file +} From a2152d5a4c97ae871ed034911d4ffd251249982a Mon Sep 17 00:00:00 2001 From: rikkolovescats Date: Mon, 15 May 2023 21:21:17 +0000 Subject: [PATCH 0451/1464] [ci] apply-version-metadata --- plugins/minigames.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/minigames.json b/plugins/minigames.json index 14ed407d..b15f63a2 100644 --- a/plugins/minigames.json +++ b/plugins/minigames.json @@ -513,4 +513,4 @@ } } } -} +} \ No newline at end of file From e3203684bb2c6a3dcebe48df8b11a8ad2cfff0d4 Mon Sep 17 00:00:00 2001 From: Loup-Garou911XD Date: Fri, 19 May 2023 01:46:55 +0530 Subject: [PATCH 0452/1464] pickup,punch btn is now bomb btn --- plugins/minigames/arms_race.py | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/plugins/minigames/arms_race.py b/plugins/minigames/arms_race.py index 728f7c0e..459a57e4 100644 --- a/plugins/minigames/arms_race.py +++ b/plugins/minigames/arms_race.py @@ -30,6 +30,7 @@ def __init__(self, bomb=None, grab=False, punch=False, curse=False, required=Fal self.next = None self.index = None + def apply(self, spaz): spaz.disconnect_controls_from_player() spaz.connect_controls_to_player(enable_punch=self.punch, @@ -154,6 +155,19 @@ def on_player_join(self, player): player.state = self.states[0] self.spawn_player(player) + def idk(self,spaz:PlayerSpaz): + + return {"press":{ + ba.InputType.PUNCH_PRESS : spaz.on_punch_press, + ba.InputType.PICK_UP_PRESS : spaz.on_pickup_press,}, + "release":{ + ba.InputType.PUNCH_RELEASE : spaz.on_punch_release, + ba.InputType.PICK_UP_RELEASE : spaz.on_pickup_release} + } + + def set_controls(self,spaz:PlayerSpaz,): + spaz.on_punch_press() + # overriding the default character spawning.. def spawn_player(self, player): if player.state is None: @@ -161,6 +175,19 @@ def spawn_player(self, player): super().spawn_player(player) player.state.apply(player.actor) + press_input=self.idk(player.actor)["press"] + release_input=self.idk(player.actor)["release"] + + for press,release in zip(press_input.keys(),release_input.keys()): + player.assigninput( + press, + lambda : player.actor.on_bomb_press() + ) + player.assigninput( + release, + lambda: player.actor.on_bomb_release() + ) + def isValidKill(self, m): if m.getkillerplayer(Player) is None: return False From eb7e05ad72f61fbf555bbccfa3a48898ee284834 Mon Sep 17 00:00:00 2001 From: Loup-Garou911XD Date: Thu, 18 May 2023 20:20:53 +0000 Subject: [PATCH 0453/1464] [ci] auto-format --- plugins/minigames/arms_race.py | 27 +++++++++++++-------------- 1 file changed, 13 insertions(+), 14 deletions(-) diff --git a/plugins/minigames/arms_race.py b/plugins/minigames/arms_race.py index 459a57e4..f97407d0 100644 --- a/plugins/minigames/arms_race.py +++ b/plugins/minigames/arms_race.py @@ -30,7 +30,6 @@ def __init__(self, bomb=None, grab=False, punch=False, curse=False, required=Fal self.next = None self.index = None - def apply(self, spaz): spaz.disconnect_controls_from_player() spaz.connect_controls_to_player(enable_punch=self.punch, @@ -155,17 +154,17 @@ def on_player_join(self, player): player.state = self.states[0] self.spawn_player(player) - def idk(self,spaz:PlayerSpaz): + def idk(self, spaz: PlayerSpaz): - return {"press":{ - ba.InputType.PUNCH_PRESS : spaz.on_punch_press, - ba.InputType.PICK_UP_PRESS : spaz.on_pickup_press,}, - "release":{ - ba.InputType.PUNCH_RELEASE : spaz.on_punch_release, - ba.InputType.PICK_UP_RELEASE : spaz.on_pickup_release} - } + return {"press": { + ba.InputType.PUNCH_PRESS: spaz.on_punch_press, + ba.InputType.PICK_UP_PRESS: spaz.on_pickup_press, }, + "release": { + ba.InputType.PUNCH_RELEASE: spaz.on_punch_release, + ba.InputType.PICK_UP_RELEASE: spaz.on_pickup_release} + } - def set_controls(self,spaz:PlayerSpaz,): + def set_controls(self, spaz: PlayerSpaz,): spaz.on_punch_press() # overriding the default character spawning.. @@ -175,13 +174,13 @@ def spawn_player(self, player): super().spawn_player(player) player.state.apply(player.actor) - press_input=self.idk(player.actor)["press"] - release_input=self.idk(player.actor)["release"] + press_input = self.idk(player.actor)["press"] + release_input = self.idk(player.actor)["release"] - for press,release in zip(press_input.keys(),release_input.keys()): + for press, release in zip(press_input.keys(), release_input.keys()): player.assigninput( press, - lambda : player.actor.on_bomb_press() + lambda: player.actor.on_bomb_press() ) player.assigninput( release, From dd4dd9089c903e206c3556344f1a0b74cc81a90b Mon Sep 17 00:00:00 2001 From: Loup-Garou911XD Date: Fri, 19 May 2023 10:10:16 +0530 Subject: [PATCH 0454/1464] removed on press inputs --- plugins/minigames/arms_race.py | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/plugins/minigames/arms_race.py b/plugins/minigames/arms_race.py index 459a57e4..f5df451c 100644 --- a/plugins/minigames/arms_race.py +++ b/plugins/minigames/arms_race.py @@ -32,10 +32,10 @@ def __init__(self, bomb=None, grab=False, punch=False, curse=False, required=Fal def apply(self, spaz): - spaz.disconnect_controls_from_player() - spaz.connect_controls_to_player(enable_punch=self.punch, - enable_bomb=self.bomb, - enable_pickup=self.grab) + #spaz.disconnect_controls_from_player() + #spaz.connect_controls_to_player(enable_punch=self.punch, + # enable_bomb=self.bomb, + # enable_pickup=self.grab) if self.curse: spaz.curse_time = -1 spaz.curse() @@ -179,10 +179,10 @@ def spawn_player(self, player): release_input=self.idk(player.actor)["release"] for press,release in zip(press_input.keys(),release_input.keys()): - player.assigninput( - press, - lambda : player.actor.on_bomb_press() - ) +# player.assigninput( +# press, +# lambda : player.actor.on_bomb_press() +# ) player.assigninput( release, lambda: player.actor.on_bomb_release() From f681ef4ad8bcd4f0b61dcffaf1986f18532a5115 Mon Sep 17 00:00:00 2001 From: Loup-Garou911XD Date: Fri, 19 May 2023 04:45:41 +0000 Subject: [PATCH 0455/1464] [ci] auto-format --- plugins/minigames/arms_race.py | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/plugins/minigames/arms_race.py b/plugins/minigames/arms_race.py index b1686331..ffa2770f 100644 --- a/plugins/minigames/arms_race.py +++ b/plugins/minigames/arms_race.py @@ -31,8 +31,8 @@ def __init__(self, bomb=None, grab=False, punch=False, curse=False, required=Fal self.index = None def apply(self, spaz): - #spaz.disconnect_controls_from_player() - #spaz.connect_controls_to_player(enable_punch=self.punch, + # spaz.disconnect_controls_from_player() + # spaz.connect_controls_to_player(enable_punch=self.punch, # enable_bomb=self.bomb, # enable_pickup=self.grab) if self.curse: @@ -177,11 +177,11 @@ def spawn_player(self, player): press_input = self.idk(player.actor)["press"] release_input = self.idk(player.actor)["release"] - for press,release in zip(press_input.keys(),release_input.keys()): -# player.assigninput( -# press, -# lambda : player.actor.on_bomb_press() -# ) + for press, release in zip(press_input.keys(), release_input.keys()): + # player.assigninput( + # press, + # lambda : player.actor.on_bomb_press() + # ) player.assigninput( release, lambda: player.actor.on_bomb_release() From 6bf4dae698d51eea019f76f7a6984f95160f50e0 Mon Sep 17 00:00:00 2001 From: Loup-Garou911XD Date: Sat, 20 May 2023 20:26:54 +0530 Subject: [PATCH 0456/1464] Fix and Updated minigames.json --- plugins/minigames.json | 8 ++++- plugins/minigames/arms_race.py | 53 ++++++++++++++-------------------- 2 files changed, 29 insertions(+), 32 deletions(-) diff --git a/plugins/minigames.json b/plugins/minigames.json index b15f63a2..d0e12251 100644 --- a/plugins/minigames.json +++ b/plugins/minigames.json @@ -325,9 +325,15 @@ "name": "Freaku", "email": "", "discord": "[Just] Freak#4999" + }, + { + "name": "LoupGarou", + "email": "LoupGarou5418@outlook.com", + "discord": "ʟօʊքɢǟʀօʊ#3063" } ], "versions": { + "1.1.0": null, "1.0.0": { "api_version": 7, "commit_sha": "7219487", @@ -513,4 +519,4 @@ } } } -} \ No newline at end of file +} diff --git a/plugins/minigames/arms_race.py b/plugins/minigames/arms_race.py index ffa2770f..fb3da8b1 100644 --- a/plugins/minigames/arms_race.py +++ b/plugins/minigames/arms_race.py @@ -30,11 +30,14 @@ def __init__(self, bomb=None, grab=False, punch=False, curse=False, required=Fal self.next = None self.index = None - def apply(self, spaz): - # spaz.disconnect_controls_from_player() - # spaz.connect_controls_to_player(enable_punch=self.punch, - # enable_bomb=self.bomb, - # enable_pickup=self.grab) + + + def apply(self, player,spaz): + + spaz.disconnect_controls_from_player() + spaz.connect_controls_to_player(enable_punch=self.punch, + enable_bomb=self.bomb, + enable_pickup=self.grab) if self.curse: spaz.curse_time = -1 spaz.curse() @@ -42,6 +45,18 @@ def apply(self, spaz): spaz.bomb_type = self.bomb spaz.set_score_text(self.name) + def set_controls(): + player.actor.node.bomb_pressed=True + player.actor.on_bomb_release() + + release_input=(ba.InputType.PUNCH_RELEASE,ba.InputType.PICK_UP_RELEASE) + if not self.bomb is None: + for release in release_input: + player.assigninput( + release, + set_controls + ) + def get_setting(self): return (self.name) @@ -154,38 +169,14 @@ def on_player_join(self, player): player.state = self.states[0] self.spawn_player(player) - def idk(self, spaz: PlayerSpaz): - - return {"press": { - ba.InputType.PUNCH_PRESS: spaz.on_punch_press, - ba.InputType.PICK_UP_PRESS: spaz.on_pickup_press, }, - "release": { - ba.InputType.PUNCH_RELEASE: spaz.on_punch_release, - ba.InputType.PICK_UP_RELEASE: spaz.on_pickup_release} - } - - def set_controls(self, spaz: PlayerSpaz,): - spaz.on_punch_press() # overriding the default character spawning.. def spawn_player(self, player): if player.state is None: player.state = self.states[0] super().spawn_player(player) - player.state.apply(player.actor) - - press_input = self.idk(player.actor)["press"] - release_input = self.idk(player.actor)["release"] + player.state.apply(player,player.actor) - for press, release in zip(press_input.keys(), release_input.keys()): - # player.assigninput( - # press, - # lambda : player.actor.on_bomb_press() - # ) - player.assigninput( - release, - lambda: player.actor.on_bomb_release() - ) def isValidKill(self, m): if m.getkillerplayer(Player) is None: @@ -203,7 +194,7 @@ def handlemessage(self, msg: Any) -> Any: self.stats.player_scored(msg.getkillerplayer(Player), 10, kill=True) if not msg.getkillerplayer(Player).state.final: msg.getkillerplayer(Player).state = msg.getkillerplayer(Player).state.next - msg.getkillerplayer(Player).state.apply(msg.getkillerplayer(Player).actor) + msg.getkillerplayer(Player).state.apply(msg.getkillerplayer(Player),msg.getkillerplayer(Player).actor) else: msg.getkillerplayer(Player).team.score += 1 self.end_game() From 2e2540ae5bc4ae2e72404b1b48512c3a2d79e1cf Mon Sep 17 00:00:00 2001 From: Loup-Garou911XD Date: Sat, 20 May 2023 14:58:01 +0000 Subject: [PATCH 0457/1464] [ci] auto-format --- plugins/minigames/arms_race.py | 18 ++++++++---------- 1 file changed, 8 insertions(+), 10 deletions(-) diff --git a/plugins/minigames/arms_race.py b/plugins/minigames/arms_race.py index fb3da8b1..b7ea3f59 100644 --- a/plugins/minigames/arms_race.py +++ b/plugins/minigames/arms_race.py @@ -30,10 +30,8 @@ def __init__(self, bomb=None, grab=False, punch=False, curse=False, required=Fal self.next = None self.index = None - - - def apply(self, player,spaz): - + def apply(self, player, spaz): + spaz.disconnect_controls_from_player() spaz.connect_controls_to_player(enable_punch=self.punch, enable_bomb=self.bomb, @@ -46,10 +44,10 @@ def apply(self, player,spaz): spaz.set_score_text(self.name) def set_controls(): - player.actor.node.bomb_pressed=True + player.actor.node.bomb_pressed = True player.actor.on_bomb_release() - release_input=(ba.InputType.PUNCH_RELEASE,ba.InputType.PICK_UP_RELEASE) + release_input = (ba.InputType.PUNCH_RELEASE, ba.InputType.PICK_UP_RELEASE) if not self.bomb is None: for release in release_input: player.assigninput( @@ -169,14 +167,13 @@ def on_player_join(self, player): player.state = self.states[0] self.spawn_player(player) - # overriding the default character spawning.. + def spawn_player(self, player): if player.state is None: player.state = self.states[0] super().spawn_player(player) - player.state.apply(player,player.actor) - + player.state.apply(player, player.actor) def isValidKill(self, m): if m.getkillerplayer(Player) is None: @@ -194,7 +191,8 @@ def handlemessage(self, msg: Any) -> Any: self.stats.player_scored(msg.getkillerplayer(Player), 10, kill=True) if not msg.getkillerplayer(Player).state.final: msg.getkillerplayer(Player).state = msg.getkillerplayer(Player).state.next - msg.getkillerplayer(Player).state.apply(msg.getkillerplayer(Player),msg.getkillerplayer(Player).actor) + msg.getkillerplayer(Player).state.apply( + msg.getkillerplayer(Player), msg.getkillerplayer(Player).actor) else: msg.getkillerplayer(Player).team.score += 1 self.end_game() From a0af0d00f6a29eac8be19d5e55e3264fbaa01fe7 Mon Sep 17 00:00:00 2001 From: Loup-Garou911XD Date: Sat, 20 May 2023 14:58:02 +0000 Subject: [PATCH 0458/1464] [ci] apply-version-metadata --- plugins/minigames.json | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/plugins/minigames.json b/plugins/minigames.json index d0e12251..66ba30dd 100644 --- a/plugins/minigames.json +++ b/plugins/minigames.json @@ -333,7 +333,12 @@ } ], "versions": { - "1.1.0": null, + "1.1.0": { + "api_version": 7, + "commit_sha": "2e2540a", + "released_on": "20-05-2023", + "md5sum": "e06fbfeb1c0c4c78e04054caab3d593f" + }, "1.0.0": { "api_version": 7, "commit_sha": "7219487", @@ -519,4 +524,4 @@ } } } -} +} \ No newline at end of file From d91fea3f5df7d969b772d36f888520c85c452934 Mon Sep 17 00:00:00 2001 From: Silver-Volt4 <35656715+Silver-Volt4@users.noreply.github.com> Date: Thu, 25 May 2023 21:45:53 +0200 Subject: [PATCH 0459/1464] Commit Plugin (for SHA) --- plugins/utilities/random_play.py | 191 +++++++++++++++++++++++++++++++ 1 file changed, 191 insertions(+) create mode 100644 plugins/utilities/random_play.py diff --git a/plugins/utilities/random_play.py b/plugins/utilities/random_play.py new file mode 100644 index 00000000..6e21b284 --- /dev/null +++ b/plugins/utilities/random_play.py @@ -0,0 +1,191 @@ +# ba_meta require api 7 +from random import choice, randint +from typing import Any, Union + +# pylint: disable=import-error +import _ba +import ba +from bastd.ui.playlist.browser import PlaylistBrowserWindow + +DEFAULT_TEAM_COLORS = ((0.1, 0.25, 1.0), (1.0, 0.25, 0.2)) +DEFAULT_TEAM_NAMES = ("Blue", "Red") + + +# More or less copied from game code +# I have no idea what I'm doing here +class RandomPlaySessionMixin(ba.MultiTeamSession, ba.Session): + def __init__(self, playlist) -> None: + """Set up playlists and launches a ba.Activity to accept joiners.""" + # pylint: disable=cyclic-import + from bastd.activity.multiteamjoin import MultiTeamJoinActivity + + app = _ba.app + _cfg = app.config + + super(ba.MultiTeamSession, self).__init__( + [], + team_names=DEFAULT_TEAM_NAMES, + team_colors=DEFAULT_TEAM_COLORS, + min_players=1, + max_players=self.get_max_players(), + ) + + self._series_length = app.teams_series_length + self._ffa_series_length = app.ffa_series_length + + self._tutorial_activity_instance = None + self._game_number = 0 + + # Our faux playlist + self._playlist = playlist + + self._current_game_spec: dict[str, Any] | None = None + self._next_game_spec: dict[str, Any] = self._playlist.pull_next() + self._next_game: type[ba.GameActivity] = self._next_game_spec["resolved_type"] + + self._instantiate_next_game() + self.setactivity(_ba.newactivity(MultiTeamJoinActivity)) + + +# Classes for Teams autopilot and FFA autopilot +# I think they have to be separate in order to comply with `ba.GameActivity.supports_session_type()` +class RandFreeForAllSession(ba.FreeForAllSession, RandomPlaySessionMixin): + def __init__(self): + playlist = RandomPlaylist(ba.FreeForAllSession) + super(ba.FreeForAllSession, self).__init__(playlist) + + +class RandDualTeamSession(ba.DualTeamSession, RandomPlaySessionMixin): + def __init__(self): + playlist = RandomPlaylist(ba.DualTeamSession) + super(ba.DualTeamSession, self).__init__(playlist) + + +# The faux playlist that just picks games at random +class RandomPlaylist: + sessiontype: ba.Session + all_games: list[ba.GameActivity] + usable_games: list[ba.GameActivity] + + last_game: ba.GameActivity + + def __init__(self, sessiontype): + self.sessiontype = sessiontype + self.usable_games = [ + gt + for gt in RandomPlaylist.all_games + if gt.supports_session_type(self.sessiontype) + ] + self.last_game = None + + def pull_next(self) -> dict[str, Any]: + """ + Generate a new game at random. + """ + + has_only_one_game = len(self.usable_games) == 1 + + while True: + game = choice(self.usable_games) + if game == self.last_game: + # Don't repeat the same game twice + if has_only_one_game: + # ...but don't freeze the game when there's only one game + break + else: + break + + game_map = choice(game.get_supported_maps(self.sessiontype)) + settings = { + s.name: s.default for s in game.get_available_settings(self.sessiontype) + } + settings["map"] = game_map + + if "Epic Mode" in settings: + # Throw in an Epic Mode once in a while + settings["Epic Mode"] = randint(0, 4) == 4 + + return {"resolved_type": game, "settings": settings} + + +# Adapted from plugin quick_custom_game. +# Hope you don't mind. +def patched__init__( + self, + sessiontype: type[ba.Session], + transition: str | None = "in_right", + origin_widget: ba.Widget | None = None, +): + width = 800 + height = 650 + + ui_scale = ba.app.ui.uiscale + y_offset = -100 if ui_scale is ba.UIScale.SMALL else 0 + x_offset = 50 if ui_scale is ba.UIScale.SMALL else 0 + + self.old__init__(sessiontype, transition, origin_widget) + # pylint: disable=protected-access + self._quick_game_button = ba.buttonwidget( + parent=self._root_widget, + position=(width - 120 * 2 + x_offset, height - 132 + y_offset), + autoselect=True, + size=(120, 60), + scale=1.1, + text_scale=1.2, + label="Random games", + on_activate_call=game_starter_factory(sessiontype), + color=(0.54, 0.52, 0.67), + textcolor=(0.7, 0.65, 0.7), + ) + + +# Returns a function that starts the game +def game_starter_factory(sessiontype: type[ba.Session]): + session: Union[RandFreeForAllSession, RandDualTeamSession] = None + + if issubclass(sessiontype, ba.FreeForAllSession): + session = RandFreeForAllSession + elif issubclass(sessiontype, ba.DualTeamSession): + session = RandDualTeamSession + else: + raise RuntimeError("Can't determine session type") + + def on_run(): + can_start = False + + def do_start(game_list): + nonlocal can_start + RandomPlaylist.all_games = game_list + if not can_start: # Don't start if the screen fade is still ongoing + can_start = True + else: + start() + + def has_faded(): + nonlocal can_start + if not can_start: # Don't start if it's still loading + can_start = True + else: + start() + + def start(): + _ba.unlock_all_input() + _ba.new_host_session(session) + + _ba.fade_screen(False, time=0.25, endcall=has_faded) + _ba.lock_all_input() + ba.app.meta.load_exported_classes(ba.GameActivity, do_start) + + return on_run + + +# ba_meta export plugin +class RandomPlayPlugin(ba.Plugin): + """ + A plugin that allows you to play randomly generated FFA or Teams matches by selecting a random minigame and map for each round. + This eliminates the need to set up long playlists to enjoy all your BombSquad content. + """ + + def __init__(self): + PlaylistBrowserWindow.old__init__ = PlaylistBrowserWindow.__init__ + PlaylistBrowserWindow.__init__ = patched__init__ From d9a606e3b6e50d8b730514b03bb6875e135e6950 Mon Sep 17 00:00:00 2001 From: Silver-Volt4 <35656715+Silver-Volt4@users.noreply.github.com> Date: Thu, 25 May 2023 21:48:36 +0200 Subject: [PATCH 0460/1464] Add changed utilities.json file --- plugins/utilities.json | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/plugins/utilities.json b/plugins/utilities.json index b10844ff..bd291a04 100644 --- a/plugins/utilities.json +++ b/plugins/utilities.json @@ -670,6 +670,25 @@ "md5sum": "24913c665d05c3056c8ba390fe88155e" } } + }, + "random_play": { + "description": "A plugin that allows you to play randomly generated FFA or Teams matches by selecting a random minigame and map for each round. This eliminates the need to set up long playlists to enjoy all your BombSquad content.", + "external_url": "", + "authors": [ + { + "name": "silver_volt4", + "email": "", + "discord": "Silver_Volt4#6502" + } + ], + "versions": { + "1.0.0": { + "api_version": 7, + "commit_sha": "d91fea3", + "released_on": "25-05-2023", + "md5sum": "cec9a9c6f6aebddd8ec8160f7cc94b57" + } + } } } } \ No newline at end of file From 527d9fcd4f8864799fd2b30d9bd7d6bdd93ad6b7 Mon Sep 17 00:00:00 2001 From: Silver-Volt4 <35656715+Silver-Volt4@users.noreply.github.com> Date: Thu, 25 May 2023 22:03:37 +0200 Subject: [PATCH 0461/1464] shorten description --- plugins/utilities.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/utilities.json b/plugins/utilities.json index bd291a04..d660a908 100644 --- a/plugins/utilities.json +++ b/plugins/utilities.json @@ -672,7 +672,7 @@ } }, "random_play": { - "description": "A plugin that allows you to play randomly generated FFA or Teams matches by selecting a random minigame and map for each round. This eliminates the need to set up long playlists to enjoy all your BombSquad content.", + "description": "Play randomly generated FFA or Teams matches from your installed minigames and maps.", "external_url": "", "authors": [ { From 3ef572f3d854d86cfb619a192a1d98ece15f3305 Mon Sep 17 00:00:00 2001 From: Silver-Volt4 <35656715+Silver-Volt4@users.noreply.github.com> Date: Thu, 25 May 2023 22:29:27 +0200 Subject: [PATCH 0462/1464] i hath done an oopsie --- plugins/utilities/random_play.py | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/plugins/utilities/random_play.py b/plugins/utilities/random_play.py index 6e21b284..463ecf9f 100644 --- a/plugins/utilities/random_play.py +++ b/plugins/utilities/random_play.py @@ -67,11 +67,11 @@ class RandomPlaylist: all_games: list[ba.GameActivity] usable_games: list[ba.GameActivity] - last_game: ba.GameActivity + last_game: str def __init__(self, sessiontype): self.sessiontype = sessiontype - self.usable_games = [ + self.usable_games: list[ba.GameActivity] = [ gt for gt in RandomPlaylist.all_games if gt.supports_session_type(self.sessiontype) @@ -87,7 +87,7 @@ def pull_next(self) -> dict[str, Any]: while True: game = choice(self.usable_games) - if game == self.last_game: + if game.name == self.last_game: # Don't repeat the same game twice if has_only_one_game: # ...but don't freeze the game when there's only one game @@ -95,6 +95,7 @@ def pull_next(self) -> dict[str, Any]: else: break + self.last_game = game.name game_map = choice(game.get_supported_maps(self.sessiontype)) settings = { s.name: s.default for s in game.get_available_settings(self.sessiontype) From f556f6a16508092b98d5eb45ca78631377bc7598 Mon Sep 17 00:00:00 2001 From: Silver-Volt4 <35656715+Silver-Volt4@users.noreply.github.com> Date: Thu, 25 May 2023 22:30:59 +0200 Subject: [PATCH 0463/1464] i hath undone the oopsie --- plugins/utilities.json | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/plugins/utilities.json b/plugins/utilities.json index d660a908..fcbd8002 100644 --- a/plugins/utilities.json +++ b/plugins/utilities.json @@ -682,6 +682,12 @@ } ], "versions": { + "1.0.1": { + "api_version": 7, + "commit_sha": "3ef572f", + "released_on": "25-05-2023", + "md5sum": "f093c09b3e9439755a515ae6751e1f7e" + }, "1.0.0": { "api_version": 7, "commit_sha": "d91fea3", From 25e60eaa8c6d5769a443d954b055af98ae6f8942 Mon Sep 17 00:00:00 2001 From: Ayush Saini <36878972+imayushsaini@users.noreply.github.com> Date: Mon, 5 Jun 2023 01:32:24 +0530 Subject: [PATCH 0464/1464] new mini games --- plugins/minigames.json | 56 ++++ plugins/minigames/castel_queen.py | 407 ++++++++++++++++++++++++++ plugins/minigames/demolition_war.py | 303 ++++++++++++++++++++ plugins/minigames/drone_war.py | 426 ++++++++++++++++++++++++++++ plugins/minigames/the_spaz_game.py | 122 ++++++++ 5 files changed, 1314 insertions(+) create mode 100644 plugins/minigames/castel_queen.py create mode 100644 plugins/minigames/demolition_war.py create mode 100644 plugins/minigames/drone_war.py create mode 100644 plugins/minigames/the_spaz_game.py diff --git a/plugins/minigames.json b/plugins/minigames.json index 66ba30dd..909e72d5 100644 --- a/plugins/minigames.json +++ b/plugins/minigames.json @@ -293,6 +293,62 @@ } } }, + "demolition_war": { + "description": "BombFight on wooden floor flying in air.", + "external_url": "https://www.youtube.com/channel/UCaQajfKHrTPgiOhuias5iPg", + "authors": [ + { + "name": "Mr.Smoothy", + "email": "smoothy@bombsquad.ga", + "discord": "mr.smoothy#5824" + } + ], + "versions": { + "1.0.0": null + } + }, + "castel_queen": { + "description": "Carry the queen for some duration in her room.", + "external_url": "https://www.youtube.com/channel/UCaQajfKHrTPgiOhuias5iPg", + "authors": [ + { + "name": "Mr.Smoothy", + "email": "smoothy@bombsquad.ga", + "discord": "mr.smoothy#5824" + } + ], + "versions": { + "1.0.0": null + } + }, + "drone_war": { + "description": "Fly with Drone and attack with rocket launcher", + "external_url": "https://www.youtube.com/channel/UCaQajfKHrTPgiOhuias5iPg", + "authors": [ + { + "name": "Mr.Smoothy", + "email": "smoothy@bombsquad.ga", + "discord": "mr.smoothy#5824" + } + ], + "versions": { + "1.0.0": null + } + }, + "the_spaz_game": { + "description": "Enemy Spaz Amoung us, kill correct person.", + "external_url": "https://www.youtube.com/channel/UCaQajfKHrTPgiOhuias5iPg", + "authors": [ + { + "name": "Mr.Smoothy", + "email": "smoothy@bombsquad.ga", + "discord": "mr.smoothy#5824" + } + ], + "versions": { + "1.0.0": null + } + }, "air_soccer": { "description": "Play soccer while flying in air", "external_url": "https://youtu.be/j6FFk7E6W_U", diff --git a/plugins/minigames/castel_queen.py b/plugins/minigames/castel_queen.py new file mode 100644 index 00000000..02986ce7 --- /dev/null +++ b/plugins/minigames/castel_queen.py @@ -0,0 +1,407 @@ +# Released under the MIT License. See LICENSE for details. +# +""" +CastelQueen - Carry the Queen alone or with your team. +Author: Mr.Smoothy +Discord: https://discord.gg/ucyaesh +Youtube: https://www.youtube.com/c/HeySmoothy +Website: https://bombsquad-community.web.app +Github: https://github.com/bombsquad-community +""" +# ba_meta require api 7 +# (see https://ballistica.net/wiki/meta-tag-system) + +from __future__ import annotations + +from typing import TYPE_CHECKING + +import ba +import _ba + +from bastd.gameutils import SharedObjects +from bastd.actor.playerspaz import PlayerSpaz +from bastd.game.keepaway import KeepAwayGame, FlagState, Player +from bastd.actor import spaz +if TYPE_CHECKING: + from typing import Any, Sequence, Dict, Type, List, Optional, Union + +# ba_meta export game +class ChooseQueen(KeepAwayGame): + name = 'FCUK The Queen' + description = 'Carry the queen for a set length of time' + @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 ['Creative Thoughts'] + + def get_instance_description(self) -> str | Sequence: + return 'FCUK the queen for ${ARG1} seconds.', self._hold_time + + def get_instance_description_short(self) -> str | Sequence: + return 'FCUK the queen for ${ARG1} seconds', self._hold_time + + def __init__(self, settings: dict): + super().__init__(settings) + shared = SharedObjects.get() + self.lifts = {} + self._room_wall_material = ba.Material() + self._room_wall_material.add_actions( + actions=( + ('modify_part_collision', 'collide', False), + ('modify_part_collision', 'physical', False) + )) + self._queen_material = ba.Material() + self._queen_material.add_actions( + conditions=('they_have_material', self._room_wall_material), + actions=( + ('modify_part_collision', 'collide', True), + ('modify_part_collision', 'physical', True) + )) + self._queen_material.add_actions( + actions=( + ('modify_part_collision', 'collide', True), + ('modify_part_collision', 'physical', True) + )) + self._room_wall_material.add_actions( + conditions=('they_have_material', self._queen_material), + actions=( + ('modify_part_collision', 'collide', True), + ('modify_part_collision', 'physical', True) + )) + self._real_wall_material = ba.Material() + self._real_wall_material.add_actions( + actions=( + ('modify_part_collision', 'collide', True), + ('modify_part_collision', 'physical', True) + )) + + self._real_wall_material.add_actions( + conditions=('they_have_material', shared.player_material), + actions=( + ('modify_part_collision', 'collide', True), + ('modify_part_collision', 'physical', True) + + )) + + def on_begin(self): + ba.getactivity().globalsnode.happy_thoughts_mode = True + super().on_begin() + self.make_map() + + def _spawn_flag(self) -> None: + ba.playsound(self._swipsound) + self._flash_flag_spawn() + assert self._flag_spawn_pos is not None + shared = SharedObjects.get() + self._flag = spaz.Spaz((0, 0, 0), character="Pixel").autoretain() + self._flag.handlemessage(ba.StandMessage((0, 14.63, -5.52), 93)) + self._flag.node.hold_position_pressed = True + self._flag.node.materials = (self._queen_material,shared.object_material) + # self._flag.node.extras_material= tuple(list(self._flag.node.extras_material).append(self._queen_materia)) + self._flag.hitpoints = 5000 + self._flag.hitpoints_max = 5000 + + self._flag_state = FlagState.NEW + self._flag_light = ba.newnode( + 'light', + owner=self._flag.node, + attrs={'intensity': 0.2, 'radius': 0.3, 'color': (0.2, 0.2, 0.2)}, + ) + assert self._flag.node + self._flag.node.connectattr('position', self._flag_light, 'position') + self._update_flag_state() + + def _update_flag_state(self) -> None: + if not self._flag.node.exists(): + self._spawn_flag() + for team in self.teams: + team.holdingflag = False + self._holding_players = [] + for player in self.players: + holdingflag = False + try: + assert isinstance(player.actor, (PlayerSpaz, type(None))) + if ( + player.actor + and player.actor.node + and player.actor.node.hold_node + ): + holdingflag = ( + player.actor.node.hold_node == self._flag.node + ) + except Exception: + ba.print_exception('Error checking hold flag.') + if holdingflag: + self._holding_players.append(player) + player.team.holdingflag = True + + holdingteams = set(t for t in self.teams if t.holdingflag) + prevstate = self._flag_state + assert self._flag is not None + assert self._flag_light + assert self._flag.node + if len(holdingteams) > 1: + self._flag_state = FlagState.CONTESTED + self._scoring_team = None + elif len(holdingteams) == 1: + holdingteam = list(holdingteams)[0] + self._flag_state = FlagState.HELD + self._scoring_team = holdingteam + else: + self._flag_state = FlagState.UNCONTESTED + self._scoring_team = None + + if self._flag_state != prevstate: + ba.playsound(self._swipsound) + + def handlemessage(self, msg: Any) -> Any: + if isinstance(msg, ba.PlayerDiedMessage): + # Augment standard behavior. + super().handlemessage(msg) + self.respawn_player(msg.getplayer(Player)) + elif isinstance(msg, (ba.PickedUpMessage, ba.DroppedMessage)): + self._update_flag_state() + else: + super().handlemessage(msg) + + def make_map(self): + shared = SharedObjects.get() + _ba.get_foreground_host_activity()._map.leftwall.materials = [ + shared.footing_material, self._real_wall_material] + + _ba.get_foreground_host_activity()._map.rightwall.materials = [ + shared.footing_material, self._real_wall_material] + + _ba.get_foreground_host_activity()._map.topwall.materials = [ + shared.footing_material, self._real_wall_material] + + self.floorwall1 = ba.newnode('region', attrs={'position': (-10, 5, -5.52), 'scale': + (15, 0.2, 2), 'type': 'box', 'materials': [shared.footing_material, self._real_wall_material]}) + self.floorwall2 = ba.newnode('region', attrs={'position': (10, 5, -5.52), 'scale': ( + 15, 0.2, 2), 'type': 'box', 'materials': [shared.footing_material, self._real_wall_material]}) + + self.wall1 = ba.newnode('region', attrs={'position': (0, 11, -6.90), 'scale': ( + 35.4, 20, 1), 'type': 'box', 'materials': [shared.footing_material, self._real_wall_material]}) + self.wall2 = ba.newnode('region', attrs={'position': (0, 11, -4.14), 'scale': ( + 35.4, 20, 1), 'type': 'box', 'materials': [shared.footing_material, self._real_wall_material]}) + + ba.newnode('locator', attrs={'shape': 'box', 'position': (-10, 5, -5.52), 'color': ( + 0, 0, 0), 'opacity': 1, 'draw_beauty': True, 'additive': False, 'size': (15, 0.2, 2)}) + + ba.newnode('locator', attrs={'shape': 'box', 'position': (10, 5, -5.52), 'color': ( + 0, 0, 0), 'opacity': 1, 'draw_beauty': True, 'additive': False, 'size': (15, 0.2, 2)}) + + self.create_static_step(0, 14.29) + # upper right + self.create_static_step(11, 16) + self.create_slope(8, 16, False) + self.create_static_step(3, 18) + + # lower right + self.create_static_step(11, 12) + self.create_slope(6, 10, True) + self.create_static_step(3, 10) + + # upper left + self.create_static_step(-11, 16) + self.create_slope(-8, 16, True) + self.create_static_step(-3, 18) + + # lower left + self.create_static_step(-11, 12) + self.create_slope(-6, 10, False) + self.create_static_step(-3, 10) + + # create queen personal room + self.room_wall_left = ba.newnode('region', attrs={'position': (-3.633, 16.63, -5.52), 'scale': + (2, 4, 5), 'type': 'box', 'materials': [shared.footing_material, self._room_wall_material]}) + self.room_wall_right = ba.newnode('region', attrs={'position': (3.533, 16.63, -5.52), 'scale': + (2, 4, 5), 'type': 'box', 'materials': [shared.footing_material, self._room_wall_material]}) + + def create_static_step(self, x, y): + shared = SharedObjects.get() + ba.newnode('region', attrs={'position': (x, y, -5.52), 'scale': (5.5, 0.1, 6), + 'type': 'box', 'materials': [shared.footing_material, self._real_wall_material]}) + ba.newnode('locator', attrs={'shape': 'box', 'position': (x, y, -5.52), 'color': ( + 1, 1, 0), 'opacity': 1, 'draw_beauty': True, 'additive': False, 'size': (5.5, 0.1, 2)}) + + def create_slope(self, x, y, backslash): + shared = SharedObjects.get() + + for _ in range(0, 21): + ba.newnode('region', attrs={'position': (x, y, -5.52), 'scale': (0.2, 0.1, 6), + 'type': 'box', 'materials': [shared.footing_material, self._real_wall_material]}) + ba.newnode('locator', attrs={'shape': 'box', 'position': (x, y, -5.52), 'color': ( + 1, 1, 0), 'opacity': 1, 'draw_beauty': True, 'additive': False, 'size': (0.2, 0.1, 2)}) + if backslash: + x = x + 0.1 + y = y + 0.1 + else: + x = x - 0.1 + y = y + 0.1 + + +class mapdefs: + points = {} + # noinspection PyDictCreation + boxes = {} + boxes['area_of_interest_bounds'] = (-1.045859963, 12.67722855, + -5.401537075) + (0.0, 0.0, 0.0) + ( + 42.46156851, 20.94044653, 0.6931564611) + points['ffa_spawn1'] = (-9.295167711, 8.010664315, + -5.44451005) + (1.555840357, 1.453808816, 0.1165648888) + points['ffa_spawn2'] = (7.484707127, 8.172681752, -5.614479365) + ( + 1.553861796, 1.453808816, 0.04419853907) + points['ffa_spawn3'] = (9.55724115, 11.30789446, -5.614479365) + ( + 1.337925849, 1.453808816, 0.04419853907) + points['ffa_spawn4'] = (-11.55747023, 10.99170684, -5.614479365) + ( + 1.337925849, 1.453808816, 0.04419853907) + points['ffa_spawn5'] = (-1.878892369, 9.46490571, -5.614479365) + ( + 1.337925849, 1.453808816, 0.04419853907) + points['ffa_spawn6'] = (-0.4912812943, 5.077006397, -5.521672101) + ( + 1.878332089, 1.453808816, 0.007578097856) + points['flag1'] = (-11.75152479, 8.057427485, -5.52) + points['flag2'] = (9.840909039, 8.188634282, -5.52) + points['flag3'] = (-0.2195258696, 5.010273907, -5.52) + points['flag4'] = (-0.04605809154, 12.73369108, -5.52) + points['flag_default'] = (-0.04201942896, 12.72374492, -5.52) + boxes['map_bounds'] = (-0.8748348681, 9.212941713, -5.729538885) + ( + 0.0, 0.0, 0.0) + (42.09666006, 26.19950145, 7.89541168) + points['powerup_spawn1'] = (1.160232442, 6.745963662, -5.469115985) + points['powerup_spawn2'] = (-1.899700206, 10.56447241, -5.505721177) + points['powerup_spawn3'] = (10.56098871, 12.25165669, -5.576232453) + points['powerup_spawn4'] = (-12.33530337, 12.25165669, -5.576232453) + points['spawn1'] = (-9.295167711, 8.010664315, + -5.44451005) + (1.555840357, 1.453808816, 0.1165648888) + points['spawn2'] = (7.484707127, 8.172681752, + -5.614479365) + (1.553861796, 1.453808816, 0.04419853907) + points['spawn_by_flag1'] = (-9.295167711, 8.010664315, -5.44451005) + ( + 1.555840357, 1.453808816, 0.1165648888) + points['spawn_by_flag2'] = (7.484707127, 8.172681752, -5.614479365) + ( + 1.553861796, 1.453808816, 0.04419853907) + points['spawn_by_flag3'] = (-1.45994593, 5.038762459, -5.535288724) + ( + 0.9516389866, 0.6666414677, 0.08607244075) + points['spawn_by_flag4'] = (0.4932087091, 12.74493212, -5.598987003) + ( + 0.5245740665, 0.5245740665, 0.01941146064) + + +class CreativeThoughts(ba.Map): + """Freaking map by smoothy.""" + + defs = mapdefs + + name = 'Creative Thoughts' + + @classmethod + def get_play_types(cls) -> List[str]: + """Return valid play types for this map.""" + return [ + 'melee', 'keep_away', 'team_flag' + ] + + @classmethod + def get_preview_texture_name(cls) -> str: + return 'alwaysLandPreview' + + @classmethod + def on_preload(cls) -> Any: + data: Dict[str, Any] = { + 'model': ba.getmodel('alwaysLandLevel'), + 'bottom_model': ba.getmodel('alwaysLandLevelBottom'), + 'bgmodel': ba.getmodel('alwaysLandBG'), + 'collide_model': ba.getcollidemodel('alwaysLandLevelCollide'), + 'tex': ba.gettexture('alwaysLandLevelColor'), + 'bgtex': ba.gettexture('alwaysLandBGColor'), + 'vr_fill_mound_model': ba.getmodel('alwaysLandVRFillMound'), + 'vr_fill_mound_tex': ba.gettexture('vrFillMound') + } + return data + + @classmethod + def get_music_type(cls) -> ba.MusicType: + return ba.MusicType.FLYING + + def __init__(self) -> None: + super().__init__(vr_overlay_offset=(0, -3.7, 2.5)) + shared = SharedObjects.get() + self._fake_wall_material = ba.Material() + self._real_wall_material = ba.Material() + self._fake_wall_material.add_actions( + conditions=(('they_are_younger_than', 9000), 'and', + ('they_have_material', shared.player_material)), + actions=( + ('modify_part_collision', 'collide', True), + ('modify_part_collision', 'physical', True) + + )) + self._real_wall_material.add_actions( + conditions=('they_have_material', shared.player_material), + actions=( + ('modify_part_collision', 'collide', True), + ('modify_part_collision', 'physical', True) + + )) + self.background = ba.newnode( + 'terrain', + attrs={ + 'model': self.preloaddata['bgmodel'], + 'lighting': False, + 'background': True, + 'color_texture': ba.gettexture("rampageBGColor") + }) + + self.leftwall = ba.newnode('region', attrs={'position': (-17.75152479, 13, -5.52), 'scale': ( + 0.1, 15.5, 2), 'type': 'box', 'materials': [shared.footing_material, self._real_wall_material]}) + self.rightwall = ba.newnode('region', attrs={'position': (17.75, 13, -5.52), 'scale': ( + 0.1, 15.5, 2), 'type': 'box', 'materials': [shared.footing_material, self._real_wall_material]}) + self.topwall = ba.newnode('region', attrs={'position': (0, 21.0, -5.52), 'scale': ( + 35.4, 0.2, 2), 'type': 'box', 'materials': [shared.footing_material, self._real_wall_material]}) + ba.newnode('locator', attrs={'shape': 'box', 'position': (-17.75152479, 13, -5.52), 'color': ( + 0, 0, 0), 'opacity': 1, 'draw_beauty': True, 'additive': False, 'size': (0.1, 15.5, 2)}) + ba.newnode('locator', attrs={'shape': 'box', 'position': (17.75, 13, -5.52), 'color': ( + 0, 0, 0), 'opacity': 1, 'draw_beauty': True, 'additive': False, 'size': (0.1, 15.5, 2)}) + ba.newnode('locator', attrs={'shape': 'box', 'position': (0, 21.0, -5.52), 'color': ( + 0, 0, 0), 'opacity': 1, 'draw_beauty': True, 'additive': False, 'size': (35.4, 0.2, 2)}) + + gnode = ba.getactivity().globalsnode + gnode.happy_thoughts_mode = True + gnode.shadow_offset = (0.0, 8.0, 5.0) + gnode.tint = (1.3, 1.23, 1.0) + gnode.ambient_color = (1.3, 1.23, 1.0) + gnode.vignette_outer = (0.64, 0.59, 0.69) + gnode.vignette_inner = (0.95, 0.95, 0.93) + gnode.vr_near_clip = 1.0 + self.is_flying = True + + # throw out some tips on flying + txt = ba.newnode('text', + attrs={ + 'text': ba.Lstr(resource='pressJumpToFlyText'), + 'scale': 1.2, + 'maxwidth': 800, + 'position': (0, 200), + 'shadow': 0.5, + 'flatness': 0.5, + 'h_align': 'center', + 'v_attach': 'bottom' + }) + cmb = ba.newnode('combine', + owner=txt, + attrs={ + 'size': 4, + 'input0': 0.3, + 'input1': 0.9, + 'input2': 0.0 + }) + ba.animate(cmb, 'input3', {3.0: 0, 4.0: 1, 9.0: 1, 10.0: 0}) + cmb.connectattr('output', txt, 'color') + ba.timer(10.0, txt.delete) + + +try: + ba._map.register_map(CreativeThoughts) +except: + pass diff --git a/plugins/minigames/demolition_war.py b/plugins/minigames/demolition_war.py new file mode 100644 index 00000000..31f2abe5 --- /dev/null +++ b/plugins/minigames/demolition_war.py @@ -0,0 +1,303 @@ + +# ba_meta require api 7 +""" +DemolitionWar - BombFight on wooden floor flying in air. +Author: Mr.Smoothy +Discord: https://discord.gg/ucyaesh +Youtube: https://www.youtube.com/c/HeySmoothy +Website: https://bombsquad-community.web.app +Github: https://github.com/bombsquad-community +""" +from __future__ import annotations + +from typing import TYPE_CHECKING + +import ba +from bastd.game.elimination import EliminationGame, Player +from bastd.gameutils import SharedObjects +from bastd.actor.bomb import BombFactory +import random +from bastd.actor.playerspaz import PlayerSpaz +if TYPE_CHECKING: + from typing import Any, Sequence + +# ba_meta export game +class DemolitionWar(EliminationGame): + name = 'DemolitionWar' + description = 'Last remaining alive wins.' + scoreconfig = ba.ScoreConfig( + label='Survived', scoretype=ba.ScoreType.SECONDS, none_is_winner=True + ) + # Show messages when players die since it's meaningful here. + announce_player_deaths = True + + allow_mid_activity_joins = False + + @classmethod + def get_available_settings( + cls, sessiontype: type[ba.Session] + ) -> list[ba.Setting]: + settings = [ + ba.IntSetting( + 'Lives Per Player', + default=1, + min_value=1, + max_value=10, + 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', 4.0), + ], + default=1.0, + ), + ba.BoolSetting('Epic Mode', default=False), + ] + if issubclass(sessiontype, ba.DualTeamSession): + settings.append(ba.BoolSetting('Solo Mode', default=False)) + settings.append( + ba.BoolSetting('Balance Total Lives', default=False) + ) + return settings + + @classmethod + def supports_session_type(cls, sessiontype: type[ba.Session]) -> bool: + return issubclass(sessiontype, ba.DualTeamSession) or issubclass( + sessiontype, ba.FreeForAllSession + ) + + @classmethod + def get_supported_maps(cls, sessiontype: type[ba.Session]) -> list[str]: + return ['Wooden Floor'] + + def __init__(self, settings: dict): + super().__init__(settings) + self._lives_per_player = 1 + self._solo_mode = False + self._balance_total_lives = False + + def spawn_player(self, player: Player) -> ba.Actor: + p = [-6, -4.3, -2.6, -0.9, 0.8, 2.5, 4.2, 5.9] + q = [-4, -2.3, -0.6, 1.1, 2.8, 4.5] + + x = random.randrange(0, len(p)) + y = random.randrange(0, len(q)) + spaz = self.spawn_player_spaz(player, position=(p[x], 1.8, q[y])) + spaz.bomb_type = 'impact' + # Let's reconnect this player's controls to this + # spaz but *without* the ability to attack or pick stuff up. + spaz.connect_controls_to_player(enable_punch=False, + enable_bomb=True, + enable_pickup=True) + + # Also lets have them make some noise when they die. + spaz.play_big_death_sound = True + return spaz + + def on_begin(self) -> None: + super().on_begin() + self.map_extend() + + def on_blast(self): + node = ba.getcollision().sourcenode + ba.emitfx((node.position[0], 0.9, node.position[2]), + (0, 2, 0), 30, 1, spread=1, chunk_type='splinter') + ba.timer(0.1, ba.Call(node.delete)) + + def map_extend(self): + # TODO need to improve here , so we can increase size of map easily with settings + p = [-6, -4.3, -2.6, -0.9, 0.8, 2.5, 4.2, 5.9] + q = [-4, -2.3, -0.6, 1.1, 2.8, 4.5] + factory = BombFactory.get() + self.ramp_bomb = ba.Material() + self.ramp_bomb.add_actions( + conditions=('they_have_material', factory.bomb_material), + actions=( + ('modify_part_collision', 'collide', True), + ('modify_part_collision', 'physical', True), + ('call', 'at_connect', ba.Call(self.on_blast)) + )) + self.ramps = [] + for i in p: + for j in q: + self.ramps.append(self.create_ramp(i, j)) + + def create_ramp(self, x, z): + + shared = SharedObjects.get() + self._real_collied_material = ba.Material() + + self._real_collied_material.add_actions( + actions=( + ('modify_part_collision', 'collide', True), + ('modify_part_collision', 'physical', True) + + )) + self.mat = ba.Material() + self.mat.add_actions( + actions=(('modify_part_collision', 'physical', False), + ('modify_part_collision', 'collide', False)) + ) + pos = (x, 0, z) + ud_1_r = ba.newnode('region', attrs={'position': pos, 'scale': (1.5, 1, 1.5), 'type': 'box', 'materials': [ + shared.footing_material, self._real_collied_material, self.ramp_bomb]}) + + node = ba.newnode('prop', + owner=ud_1_r, + attrs={ + 'model': ba.getmodel('image1x1'), + 'light_model': ba.getmodel('powerupSimple'), + 'position': (2, 7, 2), + 'body': 'puck', + 'shadow_size': 0.0, + 'velocity': (0, 0, 0), + 'color_texture': ba.gettexture('tnt'), + 'model_scale': 1.5, + 'reflection_scale': [1.5], + 'materials': [self.mat, shared.object_material, shared.footing_material], + 'density': 9000000000 + }) + node.changerotation(1, 0, 0) + mnode = ba.newnode('math', + owner=ud_1_r, + attrs={ + 'input1': (0, 0.6, 0), + 'operation': 'add' + }) + ud_1_r.connectattr('position', mnode, 'input2') + mnode.connectattr('output', node, 'position') + return ud_1_r + + + +class mapdefs: + points = {} + # noinspection PyDictCreation + boxes = {} + boxes['area_of_interest_bounds'] = (0.0, 1.185751251, 0.4326226188) + ( + 0.0, 0.0, 0.0) + (29.8180273, 11.57249038, 18.89134176) + boxes['edge_box'] = (-0.103873591, 0.4133341891, 0.4294651013) + ( + 0.0, 0.0, 0.0) + (22.48295719, 1.290242794, 8.990252454) + points['ffa_spawn1'] = (-0.08015551329, 0.02275111462, + -4.373674593) + (8.895057015, 1.0, 0.444350722) + points['ffa_spawn2'] = (-0.08015551329, 0.02275111462, + 4.076288941) + (8.895057015, 1.0, 0.444350722) + points['flag1'] = (-10.99027878, 0.05744967453, 0.1095578275) + points['flag2'] = (11.01486398, 0.03986567039, 0.1095578275) + points['flag_default'] = (-0.1001374046, 0.04180340146, 0.1095578275) + boxes['goal1'] = (12.22454533, 1.0, + 0.1087926362) + (0.0, 0.0, 0.0) + (2.0, 2.0, 12.97466313) + boxes['goal2'] = (-12.15961605, 1.0, + 0.1097860203) + (0.0, 0.0, 0.0) + (2.0, 2.0, 13.11856424) + boxes['map_bounds'] = (0.0, 1.185751251, 0.4326226188) + (0.0, 0.0, 0.0) + ( + 42.09506485, 22.81173179, 29.76723155) + points['powerup_spawn1'] = (5.414681236, 0.9515026107, -5.037912441) + points['powerup_spawn2'] = (-5.555402285, 0.9515026107, -5.037912441) + points['powerup_spawn3'] = (5.414681236, 0.9515026107, 5.148223181) + points['powerup_spawn4'] = (-5.737266365, 0.9515026107, 5.148223181) + points['spawn1'] = (-10.03866341, 0.02275111462, 0.0) + (0.5, 1.0, 4.0) + points['spawn2'] = (9.823107149, 0.01092306765, 0.0) + (0.5, 1.0, 4.0) + points['tnt1'] = (-0.08421587483, 0.9515026107, -0.7762602271) +class WoodenFloor(ba.Map): + """Stadium map for football games.""" + defs = mapdefs + defs.points['spawn1'] = (-12.03866341, 0.02275111462, 0.0) + (0.5, 1.0, 4.0) + defs.points['spawn2'] = (12.823107149, 0.01092306765, 0.0) + (0.5, 1.0, 4.0) + name = 'Wooden Floor' + + @classmethod + def get_play_types(cls) -> list[str]: + """Return valid play types for this map.""" + return ['melee', 'football', 'team_flag', 'keep_away'] + + @classmethod + def get_preview_texture_name(cls) -> str: + return 'footballStadiumPreview' + + @classmethod + def on_preload(cls) -> Any: + data: dict[str, Any] = { + + 'model_bg': ba.getmodel('doomShroomBG'), + 'bg_vr_fill_model': ba.getmodel('natureBackgroundVRFill'), + 'collide_model': ba.getcollidemodel('bridgitLevelCollide'), + 'tex': ba.gettexture('bridgitLevelColor'), + 'model_bg_tex': ba.gettexture('doomShroomBGColor'), + 'collide_bg': ba.getcollidemodel('natureBackgroundCollide'), + 'railing_collide_model': + (ba.getcollidemodel('bridgitLevelRailingCollide')), + 'bg_material': ba.Material() + } + data['bg_material'].add_actions(actions=('modify_part_collision', + 'friction', 10.0)) + return data + + def __init__(self) -> None: + super().__init__() + shared = SharedObjects.get() + self.background = ba.newnode( + 'terrain', + attrs={ + 'model': self.preloaddata['model_bg'], + 'lighting': False, + 'background': True, + 'color_texture': self.preloaddata['model_bg_tex'] + }) + self.vr = ba.newnode('terrain', + attrs={ + 'model': self.preloaddata['bg_vr_fill_model'], + 'lighting': False, + 'vr_only': True, + 'background': True, + 'color_texture': self.preloaddata['model_bg_tex'] + }) + gnode = ba.getactivity().globalsnode + gnode.tint = (1.3, 1.2, 1.0) + gnode.ambient_color = (1.3, 1.2, 1.0) + gnode.vignette_outer = (0.57, 0.57, 0.57) + gnode.vignette_inner = (0.9, 0.9, 0.9) + gnode.vr_camera_offset = (0, -0.8, -1.1) + gnode.vr_near_clip = 0.5 + + + def is_point_near_edge(self, + point: ba.Vec3, + running: bool = False) -> bool: + box_position = self.defs.boxes['edge_box'][0:3] + box_scale = self.defs.boxes['edge_box'][6:9] + xpos = (point.x - box_position[0]) / box_scale[0] + zpos = (point.z - box_position[2]) / box_scale[2] + return xpos < -0.5 or xpos > 0.5 or zpos < -0.5 or zpos > 0.5 + + def _handle_player_collide(self): + try: + player = ba.getcollision().opposingnode.getdelegate( + PlayerSpaz, True) + except ba.NotFoundError: + return + if player.is_alive(): + player.shatter(True) + + + +try: + ba._map.register_map(WoodenFloor) +except: + pass \ No newline at end of file diff --git a/plugins/minigames/drone_war.py b/plugins/minigames/drone_war.py new file mode 100644 index 00000000..b27276aa --- /dev/null +++ b/plugins/minigames/drone_war.py @@ -0,0 +1,426 @@ +# Released under the MIT License. See LICENSE for details. +# +""" +DroneWar - Attack enemies with drone, Fly with drone and fire rocket launcher. +Author: Mr.Smoothy +Discord: https://discord.gg/ucyaesh +Youtube: https://www.youtube.com/c/HeySmoothy +Website: https://bombsquad-community.web.app +Github: https://github.com/bombsquad-community +""" +# ba_meta require api 7 +# (see https://ballistica.net/wiki/meta-tag-system) + +from __future__ import annotations + +from typing import TYPE_CHECKING + +import ba +import _ba +from ba._generated.enums import InputType +from bastd.actor.bomb import Blast + +from bastd.gameutils import SharedObjects +from bastd.actor.playerspaz import PlayerSpaz, PlayerType +from bastd.game.deathmatch import DeathMatchGame, Player +from bastd.actor import spaz +if TYPE_CHECKING: + from typing import Any, Sequence, Dict, Type, List, Optional, Union + +STORAGE_ATTR_NAME = f'_shared_{__name__}_factory' + +# SMoothy's Drone (fixed version of floater) with rocket launcher +# use drone as long as you want , unlike floater which dies after being idle. +class Drone(ba.Actor): + def __init__(self, spaz): + super().__init__() + shared = SharedObjects.get() + self._drone_material = ba.Material() + self.loop_ascend = None + self.loop_descend = None + self.loop_lr = None + self.loop_ud = None + self.rocket_launcher = None + self.x_direction = 0 + self.z_direction = 0 + self.spaz = spaz + self._drone_material.add_actions( + conditions=('they_have_material', + shared.player_material), + actions=(('modify_node_collision', 'collide', True), + ('modify_part_collision', 'physical', True))) + self._drone_material.add_actions( + conditions=(('they_have_material', + shared.object_material), 'or', + ('they_have_material', + shared.footing_material), 'or', + ('they_have_material', + self._drone_material)), + actions=('modify_part_collision', 'physical', False)) + self.node = ba.newnode( + 'prop', + delegate=self, + owner = None, + attrs={ + 'position': spaz.node.position, + 'model':ba.getmodel('landMine'), + 'light_model':ba.getmodel('landMine'), + 'body':'landMine', + 'body_scale':1, + 'model_scale':1, + 'shadow_size':0.25, + 'density':999999, + 'gravity_scale':0.0, + 'color_texture':ba.gettexture('achievementCrossHair'), + 'reflection':'soft', + 'reflection_scale': [0.25], + 'materials':[shared.footing_material, self._drone_material] + }) + self.grab_node = ba.newnode( + 'prop', + owner=self.node, + attrs={ + 'position': (0, 0, 0), + 'body':'sphere', + 'model': None, + 'color_texture':None, + 'body_scale':0.2, + 'reflection':'powerup', + 'density':999999, + 'reflection_scale': [1.0], + 'model_scale':0.2, + 'gravity_scale':0, + 'shadow_size':0.1, + 'is_area_of_interest':True, + 'materials':[shared.object_material, self._drone_material] + }) + self.node.connectattr('position', self.grab_node, 'position') + self._rcombine=ba.newnode('combine', + owner=self.node, + attrs={ + 'input0':self.spaz.node.position[0], + 'input1':self.spaz.node.position[1]+3, + 'input2':self.spaz.node.position[2], + 'size':3 + }) + + self._rcombine.connectattr('output',self.node,'position') + def set_rocket_launcher(self, launcher: RocketLauncher): + self.rocket_launcher = launcher + def fire(self): + if hasattr(self.grab_node,"position"): + self.rocket_launcher.shot(self.spaz, self.x_direction, self.z_direction , (self.grab_node.position[0], self.grab_node.position[1] -1, self.grab_node.position[2])) + def ascend(self): + def loop(): + if self.node.exists(): + ba.animate( self._rcombine,'input1',{ + 0:self.node.position[1], + 1:self.node.position[1] + 2 + }) + loop() + self.loop_ascend = ba.Timer(1, loop , repeat = True) + + def pause_movement(self): + self.loop_ascend = None + def decend(self): + def loop(): + if self.node.exists(): + ba.animate( self._rcombine,'input1',{ + 0:self.node.position[1], + 1:self.node.position[1] - 2 + }) + loop() + self.loop_ascend = ba.Timer(1, loop , repeat = True ) + def pause_lr(self): + self.loop_lr = None + def pause_ud(self): + self.loop_ud = None + def left_(self, value = -1): + def loop(): + if self.node.exists(): + ba.animate( self._rcombine,'input0',{ + 0:self.node.position[0], + 1:self.node.position[0] + 2 * value + }) + if value == 0.0: + self.loop_lr = None + else: + self.x_direction = value + self.z_direction = 0 + loop() + self.loop_lr = ba.Timer(1, loop , repeat = True ) + def right_(self, value = 1): + def loop(): + if self.node.exists(): + ba.animate( self._rcombine,'input0',{ + 0:self.node.position[0], + 1:self.node.position[0] + 2 * value + }) + if value == 0.0: + self.loop_lr = None + else: + self.x_direction = value + self.z_direction = 0 + loop() + self.loop_lr = ba.Timer(1, loop , repeat = True ) + def up_(self, value=1): + def loop(): + if self.node.exists(): + ba.animate( self._rcombine,'input2',{ + 0:self.node.position[2], + 1:self.node.position[2] - 2 * value + }) + if value == 0.0: + self.loop_ud = None + else: + self.x_direction = 0 + self.z_direction = - value + loop() + self.loop_ud = ba.Timer(1, loop , repeat = True ) + def down_(self, value=-1): + def loop(): + if self.node.exists(): + ba.animate( self._rcombine,'input2',{ + 0:self.node.position[2], + 1:self.node.position[2] - 2 * value + }) + if value == 0.0: + self.loop_ud = None + else: + self.x_direction = 0 + self.z_direction = - value + loop() + self.loop_ud = ba.Timer(1, loop , repeat = True ) + def handlemessage(self, msg): + if isinstance(msg, ba.DieMessage): + self.node.delete() + self.grab_node.delete() + self.loop_ascend = None + self.loop_ud = None + self.loop_lr = None + elif isinstance(msg, ba.OutOfBoundsMessage): + self.handlemessage(ba.DieMessage()) + else: + super().handlemessage(msg) + +# =============================================Copied from Quake Game - Dliwk ===================================================================== +class RocketFactory: + """Quake Rocket factory""" + + def __init__(self) -> None: + self.ball_material = ba.Material() + + self.ball_material.add_actions( + conditions=((('we_are_younger_than', 5), 'or', + ('they_are_younger_than', 5)), 'and', + ('they_have_material', + SharedObjects.get().object_material)), + actions=('modify_node_collision', 'collide', False)) + + self.ball_material.add_actions( + conditions=('they_have_material', + SharedObjects.get().pickup_material), + actions=('modify_part_collision', 'use_node_collide', False)) + + self.ball_material.add_actions(actions=('modify_part_collision', + 'friction', 0)) + + self.ball_material.add_actions( + conditions=(('they_have_material', + SharedObjects.get().footing_material), 'or', + ('they_have_material', + SharedObjects.get().object_material)), + actions=('message', 'our_node', 'at_connect', ImpactMessage())) + + @classmethod + def get(cls): + """Get factory if exists else create new""" + activity = ba.getactivity() + if hasattr(activity, STORAGE_ATTR_NAME): + return getattr(activity, STORAGE_ATTR_NAME) + factory = cls() + setattr(activity, STORAGE_ATTR_NAME, factory) + return factory + + +class RocketLauncher: + """Very dangerous weapon""" + + def __init__(self): + self.last_shot = ba.time() + + def give(self, spaz: spaz.Spaz) -> None: + """Give spaz a rocket launcher""" + spaz.punch_callback = self.shot + self.last_shot = ba.time() + + # FIXME + # noinspection PyUnresolvedReferences + def shot(self, spaz, x, z, position) -> None: + """Release a rocket""" + time = ba.time() + if time - self.last_shot > 0.6: + self.last_shot = time + + direction = [x, 0, z] + direction[1] = 0.0 + + mag = 10.0 / 1 if ba.Vec3(*direction).length() == 0 else ba.Vec3(*direction).length() + vel = [v * mag for v in direction] + Rocket(position=position, + velocity=vel, + owner=spaz.getplayer(ba.Player), + source_player=spaz.getplayer(ba.Player), + color=spaz.node.color).autoretain() + + +class ImpactMessage: + """Rocket touched something""" + + +class Rocket(ba.Actor): + """Epic rocket from rocket launcher""" + + def __init__(self, + position=(0, 5, 0), + velocity=(1, 0, 0), + source_player=None, + owner=None, + color=(1.0, 0.2, 0.2)) -> None: + super().__init__() + self.source_player = source_player + self.owner = owner + self._color = color + factory = RocketFactory.get() + + self.node = ba.newnode('prop', + delegate=self, + attrs={ + 'position': position, + 'velocity': velocity, + 'model': ba.getmodel('impactBomb'), + 'body': 'sphere', + 'color_texture': ba.gettexture( + 'bunnyColor'), + 'model_scale': 0.2, + 'is_area_of_interest': True, + 'body_scale': 0.8, + 'materials': [ + SharedObjects.get().object_material, + factory.ball_material] + }) # yapf: disable + self.node.extra_acceleration = (self.node.velocity[0] * 200, 0, + self.node.velocity[2] * 200) + + self._life_timer = ba.Timer( + 5, ba.WeakCall(self.handlemessage, ba.DieMessage())) + + self._emit_timer = ba.Timer(0.001, ba.WeakCall(self.emit), repeat=True) + self.base_pos_y = self.node.position[1] + + ba.camerashake(5.0) + + def emit(self) -> None: + """Emit a trace after rocket""" + ba.emitfx(position=self.node.position, + scale=0.4, + spread=0.01, + chunk_type='spark') + if not self.node: + return + self.node.position = (self.node.position[0], self.base_pos_y, + self.node.position[2]) # ignore y + ba.newnode('explosion', + owner=self.node, + attrs={ + 'position': self.node.position, + 'radius': 0.2, + 'color': self._color + }) + + def handlemessage(self, msg: Any) -> Any: + """Message handling for rocket""" + super().handlemessage(msg) + if isinstance(msg, ImpactMessage): + self.node.handlemessage(ba.DieMessage()) + + elif isinstance(msg, ba.DieMessage): + if self.node: + Blast(position=self.node.position, + blast_radius=2, + source_player=self.source_player) + + self.node.delete() + self._emit_timer = None + + elif isinstance(msg, ba.OutOfBoundsMessage): + self.handlemessage(ba.DieMessage()) + + +# ba_meta export game +class ChooseQueen(DeathMatchGame): + name = 'Drone War' + + @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 spawn_player_spaz( + self, + player: PlayerType, + position: Sequence[float] | None = None, + angle: float | None = None, + ) -> PlayerSpaz: + spaz = super().spawn_player_spaz(player, position, angle) + self.spawn_drone(spaz) + return spaz + + def on_begin(self): + super().on_begin() + shared = SharedObjects.get() + self.ground_material = ba.Material() + self.ground_material.add_actions( + conditions=('they_have_material',shared.player_material), + actions=( + ('modify_part_collision', 'collide', True), + ( 'call','at_connect',ba.Call(self._handle_player_collide )), + ), + ) + pos=(0,0.1,-5) + self.main_region=ba.newnode('region',attrs={'position': pos,'scale': (30,0.001,23),'type': 'box','materials': [shared.footing_material,self.ground_material]}) + + def _handle_player_collide(self): + try: + player = ba.getcollision().opposingnode.getdelegate( + PlayerSpaz, True) + except ba.NotFoundError: + return + if player.is_alive(): + player.shatter(True) + + def spawn_drone(self, spaz): + with ba.Context(_ba.get_foreground_host_activity()): + + drone = Drone(spaz) + r_launcher = RocketLauncher() + drone.set_rocket_launcher(r_launcher) + player = spaz.getplayer(Player, True) + spaz.node.hold_node = drone.grab_node + player.actor.disconnect_controls_from_player() + player.resetinput() + player.assigninput(InputType.PICK_UP_PRESS, drone.ascend) + player.assigninput(InputType.PICK_UP_RELEASE, drone.pause_movement) + player.assigninput(InputType.JUMP_PRESS, drone.decend) + player.assigninput(InputType.PUNCH_PRESS, drone.fire) + player.assigninput(InputType.LEFT_PRESS, drone.left_) + player.assigninput(InputType.RIGHT_PRESS, drone.right_) + player.assigninput(InputType.LEFT_RELEASE, drone.pause_lr) + player.assigninput(InputType.RIGHT_RELEASE, drone.pause_lr) + player.assigninput(InputType.UP_PRESS, drone.up_) + player.assigninput(InputType.DOWN_PRESS, drone.down_) + player.assigninput(InputType.UP_RELEASE, drone.pause_ud) + player.assigninput(InputType.DOWN_RELEASE, drone.pause_ud) \ No newline at end of file diff --git a/plugins/minigames/the_spaz_game.py b/plugins/minigames/the_spaz_game.py new file mode 100644 index 00000000..5bbebac3 --- /dev/null +++ b/plugins/minigames/the_spaz_game.py @@ -0,0 +1,122 @@ + +# ba_meta require api 7 +""" +TheSpazGame - Mini game where all characters looks identical , identify enemies and kill them. +Author: Mr.Smoothy +Discord: https://discord.gg/ucyaesh +Youtube: https://www.youtube.com/c/HeySmoothy +Website: https://bombsquad-community.web.app +Github: https://github.com/bombsquad-community +""" +from __future__ import annotations + +from typing import TYPE_CHECKING + +import ba +from bastd.game.elimination import EliminationGame, Player +from bastd.actor.spazfactory import SpazFactory +import random + +if TYPE_CHECKING: + from typing import Any, Sequence + + +CHARACTER = 'Spaz' + +# ba_meta export game +class TheSpazGame(EliminationGame): + name = 'TheSpazGame' + description = 'Enemy Spaz AmongUs. Kill them all' + scoreconfig = ba.ScoreConfig( + label='Survived', scoretype=ba.ScoreType.SECONDS, none_is_winner=True + ) + + announce_player_deaths = False + + allow_mid_activity_joins = False + + @classmethod + def get_available_settings( + cls, sessiontype: type[ba.Session] + ) -> list[ba.Setting]: + settings = [ + ba.IntSetting( + 'Lives Per Player', + default=1, + min_value=1, + max_value=10, + 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.15) + ], + default=1.0, + ), + ba.BoolSetting('Epic Mode', default=False), + ] + if issubclass(sessiontype, ba.DualTeamSession): + settings.append(ba.BoolSetting('Solo Mode', default=False)) + settings.append( + ba.BoolSetting('Balance Total Lives', default=False) + ) + return settings + + @classmethod + def supports_session_type(cls, sessiontype: type[ba.Session]) -> bool: + return issubclass(sessiontype, ba.DualTeamSession) or issubclass( + sessiontype, ba.FreeForAllSession + ) + + @classmethod + def get_supported_maps(cls, sessiontype: type[ba.Session]) -> list[str]: + return ba.getmaps('melee') + + def get_instance_description(self) -> str | Sequence: + return ( + 'Enemy Spaz AmongUs. Kill them all' + ) + + def get_instance_description_short(self) -> str | Sequence: + return ( + 'Enemy Spaz AmongUs. Kill them all' + ) + def __init__(self, settings: dict): + super().__init__(settings) + self._solo_mode = False + + def spawn_player(self, player: Player) -> ba.Actor: + p = [-6, -4.3, -2.6, -0.9, 0.8, 2.5, 4.2, 5.9] + q = [-4, -2.3, -0.6, 1.1, 2.8, 4.5] + + x = random.randrange(0, len(p)) + y = random.randrange(0, len(q)) + spaz = self.spawn_player_spaz(player, position=(p[x], 1.8, q[y])) + spaz.node.color = (1,1,1) + spaz.node.highlight = (1,0.4,1) + self.update_appearance(spaz, character=CHARACTER) + # Also lets have them make some noise when they die. + spaz.play_big_death_sound = True + return spaz + + def update_appearance(self, spaz, character): + factory = SpazFactory.get() + media = factory.get_media(character) + for field, value in media.items(): + setattr(spaz.node, field, value) + spaz.node.style = factory.get_style(character) + spaz.node.name = '' + From 2aa1e508770f49bebb6fa219e255c30117421d7f Mon Sep 17 00:00:00 2001 From: imayushsaini Date: Sun, 4 Jun 2023 20:03:05 +0000 Subject: [PATCH 0465/1464] [ci] auto-format --- plugins/minigames/castel_queen.py | 7 +- plugins/minigames/demolition_war.py | 29 ++--- plugins/minigames/drone_war.py | 175 +++++++++++++++------------- plugins/minigames/the_spaz_game.py | 12 +- 4 files changed, 123 insertions(+), 100 deletions(-) diff --git a/plugins/minigames/castel_queen.py b/plugins/minigames/castel_queen.py index 02986ce7..df863689 100644 --- a/plugins/minigames/castel_queen.py +++ b/plugins/minigames/castel_queen.py @@ -26,9 +26,12 @@ from typing import Any, Sequence, Dict, Type, List, Optional, Union # ba_meta export game + + class ChooseQueen(KeepAwayGame): name = 'FCUK The Queen' description = 'Carry the queen for a set length of time' + @classmethod def supports_session_type(cls, sessiontype: Type[ba.Session]) -> bool: return issubclass(sessiontype, ba.DualTeamSession) @@ -42,7 +45,7 @@ def get_instance_description(self) -> str | Sequence: def get_instance_description_short(self) -> str | Sequence: return 'FCUK the queen for ${ARG1} seconds', self._hold_time - + def __init__(self, settings: dict): super().__init__(settings) shared = SharedObjects.get() @@ -99,7 +102,7 @@ def _spawn_flag(self) -> None: self._flag = spaz.Spaz((0, 0, 0), character="Pixel").autoretain() self._flag.handlemessage(ba.StandMessage((0, 14.63, -5.52), 93)) self._flag.node.hold_position_pressed = True - self._flag.node.materials = (self._queen_material,shared.object_material) + self._flag.node.materials = (self._queen_material, shared.object_material) # self._flag.node.extras_material= tuple(list(self._flag.node.extras_material).append(self._queen_materia)) self._flag.hitpoints = 5000 self._flag.hitpoints_max = 5000 diff --git a/plugins/minigames/demolition_war.py b/plugins/minigames/demolition_war.py index 31f2abe5..1c264336 100644 --- a/plugins/minigames/demolition_war.py +++ b/plugins/minigames/demolition_war.py @@ -22,6 +22,8 @@ from typing import Any, Sequence # ba_meta export game + + class DemolitionWar(EliminationGame): name = 'DemolitionWar' description = 'Last remaining alive wins.' @@ -121,7 +123,7 @@ def on_blast(self): (0, 2, 0), 30, 1, spread=1, chunk_type='splinter') ba.timer(0.1, ba.Call(node.delete)) - def map_extend(self): + def map_extend(self): # TODO need to improve here , so we can increase size of map easily with settings p = [-6, -4.3, -2.6, -0.9, 0.8, 2.5, 4.2, 5.9] q = [-4, -2.3, -0.6, 1.1, 2.8, 4.5] @@ -186,7 +188,6 @@ def create_ramp(self, x, z): return ud_1_r - class mapdefs: points = {} # noinspection PyDictCreation @@ -203,9 +204,9 @@ class mapdefs: points['flag2'] = (11.01486398, 0.03986567039, 0.1095578275) points['flag_default'] = (-0.1001374046, 0.04180340146, 0.1095578275) boxes['goal1'] = (12.22454533, 1.0, - 0.1087926362) + (0.0, 0.0, 0.0) + (2.0, 2.0, 12.97466313) + 0.1087926362) + (0.0, 0.0, 0.0) + (2.0, 2.0, 12.97466313) boxes['goal2'] = (-12.15961605, 1.0, - 0.1097860203) + (0.0, 0.0, 0.0) + (2.0, 2.0, 13.11856424) + 0.1097860203) + (0.0, 0.0, 0.0) + (2.0, 2.0, 13.11856424) boxes['map_bounds'] = (0.0, 1.185751251, 0.4326226188) + (0.0, 0.0, 0.0) + ( 42.09506485, 22.81173179, 29.76723155) points['powerup_spawn1'] = (5.414681236, 0.9515026107, -5.037912441) @@ -215,6 +216,8 @@ class mapdefs: points['spawn1'] = (-10.03866341, 0.02275111462, 0.0) + (0.5, 1.0, 4.0) points['spawn2'] = (9.823107149, 0.01092306765, 0.0) + (0.5, 1.0, 4.0) points['tnt1'] = (-0.08421587483, 0.9515026107, -0.7762602271) + + class WoodenFloor(ba.Map): """Stadium map for football games.""" defs = mapdefs @@ -261,13 +264,13 @@ def __init__(self) -> None: 'color_texture': self.preloaddata['model_bg_tex'] }) self.vr = ba.newnode('terrain', - attrs={ - 'model': self.preloaddata['bg_vr_fill_model'], - 'lighting': False, - 'vr_only': True, - 'background': True, - 'color_texture': self.preloaddata['model_bg_tex'] - }) + attrs={ + 'model': self.preloaddata['bg_vr_fill_model'], + 'lighting': False, + 'vr_only': True, + 'background': True, + 'color_texture': self.preloaddata['model_bg_tex'] + }) gnode = ba.getactivity().globalsnode gnode.tint = (1.3, 1.2, 1.0) gnode.ambient_color = (1.3, 1.2, 1.0) @@ -276,7 +279,6 @@ def __init__(self) -> None: gnode.vr_camera_offset = (0, -0.8, -1.1) gnode.vr_near_clip = 0.5 - def is_point_near_edge(self, point: ba.Vec3, running: bool = False) -> bool: @@ -296,8 +298,7 @@ def _handle_player_collide(self): player.shatter(True) - try: ba._map.register_map(WoodenFloor) except: - pass \ No newline at end of file + pass diff --git a/plugins/minigames/drone_war.py b/plugins/minigames/drone_war.py index b27276aa..4877afaf 100644 --- a/plugins/minigames/drone_war.py +++ b/plugins/minigames/drone_war.py @@ -31,6 +31,8 @@ # SMoothy's Drone (fixed version of floater) with rocket launcher # use drone as long as you want , unlike floater which dies after being idle. + + class Drone(ba.Actor): def __init__(self, spaz): super().__init__() @@ -60,137 +62,149 @@ def __init__(self, spaz): self.node = ba.newnode( 'prop', delegate=self, - owner = None, + owner=None, attrs={ 'position': spaz.node.position, - 'model':ba.getmodel('landMine'), - 'light_model':ba.getmodel('landMine'), - 'body':'landMine', - 'body_scale':1, - 'model_scale':1, - 'shadow_size':0.25, - 'density':999999, - 'gravity_scale':0.0, - 'color_texture':ba.gettexture('achievementCrossHair'), - 'reflection':'soft', + 'model': ba.getmodel('landMine'), + 'light_model': ba.getmodel('landMine'), + 'body': 'landMine', + 'body_scale': 1, + 'model_scale': 1, + 'shadow_size': 0.25, + 'density': 999999, + 'gravity_scale': 0.0, + 'color_texture': ba.gettexture('achievementCrossHair'), + 'reflection': 'soft', 'reflection_scale': [0.25], - 'materials':[shared.footing_material, self._drone_material] - }) + 'materials': [shared.footing_material, self._drone_material] + }) self.grab_node = ba.newnode( 'prop', owner=self.node, attrs={ 'position': (0, 0, 0), - 'body':'sphere', + 'body': 'sphere', 'model': None, - 'color_texture':None, - 'body_scale':0.2, - 'reflection':'powerup', - 'density':999999, + 'color_texture': None, + 'body_scale': 0.2, + 'reflection': 'powerup', + 'density': 999999, 'reflection_scale': [1.0], - 'model_scale':0.2, - 'gravity_scale':0, - 'shadow_size':0.1, - 'is_area_of_interest':True, - 'materials':[shared.object_material, self._drone_material] + 'model_scale': 0.2, + 'gravity_scale': 0, + 'shadow_size': 0.1, + 'is_area_of_interest': True, + 'materials': [shared.object_material, self._drone_material] }) self.node.connectattr('position', self.grab_node, 'position') - self._rcombine=ba.newnode('combine', - owner=self.node, - attrs={ - 'input0':self.spaz.node.position[0], - 'input1':self.spaz.node.position[1]+3, - 'input2':self.spaz.node.position[2], - 'size':3 - }) - - self._rcombine.connectattr('output',self.node,'position') + self._rcombine = ba.newnode('combine', + owner=self.node, + attrs={ + 'input0': self.spaz.node.position[0], + 'input1': self.spaz.node.position[1]+3, + 'input2': self.spaz.node.position[2], + 'size': 3 + }) + + self._rcombine.connectattr('output', self.node, 'position') + def set_rocket_launcher(self, launcher: RocketLauncher): self.rocket_launcher = launcher + def fire(self): - if hasattr(self.grab_node,"position"): - self.rocket_launcher.shot(self.spaz, self.x_direction, self.z_direction , (self.grab_node.position[0], self.grab_node.position[1] -1, self.grab_node.position[2])) + if hasattr(self.grab_node, "position"): + self.rocket_launcher.shot(self.spaz, self.x_direction, self.z_direction, ( + self.grab_node.position[0], self.grab_node.position[1] - 1, self.grab_node.position[2])) + def ascend(self): def loop(): if self.node.exists(): - ba.animate( self._rcombine,'input1',{ - 0:self.node.position[1], - 1:self.node.position[1] + 2 - }) + ba.animate(self._rcombine, 'input1', { + 0: self.node.position[1], + 1: self.node.position[1] + 2 + }) loop() - self.loop_ascend = ba.Timer(1, loop , repeat = True) - + self.loop_ascend = ba.Timer(1, loop, repeat=True) + def pause_movement(self): self.loop_ascend = None + def decend(self): def loop(): if self.node.exists(): - ba.animate( self._rcombine,'input1',{ - 0:self.node.position[1], - 1:self.node.position[1] - 2 - }) + ba.animate(self._rcombine, 'input1', { + 0: self.node.position[1], + 1: self.node.position[1] - 2 + }) loop() - self.loop_ascend = ba.Timer(1, loop , repeat = True ) + self.loop_ascend = ba.Timer(1, loop, repeat=True) + def pause_lr(self): self.loop_lr = None + def pause_ud(self): self.loop_ud = None - def left_(self, value = -1): + + def left_(self, value=-1): def loop(): if self.node.exists(): - ba.animate( self._rcombine,'input0',{ - 0:self.node.position[0], - 1:self.node.position[0] + 2 * value - }) + ba.animate(self._rcombine, 'input0', { + 0: self.node.position[0], + 1: self.node.position[0] + 2 * value + }) if value == 0.0: self.loop_lr = None else: self.x_direction = value self.z_direction = 0 loop() - self.loop_lr = ba.Timer(1, loop , repeat = True ) - def right_(self, value = 1): + self.loop_lr = ba.Timer(1, loop, repeat=True) + + def right_(self, value=1): def loop(): if self.node.exists(): - ba.animate( self._rcombine,'input0',{ - 0:self.node.position[0], - 1:self.node.position[0] + 2 * value - }) + ba.animate(self._rcombine, 'input0', { + 0: self.node.position[0], + 1: self.node.position[0] + 2 * value + }) if value == 0.0: self.loop_lr = None else: self.x_direction = value self.z_direction = 0 loop() - self.loop_lr = ba.Timer(1, loop , repeat = True ) + self.loop_lr = ba.Timer(1, loop, repeat=True) + def up_(self, value=1): def loop(): if self.node.exists(): - ba.animate( self._rcombine,'input2',{ - 0:self.node.position[2], - 1:self.node.position[2] - 2 * value - }) + ba.animate(self._rcombine, 'input2', { + 0: self.node.position[2], + 1: self.node.position[2] - 2 * value + }) if value == 0.0: self.loop_ud = None else: self.x_direction = 0 self.z_direction = - value loop() - self.loop_ud = ba.Timer(1, loop , repeat = True ) + self.loop_ud = ba.Timer(1, loop, repeat=True) + def down_(self, value=-1): def loop(): if self.node.exists(): - ba.animate( self._rcombine,'input2',{ - 0:self.node.position[2], - 1:self.node.position[2] - 2 * value - }) + ba.animate(self._rcombine, 'input2', { + 0: self.node.position[2], + 1: self.node.position[2] - 2 * value + }) if value == 0.0: self.loop_ud = None else: self.x_direction = 0 self.z_direction = - value loop() - self.loop_ud = ba.Timer(1, loop , repeat = True ) + self.loop_ud = ba.Timer(1, loop, repeat=True) + def handlemessage(self, msg): if isinstance(msg, ba.DieMessage): self.node.delete() @@ -204,6 +218,8 @@ def handlemessage(self, msg): super().handlemessage(msg) # =============================================Copied from Quake Game - Dliwk ===================================================================== + + class RocketFactory: """Quake Rocket factory""" @@ -261,7 +277,7 @@ def shot(self, spaz, x, z, position) -> None: time = ba.time() if time - self.last_shot > 0.6: self.last_shot = time - + direction = [x, 0, z] direction[1] = 0.0 @@ -368,30 +384,31 @@ def supports_session_type(cls, sessiontype: Type[ba.Session]) -> bool: @classmethod def get_supported_maps(cls, sessiontype: Type[ba.Session]) -> List[str]: return ['Football Stadium'] - + def spawn_player_spaz( self, player: PlayerType, position: Sequence[float] | None = None, angle: float | None = None, ) -> PlayerSpaz: - spaz = super().spawn_player_spaz(player, position, angle) + spaz = super().spawn_player_spaz(player, position, angle) self.spawn_drone(spaz) return spaz - + def on_begin(self): super().on_begin() shared = SharedObjects.get() self.ground_material = ba.Material() self.ground_material.add_actions( - conditions=('they_have_material',shared.player_material), + conditions=('they_have_material', shared.player_material), actions=( ('modify_part_collision', 'collide', True), - ( 'call','at_connect',ba.Call(self._handle_player_collide )), + ('call', 'at_connect', ba.Call(self._handle_player_collide)), ), - ) - pos=(0,0.1,-5) - self.main_region=ba.newnode('region',attrs={'position': pos,'scale': (30,0.001,23),'type': 'box','materials': [shared.footing_material,self.ground_material]}) + ) + pos = (0, 0.1, -5) + self.main_region = ba.newnode('region', attrs={'position': pos, 'scale': ( + 30, 0.001, 23), 'type': 'box', 'materials': [shared.footing_material, self.ground_material]}) def _handle_player_collide(self): try: @@ -404,7 +421,7 @@ def _handle_player_collide(self): def spawn_drone(self, spaz): with ba.Context(_ba.get_foreground_host_activity()): - + drone = Drone(spaz) r_launcher = RocketLauncher() drone.set_rocket_launcher(r_launcher) @@ -423,4 +440,4 @@ def spawn_drone(self, spaz): player.assigninput(InputType.UP_PRESS, drone.up_) player.assigninput(InputType.DOWN_PRESS, drone.down_) player.assigninput(InputType.UP_RELEASE, drone.pause_ud) - player.assigninput(InputType.DOWN_RELEASE, drone.pause_ud) \ No newline at end of file + player.assigninput(InputType.DOWN_RELEASE, drone.pause_ud) diff --git a/plugins/minigames/the_spaz_game.py b/plugins/minigames/the_spaz_game.py index 5bbebac3..278b5214 100644 --- a/plugins/minigames/the_spaz_game.py +++ b/plugins/minigames/the_spaz_game.py @@ -24,6 +24,8 @@ CHARACTER = 'Spaz' # ba_meta export game + + class TheSpazGame(EliminationGame): name = 'TheSpazGame' description = 'Enemy Spaz AmongUs. Kill them all' @@ -84,7 +86,7 @@ def supports_session_type(cls, sessiontype: type[ba.Session]) -> bool: @classmethod def get_supported_maps(cls, sessiontype: type[ba.Session]) -> list[str]: return ba.getmaps('melee') - + def get_instance_description(self) -> str | Sequence: return ( 'Enemy Spaz AmongUs. Kill them all' @@ -94,6 +96,7 @@ def get_instance_description_short(self) -> str | Sequence: return ( 'Enemy Spaz AmongUs. Kill them all' ) + def __init__(self, settings: dict): super().__init__(settings) self._solo_mode = False @@ -105,13 +108,13 @@ def spawn_player(self, player: Player) -> ba.Actor: x = random.randrange(0, len(p)) y = random.randrange(0, len(q)) spaz = self.spawn_player_spaz(player, position=(p[x], 1.8, q[y])) - spaz.node.color = (1,1,1) - spaz.node.highlight = (1,0.4,1) + spaz.node.color = (1, 1, 1) + spaz.node.highlight = (1, 0.4, 1) self.update_appearance(spaz, character=CHARACTER) # Also lets have them make some noise when they die. spaz.play_big_death_sound = True return spaz - + def update_appearance(self, spaz, character): factory = SpazFactory.get() media = factory.get_media(character) @@ -119,4 +122,3 @@ def update_appearance(self, spaz, character): setattr(spaz.node, field, value) spaz.node.style = factory.get_style(character) spaz.node.name = '' - From 96635c7f060c11d67e27823e8e73454b50e200b6 Mon Sep 17 00:00:00 2001 From: imayushsaini Date: Sun, 4 Jun 2023 20:03:06 +0000 Subject: [PATCH 0466/1464] [ci] apply-version-metadata --- plugins/minigames.json | 28 ++++++++++++++++++++++++---- 1 file changed, 24 insertions(+), 4 deletions(-) diff --git a/plugins/minigames.json b/plugins/minigames.json index 909e72d5..08eb34a7 100644 --- a/plugins/minigames.json +++ b/plugins/minigames.json @@ -304,7 +304,12 @@ } ], "versions": { - "1.0.0": null + "1.0.0": { + "api_version": 7, + "commit_sha": "2aa1e50", + "released_on": "04-06-2023", + "md5sum": "096107aaa9dad6d2753aa462c0a48537" + } } }, "castel_queen": { @@ -318,7 +323,12 @@ } ], "versions": { - "1.0.0": null + "1.0.0": { + "api_version": 7, + "commit_sha": "2aa1e50", + "released_on": "04-06-2023", + "md5sum": "74e876139e20a392c15deeafa31354f7" + } } }, "drone_war": { @@ -332,7 +342,12 @@ } ], "versions": { - "1.0.0": null + "1.0.0": { + "api_version": 7, + "commit_sha": "2aa1e50", + "released_on": "04-06-2023", + "md5sum": "569219eb72d8c27271f20fe375a01a69" + } } }, "the_spaz_game": { @@ -346,7 +361,12 @@ } ], "versions": { - "1.0.0": null + "1.0.0": { + "api_version": 7, + "commit_sha": "2aa1e50", + "released_on": "04-06-2023", + "md5sum": "55021c091b640780d6280cfb4b56b664" + } } }, "air_soccer": { From a97f1cea519653cd26f5f1d2bb81e6b1219c2ff8 Mon Sep 17 00:00:00 2001 From: Hopeless101 <108615119+Hopeless101@users.noreply.github.com> Date: Wed, 14 Jun 2023 17:44:24 +0800 Subject: [PATCH 0467/1464] First map ever uploaded --- plugins/maps/forest.py | 121 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 121 insertions(+) create mode 100644 plugins/maps/forest.py diff --git a/plugins/maps/forest.py b/plugins/maps/forest.py new file mode 100644 index 00000000..089ce01d --- /dev/null +++ b/plugins/maps/forest.py @@ -0,0 +1,121 @@ + +# ba_meta require api 7 +from __future__ import annotations +from typing import TYPE_CHECKING + +import ba +from ba import _map +from bastd.gameutils import SharedObjects +from bastd.maps import * + +if TYPE_CHECKING: + pass + + +class ForestMapData(): + points = {} + boxes = {} + + boxes['area_of_interest_bounds'] = ( + (0.0, 1.185751251, 0.4326226188) + + (0.0, 0.0, 0.0) + + (29.8180273, 11.57249038, 18.89134176) + ) + boxes['edge_box'] = ( + (-0.103873591, 0.4133341891, 0.4294651013) + + (0.0, 0.0, 0.0) + + (22.48295719, 1.290242794, 8.990252454) + ) + points['ffa_spawn1'] = (-2.0, -2.0, -4.373674593) + ( + 8.895057015, + 1.0, + 0.444350722, + ) + points['ffa_spawn2'] = (-2.0, -2.0, 2.076288941) + ( + 8.895057015, + 1.0, + 0.444350722, + ) + boxes['map_bounds'] = ( + (0.0, 1.185751251, 0.4326226188) + + (0.0, 0.0, 0.0) + + (42.09506485, 22.81173179, 29.76723155) + ) + points['flag_default'] = (-2.5, -3.0, -2.0) + points['powerup_spawn1'] = (-6.0, -2.6, -1.25) + points['powerup_spawn2'] = (1.0, -2.6, -1.25) + points['spawn1'] = (-10.0, -2.0, -2.0) + (0.5, 1.0, 3.2) + points['spawn2'] = (5.0, -2.0, -2.0) + (0.5, 1.0, 3.2) + + +class ForestMap(ba.Map): + + defs = ForestMapData() + name = 'Forest' + + @classmethod + def get_play_types(cls) -> list[str]: + return ['melee', 'keep_away'] + + @classmethod + def get_preview_texture_name(cls) -> list[str]: + return 'natureBackgroundColor' + + @classmethod + def on_preload(cls) -> any: + data: dict[str, any] = { + 'model': ba.getmodel('natureBackground'), + 'tex': ba.gettexture('natureBackgroundColor'), + 'collide_model': ba.getcollidemodel('natureBackgroundCollide'), + 'bgmodel': ba.getmodel('thePadBG'), + 'bgtex': ba.gettexture('menuBG') + } + return data + + def __init__(self) -> None: + super().__init__() + shared = SharedObjects.get() + + self.node = ba.newnode( + 'terrain', + delegate=self, + attrs={ + 'model': self.preloaddata['model'], + 'color_texture': self.preloaddata['tex'], + 'collide_model': self.preloaddata['collide_model'], + 'materials': [shared.footing_material] + } + ) + self.background = ba.newnode( + 'terrain', + attrs={ + 'model': self.preloaddata['bgmodel'], + 'lighting': False, + 'shadow': True, + 'color_texture': self.preloaddata['bgtex'] + } + ) + + gnode = ba.getactivity().globalsnode + gnode.tint = (1.0, 1.10, 1.15) + gnode.ambient_color = (0.9, 1.3, 1.1) + gnode.shadow_ortho = False + gnode.vignette_outer = (0.76, 0.76, 0.76) + gnode.vignette_inner = (0.95, 0.95, 0.99) + + def is_point_near_edge(self, + point: ba.Vec3, + running: bool = False) -> bool: + xpos = point.x + zpos = point.z + x_adj = xpos * 0.125 + z_adj = (zpos + 3.7) * 0.2 + if running: + x_adj *= 1.4 + z_adj *= 1.4 + return x_adj * x_adj + z_adj * z_adj > 1.0 + + +# ba_meta export plugin +class EnableMe(ba.Plugin): + _map.register_map(ForestMap) From a72832be483a70fb47a5ffc9ee9e2f6b1c5e7c76 Mon Sep 17 00:00:00 2001 From: Hopeless101 <108615119+Hopeless101@users.noreply.github.com> Date: Wed, 14 Jun 2023 17:50:33 +0800 Subject: [PATCH 0468/1464] Update maps.json --- plugins/maps.json | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/plugins/maps.json b/plugins/maps.json index 055d4b84..f5b8fe41 100644 --- a/plugins/maps.json +++ b/plugins/maps.json @@ -2,5 +2,20 @@ "name": "Maps", "description": "Maps", "plugins_base_url": "https://github.com/bombsquad-community/plugin-manager/{content_type}/{tag}/plugins/maps", - "plugins": {} + "plugins": { + "forest_map": { + "description": "Basically bridgit map but outter version", + "external_url": "", + "authors": [ + { + "name": "Hopeless", + "email": "", + "discord": "Hopeless#9040" + } + ], + "versions": { + "1.0.0": null + }, + }, + } } From 3380d3b63390693611f15a289781eb4b75e454ae Mon Sep 17 00:00:00 2001 From: Hopeless101 Date: Wed, 14 Jun 2023 09:54:26 +0000 Subject: [PATCH 0469/1464] [ci] auto-format --- plugins/maps/forest.py | 76 +++++++++++++++++++++--------------------- 1 file changed, 38 insertions(+), 38 deletions(-) diff --git a/plugins/maps/forest.py b/plugins/maps/forest.py index 089ce01d..d5c4d1d5 100644 --- a/plugins/maps/forest.py +++ b/plugins/maps/forest.py @@ -13,39 +13,39 @@ class ForestMapData(): - points = {} - boxes = {} - - boxes['area_of_interest_bounds'] = ( - (0.0, 1.185751251, 0.4326226188) - + (0.0, 0.0, 0.0) - + (29.8180273, 11.57249038, 18.89134176) - ) - boxes['edge_box'] = ( - (-0.103873591, 0.4133341891, 0.4294651013) - + (0.0, 0.0, 0.0) - + (22.48295719, 1.290242794, 8.990252454) - ) - points['ffa_spawn1'] = (-2.0, -2.0, -4.373674593) + ( - 8.895057015, - 1.0, - 0.444350722, - ) - points['ffa_spawn2'] = (-2.0, -2.0, 2.076288941) + ( - 8.895057015, - 1.0, - 0.444350722, - ) - boxes['map_bounds'] = ( - (0.0, 1.185751251, 0.4326226188) - + (0.0, 0.0, 0.0) - + (42.09506485, 22.81173179, 29.76723155) - ) - points['flag_default'] = (-2.5, -3.0, -2.0) - points['powerup_spawn1'] = (-6.0, -2.6, -1.25) - points['powerup_spawn2'] = (1.0, -2.6, -1.25) - points['spawn1'] = (-10.0, -2.0, -2.0) + (0.5, 1.0, 3.2) - points['spawn2'] = (5.0, -2.0, -2.0) + (0.5, 1.0, 3.2) + points = {} + boxes = {} + + boxes['area_of_interest_bounds'] = ( + (0.0, 1.185751251, 0.4326226188) + + (0.0, 0.0, 0.0) + + (29.8180273, 11.57249038, 18.89134176) + ) + boxes['edge_box'] = ( + (-0.103873591, 0.4133341891, 0.4294651013) + + (0.0, 0.0, 0.0) + + (22.48295719, 1.290242794, 8.990252454) + ) + points['ffa_spawn1'] = (-2.0, -2.0, -4.373674593) + ( + 8.895057015, + 1.0, + 0.444350722, + ) + points['ffa_spawn2'] = (-2.0, -2.0, 2.076288941) + ( + 8.895057015, + 1.0, + 0.444350722, + ) + boxes['map_bounds'] = ( + (0.0, 1.185751251, 0.4326226188) + + (0.0, 0.0, 0.0) + + (42.09506485, 22.81173179, 29.76723155) + ) + points['flag_default'] = (-2.5, -3.0, -2.0) + points['powerup_spawn1'] = (-6.0, -2.6, -1.25) + points['powerup_spawn2'] = (1.0, -2.6, -1.25) + points['spawn1'] = (-10.0, -2.0, -2.0) + (0.5, 1.0, 3.2) + points['spawn2'] = (5.0, -2.0, -2.0) + (0.5, 1.0, 3.2) class ForestMap(ba.Map): @@ -56,11 +56,11 @@ class ForestMap(ba.Map): @classmethod def get_play_types(cls) -> list[str]: return ['melee', 'keep_away'] - + @classmethod def get_preview_texture_name(cls) -> list[str]: return 'natureBackgroundColor' - + @classmethod def on_preload(cls) -> any: data: dict[str, any] = { @@ -71,11 +71,11 @@ def on_preload(cls) -> any: 'bgtex': ba.gettexture('menuBG') } return data - + def __init__(self) -> None: super().__init__() shared = SharedObjects.get() - + self.node = ba.newnode( 'terrain', delegate=self, @@ -95,7 +95,7 @@ def __init__(self) -> None: 'color_texture': self.preloaddata['bgtex'] } ) - + gnode = ba.getactivity().globalsnode gnode.tint = (1.0, 1.10, 1.15) gnode.ambient_color = (0.9, 1.3, 1.1) From 7ab457676decaeea2dc45c5617a56230a9570d82 Mon Sep 17 00:00:00 2001 From: Rikko Date: Thu, 15 Jun 2023 23:05:11 +0530 Subject: [PATCH 0470/1464] Epic mode option in Practise Tools --- plugins/utilities.json | 3 ++- plugins/utilities/practice_tools.py | 10 ++++++++-- 2 files changed, 10 insertions(+), 3 deletions(-) diff --git a/plugins/utilities.json b/plugins/utilities.json index fcbd8002..2cffc1c6 100644 --- a/plugins/utilities.json +++ b/plugins/utilities.json @@ -606,6 +606,7 @@ } ], "versions": { + "1.1.0": null, "1.0.0": { "api_version": 7, "commit_sha": "800125c", @@ -697,4 +698,4 @@ } } } -} \ No newline at end of file +} diff --git a/plugins/utilities/practice_tools.py b/plugins/utilities/practice_tools.py index c830adae..d9cda1eb 100644 --- a/plugins/utilities/practice_tools.py +++ b/plugins/utilities/practice_tools.py @@ -1348,8 +1348,8 @@ def __init__(self, window: PracticeWindow) -> None: self.count = 1 self.parent_widget = None self.activity = _ba.get_foreground_host_activity() - self.setting_name = (['Pause On Window', 'Invincible']) - self.config = (['pause', 'invincible']) + self.setting_name = (['Pause On Window', 'Invincible', 'Epic Mode']) + self.config = (['pause', 'invincible', 'epic']) def on_activate( self, @@ -1462,6 +1462,12 @@ def _check_value_change(self, setting: int, widget: ba.Widget, i.actor.node.invincible = False except: pass + elif setting == 2: + activity = _ba.get_foreground_host_activity() + if value: + activity.globalsnode.slow_motion = True + else: + activity.globalsnode.slow_motion = False class PracticeWindow(ba.Window): From 3b54b764ddcca8d8e219280b47eae287093ed282 Mon Sep 17 00:00:00 2001 From: rikkolovescats Date: Thu, 15 Jun 2023 17:37:59 +0000 Subject: [PATCH 0471/1464] [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 2cffc1c6..82edc017 100644 --- a/plugins/utilities.json +++ b/plugins/utilities.json @@ -606,7 +606,12 @@ } ], "versions": { - "1.1.0": null, + "1.1.0": { + "api_version": 7, + "commit_sha": "7ab4576", + "released_on": "15-06-2023", + "md5sum": "f439f1a9c325f6ac09f2bab23b10e275" + }, "1.0.0": { "api_version": 7, "commit_sha": "800125c", @@ -698,4 +703,4 @@ } } } -} +} \ No newline at end of file From 51a026611bf4a0653f5102b327a75ffa1e05f2a8 Mon Sep 17 00:00:00 2001 From: Rikko Date: Fri, 16 Jun 2023 00:12:14 +0530 Subject: [PATCH 0472/1464] Execute tests for maps --- test/auto_apply_version_metadata.py | 4 ++++ test/test_checks.py | 9 +++++++++ 2 files changed, 13 insertions(+) diff --git a/test/auto_apply_version_metadata.py b/test/auto_apply_version_metadata.py index 5dd8b5bd..1f8719a5 100644 --- a/test/auto_apply_version_metadata.py +++ b/test/auto_apply_version_metadata.py @@ -205,6 +205,10 @@ def auto_apply_version_metadata(last_commit_sha): category_json = utilities.apply_version_metadata_to_null_version_values(last_commit_sha) utilities.save(category_json) + maps = CategoryVersionMetadata(os.path.join("plugins", "maps")) + category_json = maps.apply_version_metadata_to_null_version_values(last_commit_sha) + maps.save(category_json) + minigames = CategoryVersionMetadata(os.path.join("plugins", "minigames")) category_json = minigames.apply_version_metadata_to_null_version_values(last_commit_sha) minigames.save(category_json) diff --git a/test/test_checks.py b/test/test_checks.py index d338419d..4971bfef 100644 --- a/test/test_checks.py +++ b/test/test_checks.py @@ -163,6 +163,15 @@ def setUp(self): self.content = json.load(fin) +class TestMapsCategoryMetadata(BaseCategoryMetadataTestCases.BaseTest): + def setUp(self): + super().setUp() + self.name = "Maps" + self.category = os.path.join("plugins", "maps") + with open(f"{self.category}.json", "rb") as fin: + self.content = json.load(fin) + + class TestMinigamesCategoryMetadata(BaseCategoryMetadataTestCases.BaseTest): def setUp(self): super().setUp() From 28031eb1f7d065b1a0c60f9aca0862e28b271d5f Mon Sep 17 00:00:00 2001 From: Rikko Date: Fri, 16 Jun 2023 00:14:09 +0530 Subject: [PATCH 0473/1464] Correct maps.json --- plugins/maps.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/plugins/maps.json b/plugins/maps.json index f5b8fe41..ecce1286 100644 --- a/plugins/maps.json +++ b/plugins/maps.json @@ -15,7 +15,7 @@ ], "versions": { "1.0.0": null - }, - }, + } + } } } From 72d2d6260102e01d024432460194ac631635b761 Mon Sep 17 00:00:00 2001 From: Rikko Date: Fri, 16 Jun 2023 00:18:04 +0530 Subject: [PATCH 0474/1464] Replace "Loading..." text with the exception message if any --- CHANGELOG.md | 4 ++++ index.json | 3 ++- plugin_manager.py | 6 +++++- 3 files changed, 11 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index ddb321aa..85ebd585 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,9 @@ ## Plugin Manager (dd-mm-yyyy) +### 0.3.5 (16-06-2023) + +- Replace the "Loading..." text with the exception message in case something goes wrong. + ### 0.3.4 (14-05-2023) - Optimize new plugin detection mechanism. diff --git a/index.json b/index.json index 4fbe3858..ba8c58b9 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.5": null, "0.3.4": { "api_version": 7, "commit_sha": "2d74b52", @@ -98,4 +99,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 fd103501..ea83afef 100644 --- a/plugin_manager.py +++ b/plugin_manager.py @@ -25,7 +25,7 @@ _uiscale = ba.app.ui.uiscale -PLUGIN_MANAGER_VERSION = "0.3.4" +PLUGIN_MANAGER_VERSION = "0.3.5" 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. @@ -1538,6 +1538,10 @@ def exception_handler(self): except RuntimeError: # User probably went back before a ba.Window could finish loading. pass + except Exception as e: + ba.textwidget(edit=self._plugin_manager_status_text, + text=str(e)) + raise async def draw_index(self): self.draw_search_bar() From 985e486b6550dab6847ebdd66f5ea91f126e77cb Mon Sep 17 00:00:00 2001 From: Rikko Date: Fri, 16 Jun 2023 00:18:44 +0530 Subject: [PATCH 0475/1464] Make map name meta consistent with filename --- plugins/maps.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/maps.json b/plugins/maps.json index ecce1286..14a7e3d5 100644 --- a/plugins/maps.json +++ b/plugins/maps.json @@ -3,7 +3,7 @@ "description": "Maps", "plugins_base_url": "https://github.com/bombsquad-community/plugin-manager/{content_type}/{tag}/plugins/maps", "plugins": { - "forest_map": { + "forest": { "description": "Basically bridgit map but outter version", "external_url": "", "authors": [ From 34cceed75844396cbde9af82a17b836663558d4f Mon Sep 17 00:00:00 2001 From: rikkolovescats Date: Thu, 15 Jun 2023 18:49:24 +0000 Subject: [PATCH 0476/1464] [ci] apply-version-metadata --- index.json | 9 +++++++-- plugins/maps.json | 9 +++++++-- 2 files changed, 14 insertions(+), 4 deletions(-) diff --git a/index.json b/index.json index ba8c58b9..3e3e90e0 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.5": null, + "0.3.5": { + "api_version": 7, + "commit_sha": "985e486", + "released_on": "15-06-2023", + "md5sum": "5da137a353b4fa35e4d9926107cf4754" + }, "0.3.4": { "api_version": 7, "commit_sha": "2d74b52", @@ -99,4 +104,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/plugins/maps.json b/plugins/maps.json index 14a7e3d5..7d509ef3 100644 --- a/plugins/maps.json +++ b/plugins/maps.json @@ -14,8 +14,13 @@ } ], "versions": { - "1.0.0": null + "1.0.0": { + "api_version": 7, + "commit_sha": "985e486", + "released_on": "15-06-2023", + "md5sum": "01fb81dc27d63789f31559140ec2bd72" + } } } } -} +} \ No newline at end of file From 8c5a6b03405c69d010c78b731e57a42725db64d4 Mon Sep 17 00:00:00 2001 From: CrossJoy <87638792+CrossJoy@users.noreply.github.com> Date: Mon, 19 Jun 2023 19:16:23 +0800 Subject: [PATCH 0477/1464] Updated to 1.2.0 --- plugins/utilities.json | 1 + plugins/utilities/practice_tools.py | 274 +++++++++++++++++++--------- 2 files changed, 188 insertions(+), 87 deletions(-) diff --git a/plugins/utilities.json b/plugins/utilities.json index 82edc017..e13d88c7 100644 --- a/plugins/utilities.json +++ b/plugins/utilities.json @@ -606,6 +606,7 @@ } ], "versions": { + "1.2.0": null, "1.1.0": { "api_version": 7, "commit_sha": "7ab4576", diff --git a/plugins/utilities/practice_tools.py b/plugins/utilities/practice_tools.py index d9cda1eb..f7677805 100644 --- a/plugins/utilities/practice_tools.py +++ b/plugins/utilities/practice_tools.py @@ -1,4 +1,4 @@ -"""Practice Tools Mod: V1.0 +"""Practice Tools Mod: V1.2 Made by Cross Joy""" # If anyone who want to help me on giving suggestion/ fix bugs/ creating PR, @@ -11,7 +11,19 @@ # Some support will be much appreciated. :') # Support link: https://www.buymeacoffee.com/CrossJoy - +# ---------------------------------------------------------------------------- +# V1.2 update +# - Added New Bot: Bomber Lite and Brawler Lite. +# - Added New Setting: Epic Mode Toggle. +# - Added immunity to curse if invincible. +# - Fixed Power Up mini billboard will not removed after debuff. +# - Fixed Power Up landmine count will not removed after debuff. +# - Fixed the config (Bot Picker, Count, Radius and Power Up Picker) will set to default when exit the practice tab. + +# V1.1 update +# - Fixed Charger Bot Pro bot spawn with shield. +# - Fixed selecting Bruiser bot is not working. +# - Added screen message when pressing spawn/clear/debuff button. # ---------------------------------------------------------------------------- # Powerful and comprehensive tools for practice purpose. @@ -45,8 +57,7 @@ import weakref from enum import Enum from typing import TYPE_CHECKING -import ba -import _ba +import ba, _ba import ba.internal import bastd from bastd.actor.powerupbox import PowerupBox @@ -56,7 +67,7 @@ BomberBotPro, BrawlerBotPro, TriggerBotPro, ChargerBotPro, BomberBotProShielded, BrawlerBotProShielded, TriggerBotProShielded, - ChargerBotProShielded) + ChargerBotProShielded, BomberBotLite, BrawlerBotLite) from bastd.mainmenu import MainMenuSession from bastd.ui.party import PartyWindow as OriginalPartyWindow from ba import app, Plugin @@ -93,14 +104,6 @@ except: ba.app.config["stopBots"] = False -try: - if ba.app.config.get("stopBots") is None: - ba.app.config["stopBots"] = False - else: - ba.app.config.get("stopBots") -except: - ba.app.config["stopBots"] = False - try: if ba.app.config.get("immortalDummy") is None: ba.app.config["immortalDummy"] = False @@ -182,7 +185,7 @@ def main(plugin: Plugin) -> None: # ba_meta require api 7 # ba_meta export plugin class Practice(Plugin): - __version__ = '1.0' + __version__ = '1.2' def on_app_running(self) -> None: """Plugin start point.""" @@ -389,9 +392,10 @@ def invincible() -> None: def new_cursed(self): + if self.node.invincible: + return self.super_curse() if ba.app.config.get("bombRadiusVisual"): - ba.animate_array(self.curse_visualizer, 'size', 1, { 0.0: [0.0], 0.2: [3 * 2.2], @@ -423,7 +427,6 @@ def new_cursed(self): def bot_handlemessage(self, msg: Any): - if isinstance(msg, ba.PowerupMessage): if msg.poweruptype == 'health': if ba.app.config.get("bombRadiusVisual"): @@ -478,8 +481,8 @@ def bot_handlemessage(self, msg: Any): elif ba.app.config.get('bombRadiusVisual'): ba.animate_array(self.bot_radius, 'size', 1, { - 0.0: [(self.hitpoints_max - self.hitpoints) * 0.0048], - 0.25: [(self.hitpoints_max - self.hitpoints) * 0.0048] + 0.0: [(self.hitpoints_max - self.hitpoints) * 0.0045], + 0.25: [(self.hitpoints_max - self.hitpoints) * 0.0045] }) ba.animate(self.bot_radius, 'opacity', { 0.0: 0.00, @@ -487,8 +490,8 @@ def bot_handlemessage(self, msg: Any): }) ba.animate_array(self.radius_visualizer_circle, 'size', 1, { - 0.0: [(self.hitpoints_max - self.hitpoints) * 0.0048], - 0.25: [(self.hitpoints_max - self.hitpoints) * 0.0048] + 0.0: [(self.hitpoints_max - self.hitpoints) * 0.0045], + 0.25: [(self.hitpoints_max - self.hitpoints) * 0.0045] }) ba.animate( @@ -557,7 +560,7 @@ def _update(self) -> None: bot_list = [] ba.print_exception('Error updating bot list: ' + str(self._bot_lists[ - self._bot_update_list])) + self._bot_update_list])) self._bot_update_list = (self._bot_update_list + 1) % self._bot_list_count @@ -645,10 +648,11 @@ def _update(self) -> None: except Exception: ba.print_exception('Error updating bot list: ' + str(self._bot_lists[ - self._bot_update_list])) + self._bot_update_list])) self._bot_update_list = (self._bot_update_list + 1) % self._bot_list_count + except: pass @@ -670,6 +674,10 @@ def immortal(self): emit_type='fairydust') +class NewChargerBotPro(ChargerBotPro): + default_shields = False + + # ------------------------------------------------------------------- class PracticeTab: @@ -687,13 +695,13 @@ def window(self) -> PracticeWindow: return window def on_activate( - self, - parent_widget: ba.Widget, - tab_button: ba.Widget, - region_width: float, - region_height: float, - scroll_widget: ba.Widget, - extra_x: float, + self, + parent_widget: ba.Widget, + tab_button: ba.Widget, + region_width: float, + region_height: float, + scroll_widget: ba.Widget, + extra_x: float, ) -> ba.Widget: """Called when the tab becomes the active one. @@ -736,21 +744,22 @@ class BotsPracticeTab(PracticeTab): def __init__(self, window: PracticeWindow, bot1=DummyBotSet(), bot2=NewBotSet()) -> None: super().__init__(window) + bot_index, count, radius = self.load_settings() self._container: ba.Widget | None = None - self.count = 1 - self.radius = 0 + self.count = count + self.radius = radius self.radius_array = (['Small', 'Medium', 'Big']) self.parent_widget = None self.bot1 = bot1 self.bot2 = bot2 self.activity = _ba.get_foreground_host_activity() self.image_array = ( - ['bonesIcon', 'neoSpazIcon', 'kronkIcon', + ['bonesIcon', 'neoSpazIcon', 'kronkIcon', 'neoSpazIcon', 'kronkIcon', 'zoeIcon', 'ninjaIcon', 'melIcon', 'jackIcon', 'bunnyIcon', 'neoSpazIcon', 'kronkIcon', 'zoeIcon', 'ninjaIcon', 'neoSpazIcon', 'kronkIcon', 'zoeIcon', 'ninjaIcon']) self.bot_array_name = ( - ['Dummy', 'Bomber', 'Bruiser', + ['Dummy', 'Bomber Lite', 'Brawler Lite', 'Bomber', 'Brawler', 'Trigger', 'Charger', 'Sticky', 'Explodey', 'Bouncy', 'Pro Bomber', 'Pro Brawler', 'Pro Trigger', 'Pro Charger', @@ -761,22 +770,22 @@ def __init__(self, window: PracticeWindow, self.config = (['stopBots', 'immortalDummy']) self.bot_array = ( - [DummyBot, SpazBot, BrawlerBot, TriggerBot, + [DummyBot, BomberBotLite, BrawlerBotLite, SpazBot, BrawlerBot, TriggerBot, ChargerBot, StickyBot, ExplodeyBot, BouncyBot, - BomberBotPro, BrawlerBotPro, TriggerBotPro, ChargerBotPro, + BomberBotPro, BrawlerBotPro, TriggerBotPro, NewChargerBotPro, BomberBotProShielded, BrawlerBotProShielded, TriggerBotProShielded, ChargerBotProShielded]) - self._icon_index = self.bot_array_name.index('Dummy') + self._icon_index = bot_index def on_activate( - self, - parent_widget: ba.Widget, - tab_button: ba.Widget, - region_width: float, - region_height: float, - scroll_widget: ba.Widget, - extra_x: float, + self, + parent_widget: ba.Widget, + tab_button: ba.Widget, + region_width: float, + region_height: float, + scroll_widget: ba.Widget, + extra_x: float, ) -> ba.Widget: b_size_2 = 100 @@ -814,6 +823,8 @@ def on_activate( text='Spawn Bot', maxwidth=200) + tint1, tint2, color = self.check_color() + self._bot_button = bot = ba.buttonwidget( parent=self._subcontainer, autoselect=True, @@ -822,11 +833,11 @@ def on_activate( on_activate_call=self._bot_window, size=(b_size_2, b_size_2), label='', - color=(1, 1, 1), + color=color, tint_texture=(ba.gettexture( self.image_array[self._icon_index] + 'ColorMask')), - tint_color=(0.6, 0.6, 0.6), - tint2_color=(0.1, 0.3, 0.1), + tint_color=tint1, + tint2_color=tint2, texture=ba.gettexture(self.image_array[self._icon_index]), mask_texture=mask_texture) @@ -1017,6 +1028,7 @@ def increase_count(self): ba.textwidget(edit=self.count_text, text=str(self.count)) + self.save_settings() def decrease_count(self): if self.count > 1: @@ -1024,6 +1036,7 @@ def decrease_count(self): ba.textwidget(edit=self.count_text, text=str(self.count)) + self.save_settings() def increase_radius(self): if self.radius < 2: @@ -1031,6 +1044,7 @@ def increase_radius(self): ba.textwidget(edit=self.radius_text, text=self.radius_array[self.radius]) + self.save_settings() def decrease_radius(self): if self.radius > 0: @@ -1038,13 +1052,18 @@ def decrease_radius(self): ba.textwidget(edit=self.radius_text, text=self.radius_array[self.radius]) + self.save_settings() def clear_bot(self): + ba.screenmessage('Cleared', + clients=[-1], transient=True, color=(1, 0.1, 0.1)) self.bot1.clear() self.bot2.clear() def do_spawn_bot(self, clid: int = -1) -> None: with ba.Context(self.activity): + ba.screenmessage('Spawned', + clients=[-1], transient=True, color=(0.2, 1, 0.2)) for i in _ba.get_foreground_host_activity().players: if i.sessionplayer.inputdevice.client_id == clid: if i.node: @@ -1079,26 +1098,8 @@ def on_bots_picker_pick(self, character: str) -> None: def _update_character(self, change: int = 0) -> None: if self._bot_button: - if self.bot_array_name[self._icon_index] in ( - 'Pro Bomber', 'Pro Brawler', - 'Pro Trigger', 'Pro Charger', - 'S.Pro Bomber', 'S.Pro Brawler', - 'S.Pro Trigger', 'S.Pro Charger'): - tint1 = (1.0, 0.2, 0.1) - tint2 = (0.6, 0.1, 0.05) - elif self.bot_array_name[self._icon_index] in 'Bouncy': - tint1 = (1, 1, 1) - tint2 = (1.0, 0.5, 0.5) - else: - tint1 = (0.6, 0.6, 0.6) - tint2 = (0.1, 0.3, 0.1) + tint1, tint2, color = self.check_color() - if self.bot_array_name[self._icon_index] in ( - 'S.Pro Bomber', 'S.Pro Brawler', - 'S.Pro Trigger', 'S.Pro Charger'): - color = (1.3, 1.2, 3.0) - else: - color = (1.0, 1.0, 1.0) ba.buttonwidget( edit=self._bot_button, @@ -1108,6 +1109,61 @@ def _update_character(self, change: int = 0) -> None: color=color, tint_color=tint1, tint2_color=tint2) + self.save_settings() + + def load_settings(self): + try: + if ba.app.config.get("botsSpawnSetting") is None: + ba.app.config["botsSpawnSetting"] = (0, 1, 0) + bot_index, count, radius = ba.app.config.get( + "botsSpawnSetting") + else: + bot_index, count, radius = ba.app.config.get( + "botsSpawnSetting") + print(ba.app.config.get("botsSpawnSetting")) + except: + ba.app.config["botsSpawnSetting"] = (0, 1, 0) + bot_index, count, radius = ba.app.config.get("botsSpawnSetting") + values = bot_index, count, radius + print("settings loaded") + return values + + def save_settings(self): + ba.app.config["botsSpawnSetting"] = (self._icon_index, self.count, + self.radius) + print(ba.app.config.get("botsSpawnSetting")) + ba.app.config.commit() + print("settings saved") + + def check_color(self): + if self.bot_array_name[self._icon_index] in ( + 'Pro Bomber', 'Pro Brawler', + 'Pro Trigger', 'Pro Charger', + 'S.Pro Bomber', 'S.Pro Brawler', + 'S.Pro Trigger', 'S.Pro Charger'): + tint1 = (1.0, 0.2, 0.1) + tint2 = (0.6, 0.1, 0.05) + elif self.bot_array_name[self._icon_index] in 'Bouncy': + tint1 = (1, 1, 1) + tint2 = (1.0, 0.5, 0.5) + elif self.bot_array_name[self._icon_index] in ('Brawler Lite', + 'Bomber Lite'): + tint1 = (1.2, 0.9, 0.2) + tint2 = (1.0, 0.5, 0.6) + else: + tint1 = (0.6, 0.6, 0.6) + tint2 = (0.1, 0.3, 0.1) + + if self.bot_array_name[self._icon_index] in ( + 'S.Pro Bomber', 'S.Pro Brawler', + 'S.Pro Trigger', 'S.Pro Charger'): + color = (1.3, 1.2, 3.0) + else: + color = (1.0, 1.0, 1.0) + + colors = tint1, tint2, color + return colors + class PowerUpPracticeTab(PracticeTab): @@ -1133,19 +1189,19 @@ def __init__(self, window: PracticeWindow) -> None: ['triple_bombs', 'curse', 'health', 'ice_bombs', 'impact_bombs', 'land_mines', 'punch', 'shield', 'sticky_bombs']) - self._icon_index = self.power_list_type_name.index('Tripple Bombs') + self._icon_index = self.load_settings() self.setting_name = (['Bomb Countdown', 'Bomb Radius Visualizer']) self.config = (['bombCountdown', 'bombRadiusVisual']) def on_activate( - self, - parent_widget: ba.Widget, - tab_button: ba.Widget, - region_width: float, - region_height: float, - scroll_widget: ba.Widget, - extra_x: float, + self, + parent_widget: ba.Widget, + tab_button: ba.Widget, + region_width: float, + region_height: float, + scroll_widget: ba.Widget, + extra_x: float, ) -> ba.Widget: b_size_2 = 100 @@ -1276,14 +1332,25 @@ def on_activate( return self._subcontainer def debuff(self): + ba.screenmessage('Debuffed', + clients=[-1], transient=True, color=(1, 0.1, 0.1)) with ba.Context(_ba.get_foreground_host_activity()): for i in _ba.get_foreground_host_activity().players: Spaz._gloves_wear_off(i.actor) Spaz._multi_bomb_wear_off(i.actor) Spaz._bomb_wear_off(i.actor) + i.actor.node.mini_billboard_1_end_time = 0 + i.actor.node.mini_billboard_2_end_time = 0 + i.actor.node.mini_billboard_3_end_time = 0 + i.actor._multi_bomb_wear_off_flash_timer = None + i.actor._boxing_gloves_wear_off_flash_timer = None + i.actor._bomb_wear_off_flash_timer = None + Spaz.set_land_mine_count(i.actor, min(0, 0)) i.actor.shield_hitpoints = 1 def get_powerup(self, clid: int = -1) -> None: + ba.screenmessage('Spawned', + clients=[-1], transient=True, color=(0.2, 1, 0.2)) with ba.Context(_ba.get_foreground_host_activity()): for i in _ba.get_foreground_host_activity().players: if i.sessionplayer.inputdevice.client_id == clid: @@ -1294,7 +1361,8 @@ def get_powerup(self, clid: int = -1) -> None: i.node.position[1], i.node.position[2] + z) PowerupBox(position=pos, - poweruptype=self.power_list_type + poweruptype= + self.power_list_type [self._icon_index]).autoretain() def _power_window(self) -> None: @@ -1319,6 +1387,7 @@ def _update_power(self, change: int = 0) -> None: texture=(ba.gettexture('powerup' + self.power_list[ self._icon_index]))) + self.save_settings() def _check_value_change(self, setting: int, widget: ba.Widget, value: str) -> None: @@ -1338,6 +1407,28 @@ def _check_value_change(self, setting: int, widget: ba.Widget, else: ba.app.config["bombRadiusVisual"] = False + def load_settings(self): + try: + if ba.app.config.get("powerSpawnSetting") is None: + ba.app.config["powerSpawnSetting"] = 0 + power_index = ba.app.config.get("powerSpawnSetting") + else: + power_index = ba.app.config.get( + "powerSpawnSetting") + print(ba.app.config.get("powerSpawnSetting")) + except: + ba.app.config["powerSpawnSetting"] = 0 + power_index = ba.app.config.get("powerSpawnSetting") + values = power_index + print("power settings loaded") + return values + + def save_settings(self): + ba.app.config["powerSpawnSetting"] = self._icon_index + print(ba.app.config.get("powerSpawnSetting")) + ba.app.config.commit() + print("power settings saved") + class OthersPracticeTab(PracticeTab): """The about tab in the practice UI""" @@ -1349,16 +1440,16 @@ def __init__(self, window: PracticeWindow) -> None: self.parent_widget = None self.activity = _ba.get_foreground_host_activity() self.setting_name = (['Pause On Window', 'Invincible', 'Epic Mode']) - self.config = (['pause', 'invincible', 'epic']) + self.config = (['pause', 'invincible']) def on_activate( - self, - parent_widget: ba.Widget, - tab_button: ba.Widget, - region_width: float, - region_height: float, - scroll_widget: ba.Widget, - extra_x: float, + self, + parent_widget: ba.Widget, + tab_button: ba.Widget, + region_width: float, + region_height: float, + scroll_widget: ba.Widget, + extra_x: float, ) -> ba.Widget: spacing_v = 60 spacing_h = -50 @@ -1403,7 +1494,11 @@ def on_activate( color=(0.8, 0.8, 0.8), v_align='center', maxwidth=200) - value = ba.app.config.get(self.config[i]) + if name == 'Epic Mode': + activity = _ba.get_foreground_host_activity() + value = activity.globalsnode.slow_motion + else: + value = ba.app.config.get(self.config[i]) txt2 = ba.textwidget( parent=self._subcontainer, position=(self._sub_width * 0.8 - spacing_v / 2, @@ -1546,7 +1641,7 @@ def __init__(self, (self.TabID.BOTS, 'Bots') ] if ba_internal.get_v1_account_misc_read_val( - 'enablePublicParties', True + 'enablePublicParties', True ): tabdefs.append( ( @@ -1742,6 +1837,7 @@ def _restore_state(self) -> None: def new_begin(self): """Runs when game is began.""" + org_begin(self) _ba.set_party_icon_always_visible(True) @@ -1817,13 +1913,13 @@ def __init__(self, mask_texture = ba.gettexture('characterIconMask') - bot_list = (['bones', 'neoSpaz', 'kronk', 'zoe', + bot_list = (['bones', 'neoSpaz', 'kronk', 'neoSpaz', 'kronk', 'zoe', 'ninja', 'mel', 'jack', 'bunny', 'neoSpaz', 'kronk', 'zoe', 'ninja', 'neoSpaz', 'kronk', 'zoe', 'ninja']) - bot_list_type = (['Dummy', 'Bomber', 'Brawler', 'Trigger', + bot_list_type = (['Dummy', 'Bomber Lite', 'Brawler Lite', 'Bomber', 'Brawler', 'Trigger', 'Charger', 'Sticky', 'Explodey', 'Bouncy', 'Pro Bomber', 'Pro Brawler', 'Pro Trigger', 'Pro Charger', 'S.Pro Bomber', 'S.Pro Brawler', @@ -1842,6 +1938,10 @@ def __init__(self, elif bot_list_type[index] in 'Bouncy': tint1 = (1, 1, 1) tint2 = (1.0, 0.5, 0.5) + elif bot_list_type[index] in ('Brawler Lite', + 'Bomber Lite'): + tint1 = (1.2, 0.9, 0.2) + tint2 = (1.0, 0.5, 0.6) else: tint1 = (0.6, 0.6, 0.6) tint2 = (0.1, 0.3, 0.1) @@ -2084,7 +2184,7 @@ def __init__(self, text = ('Practice Tools Mod\n' 'Made By Cross Joy\n' - 'version 1.0\n' + 'version 1.2\n' '\n' 'Thx to\n' 'Mikirog for the Bomb radius visualizer mod.\n' From e61958bb889d8e8f8e43b4e8cf6c4a2f38a99606 Mon Sep 17 00:00:00 2001 From: CrossJoy Date: Mon, 19 Jun 2023 11:20:50 +0000 Subject: [PATCH 0478/1464] [ci] auto-format --- plugins/utilities/practice_tools.py | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-) diff --git a/plugins/utilities/practice_tools.py b/plugins/utilities/practice_tools.py index f7677805..ae9897a1 100644 --- a/plugins/utilities/practice_tools.py +++ b/plugins/utilities/practice_tools.py @@ -57,7 +57,8 @@ import weakref from enum import Enum from typing import TYPE_CHECKING -import ba, _ba +import ba +import _ba import ba.internal import bastd from bastd.actor.powerupbox import PowerupBox @@ -560,7 +561,7 @@ def _update(self) -> None: bot_list = [] ba.print_exception('Error updating bot list: ' + str(self._bot_lists[ - self._bot_update_list])) + self._bot_update_list])) self._bot_update_list = (self._bot_update_list + 1) % self._bot_list_count @@ -648,11 +649,10 @@ def _update(self) -> None: except Exception: ba.print_exception('Error updating bot list: ' + str(self._bot_lists[ - self._bot_update_list])) + self._bot_update_list])) self._bot_update_list = (self._bot_update_list + 1) % self._bot_list_count - except: pass @@ -1100,7 +1100,6 @@ def _update_character(self, change: int = 0) -> None: if self._bot_button: tint1, tint2, color = self.check_color() - ba.buttonwidget( edit=self._bot_button, texture=ba.gettexture(self.image_array[self._icon_index]), @@ -1165,7 +1164,6 @@ def check_color(self): return colors - class PowerUpPracticeTab(PracticeTab): """The about tab in the practice UI""" @@ -1361,8 +1359,7 @@ def get_powerup(self, clid: int = -1) -> None: i.node.position[1], i.node.position[2] + z) PowerupBox(position=pos, - poweruptype= - self.power_list_type + poweruptype=self.power_list_type [self._icon_index]).autoretain() def _power_window(self) -> None: From 503317b11869fe5c054c0526f369b7003385a060 Mon Sep 17 00:00:00 2001 From: CrossJoy Date: Mon, 19 Jun 2023 11:20:51 +0000 Subject: [PATCH 0479/1464] [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 e13d88c7..c8adc4b7 100644 --- a/plugins/utilities.json +++ b/plugins/utilities.json @@ -606,7 +606,12 @@ } ], "versions": { - "1.2.0": null, + "1.2.0": { + "api_version": 7, + "commit_sha": "e61958b", + "released_on": "19-06-2023", + "md5sum": "0ef91a10240b1df25595750015042a3f" + }, "1.1.0": { "api_version": 7, "commit_sha": "7ab4576", From 6af340da3d8074afa9d9b47c9a7edad7176a8ced Mon Sep 17 00:00:00 2001 From: Rikko Date: Wed, 17 May 2023 02:57:02 +0530 Subject: [PATCH 0480/1464] Migrate plugin manager to API 8 --- index.json | 3 +- plugin_manager.py | 1715 +++++++++++++++++++++++---------------------- 2 files changed, 898 insertions(+), 820 deletions(-) diff --git a/index.json b/index.json index 3e3e90e0..5d7f5a8c 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": { + "1.0.0": null, "0.3.5": { "api_version": 7, "commit_sha": "985e486", @@ -104,4 +105,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 ea83afef..b0b40271 100644 --- a/plugin_manager.py +++ b/plugin_manager.py @@ -1,6 +1,7 @@ -# ba_meta require api 7 -import ba -import _ba +# ba_meta require api 8 +import babase +import _babase +import bauiv1 as bui from bastd.ui import popup, confirm import urllib.request @@ -21,8 +22,12 @@ from typing import Union, Optional from datetime import datetime -_env = _ba.env() -_uiscale = ba.app.ui.uiscale +# Modules used for overriding AllSettingsWindow +from threading import Thread +import logging + +_env = _babase.env() +_uiscale = bui.app.classic.ui.uiscale PLUGIN_MANAGER_VERSION = "0.3.5" @@ -214,9 +219,9 @@ def __init__(self): def setup_config(self): # is_config_updated = False existing_plugin_manager_config = copy.deepcopy( - ba.app.config.get("Community Plugin Manager")) + babase.app.config.get("Community Plugin Manager")) - plugin_manager_config = ba.app.config.setdefault("Community Plugin Manager", {}) + plugin_manager_config = babase.app.config.setdefault("Community Plugin Manager", {}) plugin_manager_config.setdefault("Custom Sources", []) installed_plugins = plugin_manager_config.setdefault("Installed Plugins", {}) for plugin_name in tuple(installed_plugins.keys()): @@ -240,26 +245,26 @@ def setup_config(self): plugin_manager_config["Settings"] = current_settings if plugin_manager_config != existing_plugin_manager_config: - ba.app.config.commit() + babase.app.config.commit() async def update_plugin_manager(self): - if not ba.app.config["Community Plugin Manager"]["Settings"]["Auto Update Plugin Manager"]: + if not babase.app.config["Community Plugin Manager"]["Settings"]["Auto Update Plugin Manager"]: return update_details = await self.plugin_manager.get_update_details() if update_details: to_version, commit_sha = update_details - ba.screenmessage(f"Plugin Manager is being updated to v{to_version}") + bui.screenmessage(f"Plugin Manager is being updated to v{to_version}") try: await self.plugin_manager.update(to_version, commit_sha) except MD5CheckSumFailedError: - ba.playsound(ba.getsound('error')) + bui.getsound('error').play() else: - ba.screenmessage("Update successful. Restart game to reload changes.", - color=(0, 1, 0)) - ba.playsound(ba.getsound('shieldUp')) + bui.screenmessage("Update successful. Restart game to reload changes.", + color=(0, 1, 0)) + bui.getsound('shieldUp').play() async def update_plugins(self): - if not ba.app.config["Community Plugin Manager"]["Settings"]["Auto Update Plugins"]: + if not babase.app.config["Community Plugin Manager"]["Settings"]["Auto Update Plugins"]: return await self.plugin_manager.setup_index() all_plugins = await self.plugin_manager.categories["All"].get_plugins() @@ -282,16 +287,16 @@ def _is_new_supported_plugin(plugin): return True async def notify_new_plugins(self): - if not ba.app.config["Community Plugin Manager"]["Settings"]["Notify New Plugins"]: + if not babase.app.config["Community Plugin Manager"]["Settings"]["Notify New Plugins"]: return await self.plugin_manager.setup_index() new_num_of_plugins = len(await self.plugin_manager.categories["All"].get_plugins()) try: - existing_num_of_plugins = ba.app.config["Community Plugin Manager"]["Existing Number of Plugins"] + existing_num_of_plugins = babase.app.config["Community Plugin Manager"]["Existing Number of Plugins"] except KeyError: - ba.app.config["Community Plugin Manager"]["Existing Number of Plugins"] = new_num_of_plugins - ba.app.config.commit() + babase.app.config["Community Plugin Manager"]["Existing Number of Plugins"] = new_num_of_plugins + babase.app.config.commit() return if existing_num_of_plugins < new_num_of_plugins: @@ -310,11 +315,11 @@ async def notify_new_plugins(self): notification_text = f"{new_supported_plugins_count} new plugin ({new_supported_plugins}) is available!" else: notification_text = f"{new_supported_plugins_count} new plugins ({new_supported_plugins}) are available!" - ba.screenmessage(notification_text, color=(0, 1, 0)) + bui.screenmessage(notification_text, color=(0, 1, 0)) if existing_num_of_plugins != new_num_of_plugins: - ba.app.config["Community Plugin Manager"]["Existing Number of Plugins"] = new_num_of_plugins - ba.app.config.commit() + babase.app.config["Community Plugin Manager"]["Existing Number of Plugins"] = new_num_of_plugins + babase.app.config.commit() async def execute(self): self.setup_config() @@ -416,8 +421,8 @@ async def refresh(self): await self.get_plugins() def save(self): - ba.app.config["Community Plugin Manager"]["Custom Sources"].append(self.meta_url) - ba.app.config.commit() + babase.app.config["Community Plugin Manager"]["Custom Sources"].append(self.meta_url) + babase.app.config.commit() class CategoryAll(Category): @@ -450,11 +455,11 @@ def is_installed(self): @property def is_installed_via_plugin_manager(self): - return self.name in ba.app.config["Community Plugin Manager"]["Installed Plugins"] + return self.name in babase.app.config["Community Plugin Manager"]["Installed Plugins"] def initialize(self): - if self.name not in ba.app.config["Community Plugin Manager"]["Installed Plugins"]: - ba.app.config["Community Plugin Manager"]["Installed Plugins"][self.name] = {} + if self.name not in babase.app.config["Community Plugin Manager"]["Installed Plugins"]: + babase.app.config["Community Plugin Manager"]["Installed Plugins"][self.name] = {} return self async def uninstall(self): @@ -465,7 +470,7 @@ async def uninstall(self): except FileNotFoundError: pass try: - del ba.app.config["Community Plugin Manager"]["Installed Plugins"][self.name] + del babase.app.config["Community Plugin Manager"]["Installed Plugins"][self.name] except KeyError: pass else: @@ -474,7 +479,7 @@ async def uninstall(self): @property def version(self): try: - version = (ba.app.config["Community Plugin Manager"] + version = (babase.app.config["Community Plugin Manager"] ["Installed Plugins"][self.name]["version"]) except KeyError: version = None @@ -489,12 +494,12 @@ def _set_content(self, content): fout.write(content) def has_settings(self): - for plugin_entry_point, plugin_class in ba.app.plugins.active_plugins.items(): + for plugin_entry_point, plugin_class in babase.app.plugins.active_plugins.items(): if plugin_entry_point.startswith(self._entry_point_initials): return plugin_class.has_settings_ui() def launch_settings(self, source_widget): - for plugin_entry_point, plugin_class in ba.app.plugins.active_plugins.items(): + for plugin_entry_point, plugin_class in babase.app.plugins.active_plugins.items(): if plugin_entry_point.startswith(self._entry_point_initials): return plugin_class.show_settings_ui(source_widget) @@ -532,32 +537,32 @@ async def has_plugins(self): return len(entry_points) > 0 def load_minigames(self): - scanner = ba._meta.DirectoryScan(paths="") + scanner = babase._meta.DirectoryScan(paths="") directory, module = self.install_path.rsplit(os.path.sep, 1) scanner._scan_module( pathlib.Path(directory), pathlib.Path(module), ) - scanned_results = set(ba.app.meta.scanresults.exports["ba.GameActivity"]) - for game in scanner.results.exports["ba.GameActivity"]: + scanned_results = set(babase.app.meta.scanresults.exports["babase.GameActivity"]) + for game in scanner.results.exports["babase.GameActivity"]: if game not in scanned_results: - ba.screenmessage(f"{game} minigame loaded") - ba.app.meta.scanresults.exports["ba.GameActivity"].append(game) + bui.screenmessage(f"{game} minigame loaded") + babase.app.meta.scanresults.exports["babase.GameActivity"].append(game) def unload_minigames(self): - scanner = ba._meta.DirectoryScan(paths="") + scanner = babase._meta.DirectoryScan(paths="") directory, module = self.install_path.rsplit(os.path.sep, 1) scanner._scan_module( pathlib.Path(directory), pathlib.Path(module), ) new_scanned_results_games = [] - for game in ba.app.meta.scanresults.exports["ba.GameActivity"]: - if game in scanner.results.exports["ba.GameActivity"]: - ba.screenmessage(f"{game} minigame unloaded") + for game in babase.app.meta.scanresults.exports["babase.GameActivity"]: + if game in scanner.results.exports["babase.GameActivity"]: + bui.screenmessage(f"{game} minigame unloaded") else: new_scanned_results_games.append(game) - ba.app.meta.scanresults.exports["ba.GameActivity"] = new_scanned_results_games + babase.app.meta.scanresults.exports["babase.GameActivity"] = new_scanned_results_games async def is_enabled(self): """ @@ -565,13 +570,13 @@ async def is_enabled(self): """ if not await self.has_plugins(): return True - for entry_point, plugin_info in ba.app.config["Plugins"].items(): + for entry_point, plugin_info in babase.app.config["Plugins"].items(): if entry_point.startswith(self._entry_point_initials) and plugin_info["enabled"]: return True # XXX: The below logic is more accurate but less efficient, since it actually # reads the local plugin file and parses entry points from it. # for entry_point in await self.get_entry_points(): - # if ba.app.config["Plugins"][entry_point]["enabled"]: + # if babase.app.config["Plugins"][entry_point]["enabled"]: # return True return False @@ -579,31 +584,31 @@ async def is_enabled(self): # own separate logic. # async def _set_status(self, to_enable=True): # for entry_point in await self.get_entry_points: - # if entry_point not in ba.app.config["Plugins"]: - # ba.app.config["Plugins"][entry_point] = {} - # ba.app.config["Plugins"][entry_point]["enabled"] = to_enable + # if entry_point not in babase.app.config["Plugins"]: + # babase.app.config["Plugins"][entry_point] = {} + # babase.app.config["Plugins"][entry_point]["enabled"] = to_enable async def enable(self): for entry_point in await self.get_entry_points(): - if entry_point not in ba.app.config["Plugins"]: - ba.app.config["Plugins"][entry_point] = {} - ba.app.config["Plugins"][entry_point]["enabled"] = True - if entry_point not in ba.app.plugins.active_plugins: + if entry_point not in babase.app.config["Plugins"]: + babase.app.config["Plugins"][entry_point] = {} + babase.app.config["Plugins"][entry_point]["enabled"] = True + if entry_point not in babase.app.plugins.active_plugins: self.load_plugin(entry_point) - ba.screenmessage(f"{entry_point} loaded") + bui.screenmessage(f"{entry_point} loaded") if await self.has_minigames(): self.load_minigames() # await self._set_status(to_enable=True) self.save() def load_plugin(self, entry_point): - plugin_class = ba._general.getclass(entry_point, ba.Plugin) + plugin_class = babase._general.getclass(entry_point, babase.Plugin) loaded_plugin_class = plugin_class() loaded_plugin_class.on_app_running() - ba.app.plugins.active_plugins[entry_point] = loaded_plugin_class + babase.app.plugins.active_plugins[entry_point] = loaded_plugin_class def disable(self): - for entry_point, plugin_info in ba.app.config["Plugins"].items(): + for entry_point, plugin_info in babase.app.config["Plugins"].items(): if entry_point.startswith(self._entry_point_initials): # if plugin_info["enabled"]: plugin_info["enabled"] = False @@ -613,17 +618,17 @@ def disable(self): self.save() def set_version(self, version): - app = ba.app + app = babase.app app.config["Community Plugin Manager"]["Installed Plugins"][self.name]["version"] = version return self # def set_entry_points(self): - # if not "entry_points" in ba.app.config["Community Plugin Manager"] + # if not "entry_points" in babase.app.config["Community Plugin Manager"] # ["Installed Plugins"][self.name]: - # ba.app.config["Community Plugin Manager"]["Installed Plugins"] + # babase.app.config["Community Plugin Manager"]["Installed Plugins"] # [self.name]["entry_points"] = [] # for entry_point in await self.get_entry_points(): - # ba.app.config["Community Plugin Manager"]["Installed Plugins"][self.name] + # babase.app.config["Community Plugin Manager"]["Installed Plugins"][self.name] # ["entry_points"].append(entry_point) async def set_content(self, content): @@ -644,7 +649,7 @@ async def set_content_from_network_response(self, request, md5sum=None, retries= return self._content def save(self): - ba.app.config.commit() + babase.app.config.commit() return self @@ -690,13 +695,13 @@ async def install(self, suppress_screenmessage=False): local_plugin = await self._download() except MD5CheckSumFailedError: if not suppress_screenmessage: - ba.screenmessage( + bui.screenmessage( f"{self.plugin.name} failed MD5 checksum during installation", color=(1, 0, 0)) return False else: if not suppress_screenmessage: - ba.screenmessage(f"{self.plugin.name} installed", color=(0, 1, 0)) - check = ba.app.config["Community Plugin Manager"]["Settings"] + bui.screenmessage(f"{self.plugin.name} installed", color=(0, 1, 0)) + check = babase.app.config["Community Plugin Manager"]["Settings"] if check["Auto Enable Plugins After Installation"]: await local_plugin.enable() return True @@ -766,7 +771,7 @@ def latest_version(self): def latest_compatible_version(self): if self._latest_compatible_version is None: for number, info in self.info["versions"].items(): - if info["api_version"] == ba.app.api_version: + if info["api_version"] == babase.app.api_version: self._latest_compatible_version = PluginVersion( self, (number, info), @@ -775,7 +780,7 @@ def latest_compatible_version(self): break if self._latest_compatible_version is None: raise NoCompatibleVersionError( - f"{self.name} has no version compatible with API {ba.app.api_version}." + f"{self.name} has no version compatible with API {babase.app.api_version}." ) return self._latest_compatible_version @@ -795,7 +800,7 @@ def create_local(self): async def uninstall(self): await self.get_local().uninstall() - ba.screenmessage(f"{self.name} uninstalled", color=(0.9, 1, 0)) + bui.screenmessage(f"{self.name} uninstalled", color=(0.9, 1, 0)) def has_update(self): try: @@ -807,14 +812,14 @@ def has_update(self): async def update(self): if await self.latest_compatible_version.install(suppress_screenmessage=True): - ba.screenmessage(f"{self.name} updated to {self.latest_compatible_version.number}", - color=(0, 1, 0)) - ba.playsound(ba.getsound('shieldUp')) + bui.screenmessage(f"{self.name} updated to {self.latest_compatible_version.number}", + color=(0, 1, 0)) + bui.getsound('shieldUp').play() else: - ba.screenmessage(f"{self.name} failed MD5 checksum while updating to " - f"{self.latest_compatible_version.number}", - color=(1, 0, 0)) - ba.playsound(ba.getsound('error')) + bui.screenmessage(f"{self.name} failed MD5 checksum while updating to " + f"{self.latest_compatible_version.number}", + color=(1, 0, 0)) + bui.getsound('error').play() class PluginWindow(popup.PopupWindow): @@ -849,11 +854,11 @@ def get_description(self, minimum_character_offset=40): return partitioned_string async def draw_ui(self): - # print(ba.app.plugins.active_plugins) + # print(babase.app.plugins.active_plugins) - ba.playsound(ba.getsound('swish')) + bui.getsound('swish').play() 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 + s = 1.25 if _uiscale is babase.UIScale.SMALL else 1.39 if babase.UIScale.MEDIUM else 1.67 width = 400 * s height = 120 + 100 * s color = (1, 1, 1) @@ -861,46 +866,46 @@ async def draw_ui(self): self._transition_out = 'out_scale' transition = 'in_scale' - self._root_widget = ba.containerwidget(size=(width, height), - # parent=_ba.get_special_widget( - # 'overlay_stack'), - 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), - scale_origin_stack_offset=self.scale_origin) + self._root_widget = bui.containerwidget(size=(width, height), + # parent=_babase.get_special_widget( + # 'overlay_stack'), + on_outside_click_call=self._cancel, + transition=transition, + scale=(2.1 if _uiscale is babase.UIScale.SMALL else 1.5 + if _uiscale is babase.UIScale.MEDIUM else 1.0), + scale_origin_stack_offset=self.scale_origin) pos = height * 0.8 plugin_title = f"{self.plugin.name} (v{self.plugin.latest_compatible_version.number})" - ba.textwidget(parent=self._root_widget, - position=(width * 0.49, pos), size=(0, 0), - h_align='center', v_align='center', text=plugin_title, - scale=text_scale * 1.25, color=color, - maxwidth=width * 0.9) + bui.textwidget(parent=self._root_widget, + position=(width * 0.49, pos), size=(0, 0), + h_align='center', v_align='center', text=plugin_title, + scale=text_scale * 1.25, color=color, + maxwidth=width * 0.9) pos -= 25 # author = - ba.textwidget(parent=self._root_widget, - position=(width * 0.49, pos), - size=(0, 0), - h_align='center', - v_align='center', - text='by ' + self.plugin.info["authors"][0]["name"], - scale=text_scale * 0.8, - color=color, maxwidth=width * 0.9) + bui.textwidget(parent=self._root_widget, + position=(width * 0.49, pos), + size=(0, 0), + h_align='center', + v_align='center', + text='by ' + self.plugin.info["authors"][0]["name"], + scale=text_scale * 0.8, + color=color, maxwidth=width * 0.9) pos -= 35 - # status = ba.textwidget(parent=self._root_widget, + # status = bui.textwidget(parent=self._root_widget, # position=(width * 0.49, pos), size=(0, 0), # h_align='center', v_align='center', # text=status_text, scale=text_scale * 0.8, # color=color, maxwidth=width * 0.9) pos -= 25 # info = - ba.textwidget(parent=self._root_widget, - position=(width * 0.49, pos), size=(0, 0), - h_align='center', v_align='center', - text=self.get_description(), - scale=text_scale * 0.6, color=color, - maxwidth=width * 0.95) + bui.textwidget(parent=self._root_widget, + position=(width * 0.49, pos), size=(0, 0), + h_align='center', v_align='center', + text=self.get_description(), + scale=text_scale * 0.6, color=color, + maxwidth=width * 0.95) b1_color = None b2_color = (0.8, 0.15, 0.35) b3_color = (0.2, 0.8, 0.3) @@ -934,69 +939,69 @@ async def draw_ui(self): button1_action = self.install if to_draw_button1: - ba.buttonwidget(parent=self._root_widget, - position=(width * 0.1, pos), - size=button_size, - on_activate_call=button1_action, - color=b1_color, - textcolor=b_text_color, - button_type='square', - text_scale=1, - label=button1_label) + bui.buttonwidget(parent=self._root_widget, + position=(width * 0.1, pos), + size=button_size, + on_activate_call=button1_action, + color=b1_color, + textcolor=b_text_color, + button_type='square', + text_scale=1, + label=button1_label) if self.plugin.is_installed: - ba.buttonwidget(parent=self._root_widget, - position=(width * 0.4, pos), - size=button_size, - on_activate_call=button2_action, - color=b2_color, - textcolor=b_text_color, - button_type='square', - text_scale=1, - label=button2_label) + bui.buttonwidget(parent=self._root_widget, + position=(width * 0.4, pos), + size=button_size, + on_activate_call=button2_action, + color=b2_color, + textcolor=b_text_color, + button_type='square', + text_scale=1, + label=button2_label) if has_update: # button3 = - ba.buttonwidget(parent=self._root_widget, - position=(width * 0.7, pos), - size=button_size, - on_activate_call=button3_action, - color=b3_color, - textcolor=b_text_color, - autoselect=True, - button_type='square', - text_scale=1, - label=button3_label) - ba.containerwidget(edit=self._root_widget, - 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) - 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.view_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="Source", - size=(10, 10), - draw_controller=open_button, - color=(1, 1, 1, 1), - rotate=25, - scale=0.45) + bui.buttonwidget(parent=self._root_widget, + position=(width * 0.7, pos), + size=button_size, + on_activate_call=button3_action, + color=b3_color, + textcolor=b_text_color, + autoselect=True, + button_type='square', + text_scale=1, + label=button3_label) + bui.containerwidget(edit=self._root_widget, + on_cancel_call=self._cancel) + + open_pos_x = (390 if _uiscale is babase.UIScale.SMALL else + 450 if _uiscale is babase.UIScale.MEDIUM else 440) + open_pos_y = (100 if _uiscale is babase.UIScale.SMALL else + 110 if _uiscale is babase.UIScale.MEDIUM else 120) + open_button = bui.buttonwidget(parent=self._root_widget, + autoselect=True, + position=(open_pos_x, open_pos_y), + size=(40, 40), + button_type="square", + label="", + # color=bui.app.classic.ui.title_color, + color=(0.6, 0.53, 0.63), + on_activate_call=lambda: bui.open_url(self.plugin.view_url)) + bui.imagewidget(parent=self._root_widget, + position=(open_pos_x, open_pos_y), + size=(40, 40), + color=(0.8, 0.95, 1), + texture=bui.gettexture("file"), + draw_controller=open_button) + bui.textwidget(parent=self._root_widget, + position=(open_pos_x-3, open_pos_y+12), + text="Source", + size=(10, 10), + draw_controller=open_button, + 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"] @@ -1005,69 +1010,69 @@ 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"]), + action=lambda: bui.open_url(self.plugin.info["external_url"]), ) - 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, - 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) + open_pos_x = (440 if _uiscale is babase.UIScale.SMALL else + 500 if _uiscale is babase.UIScale.MEDIUM else 490) + open_pos_y = (100 if _uiscale is babase.UIScale.SMALL else + 110 if _uiscale is babase.UIScale.MEDIUM else 120) + open_button = bui.buttonwidget(parent=self._root_widget, + autoselect=True, + position=(open_pos_x, open_pos_y), + size=(40, 40), + button_type="square", + label="", + # color=bui.app.classic.ui.title_color, + color=(0.6, 0.53, 0.63), + + on_activate_call=tutorial_confirm_window) + + bui.imagewidget(parent=self._root_widget, + position=(open_pos_x, open_pos_y), + size=(40, 40), + color=(0.8, 0.95, 1), + texture=bui.gettexture("frameInset"), + draw_controller=open_button) + bui.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) - settings_pos_y = (100 if _uiscale is ba.UIScale.SMALL else - 110 if _uiscale is ba.UIScale.MEDIUM else 120) - settings_button = ba.buttonwidget(parent=self._root_widget, - autoselect=True, - position=(settings_pos_x, settings_pos_y), - size=(40, 40), - button_type="square", - label="", - color=(0, 0.75, 0.75),) - ba.buttonwidget( + settings_pos_x = (60 if _uiscale is babase.UIScale.SMALL else + 60 if _uiscale is babase.UIScale.MEDIUM else 60) + settings_pos_y = (100 if _uiscale is babase.UIScale.SMALL else + 110 if _uiscale is babase.UIScale.MEDIUM else 120) + settings_button = bui.buttonwidget(parent=self._root_widget, + autoselect=True, + position=(settings_pos_x, settings_pos_y), + size=(40, 40), + button_type="square", + label="", + color=(0, 0.75, 0.75),) + bui.buttonwidget( edit=settings_button, - on_activate_call=ba.Call(self.settings, settings_button),) - ba.imagewidget(parent=self._root_widget, - position=(settings_pos_x, settings_pos_y), - size=(40, 40), - color=(0.8, 0.95, 1), - texture=ba.gettexture("settingsIcon"), - draw_controller=settings_button) + on_activate_call=babase.Call(self.settings, settings_button),) + bui.imagewidget(parent=self._root_widget, + position=(settings_pos_x, settings_pos_y), + size=(40, 40), + color=(0.8, 0.95, 1), + texture=bui.gettexture("settingsIcon"), + draw_controller=settings_button) - # ba.containerwidget(edit=self._root_widget, selected_child=button3) - # ba.containerwidget(edit=self._root_widget, start_button=button3) + # bui.containerwidget(edit=self._root_widget, selected_child=button3) + # bui.containerwidget(edit=self._root_widget, start_button=button3) def _ok(self) -> None: - ba.containerwidget(edit=self._root_widget, transition='out_scale') + bui.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') + bui.getsound('swish').play() + bui.containerwidget(edit=self._root_widget, transition='out_scale') def button(fn): async def asyncio_handler(fn, self, *args, **kwargs): @@ -1095,22 +1100,22 @@ def disable(self) -> None: @button async def enable(self) -> None: await self.local_plugin.enable() - ba.playsound(ba.getsound('gunCocking')) + bui.getsound('gunCocking').play() @button async def install(self): await self.plugin.latest_compatible_version.install() - ba.playsound(ba.getsound('cashRegister2')) + bui.getsound('cashRegister2').play() @button async def uninstall(self): await self.plugin.uninstall() - ba.playsound(ba.getsound('shieldDown')) + bui.getsound('shieldDown').play() @button async def update(self): await self.plugin.update() - ba.playsound(ba.getsound('shieldUp')) + bui.getsound('shieldUp').play() class PluginManager: @@ -1156,7 +1161,7 @@ async def setup_plugin_categories(self, plugin_index): category = Category(plugin_category_url) request = category.fetch_metadata() requests.append(request) - for repository in ba.app.config["Community Plugin Manager"]["Custom Sources"]: + for repository in babase.app.config["Community Plugin Manager"]["Custom Sources"]: plugin_category_url = partial_format(plugin_index["external_source_url"], repository=repository) category = Category(plugin_category_url, is_3rd_party=True) @@ -1194,7 +1199,7 @@ def unset_index_global_cache(self): async def get_update_details(self): index = await self.get_index() for version, info in index["versions"].items(): - if info["api_version"] != ba.app.api_version: + if info["api_version"] != babase.app.api_version: # No point checking a version of the API game doesn't support. continue if version == PLUGIN_MANAGER_VERSION: @@ -1238,74 +1243,74 @@ def __init__(self, origin_widget): self.scale_origin = origin_widget.get_screen_space_center() b_textcolor = (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.1 if _uiscale is babase.UIScale.SMALL else 1.27 if babase.UIScale.MEDIUM else 1.57 # text_scale = 0.7 * s self._transition_out = 'out_scale' transition = 'in_scale' - self._root_widget = ba.containerwidget(size=(400, 340), - # parent=_ba.get_special_widget( - # 'overlay_stack'), - on_outside_click_call=self._ok, - transition=transition, - scale=(2.1 if _uiscale is ba.UIScale.SMALL else 1.5 - if _uiscale is ba.UIScale.MEDIUM else 1.0), - scale_origin_stack_offset=self.scale_origin, - on_cancel_call=self._ok) - - ba.textwidget( + self._root_widget = bui.containerwidget(size=(400, 340), + # parent=_babase.get_special_widget( + # 'overlay_stack'), + on_outside_click_call=self._ok, + transition=transition, + scale=(2.1 if _uiscale is babase.UIScale.SMALL else 1.5 + if _uiscale is babase.UIScale.MEDIUM else 1.0), + scale_origin_stack_offset=self.scale_origin, + on_cancel_call=self._ok) + + bui.textwidget( parent=self._root_widget, position=(155, 300), size=(100, 25), text="Custom Plugin Sources", - color=ba.app.ui.title_color, + color=bui.app.classic.ui.title_color, scale=0.8, h_align="center", v_align="center", maxwidth=270, ) - scroll_size_x = (290 if _uiscale is ba.UIScale.SMALL else - 300 if _uiscale is ba.UIScale.MEDIUM else 290) - scroll_size_y = (170 if _uiscale is ba.UIScale.SMALL else - 185 if _uiscale is ba.UIScale.MEDIUM else 180) - scroll_pos_x = (55 if _uiscale is ba.UIScale.SMALL else - 40 if _uiscale is ba.UIScale.MEDIUM else 60) + scroll_size_x = (290 if _uiscale is babase.UIScale.SMALL else + 300 if _uiscale is babase.UIScale.MEDIUM else 290) + scroll_size_y = (170 if _uiscale is babase.UIScale.SMALL else + 185 if _uiscale is babase.UIScale.MEDIUM else 180) + scroll_pos_x = (55 if _uiscale is babase.UIScale.SMALL else + 40 if _uiscale is babase.UIScale.MEDIUM else 60) scroll_pos_y = 105 - self._scrollwidget = ba.scrollwidget(parent=self._root_widget, - size=(scroll_size_x, scroll_size_y), - position=(scroll_pos_x, scroll_pos_y)) - self._columnwidget = ba.columnwidget(parent=self._scrollwidget, - border=1, - margin=0) + self._scrollwidget = bui.scrollwidget(parent=self._root_widget, + size=(scroll_size_x, scroll_size_y), + position=(scroll_pos_x, scroll_pos_y)) + self._columnwidget = bui.columnwidget(parent=self._scrollwidget, + border=1, + margin=0) delete_source_button_position_pos_x = 360 delete_source_button_position_pos_y = 110 - delete_source_button = ba.buttonwidget(parent=self._root_widget, - position=(delete_source_button_position_pos_x, - delete_source_button_position_pos_y), - size=(25, 25), - on_activate_call=self.delete_selected_source, - label="", - # texture=ba.gettexture("crossOut"), - button_type="square", - color=(0.6, 0, 0), - textcolor=b_textcolor, - # autoselect=True, - text_scale=1) - - ba.imagewidget(parent=self._root_widget, - position=(delete_source_button_position_pos_x + 2, - delete_source_button_position_pos_y), - size=(25, 25), - color=(5, 2, 2), - texture=ba.gettexture("crossOut"), - draw_controller=delete_source_button) - - warning_pos_x = (43 if _uiscale is ba.UIScale.SMALL else - 35 if _uiscale is ba.UIScale.MEDIUM else + delete_source_button = bui.buttonwidget(parent=self._root_widget, + position=(delete_source_button_position_pos_x, + delete_source_button_position_pos_y), + size=(25, 25), + on_activate_call=self.delete_selected_source, + label="", + # texture=bui.gettexture("crossOut"), + button_type="square", + color=(0.6, 0, 0), + textcolor=b_textcolor, + # autoselect=True, + text_scale=1) + + bui.imagewidget(parent=self._root_widget, + position=(delete_source_button_position_pos_x + 2, + delete_source_button_position_pos_y), + size=(25, 25), + color=(5, 2, 2), + texture=bui.gettexture("crossOut"), + draw_controller=delete_source_button) + + warning_pos_x = (43 if _uiscale is babase.UIScale.SMALL else + 35 if _uiscale is babase.UIScale.MEDIUM else 48) - ba.textwidget( + bui.textwidget( parent=self._root_widget, position=(warning_pos_x, 74), size=(50, 22), @@ -1318,32 +1323,32 @@ def __init__(self, origin_widget): maxwidth=400, ) - self._add_source_widget = ba.textwidget(parent=self._root_widget, - # text="rikkolovescats/sahilp-plugins", - size=(335, 50), - position=(21, 22), - h_align='left', - v_align='center', - editable=True, - scale=0.75, - maxwidth=215, - # autoselect=True, - description="Add Source") + self._add_source_widget = bui.textwidget(parent=self._root_widget, + # text="rikkolovescats/sahilp-plugins", + size=(335, 50), + position=(21, 22), + h_align='left', + v_align='center', + editable=True, + scale=0.75, + maxwidth=215, + # autoselect=True, + description="Add Source") loop = asyncio.get_event_loop() - ba.buttonwidget(parent=self._root_widget, - position=(330, 28), - size=(37, 37), - on_activate_call=lambda: loop.create_task(self.add_source()), - label="", - texture=ba.gettexture("startButton"), - # texture=ba.gettexture("chestOpenIcon"), - button_type="square", - color=(0, 0.9, 0), - textcolor=b_textcolor, - # autoselect=True, - text_scale=1) + bui.buttonwidget(parent=self._root_widget, + position=(330, 28), + size=(37, 37), + on_activate_call=lambda: loop.create_task(self.add_source()), + label="", + texture=bui.gettexture("startButton"), + # texture=bui.gettexture("chestOpenIcon"), + button_type="square", + color=(0, 0.9, 0), + textcolor=b_textcolor, + # autoselect=True, + text_scale=1) self.draw_sources() @@ -1352,25 +1357,25 @@ def draw_sources(self): plugin.delete() color = (1, 1, 1) - for custom_source in ba.app.config["Community Plugin Manager"]["Custom Sources"]: - ba.textwidget(parent=self._columnwidget, - # size=(410, 30), - selectable=True, - # always_highlight=True, - color=color, - text=custom_source, - # click_activate=True, - on_select_call=lambda: self.select_source(custom_source), - h_align='left', - v_align='center', - scale=0.75, - maxwidth=260) + for custom_source in babase.app.config["Community Plugin Manager"]["Custom Sources"]: + bui.textwidget(parent=self._columnwidget, + # size=(410, 30), + selectable=True, + # always_highlight=True, + color=color, + text=custom_source, + # click_activate=True, + on_select_call=lambda: self.select_source(custom_source), + h_align='left', + v_align='center', + scale=0.75, + maxwidth=260) def select_source(self, source): self.selected_source = source async def add_source(self): - source = ba.textwidget(query=self._add_source_widget) + source = bui.textwidget(query=self._add_source_widget) meta_url = _CACHE["index"]["external_source_url"].format( repository=source, content_type="raw", @@ -1378,33 +1383,33 @@ async def add_source(self): ) category = Category(meta_url, is_3rd_party=True) if not await category.is_valid(): - ba.screenmessage("Enter a valid plugin source", color=(1, 0, 0)) - ba.playsound(ba.getsound('error')) + bui.screenmessage("Enter a valid plugin source", color=(1, 0, 0)) + bui.getsound('error').play() return - if source in ba.app.config["Community Plugin Manager"]["Custom Sources"]: - ba.screenmessage("Plugin source already exists") - ba.playsound(ba.getsound('error')) + if source in babase.app.config["Community Plugin Manager"]["Custom Sources"]: + bui.screenmessage("Plugin source already exists") + bui.getsound('error').play() return - ba.app.config["Community Plugin Manager"]["Custom Sources"].append(source) - ba.app.config.commit() - ba.screenmessage("Plugin source added; Refresh plugin list to see changes", - color=(0, 1, 0)) - ba.playsound(ba.getsound('cashRegister2')) + babase.app.config["Community Plugin Manager"]["Custom Sources"].append(source) + babase.app.config.commit() + bui.screenmessage("Plugin source added; Refresh plugin list to see changes", + color=(0, 1, 0)) + bui.getsound('cashRegister2').play() self.draw_sources() def delete_selected_source(self): if self.selected_source is None: return - ba.app.config["Community Plugin Manager"]["Custom Sources"].remove(self.selected_source) - ba.app.config.commit() - ba.screenmessage("Plugin source deleted; Refresh plugin list to see changes", - color=(0.9, 1, 0)) - ba.playsound(ba.getsound('shieldDown')) + babase.app.config["Community Plugin Manager"]["Custom Sources"].remove(self.selected_source) + babase.app.config.commit() + bui.screenmessage("Plugin source deleted; Refresh plugin list to see changes", + color=(0.9, 1, 0)) + bui.getsound('shieldDown').play() self.draw_sources() def _ok(self) -> None: - ba.playsound(ba.getsound('swish')) - ba.containerwidget(edit=self._root_widget, transition='out_scale') + bui.getsound('swish').play() + bui.containerwidget(edit=self._root_widget, transition='out_scale') class PluginCategoryWindow(popup.PopupMenuWindow): @@ -1414,17 +1419,17 @@ def __init__(self, choices, current_choice, origin_widget, asyncio_callback): self.scale_origin = origin_widget.get_screen_space_center() super().__init__( position=(200, 0), - scale=(2.3 if _uiscale is ba.UIScale.SMALL else - 1.65 if _uiscale is ba.UIScale.MEDIUM else 1.23), + scale=(2.3 if _uiscale is babase.UIScale.SMALL else + 1.65 if _uiscale is babase.UIScale.MEDIUM else 1.23), choices=choices, current_choice=current_choice, delegate=self) self._update_custom_sources_widget() def _update_custom_sources_widget(self): - ba.textwidget(edit=self._columnwidget.get_children()[-1], - color=(0.5, 0.5, 0.5), - on_activate_call=self.show_sources_window) + bui.textwidget(edit=self._columnwidget.get_children()[-1], + color=(0.5, 0.5, 0.5), + on_activate_call=self.show_sources_window) def popup_menu_selected_choice(self, window, choice): loop = asyncio.get_event_loop() @@ -1438,12 +1443,12 @@ def show_sources_window(self): PluginSourcesWindow(origin_widget=self.root_widget) def _ok(self) -> None: - ba.playsound(ba.getsound('swish')) - ba.containerwidget(edit=self.root_widget, transition='out_scale') + bui.getsound('swish').play() + bui.containerwidget(edit=self.root_widget, transition='out_scale') -class PluginManagerWindow(ba.Window): - def __init__(self, transition: str = "in_right", origin_widget: ba.Widget = None): +class PluginManagerWindow(bui.Window): + def __init__(self, transition: str = "in_right", origin_widget: bui.Widget = None): self.plugin_manager = PluginManager() self.category_selection_button = None self.selected_category = None @@ -1452,69 +1457,69 @@ def __init__(self, transition: str = "in_right", origin_widget: ba.Widget = None loop = asyncio.get_event_loop() loop.create_task(self.draw_index()) - self._width = (700 if _uiscale is ba.UIScale.SMALL - else 550 if _uiscale is ba.UIScale.MEDIUM + self._width = (700 if _uiscale is babase.UIScale.SMALL + else 550 if _uiscale is babase.UIScale.MEDIUM else 570) - self._height = (500 if _uiscale is ba.UIScale.SMALL - else 422 if _uiscale is ba.UIScale.MEDIUM + self._height = (500 if _uiscale is babase.UIScale.SMALL + else 422 if _uiscale is babase.UIScale.MEDIUM else 500) - top_extra = 20 if _uiscale is ba.UIScale.SMALL else 0 + top_extra = 20 if _uiscale is babase.UIScale.SMALL else 0 if origin_widget: self._transition_out = "out_scale" self._scale_origin = origin_widget.get_screen_space_center() transition = "in_scale" - super().__init__(root_widget=ba.containerwidget( + super().__init__(root_widget=bui.containerwidget( size=(self._width, self._height + top_extra), transition=transition, toolbar_visibility="menu_minimal", scale_origin_stack_offset=self._scale_origin, - scale=(1.9 if _uiscale is ba.UIScale.SMALL - else 1.5 if _uiscale is ba.UIScale.MEDIUM + scale=(1.9 if _uiscale is babase.UIScale.SMALL + else 1.5 if _uiscale is babase.UIScale.MEDIUM else 1.0), - stack_offset=(0, -25) if _uiscale is ba.UIScale.SMALL else (0, 0) + stack_offset=(0, -25) if _uiscale is babase.UIScale.SMALL else (0, 0) )) - back_pos_x = 5 + (37 if _uiscale is ba.UIScale.SMALL else - 27 if _uiscale is ba.UIScale.MEDIUM else 68) - back_pos_y = self._height - (95 if _uiscale is ba.UIScale.SMALL else - 65 if _uiscale is ba.UIScale.MEDIUM else 50) - self._back_button = back_button = ba.buttonwidget( + back_pos_x = 5 + (37 if _uiscale is babase.UIScale.SMALL else + 27 if _uiscale is babase.UIScale.MEDIUM else 68) + back_pos_y = self._height - (95 if _uiscale is babase.UIScale.SMALL else + 65 if _uiscale is babase.UIScale.MEDIUM else 50) + self._back_button = back_button = bui.buttonwidget( parent=self._root_widget, position=(back_pos_x, back_pos_y), size=(60, 60), scale=0.8, - label=ba.charstr(ba.SpecialChar.BACK), + label=babase.charstr(babase.SpecialChar.BACK), # autoselect=True, button_type='backSmall', on_activate_call=self._back) - ba.containerwidget(edit=self._root_widget, cancel_button=back_button) + bui.containerwidget(edit=self._root_widget, cancel_button=back_button) - title_pos = self._height - (83 if _uiscale is ba.UIScale.SMALL else - 50 if _uiscale is ba.UIScale.MEDIUM else 50) - ba.textwidget( + title_pos = self._height - (83 if _uiscale is babase.UIScale.SMALL else + 50 if _uiscale is babase.UIScale.MEDIUM else 50) + bui.textwidget( parent=self._root_widget, position=(-10, title_pos), size=(self._width, 25), text="Community Plugin Manager", - color=ba.app.ui.title_color, + color=bui.app.classic.ui.title_color, scale=1.05, h_align="center", v_align="center", maxwidth=270, ) - loading_pos_y = self._height - (275 if _uiscale is ba.UIScale.SMALL else - 235 if _uiscale is ba.UIScale.MEDIUM else 270) + loading_pos_y = self._height - (275 if _uiscale is babase.UIScale.SMALL else + 235 if _uiscale is babase.UIScale.MEDIUM else 270) - self._plugin_manager_status_text = ba.textwidget( + self._plugin_manager_status_text = bui.textwidget( parent=self._root_widget, position=(-5, loading_pos_y), size=(self._width, 25), text="Loading...", - color=ba.app.ui.title_color, + color=bui.app.classic.ui.title_color, scale=0.7, h_align="center", v_align="center", @@ -1523,9 +1528,9 @@ def __init__(self, transition: str = "in_right", origin_widget: ba.Widget = None def _back(self) -> None: from bastd.ui.settings.allsettings import AllSettingsWindow - ba.containerwidget(edit=self._root_widget, - transition=self._transition_out) - ba.app.ui.set_main_menu_window( + bui.containerwidget(edit=self._root_widget, + transition=self._transition_out) + bui.app.classic.ui.set_main_menu_window( AllSettingsWindow(transition='in_left').get_root_widget()) @contextlib.contextmanager @@ -1533,10 +1538,10 @@ def exception_handler(self): try: yield except urllib.error.URLError: - ba.textwidget(edit=self._plugin_manager_status_text, - text="Make sure you are connected\n to the Internet and try again.") + bui.textwidget(edit=self._plugin_manager_status_text, + text="Make sure you are connected\n to the Internet and try again.") except RuntimeError: - # User probably went back before a ba.Window could finish loading. + # User probably went back before a bui.Window could finish loading. pass except Exception as e: ba.textwidget(edit=self._plugin_manager_status_text, @@ -1551,31 +1556,31 @@ async def draw_index(self): self.draw_settings_icon() with self.exception_handler(): await self.plugin_manager.setup_index() - ba.textwidget(edit=self._plugin_manager_status_text, - text="") + bui.textwidget(edit=self._plugin_manager_status_text, + text="") await self.select_category("All") def draw_plugins_scroll_bar(self): - scroll_size_x = (515 if _uiscale is ba.UIScale.SMALL else - 430 if _uiscale is ba.UIScale.MEDIUM else 420) - scroll_size_y = (245 if _uiscale is ba.UIScale.SMALL else - 265 if _uiscale is ba.UIScale.MEDIUM else 335) - scroll_pos_x = (70 if _uiscale is ba.UIScale.SMALL else - 50 if _uiscale is ba.UIScale.MEDIUM else 70) - scroll_pos_y = (100 if _uiscale is ba.UIScale.SMALL else - 35 if _uiscale is ba.UIScale.MEDIUM else 40) - self._scrollwidget = ba.scrollwidget(parent=self._root_widget, - size=(scroll_size_x, scroll_size_y), - position=(scroll_pos_x, scroll_pos_y)) - self._columnwidget = ba.columnwidget(parent=self._scrollwidget, - border=2, - margin=0) + scroll_size_x = (515 if _uiscale is babase.UIScale.SMALL else + 430 if _uiscale is babase.UIScale.MEDIUM else 420) + scroll_size_y = (245 if _uiscale is babase.UIScale.SMALL else + 265 if _uiscale is babase.UIScale.MEDIUM else 335) + scroll_pos_x = (70 if _uiscale is babase.UIScale.SMALL else + 50 if _uiscale is babase.UIScale.MEDIUM else 70) + scroll_pos_y = (100 if _uiscale is babase.UIScale.SMALL else + 35 if _uiscale is babase.UIScale.MEDIUM else 40) + self._scrollwidget = bui.scrollwidget(parent=self._root_widget, + size=(scroll_size_x, scroll_size_y), + position=(scroll_pos_x, scroll_pos_y)) + self._columnwidget = bui.columnwidget(parent=self._scrollwidget, + border=2, + margin=0) def draw_category_selection_button(self, post_label): - category_pos_x = (440 if _uiscale is ba.UIScale.SMALL else - 340 if _uiscale is ba.UIScale.MEDIUM else 350) - category_pos_y = self._height - (141 if _uiscale is ba.UIScale.SMALL else - 110 if _uiscale is ba.UIScale.MEDIUM else 110) + category_pos_x = (440 if _uiscale is babase.UIScale.SMALL else + 340 if _uiscale is babase.UIScale.MEDIUM else 350) + category_pos_y = self._height - (141 if _uiscale is babase.UIScale.SMALL else + 110 if _uiscale is babase.UIScale.MEDIUM else 110) b_size = (140, 30) # b_textcolor = (0.75, 0.7, 0.8) b_textcolor = (0.8, 0.8, 0.85) @@ -1584,64 +1589,64 @@ def draw_category_selection_button(self, post_label): label = f"Category: {post_label}" if self.category_selection_button is None: - self.category_selection_button = ba.buttonwidget(parent=self._root_widget, - position=(category_pos_x, - category_pos_y), - size=b_size, - on_activate_call=( - self.show_categories_window), - label=label, - button_type="square", - # color=b_color, - textcolor=b_textcolor, - # autoselect=True, - text_scale=0.6) + self.category_selection_button = bui.buttonwidget(parent=self._root_widget, + position=(category_pos_x, + category_pos_y), + size=b_size, + on_activate_call=( + self.show_categories_window), + label=label, + button_type="square", + # color=b_color, + textcolor=b_textcolor, + # autoselect=True, + text_scale=0.6) else: - self.category_selection_button = ba.buttonwidget(edit=self.category_selection_button, - label=label) + self.category_selection_button = bui.buttonwidget(edit=self.category_selection_button, + label=label) def draw_search_bar(self): - search_bar_pos_x = (85 if _uiscale is ba.UIScale.SMALL else - 68 if _uiscale is ba.UIScale.MEDIUM else 90) + search_bar_pos_x = (85 if _uiscale is babase.UIScale.SMALL else + 68 if _uiscale is babase.UIScale.MEDIUM else 90) search_bar_pos_y = self._height - ( - 145 if _uiscale is ba.UIScale.SMALL else - 110 if _uiscale is ba.UIScale.MEDIUM else 116) + 145 if _uiscale is babase.UIScale.SMALL else + 110 if _uiscale is babase.UIScale.MEDIUM else 116) - search_bar_size_x = (320 if _uiscale is ba.UIScale.SMALL else - 230 if _uiscale is ba.UIScale.MEDIUM else 260) + search_bar_size_x = (320 if _uiscale is babase.UIScale.SMALL else + 230 if _uiscale is babase.UIScale.MEDIUM else 260) search_bar_size_y = ( - 35 if _uiscale is ba.UIScale.SMALL else - 35 if _uiscale is ba.UIScale.MEDIUM else 45) - - filter_txt_pos_x = (60 if _uiscale is ba.UIScale.SMALL else - 40 if _uiscale is ba.UIScale.MEDIUM else 60) - filter_txt_pos_y = search_bar_pos_y + (3 if _uiscale is ba.UIScale.SMALL else - 4 if _uiscale is ba.UIScale.MEDIUM else 8) - - ba.textwidget(parent=self._root_widget, - text="Filter", - position=(filter_txt_pos_x, filter_txt_pos_y), - selectable=False, - h_align='left', - v_align='center', - color=ba.app.ui.title_color, - scale=0.5) - - filter_txt = ba.Lstr(resource='filterText') - search_bar_maxwidth = search_bar_size_x - (95 if _uiscale is ba.UIScale.SMALL else - 77 if _uiscale is ba.UIScale.MEDIUM else + 35 if _uiscale is babase.UIScale.SMALL else + 35 if _uiscale is babase.UIScale.MEDIUM else 45) + + filter_txt_pos_x = (60 if _uiscale is babase.UIScale.SMALL else + 40 if _uiscale is babase.UIScale.MEDIUM else 60) + filter_txt_pos_y = search_bar_pos_y + (3 if _uiscale is babase.UIScale.SMALL else + 4 if _uiscale is babase.UIScale.MEDIUM else 8) + + bui.textwidget(parent=self._root_widget, + text="Filter", + position=(filter_txt_pos_x, filter_txt_pos_y), + selectable=False, + h_align='left', + v_align='center', + color=bui.app.classic.ui.title_color, + scale=0.5) + + filter_txt = babase.Lstr(resource='filterText') + search_bar_maxwidth = search_bar_size_x - (95 if _uiscale is babase.UIScale.SMALL else + 77 if _uiscale is babase.UIScale.MEDIUM else 85) - self._filter_widget = ba.textwidget(parent=self._root_widget, - text="", - size=(search_bar_size_x, search_bar_size_y), - position=(search_bar_pos_x, search_bar_pos_y), - h_align='left', - v_align='center', - editable=True, - scale=0.8, - autoselect=True, - maxwidth=search_bar_maxwidth, - description=filter_txt) + self._filter_widget = bui.textwidget(parent=self._root_widget, + text="", + size=(search_bar_size_x, search_bar_size_y), + position=(search_bar_pos_x, search_bar_pos_y), + h_align='left', + v_align='center', + editable=True, + scale=0.8, + autoselect=True, + maxwidth=search_bar_maxwidth, + description=filter_txt) self._last_filter_text = None self._last_filter_plugins = [] loop = asyncio.get_event_loop() @@ -1651,7 +1656,7 @@ async def process_search_term(self): while True: await asyncio.sleep(0.2) try: - filter_text = ba.textwidget(query=self._filter_widget) + filter_text = bui.textwidget(query=self._filter_widget) except RuntimeError: # Search filter widget got destroyed. No point checking for filter text anymore. return @@ -1665,59 +1670,59 @@ async def process_search_term(self): # attributes like color, position and more. # for plugin in self._columnwidget.get_children(): # for name, widget in tuple(self.plugins_in_current_view.items()): - # # print(ba.textwidget(query=plugin)) + # # print(bui.textwidget(query=plugin)) # # plugin.delete() # print(dir(widget)) # if filter_text in name: # import random # if random.random() > 0.9: - # ba.textwidget(edit=widget).delete() + # bui.textwidget(edit=widget).delete() # else: - # ba.textwidget(edit=widget, position=None) + # bui.textwidget(edit=widget, position=None) # else: - # ba.textwidget(edit=widget, position=None) + # bui.textwidget(edit=widget, position=None) def draw_settings_icon(self): - settings_pos_x = (610 if _uiscale is ba.UIScale.SMALL else - 500 if _uiscale is ba.UIScale.MEDIUM else 510) - settings_pos_y = (130 if _uiscale is ba.UIScale.SMALL else - 60 if _uiscale is ba.UIScale.MEDIUM else 70) - controller_button = ba.buttonwidget(parent=self._root_widget, - # autoselect=True, - position=(settings_pos_x, settings_pos_y), - size=(30, 30), - button_type="square", - label="", - on_activate_call=ba.Call(PluginManagerSettingsWindow, - self.plugin_manager, - self._root_widget)) - ba.imagewidget(parent=self._root_widget, - position=(settings_pos_x, settings_pos_y), - size=(30, 30), - color=(0.8, 0.95, 1), - texture=ba.gettexture("settingsIcon"), - draw_controller=controller_button) + settings_pos_x = (610 if _uiscale is babase.UIScale.SMALL else + 500 if _uiscale is babase.UIScale.MEDIUM else 510) + settings_pos_y = (130 if _uiscale is babase.UIScale.SMALL else + 60 if _uiscale is babase.UIScale.MEDIUM else 70) + controller_button = bui.buttonwidget(parent=self._root_widget, + # autoselect=True, + position=(settings_pos_x, settings_pos_y), + size=(30, 30), + button_type="square", + label="", + on_activate_call=babase.Call(PluginManagerSettingsWindow, + self.plugin_manager, + self._root_widget)) + bui.imagewidget(parent=self._root_widget, + position=(settings_pos_x, settings_pos_y), + size=(30, 30), + color=(0.8, 0.95, 1), + texture=bui.gettexture("settingsIcon"), + draw_controller=controller_button) def draw_refresh_icon(self): - refresh_pos_x = (610 if _uiscale is ba.UIScale.SMALL else - 500 if _uiscale is ba.UIScale.MEDIUM else 510) - refresh_pos_y = (180 if _uiscale is ba.UIScale.SMALL else - 108 if _uiscale is ba.UIScale.MEDIUM else 120) + refresh_pos_x = (610 if _uiscale is babase.UIScale.SMALL else + 500 if _uiscale is babase.UIScale.MEDIUM else 510) + refresh_pos_y = (180 if _uiscale is babase.UIScale.SMALL else + 108 if _uiscale is babase.UIScale.MEDIUM else 120) loop = asyncio.get_event_loop() - controller_button = ba.buttonwidget(parent=self._root_widget, - # autoselect=True, - position=(refresh_pos_x, refresh_pos_y), - size=(30, 30), - button_type="square", - label="", - on_activate_call=lambda: - loop.create_task(self.refresh())) - ba.imagewidget(parent=self._root_widget, - position=(refresh_pos_x, refresh_pos_y), - size=(30, 30), - color=(0.8, 0.95, 1), - texture=ba.gettexture("replayIcon"), - draw_controller=controller_button) + controller_button = bui.buttonwidget(parent=self._root_widget, + # autoselect=True, + position=(refresh_pos_x, refresh_pos_y), + size=(30, 30), + button_type="square", + label="", + on_activate_call=lambda: + loop.create_task(self.refresh())) + bui.imagewidget(parent=self._root_widget, + position=(refresh_pos_x, refresh_pos_y), + size=(30, 30), + color=(0.8, 0.95, 1), + texture=bui.gettexture("replayIcon"), + draw_controller=controller_button) def search_term_filterer(self, plugin, search_term): # This helps resolve "plugin name" to "plugin_name". @@ -1795,21 +1800,21 @@ async def draw_plugin_name(self, plugin): plugin_name_widget_to_update = self.plugins_in_current_view.get(plugin.name) if plugin_name_widget_to_update: - ba.textwidget(edit=plugin_name_widget_to_update, - color=color) + bui.textwidget(edit=plugin_name_widget_to_update, + color=color) else: - text_widget = ba.textwidget(parent=self._columnwidget, - size=(410, 30), - selectable=True, - always_highlight=True, - color=color, - # on_select_call=lambda: None, - text=plugin.name, - click_activate=True, - on_activate_call=lambda: self.show_plugin_window(plugin), - h_align='left', - v_align='center', - maxwidth=420) + text_widget = bui.textwidget(parent=self._columnwidget, + size=(410, 30), + selectable=True, + always_highlight=True, + color=color, + # on_select_call=lambda: None, + text=plugin.name, + click_activate=True, + on_activate_call=lambda: self.show_plugin_window(plugin), + h_align='left', + v_align='center', + maxwidth=420) self.plugins_in_current_view[plugin.name] = text_widget # XXX: This seems nicer. Might wanna use this in future. # text_widget.add_delete_callback(lambda: self.plugins_in_current_view.pop(plugin.name)) @@ -1841,14 +1846,14 @@ def cleanup(self): async def refresh(self): self.cleanup() - ba.textwidget(edit=self._plugin_manager_status_text, - text="Refreshing...") + bui.textwidget(edit=self._plugin_manager_status_text, + text="Refreshing...") with self.exception_handler(): await self.plugin_manager.refresh() await self.plugin_manager.setup_index() - ba.textwidget(edit=self._plugin_manager_status_text, - text="") + bui.textwidget(edit=self._plugin_manager_status_text, + text="") await self.select_category(self.selected_category) def soft_refresh(self): @@ -1859,13 +1864,13 @@ class PluginManagerSettingsWindow(popup.PopupWindow): def __init__(self, plugin_manager, origin_widget): self._plugin_manager = plugin_manager self.scale_origin = origin_widget.get_screen_space_center() - self.settings = ba.app.config["Community Plugin Manager"]["Settings"].copy() + self.settings = babase.app.config["Community Plugin Manager"]["Settings"].copy() loop = asyncio.get_event_loop() loop.create_task(self.draw_ui()) async def draw_ui(self): b_text_color = (0.8, 0.8, 0.85) - s = 1.25 if _uiscale is ba.UIScale.SMALL else 1.27 if _uiscale is ba.UIScale.MEDIUM else 1.3 + s = 1.25 if _uiscale is babase.UIScale.SMALL else 1.27 if _uiscale is babase.UIScale.MEDIUM else 1.3 width = 380 * s height = 150 + 150 * s color = (0.9, 0.9, 0.9) @@ -1880,99 +1885,99 @@ async def draw_ui(self): transition = 'in_scale' button_size = (32 * s, 32 * s) # index = await self._plugin_manager.get_index() - self._root_widget = ba.containerwidget(size=(width, height), - # parent=_ba.get_special_widget( - # 'overlay_stack'), - on_outside_click_call=self._ok, - transition=transition, - scale=(2.1 if _uiscale is ba.UIScale.SMALL else 1.5 - if _uiscale is ba.UIScale.MEDIUM else 1.0), - scale_origin_stack_offset=self.scale_origin) + self._root_widget = bui.containerwidget(size=(width, height), + # parent=_babase.get_special_widget( + # 'overlay_stack'), + on_outside_click_call=self._ok, + transition=transition, + scale=(2.1 if _uiscale is babase.UIScale.SMALL else 1.5 + if _uiscale is babase.UIScale.MEDIUM else 1.0), + scale_origin_stack_offset=self.scale_origin) pos = height * 0.9 setting_title = "Settings" - ba.textwidget(parent=self._root_widget, - position=(width * 0.49, pos), - size=(0, 0), - h_align='center', - v_align='center', - text=setting_title, - scale=text_scale, - color=ba.app.ui.title_color, - maxwidth=width * 0.9) + bui.textwidget(parent=self._root_widget, + position=(width * 0.49, pos), + size=(0, 0), + h_align='center', + v_align='center', + text=setting_title, + scale=text_scale, + color=bui.app.classic.ui.title_color, + maxwidth=width * 0.9) pos -= 20 - self._save_button = ba.buttonwidget(parent=self._root_widget, - position=((width * 0.82) - button_size[0] / 2, pos), - size=(73, 35), - on_activate_call=self.save_settings_button, - textcolor=b_text_color, - button_type='square', - text_scale=1, - scale=0, - selectable=False, - label="Save") + self._save_button = bui.buttonwidget(parent=self._root_widget, + position=((width * 0.82) - button_size[0] / 2, pos), + size=(73, 35), + on_activate_call=self.save_settings_button, + textcolor=b_text_color, + button_type='square', + text_scale=1, + scale=0, + selectable=False, + label="Save") pos -= 40 for setting, value in self.settings.items(): - ba.checkboxwidget(parent=self._root_widget, - position=(width * 0.1, pos), - size=(170, 30), - text=setting, - value=value, - on_value_change_call=ba.Call(self.toggle_setting, setting), - maxwidth=500, - textcolor=(0.9, 0.9, 0.9), - scale=text_scale * 0.8) + bui.checkboxwidget(parent=self._root_widget, + position=(width * 0.1, pos), + size=(170, 30), + text=setting, + value=value, + on_value_change_call=babase.Call(self.toggle_setting, setting), + maxwidth=500, + textcolor=(0.9, 0.9, 0.9), + scale=text_scale * 0.8) pos -= 34 * text_scale pos = height - 200 - ba.textwidget(parent=self._root_widget, - position=(width * 0.49, pos-5), - size=(0, 0), - h_align='center', - v_align='center', - text='Contribute to plugins or to this community plugin manager!', - scale=text_scale * 0.65, - color=color, - maxwidth=width * 0.95) + bui.textwidget(parent=self._root_widget, + position=(width * 0.49, pos-5), + size=(0, 0), + h_align='center', + v_align='center', + text='Contribute to plugins or to this community plugin manager!', + scale=text_scale * 0.65, + color=color, + maxwidth=width * 0.95) pos -= 75 - self.discord_button = ba.buttonwidget(parent=self._root_widget, - position=((width * 0.20) - button_size[0] / 2, pos), + self.discord_button = bui.buttonwidget(parent=self._root_widget, + position=((width * 0.20) - button_size[0] / 2, pos), + size=button_size, + on_activate_call=lambda: bui.open_url(DISCORD_URL), + textcolor=b_text_color, + color=discord_bg_color, + button_type='square', + text_scale=1, + label="") + + bui.imagewidget(parent=self._root_widget, + position=((width * 0.20)+0.5 - button_size[0] / 2, pos), + size=button_size, + texture=bui.gettexture("discordLogo"), + color=discord_fg_color, + draw_controller=self.discord_button) + + self.github_button = bui.buttonwidget(parent=self._root_widget, + position=((width * 0.49) - button_size[0] / 2, pos), size=button_size, - on_activate_call=lambda: ba.open_url(DISCORD_URL), + on_activate_call=lambda: bui.open_url(REPOSITORY_URL), textcolor=b_text_color, - color=discord_bg_color, + color=github_bg_color, button_type='square', text_scale=1, - label="") - - ba.imagewidget(parent=self._root_widget, - position=((width * 0.20)+0.5 - button_size[0] / 2, pos), - size=button_size, - texture=ba.gettexture("discordLogo"), - color=discord_fg_color, - draw_controller=self.discord_button) - - self.github_button = ba.buttonwidget(parent=self._root_widget, - position=((width * 0.49) - button_size[0] / 2, pos), - size=button_size, - on_activate_call=lambda: ba.open_url(REPOSITORY_URL), - textcolor=b_text_color, - color=github_bg_color, - button_type='square', - text_scale=1, - label='') + label='') - ba.imagewidget(parent=self._root_widget, - position=((width * 0.49) + 0.5 - button_size[0] / 2, pos), - size=button_size, - texture=ba.gettexture("githubLogo"), - color=(1, 1, 1), - draw_controller=self.github_button) + bui.imagewidget(parent=self._root_widget, + position=((width * 0.49) + 0.5 - button_size[0] / 2, pos), + size=button_size, + texture=bui.gettexture("githubLogo"), + color=(1, 1, 1), + draw_controller=self.github_button) - ba.containerwidget(edit=self._root_widget, - on_cancel_call=self._ok) + bui.containerwidget(edit=self._root_widget, + on_cancel_call=self._ok) try: plugin_manager_update_available = await self._plugin_manager.get_update_details() @@ -1983,269 +1988,311 @@ async def draw_ui(self): loop = asyncio.get_event_loop() button_size = (95 * s, 32 * s) update_button_label = f'Update to v{plugin_manager_update_available[0]}' - self._update_button = ba.buttonwidget(parent=self._root_widget, - position=((width * 0.77) - button_size[0] / 2, - pos), - size=button_size, - on_activate_call=lambda: - loop.create_task( - self.update( - *plugin_manager_update_available - ) - ), - textcolor=b_text_color, - button_type='square', - text_scale=1, - color=(0, 0.7, 0), - label=update_button_label) - self._restart_to_reload_changes_text = ba.textwidget(parent=self._root_widget, - position=(width * 0.79, pos + 20), - size=(0, 0), - h_align='center', - v_align='center', - text='', - scale=text_scale * 0.65, - color=(0, 0.8, 0), - maxwidth=width * 0.9) + self._update_button = bui.buttonwidget(parent=self._root_widget, + position=((width * 0.77) - button_size[0] / 2, + pos), + size=button_size, + on_activate_call=lambda: + loop.create_task( + self.update( + *plugin_manager_update_available + ) + ), + textcolor=b_text_color, + button_type='square', + text_scale=1, + color=(0, 0.7, 0), + label=update_button_label) + self._restart_to_reload_changes_text = bui.textwidget(parent=self._root_widget, + position=(width * 0.79, pos + 20), + size=(0, 0), + h_align='center', + v_align='center', + text='', + scale=text_scale * 0.65, + color=(0, 0.8, 0), + maxwidth=width * 0.9) else: text_color = (0, 0.8, 0) pos -= 25 - ba.textwidget(parent=self._root_widget, - position=(width * 0.49, pos), - size=(0, 0), - h_align='center', - v_align='center', - text=f'Plugin Manager v{PLUGIN_MANAGER_VERSION}', - scale=text_scale * 0.8, - color=text_color, - maxwidth=width * 0.9) + bui.textwidget(parent=self._root_widget, + position=(width * 0.49, pos), + size=(0, 0), + h_align='center', + v_align='center', + text=f'Plugin Manager v{PLUGIN_MANAGER_VERSION}', + scale=text_scale * 0.8, + color=text_color, + maxwidth=width * 0.9) pos -= 25 - ba.textwidget(parent=self._root_widget, - position=(width * 0.49, pos), - size=(0, 0), - h_align='center', - v_align='center', - text=f'API Version: {ba.app.api_version}', - scale=text_scale * 0.7, - color=(0.4, 0.8, 1), - maxwidth=width * 0.95) + bui.textwidget(parent=self._root_widget, + position=(width * 0.49, pos), + size=(0, 0), + h_align='center', + v_align='center', + text=f'API Version: {babase.app.api_version}', + scale=text_scale * 0.7, + color=(0.4, 0.8, 1), + maxwidth=width * 0.95) pos = height * 0.1 def toggle_setting(self, setting, set_value): self.settings[setting] = set_value - if self.settings == ba.app.config["Community Plugin Manager"]["Settings"]: - ba.buttonwidget(edit=self._save_button, - scale=0, - selectable=False) + if self.settings == babase.app.config["Community Plugin Manager"]["Settings"]: + bui.buttonwidget(edit=self._save_button, + scale=0, + selectable=False) else: - ba.buttonwidget(edit=self._save_button, - scale=1, - selectable=True) + bui.buttonwidget(edit=self._save_button, + scale=1, + selectable=True) def save_settings_button(self): - ba.app.config["Community Plugin Manager"]["Settings"] = self.settings.copy() - ba.app.config.commit() + babase.app.config["Community Plugin Manager"]["Settings"] = self.settings.copy() + babase.app.config.commit() self._ok() - ba.playsound(ba.getsound('gunCocking')) + bui.getsound('gunCocking').play() async def update(self, to_version=None, commit_sha=None): try: await self._plugin_manager.update(to_version, commit_sha) except MD5CheckSumFailedError: - ba.screenmessage("MD5 checksum failed during plugin manager update", color=(1, 0, 0)) - ba.playsound(ba.getsound('error')) + bui.screenmessage("MD5 checksum failed during plugin manager update", color=(1, 0, 0)) + bui.getsound('error').play() else: - ba.screenmessage("Plugin manager update successful", color=(0, 1, 0)) - ba.playsound(ba.getsound('shieldUp')) - ba.textwidget(edit=self._restart_to_reload_changes_text, - text='Update Applied!\nRestart game to reload changes.') + bui.screenmessage("Plugin manager update successful", color=(0, 1, 0)) + bui.getsound('shieldUp').play() + bui.textwidget(edit=self._restart_to_reload_changes_text, + text='Update Applied!\nRestart game to reload changes.') self._update_button.delete() def _ok(self) -> None: - ba.playsound(ba.getsound('swish')) - ba.containerwidget(edit=self._root_widget, transition='out_scale') + bui.getsound('swish').play() + bui.containerwidget(edit=self._root_widget, transition='out_scale') -class NewAllSettingsWindow(ba.Window): - def __init__(self, - transition: str = "in_right", - origin_widget: ba.Widget = None): +class NewAllSettingsWindow(bui.Window): + """Window for selecting a settings category.""" + + def __init__( + self, + transition: str = 'in_right', + origin_widget: bui.Widget | None = None, + ): # pylint: disable=too-many-statements # pylint: disable=too-many-locals - import threading - # Preload some modules we use in a background thread so we won"t + # Preload some modules we use in a background thread so we won't # have a visual hitch when the user taps them. - threading.Thread(target=self._preload_modules).start() + Thread(target=self._preload_modules).start() - ba.set_analytics_screen("Settings Window") - scale_origin: Optional[tuple[float, float]] + bui.set_analytics_screen('Settings Window') + scale_origin: tuple[float, float] | None if origin_widget is not None: - self._transition_out = "out_scale" + self._transition_out = 'out_scale' scale_origin = origin_widget.get_screen_space_center() - transition = "in_scale" + transition = 'in_scale' else: - self._transition_out = "out_right" + self._transition_out = 'out_right' scale_origin = None - width = 900 if _uiscale is ba.UIScale.SMALL else 670 - x_inset = 75 if _uiscale is ba.UIScale.SMALL else 0 + assert bui.app.classic is not None + width = 900 if _uiscale is bui.UIScale.SMALL else 670 + x_inset = 75 if _uiscale is bui.UIScale.SMALL else 0 height = 435 - self._r = "settingsWindow" - top_extra = 20 if _uiscale is ba.UIScale.SMALL else 0 + self._r = 'settingsWindow' + top_extra = 20 if _uiscale is bui.UIScale.SMALL else 0 - super().__init__(root_widget=ba.containerwidget( - size=(width, height + top_extra), - transition=transition, - toolbar_visibility="menu_minimal", - scale_origin_stack_offset=scale_origin, - scale=(1.75 if _uiscale is ba.UIScale.SMALL else - 1.35 if _uiscale is ba.UIScale.MEDIUM else 1.0), - stack_offset=(0, -8) if _uiscale is ba.UIScale.SMALL else (0, 0))) + super().__init__( + root_widget=bui.containerwidget( + size=(width, height + top_extra), + transition=transition, + toolbar_visibility='menu_minimal', + scale_origin_stack_offset=scale_origin, + scale=( + 1.75 + if _uiscale is bui.UIScale.SMALL + else 1.35 + if _uiscale is bui.UIScale.MEDIUM + else 1.0 + ), + stack_offset=(0, -8) + if _uiscale is bui.UIScale.SMALL + else (0, 0), + ) + ) - if ba.app.ui.use_toolbars and _uiscale is ba.UIScale.SMALL: + if bui.app.classic.ui.use_toolbars and _uiscale is bui.UIScale.SMALL: self._back_button = None - ba.containerwidget(edit=self._root_widget, - on_cancel_call=self._do_back) + bui.containerwidget( + edit=self._root_widget, on_cancel_call=self._do_back + ) else: - self._back_button = btn = ba.buttonwidget( + self._back_button = btn = bui.buttonwidget( parent=self._root_widget, autoselect=True, position=(40 + x_inset, height - 55), size=(130, 60), scale=0.8, text_scale=1.2, - label=ba.Lstr(resource="backText"), - button_type="back", - on_activate_call=self._do_back) - ba.containerwidget(edit=self._root_widget, cancel_button=btn) - - ba.textwidget(parent=self._root_widget, - position=(0, height - 44), - size=(width, 25), - text=ba.Lstr(resource=self._r + ".titleText"), - color=ba.app.ui.title_color, - h_align="center", - v_align="center", - maxwidth=130) + label=bui.Lstr(resource='backText'), + button_type='back', + on_activate_call=self._do_back, + ) + bui.containerwidget(edit=self._root_widget, cancel_button=btn) + + bui.textwidget( + parent=self._root_widget, + position=(0, height - 44), + size=(width, 25), + text=bui.Lstr(resource=self._r + '.titleText'), + color=bui.app.classic.ui.title_color, + h_align='center', + v_align='center', + maxwidth=130, + ) if self._back_button is not None: - ba.buttonwidget(edit=self._back_button, - button_type="backSmall", - size=(60, 60), - label=ba.charstr(ba.SpecialChar.BACK)) + bui.buttonwidget( + edit=self._back_button, + button_type='backSmall', + size=(60, 60), + label=bui.charstr(bui.SpecialChar.BACK), + ) v = height - 80 v -= 145 basew = 200 baseh = 160 - - x_offs = x_inset + (105 if _uiscale is ba.UIScale.SMALL else - 72) - basew # now unused + x_offs = ( + x_inset + (105 if _uiscale is bui.UIScale.SMALL else 72) - basew + ) # now unused x_offs2 = x_offs + basew - 7 x_offs3 = x_offs + 2 * (basew - 7) x_offs4 = x_offs + 3 * (basew - 7) x_offs5 = x_offs2 + 0.5 * (basew - 7) x_offs6 = x_offs5 + (basew - 7) - def _b_title(x: float, y: float, button: ba.Widget, - text: Union[str, ba.Lstr]) -> None: - ba.textwidget(parent=self._root_widget, - text=text, - position=(x + basew * 0.47, y + baseh * 0.22), - maxwidth=basew * 0.7, size=(0, 0), - h_align="center", - v_align="center", - draw_controller=button, - color=(0.7, 0.9, 0.7, 1.0)) - - ctb = self._controllers_button = ba.buttonwidget(parent=self._root_widget, - autoselect=True, - position=(x_offs2, v), - size=(basew, baseh), - button_type="square", - label="", - on_activate_call=self._do_controllers) - if ba.app.ui.use_toolbars and self._back_button is None: - bbtn = _ba.get_special_widget("back_button") - ba.widget(edit=ctb, left_widget=bbtn) - _b_title(x_offs2, v, ctb, - ba.Lstr(resource=self._r + ".controllersText")) + def _b_title( + x: float, y: float, button: bui.Widget, text: str | bui.Lstr + ) -> None: + bui.textwidget( + parent=self._root_widget, + text=text, + position=(x + basew * 0.47, y + baseh * 0.22), + maxwidth=basew * 0.7, + size=(0, 0), + h_align='center', + v_align='center', + draw_controller=button, + color=(0.7, 0.9, 0.7, 1.0), + ) + + ctb = self._controllers_button = bui.buttonwidget( + parent=self._root_widget, + autoselect=True, + position=(x_offs2, v), + size=(basew, baseh), + button_type='square', + label='', + on_activate_call=self._do_controllers, + ) + if bui.app.classic.ui.use_toolbars and self._back_button is None: + bbtn = bui.get_special_widget('back_button') + bui.widget(edit=ctb, left_widget=bbtn) + _b_title( + x_offs2, v, ctb, bui.Lstr(resource=self._r + '.controllersText') + ) imgw = imgh = 130 - ba.imagewidget(parent=self._root_widget, - position=(x_offs2 + basew * 0.49 - imgw * 0.5, v + 35), - size=(imgw, imgh), - texture=ba.gettexture("controllerIcon"), - draw_controller=ctb) - - gfxb = self._graphics_button = ba.buttonwidget(parent=self._root_widget, - autoselect=True, - position=(x_offs3, v), - size=(basew, baseh), - button_type="square", - label="", - on_activate_call=self._do_graphics) - if ba.app.ui.use_toolbars: - pbtn = _ba.get_special_widget("party_button") - ba.widget(edit=gfxb, up_widget=pbtn, right_widget=pbtn) - _b_title(x_offs3, v, gfxb, ba.Lstr(resource=self._r + ".graphicsText")) + bui.imagewidget( + parent=self._root_widget, + position=(x_offs2 + basew * 0.49 - imgw * 0.5, v + 35), + size=(imgw, imgh), + texture=bui.gettexture('controllerIcon'), + draw_controller=ctb, + ) + + gfxb = self._graphics_button = bui.buttonwidget( + parent=self._root_widget, + autoselect=True, + position=(x_offs3, v), + size=(basew, baseh), + button_type='square', + label='', + on_activate_call=self._do_graphics, + ) + if bui.app.classic.ui.use_toolbars: + pbtn = bui.get_special_widget('party_button') + bui.widget(edit=gfxb, up_widget=pbtn, right_widget=pbtn) + _b_title(x_offs3, v, gfxb, bui.Lstr(resource=self._r + '.graphicsText')) imgw = imgh = 110 - ba.imagewidget(parent=self._root_widget, - position=(x_offs3 + basew * 0.49 - imgw * 0.5, v + 42), - size=(imgw, imgh), - texture=ba.gettexture("graphicsIcon"), - draw_controller=gfxb) - - abtn = self._audio_button = ba.buttonwidget(parent=self._root_widget, - autoselect=True, - position=(x_offs4, v), - size=(basew, baseh), - button_type="square", - label="", - on_activate_call=self._do_audio) - _b_title(x_offs4, v, abtn, ba.Lstr(resource=self._r + ".audioText")) + bui.imagewidget( + parent=self._root_widget, + position=(x_offs3 + basew * 0.49 - imgw * 0.5, v + 42), + size=(imgw, imgh), + texture=bui.gettexture('graphicsIcon'), + draw_controller=gfxb, + ) + + abtn = self._audio_button = bui.buttonwidget( + parent=self._root_widget, + autoselect=True, + position=(x_offs4, v), + size=(basew, baseh), + button_type='square', + label='', + on_activate_call=self._do_audio, + ) + _b_title(x_offs4, v, abtn, bui.Lstr(resource=self._r + '.audioText')) imgw = imgh = 120 - ba.imagewidget(parent=self._root_widget, - position=(x_offs4 + basew * 0.49 - imgw * 0.5 + 5, v + 35), - size=(imgw, imgh), - color=(1, 1, 0), texture=ba.gettexture("audioIcon"), - draw_controller=abtn) - v -= (baseh - 5) - - avb = self._advanced_button = ba.buttonwidget(parent=self._root_widget, - autoselect=True, - position=(x_offs5, v), - size=(basew, baseh), - button_type="square", - label="", - on_activate_call=self._do_advanced) - _b_title(x_offs5, v, avb, ba.Lstr(resource=self._r + ".advancedText")) + bui.imagewidget( + parent=self._root_widget, + position=(x_offs4 + basew * 0.49 - imgw * 0.5 + 5, v + 35), + size=(imgw, imgh), + color=(1, 1, 0), + texture=bui.gettexture('audioIcon'), + draw_controller=abtn, + ) + + v -= baseh - 5 + + avb = self._advanced_button = bui.buttonwidget( + parent=self._root_widget, + autoselect=True, + position=(x_offs5, v), + size=(basew, baseh), + button_type='square', + label='', + on_activate_call=self._do_advanced, + ) + _b_title(x_offs5, v, avb, bui.Lstr(resource=self._r + '.advancedText')) imgw = imgh = 120 - ba.imagewidget(parent=self._root_widget, - position=(x_offs5 + basew * 0.49 - imgw * 0.5 + 5, - v + 35), - size=(imgw, imgh), - color=(0.8, 0.95, 1), - texture=ba.gettexture("advancedIcon"), - draw_controller=avb) - - mmb = self._modmgr_button = ba.buttonwidget(parent=self._root_widget, - autoselect=True, - position=(x_offs6, v), - size=(basew, baseh), - button_type="square", - label="", - on_activate_call=self._do_modmanager) - _b_title(x_offs6, v, mmb, ba.Lstr(value="Plugin Manager")) + bui.imagewidget( + parent=self._root_widget, + position=(x_offs5 + basew * 0.49 - imgw * 0.5 + 5, v + 35), + size=(imgw, imgh), + color=(0.8, 0.95, 1), + texture=bui.gettexture('advancedIcon'), + draw_controller=avb, + ) + + mmb = self._modmgr_button = bui.buttonwidget(parent=self._root_widget, + autoselect=True, + position=(x_offs6, v), + size=(basew, baseh), + button_type="square", + label="", + on_activate_call=self._do_modmanager) + _b_title(x_offs6, v, mmb, bui.Lstr(value="Plugin Manager")) imgw = imgh = 112 - ba.imagewidget(parent=self._root_widget, - position=(x_offs6 + basew * 0.49 - imgw * 0.5 + 5, - v + 35), - size=(imgw, imgh), - color=(0.8, 0.95, 1), - texture=ba.gettexture("storeIcon"), - draw_controller=mmb) + bui.imagewidget(parent=self._root_widget, + position=(x_offs6 + basew * 0.49 - imgw * 0.5 + 5, + v + 35), + size=(imgw, imgh), + color=(0.8, 0.95, 1), + texture=bui.gettexture("storeIcon"), + draw_controller=mmb) self._restore_state() @@ -2253,113 +2300,143 @@ def _b_title(x: float, y: float, button: ba.Widget, @staticmethod def _preload_modules() -> None: """Preload modules we use (called in bg thread).""" - # import bastd.ui.mainmenu as _unused1 - # import bastd.ui.settings.controls as _unused2 - # import bastd.ui.settings.graphics as _unused3 - # import bastd.ui.settings.audio as _unused4 - # import bastd.ui.settings.advanced as _unused5 + import bastd.ui.mainmenu as _unused1 + import bastd.ui.settings.controls as _unused2 + import bastd.ui.settings.graphics as _unused3 + import bastd.ui.settings.audio as _unused4 + import bastd.ui.settings.advanced as _unused5 def _do_back(self) -> None: # pylint: disable=cyclic-import from bastd.ui.mainmenu import MainMenuWindow + self._save_state() - ba.containerwidget(edit=self._root_widget, - transition=self._transition_out) - ba.app.ui.set_main_menu_window( - MainMenuWindow(transition="in_left").get_root_widget()) + bui.containerwidget( + edit=self._root_widget, transition=self._transition_out + ) + assert bui.app.classic is not None + bui.app.classic.ui.set_main_menu_window( + MainMenuWindow(transition='in_left').get_root_widget() + ) def _do_controllers(self) -> None: # pylint: disable=cyclic-import from bastd.ui.settings.controls import ControlsSettingsWindow + self._save_state() - ba.containerwidget(edit=self._root_widget, transition="out_left") - ba.app.ui.set_main_menu_window(ControlsSettingsWindow( - origin_widget=self._controllers_button).get_root_widget()) + bui.containerwidget(edit=self._root_widget, transition='out_left') + assert bui.app.classic is not None + bui.app.classic.ui.set_main_menu_window( + ControlsSettingsWindow( + origin_widget=self._controllers_button + ).get_root_widget() + ) def _do_graphics(self) -> None: # pylint: disable=cyclic-import from bastd.ui.settings.graphics import GraphicsSettingsWindow + self._save_state() - ba.containerwidget(edit=self._root_widget, transition="out_left") - ba.app.ui.set_main_menu_window(GraphicsSettingsWindow( - origin_widget=self._graphics_button).get_root_widget()) + bui.containerwidget(edit=self._root_widget, transition='out_left') + assert bui.app.classic is not None + bui.app.classic.ui.set_main_menu_window( + GraphicsSettingsWindow( + origin_widget=self._graphics_button + ).get_root_widget() + ) def _do_audio(self) -> None: # pylint: disable=cyclic-import from bastd.ui.settings.audio import AudioSettingsWindow + self._save_state() - ba.containerwidget(edit=self._root_widget, transition="out_left") - ba.app.ui.set_main_menu_window(AudioSettingsWindow( - origin_widget=self._audio_button).get_root_widget()) + bui.containerwidget(edit=self._root_widget, transition='out_left') + assert bui.app.classic is not None + bui.app.classic.ui.set_main_menu_window( + AudioSettingsWindow( + origin_widget=self._audio_button + ).get_root_widget() + ) def _do_advanced(self) -> None: # pylint: disable=cyclic-import from bastd.ui.settings.advanced import AdvancedSettingsWindow + self._save_state() - ba.containerwidget(edit=self._root_widget, transition="out_left") - ba.app.ui.set_main_menu_window(AdvancedSettingsWindow( - origin_widget=self._advanced_button).get_root_widget()) + bui.containerwidget(edit=self._root_widget, transition='out_left') + assert bui.app.classic is not None + bui.app.classic.ui.set_main_menu_window( + AdvancedSettingsWindow( + origin_widget=self._advanced_button + ).get_root_widget() + ) def _do_modmanager(self) -> None: self._save_state() - ba.containerwidget(edit=self._root_widget, transition="out_left") - ba.app.ui.set_main_menu_window(PluginManagerWindow( - origin_widget=self._modmgr_button).get_root_widget()) + bui.containerwidget(edit=self._root_widget, transition="out_left") + bui.app.classic.ui.set_main_menu_window( + PluginManagerWindow( + origin_widget=self._modmgr_button + ).get_root_widget() + ) def _save_state(self) -> None: try: sel = self._root_widget.get_selected_child() if sel == self._controllers_button: - sel_name = "Controllers" + sel_name = 'Controllers' elif sel == self._graphics_button: - sel_name = "Graphics" + sel_name = 'Graphics' elif sel == self._audio_button: - sel_name = "Audio" + sel_name = 'Audio' elif sel == self._advanced_button: - sel_name = "Advanced" + sel_name = 'Advanced' elif sel == self._modmgr_button: - sel_name = "Mod Manager" + sel_name = 'Mod Manager' elif sel == self._back_button: - sel_name = "Back" + sel_name = 'Back' else: - raise ValueError(f"unrecognized selection \"{sel}\"") - ba.app.ui.window_states[type(self)] = {"sel_name": sel_name} + raise ValueError(f'unrecognized selection \'{sel}\'') + assert bui.app.classic is not None + bui.app.classic.ui.window_states[type(self)] = { + 'sel_name': sel_name + } except Exception: - ba.print_exception(f"Error saving state for {self}.") + logging.exception('Error saving state for %s.', self) def _restore_state(self) -> None: try: - sel_name = ba.app.ui.window_states.get(type(self), - {}).get("sel_name") - sel: Optional[ba.Widget] - if sel_name == "Controllers": + assert bui.app.classic is not None + sel_name = bui.app.classic.ui.window_states.get(type(self), {}).get( + 'sel_name' + ) + sel: bui.Widget | None + if sel_name == 'Controllers': sel = self._controllers_button - elif sel_name == "Graphics": + elif sel_name == 'Graphics': sel = self._graphics_button - elif sel_name == "Audio": + elif sel_name == 'Audio': sel = self._audio_button - elif sel_name == "Advanced": + elif sel_name == 'Advanced': sel = self._advanced_button - elif sel_name == "Mod Manager": - sel = self._modmgr_button - elif sel_name == "Back": + elif sel_name == 'Back': sel = self._back_button else: sel = self._controllers_button if sel is not None: - ba.containerwidget(edit=self._root_widget, selected_child=sel) + bui.containerwidget(edit=self._root_widget, selected_child=sel) except Exception: - ba.print_exception(f"Error restoring state for {self}.") + logging.exception('Error restoring state for %s.', self) -# ba_meta export plugin -class EntryPoint(ba.Plugin): +# ba_meta export babase.Plugin +class EntryPoint(babase.Plugin): def on_app_running(self) -> None: """Called when the app is being launched.""" from bastd.ui.settings import allsettings allsettings.AllSettingsWindow = NewAllSettingsWindow DNSBlockWorkaround.apply() - asyncio.set_event_loop(ba._asyncio._asyncio_event_loop) + asyncio.set_event_loop(babase._asyncio._asyncio_event_loop) startup_tasks = StartupTasks() loop = asyncio.get_event_loop() loop.create_task(startup_tasks.execute()) From 07bffac8d190bf285a50a03f2ff04dedc4066db9 Mon Sep 17 00:00:00 2001 From: Rikko Date: Wed, 17 May 2023 02:57:07 +0530 Subject: [PATCH 0481/1464] Use python 3.11 with ci --- .github/workflows/ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 621ca6af..b4bf4629 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -11,7 +11,7 @@ jobs: runs-on: ubuntu-latest strategy: matrix: - python-version: ["3.10"] + python-version: ["3.11"] steps: - uses: actions/checkout@v3 with: From 40f7a6c498a8eeb6dc72c0f5f28819ac2f5f0b35 Mon Sep 17 00:00:00 2001 From: Rikko Date: Wed, 17 May 2023 03:00:50 +0530 Subject: [PATCH 0482/1464] Bump to v1.0.0 If this works out fine, then we are stable enough to mark this release as 1.0.0. --- plugin_manager.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugin_manager.py b/plugin_manager.py index b0b40271..7d823463 100644 --- a/plugin_manager.py +++ b/plugin_manager.py @@ -30,7 +30,7 @@ _uiscale = bui.app.classic.ui.uiscale -PLUGIN_MANAGER_VERSION = "0.3.5" +PLUGIN_MANAGER_VERSION = "1.0.0" 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 b262789a349393e64b51ff28c408a2f695087f14 Mon Sep 17 00:00:00 2001 From: Rikko Date: Wed, 17 May 2023 03:59:35 +0530 Subject: [PATCH 0483/1464] Update colorscheme to api 8 --- plugins/utilities.json | 3 +- plugins/utilities/colorscheme.py | 191 ++++++++++++++----------------- 2 files changed, 86 insertions(+), 108 deletions(-) diff --git a/plugins/utilities.json b/plugins/utilities.json index c8adc4b7..94a9a31f 100644 --- a/plugins/utilities.json +++ b/plugins/utilities.json @@ -223,6 +223,7 @@ } ], "versions": { + "2.0.0": null, "1.2.3": { "api_version": 7, "commit_sha": "7753b87", @@ -709,4 +710,4 @@ } } } -} \ No newline at end of file +} diff --git a/plugins/utilities/colorscheme.py b/plugins/utilities/colorscheme.py index bd4e4c5f..0dada0c5 100644 --- a/plugins/utilities/colorscheme.py +++ b/plugins/utilities/colorscheme.py @@ -6,39 +6,21 @@ # Settings -> Advanced -> Enter Code # to bring up the colorscheme UI. -# ba_meta require api 7 -import _ba -import ba +# ba_meta require api 8 +import _babase +import babase +import bauiv1 as bui from bastd.ui.colorpicker import ColorPicker -original_buttonwidget = ba.buttonwidget -original_containerwidget = ba.containerwidget -original_checkboxwidget = ba.checkboxwidget +original_buttonwidget = bui.buttonwidget +original_containerwidget = bui.containerwidget +original_checkboxwidget = bui.checkboxwidget # We set this later so we store the overridden method in case the # player is using pro-unlocker plugins that override the -# `ba.app.accounts.have_pro` method. +# `bui.app.classic.accounts.have_pro` method. original_have_pro = None - - -def is_game_version_lower_than(version): - """ - Returns a boolean value indicating whether the current game - version is lower than the passed version. Useful for addressing - any breaking changes within game versions. - """ - game_version = tuple(map(int, ba.app.version.split("."))) - version = tuple(map(int, version.split("."))) - return game_version < version - - -# Adds backward compatibility for a breaking change released in -# game version 1.7.7, which moves `_ba.add_transaction` to -# `ba.internal.add_transaction`. -if is_game_version_lower_than("1.7.7"): - original_add_transaction = _ba.add_transaction -else: - original_add_transaction = ba.internal.add_transaction +original_add_transaction = bui.app.plus.add_v1_account_transaction class ColorScheme: @@ -61,24 +43,24 @@ class ColorScheme: -------- + Apply dark colorscheme: - >>> import _ba - >>> dark = _ba.ColorScheme((0.2,0.2,0.2), (0.8,0.8,0.8)) + >>> import _babase + >>> dark = _babase.ColorScheme((0.2,0.2,0.2), (0.8,0.8,0.8)) >>> dark.apply() # Reset back to game's default colorscheme >>> dark.disable() + Colorscheme that modifies only the main colors: - >>> import _ba - >>> bluey = _ba.ColorScheme(color=(0.1,0.3,0.6)) + >>> import _babase + >>> bluey = _babase.ColorScheme(color=(0.1,0.3,0.6)) >>> bluey.apply() # Reset back to game's default colorscheme >>> bluey.disable() + Colorscheme that modifies only the highlight colors: - >>> import _ba - >>> reddish = _ba.ColorScheme(highlight=(0.8,0.35,0.35)) + >>> import _babase + >>> reddish = _babase.ColorScheme(highlight=(0.8,0.35,0.35)) >>> reddish.apply() # Reset back to game's default colorscheme >>> reddish.disable() @@ -86,8 +68,8 @@ class ColorScheme: + Revert back to game's default colorscheme irrespective of whatever colorscheme is active at the moment: - >>> import _ba - >>> _ba.ColorScheme.disable() + >>> import _babase + >>> _babase.ColorScheme.disable() """ def __init__(self, color=None, highlight=None): @@ -112,13 +94,13 @@ def _custom_checkboxwidget(self, *args, **kwargs): def _apply_color(self): if self.color is None: raise TypeError("Expected color to be an (R,G,B) tuple.") - ba.containerwidget = self._custom_containerwidget + bui.containerwidget = self._custom_containerwidget def _apply_highlight(self): if self.highlight is None: raise TypeError("Expected highlight to be an (R,G,B) tuple.") - ba.buttonwidget = self._custom_buttonwidget - ba.checkboxwidget = self._custom_checkboxwidget + bui.buttonwidget = self._custom_buttonwidget + bui.checkboxwidget = self._custom_checkboxwidget def apply(self): if self.color: @@ -128,12 +110,12 @@ def apply(self): @staticmethod def _disable_color(): - ba.buttonwidget = original_buttonwidget - ba.checkboxwidget = original_checkboxwidget + bui.buttonwidget = original_buttonwidget + bui.checkboxwidget = original_checkboxwidget @staticmethod def _disable_highlight(): - ba.containerwidget = original_containerwidget + bui.containerwidget = original_containerwidget @classmethod def disable(cls): @@ -141,10 +123,10 @@ def disable(cls): cls._disable_highlight() -class ColorSchemeWindow(ba.Window): +class ColorSchemeWindow(bui.Window): def __init__(self, default_colors=((0.41, 0.39, 0.5), (0.5, 0.7, 0.25))): self._default_colors = default_colors - self._color, self._highlight = ba.app.config.get("ColorScheme", (None, None)) + self._color, self._highlight = babase.app.config.get("ColorScheme", (None, None)) self._last_color = self._color self._last_highlight = self._highlight @@ -157,7 +139,7 @@ def __init__(self, default_colors=((0.41, 0.39, 0.5), (0.5, 0.7, 0.25))): # A hack to let players select any RGB color value through the UI, # otherwise this is limited only to pro accounts. - ba.app.accounts_v1.have_pro = lambda: True + bui.app.classic.accounts.have_pro = lambda: True self.draw_ui() @@ -165,80 +147,80 @@ def draw_ui(self): # Most of the stuff here for drawing the UI is referred from the # game's bastd/ui/profile/edit.py, and so there could be some # cruft here due to my oversight. - uiscale = ba.app.ui.uiscale - self._width = width = 480.0 if uiscale is ba.UIScale.SMALL else 380.0 - self._x_inset = x_inset = 40.0 if uiscale is ba.UIScale.SMALL else 0.0 + uiscale = bui.app.classic.ui.uiscale + self._width = width = 480.0 if uiscale is babase.UIScale.SMALL else 380.0 + self._x_inset = x_inset = 40.0 if uiscale is babase.UIScale.SMALL else 0.0 self._height = height = ( 275.0 - if uiscale is ba.UIScale.SMALL + if uiscale is babase.UIScale.SMALL else 288.0 - if uiscale is ba.UIScale.MEDIUM + if uiscale is babase.UIScale.MEDIUM else 300.0 ) spacing = 40 self._base_scale = ( 2.05 - if uiscale is ba.UIScale.SMALL + if uiscale is babase.UIScale.SMALL else 1.5 - if uiscale is ba.UIScale.MEDIUM + if uiscale is babase.UIScale.MEDIUM else 1.0 ) top_extra = 15 super().__init__( - root_widget=ba.containerwidget( + root_widget=bui.containerwidget( size=(width, height + top_extra), on_outside_click_call=self.cancel_on_outside_click, transition="in_right", scale=self._base_scale, - stack_offset=(0, 15) if uiscale is ba.UIScale.SMALL else (0, 0), + stack_offset=(0, 15) if uiscale is babase.UIScale.SMALL else (0, 0), ) ) - cancel_button = ba.buttonwidget( + cancel_button = bui.buttonwidget( parent=self._root_widget, position=(52 + x_inset, height - 60), size=(155, 60), scale=0.8, autoselect=True, - label=ba.Lstr(resource="cancelText"), + label=babase.Lstr(resource="cancelText"), on_activate_call=self._cancel, ) - ba.containerwidget(edit=self._root_widget, cancel_button=cancel_button) + bui.containerwidget(edit=self._root_widget, cancel_button=cancel_button) - save_button = ba.buttonwidget( + save_button = bui.buttonwidget( parent=self._root_widget, position=(width - (177 + x_inset), height - 110), size=(155, 60), autoselect=True, scale=0.8, - label=ba.Lstr(resource="saveText"), + label=babase.Lstr(resource="saveText"), ) - ba.widget(edit=save_button, left_widget=cancel_button) - ba.buttonwidget(edit=save_button, on_activate_call=self.save) - ba.widget(edit=cancel_button, right_widget=save_button) - ba.containerwidget(edit=self._root_widget, start_button=save_button) + bui.widget(edit=save_button, left_widget=cancel_button) + bui.buttonwidget(edit=save_button, on_activate_call=self.save) + bui.widget(edit=cancel_button, right_widget=save_button) + bui.containerwidget(edit=self._root_widget, start_button=save_button) - reset_button = ba.buttonwidget( + reset_button = bui.buttonwidget( parent=self._root_widget, position=(width - (177 + x_inset), height - 60), size=(155, 60), color=(0.2, 0.5, 0.6), autoselect=True, scale=0.8, - label=ba.Lstr(resource="settingsWindowAdvanced.resetText"), + label=babase.Lstr(resource="settingsWindowAdvanced.resetText"), ) - ba.widget(edit=reset_button, left_widget=reset_button) - ba.buttonwidget(edit=reset_button, on_activate_call=self.reset) - ba.widget(edit=cancel_button, right_widget=reset_button) - ba.containerwidget(edit=self._root_widget, start_button=reset_button) + bui.widget(edit=reset_button, left_widget=reset_button) + bui.buttonwidget(edit=reset_button, on_activate_call=self.reset) + bui.widget(edit=cancel_button, right_widget=reset_button) + bui.containerwidget(edit=self._root_widget, start_button=reset_button) v = height - 65.0 v -= spacing * 3.0 b_size = 80 b_offs = 75 - self._color_button = ba.buttonwidget( + self._color_button = bui.buttonwidget( parent=self._root_widget, autoselect=True, position=(self._width * 0.5 - b_offs - b_size * 0.5, v - 50), @@ -247,23 +229,23 @@ def draw_ui(self): label="", button_type="square", ) - ba.buttonwidget( - edit=self._color_button, on_activate_call=ba.Call(self._pick_color, "color") + bui.buttonwidget( + edit=self._color_button, on_activate_call=babase.Call(self._pick_color, "color") ) - ba.textwidget( + bui.textwidget( parent=self._root_widget, h_align="center", v_align="center", position=(self._width * 0.5 - b_offs, v - 65), size=(0, 0), draw_controller=self._color_button, - text=ba.Lstr(resource="editProfileWindow.colorText"), + text=babase.Lstr(resource="editProfileWindow.colorText"), scale=0.7, - color=ba.app.ui.title_color, + color=bui.app.classic.ui.title_color, maxwidth=120, ) - self._highlight_button = ba.buttonwidget( + self._highlight_button = bui.buttonwidget( parent=self._root_widget, autoselect=True, position=(self._width * 0.5 + b_offs - b_size * 0.5, v - 50), @@ -273,20 +255,20 @@ def draw_ui(self): button_type="square", ) - ba.buttonwidget( + bui.buttonwidget( edit=self._highlight_button, - on_activate_call=ba.Call(self._pick_color, "highlight"), + on_activate_call=babase.Call(self._pick_color, "highlight"), ) - ba.textwidget( + bui.textwidget( parent=self._root_widget, h_align="center", v_align="center", position=(self._width * 0.5 + b_offs, v - 65), size=(0, 0), draw_controller=self._highlight_button, - text=ba.Lstr(resource="editProfileWindow.highlightText"), + text=babase.Lstr(resource="editProfileWindow.highlightText"), scale=0.7, - color=ba.app.ui.title_color, + color=bui.app.classic.ui.title_color, maxwidth=120, ) @@ -306,7 +288,7 @@ def _pick_color(self, tag): ) def cancel_on_outside_click(self): - ba.playsound(ba.getsound("swish")) + bui.getsound("swish").play() self._cancel() def _cancel(self): @@ -314,44 +296,44 @@ def _cancel(self): colorscheme = ColorScheme(self._last_color, self._last_highlight) colorscheme.apply() # Good idea to revert this back now so we do not break anything else. - ba.app.accounts_v1.have_pro = original_have_pro - ba.containerwidget(edit=self._root_widget, transition="out_right") + bui.app.classic.accounts.have_pro = original_have_pro + bui.containerwidget(edit=self._root_widget, transition="out_right") def reset(self, transition_out=True): if transition_out: - ba.playsound(ba.getsound("gunCocking")) - ba.app.config["ColorScheme"] = (None, None) + bui.getsound("gunCocking").play() + babase.app.config["ColorScheme"] = (None, None) # Good idea to revert this back now so we do not break anything else. - ba.app.accounts_v1.have_pro = original_have_pro - ba.app.config.commit() - ba.containerwidget(edit=self._root_widget, transition="out_right") + bui.app.classic.accounts.have_pro = original_have_pro + babase.app.config.commit() + bui.containerwidget(edit=self._root_widget, transition="out_right") def save(self, transition_out=True): if transition_out: - ba.playsound(ba.getsound("gunCocking")) + bui.getsound("gunCocking").play() colorscheme = ColorScheme( self._color or self._default_colors[0], self._highlight or self._default_colors[1], ) colorscheme.apply() # Good idea to revert this back now so we do not break anything else. - ba.app.accounts_v1.have_pro = original_have_pro - ba.app.config["ColorScheme"] = ( + bui.app.classic.accounts.have_pro = original_have_pro + babase.app.config["ColorScheme"] = ( self._color or self._default_colors[0], self._highlight or self._default_colors[1], ) - ba.app.config.commit() - ba.containerwidget(edit=self._root_widget, transition="out_right") + babase.app.config.commit() + bui.containerwidget(edit=self._root_widget, transition="out_right") def _set_color(self, color): self._color = color if self._color_button: - ba.buttonwidget(edit=self._color_button, color=color) + bui.buttonwidget(edit=self._color_button, color=color) def _set_highlight(self, color): self._highlight = color if self._highlight_button: - ba.buttonwidget(edit=self._highlight_button, color=color) + bui.buttonwidget(edit=self._highlight_button, color=color) def color_picker_selected_color(self, picker, color): # The `ColorPicker` calls this method in the delegate once a color @@ -387,13 +369,7 @@ def add(self, transaction_code, transaction_fn): self.custom_transactions[transaction_code] = transaction_fn def enable(self): - # Adds backward compatibility for a breaking change released in - # game version 1.7.7, which moves `_ba.add_transaction` to - # `ba.internal.add_transaction`. - if is_game_version_lower_than("1.7.7"): - _ba.add_transaction = self._handle - else: - ba.internal.add_transaction = self._handle + bui.app.plus.add_v1_account_transaction = self._handle def launch_colorscheme_selection_window(): @@ -410,7 +386,7 @@ def launch_colorscheme_selection_window(): # has pro-unlocked or not if our plugin runs before the dedicated # pro-unlocker plugin has been applied. global original_have_pro - original_have_pro = ba.app.accounts_v1.have_pro + original_have_pro = bui.app.classic.accounts.have_pro ColorSchemeWindow() @@ -420,7 +396,7 @@ def colorscheme_transaction(transaction, *args, **kwargs): def load_colorscheme(): - color, highlight = ba.app.config.get("ColorScheme", (None, None)) + color, highlight = babase.app.config.get("ColorScheme", (None, None)) if color and highlight: colorscheme = ColorScheme(color, highlight) colorscheme.apply() @@ -429,7 +405,7 @@ def load_colorscheme(): def load_plugin(): # Allow access to changing colorschemes manually through the in-game # console. - _ba.ColorScheme = ColorScheme + _babase.ColorScheme = ColorScheme # Adds a new advanced code entry named "colorscheme" which can be # entered through Settings -> Advanced -> Enter Code, allowing # colorscheme modification through a friendly UI. @@ -440,8 +416,8 @@ def load_plugin(): load_colorscheme() -# ba_meta export plugin -class Main(ba.Plugin): +# ba_meta export babase.Plugin +class Main(babase.Plugin): def on_app_running(self): load_plugin() @@ -450,3 +426,4 @@ def has_settings_ui(self): def show_settings_ui(self, source_widget): launch_colorscheme_selection_window() + From 634fbe180a08a017caa17cfc59870ed043ff0222 Mon Sep 17 00:00:00 2001 From: rikkolovescats Date: Tue, 16 May 2023 22:30:35 +0000 Subject: [PATCH 0484/1464] [ci] auto-format --- plugins/utilities/colorscheme.py | 1 - 1 file changed, 1 deletion(-) diff --git a/plugins/utilities/colorscheme.py b/plugins/utilities/colorscheme.py index 0dada0c5..f392e846 100644 --- a/plugins/utilities/colorscheme.py +++ b/plugins/utilities/colorscheme.py @@ -426,4 +426,3 @@ def has_settings_ui(self): def show_settings_ui(self, source_widget): launch_colorscheme_selection_window() - From f7a9e7c0bfa6457736ac976b6140749b95e25275 Mon Sep 17 00:00:00 2001 From: rikkolovescats Date: Tue, 16 May 2023 22:30:37 +0000 Subject: [PATCH 0485/1464] [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 94a9a31f..b688b639 100644 --- a/plugins/utilities.json +++ b/plugins/utilities.json @@ -223,7 +223,12 @@ } ], "versions": { - "2.0.0": null, + "2.0.0": { + "api_version": 8, + "commit_sha": "d10ede0", + "released_on": "16-05-2023", + "md5sum": "8937918bd79435eaa167fd70cb8046ed" + }, "1.2.3": { "api_version": 7, "commit_sha": "7753b87", @@ -710,4 +715,4 @@ } } } -} +} \ No newline at end of file From c0fa2dbd79944b3e06f49aeb3e1a6ac24ae0db31 Mon Sep 17 00:00:00 2001 From: Rikko Date: Wed, 17 May 2023 05:08:21 +0530 Subject: [PATCH 0486/1464] Parse long export class names --- plugin_manager.py | 26 ++++++++++++++++++++++---- 1 file changed, 22 insertions(+), 4 deletions(-) diff --git a/plugin_manager.py b/plugin_manager.py index 7d823463..6c3d3c82 100644 --- a/plugin_manager.py +++ b/plugin_manager.py @@ -1,4 +1,5 @@ # ba_meta require api 8 +from babase._meta import EXPORT_CLASS_NAME_SHORTCUTS import babase import _babase import bauiv1 as bui @@ -40,10 +41,25 @@ "User-Agent": _env["user_agent_string"], } PLUGIN_DIRECTORY = _env["python_directory_user"] +_regexp_friendly_class_name_shortcut = lambda string: string.replace(".", "\.") REGEXP = { "plugin_api_version": re.compile(b"(?<=ba_meta require api )(.*)"), - "plugin_entry_points": re.compile(b"(ba_meta export plugin\n+class )(.*)\\("), - "minigames": re.compile(b"(ba_meta export game\n+class )(.*)\\("), + "plugin_entry_points": re.compile( + bytes( + "(ba_meta export (plugin|{})\n+class )(.*)\\(".format( + _regexp_friendly_class_name_shortcut(EXPORT_CLASS_NAME_SHORTCUTS["plugin"]), + ), + "utf-8" + ), + ), + "minigames": re.compile( + bytes( + "(ba_meta export (game|{})\n+class )(.*)\\(".format( + _regexp_friendly_class_name_shortcut(EXPORT_CLASS_NAME_SHORTCUTS["game"]), + ), + "utf-8" + ), + ), } DISCORD_URL = "https://ballistica.net/discord" @@ -521,8 +537,8 @@ async def get_entry_points(self): if not self._entry_points: content = await self.get_content() groups = REGEXP["plugin_entry_points"].findall(content) - # Actual entry points are stored in the first index inside the matching groups. - entry_points = tuple(f"{self.name}.{group[1].decode('utf-8')}" for group in groups) + # Actual entry points are stored in the last index inside the matching groups. + entry_points = tuple(f"{self.name}.{group[-1].decode('utf-8')}" for group in groups) self._entry_points = entry_points return self._entry_points @@ -2419,6 +2435,8 @@ def _restore_state(self) -> None: sel = self._audio_button elif sel_name == 'Advanced': sel = self._advanced_button + elif sel_name == "Mod Manager": + sel = self._modmgr_button elif sel_name == 'Back': sel = self._back_button else: From decdc815e3ba6d94d06ad0cdae959e8894ac2a10 Mon Sep 17 00:00:00 2001 From: rikkolovescats Date: Tue, 16 May 2023 23:39:05 +0000 Subject: [PATCH 0487/1464] [ci] auto-format --- plugin_manager.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/plugin_manager.py b/plugin_manager.py index 6c3d3c82..3cf728df 100644 --- a/plugin_manager.py +++ b/plugin_manager.py @@ -41,7 +41,9 @@ "User-Agent": _env["user_agent_string"], } PLUGIN_DIRECTORY = _env["python_directory_user"] -_regexp_friendly_class_name_shortcut = lambda string: string.replace(".", "\.") +def _regexp_friendly_class_name_shortcut(string): return string.replace(".", "\.") + + REGEXP = { "plugin_api_version": re.compile(b"(?<=ba_meta require api )(.*)"), "plugin_entry_points": re.compile( From 1e3999b96a8058ee6562158860372f517f713ea5 Mon Sep 17 00:00:00 2001 From: Rikko Date: Wed, 17 May 2023 05:14:55 +0530 Subject: [PATCH 0488/1464] Use shortcut class name for colorscheme export --- plugins/utilities.json | 9 ++------- plugins/utilities/colorscheme.py | 2 +- 2 files changed, 3 insertions(+), 8 deletions(-) diff --git a/plugins/utilities.json b/plugins/utilities.json index b688b639..94a9a31f 100644 --- a/plugins/utilities.json +++ b/plugins/utilities.json @@ -223,12 +223,7 @@ } ], "versions": { - "2.0.0": { - "api_version": 8, - "commit_sha": "d10ede0", - "released_on": "16-05-2023", - "md5sum": "8937918bd79435eaa167fd70cb8046ed" - }, + "2.0.0": null, "1.2.3": { "api_version": 7, "commit_sha": "7753b87", @@ -715,4 +710,4 @@ } } } -} \ No newline at end of file +} diff --git a/plugins/utilities/colorscheme.py b/plugins/utilities/colorscheme.py index f392e846..f022cf99 100644 --- a/plugins/utilities/colorscheme.py +++ b/plugins/utilities/colorscheme.py @@ -416,7 +416,7 @@ def load_plugin(): load_colorscheme() -# ba_meta export babase.Plugin +# ba_meta export plugin class Main(babase.Plugin): def on_app_running(self): load_plugin() From f3936b5e068d336f944062b6313d53c127266442 Mon Sep 17 00:00:00 2001 From: rikkolovescats Date: Tue, 16 May 2023 23:45:47 +0000 Subject: [PATCH 0489/1464] [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 94a9a31f..ca2f13a5 100644 --- a/plugins/utilities.json +++ b/plugins/utilities.json @@ -223,7 +223,12 @@ } ], "versions": { - "2.0.0": null, + "2.0.0": { + "api_version": 8, + "commit_sha": "efa4149", + "released_on": "16-05-2023", + "md5sum": "febad34d0105335403daacbb63fc5054" + }, "1.2.3": { "api_version": 7, "commit_sha": "7753b87", @@ -710,4 +715,4 @@ } } } -} +} \ No newline at end of file From fe2fac53df2a051f2785d58d5bc10da3062bcc64 Mon Sep 17 00:00:00 2001 From: Rikko Date: Thu, 8 Jun 2023 21:24:02 +0530 Subject: [PATCH 0490/1464] Rename bastd stuff --- plugin_manager.py | 30 +++++++++++++++--------------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/plugin_manager.py b/plugin_manager.py index 3cf728df..3a3f9265 100644 --- a/plugin_manager.py +++ b/plugin_manager.py @@ -3,7 +3,7 @@ import babase import _babase import bauiv1 as bui -from bastd.ui import popup, confirm +from bauiv1lib import popup, confirm import urllib.request import http.client @@ -56,8 +56,8 @@ def _regexp_friendly_class_name_shortcut(string): return string.replace(".", "\. ), "minigames": re.compile( bytes( - "(ba_meta export (game|{})\n+class )(.*)\\(".format( - _regexp_friendly_class_name_shortcut(EXPORT_CLASS_NAME_SHORTCUTS["game"]), + "(ba_meta export ({})\n+class )(.*)\\(".format( + _regexp_friendly_class_name_shortcut("bascenev1.GameActivity"), ), "utf-8" ), @@ -1545,7 +1545,7 @@ def __init__(self, transition: str = "in_right", origin_widget: bui.Widget = Non ) def _back(self) -> None: - from bastd.ui.settings.allsettings import AllSettingsWindow + from bauiv1lib.settings.allsettings import AllSettingsWindow bui.containerwidget(edit=self._root_widget, transition=self._transition_out) bui.app.classic.ui.set_main_menu_window( @@ -2318,15 +2318,15 @@ def _b_title( @staticmethod def _preload_modules() -> None: """Preload modules we use (called in bg thread).""" - import bastd.ui.mainmenu as _unused1 - import bastd.ui.settings.controls as _unused2 - import bastd.ui.settings.graphics as _unused3 - import bastd.ui.settings.audio as _unused4 - import bastd.ui.settings.advanced as _unused5 + import bauiv1lib.mainmenu as _unused1 + import bauiv1lib.settings.controls as _unused2 + import bauiv1lib.settings.graphics as _unused3 + import bauiv1lib.settings.audio as _unused4 + import bauiv1lib.settings.advanced as _unused5 def _do_back(self) -> None: # pylint: disable=cyclic-import - from bastd.ui.mainmenu import MainMenuWindow + from bauiv1lib.mainmenu import MainMenuWindow self._save_state() bui.containerwidget( @@ -2339,7 +2339,7 @@ def _do_back(self) -> None: def _do_controllers(self) -> None: # pylint: disable=cyclic-import - from bastd.ui.settings.controls import ControlsSettingsWindow + from bauiv1lib.settings.controls import ControlsSettingsWindow self._save_state() bui.containerwidget(edit=self._root_widget, transition='out_left') @@ -2352,7 +2352,7 @@ def _do_controllers(self) -> None: def _do_graphics(self) -> None: # pylint: disable=cyclic-import - from bastd.ui.settings.graphics import GraphicsSettingsWindow + from bauiv1lib.settings.graphics import GraphicsSettingsWindow self._save_state() bui.containerwidget(edit=self._root_widget, transition='out_left') @@ -2365,7 +2365,7 @@ def _do_graphics(self) -> None: def _do_audio(self) -> None: # pylint: disable=cyclic-import - from bastd.ui.settings.audio import AudioSettingsWindow + from bauiv1lib.settings.audio import AudioSettingsWindow self._save_state() bui.containerwidget(edit=self._root_widget, transition='out_left') @@ -2378,7 +2378,7 @@ def _do_audio(self) -> None: def _do_advanced(self) -> None: # pylint: disable=cyclic-import - from bastd.ui.settings.advanced import AdvancedSettingsWindow + from bauiv1lib.settings.advanced import AdvancedSettingsWindow self._save_state() bui.containerwidget(edit=self._root_widget, transition='out_left') @@ -2453,7 +2453,7 @@ def _restore_state(self) -> None: class EntryPoint(babase.Plugin): def on_app_running(self) -> None: """Called when the app is being launched.""" - from bastd.ui.settings import allsettings + from bauiv1lib.settings import allsettings allsettings.AllSettingsWindow = NewAllSettingsWindow DNSBlockWorkaround.apply() asyncio.set_event_loop(babase._asyncio._asyncio_event_loop) From 43a07bab6e6785ed863ef4b7717a699cd497ea89 Mon Sep 17 00:00:00 2001 From: Rikko Date: Thu, 8 Jun 2023 21:24:40 +0530 Subject: [PATCH 0491/1464] Rename bastd stuff for colorscheme plugin --- plugins/utilities.json | 9 ++------- plugins/utilities/colorscheme.py | 8 ++++---- 2 files changed, 6 insertions(+), 11 deletions(-) diff --git a/plugins/utilities.json b/plugins/utilities.json index ca2f13a5..94a9a31f 100644 --- a/plugins/utilities.json +++ b/plugins/utilities.json @@ -223,12 +223,7 @@ } ], "versions": { - "2.0.0": { - "api_version": 8, - "commit_sha": "efa4149", - "released_on": "16-05-2023", - "md5sum": "febad34d0105335403daacbb63fc5054" - }, + "2.0.0": null, "1.2.3": { "api_version": 7, "commit_sha": "7753b87", @@ -715,4 +710,4 @@ } } } -} \ No newline at end of file +} diff --git a/plugins/utilities/colorscheme.py b/plugins/utilities/colorscheme.py index f022cf99..5ef5159a 100644 --- a/plugins/utilities/colorscheme.py +++ b/plugins/utilities/colorscheme.py @@ -11,7 +11,7 @@ import babase import bauiv1 as bui -from bastd.ui.colorpicker import ColorPicker +from bauiv1lib.colorpicker import ColorPicker original_buttonwidget = bui.buttonwidget original_containerwidget = bui.containerwidget @@ -144,9 +144,9 @@ def __init__(self, default_colors=((0.41, 0.39, 0.5), (0.5, 0.7, 0.25))): self.draw_ui() def draw_ui(self): - # Most of the stuff here for drawing the UI is referred from the - # game's bastd/ui/profile/edit.py, and so there could be some - # cruft here due to my oversight. + # NOTE: Most of the stuff here for drawing the UI is referred from the + # legacy (1.6 < version <= 1.7.19) game's bastd/ui/profile/edit.py, and + # so there could be some cruft here due to my oversight. uiscale = bui.app.classic.ui.uiscale self._width = width = 480.0 if uiscale is babase.UIScale.SMALL else 380.0 self._x_inset = x_inset = 40.0 if uiscale is babase.UIScale.SMALL else 0.0 From db42952454b656097788cbc016de519aabbad1e1 Mon Sep 17 00:00:00 2001 From: rikkolovescats Date: Thu, 8 Jun 2023 16:01:08 +0000 Subject: [PATCH 0492/1464] [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 94a9a31f..6e6f8011 100644 --- a/plugins/utilities.json +++ b/plugins/utilities.json @@ -223,7 +223,12 @@ } ], "versions": { - "2.0.0": null, + "2.0.0": { + "api_version": 8, + "commit_sha": "9cfd0db", + "released_on": "08-06-2023", + "md5sum": "92390046cc91e147ebcd97df7390527f" + }, "1.2.3": { "api_version": 7, "commit_sha": "7753b87", @@ -710,4 +715,4 @@ } } } -} +} \ No newline at end of file From 47637100355845fca86e853e46fff7592197dae6 Mon Sep 17 00:00:00 2001 From: SEBASTIAN2059 Date: Wed, 7 Jun 2023 22:37:04 -0500 Subject: [PATCH 0493/1464] Hot Bomb for 1.7.20 --- plugins/minigames.json | 1 + plugins/minigames/hot_bomb.py | 1355 ++++++++++++++++----------------- 2 files changed, 670 insertions(+), 686 deletions(-) diff --git a/plugins/minigames.json b/plugins/minigames.json index 08eb34a7..2fe881df 100644 --- a/plugins/minigames.json +++ b/plugins/minigames.json @@ -266,6 +266,7 @@ } ], "versions": { + "1.1.0":null, "1.0.0": { "api_version": 7, "commit_sha": "095a773", diff --git a/plugins/minigames/hot_bomb.py b/plugins/minigames/hot_bomb.py index 66a81c69..ece91f91 100644 --- a/plugins/minigames/hot_bomb.py +++ b/plugins/minigames/hot_bomb.py @@ -2,7 +2,7 @@ # """Hot Bomb game by SEBASTIAN2059 and zPanxo""" -# ba_meta require api 7 +# ba_meta require api 8 # (see https://ballistica.net/wiki/meta-tag-system) from __future__ import annotations @@ -11,52 +11,53 @@ import random -import ba -import _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 +from bascenev1lib.actor.playerspaz import PlayerSpaz +from bascenev1lib.actor.scoreboard import Scoreboard +from bascenev1lib.actor.powerupbox import PowerupBoxFactory +from bascenev1lib.gameutils import SharedObjects +from bascenev1lib.actor.bomb import Bomb +from bascenev1lib.actor.spaz import PickupMessage, BombDiedMessage + +from bascenev1._messages import StandMessage + +import bascenev1 as bs +import _bascenev1 as _bs +import _babase + 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): +class Ball(bs.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 = bs.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) + + bs.getsound('scamper01').play(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] = {} @@ -64,236 +65,232 @@ def __init__(self, position: Sequence[float] = (0.0, 1.0, 0.0), timer: int = 5, assert activity is not None assert isinstance(activity, HotBombGame) pmats = [shared.object_material, activity.ball_material] - self.node = ba.newnode('prop', + self.node = bs.newnode('prop', delegate=self, attrs={ - 'model': activity.ball_model, + 'mesh': activity.ball_mesh, '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.light = ba.newnode('light', - owner=self.node, + + self.color_l = (1,1,1) + self.light = bs.newnode('light', + 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 = bs.Timer(0.1,call=bs.WeakCall(self.particles),repeat=True) + self._sound_effect = bs.Timer(4,call=bs.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] + self._counter: Optional[bs.Node] if self._timer is not None: self._count = self._timer - self._tick_timer = ba.Timer(1.0, - call=ba.WeakCall(self._tick), + self._tick_timer = bs.Timer(1.0, + call=bs.WeakCall(self._tick), repeat=True) - m = ba.newnode('math', owner=self.node, attrs={ - 'input1': (0, 0.6, 0), 'operation': 'add'}) + m = bs.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' - } - ) + self._counter = bs.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( + bs.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.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) + bs.getsound('scamper01').play(volume=0.4) + + + def explode(self,color=(3,1,0)) -> None: + sound = random.choice(['explosion01','explosion02','explosion03','explosion04','explosion05']) + bs.getsound(sound).play(volume=1) + bs.emitfx(position=self.node.position, + velocity=(0,10,0), + count=100, + scale=1.0, + spread=1.0, + chunk_type='spark') + explosion = bs.newnode( + 'explosion', + attrs={ + 'position': self.node.position, + 'velocity': (0,0,0), + 'radius': 2.0, + 'big': False, + 'color':color + } + ) + bs.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 = bs.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) - + self.region = bs.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 + }, + ) + bs.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: self._count -= 1 assert self._counter self._counter.text = str(self._count) - ba.playsound(ba.getsound('tick')) + bs.getsound('tick').play() 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 - ) + self._animate = bs.animate( + self.node, + 'mesh_scale', + { + 0:self.node.mesh_scale, + 0.1:1.5, + 0.2:self.scale + }, + loop=True + ) + self.animate_light = bs.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 - ) + self._animate = bs.animate( + self.node, + 'mesh_scale', + { + 0:self.node.mesh_scale, + 0.5:1.5, + 1.0:self.scale + }, + loop=True + ) + self.animate_light = bs.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 + if isinstance(msg, bs.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): + elif isinstance(msg, bs.OutOfBoundsMessage): assert self.node self.node.position = self._spawn_pos - elif isinstance(msg, ba.PickedUpMessage): + elif isinstance(msg, bs.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)) + self.handlemessage(bs.DroppedMessage(spaz.node)) if spaz.hitpoints > 10000: - ba.playsound(ba.getsound('fuse01'), volume=0.3) + bs.getsound('fuse01').play(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( + spaz.handlemessage(bs.DieMessage()) + bs.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, @@ -303,14 +300,13 @@ def damage(): else: self.damage_timer = None - self.damage_timer = ba.Timer(self.d_time, damage, repeat=True) + self.damage_timer = bs.Timer(self.d_time, damage, repeat=True) - elif isinstance(msg, ba.DroppedMessage): - from ba import _math + elif isinstance(msg, bs.DroppedMessage): spaz = msg.node.getdelegate(PlayerSpaz) self.damage_timer = None - elif isinstance(msg, ba.HitMessage): + elif isinstance(msg, bs.HitMessage): assert self.node assert msg.force_direction is not None self.node.handlemessage( @@ -327,54 +323,51 @@ def damage(): 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 + node = bs.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()) + bs.HitMessage( + pos=nodepos, + velocity=(0, 0, 0), + magnitude=mag, + hit_type='explosion', + hit_subtype='normal', + radius=2.0 + ) + ) + self.handlemessage(bs.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) + bs.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 @@ -388,15 +381,15 @@ def drop_bomb(self) -> Optional[Bomb]: else: dropping_bomb = True bomb_type = self.bomb_type - + if bomb_type == 'banana': - ba.playsound(ba.getsound('penguinHit1'), volume=0.3) + bs.getsound('penguinHit1').play(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]), @@ -404,61 +397,62 @@ def drop_bomb(self) -> Optional[Bomb]: 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())) + bs.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() + collision = bs.getcollision() opposingnode = collision.opposingnode opposingbody = collision.opposingbody - except ba.NotFoundError: + except bs.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']): + + +class Player(bs.Player['Team']): """Our player type for this game.""" -class Team(ba.Team[Player]): +class Team(bs.Team[Player]): """Our team type for this game.""" def __init__(self) -> None: self.score = 0 -lang = ba.app.lang.language +lang = bs.app.lang.language if lang == 'Spanish': name = 'Hot Bomb' description = 'Consigue explotar la bomba en\nel equipo enemigo para ganar.' @@ -469,17 +463,17 @@ def __init__(self) -> None: 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.' @@ -490,31 +484,31 @@ def __init__(self) -> None: 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]): +# ba_meta export bascenev1.GameActivity +class HotBombGame(bs.TeamGameActivity[Player, Team]): """New game.""" name = name description = description available_settings = [ - ba.IntSetting( + bs.IntSetting( 'Score to Win', min_value=1, default=5, increment=1, ), - ba.IntChoiceSetting( + bs.IntChoiceSetting( 'Time Limit', choices=[ ('None', 0), @@ -526,7 +520,7 @@ class HotBombGame(ba.TeamGameActivity[Player, Team]): ], default=0, ), - ba.FloatChoiceSetting( + bs.FloatChoiceSetting( 'Respawn Times', choices=[ ('Shorter', 0.25), @@ -536,9 +530,9 @@ class HotBombGame(ba.TeamGameActivity[Player, Team]): ('Longer', 3.0), ], default=0.5, - + ), - ba.FloatChoiceSetting( + bs.FloatChoiceSetting( difficulty, choices=[ (difficulty_o[0], 0.15), @@ -546,15 +540,15 @@ class HotBombGame(ba.TeamGameActivity[Player, Team]): (difficulty_o[2], 0.01), ], default=0.15, - + ), - ba.IntChoiceSetting( + bs.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( + ), + bs.IntChoiceSetting( num_bones, choices=[ (b_count[0], 0), @@ -562,39 +556,39 @@ class HotBombGame(ba.TeamGameActivity[Player, Team]): (b_count[2], 5), ], default=2, - + ), - ba.IntChoiceSetting( + bs.IntChoiceSetting( ball_body, choices=[(b, body.index(b)) for b in body], default=0, ), - ba.IntChoiceSetting( + bs.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, ), - ba.BoolSetting('Epic Mode', default=False), - ba.BoolSetting(space_wall, default=True), - ba.BoolSetting(bomb, default=True), - ba.BoolSetting(shield, default=False), - + bs.BoolSetting('Epic Mode', default=False), + bs.BoolSetting(space_wall, default=True), + bs.BoolSetting(bomb, default=True), + bs.BoolSetting(shield, default=False), + ] - default_music = ba.MusicType.HOCKEY + default_music = bs.MusicType.HOCKEY @classmethod - def supports_session_type(cls, sessiontype: Type[ba.Session]) -> bool: - return issubclass(sessiontype, ba.DualTeamSession) + def supports_session_type(cls, sessiontype: Type[bs.Session]) -> bool: + return issubclass(sessiontype, bs.DualTeamSession) @classmethod - def get_supported_maps(cls, sessiontype: Type[ba.Session]) -> List[str]: + def get_supported_maps(cls, sessiontype: Type[bs.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._space_under_wall = bool(settings[space_wall]) self._num_bones = int(settings[num_bones]) self._shield = bool(settings[shield]) self._bomb = bool(settings[bomb]) @@ -602,29 +596,29 @@ def __init__(self, settings: dict): 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.meshs = ['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._cheer_sound = bs.getsound('cheer') + self._chant_sound = bs.getsound('crowdChant') + self._foghorn_sound = bs.getsound('foghorn') + self._swipsound = bs.getsound('swip') + self._whistle_sound = bs.getsound('refWhistle') + self.ball_mesh = bs.getmesh(self.meshs[self._ball_body]) self.ball_body = self.bodys[self._ball_body] - self.ball_tex = ba.gettexture('powerupCurse') - self._ball_sound = ba.getsound('splatter') - + self.ball_tex = bs.gettexture('powerupCurse') + self._ball_sound = bs.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 = bs.Material() self.ball_material.add_actions(actions=(('modify_part_collision', 'friction', 0.5))) self.ball_material.add_actions(conditions=('they_have_material', @@ -641,10 +635,10 @@ def __init__(self, settings: dict): ) 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 ) ) @@ -654,67 +648,67 @@ def __init__(self, settings: dict): '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()) + ('message', 'their_node', 'at_connect', bs.DieMessage()) ) ) - - self._score_region_material = ba.Material() + + self._score_region_material = bs.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) ) ) ##### - self._check_region_material = ba.Material() + self._check_region_material = bs.Material() self._check_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._reset_count) ) ) - - self._reaction_material = ba.Material() + + self._reaction_material = bs.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=bs.Material() self._collide.add_actions( conditions=( ('they_are_different_node_than_us', ), @@ -725,24 +719,24 @@ def __init__(self, settings: dict): ('modify_part_collision', 'collide', True) ) ) - - self._wall_material = ba.Material() + + self._wall_material=bs.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 = bs.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']) @@ -761,27 +755,27 @@ def get_instance_description_short(self) -> Union[str, Sequence]: 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) + bs.timer(5,self._spawn_ball) + bs.timer(0.1,self.update_ball,repeat=True) self.add_game_complements() self.add_map_complements() self._update_scoreboard() - ba.playsound(self._chant_sound) - + self._chant_sound.play() + def _reaction(self): - node: ba.Node = ba.getcollision().opposingnode - ba.playsound(ba.getsound('hiss'), volume=0.75) - + node: bs.Node = bs.getcollision().opposingnode + bs.getsound('hiss').play(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( + + bs.emitfx( position=node.position, count=20, scale=1.5, @@ -791,116 +785,116 @@ def _reaction(self): 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 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( + part_of_wall = bs.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] + '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] } ) - wall = ba.newnode( + part_of_wall2 = bs.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 = bs.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) - ba.newnode( + pos = (0,5.3,0) + bs.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( + + bs.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 = 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'}) + #TEXT + text = bs.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) + '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) + 'w3':[ + (0,5.5,-6.1), + (19,11,1) ], - 'w4': [ - (0, 5.5, 6.5), - (19, 11, 1) + 'w4':[ + (0,5.5,6.5), + (19,11,1) ], } for i in walls_data: - w = ba.newnode( + w = bs.newnode( 'region', attrs={ 'position': walls_data[i][0], @@ -910,140 +904,138 @@ def add_map_complements(self): } ) - 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: + + def spawn_player(self, player: Player) -> bs.Actor: position = self.get_position(player) name = player.getname() - display_color = _ba.safecolor(player.color, target_intensity=0.75) + display_color = _babase.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) + bs.getsound('spawn').play(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() + collision = bs.getcollision() try: ball = collision.sourcenode.getdelegate(Ball, True) - player = collision.opposingnode.getdelegate(PlayerSpaz, True).getplayer(Player, True) - except ba.NotFoundError: + player = collision.opposingnode.getdelegate(PlayerSpaz,True).getplayer(Player, True) + except bs.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')) + + bs.getsound('laser').play() self._ball._count = self._bomb_timer self._ball._counter.text = str(self._bomb_timer) - self._ball._tick_timer = ba.Timer( + self._ball._tick_timer = bs.Timer( 1.0, - call=ba.WeakCall(self._ball._tick), + call=bs.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 - } - ) + self._ball._animate = bs.animate( + self._ball.node, + 'mesh_scale', + { + 0:self._ball.node.mesh_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 - gnode = ba.getactivity().globalsnode - + if not self._ball: return + if not self._ball.node: return + gnode = bs.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) + self._ball.node.color_texture = bs.gettexture('powerupIceBombs') + bs.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) + self._ball.node.color_texture = bs.gettexture('powerupPunch') + bs.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 @@ -1056,7 +1048,7 @@ def _handle_score(self, index=0) -> None: # Tell all players to celebrate. for player in team.players: if player.actor: - player.actor.handlemessage(ba.CelebrateMessage(2.0)) + player.actor.handlemessage(bs.CelebrateMessage(2.0)) # If we've got the player from the scoring team that last # touched us, give them points. @@ -1070,22 +1062,22 @@ def _handle_score(self, index=0) -> None: # 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) + player.actor.handlemessage(bs.DieMessage()) + + self._foghorn_sound.play() + self._cheer_sound.play() - ba.cameraflash(duration=10.0) + bs.cameraflash(duration=10.0) self._update_scoreboard() def end_game(self) -> None: - results = ba.GameResults() + results = bs.GameResults() for team in self.teams: results.set_team_score(team, team.score) self.end(results=results) @@ -1098,22 +1090,22 @@ def _update_scoreboard(self) -> None: def handlemessage(self, msg: Any) -> Any: # Respawn dead players if they're still in the game. - if isinstance(msg, ba.PlayerDiedMessage): - + if isinstance(msg, bs.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.color = (-1,-1,-1) + spaz.node.color_mask_texture = bs.gettexture('bonesColorMask') + spaz.node.color_texture = bs.gettexture('bonesColor') + spaz.node.head_mesh = bs.getmesh('bonesHead') + spaz.node.hand_mesh = bs.getmesh('bonesHand') + spaz.node.torso_mesh = bs.getmesh('bonesTorso') + spaz.node.pelvis_mesh = bs.getmesh('bonesPelvis') + spaz.node.upper_arm_mesh = bs.getmesh('bonesUpperArm') + spaz.node.forearm_mesh = bs.getmesh('bonesForeArm') + spaz.node.upper_leg_mesh = bs.getmesh('bonesUpperLeg') + spaz.node.lower_leg_mesh = bs.getmesh('bonesLowerLeg') + spaz.node.toes_mesh = bs.getmesh('bonesToes') spaz.node.style = 'bones' # Augment standard behavior... super().handlemessage(msg) @@ -1124,58 +1116,57 @@ def handlemessage(self, msg: Any) -> Any: if not self.has_ended(): try: if self._ball._count == 1: - ba.timer(3.0, self._spawn_ball) + bs.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', + def _flash_ball_spawn(self,pos,color=(1,0,0)) -> None: + light = bs.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) + bs.animate(light, 'intensity', {0.0: 0, 0.25: 0.2, 0.5: 0}, loop=True) + bs.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) + self._swipsound.play() + self._whistle_sound.play() + 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) - self._ball.node.color_texture = ba.gettexture(texture) + 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 = bs.gettexture(texture) self._ball._counter.color = counter_color - - def get_position(self, player: Player) -> ba.Actor: - position = (0, 1, 0) + + def get_position(self, player: Player) -> bs.Actor: + 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 - + from babase._general import WeakCall + assert player if respawn_time is None: respawn_time = 3.0 @@ -1189,62 +1180,59 @@ def respawn_player(self, 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( + from bascenev1lib.actor.respawnicon import RespawnIcon + player.customdata['respawn_timer'] = _bs.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. + bs.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) + 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): - +class NewBomb(bs.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): - + source_player: bs.Player = None, + owner: bs.Node = None): + super().__init__() - + shared = SharedObjects.get() # Material for powerups. - self.bomb_material = ba.Material() - self.explode_material = ba.Material() - + self.bomb_material = bs.Material() + self.explode_material = bs.Material() + self.bomb_material.add_actions( conditions=( ('we_are_older_than', 200), @@ -1260,63 +1248,64 @@ def __init__(self, position: Sequence[float] = (0, 1, 0), ), ), 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={ + self.node: bs.Node = bs.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, + 'color_texture': bs.gettexture('powerupBomb'), + 'mesh': bs.getmesh('penguinTorso'), + 'mesh_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) - + 'materials': (shared.object_material,self.bomb_material)}) + + bs.animate(self.node,'mesh_scale',{0:0,0.2:1,0.26:0.7}) + self.light = bs.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: bs.Timer = bs.Timer( + 10.0,self._check,repeat=True) + def _impact(self) -> None: - node = ba.getcollision().opposingnode + node = bs.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( + self.explode_region = bs.newnode( 'region', delegate=self, attrs={ @@ -1327,37 +1316,38 @@ def _explode(self): }, ) 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())) - + bs.getsound('stickyImpact').play(volume=0.35) + a = bs.emitfx(position=self.node.position, + velocity=(0,1,0), + count=15, + scale=1.0, + spread=0.1, + chunk_type='spark') + scorch = bs.newnode('scorch', + attrs={ + 'position': self.node.position, + 'size': 1.0, + 'big': False, + 'color':(1,1,0) + }) + + bs.animate(scorch,'size',{0:1.0,5:0}) + bs.timer(5,scorch.delete) + + + bs.timer(0.05, self.explode_region.delete) + bs.timer(0.001, bs.WeakCall(self.handlemessage, bs.DieMessage())) + def _touch_player(self): - node = ba.getcollision().opposingnode - collision = ba.getcollision() + node = bs.getcollision().opposingnode + collision = bs.getcollision() try: player = collision.opposingnode.getdelegate(PlayerSpaz, True).getplayer( Player, True) - except ba.NotFoundError: + except bs.NotFoundError: return - + if self.bomb_type == 'banana': color = player.team.color owner_team = self.owner.source_player._team @@ -1366,9 +1356,8 @@ def _touch_player(self): 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}) - + bs.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.""" @@ -1377,18 +1366,16 @@ def handlemessage(self, msg): self._explode() elif isinstance(msg, ImpactMessage): self._impact() - elif isinstance(msg, ba.DieMessage): + elif isinstance(msg, bs.DieMessage): if self.node: self.node.delete() - elif isinstance(msg, ba.OutOfBoundsMessage): + elif isinstance(msg, bs.OutOfBoundsMessage): if self.node: self.node.delete() - -###### Object##### - - + +######Object##### class HealthFactory: - """Wraps up media and other resources used by ba.Bombs. + """Wraps up media and other resources used by bs.Bombs. category: Gameplay Classes @@ -1397,32 +1384,34 @@ class HealthFactory: Attributes: - health_model - The ba.Model of a standard health. - + health_mesh + The bs.mesh of a standard health. + health_tex - The ba.Texture for health. + The bs.Texture for health. activate_sound - A ba.Sound for an activating ??. + A bs.Sound for an activating ??. health_material - A ba.Material applied to health. + A bs.Material applied to health. """ - _STORENAME = ba.storagename() + _STORENAME = bs.storagename() @classmethod def get(cls) -> HealthFactory: """Get/create a shared EggFactory object.""" - activity = ba.getactivity() + activity = bs.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. @@ -1430,16 +1419,16 @@ def __init__(self) -> None: 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') - + + self.health_mesh = bs.getmesh('egg') + + self.health_tex = bs.gettexture('eggTex1') + + self.health_sound = bs.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 = bs.Material() self.health_material.add_actions( conditions=( @@ -1462,205 +1451,199 @@ def __init__(self) -> None: ) self.health_material.add_actions(actions=('modify_part_collision', - 'friction', 0.3)) - - -class HealthBox(ba.Actor): + 'friction', 0.3)) +class HealthBox(bs.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 = bs.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) ) ) - self.node: ba.Node = ba.newnode('prop', delegate=self, attrs={ + self.node: bs.Node = bs.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, + 'color_texture': bs.gettexture(texture), + 'mesh': bs.getmesh('powerup'), + 'light_mesh':bs.getmesh('powerupSimple'), + 'mesh_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)}) - - 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) + 'materials': (shared.object_material,self.healthbox_material,factory.health_material)}) + + self.light = bs.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: bs.Timer = bs.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 isinstance(msg, bs.DieMessage): if self.node: self.node.delete() - elif isinstance(msg, ba.OutOfBoundsMessage): + elif isinstance(msg, bs.OutOfBoundsMessage): if self.node: self.node.delete() - elif isinstance(msg, ba.HitMessage): + elif isinstance(msg, bs.HitMessage): try: spaz = msg._source_player - spaz.actor.node.handlemessage(ba.PowerupMessage(poweruptype='health')) + spaz.actor.node.handlemessage(bs.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}) + bs.getsound('healthPowerup').play(volume=0.5) + bs.animate(self.light,'radius',{0:0.0,0.1:0.2,0.7:0}) except: pass - elif isinstance(msg, ba.DroppedMessage): + elif isinstance(msg, bs.DroppedMessage): spaz = msg.node.getdelegate(PlayerSpaz) self.regen_timer = None - -class Torso(ba.Actor): - +class Torso(bs.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={ + self.node: bs.Node = bs.newnode('prop', delegate=self, attrs={ 'position': position, 'velocity': velocity, - 'color_texture': ba.gettexture(texture), - 'model': ba.getmodel('bonesTorso'), - 'model_scale': 1, + 'color_texture': bs.gettexture(texture), + 'mesh': bs.getmesh('bonesTorso'), + 'mesh_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) + + self.spawn: bs.Timer = bs.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 isinstance(msg, bs.DieMessage): if self.node: self.node.delete() - elif isinstance(msg, ba.OutOfBoundsMessage): + elif isinstance(msg, bs.OutOfBoundsMessage): if self.node: self.node.delete() - -class Bone(ba.Actor): - +class Bone(bs.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'] + meshs = ['bonesUpperArm','bonesUpperLeg','bonesForeArm','bonesPelvis','bonesToes','bonesHand'] bone = None - model = 0 - for i in models: - if model == style: - bone = models[model] + mesh = 0 + for i in meshs: + if mesh == style: + bone = meshs[mesh] else: - model += 1 - self.node: ba.Node = ba.newnode('prop', delegate=self, attrs={ + mesh += 1 + self.node: bs.Node = bs.newnode('prop', delegate=self, attrs={ 'position': position, 'velocity': velocity, - 'color_texture': ba.gettexture(texture), - 'model': ba.getmodel(bone), - 'model_scale': 1.5, + 'color_texture': bs.gettexture(texture), + 'mesh': bs.getmesh(bone), + 'mesh_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) + + self.spawn: bs.Timer = bs.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 isinstance(msg, bs.DieMessage): if self.node: self.node.delete() - elif isinstance(msg, ba.OutOfBoundsMessage): + elif isinstance(msg, bs.OutOfBoundsMessage): if self.node: self.node.delete() - -###### Object##### - - -class Box(ba.Actor): - + +######Object##### +class Box(bs.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=bs.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) ) ) - self.node: ba.Node = ba.newnode('prop', delegate=self, attrs={ + self.node: bs.Node = bs.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, + 'color_texture': bs.gettexture(texture), + 'mesh': bs.getmesh('powerup'), + 'light_mesh': bs.getmesh('powerupSimple'), + 'mesh_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,]}) + 'materials': [self.dont_collide,]}) \ No newline at end of file From 0069f15d8501e81d1f4c9c00e89db0e9f71bc44d Mon Sep 17 00:00:00 2001 From: SEBASTIAN2059 Date: Thu, 8 Jun 2023 03:40:59 +0000 Subject: [PATCH 0494/1464] [ci] auto-format --- plugins/minigames/hot_bomb.py | 929 +++++++++++++++++----------------- 1 file changed, 474 insertions(+), 455 deletions(-) diff --git a/plugins/minigames/hot_bomb.py b/plugins/minigames/hot_bomb.py index ece91f91..ba68c09b 100644 --- a/plugins/minigames/hot_bomb.py +++ b/plugins/minigames/hot_bomb.py @@ -28,35 +28,38 @@ 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(bs.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 = bs.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()), ), ) - + bs.getsound('scamper01').play(volume=0.4) # Spawn just above the provided point. self._spawn_pos = (position[0], position[1] + 1.0, position[2]) @@ -72,36 +75,36 @@ def __init__(self, position: Sequence[float] = (0.0, 1.0, 0.0),timer: int = 5,d_ '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 = bs.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 = bs.Timer(0.1,call=bs.WeakCall(self.particles),repeat=True) - self._sound_effect = bs.Timer(4,call=bs.WeakCall(self.sound_effect),repeat=True) + + self._particles = bs.Timer(0.1, call=bs.WeakCall(self.particles), repeat=True) + self._sound_effect = bs.Timer(4, call=bs.WeakCall(self.sound_effect), repeat=True) self.d_time = d_time - + if timer is not None: timer = int(timer) self._timer = timer @@ -111,102 +114,103 @@ def __init__(self, position: Sequence[float] = (0.0, 1.0, 0.0),timer: int = 5,d_ self._tick_timer = bs.Timer(1.0, call=bs.WeakCall(self._tick), repeat=True) - m = bs.newnode('math', owner=self.node, attrs={'input1': (0, 0.6, 0), 'operation': 'add'}) + m = bs.newnode('math', owner=self.node, attrs={ + 'input1': (0, 0.6, 0), 'operation': 'add'}) self.node.connectattr('position', m, 'input2') self._counter = bs.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: bs.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: bs.getsound('scamper01').play(volume=0.4) - - - def explode(self,color=(3,1,0)) -> None: - sound = random.choice(['explosion01','explosion02','explosion03','explosion04','explosion05']) + + def explode(self, color=(3, 1, 0)) -> None: + sound = random.choice(['explosion01', 'explosion02', + 'explosion03', 'explosion04', 'explosion05']) bs.getsound(sound).play(volume=1) bs.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 = bs.newnode( - 'explosion', - attrs={ - 'position': self.node.position, - 'velocity': (0,0,0), - 'radius': 2.0, - 'big': False, - 'color':color - } - ) - bs.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 + } + ) + bs.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 = bs.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 = bs.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 + }, + ) bs.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: @@ -216,53 +220,54 @@ def _tick(self) -> None: bs.getsound('tick').play() if self._count == 1: self._animate = bs.animate( - self.node, - 'mesh_scale', - { - 0:self.node.mesh_scale, - 0.1:1.5, - 0.2:self.scale - }, - loop=True - ) + self.node, + 'mesh_scale', + { + 0: self.node.mesh_scale, + 0.1: 1.5, + 0.2: self.scale + }, + loop=True + ) self.animate_light = bs.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 = bs.animate( - self.node, - 'mesh_scale', - { - 0:self.node.mesh_scale, - 0.5:1.5, - 1.0:self.scale - }, - loop=True - ) + self.node, + 'mesh_scale', + { + 0: self.node.mesh_scale, + 0.5: 1.5, + 1.0: self.scale + }, + loop=True + ) self.animate_light = bs.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, bs.DieMessage): - if not self.node: return + if not self.node: + return self.node.delete() activity = self._activity() if activity and not msg.immediate: @@ -275,11 +280,13 @@ def handlemessage(self, msg: Any) -> Any: elif isinstance(msg, bs.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(bs.DroppedMessage(spaz.node)) if spaz.hitpoints > 10000: @@ -323,51 +330,54 @@ def damage(): if activity: if s_player in activity.players: self.last_players_to_touch[s_player.team.id] = s_player - + elif isinstance(msg, ExplodeHitMessage): node = bs.getcollision().opposingnode - if not self.node: return + if not self.node: + return nodepos = self.region.position mag = 2000.0 - + node.handlemessage( bs.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(bs.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) - bs.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) + bs.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 @@ -381,15 +391,15 @@ def drop_bomb(self) -> Optional[Bomb]: else: dropping_bomb = True bomb_type = self.bomb_type - + if bomb_type == 'banana': bs.getsound('penguinHit1').play(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]), @@ -397,7 +407,6 @@ def drop_bomb(self) -> Optional[Bomb]: blast_radius=self.blast_radius, source_player=self.source_player, owner=self.node).autoretain() - assert bomb.node if dropping_bomb: @@ -405,24 +414,24 @@ def drop_bomb(self) -> Optional[Bomb]: bomb.node.add_death_action( bs.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: @@ -434,13 +443,13 @@ def handlemessage(self, msg: Any) -> Any: except bs.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(bs.Player['Team']): """Our player type for this game.""" @@ -463,17 +472,17 @@ def __init__(self) -> None: 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.' @@ -484,16 +493,16 @@ def __init__(self) -> None: 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 bascenev1.GameActivity class HotBombGame(bs.TeamGameActivity[Player, Team]): @@ -530,7 +539,7 @@ class HotBombGame(bs.TeamGameActivity[Player, Team]): ('Longer', 3.0), ], default=0.5, - + ), bs.FloatChoiceSetting( difficulty, @@ -540,14 +549,14 @@ class HotBombGame(bs.TeamGameActivity[Player, Team]): (difficulty_o[2], 0.01), ], default=0.15, - + ), bs.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, - ), + ), bs.IntChoiceSetting( num_bones, choices=[ @@ -556,7 +565,7 @@ class HotBombGame(bs.TeamGameActivity[Player, Team]): (b_count[2], 5), ], default=2, - + ), bs.IntChoiceSetting( ball_body, @@ -565,7 +574,7 @@ class HotBombGame(bs.TeamGameActivity[Player, Team]): ), bs.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, ), @@ -573,7 +582,7 @@ class HotBombGame(bs.TeamGameActivity[Player, Team]): bs.BoolSetting(space_wall, default=True), bs.BoolSetting(bomb, default=True), bs.BoolSetting(shield, default=False), - + ] default_music = bs.MusicType.HOCKEY @@ -588,7 +597,7 @@ def get_supported_maps(cls, sessiontype: Type[bs.Session]) -> List[str]: 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]) @@ -596,10 +605,10 @@ def __init__(self, settings: dict): 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.meshs = ['bombSticky','powerupSimple'] - + + self.bodys = ['sphere', 'crate'] + self.meshs = ['bombSticky', 'powerupSimple'] + shared = SharedObjects.get() self._scoreboard = Scoreboard() self._cheer_sound = bs.getsound('cheer') @@ -611,13 +620,13 @@ def __init__(self, settings: dict): self.ball_body = self.bodys[self._ball_body] self.ball_tex = bs.gettexture('powerupCurse') self._ball_sound = bs.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 = bs.Material() self.ball_material.add_actions(actions=(('modify_part_collision', 'friction', 0.5))) @@ -635,10 +644,10 @@ def __init__(self, settings: dict): ) 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 ) ) @@ -648,27 +657,27 @@ def __init__(self, settings: dict): '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', bs.DieMessage()) ) ) - + self._score_region_material = bs.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) ) @@ -680,35 +689,35 @@ def __init__(self, settings: dict): '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 = bs.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=bs.Material() + + self._collide = bs.Material() self._collide.add_actions( conditions=( ('they_are_different_node_than_us', ), @@ -719,24 +728,24 @@ def __init__(self, settings: dict): ('modify_part_collision', 'collide', True) ) ) - - self._wall_material=bs.Material() + + self._wall_material = bs.Material() self._wall_material.add_actions( conditions=( 'we_are_older_than', 1 - ), + ), actions=( ('modify_part_collision', 'collide', True) ) ) - + self.ice_material = bs.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']) @@ -755,26 +764,26 @@ def get_instance_description_short(self) -> Union[str, Sequence]: 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) - bs.timer(5,self._spawn_ball) - bs.timer(0.1,self.update_ball,repeat=True) + self._ball_spawn_pos = (random.choice([-5, 5]), 4, 0) + bs.timer(5, self._spawn_ball) + bs.timer(0.1, self.update_ball, repeat=True) self.add_game_complements() self.add_map_complements() self._update_scoreboard() self._chant_sound.play() - + def _reaction(self): node: bs.Node = bs.getcollision().opposingnode bs.getsound('hiss').play(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] ) - + bs.emitfx( position=node.position, count=20, @@ -785,21 +794,21 @@ def _reaction(self): 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 @@ -809,88 +818,88 @@ def add_game_complements(self): part_of_wall = bs.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 = bs.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 = bs.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) bs.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] } ) - + bs.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 = bs.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: @@ -904,72 +913,72 @@ def add_map_complements(self): } ) - 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) -> bs.Actor: position = self.get_position(player) name = player.getname() display_color = _babase.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))) bs.getsound('spawn').play(volume=0.6) return actor - + def on_team_join(self, team: Team) -> None: self._update_scoreboard() @@ -977,7 +986,7 @@ def _handle_ball_player_collide(self) -> None: collision = bs.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 bs.NotFoundError: return @@ -985,15 +994,15 @@ def _handle_ball_player_collide(self) -> None: 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 - + bs.getsound('laser').play() self._ball._count = self._bomb_timer self._ball._counter.text = str(self._bomb_timer) @@ -1003,39 +1012,41 @@ def _reset_count(self) -> None: repeat=True ) self._ball._animate = bs.animate( - self._ball.node, - 'mesh_scale', - { - 0:self._ball.node.mesh_scale, - 0.1:self._ball.scale - } - ) + self._ball.node, + 'mesh_scale', + { + 0: self._ball.node.mesh_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 = bs.getactivity().globalsnode - + if self._ball.node.position[0] > 0: self._ball.node.color_texture = bs.gettexture('powerupIceBombs') - bs.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) + bs.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 = bs.gettexture('powerupPunch') - bs.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) + bs.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 @@ -1062,14 +1073,14 @@ def _handle_score(self,index=0) -> None: # 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(bs.DieMessage()) - + self._foghorn_sound.play() self._cheer_sound.play() @@ -1091,10 +1102,10 @@ def handlemessage(self, msg: Any) -> Any: # Respawn dead players if they're still in the game. if isinstance(msg, bs.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 = bs.gettexture('bonesColorMask') spaz.node.color_texture = bs.gettexture('bonesColor') spaz.node.head_mesh = bs.getmesh('bonesHead') @@ -1122,7 +1133,7 @@ def handlemessage(self, msg: Any) -> Any: 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 = bs.newnode('light', attrs={ 'position': pos, @@ -1136,37 +1147,37 @@ def _spawn_ball(self) -> None: timer = self._bomb_timer self._swipsound.play() self._whistle_sound.play() - 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 = bs.gettexture(texture) self._ball._counter.color = counter_color - + def get_position(self, player: Player) -> bs.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: from babase._general import WeakCall - + assert player if respawn_time is None: respawn_time = 3.0 @@ -1185,7 +1196,7 @@ def respawn_player(self, 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 @@ -1196,43 +1207,46 @@ def spawn_player_if_exists(self, player: PlayerType) -> None: 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(bs.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: bs.Player = None, owner: bs.Node = None): - + super().__init__() - + shared = SharedObjects.get() # Material for powerups. self.bomb_material = bs.Material() self.explode_material = bs.Material() - + self.bomb_material.add_actions( conditions=( ('we_are_older_than', 200), @@ -1248,48 +1262,48 @@ def __init__(self, position: Sequence[float] = (0, 1, 0), ), ), 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: bs.Node = bs.newnode('prop', delegate=self, attrs={ 'position': position, 'velocity': velocity, 'color_texture': bs.gettexture('powerupBomb'), 'mesh': bs.getmesh('penguinTorso'), - 'mesh_scale':0.7, - 'body_scale':0.7, - 'density':3, + 'mesh_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)}) - - bs.animate(self.node,'mesh_scale',{0:0,0.2:1,0.26:0.7}) + 'materials': (shared.object_material, self.bomb_material)}) + + bs.animate(self.node, 'mesh_scale', {0: 0, 0.2: 1, 0.26: 0.7}) self.light = bs.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: bs.Timer = bs.Timer( - 10.0,self._check,repeat=True) - + 10.0, self._check, repeat=True) + def _impact(self) -> None: node = bs.getcollision().opposingnode node_delegate = node.getdelegate(object) @@ -1297,12 +1311,11 @@ def _impact(self) -> None: 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 = bs.newnode( @@ -1318,26 +1331,25 @@ def _explode(self): if self.bomb_type == 'banana': bs.getsound('stickyImpact').play(volume=0.35) a = bs.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 = bs.newnode('scorch', - attrs={ - 'position': self.node.position, - 'size': 1.0, - 'big': False, - 'color':(1,1,0) - }) - - bs.animate(scorch,'size',{0:1.0,5:0}) - bs.timer(5,scorch.delete) - + attrs={ + 'position': self.node.position, + 'size': 1.0, + 'big': False, + 'color': (1, 1, 0) + }) + + bs.animate(scorch, 'size', {0: 1.0, 5: 0}) + bs.timer(5, scorch.delete) bs.timer(0.05, self.explode_region.delete) bs.timer(0.001, bs.WeakCall(self.handlemessage, bs.DieMessage())) - + def _touch_player(self): node = bs.getcollision().opposingnode collision = bs.getcollision() @@ -1347,7 +1359,7 @@ def _touch_player(self): Player, True) except bs.NotFoundError: return - + if self.bomb_type == 'banana': color = player.team.color owner_team = self.owner.source_player._team @@ -1356,8 +1368,9 @@ def _touch_player(self): if player.team == owner_team: return player.actor.node.handlemessage('knockout', 500.0) - bs.animate_array(player.actor.node,'color',3,{0:color,0.1:(1.5,1,0),0.5:(1.5,1,0),0.6:color}) - + bs.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.""" @@ -1372,8 +1385,10 @@ def handlemessage(self, msg): elif isinstance(msg, bs.OutOfBoundsMessage): if self.node: self.node.delete() - -######Object##### + +###### Object##### + + class HealthFactory: """Wraps up media and other resources used by bs.Bombs. @@ -1386,7 +1401,7 @@ class HealthFactory: health_mesh The bs.mesh of a standard health. - + health_tex The bs.Texture for health. @@ -1409,9 +1424,7 @@ def get(cls) -> HealthFactory: activity.customdata[cls._STORENAME] = factory assert isinstance(factory, HealthFactory) return factory - - - + def __init__(self) -> None: """Instantiate a BombFactory. @@ -1419,13 +1432,13 @@ def __init__(self) -> None: to get a shared instance. """ shared = SharedObjects.get() - + self.health_mesh = bs.getmesh('egg') - + self.health_tex = bs.gettexture('eggTex1') - + self.health_sound = bs.getsound('activateBeep') - + # Set up our material so new bombs don't collide with objects # that they are initially overlapping. self.health_material = bs.Material() @@ -1451,21 +1464,22 @@ def __init__(self) -> None: ) self.health_material.add_actions(actions=('modify_part_collision', - 'friction', 0.3)) + 'friction', 0.3)) + class HealthBox(bs.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 = bs.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) @@ -1476,27 +1490,27 @@ def __init__(self, position: Sequence[float] = (0, 1, 0), 'velocity': velocity, 'color_texture': bs.gettexture(texture), 'mesh': bs.getmesh('powerup'), - 'light_mesh':bs.getmesh('powerupSimple'), - 'mesh_scale':1, + 'light_mesh': bs.getmesh('powerupSimple'), + 'mesh_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 = bs.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: bs.Timer = bs.Timer( - 10.0,self._check,repeat=True) + 10.0, self._check, repeat=True) def _check(self) -> None: """Prevent the cube from annihilating.""" @@ -1516,7 +1530,7 @@ def handlemessage(self, msg): t_color = spaz.team.color spaz.actor.node.color = t_color bs.getsound('healthPowerup').play(volume=0.5) - bs.animate(self.light,'radius',{0:0.0,0.1:0.2,0.7:0}) + bs.animate(self.light, 'radius', {0: 0.0, 0.1: 0.2, 0.7: 0}) except: pass @@ -1524,13 +1538,14 @@ def handlemessage(self, msg): spaz = msg.node.getdelegate(PlayerSpaz) self.regen_timer = None + class Torso(bs.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: bs.Node = bs.newnode('prop', delegate=self, attrs={ @@ -1538,19 +1553,19 @@ def __init__(self, position: Sequence[float] = (0, 1, 0), 'velocity': velocity, 'color_texture': bs.gettexture(texture), 'mesh': bs.getmesh('bonesTorso'), - 'mesh_scale':1, + 'mesh_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: bs.Timer = bs.Timer( - 10.0,self._check,repeat=True) + 10.0, self._check, repeat=True) def _check(self) -> None: """Prevent the cube from annihilating.""" @@ -1564,16 +1579,18 @@ def handlemessage(self, msg): if self.node: self.node.delete() + class Bone(bs.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() - meshs = ['bonesUpperArm','bonesUpperLeg','bonesForeArm','bonesPelvis','bonesToes','bonesHand'] + meshs = ['bonesUpperArm', 'bonesUpperLeg', 'bonesForeArm', + 'bonesPelvis', 'bonesToes', 'bonesHand'] bone = None mesh = 0 for i in meshs: @@ -1586,19 +1603,19 @@ def __init__(self, position: Sequence[float] = (0, 1, 0), 'velocity': velocity, 'color_texture': bs.gettexture(texture), 'mesh': bs.getmesh(bone), - 'mesh_scale':1.5, + 'mesh_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: bs.Timer = bs.Timer( - 10.0,self._check,repeat=True) + 10.0, self._check, repeat=True) def _check(self) -> None: """Prevent the cube from annihilating.""" @@ -1611,20 +1628,22 @@ def handlemessage(self, msg): elif isinstance(msg, bs.OutOfBoundsMessage): if self.node: self.node.delete() - -######Object##### + +###### Object##### + + class Box(bs.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=bs.Material() + self.dont_collide = bs.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) @@ -1637,13 +1656,13 @@ def __init__(self, position: Sequence[float] = (0, 1, 0), 'color_texture': bs.gettexture(texture), 'mesh': bs.getmesh('powerup'), 'light_mesh': bs.getmesh('powerupSimple'), - 'mesh_scale':4, + 'mesh_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 c04227a1be73ff3e0ee617b638a1b86d52516801 Mon Sep 17 00:00:00 2001 From: SEBASTIAN2059 Date: Thu, 8 Jun 2023 03:41:00 +0000 Subject: [PATCH 0495/1464] [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 2fe881df..bcdd1012 100644 --- a/plugins/minigames.json +++ b/plugins/minigames.json @@ -266,7 +266,12 @@ } ], "versions": { - "1.1.0":null, + "1.1.0": { + "api_version": 8, + "commit_sha": "65d5d6f", + "released_on": "08-06-2023", + "md5sum": "b8168bd3e6fae96b9339a727bd50842f" + }, "1.0.0": { "api_version": 7, "commit_sha": "095a773", From 62dcd314a182e2bed1b0587dc89639af0b3a8f26 Mon Sep 17 00:00:00 2001 From: Rikko Date: Fri, 9 Jun 2023 02:12:35 +0530 Subject: [PATCH 0496/1464] Rename babase.GameActivity -> bascenev1.GameActivity --- plugin_manager.py | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/plugin_manager.py b/plugin_manager.py index 3a3f9265..60bb44e6 100644 --- a/plugin_manager.py +++ b/plugin_manager.py @@ -561,11 +561,11 @@ def load_minigames(self): pathlib.Path(directory), pathlib.Path(module), ) - scanned_results = set(babase.app.meta.scanresults.exports["babase.GameActivity"]) - for game in scanner.results.exports["babase.GameActivity"]: + scanned_results = set(babase.app.meta.scanresults.exports["bascenev1.GameActivity"]) + for game in scanner.results.exports["bascenev1.GameActivity"]: if game not in scanned_results: bui.screenmessage(f"{game} minigame loaded") - babase.app.meta.scanresults.exports["babase.GameActivity"].append(game) + babase.app.meta.scanresults.exports["bascenev1.GameActivity"].append(game) def unload_minigames(self): scanner = babase._meta.DirectoryScan(paths="") @@ -575,12 +575,12 @@ def unload_minigames(self): pathlib.Path(module), ) new_scanned_results_games = [] - for game in babase.app.meta.scanresults.exports["babase.GameActivity"]: - if game in scanner.results.exports["babase.GameActivity"]: + for game in babase.app.meta.scanresults.exports["bascenev1.GameActivity"]: + if game in scanner.results.exports["bascenev1.GameActivity"]: bui.screenmessage(f"{game} minigame unloaded") else: new_scanned_results_games.append(game) - babase.app.meta.scanresults.exports["babase.GameActivity"] = new_scanned_results_games + babase.app.meta.scanresults.exports["bascenev1.GameActivity"] = new_scanned_results_games async def is_enabled(self): """ From ae96baa3ab8cd167c4673e3c05c928fd967ff1e3 Mon Sep 17 00:00:00 2001 From: rikkolovescats Date: Tue, 20 Jun 2023 18:59:17 +0000 Subject: [PATCH 0497/1464] [ci] apply-version-metadata --- index.json | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/index.json b/index.json index 5d7f5a8c..2e548363 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": { - "1.0.0": null, + "1.0.0": { + "api_version": 8, + "commit_sha": "62dcd31", + "released_on": "20-06-2023", + "md5sum": "b3e0b34d92e192cc2e9af33c025a6aac" + }, "0.3.5": { "api_version": 7, "commit_sha": "985e486", @@ -105,4 +110,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 4cb7d218d0fbef58dd772c3b398ea918ed9ea12c Mon Sep 17 00:00:00 2001 From: Rikko Date: Wed, 21 Jun 2023 00:33:31 +0530 Subject: [PATCH 0498/1464] New build version changes --- index.json | 9 ++------- plugin_manager.py | 44 ++++++++++++++++++++++---------------------- 2 files changed, 24 insertions(+), 29 deletions(-) diff --git a/index.json b/index.json index 2e548363..5d7f5a8c 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": { - "1.0.0": { - "api_version": 8, - "commit_sha": "62dcd31", - "released_on": "20-06-2023", - "md5sum": "b3e0b34d92e192cc2e9af33c025a6aac" - }, + "1.0.0": null, "0.3.5": { "api_version": 7, "commit_sha": "985e486", @@ -110,4 +105,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 60bb44e6..56716cda 100644 --- a/plugin_manager.py +++ b/plugin_manager.py @@ -28,7 +28,7 @@ import logging _env = _babase.env() -_uiscale = bui.app.classic.ui.uiscale +_uiscale = bui.app.ui_v1.uiscale PLUGIN_MANAGER_VERSION = "1.0.0" @@ -38,7 +38,7 @@ CURRENT_TAG = "main" INDEX_META = "{repository_url}/{content_type}/{tag}/index.json" HEADERS = { - "User-Agent": _env["user_agent_string"], + "User-Agent": _env["legacy_user_agent_string"], } PLUGIN_DIRECTORY = _env["python_directory_user"] def _regexp_friendly_class_name_shortcut(string): return string.replace(".", "\.") @@ -1003,7 +1003,7 @@ async def draw_ui(self): size=(40, 40), button_type="square", label="", - # color=bui.app.classic.ui.title_color, + # color=bui.app.ui_v1.title_color, color=(0.6, 0.53, 0.63), on_activate_call=lambda: bui.open_url(self.plugin.view_url)) bui.imagewidget(parent=self._root_widget, @@ -1040,7 +1040,7 @@ def tutorial_confirm_window(): size=(40, 40), button_type="square", label="", - # color=bui.app.classic.ui.title_color, + # color=bui.app.ui_v1.title_color, color=(0.6, 0.53, 0.63), on_activate_call=tutorial_confirm_window) @@ -1280,7 +1280,7 @@ def __init__(self, origin_widget): position=(155, 300), size=(100, 25), text="Custom Plugin Sources", - color=bui.app.classic.ui.title_color, + color=bui.app.ui_v1.title_color, scale=0.8, h_align="center", v_align="center", @@ -1522,7 +1522,7 @@ def __init__(self, transition: str = "in_right", origin_widget: bui.Widget = Non position=(-10, title_pos), size=(self._width, 25), text="Community Plugin Manager", - color=bui.app.classic.ui.title_color, + color=bui.app.ui_v1.title_color, scale=1.05, h_align="center", v_align="center", @@ -1537,7 +1537,7 @@ def __init__(self, transition: str = "in_right", origin_widget: bui.Widget = Non position=(-5, loading_pos_y), size=(self._width, 25), text="Loading...", - color=bui.app.classic.ui.title_color, + color=bui.app.ui_v1.title_color, scale=0.7, h_align="center", v_align="center", @@ -1548,7 +1548,7 @@ def _back(self) -> None: from bauiv1lib.settings.allsettings import AllSettingsWindow bui.containerwidget(edit=self._root_widget, transition=self._transition_out) - bui.app.classic.ui.set_main_menu_window( + bui.app.ui_v1.set_main_menu_window( AllSettingsWindow(transition='in_left').get_root_widget()) @contextlib.contextmanager @@ -1647,7 +1647,7 @@ def draw_search_bar(self): selectable=False, h_align='left', v_align='center', - color=bui.app.classic.ui.title_color, + color=bui.app.ui_v1.title_color, scale=0.5) filter_txt = babase.Lstr(resource='filterText') @@ -1920,7 +1920,7 @@ async def draw_ui(self): v_align='center', text=setting_title, scale=text_scale, - color=bui.app.classic.ui.title_color, + color=bui.app.ui_v1.title_color, maxwidth=width * 0.9) pos -= 20 @@ -2140,7 +2140,7 @@ def __init__( ) ) - if bui.app.classic.ui.use_toolbars and _uiscale is bui.UIScale.SMALL: + if bui.app.ui_v1.use_toolbars and _uiscale is bui.UIScale.SMALL: self._back_button = None bui.containerwidget( edit=self._root_widget, on_cancel_call=self._do_back @@ -2164,7 +2164,7 @@ def __init__( position=(0, height - 44), size=(width, 25), text=bui.Lstr(resource=self._r + '.titleText'), - color=bui.app.classic.ui.title_color, + color=bui.app.ui_v1.title_color, h_align='center', v_align='center', maxwidth=130, @@ -2216,7 +2216,7 @@ def _b_title( label='', on_activate_call=self._do_controllers, ) - if bui.app.classic.ui.use_toolbars and self._back_button is None: + if bui.app.ui_v1.use_toolbars and self._back_button is None: bbtn = bui.get_special_widget('back_button') bui.widget(edit=ctb, left_widget=bbtn) _b_title( @@ -2240,7 +2240,7 @@ def _b_title( label='', on_activate_call=self._do_graphics, ) - if bui.app.classic.ui.use_toolbars: + if bui.app.ui_v1.use_toolbars: pbtn = bui.get_special_widget('party_button') bui.widget(edit=gfxb, up_widget=pbtn, right_widget=pbtn) _b_title(x_offs3, v, gfxb, bui.Lstr(resource=self._r + '.graphicsText')) @@ -2333,7 +2333,7 @@ def _do_back(self) -> None: edit=self._root_widget, transition=self._transition_out ) assert bui.app.classic is not None - bui.app.classic.ui.set_main_menu_window( + bui.app.ui_v1.set_main_menu_window( MainMenuWindow(transition='in_left').get_root_widget() ) @@ -2344,7 +2344,7 @@ def _do_controllers(self) -> None: self._save_state() bui.containerwidget(edit=self._root_widget, transition='out_left') assert bui.app.classic is not None - bui.app.classic.ui.set_main_menu_window( + bui.app.ui_v1.set_main_menu_window( ControlsSettingsWindow( origin_widget=self._controllers_button ).get_root_widget() @@ -2357,7 +2357,7 @@ def _do_graphics(self) -> None: self._save_state() bui.containerwidget(edit=self._root_widget, transition='out_left') assert bui.app.classic is not None - bui.app.classic.ui.set_main_menu_window( + bui.app.ui_v1.set_main_menu_window( GraphicsSettingsWindow( origin_widget=self._graphics_button ).get_root_widget() @@ -2370,7 +2370,7 @@ def _do_audio(self) -> None: self._save_state() bui.containerwidget(edit=self._root_widget, transition='out_left') assert bui.app.classic is not None - bui.app.classic.ui.set_main_menu_window( + bui.app.ui_v1.set_main_menu_window( AudioSettingsWindow( origin_widget=self._audio_button ).get_root_widget() @@ -2383,7 +2383,7 @@ def _do_advanced(self) -> None: self._save_state() bui.containerwidget(edit=self._root_widget, transition='out_left') assert bui.app.classic is not None - bui.app.classic.ui.set_main_menu_window( + bui.app.ui_v1.set_main_menu_window( AdvancedSettingsWindow( origin_widget=self._advanced_button ).get_root_widget() @@ -2392,7 +2392,7 @@ def _do_advanced(self) -> None: def _do_modmanager(self) -> None: self._save_state() bui.containerwidget(edit=self._root_widget, transition="out_left") - bui.app.classic.ui.set_main_menu_window( + bui.app.ui_v1.set_main_menu_window( PluginManagerWindow( origin_widget=self._modmgr_button ).get_root_widget() @@ -2416,7 +2416,7 @@ def _save_state(self) -> None: else: raise ValueError(f'unrecognized selection \'{sel}\'') assert bui.app.classic is not None - bui.app.classic.ui.window_states[type(self)] = { + bui.app.ui_v1.window_states[type(self)] = { 'sel_name': sel_name } except Exception: @@ -2425,7 +2425,7 @@ def _save_state(self) -> None: def _restore_state(self) -> None: try: assert bui.app.classic is not None - sel_name = bui.app.classic.ui.window_states.get(type(self), {}).get( + sel_name = bui.app.ui_v1.window_states.get(type(self), {}).get( 'sel_name' ) sel: bui.Widget | None From 79244decde7ceae3c8bccd3280457e3feb6316e5 Mon Sep 17 00:00:00 2001 From: rikkolovescats Date: Tue, 20 Jun 2023 19:04:07 +0000 Subject: [PATCH 0499/1464] [ci] apply-version-metadata --- index.json | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/index.json b/index.json index 5d7f5a8c..75ae927a 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": { - "1.0.0": null, + "1.0.0": { + "api_version": 8, + "commit_sha": "4cb7d21", + "released_on": "20-06-2023", + "md5sum": "466272e4933946258751f84f956f862e" + }, "0.3.5": { "api_version": 7, "commit_sha": "985e486", @@ -105,4 +110,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 da62efcf2bfc1f64ac1e12c0ebe9b5f168716e27 Mon Sep 17 00:00:00 2001 From: Rikko Date: Wed, 21 Jun 2023 00:56:02 +0530 Subject: [PATCH 0500/1464] New fixes --- index.json | 9 ++------- plugin_manager.py | 2 +- plugins/utilities.json | 9 ++------- plugins/utilities/colorscheme.py | 6 +++--- 4 files changed, 8 insertions(+), 18 deletions(-) diff --git a/index.json b/index.json index 75ae927a..5d7f5a8c 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": { - "1.0.0": { - "api_version": 8, - "commit_sha": "4cb7d21", - "released_on": "20-06-2023", - "md5sum": "466272e4933946258751f84f956f862e" - }, + "1.0.0": null, "0.3.5": { "api_version": 7, "commit_sha": "985e486", @@ -110,4 +105,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 56716cda..c0b69daf 100644 --- a/plugin_manager.py +++ b/plugin_manager.py @@ -41,8 +41,8 @@ "User-Agent": _env["legacy_user_agent_string"], } PLUGIN_DIRECTORY = _env["python_directory_user"] -def _regexp_friendly_class_name_shortcut(string): return string.replace(".", "\.") +_regexp_friendly_class_name_shortcut = lambda string: string.replace(".", "\\.") REGEXP = { "plugin_api_version": re.compile(b"(?<=ba_meta require api )(.*)"), diff --git a/plugins/utilities.json b/plugins/utilities.json index 6e6f8011..94a9a31f 100644 --- a/plugins/utilities.json +++ b/plugins/utilities.json @@ -223,12 +223,7 @@ } ], "versions": { - "2.0.0": { - "api_version": 8, - "commit_sha": "9cfd0db", - "released_on": "08-06-2023", - "md5sum": "92390046cc91e147ebcd97df7390527f" - }, + "2.0.0": null, "1.2.3": { "api_version": 7, "commit_sha": "7753b87", @@ -715,4 +710,4 @@ } } } -} \ No newline at end of file +} diff --git a/plugins/utilities/colorscheme.py b/plugins/utilities/colorscheme.py index 5ef5159a..a2998e37 100644 --- a/plugins/utilities/colorscheme.py +++ b/plugins/utilities/colorscheme.py @@ -147,7 +147,7 @@ def draw_ui(self): # NOTE: Most of the stuff here for drawing the UI is referred from the # legacy (1.6 < version <= 1.7.19) game's bastd/ui/profile/edit.py, and # so there could be some cruft here due to my oversight. - uiscale = bui.app.classic.ui.uiscale + uiscale = bui.app.ui_v1.uiscale self._width = width = 480.0 if uiscale is babase.UIScale.SMALL else 380.0 self._x_inset = x_inset = 40.0 if uiscale is babase.UIScale.SMALL else 0.0 self._height = height = ( @@ -241,7 +241,7 @@ def draw_ui(self): draw_controller=self._color_button, text=babase.Lstr(resource="editProfileWindow.colorText"), scale=0.7, - color=bui.app.classic.ui.title_color, + color=bui.app.ui_v1.title_color, maxwidth=120, ) @@ -268,7 +268,7 @@ def draw_ui(self): draw_controller=self._highlight_button, text=babase.Lstr(resource="editProfileWindow.highlightText"), scale=0.7, - color=bui.app.classic.ui.title_color, + color=bui.app.ui_v1.title_color, maxwidth=120, ) From 0b55bc223375731ff0307f173cf6dd071cf8088b Mon Sep 17 00:00:00 2001 From: rikkolovescats Date: Tue, 20 Jun 2023 19:26:47 +0000 Subject: [PATCH 0501/1464] [ci] auto-format --- plugin_manager.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/plugin_manager.py b/plugin_manager.py index c0b69daf..f7866add 100644 --- a/plugin_manager.py +++ b/plugin_manager.py @@ -42,7 +42,9 @@ } PLUGIN_DIRECTORY = _env["python_directory_user"] -_regexp_friendly_class_name_shortcut = lambda string: string.replace(".", "\\.") + +def _regexp_friendly_class_name_shortcut(string): return string.replace(".", "\\.") + REGEXP = { "plugin_api_version": re.compile(b"(?<=ba_meta require api )(.*)"), From 16ae34ceba1bf573734c943e5074b6a54d269206 Mon Sep 17 00:00:00 2001 From: rikkolovescats Date: Tue, 20 Jun 2023 19:26:48 +0000 Subject: [PATCH 0502/1464] [ci] apply-version-metadata --- index.json | 9 +++++++-- plugins/utilities.json | 9 +++++++-- 2 files changed, 14 insertions(+), 4 deletions(-) diff --git a/index.json b/index.json index 5d7f5a8c..6475c769 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": { - "1.0.0": null, + "1.0.0": { + "api_version": 8, + "commit_sha": "0b55bc2", + "released_on": "20-06-2023", + "md5sum": "98fa2f29c3a2d34b5ff53b7abde7ec64" + }, "0.3.5": { "api_version": 7, "commit_sha": "985e486", @@ -105,4 +110,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/plugins/utilities.json b/plugins/utilities.json index 94a9a31f..a787b99f 100644 --- a/plugins/utilities.json +++ b/plugins/utilities.json @@ -223,7 +223,12 @@ } ], "versions": { - "2.0.0": null, + "2.0.0": { + "api_version": 8, + "commit_sha": "0b55bc2", + "released_on": "20-06-2023", + "md5sum": "517fec3938f31627c1cfd2126f1ee9da" + }, "1.2.3": { "api_version": 7, "commit_sha": "7753b87", @@ -710,4 +715,4 @@ } } } -} +} \ No newline at end of file From 8a7540fa35dd7df8aba094dc9c30f8f060f76d61 Mon Sep 17 00:00:00 2001 From: Silver-Volt4 <35656715+Silver-Volt4@users.noreply.github.com> Date: Wed, 28 Jun 2023 14:05:21 +0200 Subject: [PATCH 0503/1464] Add files via upload --- plugins/utilities/random_play.py | 99 ++++++++++++++++++-------------- 1 file changed, 56 insertions(+), 43 deletions(-) diff --git a/plugins/utilities/random_play.py b/plugins/utilities/random_play.py index 463ecf9f..c5c02145 100644 --- a/plugins/utilities/random_play.py +++ b/plugins/utilities/random_play.py @@ -1,11 +1,22 @@ -# ba_meta require api 7 +# ba_meta require api 8 from random import choice, randint from typing import Any, Union # pylint: disable=import-error -import _ba -import ba -from bastd.ui.playlist.browser import PlaylistBrowserWindow +import babase +from bascenev1 import ( + Session, + MultiTeamSession, + FreeForAllSession, + DualTeamSession, + GameActivity, + newactivity, + new_host_session, +) + +from bauiv1 import Widget, UIScale, buttonwidget +from bauiv1lib.playlist.browser import PlaylistBrowserWindow +from bascenev1lib.activity.multiteamjoin import MultiTeamJoinActivity DEFAULT_TEAM_COLORS = ((0.1, 0.25, 1.0), (1.0, 0.25, 0.2)) DEFAULT_TEAM_NAMES = ("Blue", "Red") @@ -13,16 +24,16 @@ # More or less copied from game code # I have no idea what I'm doing here -class RandomPlaySessionMixin(ba.MultiTeamSession, ba.Session): +class RandomPlaySessionMixin(MultiTeamSession, Session): def __init__(self, playlist) -> None: - """Set up playlists and launches a ba.Activity to accept joiners.""" - # pylint: disable=cyclic-import - from bastd.activity.multiteamjoin import MultiTeamJoinActivity + """Set up playlists & launch a bascenev1.Activity to accept joiners.""" - app = _ba.app + app = babase.app + classic = app.classic + assert classic is not None _cfg = app.config - super(ba.MultiTeamSession, self).__init__( + super(MultiTeamSession, self).__init__( [], team_names=DEFAULT_TEAM_NAMES, team_colors=DEFAULT_TEAM_COLORS, @@ -30,8 +41,8 @@ def __init__(self, playlist) -> None: max_players=self.get_max_players(), ) - self._series_length = app.teams_series_length - self._ffa_series_length = app.ffa_series_length + self._series_length: int = classic.teams_series_length + self._ffa_series_length: int = classic.ffa_series_length self._tutorial_activity_instance = None self._game_number = 0 @@ -41,37 +52,37 @@ def __init__(self, playlist) -> None: self._current_game_spec: dict[str, Any] | None = None self._next_game_spec: dict[str, Any] = self._playlist.pull_next() - self._next_game: type[ba.GameActivity] = self._next_game_spec["resolved_type"] + self._next_game: type[GameActivity] = self._next_game_spec["resolved_type"] self._instantiate_next_game() - self.setactivity(_ba.newactivity(MultiTeamJoinActivity)) + self.setactivity(newactivity(MultiTeamJoinActivity)) # Classes for Teams autopilot and FFA autopilot # I think they have to be separate in order to comply with `ba.GameActivity.supports_session_type()` -class RandFreeForAllSession(ba.FreeForAllSession, RandomPlaySessionMixin): +class RandFreeForAllSession(FreeForAllSession, RandomPlaySessionMixin): def __init__(self): - playlist = RandomPlaylist(ba.FreeForAllSession) - super(ba.FreeForAllSession, self).__init__(playlist) + playlist = RandomPlaylist(FreeForAllSession) + super(FreeForAllSession, self).__init__(playlist) -class RandDualTeamSession(ba.DualTeamSession, RandomPlaySessionMixin): +class RandDualTeamSession(DualTeamSession, RandomPlaySessionMixin): def __init__(self): - playlist = RandomPlaylist(ba.DualTeamSession) - super(ba.DualTeamSession, self).__init__(playlist) + playlist = RandomPlaylist(DualTeamSession) + super(DualTeamSession, self).__init__(playlist) # The faux playlist that just picks games at random class RandomPlaylist: - sessiontype: ba.Session - all_games: list[ba.GameActivity] - usable_games: list[ba.GameActivity] + sessiontype: Session + all_games: list[GameActivity] + usable_games: list[GameActivity] last_game: str def __init__(self, sessiontype): self.sessiontype = sessiontype - self.usable_games: list[ba.GameActivity] = [ + self.usable_games: list[GameActivity] = [ gt for gt in RandomPlaylist.all_games if gt.supports_session_type(self.sessiontype) @@ -90,7 +101,7 @@ def pull_next(self) -> dict[str, Any]: if game.name == self.last_game: # Don't repeat the same game twice if has_only_one_game: - # ...but don't freeze the game when there's only one game + # ...but don't freeze when there's only one game break else: break @@ -113,40 +124,42 @@ def pull_next(self) -> dict[str, Any]: # Hope you don't mind. def patched__init__( self, - sessiontype: type[ba.Session], + sessiontype: type[Session], transition: str | None = "in_right", - origin_widget: ba.Widget | None = None, + origin_widget: Widget | None = None, ): width = 800 height = 650 - ui_scale = ba.app.ui.uiscale - y_offset = -100 if ui_scale is ba.UIScale.SMALL else 0 - x_offset = 50 if ui_scale is ba.UIScale.SMALL else 0 + ui_scale = babase.app.ui_v1.uiscale + + y_offset = -100 if ui_scale is UIScale.SMALL else 0 + x_offset = 50 if ui_scale is UIScale.SMALL else 0 self.old__init__(sessiontype, transition, origin_widget) # pylint: disable=protected-access - self._quick_game_button = ba.buttonwidget( + self._quick_game_button = buttonwidget( parent=self._root_widget, position=(width - 120 * 2 + x_offset, height - 132 + y_offset), autoselect=True, - size=(120, 60), + size=(80, 60), scale=1.1, text_scale=1.2, - label="Random games", + label="Random", on_activate_call=game_starter_factory(sessiontype), color=(0.54, 0.52, 0.67), textcolor=(0.7, 0.65, 0.7), ) - + + print(dir(self._customize_button)) # Returns a function that starts the game -def game_starter_factory(sessiontype: type[ba.Session]): +def game_starter_factory(sessiontype: type[Session]): session: Union[RandFreeForAllSession, RandDualTeamSession] = None - if issubclass(sessiontype, ba.FreeForAllSession): + if issubclass(sessiontype, FreeForAllSession): session = RandFreeForAllSession - elif issubclass(sessiontype, ba.DualTeamSession): + elif issubclass(sessiontype, DualTeamSession): session = RandDualTeamSession else: raise RuntimeError("Can't determine session type") @@ -170,18 +183,18 @@ def has_faded(): start() def start(): - _ba.unlock_all_input() - _ba.new_host_session(session) + babase.unlock_all_input() + new_host_session(session) - _ba.fade_screen(False, time=0.25, endcall=has_faded) - _ba.lock_all_input() - ba.app.meta.load_exported_classes(ba.GameActivity, do_start) + babase.fade_screen(False, time=0.25, endcall=has_faded) + babase.lock_all_input() + babase.app.meta.load_exported_classes(GameActivity, do_start) return on_run # ba_meta export plugin -class RandomPlayPlugin(ba.Plugin): +class RandomPlayPlugin(babase.Plugin): """ A plugin that allows you to play randomly generated FFA or Teams matches by selecting a random minigame and map for each round. This eliminates the need to set up long playlists to enjoy all your BombSquad content. From b34dabe5001cd0c03587701dc4e1f9aa436dc969 Mon Sep 17 00:00:00 2001 From: Silver-Volt4 <35656715+Silver-Volt4@users.noreply.github.com> Date: Wed, 28 Jun 2023 14:07:09 +0200 Subject: [PATCH 0504/1464] Update utilities.json --- plugins/utilities.json | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/plugins/utilities.json b/plugins/utilities.json index c8adc4b7..4a1e989c 100644 --- a/plugins/utilities.json +++ b/plugins/utilities.json @@ -694,6 +694,7 @@ } ], "versions": { + "1.1.0": null, "1.0.1": { "api_version": 7, "commit_sha": "3ef572f", @@ -709,4 +710,4 @@ } } } -} \ No newline at end of file +} From 60806436f77d69e54c749d431e823c4dfefa34b2 Mon Sep 17 00:00:00 2001 From: Silver-Volt4 Date: Wed, 28 Jun 2023 12:08:31 +0000 Subject: [PATCH 0505/1464] [ci] auto-format --- plugins/utilities/random_play.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/plugins/utilities/random_play.py b/plugins/utilities/random_play.py index c5c02145..1c55b68d 100644 --- a/plugins/utilities/random_play.py +++ b/plugins/utilities/random_play.py @@ -150,10 +150,12 @@ def patched__init__( color=(0.54, 0.52, 0.67), textcolor=(0.7, 0.65, 0.7), ) - + print(dir(self._customize_button)) # Returns a function that starts the game + + def game_starter_factory(sessiontype: type[Session]): session: Union[RandFreeForAllSession, RandDualTeamSession] = None From 2caa423d716b559db920bad6039b0eeecce03735 Mon Sep 17 00:00:00 2001 From: Silver-Volt4 Date: Wed, 28 Jun 2023 12:08:32 +0000 Subject: [PATCH 0506/1464] [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 4a1e989c..daf83616 100644 --- a/plugins/utilities.json +++ b/plugins/utilities.json @@ -694,7 +694,12 @@ } ], "versions": { - "1.1.0": null, + "1.1.0": { + "api_version": 8, + "commit_sha": "6080643", + "released_on": "28-06-2023", + "md5sum": "bbca6bb4a8005d75cb32505764c003b6" + }, "1.0.1": { "api_version": 7, "commit_sha": "3ef572f", @@ -710,4 +715,4 @@ } } } -} +} \ No newline at end of file From f21235c97c30e69628c302600369ebf735c25d14 Mon Sep 17 00:00:00 2001 From: Silver-Volt4 <35656715+Silver-Volt4@users.noreply.github.com> Date: Wed, 28 Jun 2023 14:10:28 +0200 Subject: [PATCH 0507/1464] oops i left that one in --- plugins/utilities/random_play.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/plugins/utilities/random_play.py b/plugins/utilities/random_play.py index 1c55b68d..a07b906d 100644 --- a/plugins/utilities/random_play.py +++ b/plugins/utilities/random_play.py @@ -151,8 +151,6 @@ def patched__init__( textcolor=(0.7, 0.65, 0.7), ) - print(dir(self._customize_button)) - # Returns a function that starts the game From 5fb81958b4a8add8c75ee0437a216d4bb5ff8816 Mon Sep 17 00:00:00 2001 From: Silver-Volt4 <35656715+Silver-Volt4@users.noreply.github.com> Date: Wed, 28 Jun 2023 14:13:10 +0200 Subject: [PATCH 0508/1464] why am i so incompetent lmao --- plugins/utilities.json | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/plugins/utilities.json b/plugins/utilities.json index daf83616..4a1e989c 100644 --- a/plugins/utilities.json +++ b/plugins/utilities.json @@ -694,12 +694,7 @@ } ], "versions": { - "1.1.0": { - "api_version": 8, - "commit_sha": "6080643", - "released_on": "28-06-2023", - "md5sum": "bbca6bb4a8005d75cb32505764c003b6" - }, + "1.1.0": null, "1.0.1": { "api_version": 7, "commit_sha": "3ef572f", @@ -715,4 +710,4 @@ } } } -} \ No newline at end of file +} From 972b0fd551a94bb6af0a427ad0fb0ec2d8770f0b Mon Sep 17 00:00:00 2001 From: Silver-Volt4 Date: Wed, 28 Jun 2023 12:13:52 +0000 Subject: [PATCH 0509/1464] [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 4a1e989c..a63337a8 100644 --- a/plugins/utilities.json +++ b/plugins/utilities.json @@ -694,7 +694,12 @@ } ], "versions": { - "1.1.0": null, + "1.1.0": { + "api_version": 8, + "commit_sha": "5fb8195", + "released_on": "28-06-2023", + "md5sum": "f6c1105b34d0426327688841d7e89bb9" + }, "1.0.1": { "api_version": 7, "commit_sha": "3ef572f", @@ -710,4 +715,4 @@ } } } -} +} \ No newline at end of file From 0ab05ec385dc7d8f9752c8ee3b9dee82b8b044af Mon Sep 17 00:00:00 2001 From: Rikko Date: Fri, 30 Jun 2023 00:01:32 +0530 Subject: [PATCH 0510/1464] Notes on API 7 and API 8 --- README.md | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/README.md b/README.md index c853fa2e..ce1056e7 100644 --- a/README.md +++ b/README.md @@ -2,6 +2,11 @@ # plugin-manager +**Important:** Please check out the [api7](https://github.com/bombsquad-community/plugin-manager/tree/api7) branch if you're +using the game version (1.7.0 <= your game version <= 1.7.19) which uses API 7 plugins. +If you're on game version (1.7.20 or a later version) where it uses API 8 plugins, then proceed with the rest of the +README here. + 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. From 8770d7d82c1fea24371773cce3c7ebe18bf3d808 Mon Sep 17 00:00:00 2001 From: Rikko Date: Fri, 30 Jun 2023 00:10:27 +0530 Subject: [PATCH 0511/1464] Move away from deprecated distutils --- test/test_checks.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/test/test_checks.py b/test/test_checks.py index 4971bfef..72225bca 100644 --- a/test/test_checks.py +++ b/test/test_checks.py @@ -7,7 +7,7 @@ import os import pathlib -from distutils.version import StrictVersion +from packaging.version import Version import unittest @@ -33,7 +33,7 @@ def test_versions_order(self): versions = list(self.content["versions"].items()) sorted_versions = sorted( versions, - key=lambda version: StrictVersion(version[0]), + key=lambda version: Version(version[0]), reverse=True, ) assert sorted_versions == versions @@ -105,7 +105,7 @@ def test_versions_order(self): versions = list(plugin_metadata["versions"].items()) sorted_versions = sorted( versions, - key=lambda version: StrictVersion(version[0]), + key=lambda version: Version(version[0]), reverse=True, ) self.assertEqual(sorted_versions, versions) From 8dae6422a7cd8f8bb737ac8ac4ad5d1e17c6af93 Mon Sep 17 00:00:00 2001 From: Rikko Date: Fri, 30 Jun 2023 00:15:39 +0530 Subject: [PATCH 0512/1464] Add packaging dependency for running tests --- test/pip_reqs.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/test/pip_reqs.txt b/test/pip_reqs.txt index 64b1adae..0d79228e 100644 --- a/test/pip_reqs.txt +++ b/test/pip_reqs.txt @@ -1 +1,2 @@ +packaging GitPython From e99b6bdbab95b71143796920c5209d67dfd7d174 Mon Sep 17 00:00:00 2001 From: Rikko Date: Fri, 30 Jun 2023 00:24:41 +0530 Subject: [PATCH 0513/1464] Move API 7 -> API 8 note to the top --- README.md | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index ce1056e7..6442473f 100644 --- a/README.md +++ b/README.md @@ -1,12 +1,14 @@ [![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 - **Important:** Please check out the [api7](https://github.com/bombsquad-community/plugin-manager/tree/api7) branch if you're using the game version (1.7.0 <= your game version <= 1.7.19) which uses API 7 plugins. If you're on game version (1.7.20 or a later version) where it uses API 8 plugins, then proceed with the rest of the README here. +------------------------------- + +# plugin-manager + 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. From d76be7b01b5cb28ba7e354783dca74b4feb0c9fd Mon Sep 17 00:00:00 2001 From: Rikko Date: Fri, 30 Jun 2023 00:29:17 +0530 Subject: [PATCH 0514/1464] Update commit sha for hot bomb --- plugins/minigames.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/plugins/minigames.json b/plugins/minigames.json index bcdd1012..f78d2e3b 100644 --- a/plugins/minigames.json +++ b/plugins/minigames.json @@ -268,7 +268,7 @@ "versions": { "1.1.0": { "api_version": 8, - "commit_sha": "65d5d6f", + "commit_sha": "0069f15", "released_on": "08-06-2023", "md5sum": "b8168bd3e6fae96b9339a727bd50842f" }, @@ -606,4 +606,4 @@ } } } -} \ No newline at end of file +} From a656912a470246fc1eea2ce2dfc7f85f4d613708 Mon Sep 17 00:00:00 2001 From: rikkolovescats Date: Thu, 29 Jun 2023 18:59:53 +0000 Subject: [PATCH 0515/1464] [ci] apply-version-metadata --- plugins/minigames.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/minigames.json b/plugins/minigames.json index f78d2e3b..a95fc4f5 100644 --- a/plugins/minigames.json +++ b/plugins/minigames.json @@ -606,4 +606,4 @@ } } } -} +} \ No newline at end of file From 8a8df69e36cc7ea03c086b1db8233cb0ebf0eba5 Mon Sep 17 00:00:00 2001 From: Rikko Date: Fri, 30 Jun 2023 04:38:42 +0530 Subject: [PATCH 0516/1464] Specify branch names in custom plugin sources --- CHANGELOG.md | 8 +++ README.md | 2 + index.json | 3 +- plugin_manager.py | 154 +++++++++++++++++++++++++++------------------- 4 files changed, 101 insertions(+), 66 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 85ebd585..7b9fd57c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,13 @@ ## Plugin Manager (dd-mm-yyyy) +### 1.0.1 (30-06-2023) + +- Allow specifying branch names in custom sources. + +### 1.0.0 (20-06-2023) + +- Migrate plugin manager's source code to API 8. + ### 0.3.5 (16-06-2023) - Replace the "Loading..." text with the exception message in case something goes wrong. diff --git a/README.md b/README.md index 6442473f..fe057a9e 100644 --- a/README.md +++ b/README.md @@ -184,6 +184,8 @@ That's it! Now you can make a [pull request](../../compare) with both the update - Check out [bombsquad-community/sample-plugin-source](https://github.com/bombsquad-community/sample-plugin-source) as an example. You can choose to show up plugins from this repository in your plugin manager by adding `bombsquad-community/sample-plugin-source` as a custom source through the category selection popup window in-game. +- Plugin manager will default to picking up plugins from the `main` branch of the custom source repository. You + can specify a different branch by suffixing the source URI with `@branchname`, such as `bombsquad-community/sample-plugin-source@experimental`. #### Known 3rd Party Plugin Sources diff --git a/index.json b/index.json index 6475c769..9188b63e 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": { + "1.0.1": null, "1.0.0": { "api_version": 8, "commit_sha": "0b55bc2", @@ -110,4 +111,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 f7866add..af65658a 100644 --- a/plugin_manager.py +++ b/plugin_manager.py @@ -19,6 +19,7 @@ import contextlib import hashlib import copy +import traceback from typing import Union, Optional from datetime import datetime @@ -31,7 +32,7 @@ _uiscale = bui.app.ui_v1.uiscale -PLUGIN_MANAGER_VERSION = "1.0.0" +PLUGIN_MANAGER_VERSION = "1.0.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. @@ -70,19 +71,27 @@ def _regexp_friendly_class_name_shortcut(string): return string.replace(".", "\\ _CACHE = {} -class MD5CheckSumFailedError(Exception): +class MD5CheckSumFailed(Exception): pass -class PluginNotInstalledError(Exception): +class PluginNotInstalled(Exception): pass -class CategoryDoesNotExistError(Exception): +class CategoryDoesNotExist(Exception): pass -class NoCompatibleVersionError(Exception): +class NoCompatibleVersion(Exception): + pass + + +class PluginSourceNetworkError(Exception): + pass + + +class CategoryMetadataParseError(Exception): pass @@ -109,7 +118,7 @@ def stream_network_response_to_file(request, file, md5sum=None, retries=3): content += chunk if md5sum and hashlib.md5(content).hexdigest() != md5sum: if retries <= 0: - raise MD5CheckSumFailedError("MD5 checksum match failed.") + raise MD5CheckSumFailed("MD5 checksum match failed.") return stream_network_response_to_file( request, file, @@ -276,7 +285,7 @@ async def update_plugin_manager(self): bui.screenmessage(f"Plugin Manager is being updated to v{to_version}") try: await self.plugin_manager.update(to_version, commit_sha) - except MD5CheckSumFailedError: + except MD5CheckSumFailed: bui.getsound('error').play() else: bui.screenmessage("Update successful. Restart game to reload changes.", @@ -301,7 +310,7 @@ def _is_new_supported_plugin(plugin): return False try: plugin.latest_compatible_version - except NoCompatibleVersionError: + except NoCompatibleVersion: return False else: return True @@ -354,9 +363,9 @@ async def execute(self): class Category: - def __init__(self, meta_url, is_3rd_party=False): + def __init__(self, meta_url, tag=CURRENT_TAG): self.meta_url = meta_url - self.is_3rd_party = is_3rd_party + self.tag = tag self.request_headers = HEADERS self._metadata = _CACHE.get("categories", {}).get(meta_url, {}).get("metadata") self._plugins = _CACHE.get("categories", {}).get(meta_url, {}).get("plugins") @@ -365,9 +374,8 @@ 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=tag), + self.meta_url.format(content_type="raw", tag=self.tag), headers=self.request_headers, ) response = await async_send_network_request(request) @@ -375,11 +383,13 @@ async def fetch_metadata(self): self.set_category_global_cache("metadata", self._metadata) return self - async def is_valid(self): + async def validate(self): try: await self.fetch_metadata() - except urllib.error.HTTPError: - return False + except urllib.error.HTTPError as e: + raise PluginSourceNetworkError(str(e)) + except json.decoder.JSONDecodeError as e: + raise CategoryMetadataParseError(f"Failed to parse JSON: {str(e)}") try: await asyncio.gather( self.get_name(), @@ -388,7 +398,7 @@ async def is_valid(self): self.get_plugins(), ) except KeyError: - return False + raise CategoryMetadataParseError(f"Failed to parse JSON; missing required fields.") else: return True @@ -411,7 +421,7 @@ async def get_plugins(self): Plugin( plugin_info, f"{await self.get_plugins_base_url()}/{plugin_info[0]}.py", - is_3rd_party=self.is_3rd_party, + tag=self.tag, ) for plugin_info in self._metadata["plugins"].items() ]) @@ -514,19 +524,19 @@ def _set_content(self, content): fout.write(content) def has_settings(self): - for plugin_entry_point, plugin_class in babase.app.plugins.active_plugins.items(): + for plugin_entry_point, plugin_spec in bui.app.plugins.plugin_specs.items(): if plugin_entry_point.startswith(self._entry_point_initials): - return plugin_class.has_settings_ui() + return plugin_spec.plugin.has_settings_ui() def launch_settings(self, source_widget): - for plugin_entry_point, plugin_class in babase.app.plugins.active_plugins.items(): + for plugin_entry_point, plugin_spec in bui.app.plugins.plugin_specs.items(): if plugin_entry_point.startswith(self._entry_point_initials): - return plugin_class.show_settings_ui(source_widget) + return plugin_spec.plugin.show_settings_ui(source_widget) async def get_content(self): if self._content is None: if not self.is_installed: - raise PluginNotInstalledError("Plugin is not available locally.") + raise PluginNotInstalled("Plugin is not available locally.") loop = asyncio.get_event_loop() self._content = await loop.run_in_executor(None, self._get_content) return self._content @@ -613,7 +623,8 @@ async def enable(self): if entry_point not in babase.app.config["Plugins"]: babase.app.config["Plugins"][entry_point] = {} babase.app.config["Plugins"][entry_point]["enabled"] = True - if entry_point not in babase.app.plugins.active_plugins: + plugin_spec = bui.app.plugins.plugin_specs.get(entry_point) + if plugin_spec not in bui.app.plugins.active_plugins: self.load_plugin(entry_point) bui.screenmessage(f"{entry_point} loaded") if await self.has_minigames(): @@ -623,9 +634,14 @@ async def enable(self): def load_plugin(self, entry_point): plugin_class = babase._general.getclass(entry_point, babase.Plugin) - loaded_plugin_class = plugin_class() - loaded_plugin_class.on_app_running() - babase.app.plugins.active_plugins[entry_point] = loaded_plugin_class + loaded_plugin_instance = plugin_class() + loaded_plugin_instance.on_app_running() + + plugin_spec = babase.PluginSpec(class_path=entry_point, loadable=True) + plugin_spec.enabled = True + plugin_spec.plugin = loaded_plugin_instance + bui.app.plugins.plugin_specs[entry_point] = plugin_spec + bui.app.plugins.active_plugins.append(plugin_spec.plugin) def disable(self): for entry_point, plugin_info in babase.app.config["Plugins"].items(): @@ -674,7 +690,7 @@ def save(self): class PluginVersion: - def __init__(self, plugin, version, tag=None): + def __init__(self, plugin, version, tag=CURRENT_TAG): self.number, info = version self.plugin = plugin self.api_version = info["api_version"] @@ -682,10 +698,8 @@ def __init__(self, plugin, version, tag=None): self.commit_sha = info["commit_sha"] self.md5sum = info["md5sum"] - if tag is None: - tag = self.commit_sha - self.download_url = self.plugin.url.format(content_type="raw", tag=tag) + print(self.download_url) self.view_url = self.plugin.url.format(content_type="blob", tag=tag) def __eq__(self, plugin_version): @@ -713,7 +727,7 @@ async def _download(self, retries=3): async def install(self, suppress_screenmessage=False): try: local_plugin = await self._download() - except MD5CheckSumFailedError: + except MD5CheckSumFailed: if not suppress_screenmessage: bui.screenmessage( f"{self.plugin.name} failed MD5 checksum during installation", color=(1, 0, 0)) @@ -728,20 +742,14 @@ async def install(self, suppress_screenmessage=False): class Plugin: - def __init__(self, plugin, url, is_3rd_party=False): + def __init__(self, plugin, url, tag=CURRENT_TAG): """ Initialize a plugin from network repository. """ self.name, self.info = plugin - self.is_3rd_party = is_3rd_party self.install_path = os.path.join(PLUGIN_DIRECTORY, f"{self.name}.py") - # if is_3rd_party: - # tag = CURRENT_TAG - # else: - # tag = CURRENT_TAG - tag = CURRENT_TAG self.url = url - self.download_url = url.format(content_type="raw", tag=tag) + self.tag = tag self._local_plugin = None self._versions = None @@ -773,6 +781,7 @@ def versions(self): PluginVersion( self, version, + tag=self.tag, ) for version in self.info["versions"].items() ] return self._versions @@ -783,7 +792,7 @@ def latest_version(self): self._latest_version = PluginVersion( self, tuple(self.info["versions"].items())[0], - tag=CURRENT_TAG, + tag=self.tag, ) return self._latest_version @@ -795,18 +804,18 @@ def latest_compatible_version(self): self._latest_compatible_version = PluginVersion( self, (number, info), - CURRENT_TAG if self.latest_version.number == number else None + tag=self.tag if self.latest_version.number == number else info["commit_sha"] ) break if self._latest_compatible_version is None: - raise NoCompatibleVersionError( + raise NoCompatibleVersion( f"{self.name} has no version compatible with API {babase.app.api_version}." ) return self._latest_compatible_version def get_local(self): if not self.is_installed: - raise PluginNotInstalledError( + raise PluginNotInstalled( f"{self.name} needs to be installed to get its local plugin.") if self._local_plugin is None: self._local_plugin = PluginLocal(self.name) @@ -825,7 +834,7 @@ async def uninstall(self): def has_update(self): try: latest_compatible_version = self.latest_compatible_version - except NoCompatibleVersionError: + except NoCompatibleVersion: return False else: return self.get_local().version != latest_compatible_version.number @@ -874,8 +883,6 @@ def get_description(self, minimum_character_offset=40): return partitioned_string async def draw_ui(self): - # print(babase.app.plugins.active_plugins) - bui.getsound('swish').play() b_text_color = (0.75, 0.7, 0.8) s = 1.25 if _uiscale is babase.UIScale.SMALL else 1.39 if babase.UIScale.MEDIUM else 1.67 @@ -1177,14 +1184,22 @@ async def setup_plugin_categories(self, plugin_index): self.categories["All"] = None requests = [] - for plugin_category_url in plugin_index["categories"]: - category = Category(plugin_category_url) + for meta_url in plugin_index["categories"]: + category = Category(meta_url) request = category.fetch_metadata() requests.append(request) - for repository in babase.app.config["Community Plugin Manager"]["Custom Sources"]: - plugin_category_url = partial_format(plugin_index["external_source_url"], - repository=repository) - category = Category(plugin_category_url, is_3rd_party=True) + for source in babase.app.config["Community Plugin Manager"]["Custom Sources"]: + source_splits = source.split("@", maxsplit=1) + if len(source_splits) == 1: + # Fallack to `main` if `@branchname` isn't specified in an external source URI. + source_repo, source_tag = source_splits[0], "main" + else: + source_repo, source_tag = source_splits + meta_url = partial_format( + plugin_index["external_source_url"], + repository=source_repo, + ) + category = Category(meta_url, tag=source_tag) request = category.fetch_metadata() requests.append(request) categories = await asyncio.gather(*requests) @@ -1247,7 +1262,7 @@ async def update(self, to_version=None, commit_sha=None): response = await async_send_network_request(download_url) content = response.read() if hashlib.md5(content).hexdigest() != to_version_info["md5sum"]: - raise MD5CheckSumFailedError("MD5 checksum failed during plugin manager update.") + raise MD5CheckSumFailed("MD5 checksum failed during plugin manager update.") with open(self.module_path, "wb") as fout: fout.write(content) return to_version_info @@ -1396,14 +1411,23 @@ def select_source(self, source): async def add_source(self): source = bui.textwidget(query=self._add_source_widget) - meta_url = _CACHE["index"]["external_source_url"].format( - repository=source, - content_type="raw", - tag=CURRENT_TAG + # External source URIs can optionally suffix `@branchname`, for example: + # `bombsquad-community/sample-plugin-source@experimental` + source_splits = source.split("@", maxsplit=1) + if len(source_splits) == 1: + # Fallack to `main` if `@branchname` isn't specified in an external source URI. + source_repo, source_tag = source_splits[0], "main" + else: + source_repo, source_tag = source_splits + meta_url = partial_format( + _CACHE["index"]["external_source_url"], + repository=source_repo, ) - category = Category(meta_url, is_3rd_party=True) - if not await category.is_valid(): - bui.screenmessage("Enter a valid plugin source", color=(1, 0, 0)) + category = Category(meta_url, tag=source_tag) + try: + await category.validate() + except (PluginSourceNetworkError, CategoryMetadataParseError) as e: + bui.screenmessage(str(e), color=(1, 0, 0)) bui.getsound('error').play() return if source in babase.app.config["Community Plugin Manager"]["Custom Sources"]: @@ -1564,7 +1588,7 @@ def exception_handler(self): # User probably went back before a bui.Window could finish loading. pass except Exception as e: - ba.textwidget(edit=self._plugin_manager_status_text, + bui.textwidget(edit=self._plugin_manager_status_text, text=str(e)) raise @@ -1684,7 +1708,7 @@ async def process_search_term(self): continue try: await self.draw_plugin_names(self.selected_category, search_term=filter_text) - except CategoryDoesNotExistError: + except CategoryDoesNotExist: pass # XXX: This may be more efficient, but we need a way to get a plugin's textwidget # attributes like color, position and more. @@ -1775,7 +1799,7 @@ async def draw_plugin_names(self, category, search_term=""): try: category_plugins = await self.plugin_manager.categories[category].get_plugins() except (KeyError, AttributeError): - raise CategoryDoesNotExistError(f"{category} does not exist.") + raise CategoryDoesNotExist(f"{category} does not exist.") if search_term: def search_term_filterer(plugin): return self.search_term_filterer(plugin, search_term) @@ -1800,7 +1824,7 @@ def search_term_filterer(plugin): return self.search_term_filterer(plugin, searc async def draw_plugin_name(self, plugin): try: latest_compatible_version = plugin.latest_compatible_version - except NoCompatibleVersionError: + except NoCompatibleVersion: # We currently don't show plugins that have no compatible versions. return @@ -2077,7 +2101,7 @@ def save_settings_button(self): async def update(self, to_version=None, commit_sha=None): try: await self._plugin_manager.update(to_version, commit_sha) - except MD5CheckSumFailedError: + except MD5CheckSumFailed: bui.screenmessage("MD5 checksum failed during plugin manager update", color=(1, 0, 0)) bui.getsound('error').play() else: From e31a7890c712595c856b58c209f064e6aacf462a Mon Sep 17 00:00:00 2001 From: rikkolovescats Date: Thu, 29 Jun 2023 23:09:26 +0000 Subject: [PATCH 0517/1464] [ci] auto-format --- plugin_manager.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugin_manager.py b/plugin_manager.py index af65658a..dc8dbae9 100644 --- a/plugin_manager.py +++ b/plugin_manager.py @@ -1589,7 +1589,7 @@ def exception_handler(self): pass except Exception as e: bui.textwidget(edit=self._plugin_manager_status_text, - text=str(e)) + text=str(e)) raise async def draw_index(self): From b32521fbae50c268c560eef3ac1496a11bd67d4a Mon Sep 17 00:00:00 2001 From: rikkolovescats Date: Thu, 29 Jun 2023 23:09:27 +0000 Subject: [PATCH 0518/1464] [ci] apply-version-metadata --- index.json | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/index.json b/index.json index 9188b63e..51896d5a 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": { - "1.0.1": null, + "1.0.1": { + "api_version": 8, + "commit_sha": "e31a789", + "released_on": "29-06-2023", + "md5sum": "e54913a789a31f60f18ef24edbfdd130" + }, "1.0.0": { "api_version": 8, "commit_sha": "0b55bc2", @@ -111,4 +116,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 7dba50e95b85e422d8aa20bd9b63902f3e25454d Mon Sep 17 00:00:00 2001 From: Rikko Date: Fri, 30 Jun 2023 04:46:38 +0530 Subject: [PATCH 0519/1464] Remove a debug print --- index.json | 9 ++------- plugin_manager.py | 1 - 2 files changed, 2 insertions(+), 8 deletions(-) diff --git a/index.json b/index.json index 51896d5a..9188b63e 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": { - "1.0.1": { - "api_version": 8, - "commit_sha": "e31a789", - "released_on": "29-06-2023", - "md5sum": "e54913a789a31f60f18ef24edbfdd130" - }, + "1.0.1": null, "1.0.0": { "api_version": 8, "commit_sha": "0b55bc2", @@ -116,4 +111,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 dc8dbae9..e883fba7 100644 --- a/plugin_manager.py +++ b/plugin_manager.py @@ -699,7 +699,6 @@ def __init__(self, plugin, version, tag=CURRENT_TAG): self.md5sum = info["md5sum"] self.download_url = self.plugin.url.format(content_type="raw", tag=tag) - print(self.download_url) self.view_url = self.plugin.url.format(content_type="blob", tag=tag) def __eq__(self, plugin_version): From 82081ab3cc9d4ff365c588515e95f8e04d9990fe Mon Sep 17 00:00:00 2001 From: rikkolovescats Date: Thu, 29 Jun 2023 23:17:25 +0000 Subject: [PATCH 0520/1464] [ci] apply-version-metadata --- index.json | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/index.json b/index.json index 9188b63e..3369fcba 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": { - "1.0.1": null, + "1.0.1": { + "api_version": 8, + "commit_sha": "7dba50e", + "released_on": "29-06-2023", + "md5sum": "099ebc828a13f9a7040486bab4932a55" + }, "1.0.0": { "api_version": 8, "commit_sha": "0b55bc2", @@ -111,4 +116,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 018c962743d147c903ef950f16e92c5b22a96e35 Mon Sep 17 00:00:00 2001 From: Ayush Saini <36878972+imayushsaini@users.noreply.github.com> Date: Sun, 2 Jul 2023 13:19:46 +0530 Subject: [PATCH 0521/1464] added party window plugin --- plugins/utilities.json | 1 + plugins/utilities/advanced_party_window.py | 743 ++++++++++----------- 2 files changed, 356 insertions(+), 388 deletions(-) diff --git a/plugins/utilities.json b/plugins/utilities.json index 6cdfe224..a2f49fe7 100644 --- a/plugins/utilities.json +++ b/plugins/utilities.json @@ -366,6 +366,7 @@ } ], "versions": { + "2.0.0":null, "1.0.1": { "api_version": 7, "commit_sha": "64e8a5c", diff --git a/plugins/utilities/advanced_party_window.py b/plugins/utilities/advanced_party_window.py index 8f36b022..3930bc9d 100644 --- a/plugins/utilities/advanced_party_window.py +++ b/plugins/utilities/advanced_party_window.py @@ -1,19 +1,26 @@ # -*- coding: utf-8 -*- -# ba_meta require api 7 +# ba_meta require api 8 +''' +AdvancedPartyWindow by Mr.Smoothy -# AdvancedPartyWindow by Mr.Smoothy +Updated to API 8 on 2nd July 2023 by Mr.Smoothy -# build on base of plasma's modifypartywindow +build on base of plasma's modifypartywindow -# added many features +discord mr.smoothy#5824 -# discord mr.smoothy#5824 +https://discord.gg/ucyaesh -# https://discord.gg/ucyaesh Join BCS -# Youtube : Hey Smoothy + +Youtube : Hey Smoothy + +Download more mods from +https://bombsquad-community.web.app/mods + +''' # added advanced ID revealer -# live ping support for bcs +# live ping # Made by Mr.Smoothy - Plasma Boson import traceback @@ -25,32 +32,34 @@ import copy import urllib import os -from bastd.ui.account import viewer -from bastd.ui.popup import PopupMenuWindow, PopupWindow -from ba._general import Call +from bauiv1lib.account import viewer +from bauiv1lib.popup import PopupMenuWindow, PopupWindow +from babase._general import Call import base64 import datetime import ssl -import bastd.ui.party as bastd_party +import bauiv1lib.party as bascenev1lib_party from typing import List, Sequence, Optional, Dict, Any, Union -from bastd.ui.colorpicker import ColorPickerExact -from bastd.ui.confirm import ConfirmWindow +from bauiv1lib.colorpicker import ColorPickerExact +from bauiv1lib.confirm import ConfirmWindow from dataclasses import dataclass import math import time -import ba -import _ba +import babase +import bauiv1 as bui +import bascenev1 as bs +import _babase from typing import TYPE_CHECKING, cast import urllib.request import urllib.parse from _thread import start_new_thread import threading version_str = "7" -BCSSERVER = 'api2.bombsquad.ga' +BCSSERVER = 'mods.ballistica.workers.dev' cache_chat = [] -connect = ba.internal.connect_to_party -disconnect = ba.internal.disconnect_from_host +connect = bs.connect_to_party +disconnect = bs.disconnect_from_host unmuted_names = [] smo_mode = 3 f_chat = False @@ -68,9 +77,9 @@ def newconnect_to_party(address, port=43210, print_progress=False): global ip_add global p_port - dd = _ba.get_connection_to_host_info() + dd = bs.get_connection_to_host_info() if (dd != {}): - _ba.disconnect_from_host() + bs.disconnect_from_host() ip_add = address p_port = port @@ -95,11 +104,11 @@ def __init__(self): def run(self) -> None: # pylint: disable=too-many-branches # pylint: disable=too-many-statements - ba.app.ping_thread_count += 1 + bui.app.classic.ping_thread_count += 1 sock: Optional[socket.socket] = None try: import socket - from ba.internal import get_ip_address_type + from babase._net import get_ip_address_type socket_type = get_ip_address_type(ip_add) sock = socket.socket(socket_type, socket.SOCK_DGRAM) sock.connect((ip_add, p_port)) @@ -149,38 +158,29 @@ def run(self) -> None: if self._port == 0: # This has happened. Ignore. pass - elif ba.do_once(): + elif babase.do_once(): print(f'Got EADDRNOTAVAIL on gather ping' f' for addr {self._address}' f' port {self._port}.') else: - ba.print_exception( + babase.print_exception( f'Error on gather ping ' f'(errno={exc.errno})', once=True) except Exception: - ba.print_exception('Error on gather ping', once=True) + babase.print_exception('Error on gather ping', once=True) finally: try: if sock is not None: sock.close() except Exception: - ba.print_exception('Error on gather ping cleanup', once=True) + babase.print_exception('Error on gather ping cleanup', once=True) - ba.app.ping_thread_count -= 1 - _ba.pushcall(update_ping, from_other_thread=True) + bui.app.classic.ping_thread_count -= 1 time.sleep(4) self.run() -try: - import OnlineTranslator - tranTypes = [item for item in dir(OnlineTranslator) if item.startswith("Translator_")] - if "item" in globals(): - del item -except: - tranTypes = [] # ;ba.print_exception() - -RecordFilesDir = os.path.join(_ba.env()["python_directory_user"], "Configs" + os.sep) +RecordFilesDir = os.path.join(_babase.env()["python_directory_user"], "Configs" + os.sep) if not os.path.exists(RecordFilesDir): os.makedirs(RecordFilesDir) @@ -193,21 +193,10 @@ def run(self) -> None: SystemEncode = "utf-8" -def update_ping(): - try: - _ba.set_ping_widget_value(current_ping) - except: - with _ba.Context('ui'): - if hasattr(_ba, "ping_widget") and _ba.ping_widget.exists(): - ba.textwidget(edit=_ba.ping_widget, text="Ping:"+str(current_ping)+" ms") - PingThread().start() -try: - from ba._generated.enums import TimeType -except: - from ba._enums import TimeType + class chatloggThread(): @@ -221,11 +210,11 @@ def run(self) -> None: # pylint: disable=too-many-branches # pylint: disable=too-many-statements global chatlogger - self.timerr = ba.Timer(5.0, self.chatlogg, repeat=True, timetype=TimeType.REAL) + self.timerr = babase.AppTimer(5.0, self.chatlogg, repeat=True) def chatlogg(self): global chatlogger - chats = _ba.get_chat_messages() + chats = bs.get_chat_messages() for msg in chats: if msg in self.saved_msg: pass @@ -241,20 +230,20 @@ def chatlogg(self): def save(self, msg): x = str(datetime.datetime.now()) - t = open(os.path.join(_ba.env()["python_directory_user"], "Chat logged.txt"), "a+") + t = open(os.path.join(_babase.env()["python_directory_user"], "Chat logged.txt"), "a+") t.write(x+" : " + msg + "\n") t.close() class mututalServerThread(): def run(self): - self.timer = ba.Timer(10, self.checkPlayers, repeat=True, timetype=TimeType.REAL) + self.timer = babase.AppTimer(10, self.checkPlayers, repeat=True) def checkPlayers(self): - if _ba.get_connection_to_host_info() != {}: - server_name = _ba.get_connection_to_host_info()["name"] + if bs.get_connection_to_host_info() != {}: + server_name = bs.get_connection_to_host_info()["name"] players = [] - for ros in _ba.get_game_roster(): + for ros in bs.get_game_roster(): players.append(ros["display_string"]) start_new_thread(dump_mutual_servers, (players, server_name,)) @@ -286,30 +275,36 @@ def __init__(self): super().__init__() global cache_chat self.saved_msg = [] - chats = _ba.get_chat_messages() - for msg in chats: # fill up old chat , to avoid old msg popup - cache_chat.append(msg) + try: + chats = bs.get_chat_messages() + for msg in chats: # fill up old chat , to avoid old msg popup + cache_chat.append(msg) + except: + pass def run(self) -> None: # pylint: disable=too-many-branches # pylint: disable=too-many-statements global chatlogger - self.timerr = ba.Timer(5.0, self.chatcheck, repeat=True, timetype=TimeType.REAL) + self.timerr = babase.AppTimer(5.0, self.chatcheck, repeat=True) def chatcheck(self): global unmuted_names global cache_chat - chats = _ba.get_chat_messages() + try: + chats = bs.get_chat_messages() + except: + chats = [] for msg in chats: if msg in cache_chat: pass else: if msg.split(":")[0] in unmuted_names: - ba.screenmessage(msg, color=(0.6, 0.9, 0.6)) + bs.broadcastmessage(msg, color=(0.6, 0.9, 0.6)) cache_chat.append(msg) if len(self.saved_msg) > 45: cache_chat.pop(0) - if ba.app.config.resolve('Chat Muted'): + if babase.app.config.resolve('Chat Muted'): pass else: self.timerr = None @@ -380,25 +375,25 @@ def _getTransText(text, isBaLstr=False, same_fb=False): pass return (Language_Texts.get(text, "#Unknown Text#" if not same_fb else text) if not isBaLstr else - ba.Lstr(resource="??Unknown??", fallback_value=Language_Texts.get(text, "#Unknown Text#" if not same_fb else text))) + babase.Lstr(resource="??Unknown??", fallback_value=Language_Texts.get(text, "#Unknown Text#" if not same_fb else text))) def _get_popup_window_scale() -> float: - uiscale = ba.app.ui.uiscale - return (2.3 if uiscale is ba.UIScale.SMALL else - 1.65 if uiscale is ba.UIScale.MEDIUM else 1.23) + uiscale = bui.app.ui_v1.uiscale + return (2.3 if uiscale is babase.UIScale.SMALL else + 1.65 if uiscale is babase.UIScale.MEDIUM else 1.23) def _creat_Lstr_list(string_list: list = []) -> list: - return ([ba.Lstr(resource="??Unknown??", fallback_value=item) for item in string_list]) + return ([babase.Lstr(resource="??Unknown??", fallback_value=item) for item in string_list]) customchatThread().run() -class ModifiedPartyWindow(bastd_party.PartyWindow): +class ModifiedPartyWindow(bascenev1lib_party.PartyWindow): def __init__(self, origin: Sequence[float] = (0, 0)): - _ba.set_party_window_open(True) + bui.set_party_window_open(True) self._r = 'partyWindow' self.msg_user_selected = '' self._popup_type: Optional[str] = None @@ -406,29 +401,29 @@ def __init__(self, origin: Sequence[float] = (0, 0)): self._popup_party_member_is_host: Optional[bool] = None self._width = 500 - uiscale = ba.app.ui.uiscale - self._height = (365 if uiscale is ba.UIScale.SMALL else - 480 if uiscale is ba.UIScale.MEDIUM else 600) + uiscale = bui.app.ui_v1.uiscale + self._height = (365 if uiscale is babase.UIScale.SMALL else + 480 if uiscale is babase.UIScale.MEDIUM else 600) # Custom color here - self._bg_color = ba.app.config.get("PartyWindow_Main_Color", (0.40, 0.55, 0.20)) if not isinstance( + self._bg_color = babase.app.config.get("PartyWindow_Main_Color", (0.40, 0.55, 0.20)) if not isinstance( self._getCustomSets().get("Color"), (list, tuple)) else self._getCustomSets().get("Color") if not isinstance(self._bg_color, (list, tuple)) or not len(self._bg_color) == 3: self._bg_color = (0.40, 0.55, 0.20) - ba.Window.__init__(self, root_widget=ba.containerwidget( + bui.Window.__init__(self, root_widget=bui.containerwidget( size=(self._width, self._height), transition='in_scale', color=self._bg_color, - parent=_ba.get_special_widget('overlay_stack'), + parent=bui.get_special_widget('overlay_stack'), on_outside_click_call=self.close_with_sound, scale_origin_stack_offset=origin, - scale=(2.0 if uiscale is ba.UIScale.SMALL else - 1.35 if uiscale is ba.UIScale.MEDIUM else 1.0), - stack_offset=(0, -10) if uiscale is ba.UIScale.SMALL else ( - 240, 0) if uiscale is ba.UIScale.MEDIUM else (330, 20))) + scale=(2.0 if uiscale is babase.UIScale.SMALL else + 1.35 if uiscale is babase.UIScale.MEDIUM else 1.0), + stack_offset=(0, -10) if uiscale is babase.UIScale.SMALL else ( + 240, 0) if uiscale is babase.UIScale.MEDIUM else (330, 20))) - self._cancel_button = ba.buttonwidget(parent=self._root_widget, + self._cancel_button = bui.buttonwidget(parent=self._root_widget, scale=0.7, position=(30, self._height - 47), size=(50, 50), @@ -436,9 +431,9 @@ def __init__(self, origin: Sequence[float] = (0, 0)): on_activate_call=self.close, autoselect=True, color=(0.45, 0.63, 0.15), - icon=ba.gettexture('crossOut'), + icon=bui.gettexture('crossOut'), iconscale=1.2) - self._smoothy_button = ba.buttonwidget(parent=self._root_widget, + self._smoothy_button = bui.buttonwidget(parent=self._root_widget, scale=0.6, position=(5, self._height - 47 - 40), size=(50, 50), @@ -446,12 +441,12 @@ def __init__(self, origin: Sequence[float] = (0, 0)): on_activate_call=self.smoothy_roster_changer, autoselect=True, color=(0.45, 0.63, 0.15), - icon=ba.gettexture('replayIcon'), + icon=bui.gettexture('replayIcon'), iconscale=1.2) - ba.containerwidget(edit=self._root_widget, + bui.containerwidget(edit=self._root_widget, cancel_button=self._cancel_button) - self._menu_button = ba.buttonwidget( + self._menu_button = bui.buttonwidget( parent=self._root_widget, scale=0.7, position=(self._width - 60, self._height - 47), @@ -459,18 +454,18 @@ def __init__(self, origin: Sequence[float] = (0, 0)): label="\xee\x80\x90", autoselect=True, button_type='square', - on_activate_call=ba.WeakCall(self._on_menu_button_press), + on_activate_call=bs.WeakCall(self._on_menu_button_press), color=(0.55, 0.73, 0.25), - icon=ba.gettexture('menuButton'), + icon=bui.gettexture('menuButton'), iconscale=1.2) - info = _ba.get_connection_to_host_info() + info = bs.get_connection_to_host_info() if info.get('name', '') != '': title = info['name'] else: - title = ba.Lstr(resource=self._r + '.titleText') + title = babase.Lstr(resource=self._r + '.titleText') - self._title_text = ba.textwidget(parent=self._root_widget, + self._title_text = bui.textwidget(parent=self._root_widget, scale=0.9, color=(0.5, 0.7, 0.5), text=title, @@ -483,7 +478,7 @@ def __init__(self, origin: Sequence[float] = (0, 0)): h_align='center', v_align='center') - self._empty_str = ba.textwidget(parent=self._root_widget, + self._empty_str = bui.textwidget(parent=self._root_widget, scale=0.75, size=(0, 0), position=(self._width * 0.5, @@ -494,38 +489,38 @@ def __init__(self, origin: Sequence[float] = (0, 0)): v_align='center') self._scroll_width = self._width - 50 - self._scrollwidget = ba.scrollwidget(parent=self._root_widget, + self._scrollwidget = bui.scrollwidget(parent=self._root_widget, size=(self._scroll_width, self._height - 200), position=(30, 80), color=(0.4, 0.6, 0.3)) - self._columnwidget = ba.columnwidget(parent=self._scrollwidget, + self._columnwidget = bui.columnwidget(parent=self._scrollwidget, border=2, margin=0) - ba.widget(edit=self._menu_button, down_widget=self._columnwidget) + bui.widget(edit=self._menu_button, down_widget=self._columnwidget) - self._muted_text = ba.textwidget( + self._muted_text = bui.textwidget( parent=self._root_widget, position=(self._width * 0.5, self._height * 0.5), size=(0, 0), h_align='center', v_align='center', text="") - self._chat_texts: List[ba.Widget] = [] - self._chat_texts_haxx: List[ba.Widget] = [] + self._chat_texts: List[bui.Widget] = [] + self._chat_texts_haxx: List[bui.Widget] = [] # add all existing messages if chat is not muted # print("updates") if True: # smoothy - always show chat in partywindow - msgs = _ba.get_chat_messages() + msgs = bs.get_chat_messages() for msg in msgs: self._add_msg(msg) # print(msg) # else: - # msgs=_ba.get_chat_messages() + # msgs=_babase.get_chat_messages() # for msg in msgs: # print(msg); - # txt = ba.textwidget(parent=self._columnwidget, + # txt = bui.textwidget(parent=self._columnwidget, # text=msg, # h_align='left', # v_align='center', @@ -538,8 +533,8 @@ def __init__(self, origin: Sequence[float] = (0, 0)): # if len(self._chat_texts) > 40: # first = self._chat_texts.pop(0) # first.delete() - # ba.containerwidget(edit=self._columnwidget, visible_child=txt) - self.ping_widget = txt = ba.textwidget( + # bui.containerwidget(edit=self._columnwidget, visible_child=txt) + self.ping_widget = txt = bui.textwidget( parent=self._root_widget, scale=0.6, size=(20, 5), @@ -549,12 +544,12 @@ def __init__(self, origin: Sequence[float] = (0, 0)): selectable=True, autoselect=False, v_align='center') - _ba.ping_widget = self.ping_widget + _babase.ping_widget = self.ping_widget def enable_chat_mode(): pass - self._text_field = txt = ba.textwidget( + self._text_field = txt = bui.textwidget( parent=self._root_widget, editable=True, size=(530-80, 40), @@ -563,14 +558,14 @@ def enable_chat_mode(): maxwidth=494, shadow=0.3, flatness=1.0, - description=ba.Lstr(resource=self._r + '.chatMessageText'), + description=babase.Lstr(resource=self._r + '.chatMessageText'), autoselect=True, v_align='center', corner_scale=0.7) - # for m in _ba.get_chat_messages(): + # for m in _babase.get_chat_messages(): # if m: - # ttchat=ba.textwidget( + # ttchat=bui.textwidget( # parent=self._columnwidget, # size=(10,10), # h_align='left', @@ -583,19 +578,19 @@ def enable_chat_mode(): # always_highlight=True # ) - ba.widget(edit=self._scrollwidget, + bui.widget(edit=self._scrollwidget, autoselect=True, left_widget=self._cancel_button, up_widget=self._cancel_button, down_widget=self._text_field) - ba.widget(edit=self._columnwidget, + bui.widget(edit=self._columnwidget, autoselect=True, up_widget=self._cancel_button, down_widget=self._text_field) - ba.containerwidget(edit=self._root_widget, selected_child=txt) - btn = ba.buttonwidget(parent=self._root_widget, + bui.containerwidget(edit=self._root_widget, selected_child=txt) + btn = bui.buttonwidget(parent=self._root_widget, size=(50, 35), - label=ba.Lstr(resource=self._r + '.sendText'), + label=babase.Lstr(resource=self._r + '.sendText'), button_type='square', autoselect=True, position=(self._width - 70, 35), @@ -603,7 +598,7 @@ def enable_chat_mode(): def _times_button_on_click(): # self._popup_type = "send_Times_Press" - # allow_range = 100 if _ba.get_foreground_host_session() is not None else 4 + # allow_range = 100 if _babase.get_foreground_host_session() is not None else 4 # PopupMenuWindow(position=self._times_button.get_screen_space_center(), # scale=_get_popup_window_scale(), # choices=[str(index) for index in range(1,allow_range + 1)], @@ -622,7 +617,7 @@ def _times_button_on_click(): self._send_msg_times = 1 - self._times_button = ba.buttonwidget(parent=self._root_widget, + self._times_button = bui.buttonwidget(parent=self._root_widget, size=(50, 35), label="Quick", button_type='square', @@ -630,16 +625,15 @@ def _times_button_on_click(): position=(30, 35), on_activate_call=_times_button_on_click) - ba.textwidget(edit=txt, on_return_press_call=btn.activate) - self._name_widgets: List[ba.Widget] = [] + bui.textwidget(edit=txt, on_return_press_call=btn.activate) + self._name_widgets: List[bui.Widget] = [] self._roster: Optional[List[Dict[str, Any]]] = None self.smoothy_mode = 1 self.full_chat_mode = False - self._update_timer = ba.Timer(1.0, - ba.WeakCall(self._update), - repeat=True, - timetype=ba.TimeType.REAL) + self._update_timer = babase.AppTimer(1.0, + bs.WeakCall(self._update), + repeat=True) self._update() @@ -678,13 +672,13 @@ def _on_chat_press(self, msg, widget): self.msg_user_selected = msg.split(":")[0] self._popup_type = "chatmessagepress" - # _ba.chatmessage("pressed") + # bs.chatmessage("pressed") def _add_msg(self, msg: str) -> None: try: - if ba.app.config.resolve('Chat Muted'): + if babase.app.config.resolve('Chat Muted'): - txt = ba.textwidget(parent=self._columnwidget, + txt = bui.textwidget(parent=self._columnwidget, text=msg, h_align='left', v_align='center', @@ -696,12 +690,12 @@ def _add_msg(self, msg: str) -> None: maxwidth=self._scroll_width * 0.94, shadow=0.3, flatness=1.0) - ba.textwidget(edit=txt, - on_activate_call=ba.Call( + bui.textwidget(edit=txt, + on_activate_call=babase.Call( self._on_chat_press, msg, txt)) else: - txt = ba.textwidget(parent=self._columnwidget, + txt = bui.textwidget(parent=self._columnwidget, text=msg, h_align='left', v_align='center', @@ -714,24 +708,24 @@ def _add_msg(self, msg: str) -> None: shadow=0.3, flatness=1.0) - # btn = ba.buttonwidget(parent=self._columnwidget, + # btn = bui.buttonwidget(parent=self._columnwidget, # scale=0.7, # size=(100,20), # label="smoothy buttin", - # icon=ba.gettexture('replayIcon'), + # icon=bs.gettexture('replayIcon'), # texture=None, # ) self._chat_texts_haxx.append(txt) if len(self._chat_texts_haxx) > 40: first = self._chat_texts_haxx.pop(0) first.delete() - ba.containerwidget(edit=self._columnwidget, visible_child=txt) + bui.containerwidget(edit=self._columnwidget, visible_child=txt) except Exception: pass def _add_msg_when_muted(self, msg: str) -> None: - txt = ba.textwidget(parent=self._columnwidget, + txt = bui.textwidget(parent=self._columnwidget, text=msg, h_align='left', v_align='center', @@ -744,31 +738,31 @@ def _add_msg_when_muted(self, msg: str) -> None: if len(self._chat_texts) > 40: first = self._chat_texts.pop(0) first.delete() - ba.containerwidget(edit=self._columnwidget, visible_child=txt) + bui.containerwidget(edit=self._columnwidget, visible_child=txt) def color_picker_closing(self, picker) -> None: - ba._appconfig.commit_app_config() + babase._appconfig.commit_app_config() def color_picker_selected_color(self, picker, color) -> None: # bs.animateArray(self._root_widget,"color",3,{0:self._bg_color,1500:color}) - ba.containerwidget(edit=self._root_widget, color=color) + bui.containerwidget(edit=self._root_widget, color=color) self._bg_color = color - ba.app.config["PartyWindow_Main_Color"] = color + babase.app.config["PartyWindow_Main_Color"] = color def _on_nick_rename_press(self, arg) -> None: - ba.containerwidget(edit=self._root_widget, transition='out_scale') + bui.containerwidget(edit=self._root_widget, transition='out_scale') c_width = 600 c_height = 250 - uiscale = ba.app.ui.uiscale - self._nick_rename_window = cnt = ba.containerwidget( + uiscale = bui.app.ui_v1.uiscale + self._nick_rename_window = cnt = bui.containerwidget( - scale=(1.8 if uiscale is ba.UIScale.SMALL else - 1.55 if uiscale is ba.UIScale.MEDIUM else 1.0), + scale=(1.8 if uiscale is babase.UIScale.SMALL else + 1.55 if uiscale is babase.UIScale.MEDIUM else 1.0), size=(c_width, c_height), transition='in_scale') - ba.textwidget(parent=cnt, + bui.textwidget(parent=cnt, size=(0, 0), h_align='center', v_align='center', @@ -776,7 +770,7 @@ def _on_nick_rename_press(self, arg) -> None: maxwidth=c_width * 0.8, position=(c_width * 0.5, c_height - 60)) id = self._get_nick(arg) - self._player_nick_text = txt89 = ba.textwidget( + self._player_nick_text = txt89 = bui.textwidget( parent=cnt, size=(c_width * 0.8, 40), h_align='left', @@ -788,41 +782,41 @@ def _on_nick_rename_press(self, arg) -> None: autoselect=True, maxwidth=c_width * 0.7, max_chars=200) - cbtn = ba.buttonwidget( + cbtn = bui.buttonwidget( parent=cnt, - label=ba.Lstr(resource='cancelText'), - on_activate_call=ba.Call( - lambda c: ba.containerwidget(edit=c, transition='out_scale'), + label=babase.Lstr(resource='cancelText'), + on_activate_call=babase.Call( + lambda c: bui.containerwidget(edit=c, transition='out_scale'), cnt), size=(180, 60), position=(30, 30), autoselect=True) - okb = ba.buttonwidget(parent=cnt, + okb = bui.buttonwidget(parent=cnt, label='Rename', size=(180, 60), position=(c_width - 230, 30), - on_activate_call=ba.Call( + on_activate_call=babase.Call( self._add_nick, arg), autoselect=True) - ba.widget(edit=cbtn, right_widget=okb) - ba.widget(edit=okb, left_widget=cbtn) - ba.textwidget(edit=txt89, on_return_press_call=okb.activate) - ba.containerwidget(edit=cnt, cancel_button=cbtn, start_button=okb) + bui.widget(edit=cbtn, right_widget=okb) + bui.widget(edit=okb, left_widget=cbtn) + bui.textwidget(edit=txt89, on_return_press_call=okb.activate) + bui.containerwidget(edit=cnt, cancel_button=cbtn, start_button=okb) def _add_nick(self, arg): - config = ba.app.config - new_name_raw = cast(str, ba.textwidget(query=self._player_nick_text)) + config = babase.app.config + new_name_raw = cast(str, bui.textwidget(query=self._player_nick_text)) if arg: if not isinstance(config.get('players nick'), dict): config['players nick'] = {} config['players nick'][arg] = new_name_raw config.commit() - ba.containerwidget(edit=self._nick_rename_window, + bui.containerwidget(edit=self._nick_rename_window, transition='out_scale') - # ba.containerwidget(edit=self._root_widget,transition='in_scale') + # bui.containerwidget(edit=self._root_widget,transition='in_scale') def _get_nick(self, id): - config = ba.app.config + config = babase.app.config if not isinstance(config.get('players nick'), dict): return "add nick" elif id in config['players nick']: @@ -832,23 +826,22 @@ def _get_nick(self, id): def _reset_game_record(self) -> None: try: - dir_path = _ba.get_replays_dir() + dir_path = _babase.get_replays_dir() curFilePath = os.path.join(dir_path+os.sep, "__lastReplay.brp").encode(SystemEncode) - newFileName = str(ba.Lstr(resource="replayNameDefaultText").evaluate( + newFileName = str(babase.Lstr(resource="replayNameDefaultText").evaluate( )+" (%s)" % (datetime.datetime.strftime(datetime.datetime.now(), "%Y_%m_%d_%H_%M_%S"))+".brp") newFilePath = os.path.join(dir_path+os.sep, newFileName).encode(SystemEncode) #print(curFilePath, newFilePath) # os.rename(curFilePath,newFilePath) shutil.copyfile(curFilePath, newFilePath) - _ba.reset_game_activity_tracking() - ba.screenmessage(_getTransText("Game_Record_Saved") % newFileName, color=(1, 1, 1)) + bs.broadcastmessage(_getTransText("Game_Record_Saved") % newFileName, color=(1, 1, 1)) except: - ba.print_exception() - ba.screenmessage(ba.Lstr(resource="replayWriteErrorText").evaluate() + + babase.print_exception() + bs.broadcastmessage(babase.Lstr(resource="replayWriteErrorText").evaluate() + ""+traceback.format_exc(), color=(1, 0, 0)) def _on_menu_button_press(self) -> None: - is_muted = ba.app.config.resolve('Chat Muted') + is_muted = babase.app.config.resolve('Chat Muted') global chatlogger choices = ["unmute" if is_muted else "mute", "screenmsg", "addQuickReply", "removeQuickReply", "chatlogger", "credits"] @@ -863,10 +856,6 @@ def _on_menu_button_press(self) -> None: _getTransText("Credits_for_This", isBaLstr=True) ] - if len(tranTypes) > 0: - choices.append("translator") - DisChoices.append(_getTransText("Translator", isBaLstr=True)) - choices.append("resetGameRecord") DisChoices.append(_getTransText("Restart_Game_Record", isBaLstr=True)) if self._getCustomSets().get("Enable_HostInfo_Debug", False): @@ -882,23 +871,23 @@ def _on_menu_button_press(self) -> None: self._popup_type = "menu" def _on_party_member_press(self, client_id: int, is_host: bool, - widget: ba.Widget) -> None: + widget: bui.Widget) -> None: # if we"re the host, pop up "kick" options for all non-host members - if _ba.get_foreground_host_session() is not None: - kick_str = ba.Lstr(resource="kickText") + if bs.get_foreground_host_session() is not None: + kick_str = babase.Lstr(resource="kickText") else: - kick_str = ba.Lstr(resource="kickVoteText") + kick_str = babase.Lstr(resource="kickVoteText") choices = ["kick", "@ this guy", "info", "adminkick"] - choices_display = [kick_str, _getTransText("Mention_this_guy", isBaLstr=True), ba.Lstr(resource="??Unknown??", fallback_value="Info"), - ba.Lstr(resource="??Unknown??", fallback_value=_getTransText("Kick_ID") % client_id)] + choices_display = [kick_str, _getTransText("Mention_this_guy", isBaLstr=True), babase.Lstr(resource="??Unknown??", fallback_value="Info"), + babase.Lstr(resource="??Unknown??", fallback_value=_getTransText("Kick_ID") % client_id)] try: if len(self._getCustomSets().get("partyMemberPress_Custom") if isinstance(self._getCustomSets().get("partyMemberPress_Custom"), dict) else {}) > 0: choices.append("customAction") choices_display.append(_getTransText("Custom_Action", isBaLstr=True)) except: - ba.print_exception() + babase.print_exception() PopupMenuWindow(position=widget.get_screen_space_center(), scale=_get_popup_window_scale(), @@ -911,17 +900,17 @@ def _on_party_member_press(self, client_id: int, is_host: bool, self._popup_type = "partyMemberPress" def _send_chat_message(self) -> None: - sendtext = ba.textwidget(query=self._text_field) + sendtext = bui.textwidget(query=self._text_field) if sendtext == ".ip": - _ba.chatmessage("IP "+ip_add+" PORT "+str(p_port)) + bs.chatmessage("IP "+ip_add+" PORT "+str(p_port)) - ba.textwidget(edit=self._text_field, text="") + bui.textwidget(edit=self._text_field, text="") return elif sendtext == ".info": - if _ba.get_connection_to_host_info() == {}: + if bs.get_connection_to_host_info() == {}: s_build = 0 else: - s_build = _ba.get_connection_to_host_info()['build_number'] + s_build = bs.get_connection_to_host_info()['build_number'] s_v = "0" if s_build <= 14365: s_v = " 1.4.148 or below" @@ -933,16 +922,16 @@ def _send_chat_message(self) -> None: s_v = "1.6 " else: s_v = "1.7 and above " - _ba.chatmessage("script version "+s_v+"- build "+str(s_build)) - ba.textwidget(edit=self._text_field, text="") + bs.chatmessage("script version "+s_v+"- build "+str(s_build)) + bui.textwidget(edit=self._text_field, text="") return elif sendtext == ".ping": - _ba.chatmessage("My ping:"+str(current_ping)) - ba.textwidget(edit=self._text_field, text="") + bs.chatmessage("My ping:"+str(current_ping)) + bui.textwidget(edit=self._text_field, text="") return elif sendtext == ".save": - info = _ba.get_connection_to_host_info() - config = ba.app.config + info = bs.get_connection_to_host_info() + config = babase.app.config if info.get('name', '') != '': title = info['name'] if not isinstance(config.get('Saved Servers'), dict): @@ -953,9 +942,9 @@ def _send_chat_message(self) -> None: 'name': title } config.commit() - ba.screenmessage("Server saved to manual") - ba.playsound(ba.getsound('gunCocking')) - ba.textwidget(edit=self._text_field, text="") + bs.broadcastmessage("Server saved to manual") + bui.getsound('gunCocking').play() + bui.textwidget(edit=self._text_field, text="") return # elif sendtext != "": # for index in range(getattr(self,"_send_msg_times",1)): @@ -987,16 +976,16 @@ def _send_chat_message(self) -> None: for m in range(0, hp): ms2 = ms2+" "+msg1[m] - _ba.chatmessage(ms2) + bs.chatmessage(ms2) ms2 = "" for m in range(hp, len(msg1)): ms2 = ms2+" "+msg1[m] - _ba.chatmessage(ms2) + bs.chatmessage(ms2) else: - _ba.chatmessage(msg) + bs.chatmessage(msg) - ba.textwidget(edit=self._text_field, text="") + bui.textwidget(edit=self._text_field, text="") # else: # Quickreply = self._get_quick_responds() # if len(Quickreply) > 0: @@ -1008,8 +997,8 @@ def _send_chat_message(self) -> None: # delegate=self) # self._popup_type = "QuickMessageSelect" # else: - # _ba.chatmessage(sendtext) - # ba.textwidget(edit=self._text_field,text="") + # bs.chatmessage(sendtext) + # bui.textwidget(edit=self._text_field,text="") def _get_quick_responds(self): if not hasattr(self, "_caches") or not isinstance(self._caches, dict): @@ -1024,9 +1013,9 @@ def _get_quick_responds(self): with open(filePath, "wb") as writer: writer.write(({"Chinese": u"\xe5\x8e\x89\xe5\xae\xb3\xef\xbc\x8c\xe8\xbf\x98\xe6\x9c\x89\xe8\xbf\x99\xe7\xa7\x8d\xe9\xaa\x9a\xe6\x93\x8d\xe4\xbd\x9c!\ \xe4\xbd\xa0\xe2\x84\xa2\xe8\x83\xbd\xe5\x88\xab\xe6\x89\x93\xe9\x98\x9f\xe5\x8f\x8b\xe5\x90\x97\xef\xbc\x9f\ -\xe5\x8f\xaf\xe4\xbb\xa5\xe5\x95\x8a\xe5\xb1\x85\xe7\x84\xb6\xe8\x83\xbd\xe8\xbf\x99\xe4\xb9\x88\xe7\x8e\xa9\xef\xbc\x9f"}.get(Current_Lang, "What the hell?\nDude that's amazing!")).encode("UTF-8")) +\xe5\x8f\xaf\xe4\xbb\xa5\xe5\x95\x8a\xe5\xb1\x85\xe7\x84\xb6\xe8\x83\xbd\xe8\xbf\x99\xe4\xb9\x88\xe7\x8e\xa9\xef\xbc\x9f"}.get(Current_Lang, "Thats Amazing !")).encode("UTF-8")) if os.path.getmtime(filePath) != self._caches.get("Vertify_Quickresponse_Text"): - with open(filePath, "rU", encoding="UTF-8-sig") as Reader: + with open(filePath, "r+", encoding="utf-8") as Reader: Text = Reader.read() if Text.startswith(str(codecs.BOM_UTF8)): Text = Text[3:] @@ -1034,18 +1023,18 @@ def _get_quick_responds(self): self._caches["Vertify_Quickresponse_Text"] = os.path.getmtime(filePath) return (self._caches.get("quickReplys", [])) except: - ba.print_exception() - ba.screenmessage(ba.Lstr(resource="errorText"), (1, 0, 0)) - ba.playsound(ba.getsound("error")) + babase.print_exception() + bs.broadcastmessage(babase.Lstr(resource="errorText"), (1, 0, 0)) + bui.getsound("error").play() def _write_quick_responds(self, data): try: with open(os.path.join(RecordFilesDir, "Quickmessage.txt"), "wb") as writer: writer.write("\\n".join(data).encode("utf-8")) except: - ba.print_exception() - ba.screenmessage(ba.Lstr(resource="errorText"), (1, 0, 0)) - ba.playsound(ba.getsound("error")) + babase.print_exception() + bs.broadcastmessage(babase.Lstr(resource="errorText"), (1, 0, 0)) + bui.getsound("error").play() def _getCustomSets(self): try: @@ -1061,7 +1050,7 @@ def _getCustomSets(self): filePath = os.path.join(RecordFilesDir, "Settings.json") if os.path.isfile(filePath): if os.path.getmtime(filePath) != self._caches.get("Vertify_MainSettings.json_Text"): - with open(filePath, "rU", encoding="UTF-8-sig") as Reader: + with open(filePath, "r+", encoding="utf-8") as Reader: Text = Reader.read() if Text.startswith(str(codecs.BOM_UTF8)): Text = Text[3:] @@ -1070,11 +1059,11 @@ def _getCustomSets(self): self._caches["Vertify_MainSettings.json_Text"] = os.path.getmtime( filePath) except: - ba.print_exception() + babase.print_exception() return (self._caches.get("PartyWindow_Sets") if isinstance(self._caches.get("PartyWindow_Sets"), dict) else {}) except: - ba.print_exception() + babase.print_exception() def _getObjectByID(self, type="playerName", ID=None): if ID is None: @@ -1116,7 +1105,7 @@ def _getObjectByID(self, type="playerName", ID=None): elif type.lower() in ("account", "displaystring"): return ((roster["display_string"])) except: - ba.print_exception() + babase.print_exception() return (None if len(output) == 0 else output) @@ -1126,37 +1115,37 @@ def _edit_text_msg_box(self, text, type="rewrite"): type = type.lower() text = (text) if type.find("add") != -1: - ba.textwidget(edit=self._text_field, text=ba.textwidget(query=self._text_field)+text) + bui.textwidget(edit=self._text_field, text=bui.textwidget(query=self._text_field)+text) else: - ba.textwidget(edit=self._text_field, text=text) + bui.textwidget(edit=self._text_field, text=text) - def _send_admin_kick_command(self): _ba.chatmessage( + def _send_admin_kick_command(self): bs.chatmessage( "/kick " + str(self._popup_party_member_client_id)) def new_input_window_callback(self, got_text, flag, code): if got_text: if flag.startswith("Host_Kick_Player:"): try: - result = _ba.disconnect_client( + result = _babase.disconnect_client( self._popup_party_member_client_id, ban_time=int(code)) if not result: - ba.playsound(ba.getsound('error')) - ba.screenmessage( - ba.Lstr(resource='getTicketsWindow.unavailableText'), + bui.getsound('error').play() + bs.broadcastmessage( + babase.Lstr(resource='getTicketsWindow.unavailableText'), color=(1, 0, 0)) except: - ba.playsound(ba.getsound('error')) + bui.getsound('error').play() print(traceback.format_exc()) def _kick_selected_player(self): """ - result = _ba._disconnectClient(self._popup_party_member_client_id,banTime) + result = _babase._disconnectClient(self._popup_party_member_client_id,banTime) if not result: - ba.playsound(ba.getsound("error")) - ba.screenmessage(ba.Lstr(resource="getTicketsWindow.unavailableText"),color=(1,0,0)) + bs.getsound("error").play() + bs.broadcastmessage(babase.Lstr(resource="getTicketsWindow.unavailableText"),color=(1,0,0)) """ if self._popup_party_member_client_id != -1: - if _ba.get_foreground_host_session() is not None: + if bs.get_foreground_host_session() is not None: self._popup_type = "banTimePress" choices = [0, 30, 60, 120, 300, 600, 900, 1800, 3600, 7200, 99999999] if not (isinstance(self._getCustomSets().get("Ban_Time_List"), list) and all([isinstance(item, int) for item in self._getCustomSets().get("Ban_Time_List")])) else self._getCustomSets().get("Ban_Time_List") @@ -1174,33 +1163,32 @@ def _kick_selected_player(self): """ else: # kick-votes appeared in build 14248 - if (_ba.get_connection_to_host_info().get('build_number', 0) < + if (bs.get_connection_to_host_info().get('build_number', 0) < 14248): - ba.playsound(ba.getsound('error')) - ba.screenmessage( - ba.Lstr(resource='getTicketsWindow.unavailableText'), + bui.getsound('error').play() + bs.broadcastmessage( + babase.Lstr(resource='getTicketsWindow.unavailableText'), color=(1, 0, 0)) else: # Ban for 5 minutes. - result = _ba.disconnect_client( + result = bs.disconnect_client( self._popup_party_member_client_id, ban_time=5 * 60) if not result: - ba.playsound(ba.getsound('error')) - ba.screenmessage( - ba.Lstr(resource='getTicketsWindow.unavailableText'), + bui.getsound('error').play() + bs.broadcastmessage( + babase.Lstr(resource='getTicketsWindow.unavailableText'), color=(1, 0, 0)) else: - ba.playsound(ba.getsound('error')) - ba.screenmessage( - ba.Lstr(resource='internal.cantKickHostError'), + bui.getsound('error').play() + bs.broadcastmessage( + babase.Lstr(resource='internal.cantKickHostError'), color=(1, 0, 0)) - #NewShareCodeWindow(origin_widget=self.get_root_widget(), delegate=None,code = "300",execText = u"_ba._disconnectClient(%d,{Value})"%self._popup_party_member_client_id) + #NewShareCodeWindow(origin_widget=self.get_root_widget(), delegate=None,code = "300",execText = u"_babase._disconnectClient(%d,{Value})"%self._popup_party_member_client_id) def joinbombspot(self): - import random - url = ['https://discord.gg/CbxhJTrRta', 'https://discord.gg/ucyaesh'] - ba.open_url(url[random.randint(0, 1)]) + + bui.open_url("https://discord.gg/ucyaesh") def _update(self) -> None: # pylint: disable=too-many-locals @@ -1209,19 +1197,19 @@ def _update(self) -> None: # pylint: disable=too-many-nested-blocks # # update muted state - # if ba.app.config.resolve('Chat Muted'): - # ba.textwidget(edit=self._muted_text, color=(1, 1, 1, 0.3)) + # if babase.app.config.resolve('Chat Muted'): + # bui.textwidget(edit=self._muted_text, color=(1, 1, 1, 0.3)) # # clear any chat texts we're showing # if self._chat_texts: # while self._chat_texts: # first = self._chat_texts.pop() # first.delete() # else: - # ba.textwidget(edit=self._muted_text, color=(1, 1, 1, 0.0)) + # bui.textwidget(edit=self._muted_text, color=(1, 1, 1, 0.0)) # update roster section - roster = _ba.get_game_roster() + roster = bs.get_game_roster() global f_chat global smo_mode if roster != self._roster or smo_mode != self.smoothy_mode or f_chat != self.full_chat_mode: @@ -1235,15 +1223,15 @@ def _update(self) -> None: if not self._roster: top_section_height = 60 - ba.textwidget(edit=self._empty_str, - text=ba.Lstr(resource=self._r + '.emptyText')) - ba.scrollwidget(edit=self._scrollwidget, + bui.textwidget(edit=self._empty_str, + text=babase.Lstr(resource=self._r + '.emptyText')) + bui.scrollwidget(edit=self._scrollwidget, size=(self._width - 50, self._height - top_section_height - 110), position=(30, 80)) elif self.full_chat_mode: top_section_height = 60 - ba.scrollwidget(edit=self._scrollwidget, + bui.scrollwidget(edit=self._scrollwidget, size=(self._width - 50, self._height - top_section_height - 75), position=(30, 80)) @@ -1293,11 +1281,11 @@ def _update(self) -> None: 'display_string'] except Exception: - ba.print_exception( + babase.print_exception( 'Error calcing client name str.') p_str = '???' try: - widget = ba.textwidget(parent=self._root_widget, + widget = bui.textwidget(parent=self._root_widget, position=(pos[0], pos[1]), scale=t_scale, size=(c_width * 0.85, 30), @@ -1308,7 +1296,7 @@ def _update(self) -> None: selectable=True, autoselect=True, click_activate=True, - text=ba.Lstr(value=p_str), + text=babase.Lstr(value=p_str), h_align='left', v_align='center') self._name_widgets.append(widget) @@ -1328,8 +1316,8 @@ def _update(self) -> None: # calls; not spec-string (perhaps should wait till # client_id is more readily available though). try: - ba.textwidget(edit=widget, - on_activate_call=ba.Call( + bui.textwidget(edit=widget, + on_activate_call=babase.Call( self._on_party_member_press, self._roster[index]['client_id'], is_host, widget)) @@ -1345,12 +1333,12 @@ def _update(self) -> None: if is_host: twd = min( c_width * 0.85, - _ba.get_string_width( + _babase.get_string_width( p_str, suppress_warning=True) * t_scale) try: self._name_widgets.append( - ba.textwidget( + bui.textwidget( parent=self._root_widget, position=(pos[0] + twd + 1, pos[1] - 0.5), @@ -1359,7 +1347,7 @@ def _update(self) -> None: v_align='center', maxwidth=c_width * 0.96 - twd, color=(0.1, 1, 0.1, 0.5), - text=ba.Lstr(resource=self._r + + text=babase.Lstr(resource=self._r + '.hostText'), scale=0.4, shadow=0.1, @@ -1367,8 +1355,8 @@ def _update(self) -> None: except Exception: pass try: - ba.textwidget(edit=self._empty_str, text='') - ba.scrollwidget(edit=self._scrollwidget, + bui.textwidget(edit=self._empty_str, text='') + bui.scrollwidget(edit=self._scrollwidget, size=(self._width - 50, max(100, self._height - 139 - c_height_total)), @@ -1395,7 +1383,7 @@ def hide_screen_msg(self): file = open('ba_data/data/languages/english.json', "w") json.dump(eng, file) file.close() - ba.app.lang.setlanguage(None) + bs.app.lang.setlanguage(None) def restore_screen_msg(self): file = open('ba_data/data/languages/english.json') @@ -1416,21 +1404,21 @@ def restore_screen_msg(self): file = open('ba_data/data/languages/english.json', "w") json.dump(eng, file) file.close() - ba.app.lang.setlanguage(None) + bs.app.lang.setlanguage(None) def popup_menu_selected_choice(self, popup_window: PopupMenuWindow, choice: str) -> None: """Called when a choice is selected in the popup.""" global unmuted_names if self._popup_type == "banTimePress": - result = _ba.disconnect_client(self._popup_party_member_client_id, ban_time=int(choice)) + result = _babase.disconnect_client(self._popup_party_member_client_id, ban_time=int(choice)) if not result: - ba.playsound(ba.getsound('error')) - ba.screenmessage( - ba.Lstr(resource='getTicketsWindow.unavailableText'), + bui.getsound('error').play() + bs.broadcastmessage( + babase.Lstr(resource='getTicketsWindow.unavailableText'), color=(1, 0, 0)) elif self._popup_type == "send_Times_Press": self._send_msg_times = int(choice) - ba.buttonwidget(edit=self._times_button, label="%s:%d" % + bui.buttonwidget(edit=self._times_button, label="%s:%d" % (_getTransText("Times"), getattr(self, "_send_msg_times", 1))) elif self._popup_type == "chatmessagepress": @@ -1508,12 +1496,12 @@ def popup_menu_selected_choice(self, popup_window: PopupMenuWindow, delegate=self) self._popup_type = "customAction_partyMemberPress" else: - ba.playsound(ba.getsound("error")) - ba.screenmessage( - ba.Lstr(resource="getTicketsWindow.unavailableText"), color=(1, 0, 0)) + bui.getsound("error").play() + bs.broadcastmessage( + babase.Lstr(resource="getTicketsWindow.unavailableText"), color=(1, 0, 0)) elif self._popup_type == "menu": if choice in ("mute", "unmute"): - cfg = ba.app.config + cfg = babase.app.config cfg['Chat Muted'] = (choice == 'mute') cfg.apply_and_commit() if cfg['Chat Muted']: @@ -1531,11 +1519,11 @@ def popup_menu_selected_choice(self, popup_window: PopupMenuWindow, global chatlogger if chatlogger: chatlogger = False - ba.screenmessage("Chat logger turned OFF") + bs.broadcastmessage("Chat logger turned OFF") else: chatlogger = True chatloggThread().run() - ba.screenmessage("Chat logger turned ON") + bs.broadcastmessage("Chat logger turned ON") elif choice == 'screenmsg': global screenmsg if screenmsg: @@ -1546,15 +1534,15 @@ def popup_menu_selected_choice(self, popup_window: PopupMenuWindow, self.restore_screen_msg() elif choice == "addQuickReply": try: - newReply = ba.textwidget(query=self._text_field) + newReply = bui.textwidget(query=self._text_field) data = self._get_quick_responds() data.append(newReply) self._write_quick_responds(data) - ba.screenmessage(_getTransText("Something_is_added") % + bs.broadcastmessage(_getTransText("Something_is_added") % newReply, color=(0, 1, 0)) - ba.playsound(ba.getsound("dingSmallHigh")) + bui.getsound("dingSmallHigh").play() except: - ba.print_exception() + babase.print_exception() elif choice == "removeQuickReply": Quickreply = self._get_quick_responds() PopupMenuWindow(position=self._text_field.get_screen_space_center(), @@ -1564,12 +1552,12 @@ def popup_menu_selected_choice(self, popup_window: PopupMenuWindow, current_choice=Quickreply[0], delegate=self) self._popup_type = "removeQuickReplySelect" - elif choice in ("hostInfo_Debug",) and isinstance(_ba.get_connection_to_host_info(), dict): - if len(_ba.get_connection_to_host_info()) > 0: - # print(_ba.get_connection_to_host_info(),type(_ba.get_connection_to_host_info())) + elif choice in ("hostInfo_Debug",) and isinstance(bs.get_connection_to_host_info(), dict): + if len(bs.get_connection_to_host_info()) > 0: + # print(_babase.get_connection_to_host_info(),type(_babase.get_connection_to_host_info())) - ChoiceDis = list(_ba.get_connection_to_host_info().keys()) - NewChoices = ["ba.screenmessage(str(_ba.get_connection_to_host_info().get('%s')))" % ( + ChoiceDis = list(bs.get_connection_to_host_info().keys()) + NewChoices = ["bs.broadcastmessage(str(bs.get_connection_to_host_info().get('%s')))" % ( (str(i)).replace("'", r"'").replace('"', r'\\"')) for i in ChoiceDis] PopupMenuWindow(position=popup_window.root_widget.get_screen_space_center(), scale=_get_popup_window_scale(), @@ -1580,11 +1568,11 @@ def popup_menu_selected_choice(self, popup_window: PopupMenuWindow, self._popup_type = "Custom_Exec_Choice" else: - ba.playsound(ba.getsound("error")) - ba.screenmessage( - ba.Lstr(resource="getTicketsWindow.unavailableText"), color=(1, 0, 0)) + bui.getsound("error").play() + bs.broadcastmessage( + babase.Lstr(resource="getTicketsWindow.unavailableText"), color=(1, 0, 0)) elif choice == "translator": - chats = _ba._getChatMessages() + chats = _babase._getChatMessages() if len(chats) > 0: choices = [(item) for item in chats[::-1]] PopupMenuWindow(position=popup_window.root_widget.get_screen_space_center(), @@ -1595,34 +1583,17 @@ def popup_menu_selected_choice(self, popup_window: PopupMenuWindow, delegate=self) self._popup_type = "translator_Press" else: - ba.playsound(ba.getsound("error")) - ba.screenmessage( - ba.Lstr(resource="getTicketsWindow.unavailableText"), color=(1, 0, 0)) + bui.getsound("error").play() + bs.broadcastmessage( + babase.Lstr(resource="getTicketsWindow.unavailableText"), color=(1, 0, 0)) elif choice == "resetGameRecord": ConfirmWindow(text=_getTransText("Restart_Game_Record_Confirm"), action=self._reset_game_record, cancel_button=True, cancel_is_selected=True, color=self._bg_color, text_scale=1.0, origin_widget=self.get_root_widget()) elif self._popup_type == "translator_Press": + pass - if len(tranTypes) == 1: - exec("start_new_thread(OnlineTranslator.%s,(u'%s',))" % - (tranTypes[0], choice.replace("'", r"'").replace('"', r'\\"'))) - elif len(tranTypes) > 1: - choices = ["start_new_thread(OnlineTranslator.%s,(u'%s',))" % ( - item, choice.replace("'", r"'").replace('"', r'\\"')) for item in tranTypes] - - PopupMenuWindow(position=popup_window.root_widget.get_screen_space_center(), - scale=_get_popup_window_scale(), - choices=choices, - choices_display=_creat_Lstr_list(tranTypes), - current_choice=choices[0], - delegate=self) - self._popup_type = "Custom_Exec_Choice" - else: - ba.playsound(ba.getsound("error")) - ba.screenmessage( - ba.Lstr(resource="getTicketsWindow.unavailableText"), color=(1, 0, 0)) elif self._popup_type == "customAction_partyMemberPress": try: @@ -1658,8 +1629,8 @@ def popup_menu_selected_choice(self, popup_window: PopupMenuWindow, self.popup_menu_selected_choice(popup_window, choice.replace( curKeyWord, (playerName.replace("'", r"'").replace('"', r'\\"')), 1)) else: - ba.screenmessage(_getTransText("No_valid_player_found"), (1, 0, 0)) - ba.playsound(ba.getsound("error")) + bs.broadcastmessage(_getTransText("No_valid_player_found"), (1, 0, 0)) + bui.getsound("error").play() elif curKeyWord in (r"{$PlayerID}",) != 0: playerID = self._getObjectByID("PlayerID") playerName = self._getObjectByID("PlayerName") @@ -1682,28 +1653,28 @@ def popup_menu_selected_choice(self, popup_window: PopupMenuWindow, self.popup_menu_selected_choice(popup_window, choice.replace( r"{$PlayerID}", str(playerID).replace("'", r"'").replace('"', r'\\"'))) else: - ba.screenmessage(_getTransText("No_valid_player_id_found"), (1, 0, 0)) - ba.playsound(ba.getsound("error")) + bs.broadcastmessage(_getTransText("No_valid_player_id_found"), (1, 0, 0)) + bui.getsound("error").play() elif curKeyWord in (r"{$AccountInfo}",) != 0: self.popup_menu_selected_choice(popup_window, choice.replace( r"{$AccountInfo}", (str(self._getObjectByID("roster"))).replace("'", r"'").replace('"', r'\\"'), 1)) else: exec(choice) except Exception as e: - ba.screenmessage(repr(e), (1, 0, 0)) + bs.broadcastmessage(repr(e), (1, 0, 0)) elif self._popup_type == "QuickMessageSelect": - # ba.textwidget(edit=self._text_field,text=self._get_quick_responds()[index]) + # bui.textwidget(edit=self._text_field,text=self._get_quick_responds()[index]) self._edit_text_msg_box(choice, "add") elif self._popup_type == "removeQuickReplySelect": data = self._get_quick_responds() if len(data) > 0 and choice in data: data.remove(choice) self._write_quick_responds(data) - ba.screenmessage(_getTransText("Something_is_removed") % choice, (1, 0, 0)) - ba.playsound(ba.getsound("shieldDown")) + bs.broadcastmessage(_getTransText("Something_is_removed") % choice, (1, 0, 0)) + bui.getsound("shieldDown").play() else: - ba.screenmessage(ba.Lstr(resource="errorText"), (1, 0, 0)) - ba.playsound(ba.getsound("error")) + bs.broadcastmessage(babase.Lstr(resource="errorText"), (1, 0, 0)) + bui.getsound("error").play() elif choice.startswith("custom_Exec_Choice_") or self._popup_type == "Custom_Exec_Choice": exec(choice[len("custom_Exec_Choice_"):] if choice.startswith("custom_Exec_Choice_") else choice) @@ -1724,15 +1695,16 @@ 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) + req = urllib.request.Request(url, headers={"User-Agent": f'BS{_babase.env().get("build_number", 0)}',"Accept-Language": "en-US,en;q=0.9",}) + data = urllib.request.urlopen(req) account_data = json.loads(data.read().decode('utf-8'))[0] pbid = account_data["pbid"] - except: + except Exception as e: + print(e) pass - # _ba.pushcall(Call(updateAccountWindow,loading_widget,accounts[0]),from_other_thread=True) - _ba.pushcall(Call(CustomAccountViewerWindow, pbid, account_data, + # _babase.pushcall(Call(updateAccountWindow,loading_widget,accounts[0]),from_other_thread=True) + _babase.pushcall(Call(CustomAccountViewerWindow, pbid, account_data, servers, loading_widget), from_other_thread=True) @@ -1748,26 +1720,26 @@ def __init__(self, account_id, custom_data, servers, loading_widget): self.servers = servers def _copy_pb(self): - ba.clipboard_set_text(self.pb_id) - ba.screenmessage(ba.Lstr(resource='gatherWindow.copyCodeConfirmText')) + babase.clipboard_set_text(self.pb_id) + bs.broadcastmessage(babase.Lstr(resource='gatherWindow.copyCodeConfirmText')) def _on_query_response(self, data): if data is None: - ba.textwidget(edit=self._loading_text, text="") - ba.textwidget(parent=self._scrollwidget, + bui.textwidget(edit=self._loading_text, text="") + bui.textwidget(parent=self._scrollwidget, size=(0, 0), position=(170, 200), flatness=1.0, h_align='center', v_align='center', scale=0.5, - color=ba.app.ui.infotextcolor, + color=bui.app.ui_v1.infotextcolor, text="Mutual servers", maxwidth=300) v = 200-21 for server in self.servers: - ba.textwidget(parent=self._scrollwidget, + bui.textwidget(parent=self._scrollwidget, size=(0, 0), position=(170, v), h_align='center', @@ -1794,15 +1766,15 @@ def _on_query_response(self, data): if trophystr == '': trophystr = '-' except Exception: - ba.print_exception('Error displaying trophies.') + babase.print_exception('Error displaying trophies.') account_name_spacing = 15 tscale = 0.65 - ts_height = _ba.get_string_height(trophystr, + ts_height = _babase.get_string_height(trophystr, suppress_warning=True) sub_width = self._width - 80 sub_height = 500 + ts_height * tscale + \ account_name_spacing * len(data['accountDisplayStrings']) - self._subcontainer = ba.containerwidget( + self._subcontainer = bui.containerwidget( parent=self._scrollwidget, size=(sub_width, sub_height), background=False) @@ -1817,7 +1789,7 @@ def _on_query_response(self, data): try: if data['profile'] is not None: profile = data['profile'] - character = ba.app.spaz_appearances.get( + character = babase.app.spaz_appearances.get( profile['character'], None) if character is not None: tint_color = (profile['color'] if 'color' @@ -1827,31 +1799,31 @@ def _on_query_response(self, data): (1, 1, 1)) icon_tex = character.icon_texture tint_tex = character.icon_mask_texture - mask_texture = ba.gettexture( + mask_texture = bui.gettexture( 'characterIconMask') - ba.imagewidget( + bui.imagewidget( parent=self._subcontainer, position=(sub_width * center - 40, v - 80), size=(80, 80), color=(1, 1, 1), mask_texture=mask_texture, - texture=ba.gettexture(icon_tex), - tint_texture=ba.gettexture(tint_tex), + texture=bui.gettexture(icon_tex), + tint_texture=bui.gettexture(tint_tex), tint_color=tint_color, tint2_color=tint2_color) v -= 95 except Exception: - ba.print_exception('Error displaying character.') - ba.textwidget( + babase.print_exception('Error displaying character.') + bui.textwidget( parent=self._subcontainer, size=(0, 0), position=(sub_width * center, v), h_align='center', v_align='center', scale=0.9, - color=ba.safecolor(tint_color, 0.7), + color=babase.safecolor(tint_color, 0.7), shadow=1.0, - text=ba.Lstr(value=data['profileDisplayString']), + text=babase.Lstr(value=data['profileDisplayString']), maxwidth=sub_width * maxwidth_scale * 0.75) showing_character = True v -= 33 @@ -1861,27 +1833,27 @@ def _on_query_response(self, data): v = sub_height - 20 if len(data['accountDisplayStrings']) <= 1: - account_title = ba.Lstr( + account_title = babase.Lstr( resource='settingsWindow.accountText') else: - account_title = ba.Lstr( + account_title = babase.Lstr( resource='accountSettingsWindow.accountsText', fallback_resource='settingsWindow.accountText') - ba.textwidget(parent=self._subcontainer, + bui.textwidget(parent=self._subcontainer, size=(0, 0), position=(sub_width * center, v), flatness=1.0, h_align='center', v_align='center', scale=title_scale, - color=ba.app.ui.infotextcolor, + color=bui.app.ui_v1.infotextcolor, text=account_title, maxwidth=sub_width * maxwidth_scale) draw_small = (showing_character or len(data['accountDisplayStrings']) > 1) v -= 14 if draw_small else 20 for account_string in data['accountDisplayStrings']: - ba.textwidget(parent=self._subcontainer, + bui.textwidget(parent=self._subcontainer, size=(0, 0), position=(sub_width * center, v), h_align='center', @@ -1894,17 +1866,17 @@ def _on_query_response(self, data): v += account_name_spacing v -= 25 if showing_character else 29 # ======================================================================= - ba.textwidget(parent=self._subcontainer, + bui.textwidget(parent=self._subcontainer, size=(0, 0), position=(sub_width * center, v), flatness=1.0, h_align='center', v_align='center', scale=title_scale, - color=ba.app.ui.infotextcolor, + color=bui.app.ui_v1.infotextcolor, text=str(self.pb_id), maxwidth=sub_width * maxwidth_scale) - self._copy_btn = ba.buttonwidget( + self._copy_btn = bui.buttonwidget( parent=self._subcontainer, position=(sub_width * center - 120, v - 9), size=(60, 30), @@ -1915,19 +1887,19 @@ def _on_query_response(self, data): autoselect=True) v -= 24 - ba.textwidget(parent=self._subcontainer, + bui.textwidget(parent=self._subcontainer, size=(0, 0), position=(sub_width * center, v), flatness=1.0, h_align='center', v_align='center', scale=title_scale, - color=ba.app.ui.infotextcolor, + color=bui.app.ui_v1.infotextcolor, text="Name", maxwidth=sub_width * maxwidth_scale) v -= 26 for name in self.custom_data["names"]: - ba.textwidget(parent=self._subcontainer, + bui.textwidget(parent=self._subcontainer, size=(0, 0), position=(sub_width * center, v), h_align='center', @@ -1937,20 +1909,20 @@ def _on_query_response(self, data): maxwidth=sub_width * maxwidth_scale) v -= 13 v -= 8 - ba.textwidget(parent=self._subcontainer, + bui.textwidget(parent=self._subcontainer, size=(0, 0), position=(sub_width * center, v), flatness=1.0, h_align='center', v_align='center', scale=title_scale, - color=ba.app.ui.infotextcolor, + color=bui.app.ui_v1.infotextcolor, text="Created On", maxwidth=sub_width * maxwidth_scale) v -= 19 d = self.custom_data["createdOn"] - ba.textwidget(parent=self._subcontainer, + bui.textwidget(parent=self._subcontainer, size=(0, 0), position=(sub_width * center, v), h_align='center', @@ -1959,19 +1931,19 @@ def _on_query_response(self, data): text=d[:d.index("T")], maxwidth=sub_width * maxwidth_scale) v -= 29 - ba.textwidget(parent=self._subcontainer, + bui.textwidget(parent=self._subcontainer, size=(0, 0), position=(sub_width * center, v), flatness=1.0, h_align='center', v_align='center', scale=title_scale, - color=ba.app.ui.infotextcolor, + color=bui.app.ui_v1.infotextcolor, text="Discord", maxwidth=sub_width * maxwidth_scale) v -= 19 if len(self.custom_data["discord"]) > 0: - ba.textwidget(parent=self._subcontainer, + bui.textwidget(parent=self._subcontainer, size=(0, 0), position=(sub_width * center, v), h_align='center', @@ -1981,20 +1953,20 @@ def _on_query_response(self, data): ","+self.custom_data["discord"][0]["id"], maxwidth=sub_width * maxwidth_scale) v -= 26 - ba.textwidget(parent=self._subcontainer, + bui.textwidget(parent=self._subcontainer, size=(0, 0), position=(sub_width * center, v), flatness=1.0, h_align='center', v_align='center', scale=title_scale, - color=ba.app.ui.infotextcolor, + color=bui.app.ui_v1.infotextcolor, text="Mutual servers", maxwidth=sub_width * maxwidth_scale) v = -19 v = 270 for server in self.servers: - ba.textwidget(parent=self._subcontainer, + bui.textwidget(parent=self._subcontainer, size=(0, 0), position=(sub_width * center, v), h_align='center', @@ -2006,34 +1978,34 @@ def _on_query_response(self, data): v -= 16 # ================================================================== - ba.textwidget(parent=self._subcontainer, + bui.textwidget(parent=self._subcontainer, size=(0, 0), position=(sub_width * center, v), flatness=1.0, h_align='center', v_align='center', scale=title_scale, - color=ba.app.ui.infotextcolor, - text=ba.Lstr(resource='rankText'), + color=bui.app.ui_v1.infotextcolor, + text=babase.Lstr(resource='rankText'), maxwidth=sub_width * maxwidth_scale) v -= 14 if data['rank'] is None: rank_str = '-' suffix_offset = None else: - str_raw = ba.Lstr( + str_raw = babase.Lstr( resource='league.rankInLeagueText').evaluate() # FIXME: Would be nice to not have to eval this. - rank_str = ba.Lstr( + rank_str = babase.Lstr( resource='league.rankInLeagueText', subs=[('${RANK}', str(data['rank'][2])), ('${NAME}', - ba.Lstr(translate=('leagueNames', + babase.Lstr(translate=('leagueNames', data['rank'][0]))), ('${SUFFIX}', '')]).evaluate() rank_str_width = min( sub_width * maxwidth_scale, - _ba.get_string_width(rank_str, suppress_warning=True) * + _babase.get_string_width(rank_str, suppress_warning=True) * 0.55) # Only tack our suffix on if its at the end and only for @@ -2044,7 +2016,7 @@ def _on_query_response(self, data): else: suffix_offset = None - ba.textwidget(parent=self._subcontainer, + bui.textwidget(parent=self._subcontainer, size=(0, 0), position=(sub_width * center, v), h_align='center', @@ -2054,7 +2026,7 @@ def _on_query_response(self, data): maxwidth=sub_width * maxwidth_scale) if suffix_offset is not None: assert data['rank'] is not None - ba.textwidget(parent=self._subcontainer, + bui.textwidget(parent=self._subcontainer, size=(0, 0), position=(sub_width * center + suffix_offset, v + 3), @@ -2065,28 +2037,28 @@ def _on_query_response(self, data): text='[' + str(data['rank'][1]) + ']') v -= 14 - str_raw = ba.Lstr( + str_raw = babase.Lstr( resource='league.rankInLeagueText').evaluate() old_offs = -50 prev_ranks_shown = 0 for prev_rank in data['prevRanks']: - rank_str = ba.Lstr( + rank_str = babase.Lstr( value='${S}: ${I}', subs=[ ('${S}', - ba.Lstr(resource='league.seasonText', + babase.Lstr(resource='league.seasonText', subs=[('${NUMBER}', str(prev_rank[0]))])), ('${I}', - ba.Lstr(resource='league.rankInLeagueText', + babase.Lstr(resource='league.rankInLeagueText', subs=[('${RANK}', str(prev_rank[3])), ('${NAME}', - ba.Lstr(translate=('leagueNames', + babase.Lstr(translate=('leagueNames', prev_rank[1]))), ('${SUFFIX}', '')])) ]).evaluate() rank_str_width = min( sub_width * maxwidth_scale, - _ba.get_string_width(rank_str, suppress_warning=True) * + _babase.get_string_width(rank_str, suppress_warning=True) * 0.3) # Only tack our suffix on if its at the end and only for @@ -2096,7 +2068,7 @@ def _on_query_response(self, data): suffix_offset = rank_str_width + 2 else: suffix_offset = None - ba.textwidget(parent=self._subcontainer, + bui.textwidget(parent=self._subcontainer, size=(0, 0), position=(sub_width * center + old_offs, v), h_align='left', @@ -2106,7 +2078,7 @@ def _on_query_response(self, data): flatness=1.0, maxwidth=sub_width * maxwidth_scale) if suffix_offset is not None: - ba.textwidget(parent=self._subcontainer, + bui.textwidget(parent=self._subcontainer, size=(0, 0), position=(sub_width * center + old_offs + suffix_offset, v + 1), @@ -2120,25 +2092,25 @@ def _on_query_response(self, data): v -= 13 - ba.textwidget(parent=self._subcontainer, + bui.textwidget(parent=self._subcontainer, size=(0, 0), position=(sub_width * center, v), flatness=1.0, h_align='center', v_align='center', scale=title_scale, - color=ba.app.ui.infotextcolor, - text=ba.Lstr(resource='achievementsText'), + color=bui.app.ui_v1.infotextcolor, + text=babase.Lstr(resource='achievementsText'), maxwidth=sub_width * maxwidth_scale) v -= 14 - ba.textwidget(parent=self._subcontainer, + bui.textwidget(parent=self._subcontainer, size=(0, 0), position=(sub_width * center, v), h_align='center', v_align='center', scale=0.55, text=str(data['achievementsCompleted']) + ' / ' + - str(len(ba.app.ach.achievements)), + str(len(bui.app.classic.ach.achievements)), maxwidth=sub_width * maxwidth_scale) v -= 25 @@ -2150,19 +2122,19 @@ def _on_query_response(self, data): center = 0.5 maxwidth_scale = 0.9 - ba.textwidget(parent=self._subcontainer, + bui.textwidget(parent=self._subcontainer, size=(0, 0), position=(sub_width * center, v), h_align='center', v_align='center', scale=title_scale, - color=ba.app.ui.infotextcolor, + color=bui.app.ui_v1.infotextcolor, flatness=1.0, - text=ba.Lstr(resource='trophiesThisSeasonText', + text=babase.Lstr(resource='trophiesThisSeasonText', fallback_resource='trophiesText'), maxwidth=sub_width * maxwidth_scale) v -= 19 - ba.textwidget(parent=self._subcontainer, + bui.textwidget(parent=self._subcontainer, size=(0, ts_height), position=(sub_width * 0.5, v - ts_height * tscale), @@ -2172,15 +2144,10 @@ def _on_query_response(self, data): text=trophystr) except Exception: - ba.print_exception('Error displaying account info.') + babase.print_exception('Error displaying account info.') # ba_meta export plugin - - -class bySmoothy(ba.Plugin): +class bySmoothy(babase.Plugin): def __init__(self): - if _ba.env().get("build_number", 0) >= 20577: - ba.internal.connect_to_party = newconnect_to_party - bastd_party.PartyWindow = ModifiedPartyWindow - else: - print("AdvancePartyWindow only runs with BombSquad version equal or higher than 1.7") + bs.connect_to_party = newconnect_to_party + bascenev1lib_party.PartyWindow = ModifiedPartyWindow From da0e63d677ac68010654b1b5a19b7e360dedc055 Mon Sep 17 00:00:00 2001 From: imayushsaini Date: Sun, 2 Jul 2023 07:50:25 +0000 Subject: [PATCH 0522/1464] [ci] auto-format --- plugins/utilities/advanced_party_window.py | 670 +++++++++++---------- 1 file changed, 336 insertions(+), 334 deletions(-) diff --git a/plugins/utilities/advanced_party_window.py b/plugins/utilities/advanced_party_window.py index 3930bc9d..e5c74b2b 100644 --- a/plugins/utilities/advanced_party_window.py +++ b/plugins/utilities/advanced_party_window.py @@ -20,7 +20,7 @@ ''' # added advanced ID revealer -# live ping +# live ping # Made by Mr.Smoothy - Plasma Boson import traceback @@ -193,12 +193,9 @@ def run(self) -> None: SystemEncode = "utf-8" - PingThread().start() - - class chatloggThread(): """Thread for sending out game pings.""" @@ -424,27 +421,27 @@ def __init__(self, origin: Sequence[float] = (0, 0)): 240, 0) if uiscale is babase.UIScale.MEDIUM else (330, 20))) self._cancel_button = bui.buttonwidget(parent=self._root_widget, - scale=0.7, - position=(30, self._height - 47), - size=(50, 50), - label='', - on_activate_call=self.close, - autoselect=True, - color=(0.45, 0.63, 0.15), - icon=bui.gettexture('crossOut'), - iconscale=1.2) - self._smoothy_button = bui.buttonwidget(parent=self._root_widget, - scale=0.6, - position=(5, self._height - 47 - 40), + scale=0.7, + position=(30, self._height - 47), size=(50, 50), - label='69', - on_activate_call=self.smoothy_roster_changer, + label='', + on_activate_call=self.close, autoselect=True, color=(0.45, 0.63, 0.15), - icon=bui.gettexture('replayIcon'), + icon=bui.gettexture('crossOut'), iconscale=1.2) + self._smoothy_button = bui.buttonwidget(parent=self._root_widget, + scale=0.6, + position=(5, self._height - 47 - 40), + size=(50, 50), + label='69', + on_activate_call=self.smoothy_roster_changer, + autoselect=True, + color=(0.45, 0.63, 0.15), + icon=bui.gettexture('replayIcon'), + iconscale=1.2) bui.containerwidget(edit=self._root_widget, - cancel_button=self._cancel_button) + cancel_button=self._cancel_button) self._menu_button = bui.buttonwidget( parent=self._root_widget, @@ -466,37 +463,37 @@ def __init__(self, origin: Sequence[float] = (0, 0)): title = babase.Lstr(resource=self._r + '.titleText') self._title_text = bui.textwidget(parent=self._root_widget, - scale=0.9, - color=(0.5, 0.7, 0.5), - text=title, - size=(120, 20), - position=(self._width * 0.5-60, - self._height - 29), - on_select_call=self.title_selected, - selectable=True, - maxwidth=self._width * 0.7, - h_align='center', - v_align='center') + scale=0.9, + color=(0.5, 0.7, 0.5), + text=title, + size=(120, 20), + position=(self._width * 0.5-60, + self._height - 29), + on_select_call=self.title_selected, + selectable=True, + maxwidth=self._width * 0.7, + h_align='center', + v_align='center') self._empty_str = bui.textwidget(parent=self._root_widget, - scale=0.75, - size=(0, 0), - position=(self._width * 0.5, - self._height - 65), - maxwidth=self._width * 0.85, - text="no one", - h_align='center', - v_align='center') + scale=0.75, + size=(0, 0), + position=(self._width * 0.5, + self._height - 65), + maxwidth=self._width * 0.85, + text="no one", + h_align='center', + v_align='center') self._scroll_width = self._width - 50 self._scrollwidget = bui.scrollwidget(parent=self._root_widget, - size=(self._scroll_width, - self._height - 200), - position=(30, 80), - color=(0.4, 0.6, 0.3)) + size=(self._scroll_width, + self._height - 200), + position=(30, 80), + color=(0.4, 0.6, 0.3)) self._columnwidget = bui.columnwidget(parent=self._scrollwidget, - border=2, - margin=0) + border=2, + margin=0) bui.widget(edit=self._menu_button, down_widget=self._columnwidget) self._muted_text = bui.textwidget( @@ -579,22 +576,22 @@ def enable_chat_mode(): # ) bui.widget(edit=self._scrollwidget, - autoselect=True, - left_widget=self._cancel_button, - up_widget=self._cancel_button, - down_widget=self._text_field) + autoselect=True, + left_widget=self._cancel_button, + up_widget=self._cancel_button, + down_widget=self._text_field) bui.widget(edit=self._columnwidget, - autoselect=True, - up_widget=self._cancel_button, - down_widget=self._text_field) + autoselect=True, + up_widget=self._cancel_button, + down_widget=self._text_field) bui.containerwidget(edit=self._root_widget, selected_child=txt) btn = bui.buttonwidget(parent=self._root_widget, - size=(50, 35), - label=babase.Lstr(resource=self._r + '.sendText'), - button_type='square', - autoselect=True, - position=(self._width - 70, 35), - on_activate_call=self._send_chat_message) + size=(50, 35), + label=babase.Lstr(resource=self._r + '.sendText'), + button_type='square', + autoselect=True, + position=(self._width - 70, 35), + on_activate_call=self._send_chat_message) def _times_button_on_click(): # self._popup_type = "send_Times_Press" @@ -618,12 +615,12 @@ def _times_button_on_click(): self._send_msg_times = 1 self._times_button = bui.buttonwidget(parent=self._root_widget, - size=(50, 35), - label="Quick", - button_type='square', - autoselect=True, - position=(30, 35), - on_activate_call=_times_button_on_click) + size=(50, 35), + label="Quick", + button_type='square', + autoselect=True, + position=(30, 35), + on_activate_call=_times_button_on_click) bui.textwidget(edit=txt, on_return_press_call=btn.activate) self._name_widgets: List[bui.Widget] = [] @@ -632,8 +629,8 @@ def _times_button_on_click(): self.smoothy_mode = 1 self.full_chat_mode = False self._update_timer = babase.AppTimer(1.0, - bs.WeakCall(self._update), - repeat=True) + bs.WeakCall(self._update), + repeat=True) self._update() @@ -679,34 +676,34 @@ def _add_msg(self, msg: str) -> None: if babase.app.config.resolve('Chat Muted'): txt = bui.textwidget(parent=self._columnwidget, - text=msg, - h_align='left', - v_align='center', - size=(130, 13), - scale=0.55, - position=(-0.6, 0), - selectable=True, - click_activate=True, - maxwidth=self._scroll_width * 0.94, - shadow=0.3, - flatness=1.0) + text=msg, + h_align='left', + v_align='center', + size=(130, 13), + scale=0.55, + position=(-0.6, 0), + selectable=True, + click_activate=True, + maxwidth=self._scroll_width * 0.94, + shadow=0.3, + flatness=1.0) bui.textwidget(edit=txt, - on_activate_call=babase.Call( - self._on_chat_press, - msg, txt)) + on_activate_call=babase.Call( + self._on_chat_press, + msg, txt)) else: txt = bui.textwidget(parent=self._columnwidget, - text=msg, - h_align='left', - v_align='center', - size=(0, 13), - scale=0.55, + text=msg, + h_align='left', + v_align='center', + size=(0, 13), + scale=0.55, - maxwidth=self._scroll_width * 0.94, - shadow=0.3, - flatness=1.0) + maxwidth=self._scroll_width * 0.94, + shadow=0.3, + flatness=1.0) # btn = bui.buttonwidget(parent=self._columnwidget, # scale=0.7, @@ -726,14 +723,14 @@ def _add_msg(self, msg: str) -> None: def _add_msg_when_muted(self, msg: str) -> None: txt = bui.textwidget(parent=self._columnwidget, - text=msg, - h_align='left', - v_align='center', - size=(0, 13), - scale=0.55, - maxwidth=self._scroll_width * 0.94, - shadow=0.3, - flatness=1.0) + text=msg, + h_align='left', + v_align='center', + size=(0, 13), + scale=0.55, + maxwidth=self._scroll_width * 0.94, + shadow=0.3, + flatness=1.0) self._chat_texts.append(txt) if len(self._chat_texts) > 40: first = self._chat_texts.pop(0) @@ -763,12 +760,12 @@ def _on_nick_rename_press(self, arg) -> None: transition='in_scale') bui.textwidget(parent=cnt, - size=(0, 0), - h_align='center', - v_align='center', - text='Enter nickname', - maxwidth=c_width * 0.8, - position=(c_width * 0.5, c_height - 60)) + size=(0, 0), + h_align='center', + v_align='center', + text='Enter nickname', + maxwidth=c_width * 0.8, + position=(c_width * 0.5, c_height - 60)) id = self._get_nick(arg) self._player_nick_text = txt89 = bui.textwidget( parent=cnt, @@ -792,12 +789,12 @@ def _on_nick_rename_press(self, arg) -> None: position=(30, 30), autoselect=True) okb = bui.buttonwidget(parent=cnt, - label='Rename', - size=(180, 60), - position=(c_width - 230, 30), - on_activate_call=babase.Call( - self._add_nick, arg), - autoselect=True) + label='Rename', + size=(180, 60), + position=(c_width - 230, 30), + on_activate_call=babase.Call( + self._add_nick, arg), + autoselect=True) bui.widget(edit=cbtn, right_widget=okb) bui.widget(edit=okb, left_widget=cbtn) bui.textwidget(edit=txt89, on_return_press_call=okb.activate) @@ -812,7 +809,7 @@ def _add_nick(self, arg): config['players nick'][arg] = new_name_raw config.commit() bui.containerwidget(edit=self._nick_rename_window, - transition='out_scale') + transition='out_scale') # bui.containerwidget(edit=self._root_widget,transition='in_scale') def _get_nick(self, id): @@ -838,7 +835,7 @@ def _reset_game_record(self) -> None: except: babase.print_exception() bs.broadcastmessage(babase.Lstr(resource="replayWriteErrorText").evaluate() + - ""+traceback.format_exc(), color=(1, 0, 0)) + ""+traceback.format_exc(), color=(1, 0, 0)) def _on_menu_button_press(self) -> None: is_muted = babase.app.config.resolve('Chat Muted') @@ -1187,7 +1184,7 @@ def _kick_selected_player(self): #NewShareCodeWindow(origin_widget=self.get_root_widget(), delegate=None,code = "300",execText = u"_babase._disconnectClient(%d,{Value})"%self._popup_party_member_client_id) def joinbombspot(self): - + bui.open_url("https://discord.gg/ucyaesh") def _update(self) -> None: @@ -1224,17 +1221,17 @@ def _update(self) -> None: if not self._roster: top_section_height = 60 bui.textwidget(edit=self._empty_str, - text=babase.Lstr(resource=self._r + '.emptyText')) + text=babase.Lstr(resource=self._r + '.emptyText')) bui.scrollwidget(edit=self._scrollwidget, - size=(self._width - 50, - self._height - top_section_height - 110), - position=(30, 80)) + size=(self._width - 50, + self._height - top_section_height - 110), + position=(30, 80)) elif self.full_chat_mode: top_section_height = 60 bui.scrollwidget(edit=self._scrollwidget, - size=(self._width - 50, - self._height - top_section_height - 75), - position=(30, 80)) + size=(self._width - 50, + self._height - top_section_height - 75), + position=(30, 80)) else: columns = 1 if len( @@ -1286,19 +1283,19 @@ def _update(self) -> None: p_str = '???' try: widget = bui.textwidget(parent=self._root_widget, - position=(pos[0], pos[1]), - scale=t_scale, - size=(c_width * 0.85, 30), - maxwidth=c_width * 0.85, - color=(1, 1, - 1) if index == 0 else - (1, 1, 1), - selectable=True, - autoselect=True, - click_activate=True, - text=babase.Lstr(value=p_str), - h_align='left', - v_align='center') + position=(pos[0], pos[1]), + scale=t_scale, + size=(c_width * 0.85, 30), + maxwidth=c_width * 0.85, + color=(1, 1, + 1) if index == 0 else + (1, 1, 1), + selectable=True, + autoselect=True, + click_activate=True, + text=babase.Lstr(value=p_str), + h_align='left', + v_align='center') self._name_widgets.append(widget) except Exception: pass @@ -1317,10 +1314,10 @@ def _update(self) -> None: # client_id is more readily available though). try: bui.textwidget(edit=widget, - on_activate_call=babase.Call( - self._on_party_member_press, - self._roster[index]['client_id'], - is_host, widget)) + on_activate_call=babase.Call( + self._on_party_member_press, + self._roster[index]['client_id'], + is_host, widget)) except Exception: pass pos = (self._width * 0.53 - c_width_total * 0.5 + @@ -1348,7 +1345,7 @@ def _update(self) -> None: maxwidth=c_width * 0.96 - twd, color=(0.1, 1, 0.1, 0.5), text=babase.Lstr(resource=self._r + - '.hostText'), + '.hostText'), scale=0.4, shadow=0.1, flatness=1.0)) @@ -1357,10 +1354,10 @@ def _update(self) -> None: try: bui.textwidget(edit=self._empty_str, text='') bui.scrollwidget(edit=self._scrollwidget, - size=(self._width - 50, - max(100, self._height - 139 - - c_height_total)), - position=(30, 80)) + size=(self._width - 50, + max(100, self._height - 139 - + c_height_total)), + position=(30, 80)) except Exception: pass @@ -1410,7 +1407,8 @@ def popup_menu_selected_choice(self, popup_window: PopupMenuWindow, """Called when a choice is selected in the popup.""" global unmuted_names if self._popup_type == "banTimePress": - result = _babase.disconnect_client(self._popup_party_member_client_id, ban_time=int(choice)) + result = _babase.disconnect_client( + self._popup_party_member_client_id, ban_time=int(choice)) if not result: bui.getsound('error').play() bs.broadcastmessage( @@ -1419,7 +1417,7 @@ def popup_menu_selected_choice(self, popup_window: PopupMenuWindow, elif self._popup_type == "send_Times_Press": self._send_msg_times = int(choice) bui.buttonwidget(edit=self._times_button, label="%s:%d" % - (_getTransText("Times"), getattr(self, "_send_msg_times", 1))) + (_getTransText("Times"), getattr(self, "_send_msg_times", 1))) elif self._popup_type == "chatmessagepress": if choice == "mute": @@ -1539,7 +1537,7 @@ def popup_menu_selected_choice(self, popup_window: PopupMenuWindow, data.append(newReply) self._write_quick_responds(data) bs.broadcastmessage(_getTransText("Something_is_added") % - newReply, color=(0, 1, 0)) + newReply, color=(0, 1, 0)) bui.getsound("dingSmallHigh").play() except: babase.print_exception() @@ -1653,7 +1651,8 @@ def popup_menu_selected_choice(self, popup_window: PopupMenuWindow, self.popup_menu_selected_choice(popup_window, choice.replace( r"{$PlayerID}", str(playerID).replace("'", r"'").replace('"', r'\\"'))) else: - bs.broadcastmessage(_getTransText("No_valid_player_id_found"), (1, 0, 0)) + bs.broadcastmessage(_getTransText( + "No_valid_player_id_found"), (1, 0, 0)) bui.getsound("error").play() elif curKeyWord in (r"{$AccountInfo}",) != 0: self.popup_menu_selected_choice(popup_window, choice.replace( @@ -1695,7 +1694,8 @@ 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' - req = urllib.request.Request(url, headers={"User-Agent": f'BS{_babase.env().get("build_number", 0)}',"Accept-Language": "en-US,en;q=0.9",}) + req = urllib.request.Request(url, headers={ + "User-Agent": f'BS{_babase.env().get("build_number", 0)}', "Accept-Language": "en-US,en;q=0.9", }) data = urllib.request.urlopen(req) account_data = json.loads(data.read().decode('utf-8'))[0] pbid = account_data["pbid"] @@ -1705,7 +1705,7 @@ def fetchAccountInfo(account, loading_widget): pass # _babase.pushcall(Call(updateAccountWindow,loading_widget,accounts[0]),from_other_thread=True) _babase.pushcall(Call(CustomAccountViewerWindow, pbid, account_data, - servers, loading_widget), from_other_thread=True) + servers, loading_widget), from_other_thread=True) class CustomAccountViewerWindow(viewer.AccountViewerWindow): @@ -1728,25 +1728,25 @@ def _on_query_response(self, data): if data is None: bui.textwidget(edit=self._loading_text, text="") bui.textwidget(parent=self._scrollwidget, - size=(0, 0), - position=(170, 200), - flatness=1.0, - h_align='center', - v_align='center', - scale=0.5, - color=bui.app.ui_v1.infotextcolor, - text="Mutual servers", - maxwidth=300) + size=(0, 0), + position=(170, 200), + flatness=1.0, + h_align='center', + v_align='center', + scale=0.5, + color=bui.app.ui_v1.infotextcolor, + text="Mutual servers", + maxwidth=300) v = 200-21 for server in self.servers: bui.textwidget(parent=self._scrollwidget, - size=(0, 0), - position=(170, v), - h_align='center', - v_align='center', - scale=0.55, - text=server, - maxwidth=300) + size=(0, 0), + position=(170, v), + h_align='center', + v_align='center', + scale=0.55, + text=server, + maxwidth=300) v -= 23 else: for account in self.custom_data["accounts"]: @@ -1770,7 +1770,7 @@ def _on_query_response(self, data): account_name_spacing = 15 tscale = 0.65 ts_height = _babase.get_string_height(trophystr, - suppress_warning=True) + suppress_warning=True) sub_width = self._width - 80 sub_height = 500 + ts_height * tscale + \ account_name_spacing * len(data['accountDisplayStrings']) @@ -1840,42 +1840,42 @@ def _on_query_response(self, data): resource='accountSettingsWindow.accountsText', fallback_resource='settingsWindow.accountText') bui.textwidget(parent=self._subcontainer, - size=(0, 0), - position=(sub_width * center, v), - flatness=1.0, - h_align='center', - v_align='center', - scale=title_scale, - color=bui.app.ui_v1.infotextcolor, - text=account_title, - maxwidth=sub_width * maxwidth_scale) + size=(0, 0), + position=(sub_width * center, v), + flatness=1.0, + h_align='center', + v_align='center', + scale=title_scale, + color=bui.app.ui_v1.infotextcolor, + text=account_title, + maxwidth=sub_width * maxwidth_scale) draw_small = (showing_character or len(data['accountDisplayStrings']) > 1) v -= 14 if draw_small else 20 for account_string in data['accountDisplayStrings']: bui.textwidget(parent=self._subcontainer, - size=(0, 0), - position=(sub_width * center, v), - h_align='center', - v_align='center', - scale=0.55 if draw_small else 0.8, - text=account_string, - maxwidth=sub_width * maxwidth_scale) + size=(0, 0), + position=(sub_width * center, v), + h_align='center', + v_align='center', + scale=0.55 if draw_small else 0.8, + text=account_string, + maxwidth=sub_width * maxwidth_scale) v -= account_name_spacing v += account_name_spacing v -= 25 if showing_character else 29 # ======================================================================= bui.textwidget(parent=self._subcontainer, - size=(0, 0), - position=(sub_width * center, v), - flatness=1.0, - h_align='center', - v_align='center', - scale=title_scale, - color=bui.app.ui_v1.infotextcolor, - text=str(self.pb_id), - maxwidth=sub_width * maxwidth_scale) + size=(0, 0), + position=(sub_width * center, v), + flatness=1.0, + h_align='center', + v_align='center', + scale=title_scale, + color=bui.app.ui_v1.infotextcolor, + text=str(self.pb_id), + maxwidth=sub_width * maxwidth_scale) self._copy_btn = bui.buttonwidget( parent=self._subcontainer, position=(sub_width * center - 120, v - 9), @@ -1888,106 +1888,106 @@ def _on_query_response(self, data): v -= 24 bui.textwidget(parent=self._subcontainer, - size=(0, 0), - position=(sub_width * center, v), - flatness=1.0, - h_align='center', - v_align='center', - scale=title_scale, - color=bui.app.ui_v1.infotextcolor, - text="Name", - maxwidth=sub_width * maxwidth_scale) + size=(0, 0), + position=(sub_width * center, v), + flatness=1.0, + h_align='center', + v_align='center', + scale=title_scale, + color=bui.app.ui_v1.infotextcolor, + text="Name", + maxwidth=sub_width * maxwidth_scale) v -= 26 for name in self.custom_data["names"]: bui.textwidget(parent=self._subcontainer, - size=(0, 0), - position=(sub_width * center, v), - h_align='center', - v_align='center', - scale=0.51, - text=name, - maxwidth=sub_width * maxwidth_scale) + size=(0, 0), + position=(sub_width * center, v), + h_align='center', + v_align='center', + scale=0.51, + text=name, + maxwidth=sub_width * maxwidth_scale) v -= 13 v -= 8 bui.textwidget(parent=self._subcontainer, - size=(0, 0), - position=(sub_width * center, v), - flatness=1.0, - h_align='center', - v_align='center', - scale=title_scale, - color=bui.app.ui_v1.infotextcolor, - text="Created On", - maxwidth=sub_width * maxwidth_scale) + size=(0, 0), + position=(sub_width * center, v), + flatness=1.0, + h_align='center', + v_align='center', + scale=title_scale, + color=bui.app.ui_v1.infotextcolor, + text="Created On", + maxwidth=sub_width * maxwidth_scale) v -= 19 d = self.custom_data["createdOn"] bui.textwidget(parent=self._subcontainer, - size=(0, 0), - position=(sub_width * center, v), - h_align='center', - v_align='center', - scale=0.55, - text=d[:d.index("T")], - maxwidth=sub_width * maxwidth_scale) + size=(0, 0), + position=(sub_width * center, v), + h_align='center', + v_align='center', + scale=0.55, + text=d[:d.index("T")], + maxwidth=sub_width * maxwidth_scale) v -= 29 bui.textwidget(parent=self._subcontainer, - size=(0, 0), - position=(sub_width * center, v), - flatness=1.0, - h_align='center', - v_align='center', - scale=title_scale, - color=bui.app.ui_v1.infotextcolor, - text="Discord", - maxwidth=sub_width * maxwidth_scale) + size=(0, 0), + position=(sub_width * center, v), + flatness=1.0, + h_align='center', + v_align='center', + scale=title_scale, + color=bui.app.ui_v1.infotextcolor, + text="Discord", + maxwidth=sub_width * maxwidth_scale) v -= 19 if len(self.custom_data["discord"]) > 0: bui.textwidget(parent=self._subcontainer, - size=(0, 0), - position=(sub_width * center, v), - h_align='center', - v_align='center', - scale=0.55, - text=self.custom_data["discord"][0]["username"] + - ","+self.custom_data["discord"][0]["id"], - maxwidth=sub_width * maxwidth_scale) + size=(0, 0), + position=(sub_width * center, v), + h_align='center', + v_align='center', + scale=0.55, + text=self.custom_data["discord"][0]["username"] + + ","+self.custom_data["discord"][0]["id"], + maxwidth=sub_width * maxwidth_scale) v -= 26 bui.textwidget(parent=self._subcontainer, - size=(0, 0), - position=(sub_width * center, v), - flatness=1.0, - h_align='center', - v_align='center', - scale=title_scale, - color=bui.app.ui_v1.infotextcolor, - text="Mutual servers", - maxwidth=sub_width * maxwidth_scale) + size=(0, 0), + position=(sub_width * center, v), + flatness=1.0, + h_align='center', + v_align='center', + scale=title_scale, + color=bui.app.ui_v1.infotextcolor, + text="Mutual servers", + maxwidth=sub_width * maxwidth_scale) v = -19 v = 270 for server in self.servers: bui.textwidget(parent=self._subcontainer, - size=(0, 0), - position=(sub_width * center, v), - h_align='center', - v_align='center', - scale=0.55, - text=server, - maxwidth=sub_width * maxwidth_scale) + size=(0, 0), + position=(sub_width * center, v), + h_align='center', + v_align='center', + scale=0.55, + text=server, + maxwidth=sub_width * maxwidth_scale) v -= 13 v -= 16 # ================================================================== bui.textwidget(parent=self._subcontainer, - size=(0, 0), - position=(sub_width * center, v), - flatness=1.0, - h_align='center', - v_align='center', - scale=title_scale, - color=bui.app.ui_v1.infotextcolor, - text=babase.Lstr(resource='rankText'), - maxwidth=sub_width * maxwidth_scale) + size=(0, 0), + position=(sub_width * center, v), + flatness=1.0, + h_align='center', + v_align='center', + scale=title_scale, + color=bui.app.ui_v1.infotextcolor, + text=babase.Lstr(resource='rankText'), + maxwidth=sub_width * maxwidth_scale) v -= 14 if data['rank'] is None: rank_str = '-' @@ -2001,7 +2001,7 @@ def _on_query_response(self, data): subs=[('${RANK}', str(data['rank'][2])), ('${NAME}', babase.Lstr(translate=('leagueNames', - data['rank'][0]))), + data['rank'][0]))), ('${SUFFIX}', '')]).evaluate() rank_str_width = min( sub_width * maxwidth_scale, @@ -2017,24 +2017,24 @@ def _on_query_response(self, data): suffix_offset = None bui.textwidget(parent=self._subcontainer, - size=(0, 0), - position=(sub_width * center, v), - h_align='center', - v_align='center', - scale=0.55, - text=rank_str, - maxwidth=sub_width * maxwidth_scale) + size=(0, 0), + position=(sub_width * center, v), + h_align='center', + v_align='center', + scale=0.55, + text=rank_str, + maxwidth=sub_width * maxwidth_scale) if suffix_offset is not None: assert data['rank'] is not None bui.textwidget(parent=self._subcontainer, - size=(0, 0), - position=(sub_width * center + suffix_offset, - v + 3), - h_align='left', - v_align='center', - scale=0.29, - flatness=1.0, - text='[' + str(data['rank'][1]) + ']') + size=(0, 0), + position=(sub_width * center + suffix_offset, + v + 3), + h_align='left', + v_align='center', + scale=0.29, + flatness=1.0, + text='[' + str(data['rank'][1]) + ']') v -= 14 str_raw = babase.Lstr( @@ -2047,14 +2047,14 @@ def _on_query_response(self, data): subs=[ ('${S}', babase.Lstr(resource='league.seasonText', - subs=[('${NUMBER}', str(prev_rank[0]))])), + subs=[('${NUMBER}', str(prev_rank[0]))])), ('${I}', babase.Lstr(resource='league.rankInLeagueText', - subs=[('${RANK}', str(prev_rank[3])), - ('${NAME}', - babase.Lstr(translate=('leagueNames', - prev_rank[1]))), - ('${SUFFIX}', '')])) + subs=[('${RANK}', str(prev_rank[3])), + ('${NAME}', + babase.Lstr(translate=('leagueNames', + prev_rank[1]))), + ('${SUFFIX}', '')])) ]).evaluate() rank_str_width = min( sub_width * maxwidth_scale, @@ -2069,49 +2069,49 @@ def _on_query_response(self, data): else: suffix_offset = None bui.textwidget(parent=self._subcontainer, - size=(0, 0), - position=(sub_width * center + old_offs, v), - h_align='left', - v_align='center', - scale=0.3, - text=rank_str, - flatness=1.0, - maxwidth=sub_width * maxwidth_scale) + size=(0, 0), + position=(sub_width * center + old_offs, v), + h_align='left', + v_align='center', + scale=0.3, + text=rank_str, + flatness=1.0, + maxwidth=sub_width * maxwidth_scale) if suffix_offset is not None: bui.textwidget(parent=self._subcontainer, - size=(0, 0), - position=(sub_width * center + old_offs + - suffix_offset, v + 1), - h_align='left', - v_align='center', - scale=0.20, - flatness=1.0, - text='[' + str(prev_rank[2]) + ']') + size=(0, 0), + position=(sub_width * center + old_offs + + suffix_offset, v + 1), + h_align='left', + v_align='center', + scale=0.20, + flatness=1.0, + text='[' + str(prev_rank[2]) + ']') prev_ranks_shown += 1 v -= 10 v -= 13 bui.textwidget(parent=self._subcontainer, - size=(0, 0), - position=(sub_width * center, v), - flatness=1.0, - h_align='center', - v_align='center', - scale=title_scale, - color=bui.app.ui_v1.infotextcolor, - text=babase.Lstr(resource='achievementsText'), - maxwidth=sub_width * maxwidth_scale) + size=(0, 0), + position=(sub_width * center, v), + flatness=1.0, + h_align='center', + v_align='center', + scale=title_scale, + color=bui.app.ui_v1.infotextcolor, + text=babase.Lstr(resource='achievementsText'), + maxwidth=sub_width * maxwidth_scale) v -= 14 bui.textwidget(parent=self._subcontainer, - size=(0, 0), - position=(sub_width * center, v), - h_align='center', - v_align='center', - scale=0.55, - text=str(data['achievementsCompleted']) + ' / ' + - str(len(bui.app.classic.ach.achievements)), - maxwidth=sub_width * maxwidth_scale) + size=(0, 0), + position=(sub_width * center, v), + h_align='center', + v_align='center', + scale=0.55, + text=str(data['achievementsCompleted']) + ' / ' + + str(len(bui.app.classic.ach.achievements)), + maxwidth=sub_width * maxwidth_scale) v -= 25 if prev_ranks_shown == 0 and showing_character: @@ -2123,30 +2123,32 @@ def _on_query_response(self, data): maxwidth_scale = 0.9 bui.textwidget(parent=self._subcontainer, - size=(0, 0), - position=(sub_width * center, v), - h_align='center', - v_align='center', - scale=title_scale, - color=bui.app.ui_v1.infotextcolor, - flatness=1.0, - text=babase.Lstr(resource='trophiesThisSeasonText', - fallback_resource='trophiesText'), - maxwidth=sub_width * maxwidth_scale) + size=(0, 0), + position=(sub_width * center, v), + h_align='center', + v_align='center', + scale=title_scale, + color=bui.app.ui_v1.infotextcolor, + flatness=1.0, + text=babase.Lstr(resource='trophiesThisSeasonText', + fallback_resource='trophiesText'), + maxwidth=sub_width * maxwidth_scale) v -= 19 bui.textwidget(parent=self._subcontainer, - size=(0, ts_height), - position=(sub_width * 0.5, - v - ts_height * tscale), - h_align='center', - v_align='top', - corner_scale=tscale, - text=trophystr) + size=(0, ts_height), + position=(sub_width * 0.5, + v - ts_height * tscale), + h_align='center', + v_align='top', + corner_scale=tscale, + text=trophystr) except Exception: babase.print_exception('Error displaying account info.') # ba_meta export plugin + + class bySmoothy(babase.Plugin): def __init__(self): bs.connect_to_party = newconnect_to_party From 57e2aa07f809a31d6bdea50183331d952597ac3a Mon Sep 17 00:00:00 2001 From: imayushsaini Date: Sun, 2 Jul 2023 07:50:26 +0000 Subject: [PATCH 0523/1464] [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 a2f49fe7..39d921a0 100644 --- a/plugins/utilities.json +++ b/plugins/utilities.json @@ -366,7 +366,12 @@ } ], "versions": { - "2.0.0":null, + "2.0.0": { + "api_version": 8, + "commit_sha": "da0e63d", + "released_on": "02-07-2023", + "md5sum": "7d90768d603fcf91b38ba7fa1d30501e" + }, "1.0.1": { "api_version": 7, "commit_sha": "64e8a5c", From eb205fe7b18deef7277eea895e7ec13c74e44ddb Mon Sep 17 00:00:00 2001 From: Ayush Saini <36878972+imayushsaini@users.noreply.github.com> Date: Sun, 2 Jul 2023 18:28:55 +0530 Subject: [PATCH 0524/1464] updated character chooser , easy connect --- plugins/utilities.json | 2 + plugins/utilities/character_chooser.py | 121 +++--- plugins/utilities/easy_connect.py | 496 +++++++++++++------------ 3 files changed, 319 insertions(+), 300 deletions(-) diff --git a/plugins/utilities.json b/plugins/utilities.json index a2f49fe7..7d218188 100644 --- a/plugins/utilities.json +++ b/plugins/utilities.json @@ -335,6 +335,7 @@ } ], "versions": { + "2.0.0":null, "1.2.1": { "api_version": 7, "commit_sha": "64e8a5c", @@ -436,6 +437,7 @@ } ], "versions": { + "2.0.0": null, "1.0.0": { "api_version": 7, "commit_sha": "ff4de19", diff --git a/plugins/utilities/character_chooser.py b/plugins/utilities/character_chooser.py index 006c0a4a..9dbe7333 100644 --- a/plugins/utilities/character_chooser.py +++ b/plugins/utilities/character_chooser.py @@ -1,4 +1,4 @@ -# ba_meta require api 7 +# ba_meta require api 8 ''' Character Chooser by Mr.Smoothy @@ -34,41 +34,42 @@ from typing import TYPE_CHECKING -import ba -import _ba -from bastd.actor.playerspaz import PlayerSpaz +import babase +import bauiv1 as bui +import bascenev1 as bs +import _babase +from bascenev1lib.actor.playerspaz import PlayerSpaz -from ba._error import print_exception, print_error, NotFoundError -from ba._gameutils import animate, animate_array -from ba._language import Lstr -from ba._generated.enums import SpecialChar, InputType -from ba._profile import get_player_profile_colors +from babase._error import print_exception, print_error, NotFoundError + +from babase._language import Lstr + if TYPE_CHECKING: from typing import Any, Type, List, Dict, Tuple, Union, Sequence, Optional import weakref import os import json -from ba import _lobby -from bastd.actor.spazappearance import * -from ba._lobby import ChangeMessage -from ba._lobby import PlayerReadyMessage +from bascenev1._lobby import ChangeMessage, PlayerReadyMessage +from bascenev1 import _lobby +from bascenev1lib.actor.spazappearance import * + -def __init__(self, vpos: float, sessionplayer: _ba.SessionPlayer, +def __init__(self, vpos: float, sessionplayer: bs.SessionPlayer, lobby: 'Lobby') -> None: - self._deek_sound = _ba.getsound('deek') - self._click_sound = _ba.getsound('click01') - self._punchsound = _ba.getsound('punch01') - self._swish_sound = _ba.getsound('punchSwish') - self._errorsound = _ba.getsound('error') - self._mask_texture = _ba.gettexture('characterIconMask') + self._deek_sound = bs.getsound('deek') + self._click_sound = bs.getsound('click01') + self._punchsound = bs.getsound('punch01') + self._swish_sound = bs.getsound('punchSwish') + self._errorsound = bs.getsound('error') + self._mask_texture = bs.gettexture('characterIconMask') self._vpos = vpos self._lobby = weakref.ref(lobby) self._sessionplayer = sessionplayer self._inited = False self._dead = False - self._text_node: Optional[ba.Node] = None + self._text_node: Optional[bs.Node] = None self._profilename = '' self._profilenames: List[str] = [] self._ready: bool = False @@ -76,7 +77,7 @@ def __init__(self, vpos: float, sessionplayer: _ba.SessionPlayer, self._last_change: Sequence[Union[float, int]] = (0, 0) self._profiles: Dict[str, Dict[str, Any]] = {} - app = _ba.app + app = babase.app self.bakwas_chars = ["Lee", "Todd McBurton", "Zola", "Butch", "Witch", "warrior", "Middle-Man", "Alien", "OldLady", "Gladiator", "Wrestler", "Gretel", "Robot"] @@ -84,7 +85,7 @@ def __init__(self, vpos: float, sessionplayer: _ba.SessionPlayer, # Load available player profiles either from the local config or # from the remote device. self.reload_profiles() - for name in _ba.app.spaz_appearances: + for name in bs.app.classic.spaz_appearances: if name not in self._character_names and name not in self.bakwas_chars: self._character_names.append(name) # Note: this is just our local index out of available teams; *not* @@ -96,12 +97,12 @@ def __init__(self, vpos: float, sessionplayer: _ba.SessionPlayer, # it. This will give a persistent character for them between games # and will distribute characters nicely if everyone is random. self._random_color, self._random_highlight = ( - get_player_profile_colors(None)) + bs.get_player_profile_colors(None)) # To calc our random character we pick a random one out of our # unlocked list and then locate that character's index in the full # list. - char_index_offset = app.lobby_random_char_index_offset + char_index_offset = app.classic.lobby_random_char_index_offset self._random_character_index = ( (sessionplayer.inputdevice.id + char_index_offset) % len(self._character_names)) @@ -111,7 +112,7 @@ def __init__(self, vpos: float, sessionplayer: _ba.SessionPlayer, self._profileindex = self._select_initial_profile() self._profilename = self._profilenames[self._profileindex] - self._text_node = _ba.newnode('text', + self._text_node = bs.newnode('text', delegate=self, attrs={ 'position': (-100, self._vpos), @@ -122,8 +123,8 @@ def __init__(self, vpos: float, sessionplayer: _ba.SessionPlayer, 'v_align': 'center', 'v_attach': 'top' }) - animate(self._text_node, 'scale', {0: 0, 0.1: 1.0}) - self.icon = _ba.newnode('image', + bs.animate(self._text_node, 'scale', {0: 0, 0.1: 1.0}) + self.icon = bs.newnode('image', owner=self._text_node, attrs={ 'position': (-130, self._vpos + 20), @@ -132,7 +133,7 @@ def __init__(self, vpos: float, sessionplayer: _ba.SessionPlayer, 'attach': 'topCenter' }) - animate_array(self.icon, 'scale', 2, {0: (0, 0), 0.1: (45, 45)}) + bs.animate_array(self.icon, 'scale', 2, {0: (0, 0), 0.1: (45, 45)}) # Set our initial name to '' in case anyone asks. self._sessionplayer.setname( @@ -154,39 +155,39 @@ def __init__(self, vpos: float, sessionplayer: _ba.SessionPlayer, def _set_ready(self, ready: bool) -> None: # pylint: disable=cyclic-import - from bastd.ui.profile import browser as pbrowser - from ba._general import Call + from bauiv1lib.profile import browser as pbrowser + from babase._general import Call profilename = self._profilenames[self._profileindex] # Handle '_edit' as a special case. if profilename == '_edit' and ready: - with _ba.Context('ui'): + with _babase.Context('ui'): pbrowser.ProfileBrowserWindow(in_main_menu=False) # Give their input-device UI ownership too # (prevent someone else from snatching it in crowded games) - _ba.set_ui_input_device(self._sessionplayer.inputdevice) + _babase.set_ui_input_device(self._sessionplayer.inputdevice) return if ready == False: self._sessionplayer.assigninput( - InputType.LEFT_PRESS, + babase.InputType.LEFT_PRESS, Call(self.handlemessage, ChangeMessage('team', -1))) self._sessionplayer.assigninput( - InputType.RIGHT_PRESS, + babase.InputType.RIGHT_PRESS, Call(self.handlemessage, ChangeMessage('team', 1))) self._sessionplayer.assigninput( - InputType.BOMB_PRESS, + babase.InputType.BOMB_PRESS, Call(self.handlemessage, ChangeMessage('character', 1))) self._sessionplayer.assigninput( - InputType.UP_PRESS, + babase.InputType.UP_PRESS, Call(self.handlemessage, ChangeMessage('profileindex', -1))) self._sessionplayer.assigninput( - InputType.DOWN_PRESS, + babase.InputType.DOWN_PRESS, Call(self.handlemessage, ChangeMessage('profileindex', 1))) self._sessionplayer.assigninput( - (InputType.JUMP_PRESS, InputType.PICK_UP_PRESS, - InputType.PUNCH_PRESS), + (babase.InputType.JUMP_PRESS, babase.InputType.PICK_UP_PRESS, + babase.InputType.PUNCH_PRESS), Call(self.handlemessage, ChangeMessage('ready', 1))) self._ready = False self._update_text() @@ -194,26 +195,26 @@ def _set_ready(self, ready: bool) -> None: elif ready == True: self.characterchooser = True self._sessionplayer.assigninput( - (InputType.LEFT_PRESS, InputType.RIGHT_PRESS, - InputType.UP_PRESS, InputType.DOWN_PRESS, - InputType.JUMP_PRESS, InputType.BOMB_PRESS, - InputType.PICK_UP_PRESS), self._do_nothing) + (babase.InputType.LEFT_PRESS, babase.InputType.RIGHT_PRESS, + babase.InputType.UP_PRESS, babase.InputType.DOWN_PRESS, + babase.InputType.JUMP_PRESS, babase.InputType.BOMB_PRESS, + babase.InputType.PICK_UP_PRESS), self._do_nothing) self._sessionplayer.assigninput( - (InputType.UP_PRESS), Call(self.handlemessage, ChangeMessage('characterchooser', -1))) + (babase.InputType.UP_PRESS), Call(self.handlemessage, ChangeMessage('characterchooser', -1))) self._sessionplayer.assigninput( - (InputType.DOWN_PRESS), Call(self.handlemessage, ChangeMessage('characterchooser', 1))) + (babase.InputType.DOWN_PRESS), Call(self.handlemessage, ChangeMessage('characterchooser', 1))) self._sessionplayer.assigninput( - (InputType.BOMB_PRESS), Call(self.handlemessage, ChangeMessage('ready', 0))) + (babase.InputType.BOMB_PRESS), Call(self.handlemessage, ChangeMessage('ready', 0))) self._sessionplayer.assigninput( - (InputType.JUMP_PRESS, InputType.PICK_UP_PRESS, InputType.PUNCH_PRESS), + (babase.InputType.JUMP_PRESS, babase.InputType.PICK_UP_PRESS, babase.InputType.PUNCH_PRESS), Call(self.handlemessage, ChangeMessage('ready', 2))) # Store the last profile picked by this input for reuse. input_device = self._sessionplayer.inputdevice name = input_device.name unique_id = input_device.unique_identifier - device_profiles = _ba.app.config.setdefault( + device_profiles = _babase.app.config.setdefault( 'Default Player Profiles', {}) # Make an exception if we have no custom profiles and are set @@ -229,7 +230,7 @@ def _set_ready(self, ready: bool) -> None: del device_profiles[profilekey] else: device_profiles[profilekey] = profilename - _ba.app.config.commit() + _babase.app.config.commit() # Set this player's short and full name. self._sessionplayer.setname(self._getname(), @@ -240,7 +241,7 @@ def _set_ready(self, ready: bool) -> None: else: # Inform the session that this player is ready. - _ba.getsession().handlemessage(PlayerReadyMessage(self)) + bs.getsession().handlemessage(PlayerReadyMessage(self)) def handlemessage(self, msg: Any) -> Any: @@ -258,7 +259,7 @@ def handlemessage(self, msg: Any) -> Any: print_error('got ChangeMessage after nodes died') return if msg.what == 'characterchooser': - _ba.playsound(self._click_sound) + self._click_sound.play() # update our index in our local list of characters self._character_index = ((self._character_index + msg.value) % len(self._character_names)) @@ -268,7 +269,7 @@ def handlemessage(self, msg: Any) -> Any: if msg.what == 'team': sessionteams = self.lobby.sessionteams if len(sessionteams) > 1: - _ba.playsound(self._swish_sound) + self._swish_sound.play() self._selected_team_index = ( (self._selected_team_index + msg.value) % len(sessionteams)) @@ -281,18 +282,18 @@ def handlemessage(self, msg: Any) -> Any: # This should be pretty hard to hit now with # automatic local accounts. - _ba.playsound(_ba.getsound('error')) + bui.getsound('error').play() else: # Pick the next player profile and assign our name # and character based on that. - _ba.playsound(self._deek_sound) + self._deek_sound.play() self._profileindex = ((self._profileindex + msg.value) % len(self._profilenames)) self.update_from_profile() elif msg.what == 'character': - _ba.playsound(self._click_sound) + self._click_sound.play() self.characterchooser = True # update our index in our local list of characters self._character_index = ((self._character_index + msg.value) % @@ -327,9 +328,9 @@ def _update_text(self) -> None: can_switch_teams = len(self.lobby.sessionteams) > 1 # Flash as we're coming in. - fin_color = _ba.safecolor(self.get_color()) + (1, ) + fin_color = _babase.safecolor(self.get_color()) + (1, ) if not self._inited: - animate_array(self._text_node, 'color', 4, { + bs.animate_array(self._text_node, 'color', 4, { 0.15: fin_color, 0.25: (2, 2, 2, 1), 0.35: fin_color @@ -338,7 +339,7 @@ def _update_text(self) -> None: # Blend if we're in teams mode; switch instantly otherwise. if can_switch_teams: - animate_array(self._text_node, 'color', 4, { + bs.animate_array(self._text_node, 'color', 4, { 0: self._text_node.color, 0.1: fin_color }) @@ -350,7 +351,7 @@ def _update_text(self) -> None: # ba_meta export plugin -class HeySmoothy(ba.Plugin): +class HeySmoothy(babase.Plugin): def __init__(self): _lobby.Chooser.__init__ = __init__ diff --git a/plugins/utilities/easy_connect.py b/plugins/utilities/easy_connect.py index d14745ca..abd2f43c 100644 --- a/plugins/utilities/easy_connect.py +++ b/plugins/utilities/easy_connect.py @@ -1,50 +1,48 @@ # -*- coding: utf-8 -*- -# ba_meta require api 7 - -# =============================================== -# EasyConnect by Mr.Smoothy | -# verion 1.2 | -# https://discord.gg/ucyaesh | -# Serverconnector X IPPORTRevealer | -# for bombsquad v1.7 + | -# =============================================== +# ba_meta require api 8 +''' =========================================== + EasyConnect by Mr.Smoothy | + verion 1.7 | + https://discord.gg/ucyaesh | + Serverconnector X IPPORTRevealer | + for bombsquad v1.7.20+ | + ============================================== +''' # .................___________________________________________ # WATCH IN ACTION https://www.youtube.com/watch?v=jwi2wKwZblQ # .................___________________________________________ # Have any idea/suggestion/bug report > send message on discord mr.smoothy#5824 - +# Download modshttps://bombsquad-community.web.app/mods # Discord:- # mr.smoothy#5824 - # DONT EDIT ANYTHING WITHOUT PERMISSION -# join Bombspot - bombsquad biggest modding community .... open for everyone https://discord.gg/2RKd9QQdQY -# join Bombsquad Consultancy Service - for more mods, modding help ------- for all modders and server owners +# join Bombsquad Community Server - -# https://discord.gg/2RKd9QQdQY # https://discord.gg/ucyaesh # REQUIREMENTS -# built for bs 1.7 and above +# built for bs 1.7.20 and above -# by Mr.Smoothy for Bombsquad version 1.7 +# by Mr.Smoothy for Bombsquad version 1.7.20+ -import _ba -import ba -import bastd +import _babase +import babase +import bauiv1 as bui +import bascenev1 as bs import threading -from bastd.ui.gather import manualtab, publictab -from bastd.ui import popup +from bauiv1lib.gather import manualtab, publictab +from bauiv1lib import popup from dataclasses import dataclass import random from enum import Enum -from bastd.ui.popup import PopupMenuWindow, PopupWindow -from typing import Any, Optional, Dict, List, Tuple, Type, Union, Callable -from bastd.ui.gather.publictab import PublicGatherTab +from bauiv1lib.popup import PopupMenuWindow, PopupWindow +from typing import Any, Optional, Callable +from bauiv1lib.gather.publictab import PublicGatherTab import json import urllib.request import time @@ -61,7 +59,7 @@ https://discord.gg/ucyaesh https://ballistica.net/discord """ -BCSURL = 'https://bcsserver.bombsquad.ga/bannedservers' +BCSURL = 'https://bcs.ballistica.workers.dev/bannedservers' def is_game_version_lower_than(version): @@ -70,24 +68,21 @@ def is_game_version_lower_than(version): version is lower than the passed version. Useful for addressing any breaking changes within game versions. """ - game_version = tuple(map(int, ba.app.version.split("."))) + game_version = tuple(map(int, babase.app.version.split("."))) version = tuple(map(int, version.split("."))) return game_version < version -if is_game_version_lower_than("1.7.7"): - ba_internal = _ba -else: - ba_internal = ba.internal - def updateBannedServersCache(): response = None - config = ba.app.config + config = babase.app.config if not isinstance(config.get('Banned Servers'), list): config['Banned Servers'] = [] try: - response = urllib.request.urlopen(BCSURL).read() + req = urllib.request.Request(BCSURL, headers={ + "User-Agent": f'BS{_babase.env().get("build_number", 0)}', "Accept-Language": "en-US,en;q=0.9", }) + response = urllib.request.urlopen(req).read() data = json.loads(response.decode('utf-8')) bannedlist = [] for server in data["servers"]: @@ -116,133 +111,133 @@ def run(self) -> None: result = socket.gethostbyname(self._name) except Exception: result = None - ba.pushcall(lambda: self._call(result, self._port), + babase.pushcall(lambda: self._call(result, self._port), from_other_thread=True) -def new_build_favorites_tab(self, region_height: float) -> None: +def newbuild_favorites_tab(self, region_height: float) -> None: c_height = region_height - 20 v = c_height - 35 - 25 - 30 self.retry_inter = 0.0 - uiscale = ba.app.ui.uiscale - self._width = 1240 if uiscale is ba.UIScale.SMALL else 1040 - x_inset = 100 if uiscale is ba.UIScale.SMALL else 0 - self._height = (578 if uiscale is ba.UIScale.SMALL else - 670 if uiscale is ba.UIScale.MEDIUM else 800) + uiscale = bui.app.ui_v1.uiscale + self._width = 1240 if uiscale is babase.UIScale.SMALL else 1040 + x_inset = 100 if uiscale is babase.UIScale.SMALL else 0 + self._height = (578 if uiscale is babase.UIScale.SMALL else + 670 if uiscale is babase.UIScale.MEDIUM else 800) self._scroll_width = self._width - 130 + 2 * x_inset self._scroll_height = self._height - 180 - x_inset = 100 if uiscale is ba.UIScale.SMALL else 0 + x_inset = 100 if uiscale is babase.UIScale.SMALL else 0 c_height = self._scroll_height - 20 sub_scroll_height = c_height - 63 self._favorites_scroll_width = sub_scroll_width = ( - 680 if uiscale is ba.UIScale.SMALL else 640) + 680 if uiscale is babase.UIScale.SMALL else 640) v = c_height - 30 - b_width = 140 if uiscale is ba.UIScale.SMALL else 178 - b_height = (90 if uiscale is ba.UIScale.SMALL else - 142 if uiscale is ba.UIScale.MEDIUM else 130) - b_space_extra = (0 if uiscale is ba.UIScale.SMALL else - -2 if uiscale is ba.UIScale.MEDIUM else -5) + b_width = 140 if uiscale is babase.UIScale.SMALL else 178 + b_height = (90 if uiscale is babase.UIScale.SMALL else + 142 if uiscale is babase.UIScale.MEDIUM else 130) + b_space_extra = (0 if uiscale is babase.UIScale.SMALL else + -2 if uiscale is babase.UIScale.MEDIUM else -5) - btnv = (c_height - (48 if uiscale is ba.UIScale.SMALL else - 45 if uiscale is ba.UIScale.MEDIUM else 40) - + btnv = (c_height - (48 if uiscale is babase.UIScale.SMALL else + 45 if uiscale is babase.UIScale.MEDIUM else 40) - b_height) # ================= smoothy ============= - ba.textwidget(parent=self._container, - position=(90 if uiscale is ba.UIScale.SMALL else 120, btnv + - 120 if uiscale is ba.UIScale.SMALL else btnv+90), + bui.textwidget(parent=self._container, + position=(90 if uiscale is babase.UIScale.SMALL else 120, btnv + + 120 if uiscale is babase.UIScale.SMALL else btnv+90), size=(0, 0), h_align='center', color=(0.8, 0.8, 0.8), v_align='top', text="Auto") - btnv += 50 if uiscale is ba.UIScale.SMALL else 0 + btnv += 50 if uiscale is babase.UIScale.SMALL else 0 - ba.buttonwidget(parent=self._container, + bui.buttonwidget(parent=self._container, size=(30, 30), - position=(25 if uiscale is ba.UIScale.SMALL else 40, + position=(25 if uiscale is babase.UIScale.SMALL else 40, btnv+10), color=(0.6, 0.53, 0.63), textcolor=(0.75, 0.7, 0.8), on_activate_call=self.auto_retry_dec, - text_scale=1.3 if uiscale is ba.UIScale.SMALL else 1.2, + text_scale=1.3 if uiscale is babase.UIScale.SMALL else 1.2, label="-", autoselect=True) - self.retry_inter_text = ba.textwidget(parent=self._container, + self.retry_inter_text = bui.textwidget(parent=self._container, position=( - 90 if uiscale is ba.UIScale.SMALL else 120, btnv+25), + 90 if uiscale is babase.UIScale.SMALL else 120, btnv+25), size=(0, 0), h_align='center', color=(0.8, 0.8, 0.8), v_align='center', text=str(self.retry_inter) if self.retry_inter > 0.0 else 'off') - ba.buttonwidget(parent=self._container, + bui.buttonwidget(parent=self._container, size=(30, 30), - position=(125 if uiscale is ba.UIScale.SMALL else 155, + position=(125 if uiscale is babase.UIScale.SMALL else 155, btnv+10), color=(0.6, 0.53, 0.63), textcolor=(0.75, 0.7, 0.8), on_activate_call=self.auto_retry_inc, - text_scale=1.3 if uiscale is ba.UIScale.SMALL else 1.2, + text_scale=1.3 if uiscale is babase.UIScale.SMALL else 1.2, label="+", autoselect=True) btnv -= b_height + b_space_extra - self._favorites_connect_button = btn1 = ba.buttonwidget( + self._favorites_connect_button = btn1 = bui.buttonwidget( parent=self._container, size=(b_width, b_height), - position=(25 if uiscale is ba.UIScale.SMALL else 40, btnv), + position=(25 if uiscale is babase.UIScale.SMALL else 40, btnv), button_type='square', color=(0.6, 0.53, 0.63), textcolor=(0.75, 0.7, 0.8), on_activate_call=self._on_favorites_connect_press, - text_scale=1.0 if uiscale is ba.UIScale.SMALL else 1.2, - label=ba.Lstr(resource='gatherWindow.manualConnectText'), + text_scale=1.0 if uiscale is babase.UIScale.SMALL else 1.2, + label=babase.Lstr(resource='gatherWindow.manualConnectText'), autoselect=True) - if uiscale is ba.UIScale.SMALL and ba.app.ui.use_toolbars: - ba.widget(edit=btn1, - left_widget=ba_internal.get_special_widget('back_button')) + if uiscale is babase.UIScale.SMALL and bui.app.ui_v1.use_toolbars: + bui.widget(edit=btn1, + left_widget=bui.get_special_widget('back_button')) btnv -= b_height + b_space_extra - ba.buttonwidget(parent=self._container, + bui.buttonwidget(parent=self._container, size=(b_width, b_height), - position=(25 if uiscale is ba.UIScale.SMALL else 40, + position=(25 if uiscale is babase.UIScale.SMALL else 40, btnv), button_type='square', color=(0.6, 0.53, 0.63), textcolor=(0.75, 0.7, 0.8), on_activate_call=self._on_favorites_edit_press, - text_scale=1.0 if uiscale is ba.UIScale.SMALL else 1.2, - label=ba.Lstr(resource='editText'), + text_scale=1.0 if uiscale is babase.UIScale.SMALL else 1.2, + label=babase.Lstr(resource='editText'), autoselect=True) btnv -= b_height + b_space_extra - ba.buttonwidget(parent=self._container, + bui.buttonwidget(parent=self._container, size=(b_width, b_height), - position=(25 if uiscale is ba.UIScale.SMALL else 40, + position=(25 if uiscale is babase.UIScale.SMALL else 40, btnv), button_type='square', color=(0.6, 0.53, 0.63), textcolor=(0.75, 0.7, 0.8), on_activate_call=self._on_favorite_delete_press, - text_scale=1.0 if uiscale is ba.UIScale.SMALL else 1.2, - label=ba.Lstr(resource='deleteText'), + text_scale=1.0 if uiscale is babase.UIScale.SMALL else 1.2, + label=babase.Lstr(resource='deleteText'), autoselect=True) v -= sub_scroll_height + 23 - self._scrollwidget = scrlw = ba.scrollwidget( + self._scrollwidget = scrlw = bui.scrollwidget( parent=self._container, - position=(190 if uiscale is ba.UIScale.SMALL else 225, v), + position=(190 if uiscale is babase.UIScale.SMALL else 225, v), size=(sub_scroll_width, sub_scroll_height), claims_left_right=True) - ba.widget(edit=self._favorites_connect_button, + bui.widget(edit=self._favorites_connect_button, right_widget=self._scrollwidget) - self._columnwidget = ba.columnwidget(parent=scrlw, + self._columnwidget = bui.columnwidget(parent=scrlw, left_border=10, border=2, margin=0, @@ -257,22 +252,22 @@ def new_on_favorites_connect_press(self) -> None: self._no_favorite_selected_error() else: - config = ba.app.config['Saved Servers'][self._favorite_selected] + config = babase.app.config['Saved Servers'][self._favorite_selected] _HostLookupThread(name=config['addr'], port=config['port'], - call=ba.WeakCall( + call=bs.WeakCall( self._host_lookup_result)).start() - if self.retry_inter > 0 and (ba_internal.get_connection_to_host_info() == {} or ba_internal.get_connection_to_host_info()['build_number'] == 0): - ba.screenmessage("Server full or unreachable, Retrying....") - self._retry_timer = ba.Timer(self.retry_inter, ba.Call( - self._on_favorites_connect_press), timetype=ba.TimeType.REAL) + if self.retry_inter > 0 and (bs.get_connection_to_host_info() == {} or bs.get_connection_to_host_info()['build_number'] == 0): + bui.screenmessage("Server full or unreachable, Retrying....") + self._retry_timer = bs.AppTimer(self.retry_inter, babase.Call( + self._on_favorites_connect_press)) def auto_retry_inc(self): self.retry_inter += 0.5 - ba.textwidget(edit=self.retry_inter_text, text='%.1f' % self.retry_inter) + bui.textwidget(edit=self.retry_inter_text, text='%.1f' % self.retry_inter) def auto_retry_dec(self): @@ -280,9 +275,9 @@ def auto_retry_dec(self): self.retry_inter -= 0.5 if self.retry_inter == 0.0: - ba.textwidget(edit=self.retry_inter_text, text='off') + bui.textwidget(edit=self.retry_inter_text, text='off') else: - ba.textwidget(edit=self.retry_inter_text, text='%.1f' % self.retry_inter) + bui.textwidget(edit=self.retry_inter_text, text='%.1f' % self.retry_inter) @dataclass @@ -328,121 +323,142 @@ def _clear(self) -> None: self._stats_button ]: if widget: - try: - widget.delete() - except: - pass + + widget.delete() + def update(self, index: int, party: PartyEntry, sub_scroll_width: float, sub_scroll_height: float, lineheight: float, - columnwidget: ba.Widget, join_text: ba.Widget, - filter_text: ba.Widget, existing_selection: Optional[Selection], + columnwidget: bui.Widget, join_text: bui.Widget, + filter_text: bui.Widget, existing_selection: Optional[Selection], tab: PublicGatherTab) -> None: - """Update for the given data.""" - # pylint: disable=too-many-locals - - # Quick-out: if we've been marked clean for a certain index and - # we're still at that index, we're done. - if party.clean_display_index == index: - return - - ping_good = ba_internal.get_v1_account_misc_read_val('pingGood', 100) - ping_med = ba_internal.get_v1_account_misc_read_val('pingMed', 500) - - self._clear() - hpos = 20 - vpos = sub_scroll_height - lineheight * index - 50 - self._name_widget = ba.textwidget( - text=ba.Lstr(value=party.name), - parent=columnwidget, - size=(sub_scroll_width * 0.63, 20), - position=(0 + hpos, 4 + vpos), - selectable=True, - on_select_call=ba.WeakCall( - tab.set_public_party_selection, - Selection(party.get_key(), SelectionComponent.NAME)), - on_activate_call=ba.WeakCall(tab.on_public_party_activate, party), - click_activate=True, - maxwidth=sub_scroll_width * 0.45, - corner_scale=1.4, - autoselect=True, - color=(1, 1, 1, 0.3 if party.ping is None else 1.0), - h_align='left', - v_align='center') - ba.widget(edit=self._name_widget, - left_widget=join_text, - show_buffer_top=64.0, - show_buffer_bottom=64.0) - if existing_selection == Selection(party.get_key(), - SelectionComponent.NAME): - ba.containerwidget(edit=columnwidget, - selected_child=self._name_widget) - if party.stats_addr or True: - url = party.stats_addr.replace( - '${ACCOUNT}', - ba_internal.get_v1_account_misc_read_val_2('resolvedAccountID', - 'UNKNOWN')) - self._stats_button = ba.buttonwidget( - color=(0.5, 0.8, 0.8), - textcolor=(1.0, 1.0, 1.0), - label='....', + """Update for the given data.""" + # pylint: disable=too-many-locals + + # Quick-out: if we've been marked clean for a certain index and + # we're still at that index, we're done. + plus = bui.app.plus + assert plus is not None + + # Quick-out: if we've been marked clean for a certain index and + # we're still at that index, we're done. + if party.clean_display_index == index: + return + + ping_good = plus.get_v1_account_misc_read_val('pingGood', 100) + ping_med = plus.get_v1_account_misc_read_val('pingMed', 500) + + self._clear() + hpos = 20 + vpos = sub_scroll_height - lineheight * index - 50 + self._name_widget = bui.textwidget( + text=bui.Lstr(value=party.name), parent=columnwidget, - autoselect=True, - - on_select_call=ba.WeakCall( + size=(sub_scroll_width * 0.63, 20), + position=(0 + hpos, 4 + vpos), + selectable=True, + on_select_call=bui.WeakCall( tab.set_public_party_selection, - Selection(party.get_key(), - SelectionComponent.STATS_BUTTON)), - size=(100, 40), - position=(sub_scroll_width * 0.66 + hpos, 1 + vpos), - scale=0.9) - ba.buttonwidget(edit=self._stats_button, on_activate_call=ba.Call( - self.on_stats_click, self._stats_button, party)) + Selection(party.get_key(), SelectionComponent.NAME), + ), + on_activate_call=bui.WeakCall(tab.on_public_party_activate, party), + click_activate=True, + maxwidth=sub_scroll_width * 0.45, + corner_scale=1.4, + autoselect=True, + color=(1, 1, 1, 0.3 if party.ping is None else 1.0), + h_align='left', + v_align='center', + ) + bui.widget( + edit=self._name_widget, + left_widget=join_text, + show_buffer_top=64.0, + show_buffer_bottom=64.0, + ) if existing_selection == Selection( - party.get_key(), SelectionComponent.STATS_BUTTON): - ba.containerwidget(edit=columnwidget, - selected_child=self._stats_button) - - self._size_widget = ba.textwidget( - text=str(party.size) + '/' + str(party.size_max), - parent=columnwidget, - size=(0, 0), - position=(sub_scroll_width * 0.86 + hpos, 20 + vpos), - scale=0.7, - color=(0.8, 0.8, 0.8), - h_align='right', - v_align='center') - - if index == 0: - ba.widget(edit=self._name_widget, up_widget=filter_text) - if self._stats_button: - ba.widget(edit=self._stats_button, up_widget=filter_text) - - self._ping_widget = ba.textwidget(parent=columnwidget, - size=(0, 0), - position=(sub_scroll_width * 0.94 + - hpos, 20 + vpos), - scale=0.7, - h_align='right', - v_align='center') - if party.ping is None: - ba.textwidget(edit=self._ping_widget, - text='-', - color=(0.5, 0.5, 0.5)) - else: - ba.textwidget(edit=self._ping_widget, - text=str(int(party.ping)), - color=(0, 1, 0) if party.ping <= ping_good else - (1, 1, 0) if party.ping <= ping_med else (1, 0, 0)) + party.get_key(), SelectionComponent.NAME + ): + bui.containerwidget( + edit=columnwidget, selected_child=self._name_widget + ) + if party.stats_addr or True: + url = party.stats_addr.replace( + '${ACCOUNT}', + plus.get_v1_account_misc_read_val_2( + 'resolvedAccountID', 'UNKNOWN' + ), + ) + self._stats_button = bui.buttonwidget( + color=(0.3, 0.6, 0.94), + textcolor=(1.0, 1.0, 1.0), + label='....', + parent=columnwidget, + autoselect=True, + on_activate_call=bui.Call(bui.open_url, url), + on_select_call=bui.WeakCall( + tab.set_public_party_selection, + Selection(party.get_key(), SelectionComponent.STATS_BUTTON), + ), + size=(120, 40), + position=(sub_scroll_width * 0.66 + hpos, 1 + vpos), + scale=0.9, + ) + bui.buttonwidget(edit=self._stats_button, on_activate_call=bui.WeakCall( + self.on_stats_click, self._stats_button, party)) + if existing_selection == Selection( + party.get_key(), SelectionComponent.STATS_BUTTON + ): + bui.containerwidget( + edit=columnwidget, selected_child=self._stats_button + ) + + self._size_widget = bui.textwidget( + text=str(party.size) + '/' + str(party.size_max), + parent=columnwidget, + size=(0, 0), + position=(sub_scroll_width * 0.86 + hpos, 20 + vpos), + scale=0.7, + color=(0.8, 0.8, 0.8), + h_align='right', + v_align='center', + ) - party.clean_display_index = index + if index == 0: + bui.widget(edit=self._name_widget, up_widget=filter_text) + if self._stats_button: + bui.widget(edit=self._stats_button, up_widget=filter_text) + self._ping_widget = bui.textwidget( + parent=columnwidget, + size=(0, 0), + position=(sub_scroll_width * 0.94 + hpos, 20 + vpos), + scale=0.7, + h_align='right', + v_align='center', + ) + if party.ping is None: + bui.textwidget( + edit=self._ping_widget, text='-', color=(0.5, 0.5, 0.5) + ) + else: + bui.textwidget( + edit=self._ping_widget, + text=str(int(party.ping)), + color=(0, 1, 0) + if party.ping <= ping_good + else (1, 1, 0) + if party.ping <= ping_med + else (1, 0, 0), + ) + + party.clean_display_index = index def _get_popup_window_scale() -> float: - uiscale = ba.app.ui.uiscale - return (2.3 if uiscale is ba.UIScale.SMALL else - 1.65 if uiscale is ba.UIScale.MEDIUM else 1.23) + uiscale = bui.app.ui_v1.uiscale + return (2.3 if uiscale is babase.UIScale.SMALL else + 1.65 if uiscale is babase.UIScale.MEDIUM else 1.23) _party = None @@ -452,8 +468,8 @@ def on_stats_click(self, widget, party): global _party _party = party choices = ['connect', 'copyqueue', "save"] - DisChoices = [ba.Lstr(resource="ipp", fallback_value="Connect by IP"), ba.Lstr( - resource="copy id", fallback_value="Copy Queue ID"), ba.Lstr(value="Save")] + DisChoices = [babase.Lstr(resource="ipp", fallback_value="Connect by IP"), babase.Lstr( + resource="copy id", fallback_value="Copy Queue ID"), babase.Lstr(value="Save")] if party.stats_addr: choices.append('stats') if 'discord' in party.stats_addr: @@ -462,7 +478,7 @@ def on_stats_click(self, widget, party): txt = "Youtube" else: txt = party.stats_addr[0:13] - DisChoices.append(ba.Lstr(value=txt)) + DisChoices.append(babase.Lstr(value=txt)) PopupMenuWindow( position=widget.get_screen_space_center(), scale=_get_popup_window_scale(), @@ -480,17 +496,17 @@ def popup_menu_selected_choice(self, window: popup.PopupMenu, choice: str) -> None: """Called when a menu entry is selected.""" # Unused arg. - + plus = babase.app.plus if choice == 'stats': url = _party.stats_addr.replace( '${ACCOUNT}', - ba_internal.get_v1_account_misc_read_val_2('resolvedAccountID', + plus.get_v1_account_misc_read_val_2('resolvedAccountID', 'UNKNOWN')) - ba.open_url(url) + bui.open_url(url) elif choice == 'connect': PartyQuickConnect(_party.address, _party.port) elif choice == 'save': - config = ba.app.config + config = babase.app.config ip_add = _party.address p_port = _party.port title = _party.name @@ -502,18 +518,19 @@ def popup_menu_selected_choice(self, window: popup.PopupMenu, 'name': title } config.commit() - ba.screenmessage("Server saved to manual") - ba.playsound(ba.getsound('gunCocking')) + bui.screenmessage("Server saved to manual") + bui.getsound('gunCocking').play() elif choice == "copyqueue": - ba.clipboard_set_text(_party.queue) - ba.playsound(ba.getsound('gunCocking')) + babase.clipboard_set_text(_party.queue) + bui.getsound('gunCocking').play() def _update_party_lists(self) -> None: if not self._party_lists_dirty: return starttime = time.time() - config = ba.app.config + config = babase.app.config + plus = babase.app.plus bannedservers = config.get('Banned Servers', []) assert len(self._parties_sorted) == len(self._parties) @@ -526,7 +543,7 @@ def _update_party_lists(self) -> None: # If signed out or errored, show no parties. if ( - ba.internal.get_v1_account_state() != 'signed_in' + plus.get_v1_account_state() != 'signed_in' or not self._have_valid_server_list ): self._parties_displayed = {} @@ -568,7 +585,7 @@ def _update_party_lists(self) -> None: def replace(): - manualtab.ManualGatherTab._build_favorites_tab = new_build_favorites_tab + manualtab.ManualGatherTab._build_favorites_tab = newbuild_favorites_tab manualtab.ManualGatherTab._on_favorites_connect_press = new_on_favorites_connect_press manualtab.ManualGatherTab.auto_retry_dec = auto_retry_dec manualtab.ManualGatherTab.auto_retry_inc = auto_retry_inc @@ -577,26 +594,26 @@ def replace(): publictab.UIRow.on_stats_click = on_stats_click publictab.UIRow.popup_menu_closing = popup_menu_closing publictab.UIRow.popup_menu_selected_choice = popup_menu_selected_choice - publictab.PublicGatherTab._update_party_lists = _update_party_lists + # publictab.PublicGatherTab._update_party_lists = _update_party_lists -class PartyQuickConnect(ba.Window): +class PartyQuickConnect(bui.Window): def __init__(self, address: str, port: int): self._width = 800 self._height = 400 - self._white_tex = ba.gettexture('white') - self.lineup_tex = ba.gettexture('playerLineup') - self.lineup_1_transparent_model = ba.getmodel( + self._white_tex = bui.gettexture('white') + self.lineup_tex = bui.gettexture('playerLineup') + self.lineup_1_transparent_mesh = bui.getmesh( 'playerLineup1Transparent') - self.eyes_model = ba.getmodel('plasticEyesTransparent') - uiscale = ba.app.ui.uiscale - super().__init__(root_widget=ba.containerwidget( + self.eyes_mesh = bui.getmesh('plasticEyesTransparent') + uiscale = bui.app.ui_v1.uiscale + super().__init__(root_widget=bui.containerwidget( size=(self._width, self._height), color=(0.45, 0.63, 0.15), transition='in_scale', - scale=(1.4 if uiscale is ba.UIScale.SMALL else - 1.2 if uiscale is ba.UIScale.MEDIUM else 1.0))) - self._cancel_button = ba.buttonwidget(parent=self._root_widget, + scale=(1.4 if uiscale is babase.UIScale.SMALL else + 1.2 if uiscale is babase.UIScale.MEDIUM else 1.0))) + self._cancel_button = bui.buttonwidget(parent=self._root_widget, scale=1.0, position=(60, self._height - 80), size=(50, 50), @@ -604,12 +621,12 @@ def __init__(self, address: str, port: int): on_activate_call=self.close, autoselect=True, color=(0.45, 0.63, 0.15), - icon=ba.gettexture('crossOut'), + icon=bui.gettexture('crossOut'), iconscale=1.2) - ba.containerwidget(edit=self._root_widget, + bui.containerwidget(edit=self._root_widget, cancel_button=self._cancel_button) - self.IP = ba.textwidget( + self.IP = bui.textwidget( parent=self._root_widget, position=(self._width * 0.5, self._height * 0.55 + 60), size=(0, 0), @@ -619,7 +636,7 @@ def __init__(self, address: str, port: int): v_align='center', text="IP: "+address + " PORT: "+str(port), maxwidth=self._width * 0.65) - self._title_text = ba.textwidget( + self._title_text = bui.textwidget( parent=self._root_widget, position=(self._width * 0.5, self._height * 0.55), size=(0, 0), @@ -629,7 +646,7 @@ def __init__(self, address: str, port: int): v_align='center', text="Retrying....", maxwidth=self._width * 0.65) - self._line_image = ba.imagewidget( + self._line_image = bui.imagewidget( parent=self._root_widget, color=(0.0, 0.0, 0.0), opacity=0.2, @@ -637,39 +654,38 @@ def __init__(self, address: str, port: int): size=(800-190+80, 4.0), texture=self._white_tex) self.dude_x = 60 - self._body_image_target = ba.buttonwidget( + self._body_image_target = bui.buttonwidget( parent=self._root_widget, size=(1 * 60, 1 * 80), color=(random.random(), random.random(), random.random()), label='', texture=self.lineup_tex, position=(40, 110), - model_transparent=self.lineup_1_transparent_model) - self._eyes_image = ba.imagewidget( + mesh_transparent=self.lineup_1_transparent_mesh) + self._eyes_image = bui.imagewidget( parent=self._root_widget, size=(1 * 36, 1 * 18), texture=self.lineup_tex, color=(1, 1, 1), position=(40, 165), - model_transparent=self.eyes_model) - # self._body_image_target2 = ba.imagewidget( + mesh_transparent=self.eyes_mesh) + # self._body_image_target2 = bui.imagewidget( # parent=self._root_widget, # size=(1* 60, 1 * 80), # color=(1,0.3,0.4), # texture=self.lineup_tex, # position=(700,130), - # model_transparent=self.lineup_1_transparent_model) + # mesh_transparent=self.lineup_1_transparent_mesh) self.closed = False self.retry_count = 1 self.direction = "right" self.connect(address, port) - self.move_R = ba.Timer(0.01, ba.Call(self.move_right), - timetype=ba.TimeType.REAL, repeat=True) + self.move_R = bs.AppTimer(0.01, babase.Call(self.move_right), repeat=True) def move_right(self): if self._body_image_target and self._eyes_image: - ba.buttonwidget(edit=self._body_image_target, position=(self.dude_x, 110)) - ba.imagewidget(edit=self._eyes_image, position=(self.dude_x+10, 165)) + bui.buttonwidget(edit=self._body_image_target, position=(self.dude_x, 110)) + bui.imagewidget(edit=self._eyes_image, position=(self.dude_x+10, 165)) else: self.move_R = None if self.direction == "right": @@ -682,23 +698,23 @@ def move_right(self): self.direction = "right" def connect(self, address, port): - if not self.closed and (ba_internal.get_connection_to_host_info() == {} or ba_internal.get_connection_to_host_info()['build_number'] == 0): - ba.textwidget(edit=self._title_text, text="Retrying....("+str(self.retry_count)+")") + if not self.closed and (bs.get_connection_to_host_info() == {} or bs.get_connection_to_host_info()['build_number'] == 0): + bui.textwidget(edit=self._title_text, text="Retrying....("+str(self.retry_count)+")") self.retry_count += 1 - ba_internal.connect_to_party(address, port=port) - self._retry_timer = ba.Timer(1.5, ba.Call( - self.connect, address, port), timetype=ba.TimeType.REAL) + bs.connect_to_party(address, port=port) + self._retry_timer = bs.AppTimer(1.5, babase.Call( + self.connect, address, port)) def close(self) -> None: """Close the ui.""" self.closed = True - ba.containerwidget(edit=self._root_widget, transition='out_scale') + bui.containerwidget(edit=self._root_widget, transition='out_scale') # ba_meta export plugin -class InitalRun(ba.Plugin): +class InitalRun(babase.Plugin): def __init__(self): replace() - config = ba.app.config + config = babase.app.config if config["launchCount"] % 5 == 0: updateBannedServersCache() From 0c5ce76154c214ecd9be5bb4791b452a4d8cd5ad Mon Sep 17 00:00:00 2001 From: imayushsaini Date: Sun, 2 Jul 2023 12:59:51 +0000 Subject: [PATCH 0525/1464] [ci] auto-format --- plugins/utilities/character_chooser.py | 35 ++- plugins/utilities/easy_connect.py | 367 ++++++++++++------------- 2 files changed, 200 insertions(+), 202 deletions(-) diff --git a/plugins/utilities/character_chooser.py b/plugins/utilities/character_chooser.py index 9dbe7333..da12dbb3 100644 --- a/plugins/utilities/character_chooser.py +++ b/plugins/utilities/character_chooser.py @@ -55,7 +55,6 @@ from bascenev1lib.actor.spazappearance import * - def __init__(self, vpos: float, sessionplayer: bs.SessionPlayer, lobby: 'Lobby') -> None: self._deek_sound = bs.getsound('deek') @@ -113,25 +112,25 @@ def __init__(self, vpos: float, sessionplayer: bs.SessionPlayer, self._profilename = self._profilenames[self._profileindex] self._text_node = bs.newnode('text', - delegate=self, - attrs={ - 'position': (-100, self._vpos), - 'maxwidth': 190, - 'shadow': 0.5, - 'vr_depth': -20, - 'h_align': 'left', - 'v_align': 'center', - 'v_attach': 'top' - }) + delegate=self, + attrs={ + 'position': (-100, self._vpos), + 'maxwidth': 190, + 'shadow': 0.5, + 'vr_depth': -20, + 'h_align': 'left', + 'v_align': 'center', + 'v_attach': 'top' + }) bs.animate(self._text_node, 'scale', {0: 0, 0.1: 1.0}) self.icon = bs.newnode('image', - owner=self._text_node, - attrs={ - 'position': (-130, self._vpos + 20), - 'mask_texture': self._mask_texture, - 'vr_depth': -10, - 'attach': 'topCenter' - }) + owner=self._text_node, + attrs={ + 'position': (-130, self._vpos + 20), + 'mask_texture': self._mask_texture, + 'vr_depth': -10, + 'attach': 'topCenter' + }) bs.animate_array(self.icon, 'scale', 2, {0: (0, 0), 0.1: (45, 45)}) diff --git a/plugins/utilities/easy_connect.py b/plugins/utilities/easy_connect.py index abd2f43c..c9255154 100644 --- a/plugins/utilities/easy_connect.py +++ b/plugins/utilities/easy_connect.py @@ -15,13 +15,13 @@ # .................___________________________________________ # Have any idea/suggestion/bug report > send message on discord mr.smoothy#5824 -# Download modshttps://bombsquad-community.web.app/mods +# Download modshttps://bombsquad-community.web.app/mods # Discord:- # mr.smoothy#5824 # DONT EDIT ANYTHING WITHOUT PERMISSION -# join Bombsquad Community Server - +# join Bombsquad Community Server - # https://discord.gg/ucyaesh @@ -73,7 +73,6 @@ def is_game_version_lower_than(version): return game_version < version - def updateBannedServersCache(): response = None config = babase.app.config @@ -112,7 +111,7 @@ def run(self) -> None: except Exception: result = None babase.pushcall(lambda: self._call(result, self._port), - from_other_thread=True) + from_other_thread=True) def newbuild_favorites_tab(self, region_height: float) -> None: @@ -148,45 +147,45 @@ def newbuild_favorites_tab(self, region_height: float) -> None: # ================= smoothy ============= bui.textwidget(parent=self._container, - position=(90 if uiscale is babase.UIScale.SMALL else 120, btnv + - 120 if uiscale is babase.UIScale.SMALL else btnv+90), - size=(0, 0), - h_align='center', - color=(0.8, 0.8, 0.8), - v_align='top', - text="Auto") + position=(90 if uiscale is babase.UIScale.SMALL else 120, btnv + + 120 if uiscale is babase.UIScale.SMALL else btnv+90), + size=(0, 0), + h_align='center', + color=(0.8, 0.8, 0.8), + v_align='top', + text="Auto") btnv += 50 if uiscale is babase.UIScale.SMALL else 0 bui.buttonwidget(parent=self._container, - size=(30, 30), - position=(25 if uiscale is babase.UIScale.SMALL else 40, - btnv+10), - - color=(0.6, 0.53, 0.63), - textcolor=(0.75, 0.7, 0.8), - on_activate_call=self.auto_retry_dec, - text_scale=1.3 if uiscale is babase.UIScale.SMALL else 1.2, - label="-", - autoselect=True) + size=(30, 30), + position=(25 if uiscale is babase.UIScale.SMALL else 40, + btnv+10), + + color=(0.6, 0.53, 0.63), + textcolor=(0.75, 0.7, 0.8), + on_activate_call=self.auto_retry_dec, + text_scale=1.3 if uiscale is babase.UIScale.SMALL else 1.2, + label="-", + autoselect=True) self.retry_inter_text = bui.textwidget(parent=self._container, - position=( - 90 if uiscale is babase.UIScale.SMALL else 120, btnv+25), - size=(0, 0), - h_align='center', - color=(0.8, 0.8, 0.8), - v_align='center', - text=str(self.retry_inter) if self.retry_inter > 0.0 else 'off') + position=( + 90 if uiscale is babase.UIScale.SMALL else 120, btnv+25), + size=(0, 0), + h_align='center', + color=(0.8, 0.8, 0.8), + v_align='center', + text=str(self.retry_inter) if self.retry_inter > 0.0 else 'off') bui.buttonwidget(parent=self._container, - size=(30, 30), - position=(125 if uiscale is babase.UIScale.SMALL else 155, - btnv+10), + size=(30, 30), + position=(125 if uiscale is babase.UIScale.SMALL else 155, + btnv+10), - color=(0.6, 0.53, 0.63), - textcolor=(0.75, 0.7, 0.8), - on_activate_call=self.auto_retry_inc, - text_scale=1.3 if uiscale is babase.UIScale.SMALL else 1.2, - label="+", - autoselect=True) + color=(0.6, 0.53, 0.63), + textcolor=(0.75, 0.7, 0.8), + on_activate_call=self.auto_retry_inc, + text_scale=1.3 if uiscale is babase.UIScale.SMALL else 1.2, + label="+", + autoselect=True) btnv -= b_height + b_space_extra @@ -203,31 +202,31 @@ def newbuild_favorites_tab(self, region_height: float) -> None: autoselect=True) if uiscale is babase.UIScale.SMALL and bui.app.ui_v1.use_toolbars: bui.widget(edit=btn1, - left_widget=bui.get_special_widget('back_button')) + left_widget=bui.get_special_widget('back_button')) btnv -= b_height + b_space_extra bui.buttonwidget(parent=self._container, - size=(b_width, b_height), - position=(25 if uiscale is babase.UIScale.SMALL else 40, - btnv), - button_type='square', - color=(0.6, 0.53, 0.63), - textcolor=(0.75, 0.7, 0.8), - on_activate_call=self._on_favorites_edit_press, - text_scale=1.0 if uiscale is babase.UIScale.SMALL else 1.2, - label=babase.Lstr(resource='editText'), - autoselect=True) + size=(b_width, b_height), + position=(25 if uiscale is babase.UIScale.SMALL else 40, + btnv), + button_type='square', + color=(0.6, 0.53, 0.63), + textcolor=(0.75, 0.7, 0.8), + on_activate_call=self._on_favorites_edit_press, + text_scale=1.0 if uiscale is babase.UIScale.SMALL else 1.2, + label=babase.Lstr(resource='editText'), + autoselect=True) btnv -= b_height + b_space_extra bui.buttonwidget(parent=self._container, - size=(b_width, b_height), - position=(25 if uiscale is babase.UIScale.SMALL else 40, - btnv), - button_type='square', - color=(0.6, 0.53, 0.63), - textcolor=(0.75, 0.7, 0.8), - on_activate_call=self._on_favorite_delete_press, - text_scale=1.0 if uiscale is babase.UIScale.SMALL else 1.2, - label=babase.Lstr(resource='deleteText'), - autoselect=True) + size=(b_width, b_height), + position=(25 if uiscale is babase.UIScale.SMALL else 40, + btnv), + button_type='square', + color=(0.6, 0.53, 0.63), + textcolor=(0.75, 0.7, 0.8), + on_activate_call=self._on_favorite_delete_press, + text_scale=1.0 if uiscale is babase.UIScale.SMALL else 1.2, + label=babase.Lstr(resource='deleteText'), + autoselect=True) v -= sub_scroll_height + 23 self._scrollwidget = scrlw = bui.scrollwidget( @@ -236,12 +235,12 @@ def newbuild_favorites_tab(self, region_height: float) -> None: size=(sub_scroll_width, sub_scroll_height), claims_left_right=True) bui.widget(edit=self._favorites_connect_button, - right_widget=self._scrollwidget) + right_widget=self._scrollwidget) self._columnwidget = bui.columnwidget(parent=scrlw, - left_border=10, - border=2, - margin=0, - claims_left_right=True) + left_border=10, + border=2, + margin=0, + claims_left_right=True) self._favorite_selected = None self._refresh_favorites() @@ -323,9 +322,8 @@ def _clear(self) -> None: self._stats_button ]: if widget: - + widget.delete() - def update(self, index: int, party: PartyEntry, sub_scroll_width: float, @@ -333,127 +331,128 @@ def update(self, index: int, party: PartyEntry, sub_scroll_width: float, columnwidget: bui.Widget, join_text: bui.Widget, filter_text: bui.Widget, existing_selection: Optional[Selection], tab: PublicGatherTab) -> None: - """Update for the given data.""" - # pylint: disable=too-many-locals - - # Quick-out: if we've been marked clean for a certain index and - # we're still at that index, we're done. - plus = bui.app.plus - assert plus is not None - - # Quick-out: if we've been marked clean for a certain index and - # we're still at that index, we're done. - if party.clean_display_index == index: - return - - ping_good = plus.get_v1_account_misc_read_val('pingGood', 100) - ping_med = plus.get_v1_account_misc_read_val('pingMed', 500) - - self._clear() - hpos = 20 - vpos = sub_scroll_height - lineheight * index - 50 - self._name_widget = bui.textwidget( - text=bui.Lstr(value=party.name), + """Update for the given data.""" + # pylint: disable=too-many-locals + + # Quick-out: if we've been marked clean for a certain index and + # we're still at that index, we're done. + plus = bui.app.plus + assert plus is not None + + # Quick-out: if we've been marked clean for a certain index and + # we're still at that index, we're done. + if party.clean_display_index == index: + return + + ping_good = plus.get_v1_account_misc_read_val('pingGood', 100) + ping_med = plus.get_v1_account_misc_read_val('pingMed', 500) + + self._clear() + hpos = 20 + vpos = sub_scroll_height - lineheight * index - 50 + self._name_widget = bui.textwidget( + text=bui.Lstr(value=party.name), + parent=columnwidget, + size=(sub_scroll_width * 0.63, 20), + position=(0 + hpos, 4 + vpos), + selectable=True, + on_select_call=bui.WeakCall( + tab.set_public_party_selection, + Selection(party.get_key(), SelectionComponent.NAME), + ), + on_activate_call=bui.WeakCall(tab.on_public_party_activate, party), + click_activate=True, + maxwidth=sub_scroll_width * 0.45, + corner_scale=1.4, + autoselect=True, + color=(1, 1, 1, 0.3 if party.ping is None else 1.0), + h_align='left', + v_align='center', + ) + bui.widget( + edit=self._name_widget, + left_widget=join_text, + show_buffer_top=64.0, + show_buffer_bottom=64.0, + ) + if existing_selection == Selection( + party.get_key(), SelectionComponent.NAME + ): + bui.containerwidget( + edit=columnwidget, selected_child=self._name_widget + ) + if party.stats_addr or True: + url = party.stats_addr.replace( + '${ACCOUNT}', + plus.get_v1_account_misc_read_val_2( + 'resolvedAccountID', 'UNKNOWN' + ), + ) + self._stats_button = bui.buttonwidget( + color=(0.3, 0.6, 0.94), + textcolor=(1.0, 1.0, 1.0), + label='....', parent=columnwidget, - size=(sub_scroll_width * 0.63, 20), - position=(0 + hpos, 4 + vpos), - selectable=True, + autoselect=True, + on_activate_call=bui.Call(bui.open_url, url), on_select_call=bui.WeakCall( tab.set_public_party_selection, - Selection(party.get_key(), SelectionComponent.NAME), + Selection(party.get_key(), SelectionComponent.STATS_BUTTON), ), - on_activate_call=bui.WeakCall(tab.on_public_party_activate, party), - click_activate=True, - maxwidth=sub_scroll_width * 0.45, - corner_scale=1.4, - autoselect=True, - color=(1, 1, 1, 0.3 if party.ping is None else 1.0), - h_align='left', - v_align='center', - ) - bui.widget( - edit=self._name_widget, - left_widget=join_text, - show_buffer_top=64.0, - show_buffer_bottom=64.0, + size=(120, 40), + position=(sub_scroll_width * 0.66 + hpos, 1 + vpos), + scale=0.9, ) + bui.buttonwidget(edit=self._stats_button, on_activate_call=bui.WeakCall( + self.on_stats_click, self._stats_button, party)) if existing_selection == Selection( - party.get_key(), SelectionComponent.NAME + party.get_key(), SelectionComponent.STATS_BUTTON ): bui.containerwidget( - edit=columnwidget, selected_child=self._name_widget + edit=columnwidget, selected_child=self._stats_button ) - if party.stats_addr or True: - url = party.stats_addr.replace( - '${ACCOUNT}', - plus.get_v1_account_misc_read_val_2( - 'resolvedAccountID', 'UNKNOWN' - ), - ) - self._stats_button = bui.buttonwidget( - color=(0.3, 0.6, 0.94), - textcolor=(1.0, 1.0, 1.0), - label='....', - parent=columnwidget, - autoselect=True, - on_activate_call=bui.Call(bui.open_url, url), - on_select_call=bui.WeakCall( - tab.set_public_party_selection, - Selection(party.get_key(), SelectionComponent.STATS_BUTTON), - ), - size=(120, 40), - position=(sub_scroll_width * 0.66 + hpos, 1 + vpos), - scale=0.9, - ) - bui.buttonwidget(edit=self._stats_button, on_activate_call=bui.WeakCall( - self.on_stats_click, self._stats_button, party)) - if existing_selection == Selection( - party.get_key(), SelectionComponent.STATS_BUTTON - ): - bui.containerwidget( - edit=columnwidget, selected_child=self._stats_button - ) - - self._size_widget = bui.textwidget( - text=str(party.size) + '/' + str(party.size_max), - parent=columnwidget, - size=(0, 0), - position=(sub_scroll_width * 0.86 + hpos, 20 + vpos), - scale=0.7, - color=(0.8, 0.8, 0.8), - h_align='right', - v_align='center', - ) - if index == 0: - bui.widget(edit=self._name_widget, up_widget=filter_text) - if self._stats_button: - bui.widget(edit=self._stats_button, up_widget=filter_text) + self._size_widget = bui.textwidget( + text=str(party.size) + '/' + str(party.size_max), + parent=columnwidget, + size=(0, 0), + position=(sub_scroll_width * 0.86 + hpos, 20 + vpos), + scale=0.7, + color=(0.8, 0.8, 0.8), + h_align='right', + v_align='center', + ) - self._ping_widget = bui.textwidget( - parent=columnwidget, - size=(0, 0), - position=(sub_scroll_width * 0.94 + hpos, 20 + vpos), - scale=0.7, - h_align='right', - v_align='center', + if index == 0: + bui.widget(edit=self._name_widget, up_widget=filter_text) + if self._stats_button: + bui.widget(edit=self._stats_button, up_widget=filter_text) + + self._ping_widget = bui.textwidget( + parent=columnwidget, + size=(0, 0), + position=(sub_scroll_width * 0.94 + hpos, 20 + vpos), + scale=0.7, + h_align='right', + v_align='center', + ) + if party.ping is None: + bui.textwidget( + edit=self._ping_widget, text='-', color=(0.5, 0.5, 0.5) ) - if party.ping is None: - bui.textwidget( - edit=self._ping_widget, text='-', color=(0.5, 0.5, 0.5) - ) - else: - bui.textwidget( - edit=self._ping_widget, - text=str(int(party.ping)), - color=(0, 1, 0) - if party.ping <= ping_good - else (1, 1, 0) - if party.ping <= ping_med - else (1, 0, 0), - ) + else: + bui.textwidget( + edit=self._ping_widget, + text=str(int(party.ping)), + color=(0, 1, 0) + if party.ping <= ping_good + else (1, 1, 0) + if party.ping <= ping_med + else (1, 0, 0), + ) + + party.clean_display_index = index - party.clean_display_index = index def _get_popup_window_scale() -> float: uiscale = bui.app.ui_v1.uiscale @@ -501,7 +500,7 @@ def popup_menu_selected_choice(self, window: popup.PopupMenu, url = _party.stats_addr.replace( '${ACCOUNT}', plus.get_v1_account_misc_read_val_2('resolvedAccountID', - 'UNKNOWN')) + 'UNKNOWN')) bui.open_url(url) elif choice == 'connect': PartyQuickConnect(_party.address, _party.port) @@ -614,17 +613,17 @@ def __init__(self, address: str, port: int): scale=(1.4 if uiscale is babase.UIScale.SMALL else 1.2 if uiscale is babase.UIScale.MEDIUM else 1.0))) self._cancel_button = bui.buttonwidget(parent=self._root_widget, - scale=1.0, - position=(60, self._height - 80), - size=(50, 50), - label='', - on_activate_call=self.close, - autoselect=True, - color=(0.45, 0.63, 0.15), - icon=bui.gettexture('crossOut'), - iconscale=1.2) + scale=1.0, + position=(60, self._height - 80), + size=(50, 50), + label='', + on_activate_call=self.close, + autoselect=True, + color=(0.45, 0.63, 0.15), + icon=bui.gettexture('crossOut'), + iconscale=1.2) bui.containerwidget(edit=self._root_widget, - cancel_button=self._cancel_button) + cancel_button=self._cancel_button) self.IP = bui.textwidget( parent=self._root_widget, From 47e6dba135657d1efc6ff34ffdec6e97efd87df7 Mon Sep 17 00:00:00 2001 From: imayushsaini Date: Sun, 2 Jul 2023 12:59:52 +0000 Subject: [PATCH 0526/1464] [ci] apply-version-metadata --- plugins/utilities.json | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/plugins/utilities.json b/plugins/utilities.json index 6ec0de11..2169f4d2 100644 --- a/plugins/utilities.json +++ b/plugins/utilities.json @@ -335,7 +335,12 @@ } ], "versions": { - "2.0.0":null, + "2.0.0": { + "api_version": 8, + "commit_sha": "0c5ce76", + "released_on": "02-07-2023", + "md5sum": "8b05407fda379d853f5c75677b19fd85" + }, "1.2.1": { "api_version": 7, "commit_sha": "64e8a5c", @@ -442,7 +447,12 @@ } ], "versions": { - "2.0.0": null, + "2.0.0": { + "api_version": 8, + "commit_sha": "0c5ce76", + "released_on": "02-07-2023", + "md5sum": "bb5d85fb528020e809eaebb17a388e32" + }, "1.0.0": { "api_version": 7, "commit_sha": "ff4de19", From 06aec553780c38f5f7e2763b7d414af74653b9d3 Mon Sep 17 00:00:00 2001 From: Rikko Date: Sun, 2 Jul 2023 18:58:09 +0530 Subject: [PATCH 0527/1464] Alliance elimination API 8 --- plugins/minigames.json | 3 +- plugins/minigames/alliance_elimination.py | 116 +++++++++++----------- 2 files changed, 61 insertions(+), 58 deletions(-) diff --git a/plugins/minigames.json b/plugins/minigames.json index a95fc4f5..1a571556 100644 --- a/plugins/minigames.json +++ b/plugins/minigames.json @@ -166,6 +166,7 @@ } ], "versions": { + "2.0.0": null, "1.1.0": { "api_version": 7, "commit_sha": "40b70fe", @@ -606,4 +607,4 @@ } } } -} \ No newline at end of file +} diff --git a/plugins/minigames/alliance_elimination.py b/plugins/minigames/alliance_elimination.py index e6f37761..ffee26d0 100644 --- a/plugins/minigames/alliance_elimination.py +++ b/plugins/minigames/alliance_elimination.py @@ -2,23 +2,25 @@ # """Elimination mini-game.""" -# ba_meta require api 7 +# ba_meta require api 8 # (see https://ballistica.net/wiki/meta-tag-system) from __future__ import annotations from typing import TYPE_CHECKING -import ba -from bastd.actor.spazfactory import SpazFactory -from bastd.actor.scoreboard import Scoreboard +import babase +import bauiv1 as bui +import bascenev1 as bs +from bascenev1lib.actor.spazfactory import SpazFactory +from bascenev1lib.actor.scoreboard import Scoreboard if TYPE_CHECKING: from typing import (Any, Tuple, Type, List, Sequence, Optional, Union) -class Icon(ba.Actor): +class Icon(bs.Actor): """Creates in in-game icon on screen.""" def __init__(self, @@ -37,10 +39,10 @@ def __init__(self, self._show_lives = show_lives self._show_death = show_death self._name_scale = name_scale - self._outline_tex = ba.gettexture('characterIconMask') + self._outline_tex = bs.gettexture('characterIconMask') icon = player.get_icon() - self.node = ba.newnode('image', + self.node = bs.newnode('image', delegate=self, attrs={ 'texture': icon['texture'], @@ -53,12 +55,12 @@ def __init__(self, 'absolute_scale': True, 'attach': 'bottomCenter' }) - self._name_text = ba.newnode( + self._name_text = bs.newnode( 'text', owner=self.node, attrs={ - 'text': ba.Lstr(value=player.getname()), - 'color': ba.safecolor(player.team.color), + 'text': babase.Lstr(value=player.getname()), + 'color': babase.safecolor(player.team.color), 'h_align': 'center', 'v_align': 'center', 'vr_depth': 410, @@ -69,7 +71,7 @@ def __init__(self, 'v_attach': 'bottom' }) if self._show_lives: - self._lives_text = ba.newnode('text', + self._lives_text = bs.newnode('text', owner=self.node, attrs={ 'text': 'x0', @@ -125,7 +127,7 @@ def handle_player_died(self) -> None: if not self.node: return if self._show_death: - ba.animate( + bs.animate( self.node, 'opacity', { 0.00: 1.0, 0.05: 0.0, @@ -142,16 +144,16 @@ def handle_player_died(self) -> None: }) lives = self._player.lives if lives == 0: - ba.timer(0.6, self.update_for_lives) + bs.timer(0.6, self.update_for_lives) def handlemessage(self, msg: Any) -> Any: - if isinstance(msg, ba.DieMessage): + if isinstance(msg, bs.DieMessage): self.node.delete() return None return super().handlemessage(msg) -class Player(ba.Player['Team']): +class Player(bs.Player['Team']): """Our player type for this game.""" def __init__(self) -> None: @@ -159,7 +161,7 @@ def __init__(self) -> None: self.icons: List[Icon] = [] -class Team(ba.Team[Player]): +class Team(bs.Team[Player]): """Our team type for this game.""" def __init__(self) -> None: @@ -167,14 +169,14 @@ def __init__(self) -> None: self.spawn_order: List[Player] = [] -# ba_meta export game -class AllianceEliminationGame(ba.TeamGameActivity[Player, Team]): +# ba_meta export bascenev1.GameActivity +class AllianceEliminationGame(bs.TeamGameActivity[Player, Team]): """Game type where last player(s) left alive win.""" name = 'Alliance Elimination' description = 'Fight in groups of duo, trio, or more.\nLast remaining alive wins.' - scoreconfig = ba.ScoreConfig(label='Survived', - scoretype=ba.ScoreType.SECONDS, + scoreconfig = bs.ScoreConfig(label='Survived', + scoretype=bs.ScoreType.SECONDS, none_is_winner=True) # Show messages when players die since it's meaningful here. announce_player_deaths = True @@ -183,23 +185,23 @@ class AllianceEliminationGame(ba.TeamGameActivity[Player, Team]): @classmethod def get_available_settings( - cls, sessiontype: Type[ba.Session]) -> List[ba.Setting]: + cls, sessiontype: Type[bs.Session]) -> List[babase.Setting]: settings = [ - ba.IntSetting( + bs.IntSetting( 'Lives Per Player', default=1, min_value=1, max_value=10, increment=1, ), - ba.IntSetting( + bs.IntSetting( 'Players Per Team In Arena', default=2, min_value=2, max_value=10, increment=1, ), - ba.IntChoiceSetting( + bs.IntChoiceSetting( 'Time Limit', choices=[ ('None', 0), @@ -211,7 +213,7 @@ def get_available_settings( ], default=0, ), - ba.FloatChoiceSetting( + bs.FloatChoiceSetting( 'Respawn Times', choices=[ ('Shorter', 0.25), @@ -222,27 +224,27 @@ def get_available_settings( ], default=1.0, ), - ba.BoolSetting('Epic Mode', default=False), + bs.BoolSetting('Epic Mode', default=False), ] - if issubclass(sessiontype, ba.DualTeamSession): + if issubclass(sessiontype, bs.DualTeamSession): settings.append( - ba.BoolSetting('Balance Total Lives', default=False)) + bs.BoolSetting('Balance Total Lives', default=False)) return settings @classmethod - def supports_session_type(cls, sessiontype: Type[ba.Session]) -> bool: - return issubclass(sessiontype, ba.DualTeamSession) + def supports_session_type(cls, sessiontype: Type[bs.Session]) -> bool: + return issubclass(sessiontype, bs.DualTeamSession) @classmethod - def get_supported_maps(cls, sessiontype: Type[ba.Session]) -> List[str]: - return ba.getmaps('melee') + def get_supported_maps(cls, sessiontype: Type[bs.Session]) -> List[str]: + return bs.app.classic.getmaps('melee') def __init__(self, settings: dict): super().__init__(settings) self._scoreboard = Scoreboard() self._start_time: Optional[float] = None - self._vs_text: Optional[ba.Actor] = None - self._round_end_timer: Optional[ba.Timer] = None + self._vs_text: Optional[bs.Actor] = None + self._round_end_timer: Optional[bs.Timer] = None self._epic_mode = bool(settings['Epic Mode']) self._lives_per_player = int(settings['Lives Per Player']) self._time_limit = float(settings['Time Limit']) @@ -253,16 +255,16 @@ def __init__(self, settings: dict): # Base class overrides: self.slow_motion = self._epic_mode - self.default_music = (ba.MusicType.EPIC - if self._epic_mode else ba.MusicType.SURVIVAL) + self.default_music = (bs.MusicType.EPIC + if self._epic_mode else bs.MusicType.SURVIVAL) def get_instance_description(self) -> Union[str, Sequence]: return 'Last team standing wins.' if isinstance( - self.session, ba.DualTeamSession) else 'Last one standing wins.' + self.session, bs.DualTeamSession) else 'Last one standing wins.' def get_instance_description_short(self) -> Union[str, Sequence]: return 'last team standing wins' if isinstance( - self.session, ba.DualTeamSession) else 'last one standing wins' + self.session, bs.DualTeamSession) else 'last one standing wins' def on_player_join(self, player: Player) -> None: @@ -275,8 +277,8 @@ def on_player_join(self, player: Player) -> None: if (self._get_total_team_lives(player.team) == 0 and player.team.survival_seconds is None): player.team.survival_seconds = 0 - ba.screenmessage( - ba.Lstr(resource='playerDelayedJoinText', + bs.broadcastmessage( + babase.Lstr(resource='playerDelayedJoinText', subs=[('${PLAYER}', player.getname(full=True))]), color=(0, 1, 0), ) @@ -293,11 +295,11 @@ def on_player_join(self, player: Player) -> None: def on_begin(self) -> None: super().on_begin() - self._start_time = ba.time() + self._start_time = bs.time() self.setup_standard_time_limit(self._time_limit) self.setup_standard_powerup_drops() - self._vs_text = ba.NodeActor( - ba.newnode('text', + self._vs_text = bs.NodeActor( + bs.newnode('text', attrs={ 'position': (0, 92), 'h_attach': 'center', @@ -308,12 +310,12 @@ def on_begin(self) -> None: 'scale': 0.6, 'v_attach': 'bottom', 'color': (0.8, 0.8, 0.3, 1.0), - 'text': ba.Lstr(resource='vsText') + 'text': babase.Lstr(resource='vsText') })) # If balance-team-lives is on, add lives to the smaller team until # total lives match. - if (isinstance(self.session, ba.DualTeamSession) + if (isinstance(self.session, bs.DualTeamSession) and self._balance_total_lives and self.teams[0].players and self.teams[1].players): if self._get_total_team_lives( @@ -333,7 +335,7 @@ def on_begin(self) -> None: # We could check game-over conditions at explicit trigger points, # but lets just do the simple thing and poll it. - ba.timer(1.0, self._update, repeat=True) + bs.timer(1.0, self._update, repeat=True) def _update_alliance_mode(self) -> None: # For both teams, find the first player on the spawn order list with @@ -391,10 +393,10 @@ def _update_icons(self) -> None: nplayers -= 1 test_lives += 1 - def _get_spawn_point(self, player: Player) -> Optional[ba.Vec3]: + def _get_spawn_point(self, player: Player) -> Optional[babase.Vec3]: return None - def spawn_player(self, player: Player) -> ba.Actor: + def spawn_player(self, player: Player) -> bs.Actor: actor = self.spawn_player_spaz(player, self._get_spawn_point(player)) # If we have any icons, update their state. @@ -403,7 +405,7 @@ def spawn_player(self, player: Player) -> ba.Actor: return actor def _print_lives(self, player: Player) -> None: - from bastd.actor import popuptext + from bascenev1lib.actor import popuptext # We get called in a timer so it's possible our player has left/etc. if not player or not player.is_alive() or not player.node: @@ -426,20 +428,20 @@ def on_player_leave(self, player: Player) -> None: # Update icons in a moment since our team will be gone from the # list then. - ba.timer(0, self._update_icons) + bs.timer(0, self._update_icons) # If the player to leave was the last in spawn order and had # their final turn currently in-progress, mark the survival time # for their team. if self._get_total_team_lives(player.team) == 0: assert self._start_time is not None - player.team.survival_seconds = int(ba.time() - self._start_time) + player.team.survival_seconds = int(bs.time() - self._start_time) def _get_total_team_lives(self, team: Team) -> int: return sum(player.lives for player in team.players) def handlemessage(self, msg: Any) -> Any: - if isinstance(msg, ba.PlayerDiedMessage): + if isinstance(msg, bs.PlayerDiedMessage): # Augment standard behavior. super().handlemessage(msg) @@ -447,7 +449,7 @@ def handlemessage(self, msg: Any) -> Any: player.lives -= 1 if player.lives < 0: - ba.print_error( + babase.print_error( "Got lives < 0 in Alliance Elimination; this shouldn't happen.") player.lives = 0 @@ -458,14 +460,14 @@ def handlemessage(self, msg: Any) -> Any: # Play big death sound on our last death # or for every one. if player.lives == 0: - ba.playsound(SpazFactory.get().single_player_death_sound) + SpazFactory.get().single_player_death_sound.play() # If we hit zero lives, we're dead (and our team might be too). if player.lives == 0: # If the whole team is now dead, mark their survival time. if self._get_total_team_lives(player.team) == 0: assert self._start_time is not None - player.team.survival_seconds = int(ba.time() - + player.team.survival_seconds = int(bs.time() - self._start_time) # Put ourself at the back of the spawn order. @@ -493,7 +495,7 @@ def _update(self) -> None: # the game (allows the dust to settle and draws to occur if deaths # are close enough). if len(self._get_living_teams()) < 2: - self._round_end_timer = ba.Timer(0.5, self.end_game) + self._round_end_timer = bs.Timer(0.5, self.end_game) def _get_living_teams(self) -> List[Team]: return [ @@ -505,7 +507,7 @@ def _get_living_teams(self) -> List[Team]: def end_game(self) -> None: if self.has_ended(): return - results = ba.GameResults() + results = bs.GameResults() self._vs_text = None # Kill our 'vs' if its there. for team in self.teams: results.set_team_score(team, team.survival_seconds) From 1b14789b4b8712214f487a7afc0b07e491094f3c Mon Sep 17 00:00:00 2001 From: rikkolovescats Date: Sun, 2 Jul 2023 13:30:09 +0000 Subject: [PATCH 0528/1464] [ci] auto-format --- plugins/minigames/alliance_elimination.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/minigames/alliance_elimination.py b/plugins/minigames/alliance_elimination.py index ffee26d0..f6d47b5f 100644 --- a/plugins/minigames/alliance_elimination.py +++ b/plugins/minigames/alliance_elimination.py @@ -279,7 +279,7 @@ def on_player_join(self, player: Player) -> None: player.team.survival_seconds = 0 bs.broadcastmessage( babase.Lstr(resource='playerDelayedJoinText', - subs=[('${PLAYER}', player.getname(full=True))]), + subs=[('${PLAYER}', player.getname(full=True))]), color=(0, 1, 0), ) return From ecf72c85bab6d73be90dc76ca61e2f9785b4b977 Mon Sep 17 00:00:00 2001 From: rikkolovescats Date: Sun, 2 Jul 2023 13:30:11 +0000 Subject: [PATCH 0529/1464] [ci] apply-version-metadata --- plugins/minigames.json | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/plugins/minigames.json b/plugins/minigames.json index 1a571556..ae4f5406 100644 --- a/plugins/minigames.json +++ b/plugins/minigames.json @@ -166,7 +166,12 @@ } ], "versions": { - "2.0.0": null, + "2.0.0": { + "api_version": 8, + "commit_sha": "1b14789", + "released_on": "02-07-2023", + "md5sum": "cb2a7700dd13febe6f68c3cd979b8b19" + }, "1.1.0": { "api_version": 7, "commit_sha": "40b70fe", @@ -607,4 +612,4 @@ } } } -} +} \ No newline at end of file From 1550aeb6590022e24e1135fab891558a3bda8cf6 Mon Sep 17 00:00:00 2001 From: rikkolovescats Date: Sun, 2 Jul 2023 19:50:14 +0530 Subject: [PATCH 0530/1464] Installing plugin manager using adb --- README.md | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index fe057a9e..0c621a49 100644 --- a/README.md +++ b/README.md @@ -40,8 +40,14 @@ There are two different ways the plugin manager can be installed: 1. [Download plugin_manager.py][DownloadLink] to your mods directory (check it out by going into your game's Settings -> Advanced -> Show Mods Folder). This is the recommended way (read next method to know why). - -2. Another way is to add + If you're on a newer version of Android (11 or above) and not rooted, it probably won't be possible to copy + mods to game's mods folder. In this case, you can connect your Android phone to a computer and push `plugin_manager.py` + [using `adb`](https://www.xda-developers.com/install-adb-windows-macos-linux/): + ```bash + $ adb push plugin_manager.py /sdcard/Android/data/net.froemling.bombsquad/files/mods/plugin_manager.py + ``` + +3. Another way is to add [plugin_manager.py](https://raw.githubusercontent.com/bombsquad-community/plugin-manager/main/plugin_manager.py) to your workspace. However, plugin manager self-updates will fail when installed using this way since the game will overrwrite the updated plugin manager, with the older version from workspace on the next sync. However, you can From 3b6441bd6382168a02e9f2599857d674c4dc2564 Mon Sep 17 00:00:00 2001 From: rikkolovescats Date: Sun, 2 Jul 2023 21:12:14 +0530 Subject: [PATCH 0531/1464] Add Aeliux/arcane as an external source --- README.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 0c621a49..d625cccd 100644 --- a/README.md +++ b/README.md @@ -199,7 +199,8 @@ That's it! Now you can make a [pull request](../../compare) with both the update will also help us to notify the maintainers of any future breaking changes in plugin manager that could affect 3rd party plugin sources. - [rikkolovescats/sahilp-plugins](https://github.com/rikkolovescats/sahilp-plugins) + - [rikkolovescats/sahilp-plugins](https://github.com/rikkolovescats/sahilp-plugins) + - [Aeliux/arcane](https://github.com/Aeliux/arcane) ## Tests From ceb8f5f00b9b59f84c623b89b1691272b50f6758 Mon Sep 17 00:00:00 2001 From: A Dhextras <104954857+DhextraS@users.noreply.github.com> Date: Tue, 4 Jul 2023 11:56:43 +0530 Subject: [PATCH 0532/1464] Update utilities.json --- plugins/utilities.json | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/plugins/utilities.json b/plugins/utilities.json index 2169f4d2..f71b99ff 100644 --- a/plugins/utilities.json +++ b/plugins/utilities.json @@ -422,6 +422,7 @@ } ], "versions": { + "2.0.0":null, "1.0.1": { "api_version": 7, "commit_sha": "64e8a5c", @@ -739,4 +740,4 @@ } } } -} \ No newline at end of file +} From 768280103f24fb7abad11e36d8e2e3bf1da41a34 Mon Sep 17 00:00:00 2001 From: A Dhextras <104954857+DhextraS@users.noreply.github.com> Date: Tue, 4 Jul 2023 11:57:58 +0530 Subject: [PATCH 0533/1464] Update server_switch.py --- plugins/utilities/server_switch.py | 225 +++++++++++++++-------------- 1 file changed, 114 insertions(+), 111 deletions(-) diff --git a/plugins/utilities/server_switch.py b/plugins/utilities/server_switch.py index ecd3c398..3c246c76 100644 --- a/plugins/utilities/server_switch.py +++ b/plugins/utilities/server_switch.py @@ -1,33 +1,34 @@ +# discord @mr.smoothy#5824 -# ba_meta require api 7 +# ba_meta require api 8 from __future__ import annotations import copy import time from typing import TYPE_CHECKING -import _ba -import ba +import babase +import bauiv1 as bui +import bascenev1 as bs +import _bascenev1 as _bs import time import threading from enum import Enum from dataclasses import dataclass if TYPE_CHECKING: from typing import Any, Optional, Dict, List, Tuple, Type - import ba - from bastd.ui.gather import GatherWindow + import bascenev1 as bs + from bauiv1lib.gather import GatherWindow -from bastd.ui.confirm import ConfirmWindow -# discord @mr.smoothy#5824 +from bauiv1lib.confirm import ConfirmWindow -import bastd.ui.mainmenu as bastd_ui_mainmenu +import bauiv1lib.mainmenu as bastd_ui_mainmenu -connect = ba.internal.connect_to_party -disconnect = ba.internal.disconnect_from_host +connect = bs.connect_to_party +disconnect = bs.disconnect_from_host server = [] - ip_add = "private" p_port = 44444 p_name = "nothing here" @@ -36,9 +37,9 @@ def newconnect_to_party(address, port=43210, print_progress=False): global ip_add global p_port - dd = _ba.get_connection_to_host_info() + dd = _bs.get_connection_to_host_info() if (dd != {}): - _ba.disconnect_from_host() + _bs.disconnect_from_host() ip_add = address p_port = port @@ -53,7 +54,7 @@ def newconnect_to_party(address, port=43210, print_progress=False): def newdisconnect_from_host(): try: - name = _ba.get_connection_to_host_info()['name'] + name = _bs.get_connection_to_host_info()['name'] global server global ip_add global p_port @@ -67,7 +68,7 @@ def newdisconnect_from_host(): def printip(): - ba.screenmessage("ip address is"+ip_add) + bs.screenmessage("ip address is"+ip_add) def new_refresh_in_game( @@ -77,19 +78,19 @@ def new_refresh_in_game( # pylint: disable=too-many-locals # pylint: disable=too-many-statements custom_menu_entries: List[Dict[str, Any]] = [] - session = _ba.get_foreground_host_session() + session = _bs.get_foreground_host_session() if session is not None: try: custom_menu_entries = session.get_custom_menu_entries() for cme in custom_menu_entries: if (not isinstance(cme, dict) or 'label' not in cme - or not isinstance(cme['label'], (str, ba.Lstr)) + or not isinstance(cme['label'], (str, bs.Lstr)) or 'call' not in cme or not callable(cme['call'])): raise ValueError('invalid custom menu entry: ' + str(cme)) except Exception: custom_menu_entries = [] - ba.print_exception( + babase.print_exception( f'Error getting custom menu entries for {session}') self._width = 250.0 self._height = 250.0 if self._input_player else 180.0 @@ -101,12 +102,12 @@ def new_refresh_in_game( # In this case we have a leave *and* a disconnect button. self._height += 50 self._height += 50 * (len(custom_menu_entries)) - uiscale = ba.app.ui.uiscale - ba.containerwidget( + uiscale = bui.app.ui_v1.uiscale + bui.containerwidget( edit=self._root_widget, size=(self._width*2, self._height), - scale=(2.15 if uiscale is ba.UIScale.SMALL else - 1.6 if uiscale is ba.UIScale.MEDIUM else 1.0)) + scale=(2.15 if uiscale is bui.UIScale.SMALL else + 1.6 if uiscale is bui.UIScale.MEDIUM else 1.0)) h = 125.0 v = (self._height - 80.0 if self._input_player else self._height - 60) h_offset = 0 @@ -118,9 +119,9 @@ def new_refresh_in_game( h += h_offset h_offset += d_h_offset self._start_button = None - ba.app.pause() + bui.app.pause() h, v, scale = positions[self._p_index] - ba.textwidget( + bui.textwidget( parent=self._root_widget, draw_controller=None, text="IP: "+ip_add+" PORT: "+str(p_port), @@ -139,10 +140,10 @@ def con(address, port): if (address == ip_add and port == p_port): self._resume() else: - _ba.disconnect_from_host() - _ba.connect_to_party(address, port) + _bs.disconnect_from_host() + _bs.connect_to_party(address, port) if len(server) == 0: - ba.textwidget( + bui.textwidget( parent=self._root_widget, draw_controller=None, text="Nothing in \n recents", @@ -152,7 +153,7 @@ def con(address, port): size=(20, 60), scale=1) for ser in server: - self._server_button = ba.buttonwidget( + self._server_button = bui.buttonwidget( color=(0.8, 0, 1), parent=self._root_widget, position=(h + self._button_width * scale - 80, v_h), @@ -161,7 +162,7 @@ def con(address, port): autoselect=self._use_autoselect, label=ser["name"][0:22], - on_activate_call=ba.Call(con, ser["ip"], ser["port"])) + on_activate_call=bs.Call(con, ser["ip"], ser["port"])) v_h = v_h-50 # Player name if applicable. @@ -169,25 +170,25 @@ def con(address, port): player_name = self._input_player.getname() h, v, scale = positions[self._p_index] v += 35 - ba.textwidget(parent=self._root_widget, + bui.textwidget(parent=self._root_widget, position=(h - self._button_width / 2, v), size=(self._button_width, self._button_height), color=(1, 1, 1, 0.5), scale=0.7, h_align='center', - text=ba.Lstr(value=player_name)) + text=bs.Lstr(value=player_name)) else: player_name = '' h, v, scale = positions[self._p_index] self._p_index += 1 - btn = ba.buttonwidget(parent=self._root_widget, + btn = bui.buttonwidget(parent=self._root_widget, position=(h - self._button_width / 2, v), size=(self._button_width, self._button_height), scale=scale, - label=ba.Lstr(resource=self._r + '.resumeText'), + label=bs.Lstr(resource=self._r + '.resumeText'), autoselect=self._use_autoselect, on_activate_call=self._resume) - ba.containerwidget(edit=self._root_widget, cancel_button=btn) + bui.containerwidget(edit=self._root_widget, cancel_button=btn) # Add any custom options defined by the current game. for entry in custom_menu_entries: @@ -199,11 +200,11 @@ def con(address, port): resume = bool(entry.get('resume_on_call', True)) if resume: - call = ba.Call(self._resume_and_call, entry['call']) + call = bs.Call(self._resume_and_call, entry['call']) else: - call = ba.Call(entry['call'], ba.WeakCall(self._resume)) + call = bs.Call(entry['call'], bs.WeakCall(self._resume)) - ba.buttonwidget(parent=self._root_widget, + bui.buttonwidget(parent=self._root_widget, position=(h - self._button_width / 2, v), size=(self._button_width, self._button_height), scale=scale, @@ -215,7 +216,7 @@ def con(address, port): and not (self._is_demo or self._is_arcade)): h, v, scale = positions[self._p_index] self._p_index += 1 - btn = ba.buttonwidget(parent=self._root_widget, + btn = bui.buttonwidget(parent=self._root_widget, position=(h - self._button_width / 2, v), size=(self._button_width, self._button_height), @@ -226,22 +227,22 @@ def con(address, port): if (player_name != '' and player_name[0] != '<' and player_name[-1] != '>'): - txt = ba.Lstr(resource=self._r + '.justPlayerText', + txt = bs.Lstr(resource=self._r + '.justPlayerText', subs=[('${NAME}', player_name)]) else: - txt = ba.Lstr(value=player_name) - ba.textwidget(parent=self._root_widget, + txt = bs.Lstr(value=player_name) + bui.textwidget(parent=self._root_widget, position=(h, v + self._button_height * (0.64 if player_name != '' else 0.5)), size=(0, 0), - text=ba.Lstr(resource=self._r + '.leaveGameText'), + text=bs.Lstr(resource=self._r + '.leaveGameText'), scale=(0.83 if player_name != '' else 1.0), color=(0.75, 1.0, 0.7), h_align='center', v_align='center', draw_controller=btn, maxwidth=self._button_width * 0.9) - ba.textwidget(parent=self._root_widget, + bui.textwidget(parent=self._root_widget, position=(h, v + self._button_height * 0.27), size=(0, 0), text=txt, @@ -260,9 +261,12 @@ def new_refresh(self) -> None: # pylint: disable=too-many-statements global server print(server) - from bastd.ui.confirm import QuitWindow - from bastd.ui.store.button import StoreButton - import ba + from bauiv1lib.confirm import QuitWindow + from bauiv1lib.store.button import StoreButton + import bascenev1 as bs + import _bascenev1 as _bs + import bauiv1 as bui + import _baplus # Clear everything that was there. children = self._root_widget.get_children() for child in children: @@ -276,21 +280,22 @@ def new_refresh(self) -> None: self._r = 'mainMenu' - app = ba.app - self._have_quit_button = (app.ui.uiscale is ba.UIScale.LARGE + assert bs.app.classic is not None + app = bs.app.classic + self._have_quit_button = (bui.app.ui_v1.uiscale is bui.UIScale.LARGE or (app.platform == 'windows' and app.subplatform == 'oculus')) self._have_store_button = not self._in_game self._have_settings_button = ( - (not self._in_game or not app.toolbar_test) + (not self._in_game or not bui.app.toolbar_test) and not (self._is_demo or self._is_arcade or self._is_iircade)) - self._input_device = input_device = _ba.get_ui_input_device() + self._input_device = input_device = _bs.get_ui_input_device() self._input_player = input_device.player if input_device else None self._connected_to_remote_player = ( - input_device.is_connected_to_remote_player() + input_device.is_attached_to_player() if input_device else False) positions: List[Tuple[float, float, float]] = [] @@ -299,14 +304,14 @@ def new_refresh(self) -> None: if self._in_game: h, v, scale = self._refresh_in_game(positions) print("refreshing in GAME", ip_add) - # btn = ba.buttonwidget(parent=self._root_widget, + # btn = bui.buttonwidget(parent=self._root_widget, # position=(80,270), # size=(100, 90), # scale=1.2, # label=ip_add, # autoselect=None, # on_activate_call=printip) - ba.textwidget( + bui.textwidget( parent=self._root_widget, draw_controller=None, text="IP: "+ip_add+" PORT: "+str(p_port), @@ -315,31 +320,31 @@ def new_refresh(self) -> None: v_align='center', size=(20, 60), scale=1) - self._server_button = ba.buttonwidget( + self._server_button = bui.buttonwidget( parent=self._root_widget, position=(h * 3.2 + 20 - self._button_width * scale, v), size=(self._button_width, self._button_height), scale=scale, autoselect=self._use_autoselect, - label=ba.Lstr(resource=self._r + '.settingsText'), + label=bs.Lstr(resource=self._r + '.settingsText'), transition_delay=self._tdelay, on_activate_call=self._settings) - self._server_button2 = ba.buttonwidget( + self._server_button2 = bui.buttonwidget( parent=self._root_widget, position=(h * 3.2 + 20 - self._button_width * scale, v-50), size=(self._button_width, self._button_height), scale=scale, autoselect=self._use_autoselect, - label=ba.Lstr(resource=self._r + '.settingsText'), + label=bs.Lstr(resource=self._r + '.settingsText'), transition_delay=self._tdelay, on_activate_call=self._settings) - self._server_button3 = ba.buttonwidget( + self._server_button3 = bui.buttonwidget( parent=self._root_widget, position=(h * 3.2 + 20 - self._button_width * scale, v-100), size=(self._button_width, self._button_height), scale=scale, autoselect=self._use_autoselect, - label=ba.Lstr(resource=self._r + '.settingsText'), + label=bs.Lstr(resource=self._r + '.settingsText'), transition_delay=self._tdelay, on_activate_call=self._settings) @@ -349,27 +354,27 @@ def new_refresh(self) -> None: if self._have_settings_button: h, v, scale = positions[self._p_index] self._p_index += 1 - self._settings_button = ba.buttonwidget( + self._settings_button = bui.buttonwidget( parent=self._root_widget, position=(h - self._button_width * 0.5 * scale, v), size=(self._button_width, self._button_height), scale=scale, autoselect=self._use_autoselect, - label=ba.Lstr(resource=self._r + '.settingsText'), + label=bs.Lstr(resource=self._r + '.settingsText'), transition_delay=self._tdelay, on_activate_call=self._settings) # Scattered eggs on easter. - if _ba.get_account_misc_read_val('easter', + if _baplus.get_v1_account_misc_read_val('easter', False) and not self._in_game: icon_size = 34 - ba.imagewidget(parent=self._root_widget, + bui.imagewidget(parent=self._root_widget, position=(h - icon_size * 0.5 - 15, v + self._button_height * scale - icon_size * 0.24 + 1.5), transition_delay=self._tdelay, size=(icon_size, icon_size), - texture=ba.gettexture('egg3'), + texture=bui.gettexture('egg3'), tilt_scale=0.0) self._tdelay += self._t_delay_inc @@ -379,36 +384,36 @@ def new_refresh(self) -> None: self._p_index += 1 # If we're in a replay, we have a 'Leave Replay' button. - if _ba.is_in_replay(): - ba.buttonwidget(parent=self._root_widget, + if _bs.is_in_replay(): + bui.buttonwidget(parent=self._root_widget, position=(h - self._button_width * 0.5 * scale, v), scale=scale, size=(self._button_width, self._button_height), autoselect=self._use_autoselect, - label=ba.Lstr(resource='replayEndText'), + label=bs.Lstr(resource='replayEndText'), on_activate_call=self._confirm_end_replay) - elif _ba.get_foreground_host_session() is not None: - ba.buttonwidget( + elif _bs.get_foreground_host_session() is not None: + bui.buttonwidget( parent=self._root_widget, position=(h - self._button_width * 0.5 * scale, v), scale=scale, size=(self._button_width, self._button_height), autoselect=self._use_autoselect, - label=ba.Lstr(resource=self._r + '.endGameText'), + label=bs.Lstr(resource=self._r + '.endGameText'), on_activate_call=self._confirm_end_game) # Assume we're in a client-session. else: - ba.buttonwidget( + bui.buttonwidget( parent=self._root_widget, position=(h - self._button_width * 0.5 * scale, v), scale=scale, size=(self._button_width, self._button_height), autoselect=self._use_autoselect, - label=ba.Lstr(resource=self._r + '.leavePartyText'), + label=bs.Lstr(resource=self._r + '.leavePartyText'), on_activate_call=self._confirm_leave_party) - self._store_button: Optional[ba.Widget] + self._store_button: Optional[bui.Widget] if self._have_store_button: this_b_width = self._button_width h, v, scale = positions[self._p_index] @@ -419,20 +424,20 @@ def new_refresh(self) -> None: position=(h - this_b_width * 0.5 * scale, v), size=(this_b_width, self._button_height), scale=scale, - on_activate_call=ba.WeakCall(self._on_store_pressed), + on_activate_call=bs.WeakCall(self._on_store_pressed), sale_scale=1.3, transition_delay=self._tdelay) self._store_button = store_button = sbtn.get_button() - uiscale = ba.app.ui.uiscale - icon_size = (55 if uiscale is ba.UIScale.SMALL else - 55 if uiscale is ba.UIScale.MEDIUM else 70) - ba.imagewidget( + uiscale = bui.app.ui_v1.uiscale + icon_size = (55 if uiscale is bui.UIScale.SMALL else + 55 if uiscale is bui.UIScale.MEDIUM else 70) + bui.imagewidget( parent=self._root_widget, position=(h - icon_size * 0.5, v + self._button_height * scale - icon_size * 0.23), transition_delay=self._tdelay, size=(icon_size, icon_size), - texture=ba.gettexture(self._store_char_tex), + texture=bui.gettexture(self._store_char_tex), tilt_scale=0.0, draw_controller=store_button) @@ -440,35 +445,35 @@ def new_refresh(self) -> None: else: self._store_button = None - self._quit_button: Optional[ba.Widget] + self._quit_button: Optional[bui.Widget] if not self._in_game and self._have_quit_button: h, v, scale = positions[self._p_index] self._p_index += 1 - self._quit_button = quit_button = ba.buttonwidget( + self._quit_button = quit_button = bui.buttonwidget( parent=self._root_widget, autoselect=self._use_autoselect, position=(h - self._button_width * 0.5 * scale, v), size=(self._button_width, self._button_height), scale=scale, - label=ba.Lstr(resource=self._r + + label=bs.Lstr(resource=self._r + ('.quitText' if 'Mac' in - ba.app.user_agent_string else '.exitGameText')), + bs.app.classic.legacy_user_agent_string else '.exitGameText')), on_activate_call=self._quit, transition_delay=self._tdelay) # Scattered eggs on easter. - if _ba.get_account_misc_read_val('easter', False): + if _baplus.get_v1_account_misc_read_val('easter', False): icon_size = 30 - ba.imagewidget(parent=self._root_widget, + bui.imagewidget(parent=self._root_widget, position=(h - icon_size * 0.5 + 25, v + self._button_height * scale - icon_size * 0.24 + 1.5), transition_delay=self._tdelay, size=(icon_size, icon_size), - texture=ba.gettexture('egg1'), + texture=bui.gettexture('egg1'), tilt_scale=0.0) - ba.containerwidget(edit=self._root_widget, + bui.containerwidget(edit=self._root_widget, cancel_button=quit_button) self._tdelay += self._t_delay_inc else: @@ -477,34 +482,34 @@ def new_refresh(self) -> None: # If we're not in-game, have no quit button, and this is android, # we want back presses to quit our activity. if (not self._in_game and not self._have_quit_button - and ba.app.platform == 'android'): + and bs.app.classic.platform == 'android'): def _do_quit() -> None: QuitWindow(swish=True, back=True) - ba.containerwidget(edit=self._root_widget, + bui.containerwidget(edit=self._root_widget, on_cancel_call=_do_quit) # Add speed-up/slow-down buttons for replays. # (ideally this should be part of a fading-out playback bar like most # media players but this works for now). - if _ba.is_in_replay(): + if _bs.is_in_replay(): b_size = 50.0 b_buffer = 10.0 t_scale = 0.75 - uiscale = ba.app.ui.uiscale - if uiscale is ba.UIScale.SMALL: + uiscale = bui.app.ui_v1.uiscale + if uiscale is bui.UIScale.SMALL: b_size *= 0.6 b_buffer *= 1.0 v_offs = -40 t_scale = 0.5 - elif uiscale is ba.UIScale.MEDIUM: + elif uiscale is bui.UIScale.MEDIUM: v_offs = -70 else: v_offs = -100 - self._replay_speed_text = ba.textwidget( + self._replay_speed_text = bui.textwidget( parent=self._root_widget, - text=ba.Lstr(resource='watchWindow.playbackSpeedText', + text=bs.Lstr(resource='watchWindow.playbackSpeedText', subs=[('${SPEED}', str(1.23))]), position=(h, v + v_offs + 7 * t_scale), h_align='center', @@ -516,21 +521,20 @@ def _do_quit() -> None: self._change_replay_speed(0) # Keep updating in a timer in case it gets changed elsewhere. - self._change_replay_speed_timer = ba.Timer( + self._change_replay_speed_timer = bs.Timer( 0.25, - ba.WeakCall(self._change_replay_speed, 0), - timetype=ba.TimeType.REAL, + bs.WeakCall(self._change_replay_speed, 0), repeat=True) - btn = ba.buttonwidget(parent=self._root_widget, + btn = bui.buttonwidget(parent=self._root_widget, position=(h - b_size - b_buffer, v - b_size - b_buffer + v_offs), button_type='square', size=(b_size, b_size), label='', autoselect=True, - on_activate_call=ba.Call( + on_activate_call=bs.Call( self._change_replay_speed, -1)) - ba.textwidget( + bui.textwidget( parent=self._root_widget, draw_controller=btn, text='-', @@ -540,15 +544,15 @@ def _do_quit() -> None: v_align='center', size=(0, 0), scale=3.0 * t_scale) - btn = ba.buttonwidget( + btn = bui.buttonwidget( parent=self._root_widget, position=(h + b_buffer, v - b_size - b_buffer + v_offs), button_type='square', size=(b_size, b_size), label='', autoselect=True, - on_activate_call=ba.Call(self._change_replay_speed, 1)) - ba.textwidget( + on_activate_call=bs.Call(self._change_replay_speed, 1)) + bui.textwidget( parent=self._root_widget, draw_controller=btn, text='+', @@ -559,14 +563,13 @@ def _do_quit() -> None: size=(0, 0), scale=3.0 * t_scale) -# ba_meta export plugin - -class bySmoothy(ba.Plugin): +# ba_meta export plugin +class bySmoothy(babase.Plugin): def __init__(self): - if _ba.env().get("build_number", 0) >= 20577: + if babase.env().get("build_number", 0) >= 21140: bastd_ui_mainmenu.MainMenuWindow._refresh_in_game = new_refresh_in_game - ba.internal.connect_to_party = newconnect_to_party - ba.internal.disconnect_from_host = newdisconnect_from_host + bs.connect_to_party = newconnect_to_party + bs.disconnect_from_host = newdisconnect_from_host else: - print("Server Switch only works on bs 1.7 and above") + print("Server Switch only works on bs 1.7.20 and above") From bf3e61bc9c1fa993a8c959d94bb082df02ec83e1 Mon Sep 17 00:00:00 2001 From: DhextraS Date: Tue, 4 Jul 2023 06:29:56 +0000 Subject: [PATCH 0534/1464] [ci] auto-format --- plugins/utilities/server_switch.py | 152 ++++++++++++++--------------- 1 file changed, 76 insertions(+), 76 deletions(-) diff --git a/plugins/utilities/server_switch.py b/plugins/utilities/server_switch.py index 3c246c76..aacb0fe7 100644 --- a/plugins/utilities/server_switch.py +++ b/plugins/utilities/server_switch.py @@ -171,23 +171,23 @@ def con(address, port): h, v, scale = positions[self._p_index] v += 35 bui.textwidget(parent=self._root_widget, - position=(h - self._button_width / 2, v), - size=(self._button_width, self._button_height), - color=(1, 1, 1, 0.5), - scale=0.7, - h_align='center', - text=bs.Lstr(value=player_name)) + position=(h - self._button_width / 2, v), + size=(self._button_width, self._button_height), + color=(1, 1, 1, 0.5), + scale=0.7, + h_align='center', + text=bs.Lstr(value=player_name)) else: player_name = '' h, v, scale = positions[self._p_index] self._p_index += 1 btn = bui.buttonwidget(parent=self._root_widget, - position=(h - self._button_width / 2, v), - size=(self._button_width, self._button_height), - scale=scale, - label=bs.Lstr(resource=self._r + '.resumeText'), - autoselect=self._use_autoselect, - on_activate_call=self._resume) + position=(h - self._button_width / 2, v), + size=(self._button_width, self._button_height), + scale=scale, + label=bs.Lstr(resource=self._r + '.resumeText'), + autoselect=self._use_autoselect, + on_activate_call=self._resume) bui.containerwidget(edit=self._root_widget, cancel_button=btn) # Add any custom options defined by the current game. @@ -205,25 +205,25 @@ def con(address, port): call = bs.Call(entry['call'], bs.WeakCall(self._resume)) bui.buttonwidget(parent=self._root_widget, - position=(h - self._button_width / 2, v), - size=(self._button_width, self._button_height), - scale=scale, - on_activate_call=call, - label=entry['label'], - autoselect=self._use_autoselect) + position=(h - self._button_width / 2, v), + size=(self._button_width, self._button_height), + scale=scale, + on_activate_call=call, + label=entry['label'], + autoselect=self._use_autoselect) # Add a 'leave' button if the menu-owner has a player. if ((self._input_player or self._connected_to_remote_player) and not (self._is_demo or self._is_arcade)): h, v, scale = positions[self._p_index] self._p_index += 1 btn = bui.buttonwidget(parent=self._root_widget, - position=(h - self._button_width / 2, v), - size=(self._button_width, - self._button_height), - scale=scale, - on_activate_call=self._leave, - label='', - autoselect=self._use_autoselect) + position=(h - self._button_width / 2, v), + size=(self._button_width, + self._button_height), + scale=scale, + on_activate_call=self._leave, + label='', + autoselect=self._use_autoselect) if (player_name != '' and player_name[0] != '<' and player_name[-1] != '>'): @@ -232,26 +232,26 @@ def con(address, port): else: txt = bs.Lstr(value=player_name) bui.textwidget(parent=self._root_widget, - position=(h, v + self._button_height * - (0.64 if player_name != '' else 0.5)), - size=(0, 0), - text=bs.Lstr(resource=self._r + '.leaveGameText'), - scale=(0.83 if player_name != '' else 1.0), - color=(0.75, 1.0, 0.7), - h_align='center', - v_align='center', - draw_controller=btn, - maxwidth=self._button_width * 0.9) + position=(h, v + self._button_height * + (0.64 if player_name != '' else 0.5)), + size=(0, 0), + text=bs.Lstr(resource=self._r + '.leaveGameText'), + scale=(0.83 if player_name != '' else 1.0), + color=(0.75, 1.0, 0.7), + h_align='center', + v_align='center', + draw_controller=btn, + maxwidth=self._button_width * 0.9) bui.textwidget(parent=self._root_widget, - position=(h, v + self._button_height * 0.27), - size=(0, 0), - text=txt, - color=(0.75, 1.0, 0.7), - h_align='center', - v_align='center', - draw_controller=btn, - scale=0.45, - maxwidth=self._button_width * 0.9) + position=(h, v + self._button_height * 0.27), + size=(0, 0), + text=txt, + color=(0.75, 1.0, 0.7), + h_align='center', + v_align='center', + draw_controller=btn, + scale=0.45, + maxwidth=self._button_width * 0.9) return h, v, scale @@ -366,16 +366,16 @@ def new_refresh(self) -> None: # Scattered eggs on easter. if _baplus.get_v1_account_misc_read_val('easter', - False) and not self._in_game: + False) and not self._in_game: icon_size = 34 bui.imagewidget(parent=self._root_widget, - position=(h - icon_size * 0.5 - 15, - v + self._button_height * scale - - icon_size * 0.24 + 1.5), - transition_delay=self._tdelay, - size=(icon_size, icon_size), - texture=bui.gettexture('egg3'), - tilt_scale=0.0) + position=(h - icon_size * 0.5 - 15, + v + self._button_height * scale - + icon_size * 0.24 + 1.5), + transition_delay=self._tdelay, + size=(icon_size, icon_size), + texture=bui.gettexture('egg3'), + tilt_scale=0.0) self._tdelay += self._t_delay_inc @@ -386,13 +386,13 @@ def new_refresh(self) -> None: # If we're in a replay, we have a 'Leave Replay' button. if _bs.is_in_replay(): bui.buttonwidget(parent=self._root_widget, - position=(h - self._button_width * 0.5 * scale, - v), - scale=scale, - size=(self._button_width, self._button_height), - autoselect=self._use_autoselect, - label=bs.Lstr(resource='replayEndText'), - on_activate_call=self._confirm_end_replay) + position=(h - self._button_width * 0.5 * scale, + v), + scale=scale, + size=(self._button_width, self._button_height), + autoselect=self._use_autoselect, + label=bs.Lstr(resource='replayEndText'), + on_activate_call=self._confirm_end_replay) elif _bs.get_foreground_host_session() is not None: bui.buttonwidget( parent=self._root_widget, @@ -465,16 +465,16 @@ def new_refresh(self) -> None: if _baplus.get_v1_account_misc_read_val('easter', False): icon_size = 30 bui.imagewidget(parent=self._root_widget, - position=(h - icon_size * 0.5 + 25, - v + self._button_height * scale - - icon_size * 0.24 + 1.5), - transition_delay=self._tdelay, - size=(icon_size, icon_size), - texture=bui.gettexture('egg1'), - tilt_scale=0.0) + position=(h - icon_size * 0.5 + 25, + v + self._button_height * scale - + icon_size * 0.24 + 1.5), + transition_delay=self._tdelay, + size=(icon_size, icon_size), + texture=bui.gettexture('egg1'), + tilt_scale=0.0) bui.containerwidget(edit=self._root_widget, - cancel_button=quit_button) + cancel_button=quit_button) self._tdelay += self._t_delay_inc else: self._quit_button = None @@ -488,7 +488,7 @@ def _do_quit() -> None: QuitWindow(swish=True, back=True) bui.containerwidget(edit=self._root_widget, - on_cancel_call=_do_quit) + on_cancel_call=_do_quit) # Add speed-up/slow-down buttons for replays. # (ideally this should be part of a fading-out playback bar like most @@ -526,14 +526,14 @@ def _do_quit() -> None: bs.WeakCall(self._change_replay_speed, 0), repeat=True) btn = bui.buttonwidget(parent=self._root_widget, - position=(h - b_size - b_buffer, - v - b_size - b_buffer + v_offs), - button_type='square', - size=(b_size, b_size), - label='', - autoselect=True, - on_activate_call=bs.Call( - self._change_replay_speed, -1)) + position=(h - b_size - b_buffer, + v - b_size - b_buffer + v_offs), + button_type='square', + size=(b_size, b_size), + label='', + autoselect=True, + on_activate_call=bs.Call( + self._change_replay_speed, -1)) bui.textwidget( parent=self._root_widget, draw_controller=btn, From 8fe773f2cdb09319635f73797c919b31689c443d Mon Sep 17 00:00:00 2001 From: DhextraS Date: Tue, 4 Jul 2023 06:29:57 +0000 Subject: [PATCH 0535/1464] [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 f71b99ff..aa2b264e 100644 --- a/plugins/utilities.json +++ b/plugins/utilities.json @@ -422,7 +422,12 @@ } ], "versions": { - "2.0.0":null, + "2.0.0": { + "api_version": 8, + "commit_sha": "bf3e61b", + "released_on": "04-07-2023", + "md5sum": "289cc852b7f0ec1b254d08267c9921c2" + }, "1.0.1": { "api_version": 7, "commit_sha": "64e8a5c", @@ -740,4 +745,4 @@ } } } -} +} \ No newline at end of file From 369eedf12d8fee514cdd23aa543ce975928d6390 Mon Sep 17 00:00:00 2001 From: A Dhextras <104954857+DhextraS@users.noreply.github.com> Date: Tue, 4 Jul 2023 14:50:30 +0530 Subject: [PATCH 0536/1464] Update utilities.json --- plugins/utilities.json | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/plugins/utilities.json b/plugins/utilities.json index aa2b264e..96976dbb 100644 --- a/plugins/utilities.json +++ b/plugins/utilities.json @@ -522,6 +522,7 @@ } ], "versions": { + "2.0.0": null, "1.0.0": { "api_version": 7, "commit_sha": "41e239c", @@ -745,4 +746,4 @@ } } } -} \ No newline at end of file +} From 8194e98f653825914dcf628bcdd2282c8c7712ba Mon Sep 17 00:00:00 2001 From: DhextraS Date: Tue, 4 Jul 2023 09:20:58 +0000 Subject: [PATCH 0537/1464] [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 96976dbb..7ff66c24 100644 --- a/plugins/utilities.json +++ b/plugins/utilities.json @@ -522,7 +522,12 @@ } ], "versions": { - "2.0.0": null, + "2.0.0": { + "api_version": 7, + "commit_sha": "369eedf", + "released_on": "04-07-2023", + "md5sum": "bbaee5f133b41d2eb53e3b726403a75e" + }, "1.0.0": { "api_version": 7, "commit_sha": "41e239c", @@ -746,4 +751,4 @@ } } } -} +} \ No newline at end of file From c7ebadbe56148181cb0c35404dbd32dc5b3c573b Mon Sep 17 00:00:00 2001 From: A Dhextras <104954857+DhextraS@users.noreply.github.com> Date: Tue, 4 Jul 2023 14:51:54 +0530 Subject: [PATCH 0538/1464] Update pro_unlocker.py --- plugins/utilities/pro_unlocker.py | 27 +++++++++++++++------------ 1 file changed, 15 insertions(+), 12 deletions(-) diff --git a/plugins/utilities/pro_unlocker.py b/plugins/utilities/pro_unlocker.py index 5603072d..bac31447 100644 --- a/plugins/utilities/pro_unlocker.py +++ b/plugins/utilities/pro_unlocker.py @@ -1,6 +1,7 @@ -# ba_meta require api 7 -import _ba -import ba +# ba_meta require api 8 +import bascenev1 as bs +import _baplus +import babase def is_game_version_lower_than(version): @@ -9,15 +10,16 @@ def is_game_version_lower_than(version): version is lower than the passed version. Useful for addressing any breaking changes within game versions. """ - game_version = tuple(map(int, ba.app.version.split("."))) + game_version = tuple(map(int, babase.app.version.split("."))) version = tuple(map(int, version.split("."))) return game_version < version -if is_game_version_lower_than("1.7.7"): - original_get_purchased = _ba.get_purchased +if is_game_version_lower_than("1.7.20"): + original_get_purchased = _baplus.get_purchased else: - original_get_purchased = ba.internal.get_purchased + assert bs.app.plus is not None + original_get_purchased = bs.app.plus.get_purchased def get_purchased(item): @@ -27,10 +29,11 @@ def get_purchased(item): # ba_meta export plugin -class Unlock(ba.Plugin): +class Unlock(babase.Plugin): def on_app_running(self): - ba.app.accounts_v1.have_pro = lambda: True - if is_game_version_lower_than("1.7.7"): - _ba.get_purchased = get_purchased + babase.app.classic.accounts.have_pro = lambda: True + if is_game_version_lower_than("1.7.20"): + _baplus.get_purchased = get_purchased else: - ba.internal.get_purchased = get_purchased + assert bs.app.plus is not None + bs.app.plus.get_purchased = get_purchased From a0239a924e84baa92c27aab8a882326c3c9cf549 Mon Sep 17 00:00:00 2001 From: A Dhextras <104954857+DhextraS@users.noreply.github.com> Date: Tue, 4 Jul 2023 15:03:50 +0530 Subject: [PATCH 0539/1464] Update utilities.json --- plugins/utilities.json | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/plugins/utilities.json b/plugins/utilities.json index 7ff66c24..6cdd31f4 100644 --- a/plugins/utilities.json +++ b/plugins/utilities.json @@ -522,12 +522,7 @@ } ], "versions": { - "2.0.0": { - "api_version": 7, - "commit_sha": "369eedf", - "released_on": "04-07-2023", - "md5sum": "bbaee5f133b41d2eb53e3b726403a75e" - }, + "2.0.0":null, "1.0.0": { "api_version": 7, "commit_sha": "41e239c", @@ -751,4 +746,4 @@ } } } -} \ No newline at end of file +} From 1ac7a9d044aab22980512ab2201c1a08c83bd9fa Mon Sep 17 00:00:00 2001 From: DhextraS Date: Tue, 4 Jul 2023 09:34:23 +0000 Subject: [PATCH 0540/1464] [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 6cdd31f4..cee50f85 100644 --- a/plugins/utilities.json +++ b/plugins/utilities.json @@ -522,7 +522,12 @@ } ], "versions": { - "2.0.0":null, + "2.0.0": { + "api_version": 8, + "commit_sha": "a0239a9", + "released_on": "04-07-2023", + "md5sum": "187a9894158721c8fa1ecee9e3e38e73" + }, "1.0.0": { "api_version": 7, "commit_sha": "41e239c", @@ -746,4 +751,4 @@ } } } -} +} \ No newline at end of file From 7f0fd37ddedcf930a3b9ddf3a1ff16fd7ea1e928 Mon Sep 17 00:00:00 2001 From: A Dhextras <104954857+DhextraS@users.noreply.github.com> Date: Tue, 4 Jul 2023 15:04:27 +0530 Subject: [PATCH 0541/1464] Update pro_unlocker.py From c2832136aa647a54e9f44b91b66582fa58a25afa Mon Sep 17 00:00:00 2001 From: Ayush Saini <36878972+imayushsaini@users.noreply.github.com> Date: Sat, 8 Jul 2023 15:21:36 +0530 Subject: [PATCH 0542/1464] updated server switch --- README.md | 13 +- plugins/minigames.json | 6 - plugins/minigames/alliance_elimination.py | 118 ++-- plugins/utilities.json | 28 +- plugins/utilities/character_chooser.py | 35 +- plugins/utilities/easy_connect.py | 367 ++++++------- plugins/utilities/pro_unlocker.py | 24 +- plugins/utilities/server_switch.py | 639 +++------------------- 8 files changed, 356 insertions(+), 874 deletions(-) diff --git a/README.md b/README.md index d625cccd..fe057a9e 100644 --- a/README.md +++ b/README.md @@ -40,14 +40,8 @@ There are two different ways the plugin manager can be installed: 1. [Download plugin_manager.py][DownloadLink] to your mods directory (check it out by going into your game's Settings -> Advanced -> Show Mods Folder). This is the recommended way (read next method to know why). - If you're on a newer version of Android (11 or above) and not rooted, it probably won't be possible to copy - mods to game's mods folder. In this case, you can connect your Android phone to a computer and push `plugin_manager.py` - [using `adb`](https://www.xda-developers.com/install-adb-windows-macos-linux/): - ```bash - $ adb push plugin_manager.py /sdcard/Android/data/net.froemling.bombsquad/files/mods/plugin_manager.py - ``` - -3. Another way is to add + +2. Another way is to add [plugin_manager.py](https://raw.githubusercontent.com/bombsquad-community/plugin-manager/main/plugin_manager.py) to your workspace. However, plugin manager self-updates will fail when installed using this way since the game will overrwrite the updated plugin manager, with the older version from workspace on the next sync. However, you can @@ -199,8 +193,7 @@ That's it! Now you can make a [pull request](../../compare) with both the update will also help us to notify the maintainers of any future breaking changes in plugin manager that could affect 3rd party plugin sources. - - [rikkolovescats/sahilp-plugins](https://github.com/rikkolovescats/sahilp-plugins) - - [Aeliux/arcane](https://github.com/Aeliux/arcane) + [rikkolovescats/sahilp-plugins](https://github.com/rikkolovescats/sahilp-plugins) ## Tests diff --git a/plugins/minigames.json b/plugins/minigames.json index ae4f5406..a95fc4f5 100644 --- a/plugins/minigames.json +++ b/plugins/minigames.json @@ -166,12 +166,6 @@ } ], "versions": { - "2.0.0": { - "api_version": 8, - "commit_sha": "1b14789", - "released_on": "02-07-2023", - "md5sum": "cb2a7700dd13febe6f68c3cd979b8b19" - }, "1.1.0": { "api_version": 7, "commit_sha": "40b70fe", diff --git a/plugins/minigames/alliance_elimination.py b/plugins/minigames/alliance_elimination.py index f6d47b5f..e6f37761 100644 --- a/plugins/minigames/alliance_elimination.py +++ b/plugins/minigames/alliance_elimination.py @@ -2,25 +2,23 @@ # """Elimination mini-game.""" -# ba_meta require api 8 +# ba_meta require api 7 # (see https://ballistica.net/wiki/meta-tag-system) from __future__ import annotations from typing import TYPE_CHECKING -import babase -import bauiv1 as bui -import bascenev1 as bs -from bascenev1lib.actor.spazfactory import SpazFactory -from bascenev1lib.actor.scoreboard import Scoreboard +import ba +from bastd.actor.spazfactory import SpazFactory +from bastd.actor.scoreboard import Scoreboard if TYPE_CHECKING: from typing import (Any, Tuple, Type, List, Sequence, Optional, Union) -class Icon(bs.Actor): +class Icon(ba.Actor): """Creates in in-game icon on screen.""" def __init__(self, @@ -39,10 +37,10 @@ def __init__(self, self._show_lives = show_lives self._show_death = show_death self._name_scale = name_scale - self._outline_tex = bs.gettexture('characterIconMask') + self._outline_tex = ba.gettexture('characterIconMask') icon = player.get_icon() - self.node = bs.newnode('image', + self.node = ba.newnode('image', delegate=self, attrs={ 'texture': icon['texture'], @@ -55,12 +53,12 @@ def __init__(self, 'absolute_scale': True, 'attach': 'bottomCenter' }) - self._name_text = bs.newnode( + self._name_text = ba.newnode( 'text', owner=self.node, attrs={ - 'text': babase.Lstr(value=player.getname()), - 'color': babase.safecolor(player.team.color), + 'text': ba.Lstr(value=player.getname()), + 'color': ba.safecolor(player.team.color), 'h_align': 'center', 'v_align': 'center', 'vr_depth': 410, @@ -71,7 +69,7 @@ def __init__(self, 'v_attach': 'bottom' }) if self._show_lives: - self._lives_text = bs.newnode('text', + self._lives_text = ba.newnode('text', owner=self.node, attrs={ 'text': 'x0', @@ -127,7 +125,7 @@ def handle_player_died(self) -> None: if not self.node: return if self._show_death: - bs.animate( + ba.animate( self.node, 'opacity', { 0.00: 1.0, 0.05: 0.0, @@ -144,16 +142,16 @@ def handle_player_died(self) -> None: }) lives = self._player.lives if lives == 0: - bs.timer(0.6, self.update_for_lives) + ba.timer(0.6, self.update_for_lives) def handlemessage(self, msg: Any) -> Any: - if isinstance(msg, bs.DieMessage): + if isinstance(msg, ba.DieMessage): self.node.delete() return None return super().handlemessage(msg) -class Player(bs.Player['Team']): +class Player(ba.Player['Team']): """Our player type for this game.""" def __init__(self) -> None: @@ -161,7 +159,7 @@ def __init__(self) -> None: self.icons: List[Icon] = [] -class Team(bs.Team[Player]): +class Team(ba.Team[Player]): """Our team type for this game.""" def __init__(self) -> None: @@ -169,14 +167,14 @@ def __init__(self) -> None: self.spawn_order: List[Player] = [] -# ba_meta export bascenev1.GameActivity -class AllianceEliminationGame(bs.TeamGameActivity[Player, Team]): +# ba_meta export game +class AllianceEliminationGame(ba.TeamGameActivity[Player, Team]): """Game type where last player(s) left alive win.""" name = 'Alliance Elimination' description = 'Fight in groups of duo, trio, or more.\nLast remaining alive wins.' - scoreconfig = bs.ScoreConfig(label='Survived', - scoretype=bs.ScoreType.SECONDS, + scoreconfig = ba.ScoreConfig(label='Survived', + scoretype=ba.ScoreType.SECONDS, none_is_winner=True) # Show messages when players die since it's meaningful here. announce_player_deaths = True @@ -185,23 +183,23 @@ class AllianceEliminationGame(bs.TeamGameActivity[Player, Team]): @classmethod def get_available_settings( - cls, sessiontype: Type[bs.Session]) -> List[babase.Setting]: + cls, sessiontype: Type[ba.Session]) -> List[ba.Setting]: settings = [ - bs.IntSetting( + ba.IntSetting( 'Lives Per Player', default=1, min_value=1, max_value=10, increment=1, ), - bs.IntSetting( + ba.IntSetting( 'Players Per Team In Arena', default=2, min_value=2, max_value=10, increment=1, ), - bs.IntChoiceSetting( + ba.IntChoiceSetting( 'Time Limit', choices=[ ('None', 0), @@ -213,7 +211,7 @@ def get_available_settings( ], default=0, ), - bs.FloatChoiceSetting( + ba.FloatChoiceSetting( 'Respawn Times', choices=[ ('Shorter', 0.25), @@ -224,27 +222,27 @@ def get_available_settings( ], default=1.0, ), - bs.BoolSetting('Epic Mode', default=False), + ba.BoolSetting('Epic Mode', default=False), ] - if issubclass(sessiontype, bs.DualTeamSession): + if issubclass(sessiontype, ba.DualTeamSession): settings.append( - bs.BoolSetting('Balance Total Lives', default=False)) + ba.BoolSetting('Balance Total Lives', default=False)) return settings @classmethod - def supports_session_type(cls, sessiontype: Type[bs.Session]) -> bool: - return issubclass(sessiontype, bs.DualTeamSession) + def supports_session_type(cls, sessiontype: Type[ba.Session]) -> bool: + return issubclass(sessiontype, ba.DualTeamSession) @classmethod - def get_supported_maps(cls, sessiontype: Type[bs.Session]) -> List[str]: - return bs.app.classic.getmaps('melee') + def get_supported_maps(cls, sessiontype: Type[ba.Session]) -> List[str]: + return ba.getmaps('melee') def __init__(self, settings: dict): super().__init__(settings) self._scoreboard = Scoreboard() self._start_time: Optional[float] = None - self._vs_text: Optional[bs.Actor] = None - self._round_end_timer: Optional[bs.Timer] = None + self._vs_text: Optional[ba.Actor] = None + self._round_end_timer: Optional[ba.Timer] = None self._epic_mode = bool(settings['Epic Mode']) self._lives_per_player = int(settings['Lives Per Player']) self._time_limit = float(settings['Time Limit']) @@ -255,16 +253,16 @@ def __init__(self, settings: dict): # Base class overrides: self.slow_motion = self._epic_mode - self.default_music = (bs.MusicType.EPIC - if self._epic_mode else bs.MusicType.SURVIVAL) + self.default_music = (ba.MusicType.EPIC + if self._epic_mode else ba.MusicType.SURVIVAL) def get_instance_description(self) -> Union[str, Sequence]: return 'Last team standing wins.' if isinstance( - self.session, bs.DualTeamSession) else 'Last one standing wins.' + self.session, ba.DualTeamSession) else 'Last one standing wins.' def get_instance_description_short(self) -> Union[str, Sequence]: return 'last team standing wins' if isinstance( - self.session, bs.DualTeamSession) else 'last one standing wins' + self.session, ba.DualTeamSession) else 'last one standing wins' def on_player_join(self, player: Player) -> None: @@ -277,9 +275,9 @@ def on_player_join(self, player: Player) -> None: if (self._get_total_team_lives(player.team) == 0 and player.team.survival_seconds is None): player.team.survival_seconds = 0 - bs.broadcastmessage( - babase.Lstr(resource='playerDelayedJoinText', - subs=[('${PLAYER}', player.getname(full=True))]), + ba.screenmessage( + ba.Lstr(resource='playerDelayedJoinText', + subs=[('${PLAYER}', player.getname(full=True))]), color=(0, 1, 0), ) return @@ -295,11 +293,11 @@ def on_player_join(self, player: Player) -> None: def on_begin(self) -> None: super().on_begin() - self._start_time = bs.time() + self._start_time = ba.time() self.setup_standard_time_limit(self._time_limit) self.setup_standard_powerup_drops() - self._vs_text = bs.NodeActor( - bs.newnode('text', + self._vs_text = ba.NodeActor( + ba.newnode('text', attrs={ 'position': (0, 92), 'h_attach': 'center', @@ -310,12 +308,12 @@ def on_begin(self) -> None: 'scale': 0.6, 'v_attach': 'bottom', 'color': (0.8, 0.8, 0.3, 1.0), - 'text': babase.Lstr(resource='vsText') + 'text': ba.Lstr(resource='vsText') })) # If balance-team-lives is on, add lives to the smaller team until # total lives match. - if (isinstance(self.session, bs.DualTeamSession) + if (isinstance(self.session, ba.DualTeamSession) and self._balance_total_lives and self.teams[0].players and self.teams[1].players): if self._get_total_team_lives( @@ -335,7 +333,7 @@ def on_begin(self) -> None: # We could check game-over conditions at explicit trigger points, # but lets just do the simple thing and poll it. - bs.timer(1.0, self._update, repeat=True) + ba.timer(1.0, self._update, repeat=True) def _update_alliance_mode(self) -> None: # For both teams, find the first player on the spawn order list with @@ -393,10 +391,10 @@ def _update_icons(self) -> None: nplayers -= 1 test_lives += 1 - def _get_spawn_point(self, player: Player) -> Optional[babase.Vec3]: + def _get_spawn_point(self, player: Player) -> Optional[ba.Vec3]: return None - def spawn_player(self, player: Player) -> bs.Actor: + def spawn_player(self, player: Player) -> ba.Actor: actor = self.spawn_player_spaz(player, self._get_spawn_point(player)) # If we have any icons, update their state. @@ -405,7 +403,7 @@ def spawn_player(self, player: Player) -> bs.Actor: return actor def _print_lives(self, player: Player) -> None: - from bascenev1lib.actor import popuptext + from bastd.actor import popuptext # We get called in a timer so it's possible our player has left/etc. if not player or not player.is_alive() or not player.node: @@ -428,20 +426,20 @@ def on_player_leave(self, player: Player) -> None: # Update icons in a moment since our team will be gone from the # list then. - bs.timer(0, self._update_icons) + ba.timer(0, self._update_icons) # If the player to leave was the last in spawn order and had # their final turn currently in-progress, mark the survival time # for their team. if self._get_total_team_lives(player.team) == 0: assert self._start_time is not None - player.team.survival_seconds = int(bs.time() - self._start_time) + player.team.survival_seconds = int(ba.time() - self._start_time) def _get_total_team_lives(self, team: Team) -> int: return sum(player.lives for player in team.players) def handlemessage(self, msg: Any) -> Any: - if isinstance(msg, bs.PlayerDiedMessage): + if isinstance(msg, ba.PlayerDiedMessage): # Augment standard behavior. super().handlemessage(msg) @@ -449,7 +447,7 @@ def handlemessage(self, msg: Any) -> Any: player.lives -= 1 if player.lives < 0: - babase.print_error( + ba.print_error( "Got lives < 0 in Alliance Elimination; this shouldn't happen.") player.lives = 0 @@ -460,14 +458,14 @@ def handlemessage(self, msg: Any) -> Any: # Play big death sound on our last death # or for every one. if player.lives == 0: - SpazFactory.get().single_player_death_sound.play() + ba.playsound(SpazFactory.get().single_player_death_sound) # If we hit zero lives, we're dead (and our team might be too). if player.lives == 0: # If the whole team is now dead, mark their survival time. if self._get_total_team_lives(player.team) == 0: assert self._start_time is not None - player.team.survival_seconds = int(bs.time() - + player.team.survival_seconds = int(ba.time() - self._start_time) # Put ourself at the back of the spawn order. @@ -495,7 +493,7 @@ def _update(self) -> None: # the game (allows the dust to settle and draws to occur if deaths # are close enough). if len(self._get_living_teams()) < 2: - self._round_end_timer = bs.Timer(0.5, self.end_game) + self._round_end_timer = ba.Timer(0.5, self.end_game) def _get_living_teams(self) -> List[Team]: return [ @@ -507,7 +505,7 @@ def _get_living_teams(self) -> List[Team]: def end_game(self) -> None: if self.has_ended(): return - results = bs.GameResults() + results = ba.GameResults() self._vs_text = None # Kill our 'vs' if its there. for team in self.teams: results.set_team_score(team, team.survival_seconds) diff --git a/plugins/utilities.json b/plugins/utilities.json index cee50f85..701e5dff 100644 --- a/plugins/utilities.json +++ b/plugins/utilities.json @@ -335,12 +335,7 @@ } ], "versions": { - "2.0.0": { - "api_version": 8, - "commit_sha": "0c5ce76", - "released_on": "02-07-2023", - "md5sum": "8b05407fda379d853f5c75677b19fd85" - }, + "2.0.0":null, "1.2.1": { "api_version": 7, "commit_sha": "64e8a5c", @@ -422,12 +417,7 @@ } ], "versions": { - "2.0.0": { - "api_version": 8, - "commit_sha": "bf3e61b", - "released_on": "04-07-2023", - "md5sum": "289cc852b7f0ec1b254d08267c9921c2" - }, + "2.0.0":null, "1.0.1": { "api_version": 7, "commit_sha": "64e8a5c", @@ -453,12 +443,7 @@ } ], "versions": { - "2.0.0": { - "api_version": 8, - "commit_sha": "0c5ce76", - "released_on": "02-07-2023", - "md5sum": "bb5d85fb528020e809eaebb17a388e32" - }, + "2.0.0": null, "1.0.0": { "api_version": 7, "commit_sha": "ff4de19", @@ -522,12 +507,7 @@ } ], "versions": { - "2.0.0": { - "api_version": 8, - "commit_sha": "a0239a9", - "released_on": "04-07-2023", - "md5sum": "187a9894158721c8fa1ecee9e3e38e73" - }, + "2.0.0":null, "1.0.0": { "api_version": 7, "commit_sha": "41e239c", diff --git a/plugins/utilities/character_chooser.py b/plugins/utilities/character_chooser.py index da12dbb3..9dbe7333 100644 --- a/plugins/utilities/character_chooser.py +++ b/plugins/utilities/character_chooser.py @@ -55,6 +55,7 @@ from bascenev1lib.actor.spazappearance import * + def __init__(self, vpos: float, sessionplayer: bs.SessionPlayer, lobby: 'Lobby') -> None: self._deek_sound = bs.getsound('deek') @@ -112,25 +113,25 @@ def __init__(self, vpos: float, sessionplayer: bs.SessionPlayer, self._profilename = self._profilenames[self._profileindex] self._text_node = bs.newnode('text', - delegate=self, - attrs={ - 'position': (-100, self._vpos), - 'maxwidth': 190, - 'shadow': 0.5, - 'vr_depth': -20, - 'h_align': 'left', - 'v_align': 'center', - 'v_attach': 'top' - }) + delegate=self, + attrs={ + 'position': (-100, self._vpos), + 'maxwidth': 190, + 'shadow': 0.5, + 'vr_depth': -20, + 'h_align': 'left', + 'v_align': 'center', + 'v_attach': 'top' + }) bs.animate(self._text_node, 'scale', {0: 0, 0.1: 1.0}) self.icon = bs.newnode('image', - owner=self._text_node, - attrs={ - 'position': (-130, self._vpos + 20), - 'mask_texture': self._mask_texture, - 'vr_depth': -10, - 'attach': 'topCenter' - }) + owner=self._text_node, + attrs={ + 'position': (-130, self._vpos + 20), + 'mask_texture': self._mask_texture, + 'vr_depth': -10, + 'attach': 'topCenter' + }) bs.animate_array(self.icon, 'scale', 2, {0: (0, 0), 0.1: (45, 45)}) diff --git a/plugins/utilities/easy_connect.py b/plugins/utilities/easy_connect.py index c9255154..abd2f43c 100644 --- a/plugins/utilities/easy_connect.py +++ b/plugins/utilities/easy_connect.py @@ -15,13 +15,13 @@ # .................___________________________________________ # Have any idea/suggestion/bug report > send message on discord mr.smoothy#5824 -# Download modshttps://bombsquad-community.web.app/mods +# Download modshttps://bombsquad-community.web.app/mods # Discord:- # mr.smoothy#5824 # DONT EDIT ANYTHING WITHOUT PERMISSION -# join Bombsquad Community Server - +# join Bombsquad Community Server - # https://discord.gg/ucyaesh @@ -73,6 +73,7 @@ def is_game_version_lower_than(version): return game_version < version + def updateBannedServersCache(): response = None config = babase.app.config @@ -111,7 +112,7 @@ def run(self) -> None: except Exception: result = None babase.pushcall(lambda: self._call(result, self._port), - from_other_thread=True) + from_other_thread=True) def newbuild_favorites_tab(self, region_height: float) -> None: @@ -147,45 +148,45 @@ def newbuild_favorites_tab(self, region_height: float) -> None: # ================= smoothy ============= bui.textwidget(parent=self._container, - position=(90 if uiscale is babase.UIScale.SMALL else 120, btnv + - 120 if uiscale is babase.UIScale.SMALL else btnv+90), - size=(0, 0), - h_align='center', - color=(0.8, 0.8, 0.8), - v_align='top', - text="Auto") + position=(90 if uiscale is babase.UIScale.SMALL else 120, btnv + + 120 if uiscale is babase.UIScale.SMALL else btnv+90), + size=(0, 0), + h_align='center', + color=(0.8, 0.8, 0.8), + v_align='top', + text="Auto") btnv += 50 if uiscale is babase.UIScale.SMALL else 0 bui.buttonwidget(parent=self._container, - size=(30, 30), - position=(25 if uiscale is babase.UIScale.SMALL else 40, - btnv+10), - - color=(0.6, 0.53, 0.63), - textcolor=(0.75, 0.7, 0.8), - on_activate_call=self.auto_retry_dec, - text_scale=1.3 if uiscale is babase.UIScale.SMALL else 1.2, - label="-", - autoselect=True) + size=(30, 30), + position=(25 if uiscale is babase.UIScale.SMALL else 40, + btnv+10), + + color=(0.6, 0.53, 0.63), + textcolor=(0.75, 0.7, 0.8), + on_activate_call=self.auto_retry_dec, + text_scale=1.3 if uiscale is babase.UIScale.SMALL else 1.2, + label="-", + autoselect=True) self.retry_inter_text = bui.textwidget(parent=self._container, - position=( - 90 if uiscale is babase.UIScale.SMALL else 120, btnv+25), - size=(0, 0), - h_align='center', - color=(0.8, 0.8, 0.8), - v_align='center', - text=str(self.retry_inter) if self.retry_inter > 0.0 else 'off') + position=( + 90 if uiscale is babase.UIScale.SMALL else 120, btnv+25), + size=(0, 0), + h_align='center', + color=(0.8, 0.8, 0.8), + v_align='center', + text=str(self.retry_inter) if self.retry_inter > 0.0 else 'off') bui.buttonwidget(parent=self._container, - size=(30, 30), - position=(125 if uiscale is babase.UIScale.SMALL else 155, - btnv+10), + size=(30, 30), + position=(125 if uiscale is babase.UIScale.SMALL else 155, + btnv+10), - color=(0.6, 0.53, 0.63), - textcolor=(0.75, 0.7, 0.8), - on_activate_call=self.auto_retry_inc, - text_scale=1.3 if uiscale is babase.UIScale.SMALL else 1.2, - label="+", - autoselect=True) + color=(0.6, 0.53, 0.63), + textcolor=(0.75, 0.7, 0.8), + on_activate_call=self.auto_retry_inc, + text_scale=1.3 if uiscale is babase.UIScale.SMALL else 1.2, + label="+", + autoselect=True) btnv -= b_height + b_space_extra @@ -202,31 +203,31 @@ def newbuild_favorites_tab(self, region_height: float) -> None: autoselect=True) if uiscale is babase.UIScale.SMALL and bui.app.ui_v1.use_toolbars: bui.widget(edit=btn1, - left_widget=bui.get_special_widget('back_button')) + left_widget=bui.get_special_widget('back_button')) btnv -= b_height + b_space_extra bui.buttonwidget(parent=self._container, - size=(b_width, b_height), - position=(25 if uiscale is babase.UIScale.SMALL else 40, - btnv), - button_type='square', - color=(0.6, 0.53, 0.63), - textcolor=(0.75, 0.7, 0.8), - on_activate_call=self._on_favorites_edit_press, - text_scale=1.0 if uiscale is babase.UIScale.SMALL else 1.2, - label=babase.Lstr(resource='editText'), - autoselect=True) + size=(b_width, b_height), + position=(25 if uiscale is babase.UIScale.SMALL else 40, + btnv), + button_type='square', + color=(0.6, 0.53, 0.63), + textcolor=(0.75, 0.7, 0.8), + on_activate_call=self._on_favorites_edit_press, + text_scale=1.0 if uiscale is babase.UIScale.SMALL else 1.2, + label=babase.Lstr(resource='editText'), + autoselect=True) btnv -= b_height + b_space_extra bui.buttonwidget(parent=self._container, - size=(b_width, b_height), - position=(25 if uiscale is babase.UIScale.SMALL else 40, - btnv), - button_type='square', - color=(0.6, 0.53, 0.63), - textcolor=(0.75, 0.7, 0.8), - on_activate_call=self._on_favorite_delete_press, - text_scale=1.0 if uiscale is babase.UIScale.SMALL else 1.2, - label=babase.Lstr(resource='deleteText'), - autoselect=True) + size=(b_width, b_height), + position=(25 if uiscale is babase.UIScale.SMALL else 40, + btnv), + button_type='square', + color=(0.6, 0.53, 0.63), + textcolor=(0.75, 0.7, 0.8), + on_activate_call=self._on_favorite_delete_press, + text_scale=1.0 if uiscale is babase.UIScale.SMALL else 1.2, + label=babase.Lstr(resource='deleteText'), + autoselect=True) v -= sub_scroll_height + 23 self._scrollwidget = scrlw = bui.scrollwidget( @@ -235,12 +236,12 @@ def newbuild_favorites_tab(self, region_height: float) -> None: size=(sub_scroll_width, sub_scroll_height), claims_left_right=True) bui.widget(edit=self._favorites_connect_button, - right_widget=self._scrollwidget) + right_widget=self._scrollwidget) self._columnwidget = bui.columnwidget(parent=scrlw, - left_border=10, - border=2, - margin=0, - claims_left_right=True) + left_border=10, + border=2, + margin=0, + claims_left_right=True) self._favorite_selected = None self._refresh_favorites() @@ -322,8 +323,9 @@ def _clear(self) -> None: self._stats_button ]: if widget: - + widget.delete() + def update(self, index: int, party: PartyEntry, sub_scroll_width: float, @@ -331,128 +333,127 @@ def update(self, index: int, party: PartyEntry, sub_scroll_width: float, columnwidget: bui.Widget, join_text: bui.Widget, filter_text: bui.Widget, existing_selection: Optional[Selection], tab: PublicGatherTab) -> None: - """Update for the given data.""" - # pylint: disable=too-many-locals - - # Quick-out: if we've been marked clean for a certain index and - # we're still at that index, we're done. - plus = bui.app.plus - assert plus is not None - - # Quick-out: if we've been marked clean for a certain index and - # we're still at that index, we're done. - if party.clean_display_index == index: - return - - ping_good = plus.get_v1_account_misc_read_val('pingGood', 100) - ping_med = plus.get_v1_account_misc_read_val('pingMed', 500) - - self._clear() - hpos = 20 - vpos = sub_scroll_height - lineheight * index - 50 - self._name_widget = bui.textwidget( - text=bui.Lstr(value=party.name), - parent=columnwidget, - size=(sub_scroll_width * 0.63, 20), - position=(0 + hpos, 4 + vpos), - selectable=True, - on_select_call=bui.WeakCall( - tab.set_public_party_selection, - Selection(party.get_key(), SelectionComponent.NAME), - ), - on_activate_call=bui.WeakCall(tab.on_public_party_activate, party), - click_activate=True, - maxwidth=sub_scroll_width * 0.45, - corner_scale=1.4, - autoselect=True, - color=(1, 1, 1, 0.3 if party.ping is None else 1.0), - h_align='left', - v_align='center', - ) - bui.widget( - edit=self._name_widget, - left_widget=join_text, - show_buffer_top=64.0, - show_buffer_bottom=64.0, - ) - if existing_selection == Selection( - party.get_key(), SelectionComponent.NAME - ): - bui.containerwidget( - edit=columnwidget, selected_child=self._name_widget - ) - if party.stats_addr or True: - url = party.stats_addr.replace( - '${ACCOUNT}', - plus.get_v1_account_misc_read_val_2( - 'resolvedAccountID', 'UNKNOWN' - ), - ) - self._stats_button = bui.buttonwidget( - color=(0.3, 0.6, 0.94), - textcolor=(1.0, 1.0, 1.0), - label='....', + """Update for the given data.""" + # pylint: disable=too-many-locals + + # Quick-out: if we've been marked clean for a certain index and + # we're still at that index, we're done. + plus = bui.app.plus + assert plus is not None + + # Quick-out: if we've been marked clean for a certain index and + # we're still at that index, we're done. + if party.clean_display_index == index: + return + + ping_good = plus.get_v1_account_misc_read_val('pingGood', 100) + ping_med = plus.get_v1_account_misc_read_val('pingMed', 500) + + self._clear() + hpos = 20 + vpos = sub_scroll_height - lineheight * index - 50 + self._name_widget = bui.textwidget( + text=bui.Lstr(value=party.name), parent=columnwidget, - autoselect=True, - on_activate_call=bui.Call(bui.open_url, url), + size=(sub_scroll_width * 0.63, 20), + position=(0 + hpos, 4 + vpos), + selectable=True, on_select_call=bui.WeakCall( tab.set_public_party_selection, - Selection(party.get_key(), SelectionComponent.STATS_BUTTON), + Selection(party.get_key(), SelectionComponent.NAME), ), - size=(120, 40), - position=(sub_scroll_width * 0.66 + hpos, 1 + vpos), - scale=0.9, + on_activate_call=bui.WeakCall(tab.on_public_party_activate, party), + click_activate=True, + maxwidth=sub_scroll_width * 0.45, + corner_scale=1.4, + autoselect=True, + color=(1, 1, 1, 0.3 if party.ping is None else 1.0), + h_align='left', + v_align='center', + ) + bui.widget( + edit=self._name_widget, + left_widget=join_text, + show_buffer_top=64.0, + show_buffer_bottom=64.0, ) - bui.buttonwidget(edit=self._stats_button, on_activate_call=bui.WeakCall( - self.on_stats_click, self._stats_button, party)) if existing_selection == Selection( - party.get_key(), SelectionComponent.STATS_BUTTON + party.get_key(), SelectionComponent.NAME ): bui.containerwidget( - edit=columnwidget, selected_child=self._stats_button + edit=columnwidget, selected_child=self._name_widget ) + if party.stats_addr or True: + url = party.stats_addr.replace( + '${ACCOUNT}', + plus.get_v1_account_misc_read_val_2( + 'resolvedAccountID', 'UNKNOWN' + ), + ) + self._stats_button = bui.buttonwidget( + color=(0.3, 0.6, 0.94), + textcolor=(1.0, 1.0, 1.0), + label='....', + parent=columnwidget, + autoselect=True, + on_activate_call=bui.Call(bui.open_url, url), + on_select_call=bui.WeakCall( + tab.set_public_party_selection, + Selection(party.get_key(), SelectionComponent.STATS_BUTTON), + ), + size=(120, 40), + position=(sub_scroll_width * 0.66 + hpos, 1 + vpos), + scale=0.9, + ) + bui.buttonwidget(edit=self._stats_button, on_activate_call=bui.WeakCall( + self.on_stats_click, self._stats_button, party)) + if existing_selection == Selection( + party.get_key(), SelectionComponent.STATS_BUTTON + ): + bui.containerwidget( + edit=columnwidget, selected_child=self._stats_button + ) + + self._size_widget = bui.textwidget( + text=str(party.size) + '/' + str(party.size_max), + parent=columnwidget, + size=(0, 0), + position=(sub_scroll_width * 0.86 + hpos, 20 + vpos), + scale=0.7, + color=(0.8, 0.8, 0.8), + h_align='right', + v_align='center', + ) - self._size_widget = bui.textwidget( - text=str(party.size) + '/' + str(party.size_max), - parent=columnwidget, - size=(0, 0), - position=(sub_scroll_width * 0.86 + hpos, 20 + vpos), - scale=0.7, - color=(0.8, 0.8, 0.8), - h_align='right', - v_align='center', - ) + if index == 0: + bui.widget(edit=self._name_widget, up_widget=filter_text) + if self._stats_button: + bui.widget(edit=self._stats_button, up_widget=filter_text) - if index == 0: - bui.widget(edit=self._name_widget, up_widget=filter_text) - if self._stats_button: - bui.widget(edit=self._stats_button, up_widget=filter_text) - - self._ping_widget = bui.textwidget( - parent=columnwidget, - size=(0, 0), - position=(sub_scroll_width * 0.94 + hpos, 20 + vpos), - scale=0.7, - h_align='right', - v_align='center', - ) - if party.ping is None: - bui.textwidget( - edit=self._ping_widget, text='-', color=(0.5, 0.5, 0.5) - ) - else: - bui.textwidget( - edit=self._ping_widget, - text=str(int(party.ping)), - color=(0, 1, 0) - if party.ping <= ping_good - else (1, 1, 0) - if party.ping <= ping_med - else (1, 0, 0), + self._ping_widget = bui.textwidget( + parent=columnwidget, + size=(0, 0), + position=(sub_scroll_width * 0.94 + hpos, 20 + vpos), + scale=0.7, + h_align='right', + v_align='center', ) + if party.ping is None: + bui.textwidget( + edit=self._ping_widget, text='-', color=(0.5, 0.5, 0.5) + ) + else: + bui.textwidget( + edit=self._ping_widget, + text=str(int(party.ping)), + color=(0, 1, 0) + if party.ping <= ping_good + else (1, 1, 0) + if party.ping <= ping_med + else (1, 0, 0), + ) - party.clean_display_index = index - + party.clean_display_index = index def _get_popup_window_scale() -> float: uiscale = bui.app.ui_v1.uiscale @@ -500,7 +501,7 @@ def popup_menu_selected_choice(self, window: popup.PopupMenu, url = _party.stats_addr.replace( '${ACCOUNT}', plus.get_v1_account_misc_read_val_2('resolvedAccountID', - 'UNKNOWN')) + 'UNKNOWN')) bui.open_url(url) elif choice == 'connect': PartyQuickConnect(_party.address, _party.port) @@ -613,17 +614,17 @@ def __init__(self, address: str, port: int): scale=(1.4 if uiscale is babase.UIScale.SMALL else 1.2 if uiscale is babase.UIScale.MEDIUM else 1.0))) self._cancel_button = bui.buttonwidget(parent=self._root_widget, - scale=1.0, - position=(60, self._height - 80), - size=(50, 50), - label='', - on_activate_call=self.close, - autoselect=True, - color=(0.45, 0.63, 0.15), - icon=bui.gettexture('crossOut'), - iconscale=1.2) + scale=1.0, + position=(60, self._height - 80), + size=(50, 50), + label='', + on_activate_call=self.close, + autoselect=True, + color=(0.45, 0.63, 0.15), + icon=bui.gettexture('crossOut'), + iconscale=1.2) bui.containerwidget(edit=self._root_widget, - cancel_button=self._cancel_button) + cancel_button=self._cancel_button) self.IP = bui.textwidget( parent=self._root_widget, diff --git a/plugins/utilities/pro_unlocker.py b/plugins/utilities/pro_unlocker.py index bac31447..389140f7 100644 --- a/plugins/utilities/pro_unlocker.py +++ b/plugins/utilities/pro_unlocker.py @@ -4,23 +4,8 @@ import babase -def is_game_version_lower_than(version): - """ - Returns a boolean value indicating whether the current game - version is lower than the passed version. Useful for addressing - any breaking changes within game versions. - """ - game_version = tuple(map(int, babase.app.version.split("."))) - version = tuple(map(int, version.split("."))) - return game_version < version - - -if is_game_version_lower_than("1.7.20"): - original_get_purchased = _baplus.get_purchased -else: - assert bs.app.plus is not None - original_get_purchased = bs.app.plus.get_purchased +original_get_purchased = _baplus.get_purchased def get_purchased(item): if item.startswith('characters.') or item.startswith('icons.'): @@ -32,8 +17,5 @@ def get_purchased(item): class Unlock(babase.Plugin): def on_app_running(self): babase.app.classic.accounts.have_pro = lambda: True - if is_game_version_lower_than("1.7.20"): - _baplus.get_purchased = get_purchased - else: - assert bs.app.plus is not None - bs.app.plus.get_purchased = get_purchased + _baplus.get_purchased = get_purchased + \ No newline at end of file diff --git a/plugins/utilities/server_switch.py b/plugins/utilities/server_switch.py index aacb0fe7..ba4ffdcf 100644 --- a/plugins/utilities/server_switch.py +++ b/plugins/utilities/server_switch.py @@ -1,575 +1,108 @@ -# discord @mr.smoothy#5824 - +# -*- coding: utf-8 -*- # ba_meta require api 8 - -from __future__ import annotations -import copy -import time -from typing import TYPE_CHECKING - +''' +Server Switch Plugin by My.Smoothy +Let you switch recently joined servers very quickly ++ Added button to quicky look into public server list without leaving current game. + +discord: mr.smoothy +https://discord.gg/ucyaesh +Youtube : Hey Smoothy +Download more mods from +https://bombsquad-community.web.app/mods +''' import babase +import bauiv1lib.mainmenu as bastd_ui_mainmenu import bauiv1 as bui import bascenev1 as bs -import _bascenev1 as _bs -import time -import threading -from enum import Enum -from dataclasses import dataclass -if TYPE_CHECKING: - from typing import Any, Optional, Dict, List, Tuple, Type - import bascenev1 as bs - from bauiv1lib.gather import GatherWindow - -from bauiv1lib.confirm import ConfirmWindow - -import bauiv1lib.mainmenu as bastd_ui_mainmenu - -connect = bs.connect_to_party -disconnect = bs.disconnect_from_host - -server = [] - -ip_add = "private" -p_port = 44444 -p_name = "nothing here" - - -def newconnect_to_party(address, port=43210, print_progress=False): - global ip_add - global p_port - dd = _bs.get_connection_to_host_info() - if (dd != {}): - _bs.disconnect_from_host() - - ip_add = address - p_port = port - connect(address, port, print_progress) - else: - - ip_add = address - p_port = port - # print(ip_add,p_port) - connect(ip_add, port, print_progress) - - -def newdisconnect_from_host(): - try: - name = _bs.get_connection_to_host_info()['name'] - global server - global ip_add - global p_port - pojo = {"name": name, "ip": ip_add, "port": p_port} - if pojo not in server: - server.insert(0, pojo) - server = server[:3] - except: - pass - disconnect() - - -def printip(): - bs.screenmessage("ip address is"+ip_add) - - -def new_refresh_in_game( - self, positions: List[Tuple[float, float, - float]]) -> Tuple[float, float, float]: - # pylint: disable=too-many-branches - # pylint: disable=too-many-locals - # pylint: disable=too-many-statements - custom_menu_entries: List[Dict[str, Any]] = [] - session = _bs.get_foreground_host_session() - if session is not None: - try: - custom_menu_entries = session.get_custom_menu_entries() - for cme in custom_menu_entries: - if (not isinstance(cme, dict) or 'label' not in cme - or not isinstance(cme['label'], (str, bs.Lstr)) - or 'call' not in cme or not callable(cme['call'])): - raise ValueError('invalid custom menu entry: ' + - str(cme)) - except Exception: - custom_menu_entries = [] - babase.print_exception( - f'Error getting custom menu entries for {session}') - self._width = 250.0 - self._height = 250.0 if self._input_player else 180.0 - if (self._is_demo or self._is_arcade) and self._input_player: - self._height -= 40 - if not self._have_settings_button: - self._height -= 50 - if self._connected_to_remote_player: - # In this case we have a leave *and* a disconnect button. - self._height += 50 - self._height += 50 * (len(custom_menu_entries)) - uiscale = bui.app.ui_v1.uiscale - bui.containerwidget( - edit=self._root_widget, - size=(self._width*2, self._height), - scale=(2.15 if uiscale is bui.UIScale.SMALL else - 1.6 if uiscale is bui.UIScale.MEDIUM else 1.0)) - h = 125.0 - v = (self._height - 80.0 if self._input_player else self._height - 60) - h_offset = 0 - d_h_offset = 0 - v_offset = -50 - for _i in range(6 + len(custom_menu_entries)): - positions.append((h, v, 1.0)) - v += v_offset - h += h_offset - h_offset += d_h_offset - self._start_button = None - bui.app.pause() - h, v, scale = positions[self._p_index] - bui.textwidget( +current_server_ip = "127.0.0.1" +current_server_port = 43210 +servers = [] +def _refresh_in_game(func): + def wrapper(self, *args, **kwargs): + returnValue = func(self, *args, **kwargs) + uiscale = bui.app.ui_v1.uiscale + bui.containerwidget( + edit=self._root_widget, + size=(self._width*2, self._height), # double the width + scale=( + 2.15 + if uiscale is bui.UIScale.SMALL + else 1.6 + if uiscale is bui.UIScale.MEDIUM + else 1.0 + ), + ) + h = 125 + v = self._height - 60.0 + bui.textwidget( parent=self._root_widget, draw_controller=None, - text="IP: "+ip_add+" PORT: "+str(p_port), - position=(h+self._button_width-80, v+60), + text="IP: "+current_server_ip+" PORT: "+str(current_server_port), + position=(h-self._button_width/2 + 130 , v+60), h_align='center', v_align='center', size=(20, 60), scale=0.6) - v_h = v - - global server - - def con(address, port): - global ip_add - global p_port - if (address == ip_add and port == p_port): - self._resume() - else: - _bs.disconnect_from_host() - _bs.connect_to_party(address, port) - if len(server) == 0: - bui.textwidget( - parent=self._root_widget, - draw_controller=None, - text="Nothing in \n recents", - position=(h + self._button_width * scale, v-30), - h_align='center', - v_align='center', - size=(20, 60), - scale=1) - for ser in server: - self._server_button = bui.buttonwidget( - color=(0.8, 0, 1), - parent=self._root_widget, - position=(h + self._button_width * scale - 80, v_h), - size=(self._button_width, self._button_height), - scale=scale, - autoselect=self._use_autoselect, - label=ser["name"][0:22], - - on_activate_call=bs.Call(con, ser["ip"], ser["port"])) - v_h = v_h-50 - - # Player name if applicable. - if self._input_player: - player_name = self._input_player.getname() - h, v, scale = positions[self._p_index] - v += 35 - bui.textwidget(parent=self._root_widget, - position=(h - self._button_width / 2, v), - size=(self._button_width, self._button_height), - color=(1, 1, 1, 0.5), - scale=0.7, - h_align='center', - text=bs.Lstr(value=player_name)) - else: - player_name = '' - h, v, scale = positions[self._p_index] - self._p_index += 1 - btn = bui.buttonwidget(parent=self._root_widget, - position=(h - self._button_width / 2, v), - size=(self._button_width, self._button_height), - scale=scale, - label=bs.Lstr(resource=self._r + '.resumeText'), - autoselect=self._use_autoselect, - on_activate_call=self._resume) - bui.containerwidget(edit=self._root_widget, cancel_button=btn) - - # Add any custom options defined by the current game. - for entry in custom_menu_entries: - h, v, scale = positions[self._p_index] - self._p_index += 1 - - # Ask the entry whether we should resume when we call - # it (defaults to true). - resume = bool(entry.get('resume_on_call', True)) - - if resume: - call = bs.Call(self._resume_and_call, entry['call']) - else: - call = bs.Call(entry['call'], bs.WeakCall(self._resume)) - - bui.buttonwidget(parent=self._root_widget, - position=(h - self._button_width / 2, v), - size=(self._button_width, self._button_height), - scale=scale, - on_activate_call=call, - label=entry['label'], - autoselect=self._use_autoselect) - # Add a 'leave' button if the menu-owner has a player. - if ((self._input_player or self._connected_to_remote_player) - and not (self._is_demo or self._is_arcade)): - h, v, scale = positions[self._p_index] - self._p_index += 1 - btn = bui.buttonwidget(parent=self._root_widget, - position=(h - self._button_width / 2, v), - size=(self._button_width, - self._button_height), - scale=scale, - on_activate_call=self._leave, - label='', - autoselect=self._use_autoselect) - - if (player_name != '' and player_name[0] != '<' - and player_name[-1] != '>'): - txt = bs.Lstr(resource=self._r + '.justPlayerText', - subs=[('${NAME}', player_name)]) - else: - txt = bs.Lstr(value=player_name) - bui.textwidget(parent=self._root_widget, - position=(h, v + self._button_height * - (0.64 if player_name != '' else 0.5)), - size=(0, 0), - text=bs.Lstr(resource=self._r + '.leaveGameText'), - scale=(0.83 if player_name != '' else 1.0), - color=(0.75, 1.0, 0.7), - h_align='center', - v_align='center', - draw_controller=btn, - maxwidth=self._button_width * 0.9) - bui.textwidget(parent=self._root_widget, - position=(h, v + self._button_height * 0.27), - size=(0, 0), - text=txt, - color=(0.75, 1.0, 0.7), - h_align='center', - v_align='center', - draw_controller=btn, - scale=0.45, - maxwidth=self._button_width * 0.9) - return h, v, scale - - -def new_refresh(self) -> None: - # pylint: disable=too-many-branches - # pylint: disable=too-many-locals - # pylint: disable=too-many-statements - global server - print(server) - from bauiv1lib.confirm import QuitWindow - from bauiv1lib.store.button import StoreButton - import bascenev1 as bs - import _bascenev1 as _bs - import bauiv1 as bui - import _baplus - # Clear everything that was there. - children = self._root_widget.get_children() - for child in children: - child.delete() - - self._tdelay = 0.0 - self._t_delay_inc = 0.0 - self._t_delay_play = 0.0 - self._button_width = 200.0 - self._button_height = 45.0 - - self._r = 'mainMenu' - - assert bs.app.classic is not None - app = bs.app.classic - self._have_quit_button = (bui.app.ui_v1.uiscale is bui.UIScale.LARGE - or (app.platform == 'windows' - and app.subplatform == 'oculus')) - - self._have_store_button = not self._in_game - - self._have_settings_button = ( - (not self._in_game or not bui.app.toolbar_test) - and not (self._is_demo or self._is_arcade or self._is_iircade)) - - self._input_device = input_device = _bs.get_ui_input_device() - self._input_player = input_device.player if input_device else None - self._connected_to_remote_player = ( - input_device.is_attached_to_player() - if input_device else False) - - positions: List[Tuple[float, float, float]] = [] - self._p_index = 0 - - if self._in_game: - h, v, scale = self._refresh_in_game(positions) - print("refreshing in GAME", ip_add) - # btn = bui.buttonwidget(parent=self._root_widget, - # position=(80,270), - # size=(100, 90), - # scale=1.2, - # label=ip_add, - # autoselect=None, - # on_activate_call=printip) - bui.textwidget( - parent=self._root_widget, - draw_controller=None, - text="IP: "+ip_add+" PORT: "+str(p_port), - position=(150, 270), - h_align='center', - v_align='center', - size=(20, 60), - scale=1) - self._server_button = bui.buttonwidget( - parent=self._root_widget, - position=(h * 3.2 + 20 - self._button_width * scale, v), - size=(self._button_width, self._button_height), - scale=scale, - autoselect=self._use_autoselect, - label=bs.Lstr(resource=self._r + '.settingsText'), - transition_delay=self._tdelay, - on_activate_call=self._settings) - self._server_button2 = bui.buttonwidget( - parent=self._root_widget, - position=(h * 3.2 + 20 - self._button_width * scale, v-50), - size=(self._button_width, self._button_height), - scale=scale, - autoselect=self._use_autoselect, - label=bs.Lstr(resource=self._r + '.settingsText'), - transition_delay=self._tdelay, - on_activate_call=self._settings) - self._server_button3 = bui.buttonwidget( - parent=self._root_widget, - position=(h * 3.2 + 20 - self._button_width * scale, v-100), - size=(self._button_width, self._button_height), - scale=scale, - autoselect=self._use_autoselect, - label=bs.Lstr(resource=self._r + '.settingsText'), - transition_delay=self._tdelay, - on_activate_call=self._settings) - - else: - h, v, scale = self._refresh_not_in_game(positions) - - if self._have_settings_button: - h, v, scale = positions[self._p_index] - self._p_index += 1 - self._settings_button = bui.buttonwidget( - parent=self._root_widget, - position=(h - self._button_width * 0.5 * scale, v), - size=(self._button_width, self._button_height), - scale=scale, - autoselect=self._use_autoselect, - label=bs.Lstr(resource=self._r + '.settingsText'), - transition_delay=self._tdelay, - on_activate_call=self._settings) - - # Scattered eggs on easter. - if _baplus.get_v1_account_misc_read_val('easter', - False) and not self._in_game: - icon_size = 34 - bui.imagewidget(parent=self._root_widget, - position=(h - icon_size * 0.5 - 15, - v + self._button_height * scale - - icon_size * 0.24 + 1.5), - transition_delay=self._tdelay, - size=(icon_size, icon_size), - texture=bui.gettexture('egg3'), - tilt_scale=0.0) - - self._tdelay += self._t_delay_inc - - if self._in_game: - h, v, scale = positions[self._p_index] - self._p_index += 1 - - # If we're in a replay, we have a 'Leave Replay' button. - if _bs.is_in_replay(): - bui.buttonwidget(parent=self._root_widget, - position=(h - self._button_width * 0.5 * scale, - v), - scale=scale, - size=(self._button_width, self._button_height), - autoselect=self._use_autoselect, - label=bs.Lstr(resource='replayEndText'), - on_activate_call=self._confirm_end_replay) - elif _bs.get_foreground_host_session() is not None: - bui.buttonwidget( + self._public_servers = bui.buttonwidget( + color=(0.8, 0.45, 1), parent=self._root_widget, - position=(h - self._button_width * 0.5 * scale, v), - scale=scale, - size=(self._button_width, self._button_height), + position=(h+self._button_width-10, v+60+20), + size=(self._button_width/4, self._button_height/2), + scale=1.0, autoselect=self._use_autoselect, - label=bs.Lstr(resource=self._r + '.endGameText'), - on_activate_call=self._confirm_end_game) - # Assume we're in a client-session. - else: - bui.buttonwidget( + label="~~~", + on_activate_call=bs.Call(public_servers)) + for server in servers: + self._server_button = bui.buttonwidget( + color=(0.8, 0, 1), parent=self._root_widget, - position=(h - self._button_width * 0.5 * scale, v), - scale=scale, + position=( (h- self._button_width / 2 ) + self._button_width + 20, v), size=(self._button_width, self._button_height), + scale=1.0, autoselect=self._use_autoselect, - label=bs.Lstr(resource=self._r + '.leavePartyText'), - on_activate_call=self._confirm_leave_party) + label=server["name"][0:22], + on_activate_call=bs.Call(bs.connect_to_party, server["ip"], server["port"])) + + v -= 50 + + return returnValue + return wrapper - self._store_button: Optional[bui.Widget] - if self._have_store_button: - this_b_width = self._button_width - h, v, scale = positions[self._p_index] - self._p_index += 1 - - sbtn = self._store_button_instance = StoreButton( - parent=self._root_widget, - position=(h - this_b_width * 0.5 * scale, v), - size=(this_b_width, self._button_height), - scale=scale, - on_activate_call=bs.WeakCall(self._on_store_pressed), - sale_scale=1.3, - transition_delay=self._tdelay) - self._store_button = store_button = sbtn.get_button() - uiscale = bui.app.ui_v1.uiscale - icon_size = (55 if uiscale is bui.UIScale.SMALL else - 55 if uiscale is bui.UIScale.MEDIUM else 70) - bui.imagewidget( - parent=self._root_widget, - position=(h - icon_size * 0.5, - v + self._button_height * scale - icon_size * 0.23), - transition_delay=self._tdelay, - size=(icon_size, icon_size), - texture=bui.gettexture(self._store_char_tex), - tilt_scale=0.0, - draw_controller=store_button) - - self._tdelay += self._t_delay_inc - else: - self._store_button = None - - self._quit_button: Optional[bui.Widget] - if not self._in_game and self._have_quit_button: - h, v, scale = positions[self._p_index] - self._p_index += 1 - self._quit_button = quit_button = bui.buttonwidget( - parent=self._root_widget, - autoselect=self._use_autoselect, - position=(h - self._button_width * 0.5 * scale, v), - size=(self._button_width, self._button_height), - scale=scale, - label=bs.Lstr(resource=self._r + - ('.quitText' if 'Mac' in - bs.app.classic.legacy_user_agent_string else '.exitGameText')), - on_activate_call=self._quit, - transition_delay=self._tdelay) - - # Scattered eggs on easter. - if _baplus.get_v1_account_misc_read_val('easter', False): - icon_size = 30 - bui.imagewidget(parent=self._root_widget, - position=(h - icon_size * 0.5 + 25, - v + self._button_height * scale - - icon_size * 0.24 + 1.5), - transition_delay=self._tdelay, - size=(icon_size, icon_size), - texture=bui.gettexture('egg1'), - tilt_scale=0.0) - - bui.containerwidget(edit=self._root_widget, - cancel_button=quit_button) - self._tdelay += self._t_delay_inc +connect = bs.connect_to_party +def connect_to_party(address, port=43210, print_progress=False): + global current_server_ip + global current_server_port + if (bs.get_connection_to_host_info() != {}): + bs.disconnect_from_host() + current_server_ip = address + current_server_port = port + connect(address, port, print_progress) + babase.apptimer(1, check_connect_status) + +def check_connect_status(): + global servers + global current_server_ip + global current_server_port + if (bs.get_connection_to_host_info() != {}): + if (not bs.get_connection_to_host_info()['name']): + babase.apptimer(1, check_connect_status) + return + new_server = {"name": bs.get_connection_to_host_info()['name'], "ip": current_server_ip, "port": current_server_port} + if new_server not in servers: + servers.append(new_server) + servers = servers[-3:] else: - self._quit_button = None - - # If we're not in-game, have no quit button, and this is android, - # we want back presses to quit our activity. - if (not self._in_game and not self._have_quit_button - and bs.app.classic.platform == 'android'): - - def _do_quit() -> None: - QuitWindow(swish=True, back=True) - - bui.containerwidget(edit=self._root_widget, - on_cancel_call=_do_quit) - - # Add speed-up/slow-down buttons for replays. - # (ideally this should be part of a fading-out playback bar like most - # media players but this works for now). - if _bs.is_in_replay(): - b_size = 50.0 - b_buffer = 10.0 - t_scale = 0.75 - uiscale = bui.app.ui_v1.uiscale - if uiscale is bui.UIScale.SMALL: - b_size *= 0.6 - b_buffer *= 1.0 - v_offs = -40 - t_scale = 0.5 - elif uiscale is bui.UIScale.MEDIUM: - v_offs = -70 - else: - v_offs = -100 - self._replay_speed_text = bui.textwidget( - parent=self._root_widget, - text=bs.Lstr(resource='watchWindow.playbackSpeedText', - subs=[('${SPEED}', str(1.23))]), - position=(h, v + v_offs + 7 * t_scale), - h_align='center', - v_align='center', - size=(0, 0), - scale=t_scale) - - # Update to current value. - self._change_replay_speed(0) - - # Keep updating in a timer in case it gets changed elsewhere. - self._change_replay_speed_timer = bs.Timer( - 0.25, - bs.WeakCall(self._change_replay_speed, 0), - repeat=True) - btn = bui.buttonwidget(parent=self._root_widget, - position=(h - b_size - b_buffer, - v - b_size - b_buffer + v_offs), - button_type='square', - size=(b_size, b_size), - label='', - autoselect=True, - on_activate_call=bs.Call( - self._change_replay_speed, -1)) - bui.textwidget( - parent=self._root_widget, - draw_controller=btn, - text='-', - position=(h - b_size * 0.5 - b_buffer, - v - b_size * 0.5 - b_buffer + 5 * t_scale + v_offs), - h_align='center', - v_align='center', - size=(0, 0), - scale=3.0 * t_scale) - btn = bui.buttonwidget( - parent=self._root_widget, - position=(h + b_buffer, v - b_size - b_buffer + v_offs), - button_type='square', - size=(b_size, b_size), - label='', - autoselect=True, - on_activate_call=bs.Call(self._change_replay_speed, 1)) - bui.textwidget( - parent=self._root_widget, - draw_controller=btn, - text='+', - position=(h + b_size * 0.5 + b_buffer, - v - b_size * 0.5 - b_buffer + 5 * t_scale + v_offs), - h_align='center', - v_align='center', - size=(0, 0), - scale=3.0 * t_scale) + print("connection failed falling back to gather window") + public_servers() +def public_servers(origin = None): + from bauiv1lib.gather import GatherWindow + bui.app.ui_v1.set_main_menu_window( GatherWindow(origin_widget=origin).get_root_widget()) # ba_meta export plugin class bySmoothy(babase.Plugin): def __init__(self): - if babase.env().get("build_number", 0) >= 21140: - bastd_ui_mainmenu.MainMenuWindow._refresh_in_game = new_refresh_in_game - bs.connect_to_party = newconnect_to_party - bs.disconnect_from_host = newdisconnect_from_host - else: - print("Server Switch only works on bs 1.7.20 and above") + bastd_ui_mainmenu.MainMenuWindow._refresh_in_game = _refresh_in_game(bastd_ui_mainmenu.MainMenuWindow._refresh_in_game) + bs.connect_to_party = connect_to_party + \ No newline at end of file From b9b494428575825413921bbc7ec6f2c1193d7b57 Mon Sep 17 00:00:00 2001 From: imayushsaini Date: Sat, 8 Jul 2023 09:56:30 +0000 Subject: [PATCH 0543/1464] [ci] auto-format --- plugins/utilities/character_chooser.py | 35 ++- plugins/utilities/easy_connect.py | 367 ++++++++++++------------- plugins/utilities/pro_unlocker.py | 3 +- plugins/utilities/server_switch.py | 64 +++-- 4 files changed, 238 insertions(+), 231 deletions(-) diff --git a/plugins/utilities/character_chooser.py b/plugins/utilities/character_chooser.py index 9dbe7333..da12dbb3 100644 --- a/plugins/utilities/character_chooser.py +++ b/plugins/utilities/character_chooser.py @@ -55,7 +55,6 @@ from bascenev1lib.actor.spazappearance import * - def __init__(self, vpos: float, sessionplayer: bs.SessionPlayer, lobby: 'Lobby') -> None: self._deek_sound = bs.getsound('deek') @@ -113,25 +112,25 @@ def __init__(self, vpos: float, sessionplayer: bs.SessionPlayer, self._profilename = self._profilenames[self._profileindex] self._text_node = bs.newnode('text', - delegate=self, - attrs={ - 'position': (-100, self._vpos), - 'maxwidth': 190, - 'shadow': 0.5, - 'vr_depth': -20, - 'h_align': 'left', - 'v_align': 'center', - 'v_attach': 'top' - }) + delegate=self, + attrs={ + 'position': (-100, self._vpos), + 'maxwidth': 190, + 'shadow': 0.5, + 'vr_depth': -20, + 'h_align': 'left', + 'v_align': 'center', + 'v_attach': 'top' + }) bs.animate(self._text_node, 'scale', {0: 0, 0.1: 1.0}) self.icon = bs.newnode('image', - owner=self._text_node, - attrs={ - 'position': (-130, self._vpos + 20), - 'mask_texture': self._mask_texture, - 'vr_depth': -10, - 'attach': 'topCenter' - }) + owner=self._text_node, + attrs={ + 'position': (-130, self._vpos + 20), + 'mask_texture': self._mask_texture, + 'vr_depth': -10, + 'attach': 'topCenter' + }) bs.animate_array(self.icon, 'scale', 2, {0: (0, 0), 0.1: (45, 45)}) diff --git a/plugins/utilities/easy_connect.py b/plugins/utilities/easy_connect.py index abd2f43c..c9255154 100644 --- a/plugins/utilities/easy_connect.py +++ b/plugins/utilities/easy_connect.py @@ -15,13 +15,13 @@ # .................___________________________________________ # Have any idea/suggestion/bug report > send message on discord mr.smoothy#5824 -# Download modshttps://bombsquad-community.web.app/mods +# Download modshttps://bombsquad-community.web.app/mods # Discord:- # mr.smoothy#5824 # DONT EDIT ANYTHING WITHOUT PERMISSION -# join Bombsquad Community Server - +# join Bombsquad Community Server - # https://discord.gg/ucyaesh @@ -73,7 +73,6 @@ def is_game_version_lower_than(version): return game_version < version - def updateBannedServersCache(): response = None config = babase.app.config @@ -112,7 +111,7 @@ def run(self) -> None: except Exception: result = None babase.pushcall(lambda: self._call(result, self._port), - from_other_thread=True) + from_other_thread=True) def newbuild_favorites_tab(self, region_height: float) -> None: @@ -148,45 +147,45 @@ def newbuild_favorites_tab(self, region_height: float) -> None: # ================= smoothy ============= bui.textwidget(parent=self._container, - position=(90 if uiscale is babase.UIScale.SMALL else 120, btnv + - 120 if uiscale is babase.UIScale.SMALL else btnv+90), - size=(0, 0), - h_align='center', - color=(0.8, 0.8, 0.8), - v_align='top', - text="Auto") + position=(90 if uiscale is babase.UIScale.SMALL else 120, btnv + + 120 if uiscale is babase.UIScale.SMALL else btnv+90), + size=(0, 0), + h_align='center', + color=(0.8, 0.8, 0.8), + v_align='top', + text="Auto") btnv += 50 if uiscale is babase.UIScale.SMALL else 0 bui.buttonwidget(parent=self._container, - size=(30, 30), - position=(25 if uiscale is babase.UIScale.SMALL else 40, - btnv+10), - - color=(0.6, 0.53, 0.63), - textcolor=(0.75, 0.7, 0.8), - on_activate_call=self.auto_retry_dec, - text_scale=1.3 if uiscale is babase.UIScale.SMALL else 1.2, - label="-", - autoselect=True) + size=(30, 30), + position=(25 if uiscale is babase.UIScale.SMALL else 40, + btnv+10), + + color=(0.6, 0.53, 0.63), + textcolor=(0.75, 0.7, 0.8), + on_activate_call=self.auto_retry_dec, + text_scale=1.3 if uiscale is babase.UIScale.SMALL else 1.2, + label="-", + autoselect=True) self.retry_inter_text = bui.textwidget(parent=self._container, - position=( - 90 if uiscale is babase.UIScale.SMALL else 120, btnv+25), - size=(0, 0), - h_align='center', - color=(0.8, 0.8, 0.8), - v_align='center', - text=str(self.retry_inter) if self.retry_inter > 0.0 else 'off') + position=( + 90 if uiscale is babase.UIScale.SMALL else 120, btnv+25), + size=(0, 0), + h_align='center', + color=(0.8, 0.8, 0.8), + v_align='center', + text=str(self.retry_inter) if self.retry_inter > 0.0 else 'off') bui.buttonwidget(parent=self._container, - size=(30, 30), - position=(125 if uiscale is babase.UIScale.SMALL else 155, - btnv+10), + size=(30, 30), + position=(125 if uiscale is babase.UIScale.SMALL else 155, + btnv+10), - color=(0.6, 0.53, 0.63), - textcolor=(0.75, 0.7, 0.8), - on_activate_call=self.auto_retry_inc, - text_scale=1.3 if uiscale is babase.UIScale.SMALL else 1.2, - label="+", - autoselect=True) + color=(0.6, 0.53, 0.63), + textcolor=(0.75, 0.7, 0.8), + on_activate_call=self.auto_retry_inc, + text_scale=1.3 if uiscale is babase.UIScale.SMALL else 1.2, + label="+", + autoselect=True) btnv -= b_height + b_space_extra @@ -203,31 +202,31 @@ def newbuild_favorites_tab(self, region_height: float) -> None: autoselect=True) if uiscale is babase.UIScale.SMALL and bui.app.ui_v1.use_toolbars: bui.widget(edit=btn1, - left_widget=bui.get_special_widget('back_button')) + left_widget=bui.get_special_widget('back_button')) btnv -= b_height + b_space_extra bui.buttonwidget(parent=self._container, - size=(b_width, b_height), - position=(25 if uiscale is babase.UIScale.SMALL else 40, - btnv), - button_type='square', - color=(0.6, 0.53, 0.63), - textcolor=(0.75, 0.7, 0.8), - on_activate_call=self._on_favorites_edit_press, - text_scale=1.0 if uiscale is babase.UIScale.SMALL else 1.2, - label=babase.Lstr(resource='editText'), - autoselect=True) + size=(b_width, b_height), + position=(25 if uiscale is babase.UIScale.SMALL else 40, + btnv), + button_type='square', + color=(0.6, 0.53, 0.63), + textcolor=(0.75, 0.7, 0.8), + on_activate_call=self._on_favorites_edit_press, + text_scale=1.0 if uiscale is babase.UIScale.SMALL else 1.2, + label=babase.Lstr(resource='editText'), + autoselect=True) btnv -= b_height + b_space_extra bui.buttonwidget(parent=self._container, - size=(b_width, b_height), - position=(25 if uiscale is babase.UIScale.SMALL else 40, - btnv), - button_type='square', - color=(0.6, 0.53, 0.63), - textcolor=(0.75, 0.7, 0.8), - on_activate_call=self._on_favorite_delete_press, - text_scale=1.0 if uiscale is babase.UIScale.SMALL else 1.2, - label=babase.Lstr(resource='deleteText'), - autoselect=True) + size=(b_width, b_height), + position=(25 if uiscale is babase.UIScale.SMALL else 40, + btnv), + button_type='square', + color=(0.6, 0.53, 0.63), + textcolor=(0.75, 0.7, 0.8), + on_activate_call=self._on_favorite_delete_press, + text_scale=1.0 if uiscale is babase.UIScale.SMALL else 1.2, + label=babase.Lstr(resource='deleteText'), + autoselect=True) v -= sub_scroll_height + 23 self._scrollwidget = scrlw = bui.scrollwidget( @@ -236,12 +235,12 @@ def newbuild_favorites_tab(self, region_height: float) -> None: size=(sub_scroll_width, sub_scroll_height), claims_left_right=True) bui.widget(edit=self._favorites_connect_button, - right_widget=self._scrollwidget) + right_widget=self._scrollwidget) self._columnwidget = bui.columnwidget(parent=scrlw, - left_border=10, - border=2, - margin=0, - claims_left_right=True) + left_border=10, + border=2, + margin=0, + claims_left_right=True) self._favorite_selected = None self._refresh_favorites() @@ -323,9 +322,8 @@ def _clear(self) -> None: self._stats_button ]: if widget: - + widget.delete() - def update(self, index: int, party: PartyEntry, sub_scroll_width: float, @@ -333,127 +331,128 @@ def update(self, index: int, party: PartyEntry, sub_scroll_width: float, columnwidget: bui.Widget, join_text: bui.Widget, filter_text: bui.Widget, existing_selection: Optional[Selection], tab: PublicGatherTab) -> None: - """Update for the given data.""" - # pylint: disable=too-many-locals - - # Quick-out: if we've been marked clean for a certain index and - # we're still at that index, we're done. - plus = bui.app.plus - assert plus is not None - - # Quick-out: if we've been marked clean for a certain index and - # we're still at that index, we're done. - if party.clean_display_index == index: - return - - ping_good = plus.get_v1_account_misc_read_val('pingGood', 100) - ping_med = plus.get_v1_account_misc_read_val('pingMed', 500) - - self._clear() - hpos = 20 - vpos = sub_scroll_height - lineheight * index - 50 - self._name_widget = bui.textwidget( - text=bui.Lstr(value=party.name), + """Update for the given data.""" + # pylint: disable=too-many-locals + + # Quick-out: if we've been marked clean for a certain index and + # we're still at that index, we're done. + plus = bui.app.plus + assert plus is not None + + # Quick-out: if we've been marked clean for a certain index and + # we're still at that index, we're done. + if party.clean_display_index == index: + return + + ping_good = plus.get_v1_account_misc_read_val('pingGood', 100) + ping_med = plus.get_v1_account_misc_read_val('pingMed', 500) + + self._clear() + hpos = 20 + vpos = sub_scroll_height - lineheight * index - 50 + self._name_widget = bui.textwidget( + text=bui.Lstr(value=party.name), + parent=columnwidget, + size=(sub_scroll_width * 0.63, 20), + position=(0 + hpos, 4 + vpos), + selectable=True, + on_select_call=bui.WeakCall( + tab.set_public_party_selection, + Selection(party.get_key(), SelectionComponent.NAME), + ), + on_activate_call=bui.WeakCall(tab.on_public_party_activate, party), + click_activate=True, + maxwidth=sub_scroll_width * 0.45, + corner_scale=1.4, + autoselect=True, + color=(1, 1, 1, 0.3 if party.ping is None else 1.0), + h_align='left', + v_align='center', + ) + bui.widget( + edit=self._name_widget, + left_widget=join_text, + show_buffer_top=64.0, + show_buffer_bottom=64.0, + ) + if existing_selection == Selection( + party.get_key(), SelectionComponent.NAME + ): + bui.containerwidget( + edit=columnwidget, selected_child=self._name_widget + ) + if party.stats_addr or True: + url = party.stats_addr.replace( + '${ACCOUNT}', + plus.get_v1_account_misc_read_val_2( + 'resolvedAccountID', 'UNKNOWN' + ), + ) + self._stats_button = bui.buttonwidget( + color=(0.3, 0.6, 0.94), + textcolor=(1.0, 1.0, 1.0), + label='....', parent=columnwidget, - size=(sub_scroll_width * 0.63, 20), - position=(0 + hpos, 4 + vpos), - selectable=True, + autoselect=True, + on_activate_call=bui.Call(bui.open_url, url), on_select_call=bui.WeakCall( tab.set_public_party_selection, - Selection(party.get_key(), SelectionComponent.NAME), + Selection(party.get_key(), SelectionComponent.STATS_BUTTON), ), - on_activate_call=bui.WeakCall(tab.on_public_party_activate, party), - click_activate=True, - maxwidth=sub_scroll_width * 0.45, - corner_scale=1.4, - autoselect=True, - color=(1, 1, 1, 0.3 if party.ping is None else 1.0), - h_align='left', - v_align='center', - ) - bui.widget( - edit=self._name_widget, - left_widget=join_text, - show_buffer_top=64.0, - show_buffer_bottom=64.0, + size=(120, 40), + position=(sub_scroll_width * 0.66 + hpos, 1 + vpos), + scale=0.9, ) + bui.buttonwidget(edit=self._stats_button, on_activate_call=bui.WeakCall( + self.on_stats_click, self._stats_button, party)) if existing_selection == Selection( - party.get_key(), SelectionComponent.NAME + party.get_key(), SelectionComponent.STATS_BUTTON ): bui.containerwidget( - edit=columnwidget, selected_child=self._name_widget + edit=columnwidget, selected_child=self._stats_button ) - if party.stats_addr or True: - url = party.stats_addr.replace( - '${ACCOUNT}', - plus.get_v1_account_misc_read_val_2( - 'resolvedAccountID', 'UNKNOWN' - ), - ) - self._stats_button = bui.buttonwidget( - color=(0.3, 0.6, 0.94), - textcolor=(1.0, 1.0, 1.0), - label='....', - parent=columnwidget, - autoselect=True, - on_activate_call=bui.Call(bui.open_url, url), - on_select_call=bui.WeakCall( - tab.set_public_party_selection, - Selection(party.get_key(), SelectionComponent.STATS_BUTTON), - ), - size=(120, 40), - position=(sub_scroll_width * 0.66 + hpos, 1 + vpos), - scale=0.9, - ) - bui.buttonwidget(edit=self._stats_button, on_activate_call=bui.WeakCall( - self.on_stats_click, self._stats_button, party)) - if existing_selection == Selection( - party.get_key(), SelectionComponent.STATS_BUTTON - ): - bui.containerwidget( - edit=columnwidget, selected_child=self._stats_button - ) - - self._size_widget = bui.textwidget( - text=str(party.size) + '/' + str(party.size_max), - parent=columnwidget, - size=(0, 0), - position=(sub_scroll_width * 0.86 + hpos, 20 + vpos), - scale=0.7, - color=(0.8, 0.8, 0.8), - h_align='right', - v_align='center', - ) - if index == 0: - bui.widget(edit=self._name_widget, up_widget=filter_text) - if self._stats_button: - bui.widget(edit=self._stats_button, up_widget=filter_text) + self._size_widget = bui.textwidget( + text=str(party.size) + '/' + str(party.size_max), + parent=columnwidget, + size=(0, 0), + position=(sub_scroll_width * 0.86 + hpos, 20 + vpos), + scale=0.7, + color=(0.8, 0.8, 0.8), + h_align='right', + v_align='center', + ) - self._ping_widget = bui.textwidget( - parent=columnwidget, - size=(0, 0), - position=(sub_scroll_width * 0.94 + hpos, 20 + vpos), - scale=0.7, - h_align='right', - v_align='center', + if index == 0: + bui.widget(edit=self._name_widget, up_widget=filter_text) + if self._stats_button: + bui.widget(edit=self._stats_button, up_widget=filter_text) + + self._ping_widget = bui.textwidget( + parent=columnwidget, + size=(0, 0), + position=(sub_scroll_width * 0.94 + hpos, 20 + vpos), + scale=0.7, + h_align='right', + v_align='center', + ) + if party.ping is None: + bui.textwidget( + edit=self._ping_widget, text='-', color=(0.5, 0.5, 0.5) ) - if party.ping is None: - bui.textwidget( - edit=self._ping_widget, text='-', color=(0.5, 0.5, 0.5) - ) - else: - bui.textwidget( - edit=self._ping_widget, - text=str(int(party.ping)), - color=(0, 1, 0) - if party.ping <= ping_good - else (1, 1, 0) - if party.ping <= ping_med - else (1, 0, 0), - ) + else: + bui.textwidget( + edit=self._ping_widget, + text=str(int(party.ping)), + color=(0, 1, 0) + if party.ping <= ping_good + else (1, 1, 0) + if party.ping <= ping_med + else (1, 0, 0), + ) + + party.clean_display_index = index - party.clean_display_index = index def _get_popup_window_scale() -> float: uiscale = bui.app.ui_v1.uiscale @@ -501,7 +500,7 @@ def popup_menu_selected_choice(self, window: popup.PopupMenu, url = _party.stats_addr.replace( '${ACCOUNT}', plus.get_v1_account_misc_read_val_2('resolvedAccountID', - 'UNKNOWN')) + 'UNKNOWN')) bui.open_url(url) elif choice == 'connect': PartyQuickConnect(_party.address, _party.port) @@ -614,17 +613,17 @@ def __init__(self, address: str, port: int): scale=(1.4 if uiscale is babase.UIScale.SMALL else 1.2 if uiscale is babase.UIScale.MEDIUM else 1.0))) self._cancel_button = bui.buttonwidget(parent=self._root_widget, - scale=1.0, - position=(60, self._height - 80), - size=(50, 50), - label='', - on_activate_call=self.close, - autoselect=True, - color=(0.45, 0.63, 0.15), - icon=bui.gettexture('crossOut'), - iconscale=1.2) + scale=1.0, + position=(60, self._height - 80), + size=(50, 50), + label='', + on_activate_call=self.close, + autoselect=True, + color=(0.45, 0.63, 0.15), + icon=bui.gettexture('crossOut'), + iconscale=1.2) bui.containerwidget(edit=self._root_widget, - cancel_button=self._cancel_button) + cancel_button=self._cancel_button) self.IP = bui.textwidget( parent=self._root_widget, diff --git a/plugins/utilities/pro_unlocker.py b/plugins/utilities/pro_unlocker.py index 389140f7..409cdfc7 100644 --- a/plugins/utilities/pro_unlocker.py +++ b/plugins/utilities/pro_unlocker.py @@ -4,9 +4,9 @@ import babase - original_get_purchased = _baplus.get_purchased + def get_purchased(item): if item.startswith('characters.') or item.startswith('icons.'): return original_get_purchased(item) @@ -18,4 +18,3 @@ class Unlock(babase.Plugin): def on_app_running(self): babase.app.classic.accounts.have_pro = lambda: True _baplus.get_purchased = get_purchased - \ No newline at end of file diff --git a/plugins/utilities/server_switch.py b/plugins/utilities/server_switch.py index ba4ffdcf..2dbc667f 100644 --- a/plugins/utilities/server_switch.py +++ b/plugins/utilities/server_switch.py @@ -18,13 +18,15 @@ current_server_ip = "127.0.0.1" current_server_port = 43210 servers = [] + + def _refresh_in_game(func): def wrapper(self, *args, **kwargs): returnValue = func(self, *args, **kwargs) uiscale = bui.app.ui_v1.uiscale bui.containerwidget( edit=self._root_widget, - size=(self._width*2, self._height), # double the width + size=(self._width*2, self._height), # double the width scale=( 2.15 if uiscale is bui.UIScale.SMALL @@ -36,40 +38,43 @@ def wrapper(self, *args, **kwargs): h = 125 v = self._height - 60.0 bui.textwidget( - parent=self._root_widget, - draw_controller=None, - text="IP: "+current_server_ip+" PORT: "+str(current_server_port), - position=(h-self._button_width/2 + 130 , v+60), - h_align='center', - v_align='center', - size=(20, 60), - scale=0.6) + parent=self._root_widget, + draw_controller=None, + text="IP: "+current_server_ip+" PORT: "+str(current_server_port), + position=(h-self._button_width/2 + 130, v+60), + h_align='center', + v_align='center', + size=(20, 60), + scale=0.6) self._public_servers = bui.buttonwidget( - color=(0.8, 0.45, 1), - parent=self._root_widget, - position=(h+self._button_width-10, v+60+20), - size=(self._button_width/4, self._button_height/2), - scale=1.0, - autoselect=self._use_autoselect, - label="~~~", - on_activate_call=bs.Call(public_servers)) + color=(0.8, 0.45, 1), + parent=self._root_widget, + position=(h+self._button_width-10, v+60+20), + size=(self._button_width/4, self._button_height/2), + scale=1.0, + autoselect=self._use_autoselect, + label="~~~", + on_activate_call=bs.Call(public_servers)) for server in servers: self._server_button = bui.buttonwidget( color=(0.8, 0, 1), parent=self._root_widget, - position=( (h- self._button_width / 2 ) + self._button_width + 20, v), + position=((h - self._button_width / 2) + self._button_width + 20, v), size=(self._button_width, self._button_height), scale=1.0, autoselect=self._use_autoselect, label=server["name"][0:22], on_activate_call=bs.Call(bs.connect_to_party, server["ip"], server["port"])) - + v -= 50 - - return returnValue + + return returnValue return wrapper + connect = bs.connect_to_party + + def connect_to_party(address, port=43210, print_progress=False): global current_server_ip global current_server_port @@ -79,7 +84,8 @@ def connect_to_party(address, port=43210, print_progress=False): current_server_port = port connect(address, port, print_progress) babase.apptimer(1, check_connect_status) - + + def check_connect_status(): global servers global current_server_ip @@ -88,7 +94,8 @@ def check_connect_status(): if (not bs.get_connection_to_host_info()['name']): babase.apptimer(1, check_connect_status) return - new_server = {"name": bs.get_connection_to_host_info()['name'], "ip": current_server_ip, "port": current_server_port} + new_server = {"name": bs.get_connection_to_host_info( + )['name'], "ip": current_server_ip, "port": current_server_port} if new_server not in servers: servers.append(new_server) servers = servers[-3:] @@ -96,13 +103,16 @@ def check_connect_status(): print("connection failed falling back to gather window") public_servers() -def public_servers(origin = None): + +def public_servers(origin=None): from bauiv1lib.gather import GatherWindow - bui.app.ui_v1.set_main_menu_window( GatherWindow(origin_widget=origin).get_root_widget()) + bui.app.ui_v1.set_main_menu_window(GatherWindow(origin_widget=origin).get_root_widget()) # ba_meta export plugin + + class bySmoothy(babase.Plugin): def __init__(self): - bastd_ui_mainmenu.MainMenuWindow._refresh_in_game = _refresh_in_game(bastd_ui_mainmenu.MainMenuWindow._refresh_in_game) + bastd_ui_mainmenu.MainMenuWindow._refresh_in_game = _refresh_in_game( + bastd_ui_mainmenu.MainMenuWindow._refresh_in_game) bs.connect_to_party = connect_to_party - \ No newline at end of file From d076534a526c4b98b270beed5b27fa6f932cace3 Mon Sep 17 00:00:00 2001 From: imayushsaini Date: Sat, 8 Jul 2023 09:56:31 +0000 Subject: [PATCH 0544/1464] [ci] apply-version-metadata --- plugins/utilities.json | 28 ++++++++++++++++++++++++---- 1 file changed, 24 insertions(+), 4 deletions(-) diff --git a/plugins/utilities.json b/plugins/utilities.json index 701e5dff..e929fbe9 100644 --- a/plugins/utilities.json +++ b/plugins/utilities.json @@ -335,7 +335,12 @@ } ], "versions": { - "2.0.0":null, + "2.0.0": { + "api_version": 8, + "commit_sha": "b9b4944", + "released_on": "08-07-2023", + "md5sum": "8b05407fda379d853f5c75677b19fd85" + }, "1.2.1": { "api_version": 7, "commit_sha": "64e8a5c", @@ -417,7 +422,12 @@ } ], "versions": { - "2.0.0":null, + "2.0.0": { + "api_version": 8, + "commit_sha": "b9b4944", + "released_on": "08-07-2023", + "md5sum": "30a21cb1c739b098dcaa791e4a2cd481" + }, "1.0.1": { "api_version": 7, "commit_sha": "64e8a5c", @@ -443,7 +453,12 @@ } ], "versions": { - "2.0.0": null, + "2.0.0": { + "api_version": 8, + "commit_sha": "b9b4944", + "released_on": "08-07-2023", + "md5sum": "bb5d85fb528020e809eaebb17a388e32" + }, "1.0.0": { "api_version": 7, "commit_sha": "ff4de19", @@ -507,7 +522,12 @@ } ], "versions": { - "2.0.0":null, + "2.0.0": { + "api_version": 8, + "commit_sha": "b9b4944", + "released_on": "08-07-2023", + "md5sum": "7403fcea1855ddf561aa412d703fcc6e" + }, "1.0.0": { "api_version": 7, "commit_sha": "41e239c", From 4eb520fa19088c6ae13b851c8232c07305e41857 Mon Sep 17 00:00:00 2001 From: Ayush Saini <36878972+imayushsaini@users.noreply.github.com> Date: Sat, 8 Jul 2023 15:44:27 +0530 Subject: [PATCH 0545/1464] Revert "updated server switch" oop This reverts commit c2832136aa647a54e9f44b91b66582fa58a25afa. --- README.md | 13 +- plugins/minigames.json | 6 + plugins/minigames/alliance_elimination.py | 118 ++-- plugins/utilities.json | 28 +- plugins/utilities/character_chooser.py | 35 +- plugins/utilities/easy_connect.py | 367 +++++++------ plugins/utilities/pro_unlocker.py | 24 +- plugins/utilities/server_switch.py | 639 +++++++++++++++++++--- 8 files changed, 874 insertions(+), 356 deletions(-) diff --git a/README.md b/README.md index fe057a9e..d625cccd 100644 --- a/README.md +++ b/README.md @@ -40,8 +40,14 @@ There are two different ways the plugin manager can be installed: 1. [Download plugin_manager.py][DownloadLink] to your mods directory (check it out by going into your game's Settings -> Advanced -> Show Mods Folder). This is the recommended way (read next method to know why). - -2. Another way is to add + If you're on a newer version of Android (11 or above) and not rooted, it probably won't be possible to copy + mods to game's mods folder. In this case, you can connect your Android phone to a computer and push `plugin_manager.py` + [using `adb`](https://www.xda-developers.com/install-adb-windows-macos-linux/): + ```bash + $ adb push plugin_manager.py /sdcard/Android/data/net.froemling.bombsquad/files/mods/plugin_manager.py + ``` + +3. Another way is to add [plugin_manager.py](https://raw.githubusercontent.com/bombsquad-community/plugin-manager/main/plugin_manager.py) to your workspace. However, plugin manager self-updates will fail when installed using this way since the game will overrwrite the updated plugin manager, with the older version from workspace on the next sync. However, you can @@ -193,7 +199,8 @@ That's it! Now you can make a [pull request](../../compare) with both the update will also help us to notify the maintainers of any future breaking changes in plugin manager that could affect 3rd party plugin sources. - [rikkolovescats/sahilp-plugins](https://github.com/rikkolovescats/sahilp-plugins) + - [rikkolovescats/sahilp-plugins](https://github.com/rikkolovescats/sahilp-plugins) + - [Aeliux/arcane](https://github.com/Aeliux/arcane) ## Tests diff --git a/plugins/minigames.json b/plugins/minigames.json index a95fc4f5..ae4f5406 100644 --- a/plugins/minigames.json +++ b/plugins/minigames.json @@ -166,6 +166,12 @@ } ], "versions": { + "2.0.0": { + "api_version": 8, + "commit_sha": "1b14789", + "released_on": "02-07-2023", + "md5sum": "cb2a7700dd13febe6f68c3cd979b8b19" + }, "1.1.0": { "api_version": 7, "commit_sha": "40b70fe", diff --git a/plugins/minigames/alliance_elimination.py b/plugins/minigames/alliance_elimination.py index e6f37761..f6d47b5f 100644 --- a/plugins/minigames/alliance_elimination.py +++ b/plugins/minigames/alliance_elimination.py @@ -2,23 +2,25 @@ # """Elimination mini-game.""" -# ba_meta require api 7 +# ba_meta require api 8 # (see https://ballistica.net/wiki/meta-tag-system) from __future__ import annotations from typing import TYPE_CHECKING -import ba -from bastd.actor.spazfactory import SpazFactory -from bastd.actor.scoreboard import Scoreboard +import babase +import bauiv1 as bui +import bascenev1 as bs +from bascenev1lib.actor.spazfactory import SpazFactory +from bascenev1lib.actor.scoreboard import Scoreboard if TYPE_CHECKING: from typing import (Any, Tuple, Type, List, Sequence, Optional, Union) -class Icon(ba.Actor): +class Icon(bs.Actor): """Creates in in-game icon on screen.""" def __init__(self, @@ -37,10 +39,10 @@ def __init__(self, self._show_lives = show_lives self._show_death = show_death self._name_scale = name_scale - self._outline_tex = ba.gettexture('characterIconMask') + self._outline_tex = bs.gettexture('characterIconMask') icon = player.get_icon() - self.node = ba.newnode('image', + self.node = bs.newnode('image', delegate=self, attrs={ 'texture': icon['texture'], @@ -53,12 +55,12 @@ def __init__(self, 'absolute_scale': True, 'attach': 'bottomCenter' }) - self._name_text = ba.newnode( + self._name_text = bs.newnode( 'text', owner=self.node, attrs={ - 'text': ba.Lstr(value=player.getname()), - 'color': ba.safecolor(player.team.color), + 'text': babase.Lstr(value=player.getname()), + 'color': babase.safecolor(player.team.color), 'h_align': 'center', 'v_align': 'center', 'vr_depth': 410, @@ -69,7 +71,7 @@ def __init__(self, 'v_attach': 'bottom' }) if self._show_lives: - self._lives_text = ba.newnode('text', + self._lives_text = bs.newnode('text', owner=self.node, attrs={ 'text': 'x0', @@ -125,7 +127,7 @@ def handle_player_died(self) -> None: if not self.node: return if self._show_death: - ba.animate( + bs.animate( self.node, 'opacity', { 0.00: 1.0, 0.05: 0.0, @@ -142,16 +144,16 @@ def handle_player_died(self) -> None: }) lives = self._player.lives if lives == 0: - ba.timer(0.6, self.update_for_lives) + bs.timer(0.6, self.update_for_lives) def handlemessage(self, msg: Any) -> Any: - if isinstance(msg, ba.DieMessage): + if isinstance(msg, bs.DieMessage): self.node.delete() return None return super().handlemessage(msg) -class Player(ba.Player['Team']): +class Player(bs.Player['Team']): """Our player type for this game.""" def __init__(self) -> None: @@ -159,7 +161,7 @@ def __init__(self) -> None: self.icons: List[Icon] = [] -class Team(ba.Team[Player]): +class Team(bs.Team[Player]): """Our team type for this game.""" def __init__(self) -> None: @@ -167,14 +169,14 @@ def __init__(self) -> None: self.spawn_order: List[Player] = [] -# ba_meta export game -class AllianceEliminationGame(ba.TeamGameActivity[Player, Team]): +# ba_meta export bascenev1.GameActivity +class AllianceEliminationGame(bs.TeamGameActivity[Player, Team]): """Game type where last player(s) left alive win.""" name = 'Alliance Elimination' description = 'Fight in groups of duo, trio, or more.\nLast remaining alive wins.' - scoreconfig = ba.ScoreConfig(label='Survived', - scoretype=ba.ScoreType.SECONDS, + scoreconfig = bs.ScoreConfig(label='Survived', + scoretype=bs.ScoreType.SECONDS, none_is_winner=True) # Show messages when players die since it's meaningful here. announce_player_deaths = True @@ -183,23 +185,23 @@ class AllianceEliminationGame(ba.TeamGameActivity[Player, Team]): @classmethod def get_available_settings( - cls, sessiontype: Type[ba.Session]) -> List[ba.Setting]: + cls, sessiontype: Type[bs.Session]) -> List[babase.Setting]: settings = [ - ba.IntSetting( + bs.IntSetting( 'Lives Per Player', default=1, min_value=1, max_value=10, increment=1, ), - ba.IntSetting( + bs.IntSetting( 'Players Per Team In Arena', default=2, min_value=2, max_value=10, increment=1, ), - ba.IntChoiceSetting( + bs.IntChoiceSetting( 'Time Limit', choices=[ ('None', 0), @@ -211,7 +213,7 @@ def get_available_settings( ], default=0, ), - ba.FloatChoiceSetting( + bs.FloatChoiceSetting( 'Respawn Times', choices=[ ('Shorter', 0.25), @@ -222,27 +224,27 @@ def get_available_settings( ], default=1.0, ), - ba.BoolSetting('Epic Mode', default=False), + bs.BoolSetting('Epic Mode', default=False), ] - if issubclass(sessiontype, ba.DualTeamSession): + if issubclass(sessiontype, bs.DualTeamSession): settings.append( - ba.BoolSetting('Balance Total Lives', default=False)) + bs.BoolSetting('Balance Total Lives', default=False)) return settings @classmethod - def supports_session_type(cls, sessiontype: Type[ba.Session]) -> bool: - return issubclass(sessiontype, ba.DualTeamSession) + def supports_session_type(cls, sessiontype: Type[bs.Session]) -> bool: + return issubclass(sessiontype, bs.DualTeamSession) @classmethod - def get_supported_maps(cls, sessiontype: Type[ba.Session]) -> List[str]: - return ba.getmaps('melee') + def get_supported_maps(cls, sessiontype: Type[bs.Session]) -> List[str]: + return bs.app.classic.getmaps('melee') def __init__(self, settings: dict): super().__init__(settings) self._scoreboard = Scoreboard() self._start_time: Optional[float] = None - self._vs_text: Optional[ba.Actor] = None - self._round_end_timer: Optional[ba.Timer] = None + self._vs_text: Optional[bs.Actor] = None + self._round_end_timer: Optional[bs.Timer] = None self._epic_mode = bool(settings['Epic Mode']) self._lives_per_player = int(settings['Lives Per Player']) self._time_limit = float(settings['Time Limit']) @@ -253,16 +255,16 @@ def __init__(self, settings: dict): # Base class overrides: self.slow_motion = self._epic_mode - self.default_music = (ba.MusicType.EPIC - if self._epic_mode else ba.MusicType.SURVIVAL) + self.default_music = (bs.MusicType.EPIC + if self._epic_mode else bs.MusicType.SURVIVAL) def get_instance_description(self) -> Union[str, Sequence]: return 'Last team standing wins.' if isinstance( - self.session, ba.DualTeamSession) else 'Last one standing wins.' + self.session, bs.DualTeamSession) else 'Last one standing wins.' def get_instance_description_short(self) -> Union[str, Sequence]: return 'last team standing wins' if isinstance( - self.session, ba.DualTeamSession) else 'last one standing wins' + self.session, bs.DualTeamSession) else 'last one standing wins' def on_player_join(self, player: Player) -> None: @@ -275,9 +277,9 @@ def on_player_join(self, player: Player) -> None: if (self._get_total_team_lives(player.team) == 0 and player.team.survival_seconds is None): player.team.survival_seconds = 0 - ba.screenmessage( - ba.Lstr(resource='playerDelayedJoinText', - subs=[('${PLAYER}', player.getname(full=True))]), + bs.broadcastmessage( + babase.Lstr(resource='playerDelayedJoinText', + subs=[('${PLAYER}', player.getname(full=True))]), color=(0, 1, 0), ) return @@ -293,11 +295,11 @@ def on_player_join(self, player: Player) -> None: def on_begin(self) -> None: super().on_begin() - self._start_time = ba.time() + self._start_time = bs.time() self.setup_standard_time_limit(self._time_limit) self.setup_standard_powerup_drops() - self._vs_text = ba.NodeActor( - ba.newnode('text', + self._vs_text = bs.NodeActor( + bs.newnode('text', attrs={ 'position': (0, 92), 'h_attach': 'center', @@ -308,12 +310,12 @@ def on_begin(self) -> None: 'scale': 0.6, 'v_attach': 'bottom', 'color': (0.8, 0.8, 0.3, 1.0), - 'text': ba.Lstr(resource='vsText') + 'text': babase.Lstr(resource='vsText') })) # If balance-team-lives is on, add lives to the smaller team until # total lives match. - if (isinstance(self.session, ba.DualTeamSession) + if (isinstance(self.session, bs.DualTeamSession) and self._balance_total_lives and self.teams[0].players and self.teams[1].players): if self._get_total_team_lives( @@ -333,7 +335,7 @@ def on_begin(self) -> None: # We could check game-over conditions at explicit trigger points, # but lets just do the simple thing and poll it. - ba.timer(1.0, self._update, repeat=True) + bs.timer(1.0, self._update, repeat=True) def _update_alliance_mode(self) -> None: # For both teams, find the first player on the spawn order list with @@ -391,10 +393,10 @@ def _update_icons(self) -> None: nplayers -= 1 test_lives += 1 - def _get_spawn_point(self, player: Player) -> Optional[ba.Vec3]: + def _get_spawn_point(self, player: Player) -> Optional[babase.Vec3]: return None - def spawn_player(self, player: Player) -> ba.Actor: + def spawn_player(self, player: Player) -> bs.Actor: actor = self.spawn_player_spaz(player, self._get_spawn_point(player)) # If we have any icons, update their state. @@ -403,7 +405,7 @@ def spawn_player(self, player: Player) -> ba.Actor: return actor def _print_lives(self, player: Player) -> None: - from bastd.actor import popuptext + from bascenev1lib.actor import popuptext # We get called in a timer so it's possible our player has left/etc. if not player or not player.is_alive() or not player.node: @@ -426,20 +428,20 @@ def on_player_leave(self, player: Player) -> None: # Update icons in a moment since our team will be gone from the # list then. - ba.timer(0, self._update_icons) + bs.timer(0, self._update_icons) # If the player to leave was the last in spawn order and had # their final turn currently in-progress, mark the survival time # for their team. if self._get_total_team_lives(player.team) == 0: assert self._start_time is not None - player.team.survival_seconds = int(ba.time() - self._start_time) + player.team.survival_seconds = int(bs.time() - self._start_time) def _get_total_team_lives(self, team: Team) -> int: return sum(player.lives for player in team.players) def handlemessage(self, msg: Any) -> Any: - if isinstance(msg, ba.PlayerDiedMessage): + if isinstance(msg, bs.PlayerDiedMessage): # Augment standard behavior. super().handlemessage(msg) @@ -447,7 +449,7 @@ def handlemessage(self, msg: Any) -> Any: player.lives -= 1 if player.lives < 0: - ba.print_error( + babase.print_error( "Got lives < 0 in Alliance Elimination; this shouldn't happen.") player.lives = 0 @@ -458,14 +460,14 @@ def handlemessage(self, msg: Any) -> Any: # Play big death sound on our last death # or for every one. if player.lives == 0: - ba.playsound(SpazFactory.get().single_player_death_sound) + SpazFactory.get().single_player_death_sound.play() # If we hit zero lives, we're dead (and our team might be too). if player.lives == 0: # If the whole team is now dead, mark their survival time. if self._get_total_team_lives(player.team) == 0: assert self._start_time is not None - player.team.survival_seconds = int(ba.time() - + player.team.survival_seconds = int(bs.time() - self._start_time) # Put ourself at the back of the spawn order. @@ -493,7 +495,7 @@ def _update(self) -> None: # the game (allows the dust to settle and draws to occur if deaths # are close enough). if len(self._get_living_teams()) < 2: - self._round_end_timer = ba.Timer(0.5, self.end_game) + self._round_end_timer = bs.Timer(0.5, self.end_game) def _get_living_teams(self) -> List[Team]: return [ @@ -505,7 +507,7 @@ def _get_living_teams(self) -> List[Team]: def end_game(self) -> None: if self.has_ended(): return - results = ba.GameResults() + results = bs.GameResults() self._vs_text = None # Kill our 'vs' if its there. for team in self.teams: results.set_team_score(team, team.survival_seconds) diff --git a/plugins/utilities.json b/plugins/utilities.json index 701e5dff..cee50f85 100644 --- a/plugins/utilities.json +++ b/plugins/utilities.json @@ -335,7 +335,12 @@ } ], "versions": { - "2.0.0":null, + "2.0.0": { + "api_version": 8, + "commit_sha": "0c5ce76", + "released_on": "02-07-2023", + "md5sum": "8b05407fda379d853f5c75677b19fd85" + }, "1.2.1": { "api_version": 7, "commit_sha": "64e8a5c", @@ -417,7 +422,12 @@ } ], "versions": { - "2.0.0":null, + "2.0.0": { + "api_version": 8, + "commit_sha": "bf3e61b", + "released_on": "04-07-2023", + "md5sum": "289cc852b7f0ec1b254d08267c9921c2" + }, "1.0.1": { "api_version": 7, "commit_sha": "64e8a5c", @@ -443,7 +453,12 @@ } ], "versions": { - "2.0.0": null, + "2.0.0": { + "api_version": 8, + "commit_sha": "0c5ce76", + "released_on": "02-07-2023", + "md5sum": "bb5d85fb528020e809eaebb17a388e32" + }, "1.0.0": { "api_version": 7, "commit_sha": "ff4de19", @@ -507,7 +522,12 @@ } ], "versions": { - "2.0.0":null, + "2.0.0": { + "api_version": 8, + "commit_sha": "a0239a9", + "released_on": "04-07-2023", + "md5sum": "187a9894158721c8fa1ecee9e3e38e73" + }, "1.0.0": { "api_version": 7, "commit_sha": "41e239c", diff --git a/plugins/utilities/character_chooser.py b/plugins/utilities/character_chooser.py index 9dbe7333..da12dbb3 100644 --- a/plugins/utilities/character_chooser.py +++ b/plugins/utilities/character_chooser.py @@ -55,7 +55,6 @@ from bascenev1lib.actor.spazappearance import * - def __init__(self, vpos: float, sessionplayer: bs.SessionPlayer, lobby: 'Lobby') -> None: self._deek_sound = bs.getsound('deek') @@ -113,25 +112,25 @@ def __init__(self, vpos: float, sessionplayer: bs.SessionPlayer, self._profilename = self._profilenames[self._profileindex] self._text_node = bs.newnode('text', - delegate=self, - attrs={ - 'position': (-100, self._vpos), - 'maxwidth': 190, - 'shadow': 0.5, - 'vr_depth': -20, - 'h_align': 'left', - 'v_align': 'center', - 'v_attach': 'top' - }) + delegate=self, + attrs={ + 'position': (-100, self._vpos), + 'maxwidth': 190, + 'shadow': 0.5, + 'vr_depth': -20, + 'h_align': 'left', + 'v_align': 'center', + 'v_attach': 'top' + }) bs.animate(self._text_node, 'scale', {0: 0, 0.1: 1.0}) self.icon = bs.newnode('image', - owner=self._text_node, - attrs={ - 'position': (-130, self._vpos + 20), - 'mask_texture': self._mask_texture, - 'vr_depth': -10, - 'attach': 'topCenter' - }) + owner=self._text_node, + attrs={ + 'position': (-130, self._vpos + 20), + 'mask_texture': self._mask_texture, + 'vr_depth': -10, + 'attach': 'topCenter' + }) bs.animate_array(self.icon, 'scale', 2, {0: (0, 0), 0.1: (45, 45)}) diff --git a/plugins/utilities/easy_connect.py b/plugins/utilities/easy_connect.py index abd2f43c..c9255154 100644 --- a/plugins/utilities/easy_connect.py +++ b/plugins/utilities/easy_connect.py @@ -15,13 +15,13 @@ # .................___________________________________________ # Have any idea/suggestion/bug report > send message on discord mr.smoothy#5824 -# Download modshttps://bombsquad-community.web.app/mods +# Download modshttps://bombsquad-community.web.app/mods # Discord:- # mr.smoothy#5824 # DONT EDIT ANYTHING WITHOUT PERMISSION -# join Bombsquad Community Server - +# join Bombsquad Community Server - # https://discord.gg/ucyaesh @@ -73,7 +73,6 @@ def is_game_version_lower_than(version): return game_version < version - def updateBannedServersCache(): response = None config = babase.app.config @@ -112,7 +111,7 @@ def run(self) -> None: except Exception: result = None babase.pushcall(lambda: self._call(result, self._port), - from_other_thread=True) + from_other_thread=True) def newbuild_favorites_tab(self, region_height: float) -> None: @@ -148,45 +147,45 @@ def newbuild_favorites_tab(self, region_height: float) -> None: # ================= smoothy ============= bui.textwidget(parent=self._container, - position=(90 if uiscale is babase.UIScale.SMALL else 120, btnv + - 120 if uiscale is babase.UIScale.SMALL else btnv+90), - size=(0, 0), - h_align='center', - color=(0.8, 0.8, 0.8), - v_align='top', - text="Auto") + position=(90 if uiscale is babase.UIScale.SMALL else 120, btnv + + 120 if uiscale is babase.UIScale.SMALL else btnv+90), + size=(0, 0), + h_align='center', + color=(0.8, 0.8, 0.8), + v_align='top', + text="Auto") btnv += 50 if uiscale is babase.UIScale.SMALL else 0 bui.buttonwidget(parent=self._container, - size=(30, 30), - position=(25 if uiscale is babase.UIScale.SMALL else 40, - btnv+10), - - color=(0.6, 0.53, 0.63), - textcolor=(0.75, 0.7, 0.8), - on_activate_call=self.auto_retry_dec, - text_scale=1.3 if uiscale is babase.UIScale.SMALL else 1.2, - label="-", - autoselect=True) + size=(30, 30), + position=(25 if uiscale is babase.UIScale.SMALL else 40, + btnv+10), + + color=(0.6, 0.53, 0.63), + textcolor=(0.75, 0.7, 0.8), + on_activate_call=self.auto_retry_dec, + text_scale=1.3 if uiscale is babase.UIScale.SMALL else 1.2, + label="-", + autoselect=True) self.retry_inter_text = bui.textwidget(parent=self._container, - position=( - 90 if uiscale is babase.UIScale.SMALL else 120, btnv+25), - size=(0, 0), - h_align='center', - color=(0.8, 0.8, 0.8), - v_align='center', - text=str(self.retry_inter) if self.retry_inter > 0.0 else 'off') + position=( + 90 if uiscale is babase.UIScale.SMALL else 120, btnv+25), + size=(0, 0), + h_align='center', + color=(0.8, 0.8, 0.8), + v_align='center', + text=str(self.retry_inter) if self.retry_inter > 0.0 else 'off') bui.buttonwidget(parent=self._container, - size=(30, 30), - position=(125 if uiscale is babase.UIScale.SMALL else 155, - btnv+10), + size=(30, 30), + position=(125 if uiscale is babase.UIScale.SMALL else 155, + btnv+10), - color=(0.6, 0.53, 0.63), - textcolor=(0.75, 0.7, 0.8), - on_activate_call=self.auto_retry_inc, - text_scale=1.3 if uiscale is babase.UIScale.SMALL else 1.2, - label="+", - autoselect=True) + color=(0.6, 0.53, 0.63), + textcolor=(0.75, 0.7, 0.8), + on_activate_call=self.auto_retry_inc, + text_scale=1.3 if uiscale is babase.UIScale.SMALL else 1.2, + label="+", + autoselect=True) btnv -= b_height + b_space_extra @@ -203,31 +202,31 @@ def newbuild_favorites_tab(self, region_height: float) -> None: autoselect=True) if uiscale is babase.UIScale.SMALL and bui.app.ui_v1.use_toolbars: bui.widget(edit=btn1, - left_widget=bui.get_special_widget('back_button')) + left_widget=bui.get_special_widget('back_button')) btnv -= b_height + b_space_extra bui.buttonwidget(parent=self._container, - size=(b_width, b_height), - position=(25 if uiscale is babase.UIScale.SMALL else 40, - btnv), - button_type='square', - color=(0.6, 0.53, 0.63), - textcolor=(0.75, 0.7, 0.8), - on_activate_call=self._on_favorites_edit_press, - text_scale=1.0 if uiscale is babase.UIScale.SMALL else 1.2, - label=babase.Lstr(resource='editText'), - autoselect=True) + size=(b_width, b_height), + position=(25 if uiscale is babase.UIScale.SMALL else 40, + btnv), + button_type='square', + color=(0.6, 0.53, 0.63), + textcolor=(0.75, 0.7, 0.8), + on_activate_call=self._on_favorites_edit_press, + text_scale=1.0 if uiscale is babase.UIScale.SMALL else 1.2, + label=babase.Lstr(resource='editText'), + autoselect=True) btnv -= b_height + b_space_extra bui.buttonwidget(parent=self._container, - size=(b_width, b_height), - position=(25 if uiscale is babase.UIScale.SMALL else 40, - btnv), - button_type='square', - color=(0.6, 0.53, 0.63), - textcolor=(0.75, 0.7, 0.8), - on_activate_call=self._on_favorite_delete_press, - text_scale=1.0 if uiscale is babase.UIScale.SMALL else 1.2, - label=babase.Lstr(resource='deleteText'), - autoselect=True) + size=(b_width, b_height), + position=(25 if uiscale is babase.UIScale.SMALL else 40, + btnv), + button_type='square', + color=(0.6, 0.53, 0.63), + textcolor=(0.75, 0.7, 0.8), + on_activate_call=self._on_favorite_delete_press, + text_scale=1.0 if uiscale is babase.UIScale.SMALL else 1.2, + label=babase.Lstr(resource='deleteText'), + autoselect=True) v -= sub_scroll_height + 23 self._scrollwidget = scrlw = bui.scrollwidget( @@ -236,12 +235,12 @@ def newbuild_favorites_tab(self, region_height: float) -> None: size=(sub_scroll_width, sub_scroll_height), claims_left_right=True) bui.widget(edit=self._favorites_connect_button, - right_widget=self._scrollwidget) + right_widget=self._scrollwidget) self._columnwidget = bui.columnwidget(parent=scrlw, - left_border=10, - border=2, - margin=0, - claims_left_right=True) + left_border=10, + border=2, + margin=0, + claims_left_right=True) self._favorite_selected = None self._refresh_favorites() @@ -323,9 +322,8 @@ def _clear(self) -> None: self._stats_button ]: if widget: - + widget.delete() - def update(self, index: int, party: PartyEntry, sub_scroll_width: float, @@ -333,127 +331,128 @@ def update(self, index: int, party: PartyEntry, sub_scroll_width: float, columnwidget: bui.Widget, join_text: bui.Widget, filter_text: bui.Widget, existing_selection: Optional[Selection], tab: PublicGatherTab) -> None: - """Update for the given data.""" - # pylint: disable=too-many-locals - - # Quick-out: if we've been marked clean for a certain index and - # we're still at that index, we're done. - plus = bui.app.plus - assert plus is not None - - # Quick-out: if we've been marked clean for a certain index and - # we're still at that index, we're done. - if party.clean_display_index == index: - return - - ping_good = plus.get_v1_account_misc_read_val('pingGood', 100) - ping_med = plus.get_v1_account_misc_read_val('pingMed', 500) - - self._clear() - hpos = 20 - vpos = sub_scroll_height - lineheight * index - 50 - self._name_widget = bui.textwidget( - text=bui.Lstr(value=party.name), + """Update for the given data.""" + # pylint: disable=too-many-locals + + # Quick-out: if we've been marked clean for a certain index and + # we're still at that index, we're done. + plus = bui.app.plus + assert plus is not None + + # Quick-out: if we've been marked clean for a certain index and + # we're still at that index, we're done. + if party.clean_display_index == index: + return + + ping_good = plus.get_v1_account_misc_read_val('pingGood', 100) + ping_med = plus.get_v1_account_misc_read_val('pingMed', 500) + + self._clear() + hpos = 20 + vpos = sub_scroll_height - lineheight * index - 50 + self._name_widget = bui.textwidget( + text=bui.Lstr(value=party.name), + parent=columnwidget, + size=(sub_scroll_width * 0.63, 20), + position=(0 + hpos, 4 + vpos), + selectable=True, + on_select_call=bui.WeakCall( + tab.set_public_party_selection, + Selection(party.get_key(), SelectionComponent.NAME), + ), + on_activate_call=bui.WeakCall(tab.on_public_party_activate, party), + click_activate=True, + maxwidth=sub_scroll_width * 0.45, + corner_scale=1.4, + autoselect=True, + color=(1, 1, 1, 0.3 if party.ping is None else 1.0), + h_align='left', + v_align='center', + ) + bui.widget( + edit=self._name_widget, + left_widget=join_text, + show_buffer_top=64.0, + show_buffer_bottom=64.0, + ) + if existing_selection == Selection( + party.get_key(), SelectionComponent.NAME + ): + bui.containerwidget( + edit=columnwidget, selected_child=self._name_widget + ) + if party.stats_addr or True: + url = party.stats_addr.replace( + '${ACCOUNT}', + plus.get_v1_account_misc_read_val_2( + 'resolvedAccountID', 'UNKNOWN' + ), + ) + self._stats_button = bui.buttonwidget( + color=(0.3, 0.6, 0.94), + textcolor=(1.0, 1.0, 1.0), + label='....', parent=columnwidget, - size=(sub_scroll_width * 0.63, 20), - position=(0 + hpos, 4 + vpos), - selectable=True, + autoselect=True, + on_activate_call=bui.Call(bui.open_url, url), on_select_call=bui.WeakCall( tab.set_public_party_selection, - Selection(party.get_key(), SelectionComponent.NAME), + Selection(party.get_key(), SelectionComponent.STATS_BUTTON), ), - on_activate_call=bui.WeakCall(tab.on_public_party_activate, party), - click_activate=True, - maxwidth=sub_scroll_width * 0.45, - corner_scale=1.4, - autoselect=True, - color=(1, 1, 1, 0.3 if party.ping is None else 1.0), - h_align='left', - v_align='center', - ) - bui.widget( - edit=self._name_widget, - left_widget=join_text, - show_buffer_top=64.0, - show_buffer_bottom=64.0, + size=(120, 40), + position=(sub_scroll_width * 0.66 + hpos, 1 + vpos), + scale=0.9, ) + bui.buttonwidget(edit=self._stats_button, on_activate_call=bui.WeakCall( + self.on_stats_click, self._stats_button, party)) if existing_selection == Selection( - party.get_key(), SelectionComponent.NAME + party.get_key(), SelectionComponent.STATS_BUTTON ): bui.containerwidget( - edit=columnwidget, selected_child=self._name_widget + edit=columnwidget, selected_child=self._stats_button ) - if party.stats_addr or True: - url = party.stats_addr.replace( - '${ACCOUNT}', - plus.get_v1_account_misc_read_val_2( - 'resolvedAccountID', 'UNKNOWN' - ), - ) - self._stats_button = bui.buttonwidget( - color=(0.3, 0.6, 0.94), - textcolor=(1.0, 1.0, 1.0), - label='....', - parent=columnwidget, - autoselect=True, - on_activate_call=bui.Call(bui.open_url, url), - on_select_call=bui.WeakCall( - tab.set_public_party_selection, - Selection(party.get_key(), SelectionComponent.STATS_BUTTON), - ), - size=(120, 40), - position=(sub_scroll_width * 0.66 + hpos, 1 + vpos), - scale=0.9, - ) - bui.buttonwidget(edit=self._stats_button, on_activate_call=bui.WeakCall( - self.on_stats_click, self._stats_button, party)) - if existing_selection == Selection( - party.get_key(), SelectionComponent.STATS_BUTTON - ): - bui.containerwidget( - edit=columnwidget, selected_child=self._stats_button - ) - - self._size_widget = bui.textwidget( - text=str(party.size) + '/' + str(party.size_max), - parent=columnwidget, - size=(0, 0), - position=(sub_scroll_width * 0.86 + hpos, 20 + vpos), - scale=0.7, - color=(0.8, 0.8, 0.8), - h_align='right', - v_align='center', - ) - if index == 0: - bui.widget(edit=self._name_widget, up_widget=filter_text) - if self._stats_button: - bui.widget(edit=self._stats_button, up_widget=filter_text) + self._size_widget = bui.textwidget( + text=str(party.size) + '/' + str(party.size_max), + parent=columnwidget, + size=(0, 0), + position=(sub_scroll_width * 0.86 + hpos, 20 + vpos), + scale=0.7, + color=(0.8, 0.8, 0.8), + h_align='right', + v_align='center', + ) - self._ping_widget = bui.textwidget( - parent=columnwidget, - size=(0, 0), - position=(sub_scroll_width * 0.94 + hpos, 20 + vpos), - scale=0.7, - h_align='right', - v_align='center', + if index == 0: + bui.widget(edit=self._name_widget, up_widget=filter_text) + if self._stats_button: + bui.widget(edit=self._stats_button, up_widget=filter_text) + + self._ping_widget = bui.textwidget( + parent=columnwidget, + size=(0, 0), + position=(sub_scroll_width * 0.94 + hpos, 20 + vpos), + scale=0.7, + h_align='right', + v_align='center', + ) + if party.ping is None: + bui.textwidget( + edit=self._ping_widget, text='-', color=(0.5, 0.5, 0.5) ) - if party.ping is None: - bui.textwidget( - edit=self._ping_widget, text='-', color=(0.5, 0.5, 0.5) - ) - else: - bui.textwidget( - edit=self._ping_widget, - text=str(int(party.ping)), - color=(0, 1, 0) - if party.ping <= ping_good - else (1, 1, 0) - if party.ping <= ping_med - else (1, 0, 0), - ) + else: + bui.textwidget( + edit=self._ping_widget, + text=str(int(party.ping)), + color=(0, 1, 0) + if party.ping <= ping_good + else (1, 1, 0) + if party.ping <= ping_med + else (1, 0, 0), + ) + + party.clean_display_index = index - party.clean_display_index = index def _get_popup_window_scale() -> float: uiscale = bui.app.ui_v1.uiscale @@ -501,7 +500,7 @@ def popup_menu_selected_choice(self, window: popup.PopupMenu, url = _party.stats_addr.replace( '${ACCOUNT}', plus.get_v1_account_misc_read_val_2('resolvedAccountID', - 'UNKNOWN')) + 'UNKNOWN')) bui.open_url(url) elif choice == 'connect': PartyQuickConnect(_party.address, _party.port) @@ -614,17 +613,17 @@ def __init__(self, address: str, port: int): scale=(1.4 if uiscale is babase.UIScale.SMALL else 1.2 if uiscale is babase.UIScale.MEDIUM else 1.0))) self._cancel_button = bui.buttonwidget(parent=self._root_widget, - scale=1.0, - position=(60, self._height - 80), - size=(50, 50), - label='', - on_activate_call=self.close, - autoselect=True, - color=(0.45, 0.63, 0.15), - icon=bui.gettexture('crossOut'), - iconscale=1.2) + scale=1.0, + position=(60, self._height - 80), + size=(50, 50), + label='', + on_activate_call=self.close, + autoselect=True, + color=(0.45, 0.63, 0.15), + icon=bui.gettexture('crossOut'), + iconscale=1.2) bui.containerwidget(edit=self._root_widget, - cancel_button=self._cancel_button) + cancel_button=self._cancel_button) self.IP = bui.textwidget( parent=self._root_widget, diff --git a/plugins/utilities/pro_unlocker.py b/plugins/utilities/pro_unlocker.py index 389140f7..bac31447 100644 --- a/plugins/utilities/pro_unlocker.py +++ b/plugins/utilities/pro_unlocker.py @@ -4,8 +4,23 @@ import babase +def is_game_version_lower_than(version): + """ + Returns a boolean value indicating whether the current game + version is lower than the passed version. Useful for addressing + any breaking changes within game versions. + """ + game_version = tuple(map(int, babase.app.version.split("."))) + version = tuple(map(int, version.split("."))) + return game_version < version + + +if is_game_version_lower_than("1.7.20"): + original_get_purchased = _baplus.get_purchased +else: + assert bs.app.plus is not None + original_get_purchased = bs.app.plus.get_purchased -original_get_purchased = _baplus.get_purchased def get_purchased(item): if item.startswith('characters.') or item.startswith('icons.'): @@ -17,5 +32,8 @@ def get_purchased(item): class Unlock(babase.Plugin): def on_app_running(self): babase.app.classic.accounts.have_pro = lambda: True - _baplus.get_purchased = get_purchased - \ No newline at end of file + if is_game_version_lower_than("1.7.20"): + _baplus.get_purchased = get_purchased + else: + assert bs.app.plus is not None + bs.app.plus.get_purchased = get_purchased diff --git a/plugins/utilities/server_switch.py b/plugins/utilities/server_switch.py index ba4ffdcf..aacb0fe7 100644 --- a/plugins/utilities/server_switch.py +++ b/plugins/utilities/server_switch.py @@ -1,108 +1,575 @@ -# -*- coding: utf-8 -*- +# discord @mr.smoothy#5824 + # ba_meta require api 8 -''' -Server Switch Plugin by My.Smoothy -Let you switch recently joined servers very quickly -+ Added button to quicky look into public server list without leaving current game. - -discord: mr.smoothy -https://discord.gg/ucyaesh -Youtube : Hey Smoothy -Download more mods from -https://bombsquad-community.web.app/mods -''' + +from __future__ import annotations +import copy +import time +from typing import TYPE_CHECKING + import babase -import bauiv1lib.mainmenu as bastd_ui_mainmenu import bauiv1 as bui import bascenev1 as bs -current_server_ip = "127.0.0.1" -current_server_port = 43210 -servers = [] -def _refresh_in_game(func): - def wrapper(self, *args, **kwargs): - returnValue = func(self, *args, **kwargs) - uiscale = bui.app.ui_v1.uiscale - bui.containerwidget( - edit=self._root_widget, - size=(self._width*2, self._height), # double the width - scale=( - 2.15 - if uiscale is bui.UIScale.SMALL - else 1.6 - if uiscale is bui.UIScale.MEDIUM - else 1.0 - ), - ) - h = 125 - v = self._height - 60.0 - bui.textwidget( +import _bascenev1 as _bs +import time +import threading +from enum import Enum +from dataclasses import dataclass +if TYPE_CHECKING: + from typing import Any, Optional, Dict, List, Tuple, Type + import bascenev1 as bs + from bauiv1lib.gather import GatherWindow + +from bauiv1lib.confirm import ConfirmWindow + +import bauiv1lib.mainmenu as bastd_ui_mainmenu + +connect = bs.connect_to_party +disconnect = bs.disconnect_from_host + +server = [] + +ip_add = "private" +p_port = 44444 +p_name = "nothing here" + + +def newconnect_to_party(address, port=43210, print_progress=False): + global ip_add + global p_port + dd = _bs.get_connection_to_host_info() + if (dd != {}): + _bs.disconnect_from_host() + + ip_add = address + p_port = port + connect(address, port, print_progress) + else: + + ip_add = address + p_port = port + # print(ip_add,p_port) + connect(ip_add, port, print_progress) + + +def newdisconnect_from_host(): + try: + name = _bs.get_connection_to_host_info()['name'] + global server + global ip_add + global p_port + pojo = {"name": name, "ip": ip_add, "port": p_port} + if pojo not in server: + server.insert(0, pojo) + server = server[:3] + except: + pass + disconnect() + + +def printip(): + bs.screenmessage("ip address is"+ip_add) + + +def new_refresh_in_game( + self, positions: List[Tuple[float, float, + float]]) -> Tuple[float, float, float]: + # pylint: disable=too-many-branches + # pylint: disable=too-many-locals + # pylint: disable=too-many-statements + custom_menu_entries: List[Dict[str, Any]] = [] + session = _bs.get_foreground_host_session() + if session is not None: + try: + custom_menu_entries = session.get_custom_menu_entries() + for cme in custom_menu_entries: + if (not isinstance(cme, dict) or 'label' not in cme + or not isinstance(cme['label'], (str, bs.Lstr)) + or 'call' not in cme or not callable(cme['call'])): + raise ValueError('invalid custom menu entry: ' + + str(cme)) + except Exception: + custom_menu_entries = [] + babase.print_exception( + f'Error getting custom menu entries for {session}') + self._width = 250.0 + self._height = 250.0 if self._input_player else 180.0 + if (self._is_demo or self._is_arcade) and self._input_player: + self._height -= 40 + if not self._have_settings_button: + self._height -= 50 + if self._connected_to_remote_player: + # In this case we have a leave *and* a disconnect button. + self._height += 50 + self._height += 50 * (len(custom_menu_entries)) + uiscale = bui.app.ui_v1.uiscale + bui.containerwidget( + edit=self._root_widget, + size=(self._width*2, self._height), + scale=(2.15 if uiscale is bui.UIScale.SMALL else + 1.6 if uiscale is bui.UIScale.MEDIUM else 1.0)) + h = 125.0 + v = (self._height - 80.0 if self._input_player else self._height - 60) + h_offset = 0 + d_h_offset = 0 + v_offset = -50 + for _i in range(6 + len(custom_menu_entries)): + positions.append((h, v, 1.0)) + v += v_offset + h += h_offset + h_offset += d_h_offset + self._start_button = None + bui.app.pause() + h, v, scale = positions[self._p_index] + bui.textwidget( parent=self._root_widget, draw_controller=None, - text="IP: "+current_server_ip+" PORT: "+str(current_server_port), - position=(h-self._button_width/2 + 130 , v+60), + text="IP: "+ip_add+" PORT: "+str(p_port), + position=(h+self._button_width-80, v+60), h_align='center', v_align='center', size=(20, 60), scale=0.6) - self._public_servers = bui.buttonwidget( - color=(0.8, 0.45, 1), + v_h = v + + global server + + def con(address, port): + global ip_add + global p_port + if (address == ip_add and port == p_port): + self._resume() + else: + _bs.disconnect_from_host() + _bs.connect_to_party(address, port) + if len(server) == 0: + bui.textwidget( + parent=self._root_widget, + draw_controller=None, + text="Nothing in \n recents", + position=(h + self._button_width * scale, v-30), + h_align='center', + v_align='center', + size=(20, 60), + scale=1) + for ser in server: + self._server_button = bui.buttonwidget( + color=(0.8, 0, 1), + parent=self._root_widget, + position=(h + self._button_width * scale - 80, v_h), + size=(self._button_width, self._button_height), + scale=scale, + autoselect=self._use_autoselect, + label=ser["name"][0:22], + + on_activate_call=bs.Call(con, ser["ip"], ser["port"])) + v_h = v_h-50 + + # Player name if applicable. + if self._input_player: + player_name = self._input_player.getname() + h, v, scale = positions[self._p_index] + v += 35 + bui.textwidget(parent=self._root_widget, + position=(h - self._button_width / 2, v), + size=(self._button_width, self._button_height), + color=(1, 1, 1, 0.5), + scale=0.7, + h_align='center', + text=bs.Lstr(value=player_name)) + else: + player_name = '' + h, v, scale = positions[self._p_index] + self._p_index += 1 + btn = bui.buttonwidget(parent=self._root_widget, + position=(h - self._button_width / 2, v), + size=(self._button_width, self._button_height), + scale=scale, + label=bs.Lstr(resource=self._r + '.resumeText'), + autoselect=self._use_autoselect, + on_activate_call=self._resume) + bui.containerwidget(edit=self._root_widget, cancel_button=btn) + + # Add any custom options defined by the current game. + for entry in custom_menu_entries: + h, v, scale = positions[self._p_index] + self._p_index += 1 + + # Ask the entry whether we should resume when we call + # it (defaults to true). + resume = bool(entry.get('resume_on_call', True)) + + if resume: + call = bs.Call(self._resume_and_call, entry['call']) + else: + call = bs.Call(entry['call'], bs.WeakCall(self._resume)) + + bui.buttonwidget(parent=self._root_widget, + position=(h - self._button_width / 2, v), + size=(self._button_width, self._button_height), + scale=scale, + on_activate_call=call, + label=entry['label'], + autoselect=self._use_autoselect) + # Add a 'leave' button if the menu-owner has a player. + if ((self._input_player or self._connected_to_remote_player) + and not (self._is_demo or self._is_arcade)): + h, v, scale = positions[self._p_index] + self._p_index += 1 + btn = bui.buttonwidget(parent=self._root_widget, + position=(h - self._button_width / 2, v), + size=(self._button_width, + self._button_height), + scale=scale, + on_activate_call=self._leave, + label='', + autoselect=self._use_autoselect) + + if (player_name != '' and player_name[0] != '<' + and player_name[-1] != '>'): + txt = bs.Lstr(resource=self._r + '.justPlayerText', + subs=[('${NAME}', player_name)]) + else: + txt = bs.Lstr(value=player_name) + bui.textwidget(parent=self._root_widget, + position=(h, v + self._button_height * + (0.64 if player_name != '' else 0.5)), + size=(0, 0), + text=bs.Lstr(resource=self._r + '.leaveGameText'), + scale=(0.83 if player_name != '' else 1.0), + color=(0.75, 1.0, 0.7), + h_align='center', + v_align='center', + draw_controller=btn, + maxwidth=self._button_width * 0.9) + bui.textwidget(parent=self._root_widget, + position=(h, v + self._button_height * 0.27), + size=(0, 0), + text=txt, + color=(0.75, 1.0, 0.7), + h_align='center', + v_align='center', + draw_controller=btn, + scale=0.45, + maxwidth=self._button_width * 0.9) + return h, v, scale + + +def new_refresh(self) -> None: + # pylint: disable=too-many-branches + # pylint: disable=too-many-locals + # pylint: disable=too-many-statements + global server + print(server) + from bauiv1lib.confirm import QuitWindow + from bauiv1lib.store.button import StoreButton + import bascenev1 as bs + import _bascenev1 as _bs + import bauiv1 as bui + import _baplus + # Clear everything that was there. + children = self._root_widget.get_children() + for child in children: + child.delete() + + self._tdelay = 0.0 + self._t_delay_inc = 0.0 + self._t_delay_play = 0.0 + self._button_width = 200.0 + self._button_height = 45.0 + + self._r = 'mainMenu' + + assert bs.app.classic is not None + app = bs.app.classic + self._have_quit_button = (bui.app.ui_v1.uiscale is bui.UIScale.LARGE + or (app.platform == 'windows' + and app.subplatform == 'oculus')) + + self._have_store_button = not self._in_game + + self._have_settings_button = ( + (not self._in_game or not bui.app.toolbar_test) + and not (self._is_demo or self._is_arcade or self._is_iircade)) + + self._input_device = input_device = _bs.get_ui_input_device() + self._input_player = input_device.player if input_device else None + self._connected_to_remote_player = ( + input_device.is_attached_to_player() + if input_device else False) + + positions: List[Tuple[float, float, float]] = [] + self._p_index = 0 + + if self._in_game: + h, v, scale = self._refresh_in_game(positions) + print("refreshing in GAME", ip_add) + # btn = bui.buttonwidget(parent=self._root_widget, + # position=(80,270), + # size=(100, 90), + # scale=1.2, + # label=ip_add, + # autoselect=None, + # on_activate_call=printip) + bui.textwidget( + parent=self._root_widget, + draw_controller=None, + text="IP: "+ip_add+" PORT: "+str(p_port), + position=(150, 270), + h_align='center', + v_align='center', + size=(20, 60), + scale=1) + self._server_button = bui.buttonwidget( + parent=self._root_widget, + position=(h * 3.2 + 20 - self._button_width * scale, v), + size=(self._button_width, self._button_height), + scale=scale, + autoselect=self._use_autoselect, + label=bs.Lstr(resource=self._r + '.settingsText'), + transition_delay=self._tdelay, + on_activate_call=self._settings) + self._server_button2 = bui.buttonwidget( + parent=self._root_widget, + position=(h * 3.2 + 20 - self._button_width * scale, v-50), + size=(self._button_width, self._button_height), + scale=scale, + autoselect=self._use_autoselect, + label=bs.Lstr(resource=self._r + '.settingsText'), + transition_delay=self._tdelay, + on_activate_call=self._settings) + self._server_button3 = bui.buttonwidget( + parent=self._root_widget, + position=(h * 3.2 + 20 - self._button_width * scale, v-100), + size=(self._button_width, self._button_height), + scale=scale, + autoselect=self._use_autoselect, + label=bs.Lstr(resource=self._r + '.settingsText'), + transition_delay=self._tdelay, + on_activate_call=self._settings) + + else: + h, v, scale = self._refresh_not_in_game(positions) + + if self._have_settings_button: + h, v, scale = positions[self._p_index] + self._p_index += 1 + self._settings_button = bui.buttonwidget( + parent=self._root_widget, + position=(h - self._button_width * 0.5 * scale, v), + size=(self._button_width, self._button_height), + scale=scale, + autoselect=self._use_autoselect, + label=bs.Lstr(resource=self._r + '.settingsText'), + transition_delay=self._tdelay, + on_activate_call=self._settings) + + # Scattered eggs on easter. + if _baplus.get_v1_account_misc_read_val('easter', + False) and not self._in_game: + icon_size = 34 + bui.imagewidget(parent=self._root_widget, + position=(h - icon_size * 0.5 - 15, + v + self._button_height * scale - + icon_size * 0.24 + 1.5), + transition_delay=self._tdelay, + size=(icon_size, icon_size), + texture=bui.gettexture('egg3'), + tilt_scale=0.0) + + self._tdelay += self._t_delay_inc + + if self._in_game: + h, v, scale = positions[self._p_index] + self._p_index += 1 + + # If we're in a replay, we have a 'Leave Replay' button. + if _bs.is_in_replay(): + bui.buttonwidget(parent=self._root_widget, + position=(h - self._button_width * 0.5 * scale, + v), + scale=scale, + size=(self._button_width, self._button_height), + autoselect=self._use_autoselect, + label=bs.Lstr(resource='replayEndText'), + on_activate_call=self._confirm_end_replay) + elif _bs.get_foreground_host_session() is not None: + bui.buttonwidget( parent=self._root_widget, - position=(h+self._button_width-10, v+60+20), - size=(self._button_width/4, self._button_height/2), - scale=1.0, + position=(h - self._button_width * 0.5 * scale, v), + scale=scale, + size=(self._button_width, self._button_height), autoselect=self._use_autoselect, - label="~~~", - on_activate_call=bs.Call(public_servers)) - for server in servers: - self._server_button = bui.buttonwidget( - color=(0.8, 0, 1), + label=bs.Lstr(resource=self._r + '.endGameText'), + on_activate_call=self._confirm_end_game) + # Assume we're in a client-session. + else: + bui.buttonwidget( parent=self._root_widget, - position=( (h- self._button_width / 2 ) + self._button_width + 20, v), + position=(h - self._button_width * 0.5 * scale, v), + scale=scale, size=(self._button_width, self._button_height), - scale=1.0, autoselect=self._use_autoselect, - label=server["name"][0:22], - on_activate_call=bs.Call(bs.connect_to_party, server["ip"], server["port"])) - - v -= 50 - - return returnValue - return wrapper + label=bs.Lstr(resource=self._r + '.leavePartyText'), + on_activate_call=self._confirm_leave_party) -connect = bs.connect_to_party -def connect_to_party(address, port=43210, print_progress=False): - global current_server_ip - global current_server_port - if (bs.get_connection_to_host_info() != {}): - bs.disconnect_from_host() - current_server_ip = address - current_server_port = port - connect(address, port, print_progress) - babase.apptimer(1, check_connect_status) - -def check_connect_status(): - global servers - global current_server_ip - global current_server_port - if (bs.get_connection_to_host_info() != {}): - if (not bs.get_connection_to_host_info()['name']): - babase.apptimer(1, check_connect_status) - return - new_server = {"name": bs.get_connection_to_host_info()['name'], "ip": current_server_ip, "port": current_server_port} - if new_server not in servers: - servers.append(new_server) - servers = servers[-3:] + self._store_button: Optional[bui.Widget] + if self._have_store_button: + this_b_width = self._button_width + h, v, scale = positions[self._p_index] + self._p_index += 1 + + sbtn = self._store_button_instance = StoreButton( + parent=self._root_widget, + position=(h - this_b_width * 0.5 * scale, v), + size=(this_b_width, self._button_height), + scale=scale, + on_activate_call=bs.WeakCall(self._on_store_pressed), + sale_scale=1.3, + transition_delay=self._tdelay) + self._store_button = store_button = sbtn.get_button() + uiscale = bui.app.ui_v1.uiscale + icon_size = (55 if uiscale is bui.UIScale.SMALL else + 55 if uiscale is bui.UIScale.MEDIUM else 70) + bui.imagewidget( + parent=self._root_widget, + position=(h - icon_size * 0.5, + v + self._button_height * scale - icon_size * 0.23), + transition_delay=self._tdelay, + size=(icon_size, icon_size), + texture=bui.gettexture(self._store_char_tex), + tilt_scale=0.0, + draw_controller=store_button) + + self._tdelay += self._t_delay_inc else: - print("connection failed falling back to gather window") - public_servers() + self._store_button = None + + self._quit_button: Optional[bui.Widget] + if not self._in_game and self._have_quit_button: + h, v, scale = positions[self._p_index] + self._p_index += 1 + self._quit_button = quit_button = bui.buttonwidget( + parent=self._root_widget, + autoselect=self._use_autoselect, + position=(h - self._button_width * 0.5 * scale, v), + size=(self._button_width, self._button_height), + scale=scale, + label=bs.Lstr(resource=self._r + + ('.quitText' if 'Mac' in + bs.app.classic.legacy_user_agent_string else '.exitGameText')), + on_activate_call=self._quit, + transition_delay=self._tdelay) + + # Scattered eggs on easter. + if _baplus.get_v1_account_misc_read_val('easter', False): + icon_size = 30 + bui.imagewidget(parent=self._root_widget, + position=(h - icon_size * 0.5 + 25, + v + self._button_height * scale - + icon_size * 0.24 + 1.5), + transition_delay=self._tdelay, + size=(icon_size, icon_size), + texture=bui.gettexture('egg1'), + tilt_scale=0.0) + + bui.containerwidget(edit=self._root_widget, + cancel_button=quit_button) + self._tdelay += self._t_delay_inc + else: + self._quit_button = None + + # If we're not in-game, have no quit button, and this is android, + # we want back presses to quit our activity. + if (not self._in_game and not self._have_quit_button + and bs.app.classic.platform == 'android'): + + def _do_quit() -> None: + QuitWindow(swish=True, back=True) + + bui.containerwidget(edit=self._root_widget, + on_cancel_call=_do_quit) + + # Add speed-up/slow-down buttons for replays. + # (ideally this should be part of a fading-out playback bar like most + # media players but this works for now). + if _bs.is_in_replay(): + b_size = 50.0 + b_buffer = 10.0 + t_scale = 0.75 + uiscale = bui.app.ui_v1.uiscale + if uiscale is bui.UIScale.SMALL: + b_size *= 0.6 + b_buffer *= 1.0 + v_offs = -40 + t_scale = 0.5 + elif uiscale is bui.UIScale.MEDIUM: + v_offs = -70 + else: + v_offs = -100 + self._replay_speed_text = bui.textwidget( + parent=self._root_widget, + text=bs.Lstr(resource='watchWindow.playbackSpeedText', + subs=[('${SPEED}', str(1.23))]), + position=(h, v + v_offs + 7 * t_scale), + h_align='center', + v_align='center', + size=(0, 0), + scale=t_scale) + + # Update to current value. + self._change_replay_speed(0) + + # Keep updating in a timer in case it gets changed elsewhere. + self._change_replay_speed_timer = bs.Timer( + 0.25, + bs.WeakCall(self._change_replay_speed, 0), + repeat=True) + btn = bui.buttonwidget(parent=self._root_widget, + position=(h - b_size - b_buffer, + v - b_size - b_buffer + v_offs), + button_type='square', + size=(b_size, b_size), + label='', + autoselect=True, + on_activate_call=bs.Call( + self._change_replay_speed, -1)) + bui.textwidget( + parent=self._root_widget, + draw_controller=btn, + text='-', + position=(h - b_size * 0.5 - b_buffer, + v - b_size * 0.5 - b_buffer + 5 * t_scale + v_offs), + h_align='center', + v_align='center', + size=(0, 0), + scale=3.0 * t_scale) + btn = bui.buttonwidget( + parent=self._root_widget, + position=(h + b_buffer, v - b_size - b_buffer + v_offs), + button_type='square', + size=(b_size, b_size), + label='', + autoselect=True, + on_activate_call=bs.Call(self._change_replay_speed, 1)) + bui.textwidget( + parent=self._root_widget, + draw_controller=btn, + text='+', + position=(h + b_size * 0.5 + b_buffer, + v - b_size * 0.5 - b_buffer + 5 * t_scale + v_offs), + h_align='center', + v_align='center', + size=(0, 0), + scale=3.0 * t_scale) -def public_servers(origin = None): - from bauiv1lib.gather import GatherWindow - bui.app.ui_v1.set_main_menu_window( GatherWindow(origin_widget=origin).get_root_widget()) # ba_meta export plugin class bySmoothy(babase.Plugin): def __init__(self): - bastd_ui_mainmenu.MainMenuWindow._refresh_in_game = _refresh_in_game(bastd_ui_mainmenu.MainMenuWindow._refresh_in_game) - bs.connect_to_party = connect_to_party - \ No newline at end of file + if babase.env().get("build_number", 0) >= 21140: + bastd_ui_mainmenu.MainMenuWindow._refresh_in_game = new_refresh_in_game + bs.connect_to_party = newconnect_to_party + bs.disconnect_from_host = newdisconnect_from_host + else: + print("Server Switch only works on bs 1.7.20 and above") From ed88413c43f058cd21951c17add1a2ad29b0b5fb Mon Sep 17 00:00:00 2001 From: imayushsaini Date: Sat, 8 Jul 2023 10:24:14 +0000 Subject: [PATCH 0546/1464] [ci] auto-format --- plugins/utilities/server_switch.py | 64 +++++++++++++++++------------- 1 file changed, 37 insertions(+), 27 deletions(-) diff --git a/plugins/utilities/server_switch.py b/plugins/utilities/server_switch.py index ba4ffdcf..2dbc667f 100644 --- a/plugins/utilities/server_switch.py +++ b/plugins/utilities/server_switch.py @@ -18,13 +18,15 @@ current_server_ip = "127.0.0.1" current_server_port = 43210 servers = [] + + def _refresh_in_game(func): def wrapper(self, *args, **kwargs): returnValue = func(self, *args, **kwargs) uiscale = bui.app.ui_v1.uiscale bui.containerwidget( edit=self._root_widget, - size=(self._width*2, self._height), # double the width + size=(self._width*2, self._height), # double the width scale=( 2.15 if uiscale is bui.UIScale.SMALL @@ -36,40 +38,43 @@ def wrapper(self, *args, **kwargs): h = 125 v = self._height - 60.0 bui.textwidget( - parent=self._root_widget, - draw_controller=None, - text="IP: "+current_server_ip+" PORT: "+str(current_server_port), - position=(h-self._button_width/2 + 130 , v+60), - h_align='center', - v_align='center', - size=(20, 60), - scale=0.6) + parent=self._root_widget, + draw_controller=None, + text="IP: "+current_server_ip+" PORT: "+str(current_server_port), + position=(h-self._button_width/2 + 130, v+60), + h_align='center', + v_align='center', + size=(20, 60), + scale=0.6) self._public_servers = bui.buttonwidget( - color=(0.8, 0.45, 1), - parent=self._root_widget, - position=(h+self._button_width-10, v+60+20), - size=(self._button_width/4, self._button_height/2), - scale=1.0, - autoselect=self._use_autoselect, - label="~~~", - on_activate_call=bs.Call(public_servers)) + color=(0.8, 0.45, 1), + parent=self._root_widget, + position=(h+self._button_width-10, v+60+20), + size=(self._button_width/4, self._button_height/2), + scale=1.0, + autoselect=self._use_autoselect, + label="~~~", + on_activate_call=bs.Call(public_servers)) for server in servers: self._server_button = bui.buttonwidget( color=(0.8, 0, 1), parent=self._root_widget, - position=( (h- self._button_width / 2 ) + self._button_width + 20, v), + position=((h - self._button_width / 2) + self._button_width + 20, v), size=(self._button_width, self._button_height), scale=1.0, autoselect=self._use_autoselect, label=server["name"][0:22], on_activate_call=bs.Call(bs.connect_to_party, server["ip"], server["port"])) - + v -= 50 - - return returnValue + + return returnValue return wrapper + connect = bs.connect_to_party + + def connect_to_party(address, port=43210, print_progress=False): global current_server_ip global current_server_port @@ -79,7 +84,8 @@ def connect_to_party(address, port=43210, print_progress=False): current_server_port = port connect(address, port, print_progress) babase.apptimer(1, check_connect_status) - + + def check_connect_status(): global servers global current_server_ip @@ -88,7 +94,8 @@ def check_connect_status(): if (not bs.get_connection_to_host_info()['name']): babase.apptimer(1, check_connect_status) return - new_server = {"name": bs.get_connection_to_host_info()['name'], "ip": current_server_ip, "port": current_server_port} + new_server = {"name": bs.get_connection_to_host_info( + )['name'], "ip": current_server_ip, "port": current_server_port} if new_server not in servers: servers.append(new_server) servers = servers[-3:] @@ -96,13 +103,16 @@ def check_connect_status(): print("connection failed falling back to gather window") public_servers() -def public_servers(origin = None): + +def public_servers(origin=None): from bauiv1lib.gather import GatherWindow - bui.app.ui_v1.set_main_menu_window( GatherWindow(origin_widget=origin).get_root_widget()) + bui.app.ui_v1.set_main_menu_window(GatherWindow(origin_widget=origin).get_root_widget()) # ba_meta export plugin + + class bySmoothy(babase.Plugin): def __init__(self): - bastd_ui_mainmenu.MainMenuWindow._refresh_in_game = _refresh_in_game(bastd_ui_mainmenu.MainMenuWindow._refresh_in_game) + bastd_ui_mainmenu.MainMenuWindow._refresh_in_game = _refresh_in_game( + bastd_ui_mainmenu.MainMenuWindow._refresh_in_game) bs.connect_to_party = connect_to_party - \ No newline at end of file From 506f850283780028f2cd2e7d27064b9a41eaf93f Mon Sep 17 00:00:00 2001 From: Ayush Saini <36878972+imayushsaini@users.noreply.github.com> Date: Sat, 8 Jul 2023 15:56:34 +0530 Subject: [PATCH 0547/1464] updated utilities --- plugins/utilities.json | 14 ++------------ 1 file changed, 2 insertions(+), 12 deletions(-) diff --git a/plugins/utilities.json b/plugins/utilities.json index cee50f85..706cd6b0 100644 --- a/plugins/utilities.json +++ b/plugins/utilities.json @@ -422,12 +422,7 @@ } ], "versions": { - "2.0.0": { - "api_version": 8, - "commit_sha": "bf3e61b", - "released_on": "04-07-2023", - "md5sum": "289cc852b7f0ec1b254d08267c9921c2" - }, + "2.0.0": null, "1.0.1": { "api_version": 7, "commit_sha": "64e8a5c", @@ -522,12 +517,7 @@ } ], "versions": { - "2.0.0": { - "api_version": 8, - "commit_sha": "a0239a9", - "released_on": "04-07-2023", - "md5sum": "187a9894158721c8fa1ecee9e3e38e73" - }, + "2.0.0": null, "1.0.0": { "api_version": 7, "commit_sha": "41e239c", From bae5ca90102c16eccbf817e50a001ab14694969d Mon Sep 17 00:00:00 2001 From: imayushsaini Date: Sat, 8 Jul 2023 10:27:37 +0000 Subject: [PATCH 0548/1464] [ci] apply-version-metadata --- plugins/utilities.json | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/plugins/utilities.json b/plugins/utilities.json index 706cd6b0..34c98c1e 100644 --- a/plugins/utilities.json +++ b/plugins/utilities.json @@ -422,7 +422,12 @@ } ], "versions": { - "2.0.0": null, + "2.0.0": { + "api_version": 8, + "commit_sha": "a18a595", + "released_on": "08-07-2023", + "md5sum": "30a21cb1c739b098dcaa791e4a2cd481" + }, "1.0.1": { "api_version": 7, "commit_sha": "64e8a5c", @@ -517,7 +522,12 @@ } ], "versions": { - "2.0.0": null, + "2.0.0": { + "api_version": 8, + "commit_sha": "a18a595", + "released_on": "08-07-2023", + "md5sum": "7403fcea1855ddf561aa412d703fcc6e" + }, "1.0.0": { "api_version": 7, "commit_sha": "41e239c", From 06763429e465b2bfebad8e7969c3633e217b9e2d Mon Sep 17 00:00:00 2001 From: Roman Trapeznikov <47295209+Dliwk@users.noreply.github.com> Date: Sat, 15 Jul 2023 01:24:44 +0300 Subject: [PATCH 0549/1464] Update README.md api 8 examples --- README.md | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/README.md b/README.md index d625cccd..f062de65 100644 --- a/README.md +++ b/README.md @@ -80,19 +80,19 @@ There are two different ways the plugin manager can be installed: Let's say you wanna submit this new utility-type plugin named as `sample_plugin.py`: ```python -# ba_meta require api 7 -import ba +# ba_meta require api 8 +import babase -# ba_meta export plugin -class Main(ba.Plugin): +# ba_meta export babase.Plugin +class Main(babase.Plugin): def on_app_running(self): - ba.screenmessage("Hi! I am a sample plugin!") + babase.screenmessage("Hi! I am a sample plugin!") def has_settings_ui(self): return True def show_settings_ui(self, source_widget): - ba.screenmessage("You tapped my settings!") + babase.screenmessage("You tapped my settings!") ``` You'll have to fork this repository and add your `sample_plugin.py` plugin file into the appropriate directory, which for From c41cc10665eccca0fca285d3a9a35b2eaa24ca48 Mon Sep 17 00:00:00 2001 From: Rikko Date: Sat, 15 Jul 2023 15:25:29 +0530 Subject: [PATCH 0550/1464] Update store events specials to API 8 --- plugins/utilities.json | 3 ++- plugins/utilities/store_event_specials.py | 13 ++++++------- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/plugins/utilities.json b/plugins/utilities.json index 34c98c1e..369f2e1b 100644 --- a/plugins/utilities.json +++ b/plugins/utilities.json @@ -272,6 +272,7 @@ } ], "versions": { + "2.0.0": null, "1.0.0": { "api_version": 7, "commit_sha": "63d674cf", @@ -751,4 +752,4 @@ } } } -} \ No newline at end of file +} diff --git a/plugins/utilities/store_event_specials.py b/plugins/utilities/store_event_specials.py index d9c4bdce..1e3f7ad2 100644 --- a/plugins/utilities/store_event_specials.py +++ b/plugins/utilities/store_event_specials.py @@ -21,15 +21,14 @@ For more information, please refer to """ -# ba_meta require api 7 +# ba_meta require api 8 from typing import List, Dict, Any -import ba -import ba._store -import ba.internal +import babase +import bauiv1 as bui -original_get_store_layout = ba._store.get_store_layout +original_get_store_layout = bui.app.classic.store.get_store_layout def add_special_characters(layout: @@ -62,6 +61,6 @@ def modified_get_store_layout() -> Dict[str, List[Dict[str, Any]]]: # ba_meta export plugin -class Main(ba.Plugin): +class Main(babase.Plugin): def on_app_running(self) -> None: - ba.internal.get_store_layout = modified_get_store_layout + bui.app.classic.store.get_store_layout = modified_get_store_layout From 646401f691191ab94b20a236a0a8d567f93b7072 Mon Sep 17 00:00:00 2001 From: rikkolovescats Date: Sat, 15 Jul 2023 09:56:30 +0000 Subject: [PATCH 0551/1464] [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 369f2e1b..b77d0215 100644 --- a/plugins/utilities.json +++ b/plugins/utilities.json @@ -272,7 +272,12 @@ } ], "versions": { - "2.0.0": null, + "2.0.0": { + "api_version": 8, + "commit_sha": "c41cc10", + "released_on": "15-07-2023", + "md5sum": "71c3f6386433feebac94ef0b9b6a8bf4" + }, "1.0.0": { "api_version": 7, "commit_sha": "63d674cf", @@ -752,4 +757,4 @@ } } } -} +} \ No newline at end of file From 31a61d2c050e44a8c6a28d6c79602971b2adc36f Mon Sep 17 00:00:00 2001 From: brostos <67740566+brostosjoined@users.noreply.github.com> Date: Sun, 16 Jul 2023 23:39:29 +0300 Subject: [PATCH 0552/1464] Add files via upload --- plugins/utilities/discord_richpresence.py | 873 ++++++++++++++++++++++ 1 file changed, 873 insertions(+) create mode 100644 plugins/utilities/discord_richpresence.py diff --git a/plugins/utilities/discord_richpresence.py b/plugins/utilities/discord_richpresence.py new file mode 100644 index 00000000..3cb6e448 --- /dev/null +++ b/plugins/utilities/discord_richpresence.py @@ -0,0 +1,873 @@ +# Released under the MIT and Apache License. See LICENSE for details. +# +"""placeholder :clown:""" + +# ba_meta require api 8 +#!"Made to you by @brostos & @Dliwk" + + +from __future__ import annotations +from urllib.request import Request, urlopen, urlretrieve +from pathlib import Path +from os import getcwd, remove +from zipfile import ZipFile +from bauiv1lib.popup import PopupWindow +from babase._mgen.enums import TimeType + +import asyncio +import http.client +import ast +import uuid +import json +import time +import threading +import shutil +import babase +import _babase +import bascenev1 as bs +import bascenev1lib +import bauiv1 as bui + +from typing import TYPE_CHECKING + +if TYPE_CHECKING: + from typing import Any, Tuple + + +ANDROID = babase.app.classic.platform == "android" +DIRPATH = Path(f"{_babase.app.python_directory_user}/image_id.json") + +if ANDROID: # !can add ios in future + + # Installing websocket + def get_module(): + install_path = Path(f"{getcwd()}/ba_data/python") # For the guys like me on windows + path = Path(f"{install_path}/websocket.zip") + file_path = Path(f"{install_path}/websocket") + if not file_path.exists(): + url = "https://github.com/brostosjoined/bombsquadrpc/releases/download/presence-1.0/websocket.zip" + try: + filename, headers = urlretrieve(url, filename=path) + with ZipFile(filename) as f: + f.extractall(install_path) + remove(path) + except: + pass + get_module() + + import websocket + + heartbeat_interval = int(41250) + resume_gateway_url: str | None = None + session_id: str | None = None + + start_time = time.time() + + class PresenceUpdate: + def __init__(self): + self.state: str | None = "In Game" + self.details: str | None = "Main Menu" + self.start_timestamp = time.time() + self.large_image_key: str | None = "bombsquadicon" + self.large_image_text: str | None = "BombSquad Icon" + self.small_image_key: str | None = None + self.small_image_text: str | None = ( + f"{_babase.app.classic.platform.capitalize()}({_babase.app.version})") + self.media_proxy = "mp:/app-assets/963434684669382696/{}.png" + self.identify: bool = False + self.party_id: str = str(uuid.uuid4()) + self.party_size = 1 + self.party_max = 8 + + def presence(self): + with open(DIRPATH, "r") as maptxt: + largetxt = json.load(maptxt)[self.large_image_key] + with open(DIRPATH, "r") as maptxt: + smalltxt = json.load(maptxt)[self.small_image_key] + + presencepayload = { + "op": 3, + "d": { + "since": None, # used to show how long the user went idle will add afk to work with this and then set the status to idle + "status": "online", + "afk": "false", + "activities": [ + { + "name": "BombSquad", + "type": 0, + "application_id": "963434684669382696", + "state": self.state, + "details": self.details, + "timestamps": { + "start": start_time + }, + "party": { + "id": self.party_id, + "size": [self.party_size, self.party_max] + }, + "assets": { + "large_image": self.media_proxy.format(largetxt), + "large_text": self.large_image_text, + "small_image": self.media_proxy.format(smalltxt), + "small_text": self.small_image_text, + }, + "client_info": { + "version": 0, + "os": "android", + "client": "mobile", + }, + "buttons": ["Discord Server", "Download BombSquad"], + "metadata": { + "button_urls": [ + "https://discord.gg/bombsquad-ballistica-official-1001896771347304639", + "https://bombsquad-community.web.app/download", + ] + }, + } + ], + }, + } + ws.send(json.dumps(presencepayload)) + + def on_message(ws, message): + global heartbeat_interval, resume_gateway_url, session_id + message = json.loads(message) + try: + heartbeat_interval = message["d"]["heartbeat_interval"] + except: + pass + try: + resume_gateway_url = message["d"]["resume_gateway_url"] + session_id = message["d"]["session_id"] + except: + pass + + def on_error(ws, error): + babase.print_exception(error) + + def on_close(ws, close_status_code, close_msg): + # print("### closed ###") + pass + + def on_open(ws): + print("Connected to Discord Websocket") + + def heartbeats(): + """Sending heartbeats to keep the connection alive""" + global heartbeat_interval + if babase.do_once(): + heartbeat_payload = { + "op": 1, + "d": 251, + } # step two keeping connection alive by sending heart beats and receiving opcode 11 + ws.send(json.dumps(heartbeat_payload)) + + def identify(): + """Identifying to the gateway and enable by using user token and the intents we will be using e.g 256->For Presence""" + with open(f"{getcwd()}/token.txt", 'r') as f: + token = bytes.fromhex(f.read()).decode('utf-8') + identify_payload = { + "op": 2, + "d": { + "token": token, + "properties": { + "os": "linux", + "browser": "Discord Android", + "device": "android", + }, + "intents": 256, + }, + } # step 3 send an identify + ws.send(json.dumps(identify_payload)) + identify() + while True: + heartbeat_payload = {"op": 1, "d": heartbeat_interval} + ws.send(json.dumps(heartbeat_payload)) + time.sleep(heartbeat_interval / 1000) + + threading.Thread(target=heartbeats, daemon=True, name="heartbeat").start() + + # websocket.enableTrace(True) + ws = websocket.WebSocketApp( + "wss://gateway.discord.gg/?encoding=json&v=10", + on_open=on_open, + on_message=on_message, + on_error=on_error, + on_close=on_close, + ) + if Path(f"{getcwd()}/token.txt").exists(): + threading.Thread(target=ws.run_forever, daemon=True, name="websocket").start() + + +if not ANDROID: + # installing pypresence + def get_module(): + install_path = Path(f"{getcwd()}/ba_data/python") + path = Path(f"{install_path}/pypresence.zip") + file_path = Path(f"{install_path}/pypresence") + if not file_path.exists(): + url = "https://github.com/brostosjoined/bombsquadrpc/releases/download/presence-1.0/pypresence.zip" + try: + filename, headers = urlretrieve(url, filename=path) + with ZipFile(filename) as f: + f.extractall(install_path) + remove(path) + except: + pass + get_module() + + #Updating pypresence + try: + from pypresence import PipeClosed, DiscordError, DiscordNotFound + except ImportError: + shutil.rmtree(Path(f"{getcwd()}/ba_data/python/pypresence")) + get_module() + + + from pypresence.utils import get_event_loop + import pypresence + import socket + + DEBUG = True + + _last_server_addr = 'localhost' + _last_server_port = 43210 + + def print_error(err: str, include_exception: bool = False) -> None: + if DEBUG: + if include_exception: + babase.print_exception(err) + else: + babase.print_error(err) + else: + print(f"ERROR in discordrp.py: {err}") + + def log(msg: str) -> None: + if DEBUG: + print(f"LOG in discordrp.py: {msg}") + + def _run_overrides() -> None: + old_init = bs.Activity.__init__ + + def new_init(self, *args: Any, **kwargs: Any) -> None: # type: ignore + old_init(self, *args, **kwargs) + self._discordrp_start_time = time.mktime(time.localtime()) + + bs.Activity.__init__ = new_init # type: ignore + + old_connect = bs.connect_to_party + + def new_connect(*args, **kwargs) -> None: # type: ignore + global _last_server_addr + global _last_server_port + old_connect(*args, **kwargs) + c = kwargs.get("address") or args[0] + _last_server_port = kwargs.get("port") or args[1] + + bs.connect_to_party = new_connect + + start_time = time.time() + + class RpcThread(threading.Thread): + def __init__(self): + super().__init__(name="RpcThread") + self.rpc = pypresence.Presence(963434684669382696) + self.state: str | None = "In Game" + self.details: str | None = "Main Menu" + self.start_timestamp = time.mktime(time.localtime()) + self.large_image_key: str | None = "bombsquadicon" + self.large_image_text: str | None = "BombSquad Icon" + self.small_image_key: str | None = None + self.small_image_text: str | None = None + self.party_id: str = str(uuid.uuid4()) + self.party_size = 1 + self.party_max = 8 + self.join_secret: str | None = None + self._last_update_time: float = 0 + self._last_secret_update_time: float = 0 + self._last_connect_time: float = 0 + self.should_close = False + + @staticmethod + def is_discord_running(): + for i in range(6463,6473): + s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) + s.settimeout(0.01) + try: + conn = s.connect_ex(('localhost', i)) + s.close() + if (conn == 0): + s.close() + return(True) + except: + s.close() + return(False) + + def _generate_join_secret(self): + # resp = requests.get('https://legacy.ballistica.net/bsAccessCheck').text + connection_info = bs.get_connection_to_host_info() + if connection_info: + addr = _last_server_addr + port = _last_server_port + else: + try: + with urlopen( + "https://legacy.ballistica.net/bsAccessCheck" + ) as resp: + resp = resp.read().decode() + resp = ast.literal_eval(resp) + addr = resp["address"] + port = 43210 + secret_dict = { + "format_version": 1, + "hostname": addr, + "port": port, + } + self.join_secret = json.dumps(secret_dict) + except: + pass + + def _update_secret(self): + threading.Thread(target=self._generate_join_secret, daemon=True).start() + self._last_secret_update_time = time.time() + + def run(self) -> None: + asyncio.set_event_loop(get_event_loop()) + while not self.should_close: + if time.time() - self._last_update_time > 0.1: + self._do_update_presence() + if time.time() - self._last_secret_update_time > 15: + self._update_secret() + # if time.time() - self._last_connect_time > 120 and is_discord_running(): #!Eric please add module manager(pip) + # self._reconnect() + time.sleep(0.03) + + def _subscribe(self, event: str, **args): + self.rpc.send_data( + 1, + { + "nonce": f"{time.time():.20f}", + "cmd": "SUBSCRIBE", + "evt": event, + "args": args, + }, + ) + data = self.rpc.loop.run_until_complete(self.rpc.read_output()) + self.handle_event(data) + + def _subscribe_events(self): + self._subscribe("ACTIVITY_JOIN") + self._subscribe("ACTIVITY_JOIN_REQUEST") + + # def _update_presence(self) -> None: + # self._last_update_time = time.time() + # try: + # self._do_update_presence() + # except (AttributeError, AssertionError): + # try: + # self._reconnect() + # except Exception: + # print_error("failed to update presence", include_exception= True) + + + def _reconnect(self) -> None: + self.rpc.connect() + self._subscribe_events() + self._do_update_presence() + self._last_connect_time = time.time() + + def _do_update_presence(self) -> None: + if RpcThread.is_discord_running(): + self._last_update_time = time.time() + try: + data = self.rpc.update( + state=self.state or " ", + details=self.details, + start=start_time, + large_image=self.large_image_key, + large_text=self.large_image_text, + small_image=self.small_image_key, + small_text=self.small_image_text, + party_id=self.party_id, + party_size=[self.party_size, self.party_max], + join=self.join_secret, + # buttons = [ #!cant use buttons together with join + # { + # "label": "Discord Server", + # "url": "https://ballistica.net/discord" + # }, + # { + # "label": "Download Bombsquad", + # "url": "https://bombsquad.ga/download"} + # ] + ) + + self.handle_event(data) + except (PipeClosed, DiscordError, AssertionError, AttributeError): + try: + self._reconnect() + except (DiscordNotFound, DiscordError): + pass + + def handle_event(self, data): + evt = data["evt"] + if evt is None: + return + + data = data.get("data", {}) + + if evt == "ACTIVITY_JOIN": + secret = data.get("secret") + try: + server = json.loads(secret) + format_version = server["format_version"] + except Exception: + babase.print_exception("discordrp: unknown activity join format") + else: + try: + if format_version == 1: + hostname = server["hostname"] + port = server["port"] + self._connect_to_party(hostname, port) + except Exception: + babase.print_exception( + f"discordrp: incorrect activity join data, {format_version=}" + ) + + elif evt == "ACTIVITY_JOIN_REQUEST": + user = data.get("user", {}) + uid = user.get("id") + username = user.get("username") + discriminator = user.get("discriminator", None) + avatar = user.get("avatar") + self.on_join_request(username, uid, discriminator, avatar) + + def _connect_to_party(self, hostname, port) -> None: + babase.pushcall( + babase.Call(bs.connect_to_party, hostname, port), from_other_thread=True + ) + + def on_join_request(self, username, uid, discriminator, avatar) -> None: + del uid # unused + del avatar # unused + babase.pushcall( + babase.Call( + bui.screenmessage, + "Discord: {} wants to join!".format(username), + color=(0.0, 1.0, 0.0), + ), + from_other_thread=True, + ) + babase.pushcall(lambda: bui.getsound('bellMed').play(), from_other_thread=True) + + +class Discordlogin(PopupWindow): + + def __init__(self): + # pylint: disable=too-many-locals + _uiscale = bui.app.ui_v1.uiscale + self._transitioning_out = False + s = 1.25 if _uiscale is babase.UIScale.SMALL else 1.27 if _uiscale is babase.UIScale.MEDIUM else 1.3 + self._width = 380 * s + self._height = 150 + 150 * s + self.path = Path(f"{getcwd()}/token.txt") + bg_color = (0.5, 0.4, 0.6) + log_btn_colour = (0.10, 0.95, 0.10) if not self.path.exists() else (1.00, 0.15, 0.15) + log_txt = "LOG IN" if not self.path.exists() else "LOG OUT" + + + + + # creates our _root_widget + PopupWindow.__init__(self, + position=(0.0, 0.0), + size=(self._width, self._height), + scale=(2.1 if _uiscale is babase.UIScale.SMALL else 1.5 + if _uiscale is babase.UIScale.MEDIUM else 1.0), + bg_color=bg_color) + + + self._cancel_button = bui.buttonwidget( + parent=self.root_widget, + position=(25, self._height - 40), + size=(50, 50), + scale=0.58, + label='', + color=bg_color, + on_activate_call=self._on_cancel_press, + autoselect=True, + icon=bui.gettexture('crossOut'), + iconscale=1.2) + + + + bui.imagewidget(parent=self.root_widget, + position=(180, self._height - 55), + size=(32 * s, 32 * s), + texture=bui.gettexture("discordLogo"), + color=(10 - 0.32, 10 - 0.39, 10 - 0.96)) + + + + self.email_widget = bui.textwidget(parent=self.root_widget, + text="Email/Phone Number", + size=(400, 70), + position=(50, 180), + h_align='left', + v_align='center', + editable=True, + scale=0.8, + autoselect=True, + maxwidth=220) + + + self.password_widget = bui.textwidget(parent=self.root_widget, + text="Password", + size=(400, 70), + position=(50, 120), + h_align='left', + v_align='center', + editable=True, + scale=0.8, + autoselect=True, + maxwidth=220) + + + bui.containerwidget(edit=self.root_widget, + cancel_button=self._cancel_button) + + bui.textwidget( + parent=self.root_widget, + position=(265, self._height - 37), + size=(0, 0), + h_align='center', + v_align='center', + scale=1.0, + text="Discord", + maxwidth=200, + color=(0.80, 0.80, 0.80)) + + bui.textwidget( + parent=self.root_widget, + position=(265, self._height - 78), + size=(0, 0), + h_align='center', + v_align='center', + scale=1.0, + text="💀Use at your own risk💀\n ⚠️discord account might get terminated⚠️", + maxwidth=200, + color=(1.00, 0.15, 0.15)) + + + self._login_button = bui.buttonwidget( + parent=self.root_widget, + position=(120, 65), + size=(400, 80), + scale=0.58, + label=log_txt, + color=log_btn_colour, + on_activate_call=self.login, + autoselect=True) + + def _on_cancel_press(self) -> None: + self._transition_out() + + def _transition_out(self) -> None: + if not self._transitioning_out: + self._transitioning_out = True + bui.containerwidget(edit=self.root_widget, transition='out_scale') + + def on_bascenev1libup_cancel(self) -> None: + bui.getsound('swish').play() + self._transition_out() + + def login(self): + if not self.path.exists(): + json_data = { + 'login': bui.textwidget(query=self.email_widget), + 'password': bui.textwidget(query=self.password_widget), + 'undelete': False, + 'captcha_key': None, + 'login_source': None, + 'gift_code_sku_id': None, + } + headers = { + 'user-agent': "Mozilla/5.0", + 'content-type': "application/json", + } + + conn = http.client.HTTPSConnection("discord.com") + + payload = json.dumps(json_data) + # conn.request("POST", "/api/v9/auth/login", payload, headers) + # res = conn.getresponse().read() + + try: + conn.request("POST", "/api/v9/auth/login", payload, headers) + res = conn.getresponse().read() + token = json.loads(res)['token'].encode().hex().encode() + with open(self.path, 'wb') as f: + f.write(token) + bui.screenmessage("Successfully logged in", (0.21, 1.0, 0.20)) + bui.getsound('shieldUp').play() + self.on_bascenev1libup_cancel() + except: + bui.screenmessage("Incorrect credentials", (1.00, 0.15, 0.15)) + bui.getsound('error').play() + + conn.close() + else: + remove(self.path) + bui.getsound('shieldDown').play() + bui.screenmessage("Account successfully removed!!", (0.10, 0.10, 1.00)) + self.on_bascenev1libup_cancel() + ws.close() + + +run_once = False +def get_once_asset(): + global run_once + if run_once: + return + response = Request( + "https://discordapp.com/api/oauth2/applications/963434684669382696/assets", + headers={"User-Agent": "Mozilla/5.0"}, + ) + try: + with urlopen(response) as assets: + assets = json.loads(assets.read()) + asset = [] + asset_id = [] + for x in assets: + dem = x["name"] + don = x["id"] + asset_id.append(don) + asset.append(dem) + asset_id_dict = dict(zip(asset, asset_id)) + + with open(DIRPATH, "w") as imagesets: + jsonfile = json.dumps(asset_id_dict) + json.dump(asset_id_dict, imagesets, indent=4) + except: + pass + run_once = True + +def get_class(): + if ANDROID: + return PresenceUpdate() + elif not ANDROID: + return RpcThread() + + +# ba_meta export babase.Plugin +class DiscordRP(babase.Plugin): + def __init__(self) -> None: + self.update_timer: bs.Timer | None = None + self.rpc_thread = get_class() + self._last_server_info: str | None = None + + if not ANDROID: + _run_overrides() + get_once_asset() + + def on_app_running(self) -> None: + if not ANDROID: + self.rpc_thread.start() + self.update_timer = bs.AppTimer( + 1, bs.WeakCall(self.update_status), repeat=True + ) + if ANDROID: + self.update_timer = bs.AppTimer( + 4, bs.WeakCall(self.update_status), repeat=True + ) + + def has_settings_ui(self): + return True + + def show_settings_ui(self, button): + if not ANDROID: + bui.screenmessage("Nothing here achievement!!!", (0.26, 0.65, 0.94)) + bui.getsound('achievement').play() + if ANDROID: + Discordlogin() + + def on_app_shutdown(self) -> None: + if not ANDROID and self.rpc_thread.is_discord_running(): + self.rpc_thread.rpc.close() + self.rpc_thread.should_close = True + else: + # stupid code + ws.close() + + def _get_current_activity_name(self) -> str | None: + act = bs.get_foreground_host_activity() + if isinstance(act, bs.GameActivity): + return act.name + + this = "Lobby" + name: str | None = ( + act.__class__.__name__.replace("Activity", "") + .replace("ScoreScreen", "Ranking") + .replace("Coop", "") + .replace("MultiTeam", "") + .replace("Victory", "") + .replace("EndSession", "") + .replace("Transition", "") + .replace("Draw", "") + .replace("FreeForAll", "") + .replace("Join", this) + .replace("Team", "") + .replace("Series", "") + .replace("CustomSession", "Custom Session(mod)") + ) + + if name == "MainMenu": + name = "Main Menu" + if name == this: + self.rpc_thread.large_image_key = "lobby" + self.rpc_thread.large_image_text = "Bombing up" + #self.rpc_thread.small_image_key = "lobbysmall" + if name == "Ranking": + self.rpc_thread.large_image_key = "ranking" + self.rpc_thread.large_image_text = "Viewing Results" + return name + + def _get_current_map_name(self) -> Tuple[str | None, str | None]: + act = bs.get_foreground_host_activity() + if isinstance(act, bs.GameActivity): + texname = act.map.get_preview_texture_name() + if texname: + return act.map.name, texname.lower().removesuffix("preview") + return None, None + + def update_status(self) -> None: + roster = bs.get_game_roster() + connection_info = bs.get_connection_to_host_info() + + self.rpc_thread.large_image_key = "bombsquadicon" + self.rpc_thread.large_image_text = "BombSquad" + self.rpc_thread.small_image_key = _babase.app.classic.platform + self.rpc_thread.small_image_text = ( + f"{_babase.app.classic.platform.capitalize()}({_babase.app.version})" + ) + connection_info = bs.get_connection_to_host_info() + if not ANDROID: + svinfo = str(connection_info) + if self._last_server_info != svinfo: + self._last_server_info = svinfo + self.rpc_thread.party_id = str(uuid.uuid4()) + self.rpc_thread._update_secret() + if connection_info != {}: + servername = connection_info["name"] + self.rpc_thread.details = "Online" + self.rpc_thread.party_size = max( + 1, sum(len(client["players"]) for client in roster) + ) + self.rpc_thread.party_max = max(8, self.rpc_thread.party_size) + if len(servername) == 19 and "Private Party" in servername: + self.rpc_thread.state = "Private Party" + elif servername == "": # A local game joinable from the internet + try: + offlinename = json.loads(bs.get_game_roster()[0]["spec_string"])[ + "n" + ] + if len(offlinename > 19): + self.rpc_thread.state = offlinename[slice(19)] + "..." + else: + self.rpc_thread.state = offlinename + except IndexError: + pass + else: + if len(servername) > 19: + self.rpc_thread.state = servername[slice(19)] + ".." + else: + self.rpc_thread.state = servername[slice(19)] + + if connection_info == {}: + self.rpc_thread.details = "Local" #! replace with something like ballistica github cause + self.rpc_thread.state = self._get_current_activity_name() + self.rpc_thread.party_size = max(1, len(roster)) + self.rpc_thread.party_max = max(1, bs.get_public_party_max_size()) + + if ( + bs.get_foreground_host_session() is not None + and self.rpc_thread.details == "Local" + ): + session = ( + bs.get_foreground_host_session() + .__class__.__name__.replace("MainMenuSession", "") + .replace("EndSession", "") + .replace("FreeForAllSession", ": FFA") #! for session use small image key + .replace("DualTeamSession", ": Teams") + .replace("CoopSession", ": Coop") + ) + #! self.rpc_thread.small_image_key = session.lower() + self.rpc_thread.details = f"{self.rpc_thread.details} {session}" + if ( + self.rpc_thread.state == "NoneType" + ): # sometimes the game just breaks which means its not really watching replay FIXME + self.rpc_thread.state = "Watching Replay" + self.rpc_thread.large_image_key = "replay" + self.rpc_thread.large_image_text = "Viewing Awesomeness" + #!self.rpc_thread.small_image_key = "replaysmall" + + act = bs.get_foreground_host_activity() + session = bs.get_foreground_host_session() + if act: + from bascenev1lib.game.elimination import EliminationGame + from bascenev1lib.game.thelaststand import TheLastStandGame + from bascenev1lib.game.meteorshower import MeteorShowerGame + + # noinspection PyUnresolvedReferences,PyProtectedMember + try: + self.rpc_thread.start_timestamp = act._discordrp_start_time # type: ignore + except AttributeError: + # This can be the case if plugin launched AFTER activity + # has been created; in that case let's assume it was + # created just now. + self.rpc_thread.start_timestamp = act._discordrp_start_time = time.mktime( # type: ignore + time.localtime() + ) + if isinstance(act, EliminationGame): + alive_count = len([p for p in act.players if p.lives > 0]) + self.rpc_thread.details += f" ({alive_count} players left)" + elif isinstance(act, TheLastStandGame): + # noinspection PyProtectedMember + points = act._score + self.rpc_thread.details += f" ({points} points)" + elif isinstance(act, MeteorShowerGame): + with bs.ContextRef(act): + sec = bs.time() - act._timer.getstarttime() + secfmt = "" + if sec < 60: + secfmt = f"{sec:.2f}" + else: + secfmt = f"{int(sec) // 60:02}:{sec:.2f}" + self.rpc_thread.details += f" ({secfmt})" + + # if isinstance(session, ba.DualTeamSession): + # scores = ':'.join([ + # str(t.customdata['score']) + # for t in session.sessionteams + # ]) + # self.rpc_thread.details += f' ({scores})' + + mapname, short_map_name = self._get_current_map_name() + if mapname: + with open(DIRPATH, 'r') as asset_dict: + asset_keys = json.load(asset_dict).keys() + if short_map_name in asset_keys: + self.rpc_thread.large_image_text = mapname + self.rpc_thread.large_image_key = short_map_name + self.rpc_thread.small_image_key = 'bombsquadlogo2' + self.rpc_thread.small_image_text = 'BombSquad' + + if _babase.get_idle_time() / (1000 * 60) % 60 >= 0.4: + self.rpc_thread.details = f"AFK in {self.rpc_thread.details}" + if not ANDROID: + self.rpc_thread.large_image_key = ( + "https://media.tenor.com/uAqNn6fv7x4AAAAM/bombsquad-spaz.gif" + ) + if ANDROID and Path(f"{getcwd()}/token.txt").exists(): + self.rpc_thread.presence() + \ No newline at end of file From af9433f1c8d701541dc22030b886f84b264c90a9 Mon Sep 17 00:00:00 2001 From: brostos <67740566+brostosjoined@users.noreply.github.com> Date: Sun, 16 Jul 2023 23:48:50 +0300 Subject: [PATCH 0553/1464] Update utilities.json --- plugins/utilities.json | 23 +++++++++++++++++++++-- 1 file changed, 21 insertions(+), 2 deletions(-) diff --git a/plugins/utilities.json b/plugins/utilities.json index b77d0215..794e33ff 100644 --- a/plugins/utilities.json +++ b/plugins/utilities.json @@ -755,6 +755,25 @@ "md5sum": "cec9a9c6f6aebddd8ec8160f7cc94b57" } } - } + }, + { + "name": "Utilities", + ... + "plugins": { + ... + "discord_richpresence": { + "description": "Display Bombquad on Discord Rich Presence", + "external_url": "https://github.com/brostosjoined/bombsquadrpc", + "authors": [ + { + "name": "Brostos & Dliwk", + "email": null, + "discord": "@brostos & @Dliwk", + } + ], + "versions": { + "1.0.0": null + } + }, } -} \ No newline at end of file +} From b2d010ce10c4ea8d4cf6ecda98e6a3cb35adeac5 Mon Sep 17 00:00:00 2001 From: brostos <67740566+brostosjoined@users.noreply.github.com> Date: Sun, 16 Jul 2023 23:50:50 +0300 Subject: [PATCH 0554/1464] Update utilities.json --- plugins/utilities.json | 5 ----- 1 file changed, 5 deletions(-) diff --git a/plugins/utilities.json b/plugins/utilities.json index 794e33ff..eb12cab0 100644 --- a/plugins/utilities.json +++ b/plugins/utilities.json @@ -756,11 +756,6 @@ } } }, - { - "name": "Utilities", - ... - "plugins": { - ... "discord_richpresence": { "description": "Display Bombquad on Discord Rich Presence", "external_url": "https://github.com/brostosjoined/bombsquadrpc", From 538f26609614d5ee536555294c613f81389cf805 Mon Sep 17 00:00:00 2001 From: brostosjoined Date: Sun, 16 Jul 2023 20:58:09 +0000 Subject: [PATCH 0555/1464] [ci] auto-format --- plugins/utilities/discord_richpresence.py | 121 ++++++++++------------ 1 file changed, 55 insertions(+), 66 deletions(-) diff --git a/plugins/utilities/discord_richpresence.py b/plugins/utilities/discord_richpresence.py index 3cb6e448..a7b3d075 100644 --- a/plugins/utilities/discord_richpresence.py +++ b/plugins/utilities/discord_richpresence.py @@ -24,7 +24,7 @@ import shutil import babase import _babase -import bascenev1 as bs +import bascenev1 as bs import bascenev1lib import bauiv1 as bui @@ -216,23 +216,22 @@ def get_module(): pass get_module() - #Updating pypresence + # Updating pypresence try: from pypresence import PipeClosed, DiscordError, DiscordNotFound except ImportError: shutil.rmtree(Path(f"{getcwd()}/ba_data/python/pypresence")) get_module() - - + from pypresence.utils import get_event_loop - import pypresence + import pypresence import socket - + DEBUG = True - + _last_server_addr = 'localhost' _last_server_port = 43210 - + def print_error(err: str, include_exception: bool = False) -> None: if DEBUG: if include_exception: @@ -263,8 +262,8 @@ def new_connect(*args, **kwargs) -> None: # type: ignore old_connect(*args, **kwargs) c = kwargs.get("address") or args[0] _last_server_port = kwargs.get("port") or args[1] - - bs.connect_to_party = new_connect + + bs.connect_to_party = new_connect start_time = time.time() @@ -287,10 +286,10 @@ def __init__(self): self._last_secret_update_time: float = 0 self._last_connect_time: float = 0 self.should_close = False - - @staticmethod + + @staticmethod def is_discord_running(): - for i in range(6463,6473): + for i in range(6463, 6473): s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) s.settimeout(0.01) try: @@ -298,11 +297,11 @@ def is_discord_running(): s.close() if (conn == 0): s.close() - return(True) + return (True) except: s.close() - return(False) - + return (False) + def _generate_join_secret(self): # resp = requests.get('https://legacy.ballistica.net/bsAccessCheck').text connection_info = bs.get_connection_to_host_info() @@ -359,7 +358,7 @@ def _subscribe_events(self): self._subscribe("ACTIVITY_JOIN") self._subscribe("ACTIVITY_JOIN_REQUEST") - # def _update_presence(self) -> None: + # def _update_presence(self) -> None: # self._last_update_time = time.time() # try: # self._do_update_presence() @@ -368,7 +367,6 @@ def _subscribe_events(self): # self._reconnect() # except Exception: # print_error("failed to update presence", include_exception= True) - def _reconnect(self) -> None: self.rpc.connect() @@ -445,7 +443,7 @@ def handle_event(self, data): def _connect_to_party(self, hostname, port) -> None: babase.pushcall( babase.Call(bs.connect_to_party, hostname, port), from_other_thread=True - ) + ) def on_join_request(self, username, uid, discriminator, avatar) -> None: del uid # unused @@ -473,10 +471,7 @@ def __init__(self): self.path = Path(f"{getcwd()}/token.txt") bg_color = (0.5, 0.4, 0.6) log_btn_colour = (0.10, 0.95, 0.10) if not self.path.exists() else (1.00, 0.15, 0.15) - log_txt = "LOG IN" if not self.path.exists() else "LOG OUT" - - - + log_txt = "LOG IN" if not self.path.exists() else "LOG OUT" # creates our _root_widget PopupWindow.__init__(self, @@ -485,7 +480,6 @@ def __init__(self): scale=(2.1 if _uiscale is babase.UIScale.SMALL else 1.5 if _uiscale is babase.UIScale.MEDIUM else 1.0), bg_color=bg_color) - self._cancel_button = bui.buttonwidget( parent=self.root_widget, @@ -498,44 +492,38 @@ def __init__(self): autoselect=True, icon=bui.gettexture('crossOut'), iconscale=1.2) - - - + bui.imagewidget(parent=self.root_widget, - position=(180, self._height - 55), - size=(32 * s, 32 * s), - texture=bui.gettexture("discordLogo"), - color=(10 - 0.32, 10 - 0.39, 10 - 0.96)) - + position=(180, self._height - 55), + size=(32 * s, 32 * s), + texture=bui.gettexture("discordLogo"), + color=(10 - 0.32, 10 - 0.39, 10 - 0.96)) - self.email_widget = bui.textwidget(parent=self.root_widget, - text="Email/Phone Number", - size=(400, 70), - position=(50, 180), - h_align='left', - v_align='center', - editable=True, - scale=0.8, - autoselect=True, - maxwidth=220) - - + text="Email/Phone Number", + size=(400, 70), + position=(50, 180), + h_align='left', + v_align='center', + editable=True, + scale=0.8, + autoselect=True, + maxwidth=220) + self.password_widget = bui.textwidget(parent=self.root_widget, - text="Password", - size=(400, 70), - position=(50, 120), - h_align='left', - v_align='center', - editable=True, - scale=0.8, - autoselect=True, - maxwidth=220) - - + text="Password", + size=(400, 70), + position=(50, 120), + h_align='left', + v_align='center', + editable=True, + scale=0.8, + autoselect=True, + maxwidth=220) + bui.containerwidget(edit=self.root_widget, - cancel_button=self._cancel_button) - + cancel_button=self._cancel_button) + bui.textwidget( parent=self.root_widget, position=(265, self._height - 37), @@ -546,7 +534,7 @@ def __init__(self): text="Discord", maxwidth=200, color=(0.80, 0.80, 0.80)) - + bui.textwidget( parent=self.root_widget, position=(265, self._height - 78), @@ -557,8 +545,7 @@ def __init__(self): text="💀Use at your own risk💀\n ⚠️discord account might get terminated⚠️", maxwidth=200, color=(1.00, 0.15, 0.15)) - - + self._login_button = bui.buttonwidget( parent=self.root_widget, position=(120, 65), @@ -623,8 +610,10 @@ def login(self): self.on_bascenev1libup_cancel() ws.close() - + run_once = False + + def get_once_asset(): global run_once if run_once: @@ -652,6 +641,7 @@ def get_once_asset(): pass run_once = True + def get_class(): if ANDROID: return PresenceUpdate() @@ -672,7 +662,7 @@ def __init__(self) -> None: def on_app_running(self) -> None: if not ANDROID: - self.rpc_thread.start() + self.rpc_thread.start() self.update_timer = bs.AppTimer( 1, bs.WeakCall(self.update_status), repeat=True ) @@ -703,7 +693,7 @@ def _get_current_activity_name(self) -> str | None: act = bs.get_foreground_host_activity() if isinstance(act, bs.GameActivity): return act.name - + this = "Lobby" name: str | None = ( act.__class__.__name__.replace("Activity", "") @@ -784,7 +774,7 @@ def update_status(self) -> None: self.rpc_thread.state = servername[slice(19)] if connection_info == {}: - self.rpc_thread.details = "Local" #! replace with something like ballistica github cause + self.rpc_thread.details = "Local" # ! replace with something like ballistica github cause self.rpc_thread.state = self._get_current_activity_name() self.rpc_thread.party_size = max(1, len(roster)) self.rpc_thread.party_max = max(1, bs.get_public_party_max_size()) @@ -797,7 +787,7 @@ def update_status(self) -> None: bs.get_foreground_host_session() .__class__.__name__.replace("MainMenuSession", "") .replace("EndSession", "") - .replace("FreeForAllSession", ": FFA") #! for session use small image key + .replace("FreeForAllSession", ": FFA") # ! for session use small image key .replace("DualTeamSession", ": Teams") .replace("CoopSession", ": Coop") ) @@ -870,4 +860,3 @@ def update_status(self) -> None: ) if ANDROID and Path(f"{getcwd()}/token.txt").exists(): self.rpc_thread.presence() - \ No newline at end of file From cf20557a6e4fa39c08a06e0d889c1346c723d155 Mon Sep 17 00:00:00 2001 From: brostos <67740566+brostosjoined@users.noreply.github.com> Date: Mon, 17 Jul 2023 00:09:15 +0300 Subject: [PATCH 0556/1464] Update utilities.json --- plugins/utilities.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/plugins/utilities.json b/plugins/utilities.json index eb12cab0..855ae950 100644 --- a/plugins/utilities.json +++ b/plugins/utilities.json @@ -761,9 +761,9 @@ "external_url": "https://github.com/brostosjoined/bombsquadrpc", "authors": [ { - "name": "Brostos & Dliwk", + "name": "Brostos&Dliwk", "email": null, - "discord": "@brostos & @Dliwk", + "discord": "@brostos&@dliwk", } ], "versions": { From ee7ece6d6465b0557ebe8faab56caa7d160cd996 Mon Sep 17 00:00:00 2001 From: brostos <67740566+brostosjoined@users.noreply.github.com> Date: Mon, 17 Jul 2023 00:15:31 +0300 Subject: [PATCH 0557/1464] Update utilities.json --- plugins/utilities.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/utilities.json b/plugins/utilities.json index 855ae950..3174c116 100644 --- a/plugins/utilities.json +++ b/plugins/utilities.json @@ -769,6 +769,6 @@ "versions": { "1.0.0": null } - }, + } } } From 6c687a14ef7a80b71c635453f450cd3387b2de53 Mon Sep 17 00:00:00 2001 From: brostos <67740566+brostosjoined@users.noreply.github.com> Date: Mon, 17 Jul 2023 00:17:54 +0300 Subject: [PATCH 0558/1464] Update utilities.json --- plugins/utilities.json | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/plugins/utilities.json b/plugins/utilities.json index 3174c116..13a0f55c 100644 --- a/plugins/utilities.json +++ b/plugins/utilities.json @@ -757,13 +757,13 @@ } }, "discord_richpresence": { - "description": "Display Bombquad on Discord Rich Presence", + "description": "Discord Rich Presence for Bombsquad.", "external_url": "https://github.com/brostosjoined/bombsquadrpc", "authors": [ { - "name": "Brostos&Dliwk", - "email": null, - "discord": "@brostos&@dliwk", + "name": "Dliwk&brostos", + "email": "", + "discord": "dliwk&brostos" } ], "versions": { From d711e289806d09c83384cdead750dfc1fa733d17 Mon Sep 17 00:00:00 2001 From: brostosjoined Date: Sun, 16 Jul 2023 21:18:32 +0000 Subject: [PATCH 0559/1464] [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 13a0f55c..6c91dd7f 100644 --- a/plugins/utilities.json +++ b/plugins/utilities.json @@ -767,8 +767,13 @@ } ], "versions": { - "1.0.0": null + "1.0.0": { + "api_version": 8, + "commit_sha": "6c687a1", + "released_on": "16-07-2023", + "md5sum": "df4e9b022d8bf61b3103855e5129fe58" + } } } } -} +} \ No newline at end of file From b08b5d12be66effb9e81338f7c02088872e9f430 Mon Sep 17 00:00:00 2001 From: brostos <67740566+brostosjoined@users.noreply.github.com> Date: Tue, 18 Jul 2023 22:13:27 +0300 Subject: [PATCH 0560/1464] Rikkoooooooo Found the first bug --- plugins/utilities/discord_richpresence.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/utilities/discord_richpresence.py b/plugins/utilities/discord_richpresence.py index a7b3d075..b30a5c72 100644 --- a/plugins/utilities/discord_richpresence.py +++ b/plugins/utilities/discord_richpresence.py @@ -761,7 +761,7 @@ def update_status(self) -> None: offlinename = json.loads(bs.get_game_roster()[0]["spec_string"])[ "n" ] - if len(offlinename > 19): + if len(offlinename) > 19: # Thanks Rikko self.rpc_thread.state = offlinename[slice(19)] + "..." else: self.rpc_thread.state = offlinename From 3531577e0cf25355250dbc8ad072b50d5182a92d Mon Sep 17 00:00:00 2001 From: brostosjoined Date: Tue, 18 Jul 2023 19:14:10 +0000 Subject: [PATCH 0561/1464] [ci] auto-format --- plugins/utilities/discord_richpresence.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/utilities/discord_richpresence.py b/plugins/utilities/discord_richpresence.py index b30a5c72..3ebccb02 100644 --- a/plugins/utilities/discord_richpresence.py +++ b/plugins/utilities/discord_richpresence.py @@ -761,7 +761,7 @@ def update_status(self) -> None: offlinename = json.loads(bs.get_game_roster()[0]["spec_string"])[ "n" ] - if len(offlinename) > 19: # Thanks Rikko + if len(offlinename) > 19: # Thanks Rikko self.rpc_thread.state = offlinename[slice(19)] + "..." else: self.rpc_thread.state = offlinename From 230d12d63833d69a211c84659be9d86b64e0d642 Mon Sep 17 00:00:00 2001 From: Rikko Date: Wed, 19 Jul 2023 00:47:44 +0530 Subject: [PATCH 0562/1464] Reset metadata --- plugins/utilities.json | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/plugins/utilities.json b/plugins/utilities.json index 6c91dd7f..13a0f55c 100644 --- a/plugins/utilities.json +++ b/plugins/utilities.json @@ -767,13 +767,8 @@ } ], "versions": { - "1.0.0": { - "api_version": 8, - "commit_sha": "6c687a1", - "released_on": "16-07-2023", - "md5sum": "df4e9b022d8bf61b3103855e5129fe58" - } + "1.0.0": null } } } -} \ No newline at end of file +} From f85bfae52699b749d25048881e162ea0f2a2bea9 Mon Sep 17 00:00:00 2001 From: rikkolovescats Date: Tue, 18 Jul 2023 19:18:28 +0000 Subject: [PATCH 0563/1464] [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 13a0f55c..08ee3bdb 100644 --- a/plugins/utilities.json +++ b/plugins/utilities.json @@ -767,8 +767,13 @@ } ], "versions": { - "1.0.0": null + "1.0.0": { + "api_version": 8, + "commit_sha": "230d12d", + "released_on": "18-07-2023", + "md5sum": "5fa8706f36d618f8302551dd2a0403a0" + } } } } -} +} \ No newline at end of file From 833e43a98c3530d849f9052226a635040781fa38 Mon Sep 17 00:00:00 2001 From: brostos <67740566+brostosjoined@users.noreply.github.com> Date: Wed, 19 Jul 2023 23:06:42 +0300 Subject: [PATCH 0564/1464] Loups request --- .../discord_richpresence/pypresence.zip | Bin 0 -> 8353 bytes .../discord_richpresence/websocket.zip | Bin 0 -> 48208 bytes 2 files changed, 0 insertions(+), 0 deletions(-) create mode 100644 plugins/resources/discord_richpresence/pypresence.zip create mode 100644 plugins/resources/discord_richpresence/websocket.zip diff --git a/plugins/resources/discord_richpresence/pypresence.zip b/plugins/resources/discord_richpresence/pypresence.zip new file mode 100644 index 0000000000000000000000000000000000000000..250d8e2e340019b5f60fd2fed65ec0505cfde78b GIT binary patch literal 8353 zcmZviWmFw&leRbR?k)i~9xMa~I#vgTc z&27w`baff++`VE1r23gq1JAGNf^^`2B{jIA_V{alM4%OEPfnd^?XjWame9UFmyv;} zgmHvzzaMWO&ZmYq^WUiJNp9>hnKj}$Q@ar09$@J{>VinK3m?P?MHw{jtl@y*n>KeV zLEwj8rE0{cYc9Y}HIQSqIoQQ+oz9k^-~di!()t-2^pe*OG*7pW0z zKiXV$dVJy)*W4_4Raw?rD)j&@|F39#*3CJ^g$4k+F#rJEe@DYW-_h96%G}t-={+6= zYU;MD?5N%wx;<9J`7&5!VjxJ1*O)~KebNvlpa6)z5uCx^dR|KbRbnMP_pPH(3Z}q0 zT?s`eG(FtWla+1lQ?4@XC~sAc6iaj=+dzIH*X+(L%pa$`0S^|Z@=*j{5SFA7R~o|7POw-N3s?dwoTd#EvdhZJb0z8_UxAa!IQX2r~qi!rfvNoSQg?X z35e6_3hA#GW=Cam;1_R4BG>T?krmxH+JyL6w07?sWRsCcX5K7+_u>W1CFG=NC<5Ih zJD#5rcA8=(_)`H}Gq^@fC^}0Sq(r@B^A62oJ?ut*zGPT`S z^QVi3s|Kx;1gfZjMP|9^FKKVzO95Ut&oVsLvWvCvF=>H|R&|ZuV40kPp_ig8pJt_+ z5v$i<&BXvzK*eV1wY_wu-hh4vA^S5UpAlkk99IF85TcRGf>iR>}>` z%}M7W=i9Sy%(~JXGkcvUh@%=5KuplRQrAW9{EdlEPgOjZPJrvmUyJccU=qYqw$qkn z^wBANDE(SGbydIgg7SlXQVLAU2r+NPy`-hV(s@Kmp|Q947=L%jx{?%)Aq+ ziB)OhBHe{;UTOfvAUx{Cr({a;2GY74Uma4&40NdmvE*jaM7ZuMpK&vLt6EG#OfPe1 zpBD&N4uk59Y+HB58^=BMgA-%k!1@~rxHI2nHw0i#vPLXx1x3X$4ci2>_~X1;o6RCD zE^rWbA~k`v4PunOH;oY9O2 z-me?^OQb+CEVDZ3u;N+5!q{5$wjeYS1=Ex-Oa0NhElK&mscBOZxKKD@`qh6^b1Z5+ z36Kawry#5LJ`z-vAAQ4~I~xqPm7es2XD_y7fQ@A**;Q#SCvllreaW{~S$e@l+vQb? zN-8J`9qYbNY<1ZNk0@%{L#niy-f5aq?5@)rZgs1}L--~q?(wk2lrx%T^+BR5~s4>)(3 z2;hux+37XMutmaarez03lZAQP$<^z?z|w$&?5*kadfdE5l1qf>fJ2?mSxCY|7(I-> z8Qcy&3fGfCFuP`Q(Byuz89cR6BGgFl8tpvQQXSK?E%a|TW4fGb%ph+f=|k!dgZELF zwk;s9A=`%aPb?vXH;&CBF)A`tty@D-)V8f|(0b8ZSfgrD^Mm=dOJi{O`Wcluy+v-HnsMz}+<3lBm4zG!EL zo3mTDW6BvV^AQeHQT&-kjHj~nYztWdPo!)l(w!JuED#Gidq{ooS{-#lAM&&|fUu&m z!zz(0+#{w`Be+Dh=Bp^=QfjD3%;VqIlV1mDkp>Y_Svwpf1tO|jK79LGr8`an*XaHD zhz4Z2n_Sg9Av!Xf$~NSTYO~VF5vE)OW8U}n0I#de;>{;@aS9r-&2B#J#~KRm`LQ!U zwSkx_6dAsFg6Jhj%ERxI9T7mt6EfkA$-(rN2k=?_j!w!49)irPYjlvc!%j0Lg?rML zM&{Y}Au!PAIZqn@K8J73-ZKwQk;|-?H`%t+U-l-3Yr{n>I|g?Et{#fcQen@;KI0)X zzWF%kp4Z{+K%fZ7>dX{2eK@RNZ?8R3Qd8KCibX@TWGOcvz0T_Rc(JG{sD;=ENl*zB z{s#DWH7T>N86klM0E~G6fWIp4KWgiLD#@w3rtJzlruTi-<}}P`iHVgLZG;8?LIeLd zYwBt+4_L%+NoHwCGNlx|Y;;c>uHr{FONAJNF2U&H^r1W?lYu-u(_*UMWAH(hEO7^5 z&P|e|?VZoXkRPi8@y80($h@*Zo%{nc8zs{a3(T4NBIu%U3&!VF7dw$&3W#J`7;)yb z&9uQ4P*ig0BZA!$$_yj(fUmyi#G^9bf2Gho&( zU~I3Tjyq;b%lqN=v5E>B6-NHXOlO8GC7#IpzCfCv>6VQCy>IGHi< zh%?bkw0Pa|~wE1tP$FQ+y!%mX146Q?S zSMRcJGq4szNad&!aJD3uq@FFxutCj zVn$2$Y!n)19L%GyxfBUWeFi4qP9xxVl6$25Ij_x=cj?)AQUcoZO`@}f>1FC2;;SJH z-VGVFeLrZ@FuP7atXQ#?v!uc`P`n`cVz2dG)z24(?4g`q0 z9X?;2o)4gzsIYC9FY6of0B&c6R!G#y0=P!9>ovTn70w(kCy;=`?F3vAKmE%6FP(%@ zqW;*B97io0cd1dAy>|83sH0`9K-)QlEX?+aLe~Tk0Xr-kpG`IKe z7RCc%XrA&@@6^{UAEjVXjy8*y*-3`jWcv9o)8oBpnQNffyH7*Xh~u8-uVyWKhjPQWk%A}=kqY4qoXe8MF&`#;9 z#B@HUy>N$6RV|xjeW+g9usLFC;l{gwyPi~LWuf!+&Sb`7xO+K-MH7T?{o%Pw0~~Zo z&?+u=*A;0G>GNFY`4j(V6#l}vnb@uIVua;v^Ic{YvX7E(kaBk3RW9CcaVMhn=MUGD zJ|pC-Aa}IZYSB9%tf}G$q_S#}-N1V#;{$Sn1IeR&b)Y_^R9Cy>lmepVu@%TpA@2yq zcp~$I&((3w`gYka#>(moj~jW}y>~26;94R1VM*e>3Nz978QO}cL}ZXOXGBJJ0@ba= z31At;bvGqZTmlAseFchwDYYL#n$v8!0kd4W={$g9SfM|3*d{{%nzD((f{&4oiE5HX zB4PPp1L{?x7&#?(%=1&!dG*dFflqP5raR2>#X`KSmX`1cX~2BT$_t*&)9^EsopoPy z&gEo~l%VAir%niZI$kYMMT*QhE}0EXb~SfV)y_7AyJu!uZ)6$zX5936WjUP-Sig@*%ONv3J{hJSA|4nYdxxr*z?rF z#x023yqUz*;U2bFVjcTYoL?_ zV{opTzVl?ftntca8IHS+{e(mg_ud^C+mlD zA{}f~NPVU81yb>>82`Z_BnI{nG3))F{)Nluw~I@pkEa#iNG3-Xh+ihgefIaX+dkWL zq8B5CF)F`0)Q0Er`DWei6?(ZJ{_wstE$mP`%ww5$CT}*=Y26xEA(}RY_-CuQ(w-3uMjjz)> zRkUc+S~TBm!yBy1zw@2d>Rb5dpM;(1(KbCDefhVbAZ9X)NCyW1D&9rKAML5Jo1w9t zlew*p<9mBrktk(Jz>GS0{u|SA<bw_v(S0sb&Yze8Wa`rY&&hP z`Ch}H?Q3cn+YUZ;xxWq|m@uq%uH)Aif1c3&tRicXc;~ZyjW&gv(&s>v=rn3@+}F$ahS2;Ier4QysC@-69Wj#_Ji#SKijs?!G|{=7 zIwbXHc}ZfN1(XI@i(ZaVI!_Nh-UGHpA3TkXaUjs}IvJEr1ev^ri0wtVSt;<;8E$8; z;v70cYqY06r`t96bx z@i#eJ*{PNu&~B~rT=x3jQ>sTev%~yderT|-|J=o|PEw&^v@0dbmFo;vuo7xZVz*Hr zm_2Ox0ZK=Ub;JizZlA>`qIAfo5eM4X{OvA5raMrb^g`sS4kDZOP^vHOU`f#WE7-w7 z>aSH$c4G&&syX3zL;U9zC$55_N%%uc5BuHQ`VL-;{mN(**=`+~ma4L_6Zj#^0U^4i z24{*{0t)xO&RqlRG+VP@xVx0HZZp8dG=tAokA{wT3Ica?&5b+B?)N>@T zkinLvuBt_g+jsb8$_Dz@@WxWMk40~5+B)1ZE+Q-o#0@r;7Yf~(L&%U9>LYrwq3V_7H4uXrg`XN| zf?&ghSF9*Olr*;LKi@hX#Ul8B#+>Cb@=rjRtFuHP9D#B^esKY6HDj%+5FU*=EHnk_orp2{}p#S=|J z(7hEAr#!*8h=(hMk2O~lwU6Da)h)qAPa0rT#F>N<9sj5h7$!oaOhBv}hSuh-`T;o_ zaa_{UO`|uilr#c!g~fRz8l97ZGklP##t+GkQ$rC7;yii6U! zu^Vnj`b5p8cP9dGdG)pic~wz`m6IP24e)NDgmvePK&;U zQnc%KSR}(C*&-BucGZf1D}c+wp9q?swH~^I%NCAGUqNUQ6VgJ@@JDK?!2I_iKXo)S zaukcl9k!^Vyg7ojVrPP>I!WKr#=8rB6ENPGYTr5Dti743@0@|l+iXKH#b7uuTQEGHrBUVCNesR<^W4>`+Tj!bP{qS+grL|8G+%4X@|e$s#5&ax~3!z081B6)w2T+>~|Z zNnedE$0&0AMmcDUA?`y@8YPFNgDCn%QcS}?(LbKWP#8ZtfHxHg5-vcziRjMR&_$1f zF#tEVsb*9|mzwo}hW|)rpvzdapn4t8JbQ z4_Aj+S~3X1>h8>$_P9{g@~zMlxcIL4xS}EUovd7D5@{OoAE+*R3|R@;g{ybzbHSXj z2t~>X%mr_)NBZc+58x-_=%&8zd{*(0m#w}nWDsxUp;7qS%iMC8AGl0(DZhgVVF0R4 ze{SkYOFQgG$!<%T(8=67z(%o@SaI~C)gP5bN)5p^_-?qhs#t2?PoHMvx=1*XZAuEo zJY#1^>dQa4pz6?-!}*28sTVTL@Yqk6T4Vor!xwcm#Wy?saP#qO(QQT>)9wI?asFLh zUO;)#QpYV0kAb(otNMe_ONc~gb9}6xYolbLW^t;u!k~tS$GI zx_%VrdieBapz{~LE(83U!O_eyA(p$W$n*Lg9hj<-9KxEz9g%-9XQ`%gI$C^68u3Mm zcP_5unTt4h(k@i9^jNO;ZXd!No)vxTZ9Y#S1D4&xF3s;y^m3sjD749hO^G}=qu;LsREd;J4|qSAK3?oU3M*S~57o`lq6sWCE~FQeN+gM@Qs~+t1Y%|r9=ddGkDzo-f1mXP ze)?!_dx5#$w)O*#(+aQn20CRLo~0IiP|x2!Wwuo|EHD_P)J4%3dAO);{d?@_X1s+#6r1dkj=+-eev5CRVO3O*y+QsPXHFww zQto44tlAHC4F|aA*CkH~RVp6*1q!OGRNl%1Q}ZiwJ~y|QXbx!Ctlw+0O_&?Y6=A^J z;{Id>B2-Xnys|`A%^Sv%Jw>2V+9c;5_}^Sy{T_wTBroSkJKsGjXA%y+UnS3U-|81_ z)(*?gc`yP4&PGEBnsJzdA60%Jj+D(CY>6`)x@DG`74vI}6WX-D5 z6RrC(h~~!nf*bon2$tzg2kw1yy$Q30+c*jIgghueycXp%_?ZaN#@s1WNXN3?k)P0q zpeVCgvGKgJ030GLyFZCSjW&|(6@tn^i@fSNWg3DD*$xoaK|kgqrA$E>bQE@uwZS6e zm)19;IGb;=&zT~0fg6hi0}LIvaN}GCQBGOn%lsb5Ksq%?<>gO4--fj<5X9=DVct?> zyHL`CIeQ4)U@=2e23>7A=wH&-(;0OZ=V4)}P|TweSI%$pA7lqa!b!Ovf_yF(*p%NB zo!foS3fOSi8qzPzVo#hL)IP6#@lT;0!2wMJjq>0A)>3j&Ln^)_efst9$<7G_0KCty z{%JQlJDFSkC8QFSHY`_|P`&SU$=YGKW4=~*VD%EGT46S#_rm*|;Lh=J&^8)Tv{+NW zZny%aDz_=Mi+~wto#)<1zdm<1=9(x25$F=w#?G3JwIJdFlnEz|b>(1&cj|EwrM7aVsjDsM!;gNFrQ@&e#u3Up&SaW)@>H2oE(T!_nZzFYo zL@EqQqALCHKE3wW1S#6*k9@@t``P~ZIX$sVC-B;YCpL>`n)hX+1 zP8_^?G=73xHZ!;guGbVW1x_0qXsMrf@8vRFC9P;n1|eJ>_=`YMr6utGLL8{eS5=B~ zQZhDGADDD=cc)sDB7{;*4=S%{84zuuDv)3>x=$F3O+6MPiwD`8=}6|pGAL6)Jd)PO z;RSuC>Pp(U8o!;J93?69bZ?O`LF6Xc3zz0$&*)(HzhV)0i8tDr6kj*tBZ+fg@upY8 z$dn&TI{&F-H+;)?$i4a1C1wY_EXdvKcLJf5G;rlKnE{K26W>(tQy%!ew#zT3n}D3J zTqkAbb8`*Hz-fKB!=y{iZ7#wc4@#q>52@UKpmAAKAt)5gUilIj)A+~22Y!u?A^@5J zJmW^~y*Cj>eET;SX*m1M5 znVw>6aUMB{cW zxQ?yqhJUS}<{f=;s)~{x3WYr&EaU)_NBjNmse^%I{(t}c|DIUCXFA}0c>UkUKRot- z%&-4s{5j|S>*oJrAippFVEk+9`zPg3fB$ca*83;;56XYs{yzzSHuQfJDp3AK_*Z-X zC*{v3>Tik<`oAduXsP~W{8=ggW~{$E4gYwT|M@-OeK+|hPI)O{5EK9a00;m8 zj5XEc!T_QTKmY(jU;qHr|8Ct(44v$ZtW2Eg_4F)kEu8iA=xV*dyIF>!Q6~_}pgoz4LtMi-6Ui7|e(uE1pnv8^h(7w?-i65}3MUh395hOM z)o@i8GWy2tL9MDIk9L}aQwvI{&gX@0fWB`%uBsK4&b|a@QVkq=J3yObdU{|bcaj9L z9e};M1^~K6#=F@bIaNgO!G%c73=(yR!T{s5B`3z}D&4%+FYv03*2R*+Pzp-X0P|oy z!5a0qXWNQv1kc0Uz!R0ClzDTp+9O-^Tk?B^U!+jXRiTcpGk($@+OIm5@s&&ISdL!9 zBagnkxw6oks1+)ggKQW@A>Qre1i`93=XISibRs%c-3VUK$?})iVY#{lq+2lsomt(u z@;Bv=1y*wPFr8INlX^kIMK=E>qQ;{`de236V^p~Ges;L44{&MGHGNR!q1LMpIy3f7 zseKsIEx?bT#@$or?Zp6$;1Ld(;e*`}#e-ehCshJHpnlx93*qo$RZffxw{Bd46*$OY zRKoz_4aFYbyDJpiC`)l0&V;@1a8yVdPh9T1#;0~RzVzP!4V6hPemUJXI%T{aqCX5A3U=_ zqD(|J!)n+H7Kkj{kf%DKys=80McEdj$@;SrXE&b?;{4Z-k!2L+gPXI36vcuw0amd5 zT3R1MtGj6<4x_CVp+EwYr-R~=YypvkhvU?)819Mk62Azvn8*TyjdY-a9$20L)_|{B zzcZ`Uho@+w`pq&-u9kv=zP`N1j1;*X8aW_1RXy!jy3Sw6c6{QO8~H>DWt0-<{cHk3 zP_k_!+Q2xy?VuJzc6kAx+@pelXrdHmzevXWuh}GyJY4Tcmoq{45A-`HSb$Fy14^lY z(#NC3YnaJ;9AdKFMtd4;d~RiS;rV38&t}b+FXTLT7%`*ANAmqPvYx?w-d|FkKi7`e zbpIB~P^N*U&xg1KHw60uWW>y3Sxc3TVrNJ8E;2s{cLHpMjlCwVd&E4Q9P>PT<%E=1x}E|NY|NO&ij)Rsm=lK) z<`HEU!l~(hBnh&4#p1``#uVB~uSj~KP5mzha?QbdZSj8nq4M1hIc6{v>c6C~!6GU0 zVP1U@_vs!h*wY=(p;XglIp=({3o5#$Q+$zY2)Y@D=hMT-XEXcl@eYG0=w!FkI6eUQ zEtpJc-0x@3we4Ni*c{AY8~?xxsfsAsF?^9SZ4$?~;jyvc%a6ZcZRU8;M5b?=Z6Paq%UWF7~1&*^vKS#}a{M|rjb>AOBz)h3w7T@wb zsG_W`qq}ux%vn4Rp1vPRm_0gNzk(OR=TI9x?BuWcow@S4)x!4Mv!uh&fvMTLv0z2R z?2rAvAK7zY$aJRNnwTv*kgpBZ1`v11ZqJs<-c>sJniTpINt3-DS~A?~V$JLRDV^c=aO1h{y6jBo@8`bl-Vp5kFa_}F?fx|E{V-kY z=6f;?VNsmrNWJNpEz)Y)IW2fG-ZW_g?$(vkiwat0_;fPtTz^;q3RxT+~AZ=O5vPvh%t5#7m#x<-y?_lP8j*j8jUkOIe{bY~ zQzFmb$X4;5vPQ)tar$dt;WI3k-{A@HbaeLaPE*9E4*4-EBmHQi_aX^3j7UMe)<;gg z48aLH7};-(Y8?>g@#augBiC1I-Beba^ZJ=R&#Y-NBqbZn!-8 zH))x#sGVq2uTDu(kD*%Jrcz*|qpF3R(53J}5x80D9W&@F9e-j9D#F0VAT3=TTNF~c z95#zk{25nV7w#r$>CV1tjU0Xm#83o}DnQ5QUnU5mBZnD48Qe@5wZw#>0(6dbTnzxn z!2m`O^uxY}e&<{5fmU4*;OK)HR@m5m`MM{w+eM#or>p2v;}M7%*6k~kNq+e$!L7${ zL2Z(WEi8E2`H~#!guPjLj&g-xY?VaPV|B@|^*QJIu=GrZcst41T;H!q4$k7i=pGq6 z>>9knTd!NyU|5eY)?5zyv=p5Oea@)v1d~;-GJt#=Zy?TljhnjsCn;)2k1;NVhD~!g zV!=#Va0^!sr+wh(gJ}bB^1 zOc%g_1RQ^eWY&-$uIppIL^p`n1Ddo;n5$_b)wCs4#gMLhZk`ygnkdAV`bc*eW%lU+ zUSdX7=@SDDo6R+yET!f4_!0Wy@#-7FdtQrI$%?}cK)T*#dGT&8FZN<;&_RR zFMzLA-@_eR$NHhkL(9Yt%q=MS>X30-DHg8Nom zRAG5R1I7UmFh(Rv#@%L^h{u$86cc;V$EY$*(ekrNN~Ydv90a`oK2FWIo1w;Nqn}&? zR%~l4>#P7&YdI2&)TGH+ccT$f*FW4fqfI#A@*$RtBMLNWQC#afWeEkzXgD%Inh7AMz=xfxm6Z2L`EIxu|-Z4?KYf0R`t zr?jLaki|a}dhD7e+j@D6<5TkIU>>4k#VY>zRgdz+F;31wEsKR%X)@Tf5g5ERXGZ4Z zd4WfpLKRoJRYB}GZp!*Bq}WmWjKgsza>)_~O=V|~Nf{6R;n~gnP`#V6t+IhMs25@a z1jw*Vu*Y1>Z=C*zOB~t^hI$eF+b78kysKO;vaaUPYO5R7-SH<_VM4U)1*?%`7-dx% z=EtWcOp;eqlLDU+Yg`!!7@ za%AWqYK~;}I98q02j32bFL)h0|*8PqXglgm?SwpS8$%vTq*4)1O@W z9*Ti7_yks%OR1;#<8aXuEmWzPvtlQ0XsxUMOVOxPNBajKSJm0pN~SO%aWC!1C9R7J z*f3vKi1z$_LNKB}{V154B1P)AG z)eWs&6{ZC2w{gxTlz*49JgH;F;!VlnZvXC6LTLRd>5m85lch!T-gw-~E9RY(%R=?KPZ43HFA5roiBhmw}(t!Rb#lybx! zr_Xm!neg?2>}RptYy65wI+S1-IL=2vT1w0}Kw3)8Cx9geNdx>sv^{pm*Qkt_N+ZoD z4i5V(AjNZ!=74ETGWr^;`8XWA%sqbQp-*+oifTlO5}cV<1!H&WX*|wnPw0k3G!9}~ zYV>=kp@CT=e2Nonms^Zdnx${y0*;yZ$@WLI*TQimMdR5I9?L~mnf46UgznwP-D}4Z zS}6n!)%|i>| zzF`F92o22#1My|ofbX%v@M5-cnOUnm9JhYIM@GqLqtOA3^UXVuPC}@9%RaVNpe&LmcA`EpD zz0wXdm(Ps)!crgZvrQ&CiGuXZv>}YZtZ#abi=1iuFTaRK>lDQm#^hm$=CIPNsu!xz z^Qrjfay&KGN?BVqatPP1r*xruHUhJ~PPhJGwTJc}Y793}3!S=Grm4w&&w3AnO< zRG9?$aTsX6wS7Z+d7UtHdK^`sa424c+LNjhQ!5R)DRB8AaLwY+3?3QUIw zok!``9WJ`=^qkJ?^TGgQF$CSQ6P5W63h_D2@_iwA5VGfEeQ5Rgm>x)F_OMSx*+S2b z&8ybJ#Y`0k5;ABM8az+Cgm<5ILWPjf&@k}q;p=IeS|sA&H#T<%+#{422X@} z!Ts<6mG6D;C0ow+H#7|cDj=5wzdM>LR*W*yvKO832lGTu=AnRndpcsWP+M*Xq9l01 zuI3N$e>40&AX!cDe|Tq25dZ-3|H<(7_Wwor6&@QqZ1%;y7ix$Tp%R|RLoOSI_ey}; zBkdpUSvcz!4=CbwEs5mj7t4+|dR1q^zpoh>y;N;SQqqf;0op)yqOhR@ds7a2ZPF}l z6jZ53rn9HYwDCGpxq~bU$)$Q`{3@4$Bay@!X`#l0Qzyi^51L&5^Z>)({wiHNjd0j1 zSI%go$}1w-CHK@vMD96PD8p**BIRmTjtJ}6LygvDpEG{lzSSF-gv(PNI>}hrPCGiN zTJF7v4cr7KLuy^xcc$7UC`xpfl7o*h&bcaK;}X1==C!N0uO5ooCx_lEn-A&QFkUN! zMvu(O;e^)Ixnbw-rs}p52gfH<3n7wd?2OXV9Y!DzAsa^Os!`r`#0pflKQF zXnjhvGY_6H{z|i9-vbfI;`*frNNfTDJ(rg-zl$5;8McR5lR`t62|z)`Mw3KGvNeFO ziBrR*GKuUN&MmT)Ofm(E(H=ciAjT>~{}@27Fgq#i$dP(Gm|Pc?6SKKIyS6O{Y2{dv z2G3l{^2d*?s;H@}t|>DCi@Ghg3kXLzRJoIwbM4 zR&lEJbHwn;#?4XCJKDrXszePPPMAgI0ZAJGeTD3X-w)ib&Z{Q;xx3n1(H=Lor94~T z+(x&vwzjjirK%}zSEngD+gd#xnL69rgDopp-yiC)t(BK5#G`(^^kBbn=we(5>3A1! z#@ii-Tj|)Ws67R(L=&bkRFf($U58erxbAWJZYN#q#6}X%$R-hb88!)2sgB1~W-`Dl z5kv|hlm^JIJM0Orxu@SR-Md#Lh`!$L^ndjB?cjsZP?|fB9pg;$OM(UbIwq*}ct_7L z@0ze1O=;Jf#^2Fw4k?iu*-SyvST@UeXz7-@qy6z}5*cHt*Io}s+EmWstiLW_*>uIs zk%=@Fh2{WgCY=8iID~BQ8CgIQ7W^DCWX012U002NCkXmHJo@j~Pl6&(;@DG?#k-S5|NBz1xx<8VV+AF3%&S zMckWAsY9M{N_y3T$`?0E5-`!*?|gEP?Q_v`9msaCsy~OSw=P z_#H=)gkNON;REp+xB$v9guT6|@SNT%59yl=#X|Q2aYIQhYKk_``w>G=oY1GOEuFtU zeycEVC(Yep!Q%&=1F~^ZUBcWHK!?i_M&L|wg5|Qo_aH*v&y5v%-Xl1-vtxuBJY)bK z2d!N_t{*NjP2@MUs2BU>MkW>=QbTrhc{x?bbL9W=I|8*I<2AqjM3G+1CFYbM;_)8& zrOfLG@r=fRjo*}(WV<~2yiKI?=mip{5`-HVD9&>O^$Hv~SFg_+(1E!36=<27o-2|-WC>s0fLnpM1hUq*)vLo#|-8WY_oB{$qI%tM}w7A7KsIW z4!(=1x+q=2JIqqBAp^-tIjc~1A=n%~5(0_9&9kB(5*`d++CH1`2F=tCYZsSnhWjkj zA5!s!T3V24stN^w7i&P1@U^xxp=6WDCiyAIZ{dL38Noma&`2#kPxF*YNM#D`aVKd6 z+%{Z5O%yWU7Sd5SDA=RquybazrWZKk^528yC9Im{%tW|@XEZ`fTFf(M)G74L>kDin z0K+n15z{hHtqZoCPL3MEU!8ybe7$LTlSj8F?bd`Rs% zE=!8Kcc&;_B8L9H`?d*iQ_T@dltgX({_(2GSj|}__;T*C@HHts2JVq5Bw0) zN6yE~bU0!jrJv57!IyG0QB7Q~W6O2G1g{;QKg|#w${FM>BThROHWa*2P~I-1#7r7h zX|sWkap=Y@nDJvG0xb&cT;*4QOudImGJ+jk<0g#Fq+JJ}8mI3m8LKgyj;5uLwMCRq!zNdU!cJT{30r{_dfy z*|z<-yZHEiQE!o1Kuv?QGYkGsWx)6TYZ`M-l^mr;5b%mhI|wr+2t zuT?-r?sD3YaSC+epI~HUJkSm;U}&YBZz;*{VcL9SLwIFX^aAxpc5LE1)3GTlOd6je zn3_{Ge{-o3m*?<~TG%*jxZP(9+KumMFxj6YcaUK8Plq!qSpXX2d|IO!j*U3Q_tL&I zA9V!i0+#UX*0*9CdHJBs>4(?^+GcE3Yu84+_Vm}D%aNL>#WRd5aoFANbqSHy>6d@c zJ9)Lhvo7o=uhpQs8&bA|3p;WyY+k!e8TlFV0Kg02r64<5dIBgL~_`TO9O**IGN06=_IL6i%0rsO9mW7-K!Gx z1BFLZ;h{q}%*293DR!`ycJuiXZ!aoNFz5Uvh%tm*5sBSJBB3&L+I+zWyM!y|jpkvE zVPZ)`^ZBU}!Iq*YEJ*~cTp~Fk3RAgipmd6{Tik#Ja`9wjA0alk%p$ENHLu?4cT9K) zzGf^0>q}6cH_ViZ1Xz7dqoxL$pwDvxJ3qC}O+;kVkGr-8fXn6?3(kU6hA!CbTcn`ktMNqber zNeae78j{x>nt5ahrf4?N%mOi2d#o`Tjb+enb+B~4dqn)s6=WEzxX}jYNpS`&(03;X z!7A`Z*tEqt5}9TPx&bzg?HmXPZY2zdnE_WfY!w*_dlh{vI5VnIk8443cX;l@52uriBdysr^a_(&`eHAVr}JqsLgx^kS~2R zNo8G>9xt$U-5AAOTj?BW6=G>^Z?IGTh(AWmzS|S)Uo#dAYmq2U0&<-`Z4g9(43F7D ztNpnlFQ2`5RV#krY-VT?2(R18khT%y)?edFi#-||yR*q*{1sON3mK=ZwZ3FccHD?O zG}v}0LZL;b=>*zGFqVQjZnrM-$J7C-ADCof72|e2Cs-VG&kj4IiW_RxW5}hAaMh97 zPYHBOf~;KNaN(oV28cVef`Io*>CB9 zlapFXVM-w3ZlAl7)W4702+e7h@oCI(KX43s`>{4>5#jdHLYT(nD2-6B2h{CWe9PB% z)mhl#WAV~AViGha6p}O!#i1>;Rj_rgOS-R!EV%A?s2?DK1FcfkmEMgtCqLs^I@$ND z`d1%=4LCkk*4*bToXJRdbV~4T!R14Z8n>KlB3oz~_i;5CXpa&!w8d&<_yR|R2kNYQ4$-C~heh&sZ=$J`8S!2arr*oiM?18DA{ub)wE2bs z?Sh##+jy+iKnUK*pf&jv{L|+JrAtI%jhjN6UNY2!t6XaB3I*(E82-v-)kk{~OelBq zKT5n~+A;b141x#jI8=ZOsve&Lz9OL?u<3JHDd#x zq~#pnwJ_|xq7m~)b{@18dWP?s|Bfq74AEqYv+9<()A@CVcXlpE)XKg|mw)SQdFucT zDMzcB$)kTv5&hZ`$=b8?vBTVl=syaZ}} zZ#iJVF-A z!^QBfO=T;8Zl}^XXuLe#AW8v^CGkRm_dY0KwA&n?d;=}TS6DXClVT7ktuDKBl&~Dd zGs+GnhqVh+H9(1tgw^DnbQm0Hp<75hP{iN2Ms#63d%RrdIdKTJTN<|?sHPZb3ypLI zeTK}!;t{6_B~~t)>OUGOX7$b#x^Fs}nG!>xBeaz^>N*c6ClNX*Zp(w8*E}8wQv$EK zj`kg-;Mri!_tm70FW$}q8#xPqj!A)YF}tUeiB?WR!cW1Es_!M{W=Od-i^G+01;|d!&8=U1lw^*`RhHAa;P>P0={8xe=9E4;l!-mr21t7m&){DyU0(2>>LfrA^Eb6WV|cQhOif4CwL zgBd5Sz9|rdXTQtnVAhsCQeqmmIhSpb4FjNNOCRSca1UlQ_qrYP$&fHx@Wm=WlUP`) z7-$`a$X$)py4^6PUU6KE{fFgP0HtV7MKh7e4|JG^~npex&PXPu9&Q82J$+ z<8(B5?_1-%qlz8;v`fKmz_Je>pX0%IhnYwO?ud236TqDJd$q&o%Ir6f%+aszAxe)0 zjZLrv3(Hoop19;SA0m~(B78j-Y(cP4jOt}=^pM-#ot)e}(qD!f(3%!)tL^G)|27Sl ze0&6HmA+UCI2!u~n`T@*nvE z@!F*ui_oo=JdTaoVs@1cFjd%_G9L&-F7#=3%!Ef10U=4Tf{d#uFVMyVi4O(yY|}uf za=h4wbZbwW>_lGk7q(3l^Ro>kPrm0fV}p5DS?&{c$Nkef*$?p_g?IHEmjij5P{|V_ zpAtRVgVH4y^pyyRDC;c|Mx^Q^69z{9wfxKn^Q)t?bVIT{NmJ$h{4~#~P-1;}dot8jM+0);uRty{c=F4S#1}@`&FDc6c!UTOjrQb#NZ7cDfgU zIF+J#Snm-(+xBN<2qStF?i;g0w67*|yg+LK#t_IzmH^w;V>>%Pf_deVEx4)gPH|mB zer-kY=>E5$vnpcJM^uTwDG^srCUpmE&N=KX7U+xmFJ}Eq3LNSu;aB1-5p4HOEFxuy z7JO|o8vknwIqy9R>C++Gk~aTzNt_%imNR|&Qk)G-wl-LO+Vz_NU&yv{OdY{>Ib3jQ zk-#xuT>gyU1+^^{-Wu6-&l!WY&yU0ehY#jXue;6sVcR4}7}7FDu0z_`b+X_E@6Wdm zFON>*vkrj}mlQ;LXqTh1q=JIJ*;G0+Vwy@B_ctWbKLPUhT42rev+FUqLNRjU$e?4| z2T}|VQJmSNvF1xvj53JJVDnWED8A?@f_t!)UTcAS z_x(1@uFu4zyJ@$vZIS5mlR3q-zP#WT3O1;i&tUB`ZSr&+E9G-^YpI`Xmkv|mv>Vei z=8vib(~YjK68vf(z#~J2Yy60G2IjPn%AOfp<2;4s1mIi`Ql1Uh#uqsBF)7EZ5WgPHwm9??J22 zcTY2w%Fo@u%+S>X~-0bZ=+jfexYM4xEt#4+7H!9f$!5Zb6GivgDopedJQ;%>eI%IFQhmqrm zyWDdilh+&{)^_R%2wA*0GD?$VVpIGOjdHd)xPHFIkuQDx)@F94HcSRXrZ5h~x<)cc ze@f?@nFa7IWcw$<0WCM+2B_O~0-9!B1f~7}D{fN2APyNE5HgN%&pWyu7>`h;k_$;^ z6s)*z0=ifXvEh^?Fhg6WF1x@vgSJDlpURkjVBEpMNjb%Ij5;NM@k~-xG(B7cdt&E`2USXH<&7!@V-$wc3$Kincob0w7v*J<-ZIfT{)O`qIGyyy>Y=Hx-zU*OWt!oV29cyVkajff)KIX#%>-*rIOX=ld-BN{ZKk_Z#6dt`hitEEJU zK&&Tev{f#lCFInwq`Ga@hc2gq3G?V-G_v!tzk{;JE%q9E$~PpPJ{z*)`o=VSIxP^# zF9-#9ZP>A5JCTFo6}YumGP#6HB#7wN`v;JCKd{AcA$GG)EdtjvM2VNmAf1h0 zT0Y?dT-nYRz-sNqj&(tOJCpDHm=m!A_1P@7dKjhVUe%dyJ-T@JRnHI3OludVi?}(> z+G;!ZfmeYWKr8Nl*)a%y=2_o)dvfu$;7|)6!cqmk+DJ6^vnl?|Y9*S+ez(eE9QPCFuL{ z!LXCw;R?r7gd)W6oXBN+Y1K<2$6e*$=QD-o;j+|K_H{0{%w1R?`1>JlMiueV0OI>> z@Ij^-C|HW{gK9FFT~6fz#&b0G8x8l(0m$$N`~P;8?Z!A{1u_6YtnB|M^BLJWn*7&L zCp=b8TcfrAZ30>^!6j;{IVLi8SJ`KyuQ*~(J6r2YSZ<8Dt|PT2cnZXI_zKUnIsbkD z*1_F6imSU%XSb)|TZMtt0irdvrb5<8}D-{yc#}LPgTr&Q?9h{DP+}7MY|Du zcH6AU(U9V78p|bx7qm_{LS=w@#nYq#{mSej;S1JN9a7PDi&*7~3}^Nr|0FbQd$J^2 zH37MIeMX|)y2Jw+wyZn;%BhZq4a?T<-n;;^q9$DTsz$gC?1l}=_`@V<786Myh|WH8 zX`8ZlZl+vPUp><{T=T}NTqbg}`8+0tJ0z)~&-uN+stvJw%`8+KD-i?;=+>EJL6W#k946)aNlq;&*6HZh zSi*@IFMbLjjH42PX~55Ey|p&wqtkluf}mA=U(Xk8+p_Er9TQKg#3F*J@O0$p>ugQc z$ov0e{9GX#^y+lKWsyz@_6=s<(B8q`fZL?rV*4BjOyEs+Yj2$ zg&5Pcy2>R*1T(1Omcagz?vtPB%xpO?8*}JQ7uMTe%sG9XKD=gjbhmf(wx>%~m|Z<) zX>IKErB4?(u-;x1bhf|xf2=(ojHW=#z(L{gTR0xzU`EP0;bc7-2($Yf9q&Eskqo+{ zgyPAyRJ};nDLv>Ok)rLWA7pe;jaCdtx=411iBjBe!x`}*FMzU#1;Kv zp!CIL2@O~lS!O0^rjTFMlOK&d8e{l|4nPd1xaQ$WfA0ajN~VgY8j8|}3Um|Ft0!b0 z&LF=}eLxeN*aQD!PorN!#(P$^(CioA{J)sjRT}n>V|%60YLW=lCZ!{iD;vG zg8+E?)JVW;_VxAk=`u70*EWDg*I}%YD8B0dB>mHk*obq=8S(y>S(AZp&Q!=mLuywnkcO!lsL=YnbJiY2-IYJ0i<}L9cqSn4i~rlMf+0^jzZCrv+b6(TWROiH3o#SGy5Kjkw6bn zLt6uLFeqGtY$^+lp$RSGT_EjUq)7~ec5!RS^;DiQw@C~=jtQy}uoZApLw{*SICAH8 z?%VvtipX*!g&#(kFhR*-c4nrc{z}gh0M=lrBPeJGG76C?f=Fj)Ftz%rn2oxF%V5Ye z6J8Lw9O5vd8OW|f)E}t`C3GJ_c;O2pQOc;-`;*i|U%+lCA*jtUXP=-B6@h4$295NI zu4ohs`=Z(qxYPK-?mUphSU6$-F#{Mt3|huVIA}i;B1xfvIAEm-GSCP&;&89J`X-ea zR+~xt5tmHSo6gn zVjrxi`?<5O5;!cH+PM2*Mh#7w;+7c&t^?MlI+gOntvH`&V02)RB|sCj7Rn*}M|!-tJO|L8cx@0Tn&A^si8@mDrtpb%Qc(5Sj19sF z+lQ5b26y^q;SLr_kOsIW>ycR zoRvsjoBTn2#hCD=X`^g_nJA%dtR=C#8{n7<^s;umK5c#%=Bhq(ym$ED8jJk_;)5$0|4rLP|R@)FT?mz7w+*0OStB zs4?Gy4BgZTKli7$<=|5c&aiP0*Ltj01RIsjZ8AxGX!Pmy8vwW?*?`J|HDaN*|EIwC zFJvHjEFJJ9QJdG|jpT6vQ;B6x8)~|@_z;Tu+e`WYhm1^d?NKmYrJjJ$LW!HB@O?Z> zS!?-JaR7l$VTiM8WOc9oG$)j!-cmj$^Xqi=q{!ymASR<={||jdsVa~GfkMTi-CZN7 zbr>**+{&i%Z<2Av*nk*f>(r6In%2#FW^kPGrcm=d=BNN7K-DIobp4D#hBhh0~J0(CvA@8TP-4aZZUf*Ogcj!&OEV626 z!*(+zAS*Qg%TQ4y|F5VcQ^vd>=kdqZ@72F!a`bqffUZ9mzce%Ia0GCKmz6(zq7Htg z=1)IOufU_jXki|u$jKktlafXF)m_qhV67_t=|(q3>n6e%2grFJ%vj5Fnm9FwO(5E^ zq_~OHYCvbgX5<>Mg>JUc5h*nxWB=>E-M~)b1@b0;#w%cm>MyI}!cD~pj`?VAP`GYW zs6fH_O;u8pc1ai;ZLH+$9w{*I@{TkM^6k_-~cncadXQ`j%bZtB8J+;PdZZexX1xaWeX_@EZ1$tuU4YH>DqVT7{G ziBo0oU>mUcIR|+vVOtM{>qZ{O;{gc^+;@YgdUb{lRb{2$1C%E5=~qIYdRknQoP7SK z)~Swg!}YmTKwR5w4`v4?8#HrGDPRqK^>`JJs!qi+PLU}d?W8yjrr+E#M>R8I9Qm;4 zUb9bxrBaWysHFAe10ojE0rt*+)&g-8AufophiCTrw(z4j`^0&h=?@fz;?+VBA{yX6 zG-s3o)R?OeZ6ypBdYL^ot+;T--u<{#mc}9w^e^Y)?*1}POR}QIrUHrUn1Mn_KH&6H z4GH8)oN{W0=k;fs$n_u2EL=~)*RngxXpzfib$7S6cV}w!fnQbVOJ7w}9t>G}(|U8Y zrhFpZ4Ah+eu`Dlc@y7Tn;C42u7gw>o5}e@A%_KWLaM%La1L|~ufUOp7nmWwz*5wv2 zGmCRv<+cEGwCsmT4{db~PTbN7X}77jeTD}deLW~H7%+H7Fx*fLl42!ZGj#sF?(FSd zo!#Dcs8hARxr%Ic`Y34BmlXnEmnq3>OPh}5)=q7yAUM)(2q9qEfGgh_ zbR9bKnkrxi4SF@Kg(W5I0HssFNvPc4*liEBxZ`Un|G0D+7j6CAOxz$hd%xj}da`-i zdY=26I3H+h`+1@k*nJ$KW|*g|Tt_^Xs8Rj@Caxz&?w`S@bynIsx21nA{|A+oO1KiYHhpc@=x&s4$7LG zG#ZP$!c0!W#(>Y=R3uj-$#tB~QgZgA!NL7Ad21zGT6J{OjdJ|nN1&SIk_Jk*v+#f-?2pBG~P@?%MT6{Kt&#Ij^`pF zIhXU}M69k5O&7<3V+V=HWGc9hKw6mb7IJ{a)k=`us(vteI#N~2GvGQi5IRMq`jJN$ z*VUre>MH?JEwfzDoXUlELM75V``PhL==D1K46|Bt7-z>LqJ7RWN`xchov`cO+9};| z=)bk;_;`ttRdmjjFsL_5+VA?c?}33rTg>5$-(=g}%qTmv1-k8{o3>|E z+Jwg4&|3`5+DxTZB_Z6c!v&pgKThkZ6sf0hUkMWw+tryzY8x-U{(xccUSz=Sp4JnP zxFMEsR^JT4siPH=MgZHEuGaIui@PK5jlS| zb!dBu@cO@df*)x?y*$$%_m?}Y-0o?nQ~+`xzi;=A`^hk}kEa*Ut%9|=qkw%GfE2#O z$5Y}#Vt3?@aY}AJHfFXxi_{2z%OIEUW*v2f->MX1FGLrls*&bZe`!SH8ND@QlLY?u zj-J1lLr<7t55bxZ%d-}a?iZp?MfOUYDWyq=gijPY)+1DC0$@E_0L$73;xBB!acSh?H=C5?wtySWrhJ-wZ8CO=dj zTN;lJeYQNC4<}h$l*fGfyexo%AfQN9Sst0xXc$3%H){=c38O|2I_w`%X0=MfY8@ES4*wH zmS2`*);hAUlRWJ}Ybux~UC!mQP-b!B2vBMj(0LB zTPwO|UC1AzjP$P-?XyiRK@vpWjO`BI4M2KDi6c;+D&j6u58ClrWob`JoFjWak=*=} z^rD4WrCJmwlo`G{=EQ{OD&KQTYCYE z2UN|%bbM7#WNdz7=!H@r`mKL$)sh(p6^C0&16TPv^;>V!&1A5XiYIJze;{`16uJ9& z)NB$|{uPN$6uK$uoj_V_76)GHD0v$2aj*w|(k^To(&ea{pXf_ub&0l?vtjH&+;V?l zK|0*}V^2Orfaaz{bgg)lO*ci3dQo1A__g?kFQY)Kx(1J`s(nL(Y%mAzSCMG#OO;ff z$qpr&6){mdQpZgaj>+qjtq5eQ6zrLEH5Pb%j%0SI!2g@%Yh@g|%=mauy*c{N?&x!* zzqytEZNtI%^#=Y42g_YeIq#`A&Xz<}$m6hU$wy{O2@xJ1*c0wgn}O-z5>9xbWEsXp zIjyn2um02_`T(Y4bTu(-*qN`;J6RLo*CDUxJt6FXghR^^WD7RlyK(PT>{<+xIro%> zXUlJ6&HIWuvynM7@EZC!@Vz^1*R|_A(12cAIP!77D#;GZrJBs=KhUYG@Tl3lp3wI| zYiy{f$Z}+LU==x4By(z+O zgvJHe+~BW>`DyZ1 z5OTbE>D%Mo{;EaBsQKue!tDzCx@5EF-TUQiRK6To&;j^5>myM=8iUEaj~Vl)kn`lW zZjZPX0s!UFz;U@;JZc9WH4!=iOaCX&v)bqFQ2U#;N0ji#wb_iFn9J^WQh+;!e!tzf z60k+K;jtxC=bb!Kk+xPz%zI7{0+>rm_ za^e5`f%|`Pxrw`xiM_LhovqV;bz2PZEgH}#<88#Ap}dmn5O!*OeT85ze|w({Pp)+07@N`L zTKDW6NBvugN(!=+^*+!YA{VJETTS5PfI6!AOlDt0<0M7*Wgw%Zu3dyI=qgr8!b zntIY1Ux4%wi>nCauozgah(z}DnlSe-duQ&zz}byGbM{CAsEHe6u5|5zCs)Se6>X9E?#o{p4=Rv81a>PtqifboehtWnQmO9-i{-xW@+Aewi=P;b8?+rz{-NMs4ED|q|f2` zgyhsRru3QI{;%vJ>%16sUb1M9KroeU8!Sp2ZV*>2e)}nIzWCO=f?w!y{+@P(N(i^} zwZyi{Dwv|?NByFs{b&P*gwCKr zUh`w5@QOk2)j;M`#E^xAddp4*eZW~g@R4y14Wyg-G3rp1({QprwTdLRFbc5MAlM+8pV$ZEn_CR=M_X)dWqYmm2V z?tw6pbvdm~P70F50nfk3eFatPtuK`Z7#4~lh|nMN%^ z;9K?+=%djcQxn<0toI25YEo@p+^y48O@!S^rlgcmVK4?kHHRUIFTDrv69*|H8f9|_ zSz<8OhL5x$6lr`evW()Vq@kKo%AGN2H&lXCQ$=^%=q9>e&X?RepDJeOXI{@$i7F!1 z^F{{dOc~AtOH*Bw$f_wI%)e`l;J~KcgOBsYMNaZ{h1x)N3#g|JY9!zX(H1c zLC{L7B5N@;O<$tR3?RlZcLqVZ>HwC|)c!%NQ;mEKV(r%u%n0ZYNHrIXU=3B^*;(dq zG!1DzTM3=D>fOynrW#qs(QLY@F~g}A3$v3CPq}2P_fbyiN*AgCR4P%F`J)>z>CAp9 z*G2#b`@;@B{-RiMVd@H|jJz$;vx=%DPqJwdl6gK+#adcW!V8a z07h_mxY(Gx2Z|yGoceuo2(6$SQ~Qmh6H8Z?*W*b`@fnwd9bLLC!+;f%bT)Ll?kqU& zzyTHblLml%8$rMk~elLEZU4n9CnO1=31l z3|s1i7AV)7Kyp$XJ`vDM$5ms7ScJ?G#Tsa+JY@gi@}?0R$S}8IA3hzh&GGcdg+{ zF7BD<);#i>8u!l<5S-VIc%3pzeo$ReM3ptNY=tuK%t2@^CUGU;aaNu28CeaKQ_B+C z++UG~(&SjeCABjr33QsVymBG=%WJ-bhRO<`)vQ|BxQ>L`k?sZ0ZN|YF(!all%NB1y zG4;24h!I9S7A=^${=gCG-E4%lId236=BMqoFkhr&Rgu=rJls_TZcauGWGleMpV^ZE zrJiX?e#Ffs^H?0m6#{f~-O1bF%T2)2T6g$YFDWb$2?8_$HxlQd|nDxy=K z`Z5GvK?g8MSV=0v*c}~bc&p5izcw#TeXL`t58Xj438aA~AeHTMM{f1GO^GBC%bm&a zL0^_o*$5N9lFgP4SFH05p@9p-9^S)fb+ehudG-l~<6WZPLDn!nJ1IonNff9mL9vgy zpht!q09Plp`!7QwTnN^1F(P@=?>W!Kgk;QC#n8rYSfMQ`ZqzRku@+nThI$d(SM$S$ z8IMYR0BU!%^r^>wfLEvV+>RhsXCpa<%X(|0JkLlX+xc(5W5%%wMdq;xK3(ufBDtoD zW(x)fgGTjpfeLFlpBrF7e32L^w$)~D$=84Adpo~R7vlUbumsiJl5?N1xl8Wko==XA zDp=!0SVY9e(%-RqUt7p<>IKn(R$~qC&4>SvEzJo&7FfSRTryk!HcA#c|7MqA1UgW0 z-@qs*d#~JBvg0qcOfI2}awvRoLA-#muEbL`?R-EMt!k|yH7(6bTJG2;@VlH``Q2vz z3$2*C1yG^#g^goL*>^*kS3^6zDj^&=tEBw=t}#@>u==6?J=O1a^U^B+68g zMsjKM#%z5mh4}#N?I1m(uSRK<`G&WuD;!G2U7!jr;#zP?pgwUe9Y*_h$dhWvHH#uy zecekYVr}P{LoRK7ccB@d`P?7i&(ekUcy} ziB^C)aSRCVi+MCwx^VLIzEja%tDW*b`Ou!!_PR85E_F44e(^Kn_xa5}BwPBs@LKGU z#=K$?vae&dzE|cg9rj-B-5D=a90F>-11Kw1!e)6P9ZQ=_u@}aK;CHxs(O@SI^}!30 z99Ksg$|=C z0@k1;pyYjsEgo1gN8>u=%Ba$|UT}vXdaLTEjp3p5*X*~u@nQMkw%x>gapQi*?kTZhgBE8|K_cvcA!&O%?jm5SsvczH=G-gzqUd zG|5t_PDAx1B2SNT7rkSavv>o*ni*6uHhleCzVeVF?t2Og06;yw47jcXaD&vohBxap);DHelMi@t$cs3N8-S5oM(UEvK zXFuNdmHH1EHGEuw0>BQOa&FK>UA@k3G^t{Bz|#TY4uuWw*f2YB@$eGUYzCW~OV+s`b<)UWh~Li|LyomZ%NU*a^RF2v@M|Q# zD@w>+5i%z9#_JC6wrvxRkHz9iV3?A~V=~+-H~!=VtLAA#n0LbaVx1hfmZwaOFHN+0 zB8~OlzofwCsEP!n1GqxKBrjOw7qEyi-D$x&Zx}p0ODI#hz;X0waJiiB5`XD2XI?E}mS;9?-GB zLU{GGEZI!lN?bj~IkBCmqK;t8Mj`u07pQ$M8w`#pl&$lggknSFAhPswNqT8qi2Z)` zJf2a*fr?wyxbB351p+55dMpQ#eC{OZAnanaK73EiaC8$!A6bmo9Qqf)xRl!xh03f2Jal1!-_iw{T4@!}ee_xlh0Qk;RTL$*s17u*?AfK}vjb!s3&T}COREi$f zdUCN8HcUt}JZ)rftiO|vlgXggQGXwmNfb&M`|z}3w#6*Ls!~~=LrqHq7zZdj`$n56 zOoEKsdup92G*?!gCtR9F>5AZ-=i98S_Iq>Z}&{+^lbYle)>>BH>lV%fL zFUJ>K=$bAC4hbnrg`d0onk=+Q?WkYH$qV^HbY$LOJTP$Fx|ksL z$$asnGmuF^g$qN1obiY`Fvu^^0?+(Kn-9&A5TfOYNOlVZLkk}21Mg@m!IWj127;jm zZiZBJ7a^F^9Op>YC~^^;<+J*Y=sVs5d4*~!g$N-dtU_+mhX^bINr)*-Hnd4bgpmi4 zG$JJcXJ^SKCkcw`X3IG9Odnl9uZ=tMF) zZEkT2ib6bTX)$q2&`}Xzi6#9KP-~6aY)kj~_HgX+CV%WPR-q?xYs)w#Eud7-@z(>I zRjgIE(5DGCI+uL$t(6jWhGPctyaT%I+aNZrKk%bjfQP(ZcXSt%S=%FeLcQu#>@wPw zv7z8nOd#fyfti{*U|3KR*wjAoHpymI@Fw)-=)Pm5u+2Gd(L;ECLp-7^j@xsXV{sAV zTLPho&hSkNxwYDC^0)RVf|h2D4fR&RBZdf)`}xqmlys{RlU~W#tN(Z8s(~1+yLnsEuTu5g7U6@W9rG+`A7q5*_&Wiw-KL|hA zDz%$d-sU{jLJ~$3<_U}ubckU>O)~Me@fMD(mRKrBoec^kXtMVOLITB`>G8Fr@Bu#8 zJvHR<7UXsSsg=BPZjRdbn?5qTZcXI0jTw{WUO*egt-jZl{mL&Jb%^X6GVu=tnfpX0scA#=GT|CV$)evg%pyU{-oW8^)pr^QH+%9^GpW+If z%HSmed+R^|(ThQ30|=gqlnJuJpt$#IaGvAJp)f08GL;n#0T!lzF<4R>M;DTU6z7NV|;~dMy%^Rkc)MKD?$ofEYDD_r=bd9GV*rkEM=0D$QgSC!zK#Hei zt1*f+E)ONt-*#HeF^G{M4`(y!c~Ndd1_T}Kym_=+OC1U~b_%B)AkO?-@^pIt7Q=7e zEO=Y~VMyh+Gi(10ij(&bdDI3X^m`ci!SFx)J0{KWLdc=j^2^h zQjXLDrf~;4(l=vH1iQl7#rfB%x#=ZWnp^)SX@=k zszBXdBDqPXo!K?14b%=)4TFDbg7j(a(W)JybLw@I8Asygd=w1EG!3y=aOS9(%|pm@ z*=?qPC(_gZ!ffU0O`11lopo*up}@a-ZiEdL*LZSe(b*R`I^A`PDl{BRlHFjJUPXQK z3Fc-aHipl_m5FwpMst@QAD;|pee_kwuQ)C1=vgC%#z8>Krd|=NAxPs(v9MWS0VM-h z4jMfz^@ULMV>c_wi`LHGLq>G`X7u6QySY6_RI!sX()Ip%h z6iBFS3<~!uhx_I05IBn3W?YKFkM>P7W2^mrbe!JwTQK^H|lNeWR?db2?g5SIV4pET7LdaIOJEO&N8KoHS(S>r+X_` zzw>$Kv~GmQS9CG_92kB08M)~hzh2!DR(IN&*vGpR*B8^Z?SQ&ayDIWEu8LAlrKAJw zyH3|aa#1m8_+0X#1utcVO0kjdixKVca$h|aN4zT~;8+|puhv7 z2j@s5;-qEy>RY-#$%_$Hp|V0unu|9D4D?%^HvcA)wujY$4}_Qo6&9v;v^7>KTQt6R zNt8%dzx3_|Y#2o2oT!M0W4GsLt9APGI3tc>7z6)|xo73UsET*6Lt{`_iAu>ugZ1{vI{YhPV4B7wC9gL z2nzQKeyvKk)b1E$eOJ9fc+Vjy-qvyU(gHr%KKbNV#(dj}D95w3duSYlgMcRdoQKX1HZ}gZA;=F2N3TS{ll)rC!zcl+e`n78sy)6c_?k7WdnQ887c&Z)s!MC zaTM$xj}^C=W8T57y=irsl(#P$f3aP-Y@9!trXVs}gtJ4>Bk?$KGP`|JLIpf9#l^*S zJ`w#YC~Dws&vQkxAq*v`T#;T2>LWi+cRS6HYOud4IbI%Yd>?=7_v*OQ(-xZhZOz|5qUXz~ZlP;7=W^`lpWdZ_2|q_U7i6cIH2+ zVUEg1>;@Zx?}<9hD-veQk->{?6q{pj&Z(Sz0x~igtx9$F^k1Xw8CVG2&SYvsnzQ$pcOeRrax48Op5urRe<`DkbMWr+c z!) z;sTHZ;_yfh5+X7;DIEWCVyB?uru91>49kjc<#Jau_mkW+GAmlq{k3N>^riiOiUg zmf;_t1i90&>Kvx|zw_|==|#Tx?tPtxm)o-GtRvhz$&;sr;N0DI4(c&V_>{#$1HT2s zyUZ-3*=lqPL5?_tz> ze{w9E2q9RD1WwGuibz57L#Yz$_CS^B>7VV($Le)BbMS%YvWXsbpEf%1vyj%#>xDTU z{IZF{bKY;f?&q;;x{Mh~ga7mN+8FbJZajJNog=+#%y9>2RI?<>@ax$&*IgLBZ8@Lf z_oMh0ZwEYCS}uy8pes1biOCRtDt_*-1M?L3po8wt;pAp8=bV;{jfP~Yb>mgLTXI8@ zfYe+R`svVvp{8aqIz=$nKlaU~+zYcwEN+*}^|Y|IW9hQBE;K0FE^E}&AABNDS{X4G zFfg^z%If=LprPe_9fhFHoc-&DwPm)nTc>ZKzb&Dvo9T3^Zcw1Kyw(lqb5hbZa%Q_t zj!)=!Rit)rkv)1Ik7|eiCYnIs5OtRvH(i9iP`-*nL~`{Ecf7FrdsW$4`qVdO3A%mXXJu1b)HMZygAytb`S=>8C7~r9w3V^*+6%Hk_4{SoZ*{fzDbc!cn0}ah zhq)&QbCnET2{0uQI&Lj4(2PY@2yH1qVn_MNQ<{TB%_y zf{V}=b;1fL_vS;-h&AkOdt!vOk$RvigMWxvpZ&2Pi_vP~Ma73^=gmhF_ncybjuK%{cH}{EfV3AwJWkueiBJ zUCvL59*v~1hg}_?+!Gd(X*DAe@0L=lDXIs-sW`!aI8(6IP{6!{>ARwB(}~cc$oGQ5 zjJFBAmO8Pg5+@ieHhtNS?C}iljCnAHi~VWCeI@ibX&|kZ z6iiN(D+c!Ck=z!Uv$bdGiu;>y9qGA@w9H!OGgqtK1e4PDo6eSz!& zwoYX+;G(MRGRFL+h~8Mix*s5~aTR~2JDhhh=&pc~UUQao&5TOXMtDfg@NFbenS|s= zXk28VkKcMiyr+3xG+vb<>TJ@qty$YzqT~kE4_Sz5#H=u7#7RzU{Nc3M_ z;n8wmk>Po}-MXGC=PPXwg=0V51ZmEXB1s;)h%#Y*N#~6}ovSO!*TfSt@dxcszAHBv z;$e0mRWg&3U?rd`l^X?iu@$>GVLBE`zS1OX3L(aQK6)x~Z#>o=k$oL!_3CT$_7=wQ zbQJ4aD1rlmC##G!uvai@(v4G7kn8JYu&y_mXC5(rDRyd=EQV4`YWGco_}+ICk7@%w zq@B4zV#gPFQdP$!_-qEgwv)Oysq9@gm=9Nt2EUXJvL*X{>MRV4#Az-t?GCAaks5MX zRe~1T=k&eJ&4AFsDt4?l`>M-#fs-U9(>%9FTcpmyTd^;;qv1SKci8J;qGv3lVVRvc zDL8ht5XFka2Uk&MMi!$qR*;RLInwMo39_=s3*obez<|CqfQrJ*#YrWqkcJJgL4m*m z%4o_ScVc&nI-+w;O1+~JK`qZSM7HjO8ip=mf1C&E7a!~OZ&wxFoY!tN z=BWHUdA0T7uh4>huSH+u;w!>tePpvDM<~HApr{rtFbKmGR#auB1UIy9UzVFfbE+-F zb61>lUqy7Y{uH+$Yim(ZCQ<)MF6&T5CsI4L)+yvG>xR3YuF(BQ!z-eHL6>f)Ui@U^vDx?USlS*%`NPa+_% zlusfIm*M!?Wbkgk@jt~%$JRoW_@6U*=w7Gd3c}7D(3Zf)uK8yQw#b(@Z+XlictZ*n z6-dkHjltSQ}c?`16tvO!YEbo@7Q<^1YAA>quY)X)Q!Zj> zrn|uN?KnXW=aHwI7zbe$q=xG6SZtG!`swg$S8_01&4l?jfW~lXh(eTo7Jqp~tTN=* z81|Q{Fj$+SCoU3MDkZ0@-}3F#<0xYD7IW~M3ikV8lhC8 zT$Y!#3*#zA^pa7@gla84LX~sO7!tz#IhOwSi6)U6gBFY61H15FNyv@8Jx#cE7h7<4 zyVef)ymW4szhTG_W*>g4ozTX~oYieQzgh41Ketn}2OS@l4^5Ql|5$+n&Vy$$&CA~>WLM%u=KiRiFwK(_f00MQK=USHztDf(ZCSd(IJG|`DM z--ch9Rc;DEtxMh03Wh&gWI42b5Hz|bzI*GN1odPg(ThVhp{VY zYx4gZb5OXk+{1wXFm`@oj(?N1bak@%nQAc_w*PQ-zH0Ru$@5#9T~k=j_TkpN&^yRP zW2h5}+}hMp0t6?TWkt|b6C*Ev{bD8|Rg{{K%34I?ym^>(z-Xu{W+HGU*-T1(!)3q9 zQgpQ|w5U0Rvrg%O;5p>< z_nzDMHH(_o1d@D>kwgUHqlV*?m}?Zv?Gm6wBx~*m%EnqQ-0l5!+{Hv7HF{J_1w!o% z=WW=k7J;51y3+;F!2)B6sigke3RmH8SPsCiZCu$@RP^bW$7pRzwsc(Xpz?mY@c4PO zba~IJg(a##9%v04`CT3&1fB+NfV!U0M5?7;&uieZD(1M!oOroOZ79-#X@^$w}s_V^C9!`J(^#Qr+-cy0uPGY};8IwO^EWs#phd#8#v#c@Mfb~xWz>p{0nBpx>| zJH>{>cAr~?gc}f9l{1^n6H{7KD0CTYINZ(eK;8rpg$AvL5(O%=>unPt9v?M=VBfB( zBK5^XBhrz2XNw|A-5r`r*0;k93dLU( z$3FTgE^+D;44QTLj1jc02zWyaO(f*wk-ggDUnRY{3E%1a;WEQdm(xsKeF3^0@xUo6I>ZGgd5jQ$bMQV4}GuvJ^hjGoPy}w zc!3L@rN3+QJKem#YRz58=v*-9UAJg&U0@ADn_&A`9P<62Bad#ucZxhH??uPww-9&K z#b4B+>bzVd)$J9kkn&3_?a(-CFGELR5A=D*QB@a1Cs`NYe%d}=xl^|K6eiP9NJ74Q zQ)B#1#(!T*Z6TqPi7G+0Ys#ZYAGcUTOOm@|Wi0-1PcbPPr5TE)rcUh5;FIJADgz1C z)rjLZhaxs_paJJN{?^mt-R^Bo{mM%iWB@bSV)PA5u)xSFi>*wa+g~YwSeGcx-5!T~zI|hy1kakTAAOCGUiTI@SL zb{M{iu#)A|&&Qh6(Gdf}=bjM*H)cNmyaS4-V__cRc0TDK5C1Rt_Mf1`N072y1{X^x z`T}C8g6l1xwTLX1QqVi<68?3HB43{TEWZaBaBAC7Ll@YR5=&;+xKQbwyL&wfO*0QK zGDqPMQ|3*p$Y?4mxdoZKN&`-LBL`|j@XnjIS}`iBF8g?nYq;o(nupf4Xg}<^ zvlj&+4XxZ(ZsFW9hVs}@e&61~apC(<$YS@c$t71SbK(~qt$7L@l^*lou7JeLDVuW? zk^DQK#=lrmPSu!g)0r|$H%yXa<~O!Ims=tAYH?x?q&_@xhEEc-Ze|Q5C-?+xHil+s zlp3bmc3V->AE`C(&9-twRTNyt*`un5i6>@EbN>Q*=!n7;X9y2r(-LRuipj$UJ9icB z9>(}l_1$zFv~{n-S;m=o3*M*vY~ixuR>eK&)Y;h#m5vIJn(;Db7XMk z+YqLUT*?&D=9h^|S%vIOF&!2#Wq2$w^=L*x@+Zr4e5Z9#KfQ3Sj%s1=R-OaHz;=1y z(FCSH{M@utD_V^m=_V3SmQlo?(MdRPOB5tL%V?9YBr1IA3r`LGwHc*jNjP*5SpBaN zq;1xdNhc081N~dl&+Efo45_#WgqsohPQ4D8xeQ3KMi#=f&~s}Tveg(qYS8ZUFlok| z7InmU%R?!jd+mmNvuF6h*Dj9`j(Y}$z|eiBcs9%7gmi6bn={Rxf4iN^6n)1`ng*=k z!T57yJ#8Fky@l;$*$-Nm&uzgqs(qomY&a|V@WQLYY%RXPMByY=G$8kZZu6bFO|}$_ zQfk__4#b117nIG6U5ERuw(FYr)(XLIfovF-nOfK(&`PZ1W+h6-cNZk;C2ZWcs-(gc z{AoV`w*_AT7-);3)#Yq4!p6&%XE-7geDEecIPs<;C3yff;S7ApD{Tv720-HF`0Gep zMcq|Re&#Iq3u%*|6DL0Kqo_pEn}sht;(H*`I$9IhQe|_;VmGEpHK{Ijb$XSqpdge1 zQ!@;f-abB6eD99`UtOmNYQH+;Pr9xQ2LSNnJ^y>U?&@M`^AAn@Nd3oovLXC9Pe7kw=m$$pc%z7jP>tyn1#AdqP<(bSDddq3nWmV;35fyC zn@b!9O|p}damQK{f5}*AibPPVS;T$@WWdi=JaoQ-ansD+jFliZ>Si1Ds)wj1Nob7- zSdxlRB5|O2&R{07-VXp~Sf&61UDE~>N&os(E~X?6h?zGd!1<0Jik1X-k($O2lN=ZP zG@^MLZ0p+V&vS6Yy!28dcAA#wiP zdEJu-kLQi2D;Pd_d%Mu2H4m1M3+(o;+%Ei?;T2>nU;n*B=)a7)UG9LCJS>pg=8?AK zz@%Yt=()_IHZs#=M{c=>1j3l{;$w{n(!r+hz^X#A0-;u<&T@KkrL@@^wZ&-b&G4Id z*=Wd<=#G~kw`kq1WM`;%l}ADsVc|zY7LU-l&zk-(S`h*t<;gun%9h)_j+K82bPX=D z4mbp9MzfIY6wI6g2w(XcP*ZN&oTCTevb%_LK)}TU@}fgo7jH^h*XbT6R}wIG-vzAw=6;X38kvzi#iH9v#It&zFMPi+04*Xn1(5&brOP)MEL9 zFcDdksaBH3BJ;QKnMkW@pzVXYIUpxRkuJGtl7pY%7Jhh4f&pUlzE+qgt zmM2V43}$$L6?ZY{bMU&-%XpqWX+4)PDUZ|B0DjSbSR&5Rsd(IGd9S#yZk z2zDYPuR7_VaOuub$-{IEeL3wd8Hz7v_(@GC;+y!*`1(>|i=s#|$qf}P<9&U+7 zfjvHZOG}c5IZgAHC@GCygooX1--aQ+sKgN~fmGIsR%69cE+N9Fyy(5Eal?=MHrqBb z=3_^?1%R%#;$=i~Vz>x)K3<#5VqWDPiM_LicVCs84lC<(hwqx7Zsjd>e6Y7fzfNJd zpZdcT=$<_&-=CDV#precV=Q2m2?-!0K{nMOWvuo$dvUb(Ss&BE9_${vCIjZLcdtfs|Tyd>&gWvAlI>8Nl^~0U8ts( zhbd5c4%S*mvMIB7dq|1k&Nu?Egz>gW`E$=_heEqd9?g{H6fN0FdELv+;k#}yoYWx` z?)GS2yftDDSmrmq+A4_XiiaU%b zjT%uDl5ZrgrW5b|XWOyXvlV&Ht7!D-?FiNIjO)*Dq}T^8C{3!h#KW^h$U?U0XeO-w zxSX?uHkr}zpZJ`g91p48ZT#wMYwa$Z#6?`GR)P+bA)G{0l#%$-d6Y@CFgciKY(Kn| zka$DFwi#if-+fyf%%^~2Rw;ivzpYXku@Wb&w@r}>J3Gg=O*_wu)|YPCyrCe`ypDY3 z;77X#To(647K@oO!r<3o0st^Nw-ECzaWV8PU8y$Eb%AxCft=%_Gc^%v$pv15Pf4o^ zgE^)oX`yH>793SGkn{z}E>R|uI}34AhO}O+S(4_ACws>C$MsZp7d9_Xbm_yGhuAgV z=+oAt8B^Y-Y=OJ9*uu-G0Y~g(CUdy{&l`VaILZQP6p#L!jIOyZ$<-ymMEb{ za;@`kGm|O&42eF3M8*UWBzE~gD{1oBLCq&_mmB8?v5Juv50(#*s$K+L57o1hf zWL$AdXPau-$6E~uIv8EC5*HlvF*TDZm0l$V;N+*@#ovLw)0mY;=`abARHQr%b7@du z-h;HIx)zAazimfbQvZ2 zF5JLPQVP3+3Q8PsK>Ym6s&N)fj1&X?dGo=N9D(up1~PEr<4qV`aV*oAE`1%m{mdrV zyNH0~dl;uIN0bX+BVtDw4i%bFBbA&Xc{$ifFa5OS;~o}@q80ZtW!gxq1fEd?Ef|(H ztg!rtoD7cmTXb&`I?2WJVh~!e89-eJ^cgB4N4nT{>(YQo83xwewc!dbG!iw>Le&o- z^RIt$@BBR}h^|Hpv`gMG$-u&Ev(eNCZN|iB^W)$vkMl&Uljy;bOXdtp(ICG4eN??^)J3xQE$| zT?IcQ;0?|vf;g4RlTk-w(lDYU&||~7l0!d5e~{3(X}LhE5-yQKb4dy8#-IN!3gL}U5t!Ot0K;pc}X0mFO3qXTI9rS1>XrJ($J|m?P>r;RoIi-kAO{@?GIASbn2#SMzX`~i}M`3`-t*}55 zH3l8ip&Ibte3{fITms#tH$#nlINsP>l0-!+)O|bnjAsS8HqFOshQ9$!p_XIR9B#fb zIO*nV%TSguT0Z0tzIvnuu2rFqA^7B!!3p{3 zqAi{925?dL1XHhO5g#9KOG{xB>hI<{%x@#Y&6Y8{kZS7u*3%hZd)YA0d^4SrCBQ<|})=tqFXacxP z+RA7|Y7_vEWgz7K-no9U{N9ZS-5b6eb`1Bpd=s_(B}hj_Yh@vkcFvh}SSTP5hE139f#~|&kO9=qBNeAkA{{ps%2%of zyMAFy_+jC1CAg}gOr5*e(s+K<6-Hrq(TP=?l6>g4N#Z$_4I0pCv#J3 zTyC)!8j=^-PcGmfy+^fdV#EAPdnY#I%x4i&hKjx*1H9nmz?AHQRqX@m`gA;~f9@*t z&w8Pos!A|IUnHnPmy+6cS24WymT-;WF#_#*g85AKU$a?36LqXmvYm`9mCxHu)~O3K zQ6GXbHOCaglBfLL{i=Z$q&xW)2=?z$;v+UVqgM;Lr0y$KBQ5lXl>B!OTS3pCwj4j% z{6A5ubX4|i#=O9M7EI0HpSM#l?@wDW?p;8O&w;f=*NlaTI6KCHyzWral#B)|8uy~# zKCYjr=#Z+p*KkigTYvh?!F_}75StgTpTK1+7hY`Ol}`|B2lg1nSxS20BzkQGF@)DE zuX>ZP7Q0??6K?<+n?cNZbiGqVcL=)7x*v3dMLoc@JMwN?n6P~k2ctJt8V$-O9%jKj zf`}5VKP=`jz(%s2AiI|=Xw-tFD9XgqxQ7n$H2P<(04ax&TJzITKS9K4Y0WAq|0opE zJwZJ4!O-y+Rz|@Q#OwR@bhV$uAS~|=;HZqbqWD==EO0FinLoMk@1DnD?c`6dE>JMd z&7_G%kw^E=kOT}6Jx=HbarmuYvqddb9#ET9sSOI(s)TvZ48x9LIeqEXS(_;pzxPp^x_`$$lC8zB2 zz;Xc2b)Z7xnrO%Wtchit_U8-tx%!8Jr?@Y+e2a6ol8?u?4+zrx2{s4*e3K7oi|KXu zVipK&iP;0%8z>)|;VCZ8qs3GH;k*ei1Q5jJA-`6+tP zxdANS=CxotsbO|$=!3dDFj^1@j2;A$*M^7;26&x;4dNjS0kq;^n{G{qAg3DwM7~Qc zI3*1x9FX(tzxob-65XGZt$*JC>xJ<1>3^51T}+)_oaz5p9QX6pzuo;4%KeYK|J!NU z|Mv&~mB#X)!k1y95b&GHWamnq%MNxw;&Z;(V}C1of_^9r7Pn3+4P}(X@{7O|JJg;&1q1 ze90I+esjH;^wg;wI*703z&?#dkGfHfzfG{nvFALv{I_OW#CNQx$R7&|{vRx1`p1$7 z2uR3T_C;nD1{MYt2zgnkY58e6T15zoar!a&=^4daiAib7X^Ba>qa&y3nF(oGy0OWb zCM5`333@3RKqw(hh?*{)zKXHm4z;z$PEJ;W5kI>6qE-QJq52i3xfKN!38tCeW>O{< zo`sGbJpr`z>W+SPRz6}>v&BTzpa^9o#LVV(jsF>R(qzd>fVihZvgYqtVCYdo5BMMA)No@uAWWTD8;*oqHJroD8 zLtyb1;Gt|x&#|?UPqQklRb-Vcj7&RyL>TfJRlF+%l3J`}eMBAM_dxYOg*JNxIRkz= z5}#tr6u8KZLjSM1`kxaojH#^({pYavT$ z;l^D{7J(F|os^AG#9|tch^+3zd7*vfr3+B&qRwChvxmEx4ckWaV7c@293kYfiBR&t;;unZ5BO@Ff(&?Vbai~`k&o~Ey~`=E||E<%w8#Al}lcE9XCOIpuzj!wf)E zmfGpL+k>_5R}T@nJnBYCsdbNA?J-v)#=0UHNTPvp0KSP9B#6~hxjlnB26hIqKISiU zT0eESj_H73WWRM=rSIVz&a@@H6A;|K3gu^p>$Cu^!5G&b;&hOk|hsF<9vYT>b ziFABMDKFfb++$-Ga&4a9%@_Y)UuPW^$C|Wp+}+(FxCD2CySux)yE_DT*AQHSy9alI z`{04#E+2RA?&e;;-R-|-&guHi`_4JtJyTWBQ@gm@l{V?}k9p;KzEn`|{qya5MY!i^ z_e+A3>^>%wxI>pWO$XPk$*h+RAAZ7PNFA-T>D?Y4OCT}Uu7QAHmYVsjjsp$RSuH}g zfK`#E-D-MwicWQ=_PE*ydk_~EFiwRlJUJNknL2HRjg`5>C_cKt*b18*RfasX`tjpJ zAo|CNXNu-c10@m#iv_2p*N$$ed(KhgzP{`2z+cx3b%g~2ieLf)`cFTC{=Av}V~pg9 zrcLZlBl26>pvRqGUDo&nHxgon>mX-x0cXh_v5_GxkIK1Tc%^@&Kv40RHS* zT}e>~&2z(XQ^{aNY1Fcz)~qke+N-9}3mH@=9F?l0J#GG9N^@}4r;s7V23?kbcKJm6>dbF%9t<9|zv>Id!3o{OvOW^P8pfDGQ8+Vy#_d=NAf@}iQWd}Gj>7e?D(US!+(aBFV0C28$kjeKvWyqaK zs_FsXq!)mwivqJ%p@B#;;(nY2!+oH;ICA}%kHud#NC@a0|64%k)PuE zar$`6*_}VIgdN~|1$*zn;dz1#an?=plPZ~#8)^ud3*&wwxORE_tG2f)73_UhSWTgE z{4_Wz?D>!}2re;IB2AUN2aIr3R$6uQmt~$`Hs9Gr_p;)LLFJ%vaC-&&kjOuA<(O}d zPSL{G&Gs1MY`z3;nR8*qLMY7~$4iwQ@^XPn5wxI1bm=eK{6cNuo#`}pixYdS(@6$R z#$!df^Z`BLpZd~ zg<&OoWSus>7?^&tGHN#K@UD@+*~f()sJC=1ZHL1^`qT1^i`}d<47Uqx?Cp7}9QyI9 z`e@S?Y5oW4*WRno9ub(7pH~ARharJ_6!R@8JH^fMNX+{6wS9OEsAY-M2&BLcN5eQh zK~3g%;udp+F#@(dE3FWi?};o6+YGP)A@KP~7!M{bNgNbz`M^X^-k70quUV0(9Q=hbb z0dh;KIu4TXkHZRs^#rhwqcVAs`>d=XucizJU<(X8XZ*r?}fI4|_x^q?Ijx6C}&u)o#U3IP5z z;k*E22^tHC<&G;xQOwnfKB+clwCDC3J9$i1fQdol9WF7AA=-XYw!&kNc;=|C`Q_g$DuM3PgzK|KD% z#!tw$jGlRIpkkt`Kz(K+kjx0}glnO#Dnm;3;K# zkGUxcj-p_I(lUVy~uFdEO=5Pp>hUZRomWtX7h;l!kToB z8qXn3i9n5_XE6}j6YiM(jsO=>~>Z@ zhR}O>?s3P7J{1dk^+uMe$k_bmss`&_8hoUk0iUc3Jy^j$@A2Bypk!0Yw3LG3++g%6 zRWBBNtt3BOz03N-d(Pi_MUeWH6MhiJZ_862goUa$tkh^;?gsbya%5o%+MrJ>$eA*p7fQg#^-Ve!X*ovYlZlbJ; zkkiEN63S3nw*k2ZvZ7X>@;#Oke-uEMXKDz`q0d|AIrz0j#NjpK)4}en#;u&5+|}?j zzdR>Cysy&mRfE3XqSx)ialm@;Q^Xf8B_Akc$TC&BQeFt)J+_BQavdfP>>cALW)#zh zLRYxnKoHIF6qOp>dBw-xI5*~TA$<+Vp;q^6Yae<0?&LmlnjHw;-1JBs%@?gq##jvK zZ~Z6b)3^(RE4nWS8(k+GT?AmyZI8p5^?n+ouxG)>TfGoXZRoX1z`Kdy{FH0rWO+1Cw`2zX7e`LYS0E1@ z7Fudzr^ojF2dTN(pK(RGk-_+Z0ox5zYUf$a&mS$yFquz=(C!PK$9&hpy%PxuB&Tyf z6Paw({48O~3bsNgiw;6SzPeC}R2L0!F=wvB6&(vBz}h&eCVDW=BF74b{DQoAl!~H2 zus|wWX=F|^<2%WS95G-+qs+^wVzP!$`=O7*3edKTmD;3ivyl&00wf=*w9&>l3o3Y&Bh8PEjmh8JtXM4!~i7~iYOl2WYs*&s4r;havBKRUS;{Vvf8DcMBe7LR-PMy(3_ zk|&mP0aB?et=0sJ!`~`8@W?LE*n}cB zmg*@aTmeTK%J6Nj5>&plxefKYH8+x?QX+IPg%62yoPv^2c<6ATet z5s6s$BNi;IpkPIK;^s%uG#GB`#4(|}pQZ!?A}NVl!&M*xqst zlTt~YGaAg*71Eal3x_vBr@+J}KPC6f;mq4Jp=7`cvCjhS`*}#5Idegh!_06F$Ed@c z%0kdTTKOxKW;=eSMIN+7mibu-LMM+rs{%@moVwWndH_z~Z3)?t*Hh)y#}HIbtlh-G zu<~qBjoZD6!WHzQVYi5TW#NKw@&fODd_9Tt<{c>+cpKuns6qv6X}SFk=v={ZLA!|! ze2@g4i78t{no z@&-TO1A6^VLBB`b)=2^DNQ27nIiaVZXKM&+yh5Iqok7s8*HcRvw_ltt*8=>mEbcv0 zXD>96eI5|JV1E>kej&eT`pkHHJ54)sZMpC`zsgYVC{z6O+NmsEgcO<(%LJD{55fSa zW70cS?%eW(thf!snvy=&hk6mHdAs^!{mFw5Iv$v^<3Vs^d4H`qEPXj%`2F z>U@xdQe`>;jHsC4sXaMCg0UDC=d5WU&3wP{xLyU8fb`-zEc45LJ8!MYj{n!=ii)iG zPAvR(2s1J*mvQzOE+&Uz7M3A;h=ZVD%d4pvt%hkVE?;u~ZTg2`iMsef9t5?=Pnq2qMMERo|Yt?B{XKWiMp%F29?meur)OvRU0L=d2C<(^H5)6g}Pl*$A!(wsT z!N3+PGKRzf>9Xk!UDzx3GOE^6fk-pzVeC5m+Lk+* z9Dm&ULFf|)UPn19!cl1jmEnLvSlttqT5#ujfZ zC{nO6k1lk?U?Px>>75}tO3K%LPzUQ>6Hyd9Zpj5|0g_$5k;!5i54^D2u>t^2p|QV^ z%kvsK4MA1nlf2#|-_Nh2@F!?3@G-)hR&V2&`|oK<0s{guOme~`g^@+#{3SUcavfpZ zHk;98gu+PO7_s5CXHF7Q6j);-f+2575I}JYR=9Y{xGEE8_blK&vKnQbw5vYs_-*iv z2r4A~*arx_UN@Oboze4OrFAW&ktKZBKa&1h?$G5X!p}K}EzO5OaplS5FihB5H2smf z1i?Thp14u;xIQIOGSLEO)6rT_+Y~EwpBX3&`-t~x{!8vTXMUW%h+rvs3xD;Y!_#IV zuMsrpk0!SPgNQ>J_+N_xb;WTo0)&wY*_$)eu5nBx1Y@+UU3!RtAC{X&1PpU3cKoAz z{eKM`ovxMO$}Bihy^K21^m})$`J(aT$^VKMHZW$j0tZp2E`rKy7s#k5Iz~_~@^@N@ z%sNA52FCVJ#lGXIasT|pE9Ba2j|kkj?O@1CyuWG+a1#+PeR^t4L;=*(D72bSnjcHX@;kYEDc?1E>%c^|1^sl^t7)eEi&{%#rxX!&%rFFc4Ba3}89edox*u~ER4-4Ss(7i#xBnE8f*${~SWvasu8^xM zF{y^etKp7Pu0+oFa8y(z(aa+tDzscyXNA`6vXV(>@FiGSwWcX+4RWW<0|qnCx~00r zu>OkqNEBdMB;&KojC<8awels;V99T7tQ|UZOuxGA2@6EvQ1^UyC16^Y2D59gjAWqg z!7rcb>KXZz0qD6ZC#*g0$v;Gw+jMO(*LM*vnMzmE=fHj1%5E#JA`4fJA6mcHSn22H zJ5M3{=})EF<8pC-lcgt$Qm1hCqZZKb?yp%3KK~gW(utmTQw~HW{JPju8?0IGC30L- z*EeIZ%+2EbA)-ND&D0#J_O;K|F~w8TG@+jLZPYDTB((G4F$csXaLFe{0Hh7+CCZtY z&jpc}UB7P9Q+;SCM25~U<|W#eBP3Rx=Uo2l; zF>Y~rwr;owZHJ{tj=Tl-shXIt%%`shXtNl3Y8@X>^QPwB{)DrsNArk-g(KtvyhP#9 zcyPXs>^(N)$r8h!U7;Ln6Am#me1%Ds^(;^*)&2%4-;GJGoY!D0UpbXx_V~?YqH@6TEy(thRrU>X%jv1<66|+%`L;$MFR;nw3Jx;n$8FV+L!s4sI}l+)euU* zkV&cS$|?jX3zbrg0dO{|m$FAL!JghvejpQh;zx(AL-jyc=#IRe( zDN1#QH~*^fXT)?Ns$_S<^Bj*jm#f;acyLth$9U>yVC;=ccLdn$ld+uL{B+o)F4Z`~ zsEe^~o6T3yOY+w${2f&7`D>&aWt;4om#QWsz>G`vtSlq+Fj|JdLHcYPiA$8L12EHV zh0lc=S95k?Tgp&{^Kp_67w^pTo|0P&__{d9-brSMPLSDd%=F9zIP9XI*>H@+i?YX> za?RQ79(%H3*)}<%;F?2PDqdEXEFO77daNs+ztFd6!S>jbZ4?*otHu2KW+)b)=;z_B z?UA~iT~rKcFY1IAs5?-IktNZbhAxGAJT1p{5Rhr;47GKT_HmJhoZgQ`cc}arZtSb|{lTiQD_vD4Bwu^a!xbe5w!LuF z`l`$DU;t6@aO6f$wyVTxf>!}Q;XA$L^)^sW+7%bzq$RkReJ9~EO~}8uz!U~~7cunA z;l|V7E82r9;X5Y7%(DuLr3MvLr&);af0f1`BXzl!CrRP!Sg4+z$z&5hJ8h0Vb=aMH znYU+jl(OPM?y1GG+mkLjgvVR&c%vkPe{d@SPcWmlh#Aj|IuFnnxjsz zR7Jo)9Z#9l5;8U*6J~O@5b)Ue=w__vG>|E1-4Nr9!v$!29I8&nT%H{13LACA7aFMW z?TP26I*Pd2VeG>DLR>+tH~O?v4Z8NDCX#)mECAP#iqp5W0(Rc2Ty{Prpo-g75_X*7^tlfBJH7Xr?t7TWA?0{bPh5{=&=VSQ&a$Ev* zT0Q~k^RFTHHl-u~ym6>|o!EpD56m_pLm))OP+?F|XQt!c9)FU-yS}QZC+z%<)LR`C z_0Q0^)rYNB5jny6hvN+@dYf3Q`MPHJZW}#A*8xFZXfvExC@@ufFKNvguA=Rn1BJDS z)}vLxfS6Uy&z8%Wt77y*pc5wklxN?eSa=urU%} zJ8yovXJcHp+{oOmGIR26p3`QPhtHbzMm;^(<^@icPUEB&d*vuw*8^C_iQQ(d>fR5$E+}#?%pUZGF(DtGexHdUe3>n%0Avs0xm{uZumdn=WS+r% zcos;x8pP*;YY2R&c;k#8ZbZKxQn=W8HY5!qGq;c6J}TSN3NZ=r2$PVqGdK6gF#}En z&QMb++#$n|z#6n15NTzw0`R2Uf*YE%sHW$GlKcxxI$wqHSV+6n2;T>Od~a zzF?~Zf|w;r+Ep~E9yf3ReE~$8h!_tuUpz(cE1j=&aasupdSJ!2grQ=q(DX5LvG=es z$Etl=Fwei@WB$k}(_0}$;cXbo0g?A6x1jHi~wv zkORFM(F=MT(@$5(TuN67a4HJo&4ZdcLSwhl#nru&;KjidH+!De=QkJwCdZht;hLYNe3qQ$uy^C=3WVF$M z`-PBr(Ois-u|4!$Px^D##6%I#3xH>wJ~}N-ZyBKI&wN{@`4C^DkxpbbnU?;_aP_$J z<(tAme?e2(B#Id}Iex1XGZ)PkIFH)h%fa(>U&=?jahYqxl?valQFRq*pqvOK)Mo%6 zg=_MT?`T{w9R$$N9&I|rvBY{WAQ&K}FASMfrU#jZuD zP6(R{Au8or5@z_oVDbJ7(`db^#vbubJGnKSYEB@d=}pa6EV}bh5rNv-WwRFcE@j=D z0lA55mYce{*sZGRsG=9)vZTUC^fc+v#A1*&UUOXeKBD$UrKkb*SK;9z2{Da^gNse7 z`$JI)v1g`;af$=v7QWe_L=jNo%Zbv{I6mk8T+bz-;>BX%iV7;1Sp2Zt0X52!hB6%n zTE;8Y1Pe00m)hCoAJM33Ex~h;?&^~IW*aZ}Lr|6H8 zhO8ey*3MIYEl?efQloB$x$-%F<_Q%0I-9Kf7?SvO*g@boewR1MeZE31xOm2DMRd{< zhhyj%B{y)vde!TrttZILCcOnakA4!_*;Y2{=6P&2gyQSjQ;V)C1h!>=2cQur@Mp5t z$n1jWezY&Tq4(r7>=JCWxsh#R9=9i?gD768!QYdW=oKPN7B~QoXfg$_)n>Ty z+Vb%8=yjH22Xv)jE(;dX!;g_NWqv>$#Y;e+rH-sr_Q^U3*1WY}Mrc^x3i>aAVuhNzqQ)OKg+e4_fG z7*u>Y*;v7sTOLUx#Vq<qo;yOI zvg@AZEo7$RNQcA$K#a67X9Q#F$Gixp#&N;idhA3Efat~{+^2(s^X|JUh-XsP@Au_! zE^>Evrf-0bdXRGH07k&`w8P@hI0 zG)hgFz4SMNn>bWfm$)7i-zAtPXwtA*mi;B!uv#NOHX! z27ZNP+%qW2!GDM_B3TcXnVU$-M3fd6u&n^3?=H+PEqRbFiJyywLD@UU1V5li)x!D& zE!6vIE~E+1pZ5YCtGwGBvg!&zS#Sq}iV3r6?{s-{(^$nwecZ^s&eEr_zPDsivV!Yu zB~VJFtx0js6E}Msu+V@PJt~ z`wKr8LGF>anTz;jUF+hg-c6evZ4p%bAbW@8L?ADqqEJ%@OFly|rgy+2R&)3% zB7~XFLW54g=zY?fX;be#t}yJES!~MUK&j~+>}cm;<0XtrkAS{Sh2x;DVH6cq0Qgm7HQt+GBC$Qr28;M`CQ0Gm%ebx# zo@>Mw4dG;fHL=Nli?Y~KJ$gC>Y88o6g)*Y(1ZByY086t8d9XaRFO}4LtK9DWh4kW- zBu5n+7P-S}pdM2l?z0_nlaH7}7cx=`Vli!>bV@K&=Y0aRuY|BdQfQFx+}U8w*=Sp%QOks##SFmbvf5*w~3Va=i3}m=gHIpe`r2Y8sKfTtMm?? z6!UmtnosV&3cD9YsTvS6Ir1f>G{v?LlCan+8mjYGGZ#%J3t8`_q%uII>64Ki3Be(e zr8~4dgTYfZCEx55xRUzT??`WRfH=y5nq}hTb&oUzH?rOJVjIAx?+OMDAw41w9$W?s z0p!3DKSxYqX9!7A#25!1Kw85BH85if&nya8KwbG^pHJTf4k}vaOHQ+}Je4bT9iDCl z+K}XO8yzn_exx=rT9x;b1!OTFRv8bC zMq2y3vD?msdB_agMQbw%3YSwvRGh0hXfxum!QMK=ku1}sIQS6!T*R_}QFLr}FUPxP zKt8|165v58`ylr66r5s}3ezxJNQkB66)yKvp!qxVfYRGZ4Y*3!zKqz)#l*`HfVq zIyal?UYUn({exlr&T?nvGKHBUV*(%0R-?h|~Rxl%FU%UI9Xq^^aS_H4U4JE@YsFMUy2fm}AM@meIl<`JBP?Y$- zxn^*3_}){-AR5LH?mBtf6!^s#XlR?pm={ob13T%3>epdsSKkGwkt1K7Y32y}MB<02 zmaV8D81!?tgiAb|-qjG#KXZ36Dumlhz?bSP=g@?>=w47J#%;__cV5%hs}0jgW^1mn z@D=?~5Y}KWqD9;V{}Dp)WyE0wD>Z(8Zn?ZXZ|Lh7QQ1Ap2uSD@|0$s%I)bO&=N|XB zfh;7d=o1oPaNSR2I>XL5upft3_A7&>t%#Y>M$OrHf|~lh)vINz;=@oP$2Zs7H$PV)QQpO-M?`n_D-+v)MW8i8vo zqNK(&Z#H@Oh&5IHx`N31b?)Si@MabLAgj`Qjy71zeR*CMX>0?Sa`}*8H!NESEHe9a z{!KpV<1BbIa>&I{4Vs%OL2}XkbeyF60X}Ur<9eirrOz0pMuo0~&b9~24+*)!f*CyD zI$k7FDS(23SG2+~mm>JXn=jf9t)($vdG}jTY zrUpjZZ~h}(<&jdgCoz=>pI6k2@Jn6{&6Q64uMsn;G=gyK!c4sR0@ojCXV-yIn zJ8jjk5EA?k_bQu~q|drxPs*+oiU_++Yq)}odX;pHgqbkPQNaZ=+&9?$yQ=P}m~b;U zKC*$fI|oq~eG5G~0N4n{s!ox7zJlWstqITE*SCpXr@IL-O!VYnz$B#&w)fkcsvBSg ziIilc47sAA;0g-(g<}b9g2;MP?{Uzmqj|w7t$Xa?W=RztzfGZUT}1f3nzNtS_%l{R zZRtUs8!MQBRhoIE$dsSBfSJzlHd(;!O-e%+wqF`+HErs7<%F+MI4xg=6W>hYbNA^P-9bnibXtyZ#0!Z7DfU zPFQLWaCeBi-t?U25v+~=kFS>i>ef#W``IrJO{_m(2)3t(Evo0gCM*PD(wz?#6TN;Y=F$z#$wB%44{^^`%oVB?Hr zF?W4tCK^H(W3fHih1VDDb}Wqc)AV9D-F`VpCt7(UD{EU04O?-^EY zj*b~M)-YfCl?zyr*z#a+@6WAbebLsL(#5u0t?n&U3>1n;ey$@jO-t8)C^YHn`toz3 z_Sox$W4oJ6fbfKt%cJ`C7c?PM)B2BBJmc~|hnU_s6nZmO&*pJ^VG@et5&nT>Afp{4e##x(_&nQLvBfUeJF z9_B(NamrjXMXYFNR9128vO=)p5Yp_v_J!a;M260FBA^;1U)nr|XRAj~+J?0t6Q2HZ zX=d+%!<SeNGeGzm$9ef9L+IQ$ZZ7WT%Z=sMb z#|z9k`8J6bd9tU>$?~ACX=SC~wGX_sQRiH9TC;O+bc^OsR*UZFf3X>ltcqlhIeX5AIqfvCvrZl!*!5QxKXK<{Adu7vnlFig2#_55Y zjO8Fa8{~WS`AU2?Lz*Iyvi#bj%1}(pOX_Qv*gD?)rGkMC0+6F?>G*-pF`QMdFSRp$ zyi|^qydY@7!43;?o{CaxHczI;| z#a3&zOFlb2Po4m;=udYoJ>c_jQyC^~skmU5PnpuB{3&V9MdqM{>@Z}g3zQp>t=N-2 z@i8(Z>k(w`wVynnywKKaSk9VKG0nDI<0H1W_T*&QeYHiP!5BYRE{BTM=J3Gcmf|!! zmmZIJb0=(CSHaNxC?(m&gL|?Q_BU=)G%k42l9rOlT=#6!7PZ+|L!R;?uzLr4#auRd zk45yHPqQV4j89spUPxx-G(N*P!-<}D(_T!0v>jXjGs+ZvtC9xa^>`t zargA~ohH25HQ48|zUb!VNcEEE$ZpsO#H>)Jkt+e44-dt7?U-!%RtHAMh1W^4q<{ID zM!iU;p<}GVd8qh2lNs} z2*ddYg$dHRYO9A##6MwlZo<$>jeN9KURUwN8%CFzU1A(Tvr^h#}9~sJ* zcuvD2&VN)EXqH<>_CzV2(~A|}+x)F4dDm9Kof4`7xubNoJEcV<}A?dOn?f_A7R zfwi;?Ui8O8v4GaVxPJ+{1#4B2`ub?n+)w~lF3-Ef4q+2<1m?tSk7kJMzQQ^fI*+2j zLd4IB5THIM16v|%J!uz#b~d-8;nHX`wGwSN*ZXQG1iytTCubiu4LSu0tuJ#@djdh6Xi5c}h*0wX;;BK#smAb6FHdZ(p0NBtqn{Ns3g`_JRwX$FSBsXG6TNB||*NkRkyQfK{hY}FsJeVWs7x)|H zuk%;mL*7pj`wcOa{5#~&nPTtb-@DEKj`vjmTl{bD`S*zT-q*ho4BCG~{M!lpJ>k7~ z>Td#*;ok{=by9s#dGCk$n^I`}H_D$CsQ2OTJ;8p5uUq{+{GSeC?*Z>EZ+-&=9R3FQ zw*k&?!rQs;#MXaEv;RE)c(v^LSHi!9+W)#T-%fZJ{fA2F_W|Yg|D*roCH@xj4)m|P z1Q5_4%lPykK>rkS|7$J(S<3y#TK>FDo&Ou+ufp!%U(BDl_j>BzI6m+HzqP;W#Q&kL zevf;vYW|Ib^!eYoe`uWF0l)vhw7;ro-;>^p)_#-V zgZ~@pKi+cRx6}Rxwa5M!(EqymzHcP_jYCfSFSviU6~5o$`*QPd5^MH Date: Thu, 20 Jul 2023 22:19:02 +0530 Subject: [PATCH 0565/1464] Update soccer.py --- plugins/minigames/soccer.py | 130 ++++++++++++++++++------------------ 1 file changed, 66 insertions(+), 64 deletions(-) diff --git a/plugins/minigames/soccer.py b/plugins/minigames/soccer.py index d86c7d54..fccbd4aa 100644 --- a/plugins/minigames/soccer.py +++ b/plugins/minigames/soccer.py @@ -2,23 +2,24 @@ # BY Stary_Agent """Hockey game and support classes.""" -# ba_meta require api 7 +# ba_meta require api 8 # (see https://ballistica.net/wiki/meta-tag-system) from __future__ import annotations from typing import TYPE_CHECKING -import ba -from bastd.actor.playerspaz import PlayerSpaz -from bastd.actor.scoreboard import Scoreboard -from bastd.actor.powerupbox import PowerupBoxFactory -from bastd.gameutils import SharedObjects +import babase +import bauiv1 as bui +import bascenev1 as bs +from bascenev1lib.actor.playerspaz import PlayerSpaz +from bascenev1lib.actor.scoreboard import Scoreboard +from bascenev1lib.actor.powerupbox import PowerupBoxFactory +from bascenev1lib.gameutils import SharedObjects if TYPE_CHECKING: from typing import Any, Sequence, Dict, Type, List, Optional, Union - class PuckDiedMessage: """Inform something that a puck has died.""" @@ -26,7 +27,7 @@ def __init__(self, puck: Puck): self.puck = puck -class Puck(ba.Actor): +class Puck(bs.Actor): """A lovely giant hockey puck.""" def __init__(self, position: Sequence[float] = (0.0, 1.0, 0.0)): @@ -41,10 +42,10 @@ def __init__(self, position: Sequence[float] = (0.0, 1.0, 0.0)): assert activity is not None assert isinstance(activity, HockeyGame) pmats = [shared.object_material, activity.puck_material] - self.node = ba.newnode('prop', + self.node = bs.newnode('prop', delegate=self, attrs={ - 'model': activity.puck_model, + 'mesh': activity.puck_model, 'color_texture': activity.puck_tex, 'body': 'sphere', 'reflection': 'soft', @@ -54,10 +55,10 @@ def __init__(self, position: Sequence[float] = (0.0, 1.0, 0.0)): 'position': self._spawn_pos, 'materials': pmats }) - ba.animate(self.node, 'model_scale', {0: 0, 0.2: 1.3, 0.26: 1}) + bs.animate(self.node, 'mesh_scale', {0: 0, 0.2: 1.3, 0.26: 1}) def handlemessage(self, msg: Any) -> Any: - if isinstance(msg, ba.DieMessage): + if isinstance(msg, bs.DieMessage): assert self.node self.node.delete() activity = self._activity() @@ -65,11 +66,11 @@ def handlemessage(self, msg: Any) -> Any: activity.handlemessage(PuckDiedMessage(self)) # If we go out of bounds, move back to where we started. - elif isinstance(msg, ba.OutOfBoundsMessage): + elif isinstance(msg, bs.OutOfBoundsMessage): assert self.node self.node.position = self._spawn_pos - elif isinstance(msg, ba.HitMessage): + elif isinstance(msg, bs.HitMessage): assert self.node assert msg.force_direction is not None self.node.handlemessage( @@ -90,31 +91,31 @@ def handlemessage(self, msg: Any) -> Any: super().handlemessage(msg) -class Player(ba.Player['Team']): +class Player(bs.Player['Team']): """Our player type for this game.""" -class Team(ba.Team[Player]): +class Team(bs.Team[Player]): """Our team type for this game.""" def __init__(self) -> None: self.score = 0 -# ba_meta export game -class HockeyGame(ba.TeamGameActivity[Player, Team]): +# ba_meta export bascenev1.GameActivity +class HockeyGame(bs.TeamGameActivity[Player, Team]): """Ice hockey game.""" name = 'Epic Soccer' description = 'Score some goals.' available_settings = [ - ba.IntSetting( + bs.IntSetting( 'Score to Win', min_value=1, default=1, increment=1, ), - ba.IntChoiceSetting( + bs.IntChoiceSetting( 'Time Limit', choices=[ ('None', 0), @@ -126,7 +127,7 @@ class HockeyGame(ba.TeamGameActivity[Player, Team]): ], default=0, ), - ba.FloatChoiceSetting( + bs.FloatChoiceSetting( 'Respawn Times', choices=[ ('Shorter', 0.1), @@ -138,31 +139,32 @@ class HockeyGame(ba.TeamGameActivity[Player, Team]): default=1.0, ), ] - default_music = ba.MusicType.HOCKEY + default_music = bs.MusicType.HOCKEY @classmethod - def supports_session_type(cls, sessiontype: Type[ba.Session]) -> bool: - return issubclass(sessiontype, ba.DualTeamSession) + def supports_session_type(cls, sessiontype: Type[bs.Session]) -> bool: + return issubclass(sessiontype, bs.DualTeamSession) @classmethod - def get_supported_maps(cls, sessiontype: Type[ba.Session]) -> List[str]: - return ba.getmaps('football') + def get_supported_maps(cls, sessiontype: Type[bs.Session]) -> List[str]: + assert babase.app.classic is not None + return babase.app.classic.getmaps('football') def __init__(self, settings: dict): super().__init__(settings) shared = SharedObjects.get() self.slow_motion = True 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.puck_model = ba.getmodel('bomb') - self.puck_tex = ba.gettexture('landMine') - self.puck_scored_tex = ba.gettexture('landMineLit') - self._puck_sound = ba.getsound('metalHit') - self.puck_material = ba.Material() + self._cheer_sound = bui.getsound('cheer') + self._chant_sound = bui.getsound('crowdChant') + self._foghorn_sound = bui.getsound('foghorn') + self._swipsound = bui.getsound('swip') + self._whistle_sound = bui.getsound('refWhistle') + self.puck_model = bs.getmesh('bomb') + self.puck_tex = bs.gettexture('landMine') + self.puck_scored_tex = bs.gettexture('landMineLit') + self._puck_sound = bs.getsound('metalHit') + self.puck_material = bs.Material() self.puck_material.add_actions(actions=(('modify_part_collision', 'friction', 0.5))) self.puck_material.add_actions(conditions=('they_have_material', @@ -193,15 +195,15 @@ def __init__(self, settings: dict): 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() + ('message', 'their_node', 'at_connect', bs.DieMessage()))) + self._score_region_material = bs.Material() self._score_region_material.add_actions( conditions=('they_have_material', self.puck_material), actions=(('modify_part_collision', 'collide', True), ('modify_part_collision', 'physical', False), ('call', 'at_connect', self._handle_score))) self._puck_spawn_pos: Optional[Sequence[float]] = None - self._score_regions: Optional[List[ba.NodeActor]] = None + self._score_regions: Optional[List[bs.NodeActor]] = None self._puck: Optional[Puck] = None self._score_to_win = int(settings['Score to Win']) self._time_limit = float(settings['Time Limit']) @@ -228,8 +230,8 @@ def on_begin(self) -> None: defs = self.map.defs self._score_regions = [] self._score_regions.append( - ba.NodeActor( - ba.newnode('region', + bs.NodeActor( + bs.newnode('region', attrs={ 'position': defs.boxes['goal1'][0:3], 'scale': defs.boxes['goal1'][6:9], @@ -237,8 +239,8 @@ def on_begin(self) -> None: 'materials': [self._score_region_material] }))) self._score_regions.append( - ba.NodeActor( - ba.newnode('region', + bs.NodeActor( + bs.newnode('region', attrs={ 'position': defs.boxes['goal2'][0:3], 'scale': defs.boxes['goal2'][6:9], @@ -246,19 +248,19 @@ def on_begin(self) -> None: 'materials': [self._score_region_material] }))) self._update_scoreboard() - ba.playsound(self._chant_sound) + self._chant_sound.play() def on_team_join(self, team: Team) -> None: self._update_scoreboard() def _handle_puck_player_collide(self) -> None: - collision = ba.getcollision() + collision = bs.getcollision() try: puck = collision.sourcenode.getdelegate(Puck, True) player = collision.opposingnode.getdelegate(PlayerSpaz, True).getplayer( Player, True) - except ba.NotFoundError: + except bs.NotFoundError: return puck.last_players_to_touch[player.team.id] = player @@ -277,7 +279,7 @@ def _handle_score(self) -> None: if self._puck.scored: return - region = ba.getcollision().sourcenode + region = bs.getcollision().sourcenode index = 0 for index in range(len(self._score_regions)): if region == self._score_regions[index].node: @@ -291,7 +293,7 @@ def _handle_score(self) -> None: # Tell all players to celebrate. for player in team.players: if player.actor: - player.actor.handlemessage(ba.CelebrateMessage(2.0)) + player.actor.handlemessage(bs.CelebrateMessage(2.0)) # If we've got the player from the scoring team that last # touched us, give them points. @@ -306,30 +308,30 @@ def _handle_score(self) -> None: if team.score >= self._score_to_win: self.end_game() - ba.playsound(self._foghorn_sound) - ba.playsound(self._cheer_sound) + self._foghorn_sound.play() + self._cheer_sound.play() self._puck.scored = True # Change puck texture to something cool self._puck.node.color_texture = self.puck_scored_tex # Kill the puck (it'll respawn itself shortly). - ba.timer(1.0, self._kill_puck) + bs.timer(1.0, self._kill_puck) - light = ba.newnode('light', + light = bs.newnode('light', attrs={ - 'position': ba.getcollision().position, + 'position': bs.getcollision().position, 'height_attenuated': False, 'color': (1, 0, 0) }) - ba.animate(light, 'intensity', {0: 0, 0.5: 1, 1.0: 0}, loop=True) - ba.timer(1.0, light.delete) + bs.animate(light, 'intensity', {0: 0, 0.5: 1, 1.0: 0}, loop=True) + bs.timer(1.0, light.delete) - ba.cameraflash(duration=10.0) + bs.cameraflash(duration=10.0) self._update_scoreboard() def end_game(self) -> None: - results = ba.GameResults() + results = bs.GameResults() for team in self.teams: results.set_team_score(team, team.score) self.end(results=results) @@ -342,7 +344,7 @@ def _update_scoreboard(self) -> None: def handlemessage(self, msg: Any) -> Any: # Respawn dead players if they're still in the game. - if isinstance(msg, ba.PlayerDiedMessage): + if isinstance(msg, bs.PlayerDiedMessage): # Augment standard behavior... super().handlemessage(msg) self.respawn_player(msg.getplayer(Player)) @@ -350,23 +352,23 @@ def handlemessage(self, msg: Any) -> Any: # Respawn dead pucks. elif isinstance(msg, PuckDiedMessage): if not self.has_ended(): - ba.timer(3.0, self._spawn_puck) + bs.timer(3.0, self._spawn_puck) else: super().handlemessage(msg) def _flash_puck_spawn(self) -> None: - light = ba.newnode('light', + light = bs.newnode('light', attrs={ 'position': self._puck_spawn_pos, 'height_attenuated': False, 'color': (1, 0, 0) }) - ba.animate(light, 'intensity', {0.0: 0, 0.25: 1, 0.5: 0}, loop=True) - ba.timer(1.0, light.delete) + bs.animate(light, 'intensity', {0.0: 0, 0.25: 1, 0.5: 0}, loop=True) + bs.timer(1.0, light.delete) def _spawn_puck(self) -> None: - ba.playsound(self._swipsound) - ba.playsound(self._whistle_sound) + self._swipsound.play() + self._whistle_sound.play() self._flash_puck_spawn() assert self._puck_spawn_pos is not None self._puck = Puck(position=self._puck_spawn_pos) From e4a317c8a93520619c0383f36876e91940294456 Mon Sep 17 00:00:00 2001 From: A Dhextras <104954857+dhextras@users.noreply.github.com> Date: Thu, 20 Jul 2023 22:22:06 +0530 Subject: [PATCH 0566/1464] Update minigames.json --- plugins/minigames.json | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/plugins/minigames.json b/plugins/minigames.json index ae4f5406..477e2b8b 100644 --- a/plugins/minigames.json +++ b/plugins/minigames.json @@ -14,6 +14,7 @@ } ], "versions": { + "2.0.0":null, "1.0.0": { "api_version": 7, "commit_sha": "e59073b", @@ -612,4 +613,4 @@ } } } -} \ No newline at end of file +} From a941899b19bc243f9fc9cbfbb28fd0c94dc93fab Mon Sep 17 00:00:00 2001 From: dhextras Date: Thu, 20 Jul 2023 16:56:57 +0000 Subject: [PATCH 0567/1464] [ci] auto-format --- plugins/minigames/soccer.py | 1 + 1 file changed, 1 insertion(+) diff --git a/plugins/minigames/soccer.py b/plugins/minigames/soccer.py index fccbd4aa..cd9b4f5b 100644 --- a/plugins/minigames/soccer.py +++ b/plugins/minigames/soccer.py @@ -20,6 +20,7 @@ if TYPE_CHECKING: from typing import Any, Sequence, Dict, Type, List, Optional, Union + class PuckDiedMessage: """Inform something that a puck has died.""" From c84632fecee4df1644f8805e8e687a6a41339361 Mon Sep 17 00:00:00 2001 From: dhextras Date: Thu, 20 Jul 2023 16:56:58 +0000 Subject: [PATCH 0568/1464] [ci] apply-version-metadata --- plugins/minigames.json | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/plugins/minigames.json b/plugins/minigames.json index 477e2b8b..de4d1409 100644 --- a/plugins/minigames.json +++ b/plugins/minigames.json @@ -14,7 +14,12 @@ } ], "versions": { - "2.0.0":null, + "2.0.0": { + "api_version": 8, + "commit_sha": "a941899", + "released_on": "20-07-2023", + "md5sum": "19f033445a8fe30fc7f4f62d94a54444" + }, "1.0.0": { "api_version": 7, "commit_sha": "e59073b", @@ -613,4 +618,4 @@ } } } -} +} \ No newline at end of file From 768b28bcdff2a92d95792457b2832c1657216d8c Mon Sep 17 00:00:00 2001 From: brostos <67740566+brostosjoined@users.noreply.github.com> Date: Fri, 21 Jul 2023 11:40:52 +0300 Subject: [PATCH 0569/1464] Delete plugins/resources directory --- .../discord_richpresence/pypresence.zip | Bin 8353 -> 0 bytes .../discord_richpresence/websocket.zip | Bin 48208 -> 0 bytes 2 files changed, 0 insertions(+), 0 deletions(-) delete mode 100644 plugins/resources/discord_richpresence/pypresence.zip delete mode 100644 plugins/resources/discord_richpresence/websocket.zip diff --git a/plugins/resources/discord_richpresence/pypresence.zip b/plugins/resources/discord_richpresence/pypresence.zip deleted file mode 100644 index 250d8e2e340019b5f60fd2fed65ec0505cfde78b..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 8353 zcmZviWmFw&leRbR?k)i~9xMa~I#vgTc z&27w`baff++`VE1r23gq1JAGNf^^`2B{jIA_V{alM4%OEPfnd^?XjWame9UFmyv;} zgmHvzzaMWO&ZmYq^WUiJNp9>hnKj}$Q@ar09$@J{>VinK3m?P?MHw{jtl@y*n>KeV zLEwj8rE0{cYc9Y}HIQSqIoQQ+oz9k^-~di!()t-2^pe*OG*7pW0z zKiXV$dVJy)*W4_4Raw?rD)j&@|F39#*3CJ^g$4k+F#rJEe@DYW-_h96%G}t-={+6= zYU;MD?5N%wx;<9J`7&5!VjxJ1*O)~KebNvlpa6)z5uCx^dR|KbRbnMP_pPH(3Z}q0 zT?s`eG(FtWla+1lQ?4@XC~sAc6iaj=+dzIH*X+(L%pa$`0S^|Z@=*j{5SFA7R~o|7POw-N3s?dwoTd#EvdhZJb0z8_UxAa!IQX2r~qi!rfvNoSQg?X z35e6_3hA#GW=Cam;1_R4BG>T?krmxH+JyL6w07?sWRsCcX5K7+_u>W1CFG=NC<5Ih zJD#5rcA8=(_)`H}Gq^@fC^}0Sq(r@B^A62oJ?ut*zGPT`S z^QVi3s|Kx;1gfZjMP|9^FKKVzO95Ut&oVsLvWvCvF=>H|R&|ZuV40kPp_ig8pJt_+ z5v$i<&BXvzK*eV1wY_wu-hh4vA^S5UpAlkk99IF85TcRGf>iR>}>` z%}M7W=i9Sy%(~JXGkcvUh@%=5KuplRQrAW9{EdlEPgOjZPJrvmUyJccU=qYqw$qkn z^wBANDE(SGbydIgg7SlXQVLAU2r+NPy`-hV(s@Kmp|Q947=L%jx{?%)Aq+ ziB)OhBHe{;UTOfvAUx{Cr({a;2GY74Uma4&40NdmvE*jaM7ZuMpK&vLt6EG#OfPe1 zpBD&N4uk59Y+HB58^=BMgA-%k!1@~rxHI2nHw0i#vPLXx1x3X$4ci2>_~X1;o6RCD zE^rWbA~k`v4PunOH;oY9O2 z-me?^OQb+CEVDZ3u;N+5!q{5$wjeYS1=Ex-Oa0NhElK&mscBOZxKKD@`qh6^b1Z5+ z36Kawry#5LJ`z-vAAQ4~I~xqPm7es2XD_y7fQ@A**;Q#SCvllreaW{~S$e@l+vQb? zN-8J`9qYbNY<1ZNk0@%{L#niy-f5aq?5@)rZgs1}L--~q?(wk2lrx%T^+BR5~s4>)(3 z2;hux+37XMutmaarez03lZAQP$<^z?z|w$&?5*kadfdE5l1qf>fJ2?mSxCY|7(I-> z8Qcy&3fGfCFuP`Q(Byuz89cR6BGgFl8tpvQQXSK?E%a|TW4fGb%ph+f=|k!dgZELF zwk;s9A=`%aPb?vXH;&CBF)A`tty@D-)V8f|(0b8ZSfgrD^Mm=dOJi{O`Wcluy+v-HnsMz}+<3lBm4zG!EL zo3mTDW6BvV^AQeHQT&-kjHj~nYztWdPo!)l(w!JuED#Gidq{ooS{-#lAM&&|fUu&m z!zz(0+#{w`Be+Dh=Bp^=QfjD3%;VqIlV1mDkp>Y_Svwpf1tO|jK79LGr8`an*XaHD zhz4Z2n_Sg9Av!Xf$~NSTYO~VF5vE)OW8U}n0I#de;>{;@aS9r-&2B#J#~KRm`LQ!U zwSkx_6dAsFg6Jhj%ERxI9T7mt6EfkA$-(rN2k=?_j!w!49)irPYjlvc!%j0Lg?rML zM&{Y}Au!PAIZqn@K8J73-ZKwQk;|-?H`%t+U-l-3Yr{n>I|g?Et{#fcQen@;KI0)X zzWF%kp4Z{+K%fZ7>dX{2eK@RNZ?8R3Qd8KCibX@TWGOcvz0T_Rc(JG{sD;=ENl*zB z{s#DWH7T>N86klM0E~G6fWIp4KWgiLD#@w3rtJzlruTi-<}}P`iHVgLZG;8?LIeLd zYwBt+4_L%+NoHwCGNlx|Y;;c>uHr{FONAJNF2U&H^r1W?lYu-u(_*UMWAH(hEO7^5 z&P|e|?VZoXkRPi8@y80($h@*Zo%{nc8zs{a3(T4NBIu%U3&!VF7dw$&3W#J`7;)yb z&9uQ4P*ig0BZA!$$_yj(fUmyi#G^9bf2Gho&( zU~I3Tjyq;b%lqN=v5E>B6-NHXOlO8GC7#IpzCfCv>6VQCy>IGHi< zh%?bkw0Pa|~wE1tP$FQ+y!%mX146Q?S zSMRcJGq4szNad&!aJD3uq@FFxutCj zVn$2$Y!n)19L%GyxfBUWeFi4qP9xxVl6$25Ij_x=cj?)AQUcoZO`@}f>1FC2;;SJH z-VGVFeLrZ@FuP7atXQ#?v!uc`P`n`cVz2dG)z24(?4g`q0 z9X?;2o)4gzsIYC9FY6of0B&c6R!G#y0=P!9>ovTn70w(kCy;=`?F3vAKmE%6FP(%@ zqW;*B97io0cd1dAy>|83sH0`9K-)QlEX?+aLe~Tk0Xr-kpG`IKe z7RCc%XrA&@@6^{UAEjVXjy8*y*-3`jWcv9o)8oBpnQNffyH7*Xh~u8-uVyWKhjPQWk%A}=kqY4qoXe8MF&`#;9 z#B@HUy>N$6RV|xjeW+g9usLFC;l{gwyPi~LWuf!+&Sb`7xO+K-MH7T?{o%Pw0~~Zo z&?+u=*A;0G>GNFY`4j(V6#l}vnb@uIVua;v^Ic{YvX7E(kaBk3RW9CcaVMhn=MUGD zJ|pC-Aa}IZYSB9%tf}G$q_S#}-N1V#;{$Sn1IeR&b)Y_^R9Cy>lmepVu@%TpA@2yq zcp~$I&((3w`gYka#>(moj~jW}y>~26;94R1VM*e>3Nz978QO}cL}ZXOXGBJJ0@ba= z31At;bvGqZTmlAseFchwDYYL#n$v8!0kd4W={$g9SfM|3*d{{%nzD((f{&4oiE5HX zB4PPp1L{?x7&#?(%=1&!dG*dFflqP5raR2>#X`KSmX`1cX~2BT$_t*&)9^EsopoPy z&gEo~l%VAir%niZI$kYMMT*QhE}0EXb~SfV)y_7AyJu!uZ)6$zX5936WjUP-Sig@*%ONv3J{hJSA|4nYdxxr*z?rF z#x023yqUz*;U2bFVjcTYoL?_ zV{opTzVl?ftntca8IHS+{e(mg_ud^C+mlD zA{}f~NPVU81yb>>82`Z_BnI{nG3))F{)Nluw~I@pkEa#iNG3-Xh+ihgefIaX+dkWL zq8B5CF)F`0)Q0Er`DWei6?(ZJ{_wstE$mP`%ww5$CT}*=Y26xEA(}RY_-CuQ(w-3uMjjz)> zRkUc+S~TBm!yBy1zw@2d>Rb5dpM;(1(KbCDefhVbAZ9X)NCyW1D&9rKAML5Jo1w9t zlew*p<9mBrktk(Jz>GS0{u|SA<bw_v(S0sb&Yze8Wa`rY&&hP z`Ch}H?Q3cn+YUZ;xxWq|m@uq%uH)Aif1c3&tRicXc;~ZyjW&gv(&s>v=rn3@+}F$ahS2;Ier4QysC@-69Wj#_Ji#SKijs?!G|{=7 zIwbXHc}ZfN1(XI@i(ZaVI!_Nh-UGHpA3TkXaUjs}IvJEr1ev^ri0wtVSt;<;8E$8; z;v70cYqY06r`t96bx z@i#eJ*{PNu&~B~rT=x3jQ>sTev%~yderT|-|J=o|PEw&^v@0dbmFo;vuo7xZVz*Hr zm_2Ox0ZK=Ub;JizZlA>`qIAfo5eM4X{OvA5raMrb^g`sS4kDZOP^vHOU`f#WE7-w7 z>aSH$c4G&&syX3zL;U9zC$55_N%%uc5BuHQ`VL-;{mN(**=`+~ma4L_6Zj#^0U^4i z24{*{0t)xO&RqlRG+VP@xVx0HZZp8dG=tAokA{wT3Ica?&5b+B?)N>@T zkinLvuBt_g+jsb8$_Dz@@WxWMk40~5+B)1ZE+Q-o#0@r;7Yf~(L&%U9>LYrwq3V_7H4uXrg`XN| zf?&ghSF9*Olr*;LKi@hX#Ul8B#+>Cb@=rjRtFuHP9D#B^esKY6HDj%+5FU*=EHnk_orp2{}p#S=|J z(7hEAr#!*8h=(hMk2O~lwU6Da)h)qAPa0rT#F>N<9sj5h7$!oaOhBv}hSuh-`T;o_ zaa_{UO`|uilr#c!g~fRz8l97ZGklP##t+GkQ$rC7;yii6U! zu^Vnj`b5p8cP9dGdG)pic~wz`m6IP24e)NDgmvePK&;U zQnc%KSR}(C*&-BucGZf1D}c+wp9q?swH~^I%NCAGUqNUQ6VgJ@@JDK?!2I_iKXo)S zaukcl9k!^Vyg7ojVrPP>I!WKr#=8rB6ENPGYTr5Dti743@0@|l+iXKH#b7uuTQEGHrBUVCNesR<^W4>`+Tj!bP{qS+grL|8G+%4X@|e$s#5&ax~3!z081B6)w2T+>~|Z zNnedE$0&0AMmcDUA?`y@8YPFNgDCn%QcS}?(LbKWP#8ZtfHxHg5-vcziRjMR&_$1f zF#tEVsb*9|mzwo}hW|)rpvzdapn4t8JbQ z4_Aj+S~3X1>h8>$_P9{g@~zMlxcIL4xS}EUovd7D5@{OoAE+*R3|R@;g{ybzbHSXj z2t~>X%mr_)NBZc+58x-_=%&8zd{*(0m#w}nWDsxUp;7qS%iMC8AGl0(DZhgVVF0R4 ze{SkYOFQgG$!<%T(8=67z(%o@SaI~C)gP5bN)5p^_-?qhs#t2?PoHMvx=1*XZAuEo zJY#1^>dQa4pz6?-!}*28sTVTL@Yqk6T4Vor!xwcm#Wy?saP#qO(QQT>)9wI?asFLh zUO;)#QpYV0kAb(otNMe_ONc~gb9}6xYolbLW^t;u!k~tS$GI zx_%VrdieBapz{~LE(83U!O_eyA(p$W$n*Lg9hj<-9KxEz9g%-9XQ`%gI$C^68u3Mm zcP_5unTt4h(k@i9^jNO;ZXd!No)vxTZ9Y#S1D4&xF3s;y^m3sjD749hO^G}=qu;LsREd;J4|qSAK3?oU3M*S~57o`lq6sWCE~FQeN+gM@Qs~+t1Y%|r9=ddGkDzo-f1mXP ze)?!_dx5#$w)O*#(+aQn20CRLo~0IiP|x2!Wwuo|EHD_P)J4%3dAO);{d?@_X1s+#6r1dkj=+-eev5CRVO3O*y+QsPXHFww zQto44tlAHC4F|aA*CkH~RVp6*1q!OGRNl%1Q}ZiwJ~y|QXbx!Ctlw+0O_&?Y6=A^J z;{Id>B2-Xnys|`A%^Sv%Jw>2V+9c;5_}^Sy{T_wTBroSkJKsGjXA%y+UnS3U-|81_ z)(*?gc`yP4&PGEBnsJzdA60%Jj+D(CY>6`)x@DG`74vI}6WX-D5 z6RrC(h~~!nf*bon2$tzg2kw1yy$Q30+c*jIgghueycXp%_?ZaN#@s1WNXN3?k)P0q zpeVCgvGKgJ030GLyFZCSjW&|(6@tn^i@fSNWg3DD*$xoaK|kgqrA$E>bQE@uwZS6e zm)19;IGb;=&zT~0fg6hi0}LIvaN}GCQBGOn%lsb5Ksq%?<>gO4--fj<5X9=DVct?> zyHL`CIeQ4)U@=2e23>7A=wH&-(;0OZ=V4)}P|TweSI%$pA7lqa!b!Ovf_yF(*p%NB zo!foS3fOSi8qzPzVo#hL)IP6#@lT;0!2wMJjq>0A)>3j&Ln^)_efst9$<7G_0KCty z{%JQlJDFSkC8QFSHY`_|P`&SU$=YGKW4=~*VD%EGT46S#_rm*|;Lh=J&^8)Tv{+NW zZny%aDz_=Mi+~wto#)<1zdm<1=9(x25$F=w#?G3JwIJdFlnEz|b>(1&cj|EwrM7aVsjDsM!;gNFrQ@&e#u3Up&SaW)@>H2oE(T!_nZzFYo zL@EqQqALCHKE3wW1S#6*k9@@t``P~ZIX$sVC-B;YCpL>`n)hX+1 zP8_^?G=73xHZ!;guGbVW1x_0qXsMrf@8vRFC9P;n1|eJ>_=`YMr6utGLL8{eS5=B~ zQZhDGADDD=cc)sDB7{;*4=S%{84zuuDv)3>x=$F3O+6MPiwD`8=}6|pGAL6)Jd)PO z;RSuC>Pp(U8o!;J93?69bZ?O`LF6Xc3zz0$&*)(HzhV)0i8tDr6kj*tBZ+fg@upY8 z$dn&TI{&F-H+;)?$i4a1C1wY_EXdvKcLJf5G;rlKnE{K26W>(tQy%!ew#zT3n}D3J zTqkAbb8`*Hz-fKB!=y{iZ7#wc4@#q>52@UKpmAAKAt)5gUilIj)A+~22Y!u?A^@5J zJmW^~y*Cj>eET;SX*m1M5 znVw>6aUMB{cW zxQ?yqhJUS}<{f=;s)~{x3WYr&EaU)_NBjNmse^%I{(t}c|DIUCXFA}0c>UkUKRot- z%&-4s{5j|S>*oJrAippFVEk+9`zPg3fB$ca*83;;56XYs{yzzSHuQfJDp3AK_*Z-X zC*{v3>Tik<`oAduXsP~W{8=ggW~{$E4gYwT|M@-OeK+|hPI)O{5EK9a00;m8 zj5XEc!T_QTKmY(jU;qHr|8Ct(44v$ZtW2Eg_4F)kEu8iA=xV*dyIF>!Q6~_}pgoz4LtMi-6Ui7|e(uE1pnv8^h(7w?-i65}3MUh395hOM z)o@i8GWy2tL9MDIk9L}aQwvI{&gX@0fWB`%uBsK4&b|a@QVkq=J3yObdU{|bcaj9L z9e};M1^~K6#=F@bIaNgO!G%c73=(yR!T{s5B`3z}D&4%+FYv03*2R*+Pzp-X0P|oy z!5a0qXWNQv1kc0Uz!R0ClzDTp+9O-^Tk?B^U!+jXRiTcpGk($@+OIm5@s&&ISdL!9 zBagnkxw6oks1+)ggKQW@A>Qre1i`93=XISibRs%c-3VUK$?})iVY#{lq+2lsomt(u z@;Bv=1y*wPFr8INlX^kIMK=E>qQ;{`de236V^p~Ges;L44{&MGHGNR!q1LMpIy3f7 zseKsIEx?bT#@$or?Zp6$;1Ld(;e*`}#e-ehCshJHpnlx93*qo$RZffxw{Bd46*$OY zRKoz_4aFYbyDJpiC`)l0&V;@1a8yVdPh9T1#;0~RzVzP!4V6hPemUJXI%T{aqCX5A3U=_ zqD(|J!)n+H7Kkj{kf%DKys=80McEdj$@;SrXE&b?;{4Z-k!2L+gPXI36vcuw0amd5 zT3R1MtGj6<4x_CVp+EwYr-R~=YypvkhvU?)819Mk62Azvn8*TyjdY-a9$20L)_|{B zzcZ`Uho@+w`pq&-u9kv=zP`N1j1;*X8aW_1RXy!jy3Sw6c6{QO8~H>DWt0-<{cHk3 zP_k_!+Q2xy?VuJzc6kAx+@pelXrdHmzevXWuh}GyJY4Tcmoq{45A-`HSb$Fy14^lY z(#NC3YnaJ;9AdKFMtd4;d~RiS;rV38&t}b+FXTLT7%`*ANAmqPvYx?w-d|FkKi7`e zbpIB~P^N*U&xg1KHw60uWW>y3Sxc3TVrNJ8E;2s{cLHpMjlCwVd&E4Q9P>PT<%E=1x}E|NY|NO&ij)Rsm=lK) z<`HEU!l~(hBnh&4#p1``#uVB~uSj~KP5mzha?QbdZSj8nq4M1hIc6{v>c6C~!6GU0 zVP1U@_vs!h*wY=(p;XglIp=({3o5#$Q+$zY2)Y@D=hMT-XEXcl@eYG0=w!FkI6eUQ zEtpJc-0x@3we4Ni*c{AY8~?xxsfsAsF?^9SZ4$?~;jyvc%a6ZcZRU8;M5b?=Z6Paq%UWF7~1&*^vKS#}a{M|rjb>AOBz)h3w7T@wb zsG_W`qq}ux%vn4Rp1vPRm_0gNzk(OR=TI9x?BuWcow@S4)x!4Mv!uh&fvMTLv0z2R z?2rAvAK7zY$aJRNnwTv*kgpBZ1`v11ZqJs<-c>sJniTpINt3-DS~A?~V$JLRDV^c=aO1h{y6jBo@8`bl-Vp5kFa_}F?fx|E{V-kY z=6f;?VNsmrNWJNpEz)Y)IW2fG-ZW_g?$(vkiwat0_;fPtTz^;q3RxT+~AZ=O5vPvh%t5#7m#x<-y?_lP8j*j8jUkOIe{bY~ zQzFmb$X4;5vPQ)tar$dt;WI3k-{A@HbaeLaPE*9E4*4-EBmHQi_aX^3j7UMe)<;gg z48aLH7};-(Y8?>g@#augBiC1I-Beba^ZJ=R&#Y-NBqbZn!-8 zH))x#sGVq2uTDu(kD*%Jrcz*|qpF3R(53J}5x80D9W&@F9e-j9D#F0VAT3=TTNF~c z95#zk{25nV7w#r$>CV1tjU0Xm#83o}DnQ5QUnU5mBZnD48Qe@5wZw#>0(6dbTnzxn z!2m`O^uxY}e&<{5fmU4*;OK)HR@m5m`MM{w+eM#or>p2v;}M7%*6k~kNq+e$!L7${ zL2Z(WEi8E2`H~#!guPjLj&g-xY?VaPV|B@|^*QJIu=GrZcst41T;H!q4$k7i=pGq6 z>>9knTd!NyU|5eY)?5zyv=p5Oea@)v1d~;-GJt#=Zy?TljhnjsCn;)2k1;NVhD~!g zV!=#Va0^!sr+wh(gJ}bB^1 zOc%g_1RQ^eWY&-$uIppIL^p`n1Ddo;n5$_b)wCs4#gMLhZk`ygnkdAV`bc*eW%lU+ zUSdX7=@SDDo6R+yET!f4_!0Wy@#-7FdtQrI$%?}cK)T*#dGT&8FZN<;&_RR zFMzLA-@_eR$NHhkL(9Yt%q=MS>X30-DHg8Nom zRAG5R1I7UmFh(Rv#@%L^h{u$86cc;V$EY$*(ekrNN~Ydv90a`oK2FWIo1w;Nqn}&? zR%~l4>#P7&YdI2&)TGH+ccT$f*FW4fqfI#A@*$RtBMLNWQC#afWeEkzXgD%Inh7AMz=xfxm6Z2L`EIxu|-Z4?KYf0R`t zr?jLaki|a}dhD7e+j@D6<5TkIU>>4k#VY>zRgdz+F;31wEsKR%X)@Tf5g5ERXGZ4Z zd4WfpLKRoJRYB}GZp!*Bq}WmWjKgsza>)_~O=V|~Nf{6R;n~gnP`#V6t+IhMs25@a z1jw*Vu*Y1>Z=C*zOB~t^hI$eF+b78kysKO;vaaUPYO5R7-SH<_VM4U)1*?%`7-dx% z=EtWcOp;eqlLDU+Yg`!!7@ za%AWqYK~;}I98q02j32bFL)h0|*8PqXglgm?SwpS8$%vTq*4)1O@W z9*Ti7_yks%OR1;#<8aXuEmWzPvtlQ0XsxUMOVOxPNBajKSJm0pN~SO%aWC!1C9R7J z*f3vKi1z$_LNKB}{V154B1P)AG z)eWs&6{ZC2w{gxTlz*49JgH;F;!VlnZvXC6LTLRd>5m85lch!T-gw-~E9RY(%R=?KPZ43HFA5roiBhmw}(t!Rb#lybx! zr_Xm!neg?2>}RptYy65wI+S1-IL=2vT1w0}Kw3)8Cx9geNdx>sv^{pm*Qkt_N+ZoD z4i5V(AjNZ!=74ETGWr^;`8XWA%sqbQp-*+oifTlO5}cV<1!H&WX*|wnPw0k3G!9}~ zYV>=kp@CT=e2Nonms^Zdnx${y0*;yZ$@WLI*TQimMdR5I9?L~mnf46UgznwP-D}4Z zS}6n!)%|i>| zzF`F92o22#1My|ofbX%v@M5-cnOUnm9JhYIM@GqLqtOA3^UXVuPC}@9%RaVNpe&LmcA`EpD zz0wXdm(Ps)!crgZvrQ&CiGuXZv>}YZtZ#abi=1iuFTaRK>lDQm#^hm$=CIPNsu!xz z^Qrjfay&KGN?BVqatPP1r*xruHUhJ~PPhJGwTJc}Y793}3!S=Grm4w&&w3AnO< zRG9?$aTsX6wS7Z+d7UtHdK^`sa424c+LNjhQ!5R)DRB8AaLwY+3?3QUIw zok!``9WJ`=^qkJ?^TGgQF$CSQ6P5W63h_D2@_iwA5VGfEeQ5Rgm>x)F_OMSx*+S2b z&8ybJ#Y`0k5;ABM8az+Cgm<5ILWPjf&@k}q;p=IeS|sA&H#T<%+#{422X@} z!Ts<6mG6D;C0ow+H#7|cDj=5wzdM>LR*W*yvKO832lGTu=AnRndpcsWP+M*Xq9l01 zuI3N$e>40&AX!cDe|Tq25dZ-3|H<(7_Wwor6&@QqZ1%;y7ix$Tp%R|RLoOSI_ey}; zBkdpUSvcz!4=CbwEs5mj7t4+|dR1q^zpoh>y;N;SQqqf;0op)yqOhR@ds7a2ZPF}l z6jZ53rn9HYwDCGpxq~bU$)$Q`{3@4$Bay@!X`#l0Qzyi^51L&5^Z>)({wiHNjd0j1 zSI%go$}1w-CHK@vMD96PD8p**BIRmTjtJ}6LygvDpEG{lzSSF-gv(PNI>}hrPCGiN zTJF7v4cr7KLuy^xcc$7UC`xpfl7o*h&bcaK;}X1==C!N0uO5ooCx_lEn-A&QFkUN! zMvu(O;e^)Ixnbw-rs}p52gfH<3n7wd?2OXV9Y!DzAsa^Os!`r`#0pflKQF zXnjhvGY_6H{z|i9-vbfI;`*frNNfTDJ(rg-zl$5;8McR5lR`t62|z)`Mw3KGvNeFO ziBrR*GKuUN&MmT)Ofm(E(H=ciAjT>~{}@27Fgq#i$dP(Gm|Pc?6SKKIyS6O{Y2{dv z2G3l{^2d*?s;H@}t|>DCi@Ghg3kXLzRJoIwbM4 zR&lEJbHwn;#?4XCJKDrXszePPPMAgI0ZAJGeTD3X-w)ib&Z{Q;xx3n1(H=Lor94~T z+(x&vwzjjirK%}zSEngD+gd#xnL69rgDopp-yiC)t(BK5#G`(^^kBbn=we(5>3A1! z#@ii-Tj|)Ws67R(L=&bkRFf($U58erxbAWJZYN#q#6}X%$R-hb88!)2sgB1~W-`Dl z5kv|hlm^JIJM0Orxu@SR-Md#Lh`!$L^ndjB?cjsZP?|fB9pg;$OM(UbIwq*}ct_7L z@0ze1O=;Jf#^2Fw4k?iu*-SyvST@UeXz7-@qy6z}5*cHt*Io}s+EmWstiLW_*>uIs zk%=@Fh2{WgCY=8iID~BQ8CgIQ7W^DCWX012U002NCkXmHJo@j~Pl6&(;@DG?#k-S5|NBz1xx<8VV+AF3%&S zMckWAsY9M{N_y3T$`?0E5-`!*?|gEP?Q_v`9msaCsy~OSw=P z_#H=)gkNON;REp+xB$v9guT6|@SNT%59yl=#X|Q2aYIQhYKk_``w>G=oY1GOEuFtU zeycEVC(Yep!Q%&=1F~^ZUBcWHK!?i_M&L|wg5|Qo_aH*v&y5v%-Xl1-vtxuBJY)bK z2d!N_t{*NjP2@MUs2BU>MkW>=QbTrhc{x?bbL9W=I|8*I<2AqjM3G+1CFYbM;_)8& zrOfLG@r=fRjo*}(WV<~2yiKI?=mip{5`-HVD9&>O^$Hv~SFg_+(1E!36=<27o-2|-WC>s0fLnpM1hUq*)vLo#|-8WY_oB{$qI%tM}w7A7KsIW z4!(=1x+q=2JIqqBAp^-tIjc~1A=n%~5(0_9&9kB(5*`d++CH1`2F=tCYZsSnhWjkj zA5!s!T3V24stN^w7i&P1@U^xxp=6WDCiyAIZ{dL38Noma&`2#kPxF*YNM#D`aVKd6 z+%{Z5O%yWU7Sd5SDA=RquybazrWZKk^528yC9Im{%tW|@XEZ`fTFf(M)G74L>kDin z0K+n15z{hHtqZoCPL3MEU!8ybe7$LTlSj8F?bd`Rs% zE=!8Kcc&;_B8L9H`?d*iQ_T@dltgX({_(2GSj|}__;T*C@HHts2JVq5Bw0) zN6yE~bU0!jrJv57!IyG0QB7Q~W6O2G1g{;QKg|#w${FM>BThROHWa*2P~I-1#7r7h zX|sWkap=Y@nDJvG0xb&cT;*4QOudImGJ+jk<0g#Fq+JJ}8mI3m8LKgyj;5uLwMCRq!zNdU!cJT{30r{_dfy z*|z<-yZHEiQE!o1Kuv?QGYkGsWx)6TYZ`M-l^mr;5b%mhI|wr+2t zuT?-r?sD3YaSC+epI~HUJkSm;U}&YBZz;*{VcL9SLwIFX^aAxpc5LE1)3GTlOd6je zn3_{Ge{-o3m*?<~TG%*jxZP(9+KumMFxj6YcaUK8Plq!qSpXX2d|IO!j*U3Q_tL&I zA9V!i0+#UX*0*9CdHJBs>4(?^+GcE3Yu84+_Vm}D%aNL>#WRd5aoFANbqSHy>6d@c zJ9)Lhvo7o=uhpQs8&bA|3p;WyY+k!e8TlFV0Kg02r64<5dIBgL~_`TO9O**IGN06=_IL6i%0rsO9mW7-K!Gx z1BFLZ;h{q}%*293DR!`ycJuiXZ!aoNFz5Uvh%tm*5sBSJBB3&L+I+zWyM!y|jpkvE zVPZ)`^ZBU}!Iq*YEJ*~cTp~Fk3RAgipmd6{Tik#Ja`9wjA0alk%p$ENHLu?4cT9K) zzGf^0>q}6cH_ViZ1Xz7dqoxL$pwDvxJ3qC}O+;kVkGr-8fXn6?3(kU6hA!CbTcn`ktMNqber zNeae78j{x>nt5ahrf4?N%mOi2d#o`Tjb+enb+B~4dqn)s6=WEzxX}jYNpS`&(03;X z!7A`Z*tEqt5}9TPx&bzg?HmXPZY2zdnE_WfY!w*_dlh{vI5VnIk8443cX;l@52uriBdysr^a_(&`eHAVr}JqsLgx^kS~2R zNo8G>9xt$U-5AAOTj?BW6=G>^Z?IGTh(AWmzS|S)Uo#dAYmq2U0&<-`Z4g9(43F7D ztNpnlFQ2`5RV#krY-VT?2(R18khT%y)?edFi#-||yR*q*{1sON3mK=ZwZ3FccHD?O zG}v}0LZL;b=>*zGFqVQjZnrM-$J7C-ADCof72|e2Cs-VG&kj4IiW_RxW5}hAaMh97 zPYHBOf~;KNaN(oV28cVef`Io*>CB9 zlapFXVM-w3ZlAl7)W4702+e7h@oCI(KX43s`>{4>5#jdHLYT(nD2-6B2h{CWe9PB% z)mhl#WAV~AViGha6p}O!#i1>;Rj_rgOS-R!EV%A?s2?DK1FcfkmEMgtCqLs^I@$ND z`d1%=4LCkk*4*bToXJRdbV~4T!R14Z8n>KlB3oz~_i;5CXpa&!w8d&<_yR|R2kNYQ4$-C~heh&sZ=$J`8S!2arr*oiM?18DA{ub)wE2bs z?Sh##+jy+iKnUK*pf&jv{L|+JrAtI%jhjN6UNY2!t6XaB3I*(E82-v-)kk{~OelBq zKT5n~+A;b141x#jI8=ZOsve&Lz9OL?u<3JHDd#x zq~#pnwJ_|xq7m~)b{@18dWP?s|Bfq74AEqYv+9<()A@CVcXlpE)XKg|mw)SQdFucT zDMzcB$)kTv5&hZ`$=b8?vBTVl=syaZ}} zZ#iJVF-A z!^QBfO=T;8Zl}^XXuLe#AW8v^CGkRm_dY0KwA&n?d;=}TS6DXClVT7ktuDKBl&~Dd zGs+GnhqVh+H9(1tgw^DnbQm0Hp<75hP{iN2Ms#63d%RrdIdKTJTN<|?sHPZb3ypLI zeTK}!;t{6_B~~t)>OUGOX7$b#x^Fs}nG!>xBeaz^>N*c6ClNX*Zp(w8*E}8wQv$EK zj`kg-;Mri!_tm70FW$}q8#xPqj!A)YF}tUeiB?WR!cW1Es_!M{W=Od-i^G+01;|d!&8=U1lw^*`RhHAa;P>P0={8xe=9E4;l!-mr21t7m&){DyU0(2>>LfrA^Eb6WV|cQhOif4CwL zgBd5Sz9|rdXTQtnVAhsCQeqmmIhSpb4FjNNOCRSca1UlQ_qrYP$&fHx@Wm=WlUP`) z7-$`a$X$)py4^6PUU6KE{fFgP0HtV7MKh7e4|JG^~npex&PXPu9&Q82J$+ z<8(B5?_1-%qlz8;v`fKmz_Je>pX0%IhnYwO?ud236TqDJd$q&o%Ir6f%+aszAxe)0 zjZLrv3(Hoop19;SA0m~(B78j-Y(cP4jOt}=^pM-#ot)e}(qD!f(3%!)tL^G)|27Sl ze0&6HmA+UCI2!u~n`T@*nvE z@!F*ui_oo=JdTaoVs@1cFjd%_G9L&-F7#=3%!Ef10U=4Tf{d#uFVMyVi4O(yY|}uf za=h4wbZbwW>_lGk7q(3l^Ro>kPrm0fV}p5DS?&{c$Nkef*$?p_g?IHEmjij5P{|V_ zpAtRVgVH4y^pyyRDC;c|Mx^Q^69z{9wfxKn^Q)t?bVIT{NmJ$h{4~#~P-1;}dot8jM+0);uRty{c=F4S#1}@`&FDc6c!UTOjrQb#NZ7cDfgU zIF+J#Snm-(+xBN<2qStF?i;g0w67*|yg+LK#t_IzmH^w;V>>%Pf_deVEx4)gPH|mB zer-kY=>E5$vnpcJM^uTwDG^srCUpmE&N=KX7U+xmFJ}Eq3LNSu;aB1-5p4HOEFxuy z7JO|o8vknwIqy9R>C++Gk~aTzNt_%imNR|&Qk)G-wl-LO+Vz_NU&yv{OdY{>Ib3jQ zk-#xuT>gyU1+^^{-Wu6-&l!WY&yU0ehY#jXue;6sVcR4}7}7FDu0z_`b+X_E@6Wdm zFON>*vkrj}mlQ;LXqTh1q=JIJ*;G0+Vwy@B_ctWbKLPUhT42rev+FUqLNRjU$e?4| z2T}|VQJmSNvF1xvj53JJVDnWED8A?@f_t!)UTcAS z_x(1@uFu4zyJ@$vZIS5mlR3q-zP#WT3O1;i&tUB`ZSr&+E9G-^YpI`Xmkv|mv>Vei z=8vib(~YjK68vf(z#~J2Yy60G2IjPn%AOfp<2;4s1mIi`Ql1Uh#uqsBF)7EZ5WgPHwm9??J22 zcTY2w%Fo@u%+S>X~-0bZ=+jfexYM4xEt#4+7H!9f$!5Zb6GivgDopedJQ;%>eI%IFQhmqrm zyWDdilh+&{)^_R%2wA*0GD?$VVpIGOjdHd)xPHFIkuQDx)@F94HcSRXrZ5h~x<)cc ze@f?@nFa7IWcw$<0WCM+2B_O~0-9!B1f~7}D{fN2APyNE5HgN%&pWyu7>`h;k_$;^ z6s)*z0=ifXvEh^?Fhg6WF1x@vgSJDlpURkjVBEpMNjb%Ij5;NM@k~-xG(B7cdt&E`2USXH<&7!@V-$wc3$Kincob0w7v*J<-ZIfT{)O`qIGyyy>Y=Hx-zU*OWt!oV29cyVkajff)KIX#%>-*rIOX=ld-BN{ZKk_Z#6dt`hitEEJU zK&&Tev{f#lCFInwq`Ga@hc2gq3G?V-G_v!tzk{;JE%q9E$~PpPJ{z*)`o=VSIxP^# zF9-#9ZP>A5JCTFo6}YumGP#6HB#7wN`v;JCKd{AcA$GG)EdtjvM2VNmAf1h0 zT0Y?dT-nYRz-sNqj&(tOJCpDHm=m!A_1P@7dKjhVUe%dyJ-T@JRnHI3OludVi?}(> z+G;!ZfmeYWKr8Nl*)a%y=2_o)dvfu$;7|)6!cqmk+DJ6^vnl?|Y9*S+ez(eE9QPCFuL{ z!LXCw;R?r7gd)W6oXBN+Y1K<2$6e*$=QD-o;j+|K_H{0{%w1R?`1>JlMiueV0OI>> z@Ij^-C|HW{gK9FFT~6fz#&b0G8x8l(0m$$N`~P;8?Z!A{1u_6YtnB|M^BLJWn*7&L zCp=b8TcfrAZ30>^!6j;{IVLi8SJ`KyuQ*~(J6r2YSZ<8Dt|PT2cnZXI_zKUnIsbkD z*1_F6imSU%XSb)|TZMtt0irdvrb5<8}D-{yc#}LPgTr&Q?9h{DP+}7MY|Du zcH6AU(U9V78p|bx7qm_{LS=w@#nYq#{mSej;S1JN9a7PDi&*7~3}^Nr|0FbQd$J^2 zH37MIeMX|)y2Jw+wyZn;%BhZq4a?T<-n;;^q9$DTsz$gC?1l}=_`@V<786Myh|WH8 zX`8ZlZl+vPUp><{T=T}NTqbg}`8+0tJ0z)~&-uN+stvJw%`8+KD-i?;=+>EJL6W#k946)aNlq;&*6HZh zSi*@IFMbLjjH42PX~55Ey|p&wqtkluf}mA=U(Xk8+p_Er9TQKg#3F*J@O0$p>ugQc z$ov0e{9GX#^y+lKWsyz@_6=s<(B8q`fZL?rV*4BjOyEs+Yj2$ zg&5Pcy2>R*1T(1Omcagz?vtPB%xpO?8*}JQ7uMTe%sG9XKD=gjbhmf(wx>%~m|Z<) zX>IKErB4?(u-;x1bhf|xf2=(ojHW=#z(L{gTR0xzU`EP0;bc7-2($Yf9q&Eskqo+{ zgyPAyRJ};nDLv>Ok)rLWA7pe;jaCdtx=411iBjBe!x`}*FMzU#1;Kv zp!CIL2@O~lS!O0^rjTFMlOK&d8e{l|4nPd1xaQ$WfA0ajN~VgY8j8|}3Um|Ft0!b0 z&LF=}eLxeN*aQD!PorN!#(P$^(CioA{J)sjRT}n>V|%60YLW=lCZ!{iD;vG zg8+E?)JVW;_VxAk=`u70*EWDg*I}%YD8B0dB>mHk*obq=8S(y>S(AZp&Q!=mLuywnkcO!lsL=YnbJiY2-IYJ0i<}L9cqSn4i~rlMf+0^jzZCrv+b6(TWROiH3o#SGy5Kjkw6bn zLt6uLFeqGtY$^+lp$RSGT_EjUq)7~ec5!RS^;DiQw@C~=jtQy}uoZApLw{*SICAH8 z?%VvtipX*!g&#(kFhR*-c4nrc{z}gh0M=lrBPeJGG76C?f=Fj)Ftz%rn2oxF%V5Ye z6J8Lw9O5vd8OW|f)E}t`C3GJ_c;O2pQOc;-`;*i|U%+lCA*jtUXP=-B6@h4$295NI zu4ohs`=Z(qxYPK-?mUphSU6$-F#{Mt3|huVIA}i;B1xfvIAEm-GSCP&;&89J`X-ea zR+~xt5tmHSo6gn zVjrxi`?<5O5;!cH+PM2*Mh#7w;+7c&t^?MlI+gOntvH`&V02)RB|sCj7Rn*}M|!-tJO|L8cx@0Tn&A^si8@mDrtpb%Qc(5Sj19sF z+lQ5b26y^q;SLr_kOsIW>ycR zoRvsjoBTn2#hCD=X`^g_nJA%dtR=C#8{n7<^s;umK5c#%=Bhq(ym$ED8jJk_;)5$0|4rLP|R@)FT?mz7w+*0OStB zs4?Gy4BgZTKli7$<=|5c&aiP0*Ltj01RIsjZ8AxGX!Pmy8vwW?*?`J|HDaN*|EIwC zFJvHjEFJJ9QJdG|jpT6vQ;B6x8)~|@_z;Tu+e`WYhm1^d?NKmYrJjJ$LW!HB@O?Z> zS!?-JaR7l$VTiM8WOc9oG$)j!-cmj$^Xqi=q{!ymASR<={||jdsVa~GfkMTi-CZN7 zbr>**+{&i%Z<2Av*nk*f>(r6In%2#FW^kPGrcm=d=BNN7K-DIobp4D#hBhh0~J0(CvA@8TP-4aZZUf*Ogcj!&OEV626 z!*(+zAS*Qg%TQ4y|F5VcQ^vd>=kdqZ@72F!a`bqffUZ9mzce%Ia0GCKmz6(zq7Htg z=1)IOufU_jXki|u$jKktlafXF)m_qhV67_t=|(q3>n6e%2grFJ%vj5Fnm9FwO(5E^ zq_~OHYCvbgX5<>Mg>JUc5h*nxWB=>E-M~)b1@b0;#w%cm>MyI}!cD~pj`?VAP`GYW zs6fH_O;u8pc1ai;ZLH+$9w{*I@{TkM^6k_-~cncadXQ`j%bZtB8J+;PdZZexX1xaWeX_@EZ1$tuU4YH>DqVT7{G ziBo0oU>mUcIR|+vVOtM{>qZ{O;{gc^+;@YgdUb{lRb{2$1C%E5=~qIYdRknQoP7SK z)~Swg!}YmTKwR5w4`v4?8#HrGDPRqK^>`JJs!qi+PLU}d?W8yjrr+E#M>R8I9Qm;4 zUb9bxrBaWysHFAe10ojE0rt*+)&g-8AufophiCTrw(z4j`^0&h=?@fz;?+VBA{yX6 zG-s3o)R?OeZ6ypBdYL^ot+;T--u<{#mc}9w^e^Y)?*1}POR}QIrUHrUn1Mn_KH&6H z4GH8)oN{W0=k;fs$n_u2EL=~)*RngxXpzfib$7S6cV}w!fnQbVOJ7w}9t>G}(|U8Y zrhFpZ4Ah+eu`Dlc@y7Tn;C42u7gw>o5}e@A%_KWLaM%La1L|~ufUOp7nmWwz*5wv2 zGmCRv<+cEGwCsmT4{db~PTbN7X}77jeTD}deLW~H7%+H7Fx*fLl42!ZGj#sF?(FSd zo!#Dcs8hARxr%Ic`Y34BmlXnEmnq3>OPh}5)=q7yAUM)(2q9qEfGgh_ zbR9bKnkrxi4SF@Kg(W5I0HssFNvPc4*liEBxZ`Un|G0D+7j6CAOxz$hd%xj}da`-i zdY=26I3H+h`+1@k*nJ$KW|*g|Tt_^Xs8Rj@Caxz&?w`S@bynIsx21nA{|A+oO1KiYHhpc@=x&s4$7LG zG#ZP$!c0!W#(>Y=R3uj-$#tB~QgZgA!NL7Ad21zGT6J{OjdJ|nN1&SIk_Jk*v+#f-?2pBG~P@?%MT6{Kt&#Ij^`pF zIhXU}M69k5O&7<3V+V=HWGc9hKw6mb7IJ{a)k=`us(vteI#N~2GvGQi5IRMq`jJN$ z*VUre>MH?JEwfzDoXUlELM75V``PhL==D1K46|Bt7-z>LqJ7RWN`xchov`cO+9};| z=)bk;_;`ttRdmjjFsL_5+VA?c?}33rTg>5$-(=g}%qTmv1-k8{o3>|E z+Jwg4&|3`5+DxTZB_Z6c!v&pgKThkZ6sf0hUkMWw+tryzY8x-U{(xccUSz=Sp4JnP zxFMEsR^JT4siPH=MgZHEuGaIui@PK5jlS| zb!dBu@cO@df*)x?y*$$%_m?}Y-0o?nQ~+`xzi;=A`^hk}kEa*Ut%9|=qkw%GfE2#O z$5Y}#Vt3?@aY}AJHfFXxi_{2z%OIEUW*v2f->MX1FGLrls*&bZe`!SH8ND@QlLY?u zj-J1lLr<7t55bxZ%d-}a?iZp?MfOUYDWyq=gijPY)+1DC0$@E_0L$73;xBB!acSh?H=C5?wtySWrhJ-wZ8CO=dj zTN;lJeYQNC4<}h$l*fGfyexo%AfQN9Sst0xXc$3%H){=c38O|2I_w`%X0=MfY8@ES4*wH zmS2`*);hAUlRWJ}Ybux~UC!mQP-b!B2vBMj(0LB zTPwO|UC1AzjP$P-?XyiRK@vpWjO`BI4M2KDi6c;+D&j6u58ClrWob`JoFjWak=*=} z^rD4WrCJmwlo`G{=EQ{OD&KQTYCYE z2UN|%bbM7#WNdz7=!H@r`mKL$)sh(p6^C0&16TPv^;>V!&1A5XiYIJze;{`16uJ9& z)NB$|{uPN$6uK$uoj_V_76)GHD0v$2aj*w|(k^To(&ea{pXf_ub&0l?vtjH&+;V?l zK|0*}V^2Orfaaz{bgg)lO*ci3dQo1A__g?kFQY)Kx(1J`s(nL(Y%mAzSCMG#OO;ff z$qpr&6){mdQpZgaj>+qjtq5eQ6zrLEH5Pb%j%0SI!2g@%Yh@g|%=mauy*c{N?&x!* zzqytEZNtI%^#=Y42g_YeIq#`A&Xz<}$m6hU$wy{O2@xJ1*c0wgn}O-z5>9xbWEsXp zIjyn2um02_`T(Y4bTu(-*qN`;J6RLo*CDUxJt6FXghR^^WD7RlyK(PT>{<+xIro%> zXUlJ6&HIWuvynM7@EZC!@Vz^1*R|_A(12cAIP!77D#;GZrJBs=KhUYG@Tl3lp3wI| zYiy{f$Z}+LU==x4By(z+O zgvJHe+~BW>`DyZ1 z5OTbE>D%Mo{;EaBsQKue!tDzCx@5EF-TUQiRK6To&;j^5>myM=8iUEaj~Vl)kn`lW zZjZPX0s!UFz;U@;JZc9WH4!=iOaCX&v)bqFQ2U#;N0ji#wb_iFn9J^WQh+;!e!tzf z60k+K;jtxC=bb!Kk+xPz%zI7{0+>rm_ za^e5`f%|`Pxrw`xiM_LhovqV;bz2PZEgH}#<88#Ap}dmn5O!*OeT85ze|w({Pp)+07@N`L zTKDW6NBvugN(!=+^*+!YA{VJETTS5PfI6!AOlDt0<0M7*Wgw%Zu3dyI=qgr8!b zntIY1Ux4%wi>nCauozgah(z}DnlSe-duQ&zz}byGbM{CAsEHe6u5|5zCs)Se6>X9E?#o{p4=Rv81a>PtqifboehtWnQmO9-i{-xW@+Aewi=P;b8?+rz{-NMs4ED|q|f2` zgyhsRru3QI{;%vJ>%16sUb1M9KroeU8!Sp2ZV*>2e)}nIzWCO=f?w!y{+@P(N(i^} zwZyi{Dwv|?NByFs{b&P*gwCKr zUh`w5@QOk2)j;M`#E^xAddp4*eZW~g@R4y14Wyg-G3rp1({QprwTdLRFbc5MAlM+8pV$ZEn_CR=M_X)dWqYmm2V z?tw6pbvdm~P70F50nfk3eFatPtuK`Z7#4~lh|nMN%^ z;9K?+=%djcQxn<0toI25YEo@p+^y48O@!S^rlgcmVK4?kHHRUIFTDrv69*|H8f9|_ zSz<8OhL5x$6lr`evW()Vq@kKo%AGN2H&lXCQ$=^%=q9>e&X?RepDJeOXI{@$i7F!1 z^F{{dOc~AtOH*Bw$f_wI%)e`l;J~KcgOBsYMNaZ{h1x)N3#g|JY9!zX(H1c zLC{L7B5N@;O<$tR3?RlZcLqVZ>HwC|)c!%NQ;mEKV(r%u%n0ZYNHrIXU=3B^*;(dq zG!1DzTM3=D>fOynrW#qs(QLY@F~g}A3$v3CPq}2P_fbyiN*AgCR4P%F`J)>z>CAp9 z*G2#b`@;@B{-RiMVd@H|jJz$;vx=%DPqJwdl6gK+#adcW!V8a z07h_mxY(Gx2Z|yGoceuo2(6$SQ~Qmh6H8Z?*W*b`@fnwd9bLLC!+;f%bT)Ll?kqU& zzyTHblLml%8$rMk~elLEZU4n9CnO1=31l z3|s1i7AV)7Kyp$XJ`vDM$5ms7ScJ?G#Tsa+JY@gi@}?0R$S}8IA3hzh&GGcdg+{ zF7BD<);#i>8u!l<5S-VIc%3pzeo$ReM3ptNY=tuK%t2@^CUGU;aaNu28CeaKQ_B+C z++UG~(&SjeCABjr33QsVymBG=%WJ-bhRO<`)vQ|BxQ>L`k?sZ0ZN|YF(!all%NB1y zG4;24h!I9S7A=^${=gCG-E4%lId236=BMqoFkhr&Rgu=rJls_TZcauGWGleMpV^ZE zrJiX?e#Ffs^H?0m6#{f~-O1bF%T2)2T6g$YFDWb$2?8_$HxlQd|nDxy=K z`Z5GvK?g8MSV=0v*c}~bc&p5izcw#TeXL`t58Xj438aA~AeHTMM{f1GO^GBC%bm&a zL0^_o*$5N9lFgP4SFH05p@9p-9^S)fb+ehudG-l~<6WZPLDn!nJ1IonNff9mL9vgy zpht!q09Plp`!7QwTnN^1F(P@=?>W!Kgk;QC#n8rYSfMQ`ZqzRku@+nThI$d(SM$S$ z8IMYR0BU!%^r^>wfLEvV+>RhsXCpa<%X(|0JkLlX+xc(5W5%%wMdq;xK3(ufBDtoD zW(x)fgGTjpfeLFlpBrF7e32L^w$)~D$=84Adpo~R7vlUbumsiJl5?N1xl8Wko==XA zDp=!0SVY9e(%-RqUt7p<>IKn(R$~qC&4>SvEzJo&7FfSRTryk!HcA#c|7MqA1UgW0 z-@qs*d#~JBvg0qcOfI2}awvRoLA-#muEbL`?R-EMt!k|yH7(6bTJG2;@VlH``Q2vz z3$2*C1yG^#g^goL*>^*kS3^6zDj^&=tEBw=t}#@>u==6?J=O1a^U^B+68g zMsjKM#%z5mh4}#N?I1m(uSRK<`G&WuD;!G2U7!jr;#zP?pgwUe9Y*_h$dhWvHH#uy zecekYVr}P{LoRK7ccB@d`P?7i&(ekUcy} ziB^C)aSRCVi+MCwx^VLIzEja%tDW*b`Ou!!_PR85E_F44e(^Kn_xa5}BwPBs@LKGU z#=K$?vae&dzE|cg9rj-B-5D=a90F>-11Kw1!e)6P9ZQ=_u@}aK;CHxs(O@SI^}!30 z99Ksg$|=C z0@k1;pyYjsEgo1gN8>u=%Ba$|UT}vXdaLTEjp3p5*X*~u@nQMkw%x>gapQi*?kTZhgBE8|K_cvcA!&O%?jm5SsvczH=G-gzqUd zG|5t_PDAx1B2SNT7rkSavv>o*ni*6uHhleCzVeVF?t2Og06;yw47jcXaD&vohBxap);DHelMi@t$cs3N8-S5oM(UEvK zXFuNdmHH1EHGEuw0>BQOa&FK>UA@k3G^t{Bz|#TY4uuWw*f2YB@$eGUYzCW~OV+s`b<)UWh~Li|LyomZ%NU*a^RF2v@M|Q# zD@w>+5i%z9#_JC6wrvxRkHz9iV3?A~V=~+-H~!=VtLAA#n0LbaVx1hfmZwaOFHN+0 zB8~OlzofwCsEP!n1GqxKBrjOw7qEyi-D$x&Zx}p0ODI#hz;X0waJiiB5`XD2XI?E}mS;9?-GB zLU{GGEZI!lN?bj~IkBCmqK;t8Mj`u07pQ$M8w`#pl&$lggknSFAhPswNqT8qi2Z)` zJf2a*fr?wyxbB351p+55dMpQ#eC{OZAnanaK73EiaC8$!A6bmo9Qqf)xRl!xh03f2Jal1!-_iw{T4@!}ee_xlh0Qk;RTL$*s17u*?AfK}vjb!s3&T}COREi$f zdUCN8HcUt}JZ)rftiO|vlgXggQGXwmNfb&M`|z}3w#6*Ls!~~=LrqHq7zZdj`$n56 zOoEKsdup92G*?!gCtR9F>5AZ-=i98S_Iq>Z}&{+^lbYle)>>BH>lV%fL zFUJ>K=$bAC4hbnrg`d0onk=+Q?WkYH$qV^HbY$LOJTP$Fx|ksL z$$asnGmuF^g$qN1obiY`Fvu^^0?+(Kn-9&A5TfOYNOlVZLkk}21Mg@m!IWj127;jm zZiZBJ7a^F^9Op>YC~^^;<+J*Y=sVs5d4*~!g$N-dtU_+mhX^bINr)*-Hnd4bgpmi4 zG$JJcXJ^SKCkcw`X3IG9Odnl9uZ=tMF) zZEkT2ib6bTX)$q2&`}Xzi6#9KP-~6aY)kj~_HgX+CV%WPR-q?xYs)w#Eud7-@z(>I zRjgIE(5DGCI+uL$t(6jWhGPctyaT%I+aNZrKk%bjfQP(ZcXSt%S=%FeLcQu#>@wPw zv7z8nOd#fyfti{*U|3KR*wjAoHpymI@Fw)-=)Pm5u+2Gd(L;ECLp-7^j@xsXV{sAV zTLPho&hSkNxwYDC^0)RVf|h2D4fR&RBZdf)`}xqmlys{RlU~W#tN(Z8s(~1+yLnsEuTu5g7U6@W9rG+`A7q5*_&Wiw-KL|hA zDz%$d-sU{jLJ~$3<_U}ubckU>O)~Me@fMD(mRKrBoec^kXtMVOLITB`>G8Fr@Bu#8 zJvHR<7UXsSsg=BPZjRdbn?5qTZcXI0jTw{WUO*egt-jZl{mL&Jb%^X6GVu=tnfpX0scA#=GT|CV$)evg%pyU{-oW8^)pr^QH+%9^GpW+If z%HSmed+R^|(ThQ30|=gqlnJuJpt$#IaGvAJp)f08GL;n#0T!lzF<4R>M;DTU6z7NV|;~dMy%^Rkc)MKD?$ofEYDD_r=bd9GV*rkEM=0D$QgSC!zK#Hei zt1*f+E)ONt-*#HeF^G{M4`(y!c~Ndd1_T}Kym_=+OC1U~b_%B)AkO?-@^pIt7Q=7e zEO=Y~VMyh+Gi(10ij(&bdDI3X^m`ci!SFx)J0{KWLdc=j^2^h zQjXLDrf~;4(l=vH1iQl7#rfB%x#=ZWnp^)SX@=k zszBXdBDqPXo!K?14b%=)4TFDbg7j(a(W)JybLw@I8Asygd=w1EG!3y=aOS9(%|pm@ z*=?qPC(_gZ!ffU0O`11lopo*up}@a-ZiEdL*LZSe(b*R`I^A`PDl{BRlHFjJUPXQK z3Fc-aHipl_m5FwpMst@QAD;|pee_kwuQ)C1=vgC%#z8>Krd|=NAxPs(v9MWS0VM-h z4jMfz^@ULMV>c_wi`LHGLq>G`X7u6QySY6_RI!sX()Ip%h z6iBFS3<~!uhx_I05IBn3W?YKFkM>P7W2^mrbe!JwTQK^H|lNeWR?db2?g5SIV4pET7LdaIOJEO&N8KoHS(S>r+X_` zzw>$Kv~GmQS9CG_92kB08M)~hzh2!DR(IN&*vGpR*B8^Z?SQ&ayDIWEu8LAlrKAJw zyH3|aa#1m8_+0X#1utcVO0kjdixKVca$h|aN4zT~;8+|puhv7 z2j@s5;-qEy>RY-#$%_$Hp|V0unu|9D4D?%^HvcA)wujY$4}_Qo6&9v;v^7>KTQt6R zNt8%dzx3_|Y#2o2oT!M0W4GsLt9APGI3tc>7z6)|xo73UsET*6Lt{`_iAu>ugZ1{vI{YhPV4B7wC9gL z2nzQKeyvKk)b1E$eOJ9fc+Vjy-qvyU(gHr%KKbNV#(dj}D95w3duSYlgMcRdoQKX1HZ}gZA;=F2N3TS{ll)rC!zcl+e`n78sy)6c_?k7WdnQ887c&Z)s!MC zaTM$xj}^C=W8T57y=irsl(#P$f3aP-Y@9!trXVs}gtJ4>Bk?$KGP`|JLIpf9#l^*S zJ`w#YC~Dws&vQkxAq*v`T#;T2>LWi+cRS6HYOud4IbI%Yd>?=7_v*OQ(-xZhZOz|5qUXz~ZlP;7=W^`lpWdZ_2|q_U7i6cIH2+ zVUEg1>;@Zx?}<9hD-veQk->{?6q{pj&Z(Sz0x~igtx9$F^k1Xw8CVG2&SYvsnzQ$pcOeRrax48Op5urRe<`DkbMWr+c z!) z;sTHZ;_yfh5+X7;DIEWCVyB?uru91>49kjc<#Jau_mkW+GAmlq{k3N>^riiOiUg zmf;_t1i90&>Kvx|zw_|==|#Tx?tPtxm)o-GtRvhz$&;sr;N0DI4(c&V_>{#$1HT2s zyUZ-3*=lqPL5?_tz> ze{w9E2q9RD1WwGuibz57L#Yz$_CS^B>7VV($Le)BbMS%YvWXsbpEf%1vyj%#>xDTU z{IZF{bKY;f?&q;;x{Mh~ga7mN+8FbJZajJNog=+#%y9>2RI?<>@ax$&*IgLBZ8@Lf z_oMh0ZwEYCS}uy8pes1biOCRtDt_*-1M?L3po8wt;pAp8=bV;{jfP~Yb>mgLTXI8@ zfYe+R`svVvp{8aqIz=$nKlaU~+zYcwEN+*}^|Y|IW9hQBE;K0FE^E}&AABNDS{X4G zFfg^z%If=LprPe_9fhFHoc-&DwPm)nTc>ZKzb&Dvo9T3^Zcw1Kyw(lqb5hbZa%Q_t zj!)=!Rit)rkv)1Ik7|eiCYnIs5OtRvH(i9iP`-*nL~`{Ecf7FrdsW$4`qVdO3A%mXXJu1b)HMZygAytb`S=>8C7~r9w3V^*+6%Hk_4{SoZ*{fzDbc!cn0}ah zhq)&QbCnET2{0uQI&Lj4(2PY@2yH1qVn_MNQ<{TB%_y zf{V}=b;1fL_vS;-h&AkOdt!vOk$RvigMWxvpZ&2Pi_vP~Ma73^=gmhF_ncybjuK%{cH}{EfV3AwJWkueiBJ zUCvL59*v~1hg}_?+!Gd(X*DAe@0L=lDXIs-sW`!aI8(6IP{6!{>ARwB(}~cc$oGQ5 zjJFBAmO8Pg5+@ieHhtNS?C}iljCnAHi~VWCeI@ibX&|kZ z6iiN(D+c!Ck=z!Uv$bdGiu;>y9qGA@w9H!OGgqtK1e4PDo6eSz!& zwoYX+;G(MRGRFL+h~8Mix*s5~aTR~2JDhhh=&pc~UUQao&5TOXMtDfg@NFbenS|s= zXk28VkKcMiyr+3xG+vb<>TJ@qty$YzqT~kE4_Sz5#H=u7#7RzU{Nc3M_ z;n8wmk>Po}-MXGC=PPXwg=0V51ZmEXB1s;)h%#Y*N#~6}ovSO!*TfSt@dxcszAHBv z;$e0mRWg&3U?rd`l^X?iu@$>GVLBE`zS1OX3L(aQK6)x~Z#>o=k$oL!_3CT$_7=wQ zbQJ4aD1rlmC##G!uvai@(v4G7kn8JYu&y_mXC5(rDRyd=EQV4`YWGco_}+ICk7@%w zq@B4zV#gPFQdP$!_-qEgwv)Oysq9@gm=9Nt2EUXJvL*X{>MRV4#Az-t?GCAaks5MX zRe~1T=k&eJ&4AFsDt4?l`>M-#fs-U9(>%9FTcpmyTd^;;qv1SKci8J;qGv3lVVRvc zDL8ht5XFka2Uk&MMi!$qR*;RLInwMo39_=s3*obez<|CqfQrJ*#YrWqkcJJgL4m*m z%4o_ScVc&nI-+w;O1+~JK`qZSM7HjO8ip=mf1C&E7a!~OZ&wxFoY!tN z=BWHUdA0T7uh4>huSH+u;w!>tePpvDM<~HApr{rtFbKmGR#auB1UIy9UzVFfbE+-F zb61>lUqy7Y{uH+$Yim(ZCQ<)MF6&T5CsI4L)+yvG>xR3YuF(BQ!z-eHL6>f)Ui@U^vDx?USlS*%`NPa+_% zlusfIm*M!?Wbkgk@jt~%$JRoW_@6U*=w7Gd3c}7D(3Zf)uK8yQw#b(@Z+XlictZ*n z6-dkHjltSQ}c?`16tvO!YEbo@7Q<^1YAA>quY)X)Q!Zj> zrn|uN?KnXW=aHwI7zbe$q=xG6SZtG!`swg$S8_01&4l?jfW~lXh(eTo7Jqp~tTN=* z81|Q{Fj$+SCoU3MDkZ0@-}3F#<0xYD7IW~M3ikV8lhC8 zT$Y!#3*#zA^pa7@gla84LX~sO7!tz#IhOwSi6)U6gBFY61H15FNyv@8Jx#cE7h7<4 zyVef)ymW4szhTG_W*>g4ozTX~oYieQzgh41Ketn}2OS@l4^5Ql|5$+n&Vy$$&CA~>WLM%u=KiRiFwK(_f00MQK=USHztDf(ZCSd(IJG|`DM z--ch9Rc;DEtxMh03Wh&gWI42b5Hz|bzI*GN1odPg(ThVhp{VY zYx4gZb5OXk+{1wXFm`@oj(?N1bak@%nQAc_w*PQ-zH0Ru$@5#9T~k=j_TkpN&^yRP zW2h5}+}hMp0t6?TWkt|b6C*Ev{bD8|Rg{{K%34I?ym^>(z-Xu{W+HGU*-T1(!)3q9 zQgpQ|w5U0Rvrg%O;5p>< z_nzDMHH(_o1d@D>kwgUHqlV*?m}?Zv?Gm6wBx~*m%EnqQ-0l5!+{Hv7HF{J_1w!o% z=WW=k7J;51y3+;F!2)B6sigke3RmH8SPsCiZCu$@RP^bW$7pRzwsc(Xpz?mY@c4PO zba~IJg(a##9%v04`CT3&1fB+NfV!U0M5?7;&uieZD(1M!oOroOZ79-#X@^$w}s_V^C9!`J(^#Qr+-cy0uPGY};8IwO^EWs#phd#8#v#c@Mfb~xWz>p{0nBpx>| zJH>{>cAr~?gc}f9l{1^n6H{7KD0CTYINZ(eK;8rpg$AvL5(O%=>unPt9v?M=VBfB( zBK5^XBhrz2XNw|A-5r`r*0;k93dLU( z$3FTgE^+D;44QTLj1jc02zWyaO(f*wk-ggDUnRY{3E%1a;WEQdm(xsKeF3^0@xUo6I>ZGgd5jQ$bMQV4}GuvJ^hjGoPy}w zc!3L@rN3+QJKem#YRz58=v*-9UAJg&U0@ADn_&A`9P<62Bad#ucZxhH??uPww-9&K z#b4B+>bzVd)$J9kkn&3_?a(-CFGELR5A=D*QB@a1Cs`NYe%d}=xl^|K6eiP9NJ74Q zQ)B#1#(!T*Z6TqPi7G+0Ys#ZYAGcUTOOm@|Wi0-1PcbPPr5TE)rcUh5;FIJADgz1C z)rjLZhaxs_paJJN{?^mt-R^Bo{mM%iWB@bSV)PA5u)xSFi>*wa+g~YwSeGcx-5!T~zI|hy1kakTAAOCGUiTI@SL zb{M{iu#)A|&&Qh6(Gdf}=bjM*H)cNmyaS4-V__cRc0TDK5C1Rt_Mf1`N072y1{X^x z`T}C8g6l1xwTLX1QqVi<68?3HB43{TEWZaBaBAC7Ll@YR5=&;+xKQbwyL&wfO*0QK zGDqPMQ|3*p$Y?4mxdoZKN&`-LBL`|j@XnjIS}`iBF8g?nYq;o(nupf4Xg}<^ zvlj&+4XxZ(ZsFW9hVs}@e&61~apC(<$YS@c$t71SbK(~qt$7L@l^*lou7JeLDVuW? zk^DQK#=lrmPSu!g)0r|$H%yXa<~O!Ims=tAYH?x?q&_@xhEEc-Ze|Q5C-?+xHil+s zlp3bmc3V->AE`C(&9-twRTNyt*`un5i6>@EbN>Q*=!n7;X9y2r(-LRuipj$UJ9icB z9>(}l_1$zFv~{n-S;m=o3*M*vY~ixuR>eK&)Y;h#m5vIJn(;Db7XMk z+YqLUT*?&D=9h^|S%vIOF&!2#Wq2$w^=L*x@+Zr4e5Z9#KfQ3Sj%s1=R-OaHz;=1y z(FCSH{M@utD_V^m=_V3SmQlo?(MdRPOB5tL%V?9YBr1IA3r`LGwHc*jNjP*5SpBaN zq;1xdNhc081N~dl&+Efo45_#WgqsohPQ4D8xeQ3KMi#=f&~s}Tveg(qYS8ZUFlok| z7InmU%R?!jd+mmNvuF6h*Dj9`j(Y}$z|eiBcs9%7gmi6bn={Rxf4iN^6n)1`ng*=k z!T57yJ#8Fky@l;$*$-Nm&uzgqs(qomY&a|V@WQLYY%RXPMByY=G$8kZZu6bFO|}$_ zQfk__4#b117nIG6U5ERuw(FYr)(XLIfovF-nOfK(&`PZ1W+h6-cNZk;C2ZWcs-(gc z{AoV`w*_AT7-);3)#Yq4!p6&%XE-7geDEecIPs<;C3yff;S7ApD{Tv720-HF`0Gep zMcq|Re&#Iq3u%*|6DL0Kqo_pEn}sht;(H*`I$9IhQe|_;VmGEpHK{Ijb$XSqpdge1 zQ!@;f-abB6eD99`UtOmNYQH+;Pr9xQ2LSNnJ^y>U?&@M`^AAn@Nd3oovLXC9Pe7kw=m$$pc%z7jP>tyn1#AdqP<(bSDddq3nWmV;35fyC zn@b!9O|p}damQK{f5}*AibPPVS;T$@WWdi=JaoQ-ansD+jFliZ>Si1Ds)wj1Nob7- zSdxlRB5|O2&R{07-VXp~Sf&61UDE~>N&os(E~X?6h?zGd!1<0Jik1X-k($O2lN=ZP zG@^MLZ0p+V&vS6Yy!28dcAA#wiP zdEJu-kLQi2D;Pd_d%Mu2H4m1M3+(o;+%Ei?;T2>nU;n*B=)a7)UG9LCJS>pg=8?AK zz@%Yt=()_IHZs#=M{c=>1j3l{;$w{n(!r+hz^X#A0-;u<&T@KkrL@@^wZ&-b&G4Id z*=Wd<=#G~kw`kq1WM`;%l}ADsVc|zY7LU-l&zk-(S`h*t<;gun%9h)_j+K82bPX=D z4mbp9MzfIY6wI6g2w(XcP*ZN&oTCTevb%_LK)}TU@}fgo7jH^h*XbT6R}wIG-vzAw=6;X38kvzi#iH9v#It&zFMPi+04*Xn1(5&brOP)MEL9 zFcDdksaBH3BJ;QKnMkW@pzVXYIUpxRkuJGtl7pY%7Jhh4f&pUlzE+qgt zmM2V43}$$L6?ZY{bMU&-%XpqWX+4)PDUZ|B0DjSbSR&5Rsd(IGd9S#yZk z2zDYPuR7_VaOuub$-{IEeL3wd8Hz7v_(@GC;+y!*`1(>|i=s#|$qf}P<9&U+7 zfjvHZOG}c5IZgAHC@GCygooX1--aQ+sKgN~fmGIsR%69cE+N9Fyy(5Eal?=MHrqBb z=3_^?1%R%#;$=i~Vz>x)K3<#5VqWDPiM_LicVCs84lC<(hwqx7Zsjd>e6Y7fzfNJd zpZdcT=$<_&-=CDV#precV=Q2m2?-!0K{nMOWvuo$dvUb(Ss&BE9_${vCIjZLcdtfs|Tyd>&gWvAlI>8Nl^~0U8ts( zhbd5c4%S*mvMIB7dq|1k&Nu?Egz>gW`E$=_heEqd9?g{H6fN0FdELv+;k#}yoYWx` z?)GS2yftDDSmrmq+A4_XiiaU%b zjT%uDl5ZrgrW5b|XWOyXvlV&Ht7!D-?FiNIjO)*Dq}T^8C{3!h#KW^h$U?U0XeO-w zxSX?uHkr}zpZJ`g91p48ZT#wMYwa$Z#6?`GR)P+bA)G{0l#%$-d6Y@CFgciKY(Kn| zka$DFwi#if-+fyf%%^~2Rw;ivzpYXku@Wb&w@r}>J3Gg=O*_wu)|YPCyrCe`ypDY3 z;77X#To(647K@oO!r<3o0st^Nw-ECzaWV8PU8y$Eb%AxCft=%_Gc^%v$pv15Pf4o^ zgE^)oX`yH>793SGkn{z}E>R|uI}34AhO}O+S(4_ACws>C$MsZp7d9_Xbm_yGhuAgV z=+oAt8B^Y-Y=OJ9*uu-G0Y~g(CUdy{&l`VaILZQP6p#L!jIOyZ$<-ymMEb{ za;@`kGm|O&42eF3M8*UWBzE~gD{1oBLCq&_mmB8?v5Juv50(#*s$K+L57o1hf zWL$AdXPau-$6E~uIv8EC5*HlvF*TDZm0l$V;N+*@#ovLw)0mY;=`abARHQr%b7@du z-h;HIx)zAazimfbQvZ2 zF5JLPQVP3+3Q8PsK>Ym6s&N)fj1&X?dGo=N9D(up1~PEr<4qV`aV*oAE`1%m{mdrV zyNH0~dl;uIN0bX+BVtDw4i%bFBbA&Xc{$ifFa5OS;~o}@q80ZtW!gxq1fEd?Ef|(H ztg!rtoD7cmTXb&`I?2WJVh~!e89-eJ^cgB4N4nT{>(YQo83xwewc!dbG!iw>Le&o- z^RIt$@BBR}h^|Hpv`gMG$-u&Ev(eNCZN|iB^W)$vkMl&Uljy;bOXdtp(ICG4eN??^)J3xQE$| zT?IcQ;0?|vf;g4RlTk-w(lDYU&||~7l0!d5e~{3(X}LhE5-yQKb4dy8#-IN!3gL}U5t!Ot0K;pc}X0mFO3qXTI9rS1>XrJ($J|m?P>r;RoIi-kAO{@?GIASbn2#SMzX`~i}M`3`-t*}55 zH3l8ip&Ibte3{fITms#tH$#nlINsP>l0-!+)O|bnjAsS8HqFOshQ9$!p_XIR9B#fb zIO*nV%TSguT0Z0tzIvnuu2rFqA^7B!!3p{3 zqAi{925?dL1XHhO5g#9KOG{xB>hI<{%x@#Y&6Y8{kZS7u*3%hZd)YA0d^4SrCBQ<|})=tqFXacxP z+RA7|Y7_vEWgz7K-no9U{N9ZS-5b6eb`1Bpd=s_(B}hj_Yh@vkcFvh}SSTP5hE139f#~|&kO9=qBNeAkA{{ps%2%of zyMAFy_+jC1CAg}gOr5*e(s+K<6-Hrq(TP=?l6>g4N#Z$_4I0pCv#J3 zTyC)!8j=^-PcGmfy+^fdV#EAPdnY#I%x4i&hKjx*1H9nmz?AHQRqX@m`gA;~f9@*t z&w8Pos!A|IUnHnPmy+6cS24WymT-;WF#_#*g85AKU$a?36LqXmvYm`9mCxHu)~O3K zQ6GXbHOCaglBfLL{i=Z$q&xW)2=?z$;v+UVqgM;Lr0y$KBQ5lXl>B!OTS3pCwj4j% z{6A5ubX4|i#=O9M7EI0HpSM#l?@wDW?p;8O&w;f=*NlaTI6KCHyzWral#B)|8uy~# zKCYjr=#Z+p*KkigTYvh?!F_}75StgTpTK1+7hY`Ol}`|B2lg1nSxS20BzkQGF@)DE zuX>ZP7Q0??6K?<+n?cNZbiGqVcL=)7x*v3dMLoc@JMwN?n6P~k2ctJt8V$-O9%jKj zf`}5VKP=`jz(%s2AiI|=Xw-tFD9XgqxQ7n$H2P<(04ax&TJzITKS9K4Y0WAq|0opE zJwZJ4!O-y+Rz|@Q#OwR@bhV$uAS~|=;HZqbqWD==EO0FinLoMk@1DnD?c`6dE>JMd z&7_G%kw^E=kOT}6Jx=HbarmuYvqddb9#ET9sSOI(s)TvZ48x9LIeqEXS(_;pzxPp^x_`$$lC8zB2 zz;Xc2b)Z7xnrO%Wtchit_U8-tx%!8Jr?@Y+e2a6ol8?u?4+zrx2{s4*e3K7oi|KXu zVipK&iP;0%8z>)|;VCZ8qs3GH;k*ei1Q5jJA-`6+tP zxdANS=CxotsbO|$=!3dDFj^1@j2;A$*M^7;26&x;4dNjS0kq;^n{G{qAg3DwM7~Qc zI3*1x9FX(tzxob-65XGZt$*JC>xJ<1>3^51T}+)_oaz5p9QX6pzuo;4%KeYK|J!NU z|Mv&~mB#X)!k1y95b&GHWamnq%MNxw;&Z;(V}C1of_^9r7Pn3+4P}(X@{7O|JJg;&1q1 ze90I+esjH;^wg;wI*703z&?#dkGfHfzfG{nvFALv{I_OW#CNQx$R7&|{vRx1`p1$7 z2uR3T_C;nD1{MYt2zgnkY58e6T15zoar!a&=^4daiAib7X^Ba>qa&y3nF(oGy0OWb zCM5`333@3RKqw(hh?*{)zKXHm4z;z$PEJ;W5kI>6qE-QJq52i3xfKN!38tCeW>O{< zo`sGbJpr`z>W+SPRz6}>v&BTzpa^9o#LVV(jsF>R(qzd>fVihZvgYqtVCYdo5BMMA)No@uAWWTD8;*oqHJroD8 zLtyb1;Gt|x&#|?UPqQklRb-Vcj7&RyL>TfJRlF+%l3J`}eMBAM_dxYOg*JNxIRkz= z5}#tr6u8KZLjSM1`kxaojH#^({pYavT$ z;l^D{7J(F|os^AG#9|tch^+3zd7*vfr3+B&qRwChvxmEx4ckWaV7c@293kYfiBR&t;;unZ5BO@Ff(&?Vbai~`k&o~Ey~`=E||E<%w8#Al}lcE9XCOIpuzj!wf)E zmfGpL+k>_5R}T@nJnBYCsdbNA?J-v)#=0UHNTPvp0KSP9B#6~hxjlnB26hIqKISiU zT0eESj_H73WWRM=rSIVz&a@@H6A;|K3gu^p>$Cu^!5G&b;&hOk|hsF<9vYT>b ziFABMDKFfb++$-Ga&4a9%@_Y)UuPW^$C|Wp+}+(FxCD2CySux)yE_DT*AQHSy9alI z`{04#E+2RA?&e;;-R-|-&guHi`_4JtJyTWBQ@gm@l{V?}k9p;KzEn`|{qya5MY!i^ z_e+A3>^>%wxI>pWO$XPk$*h+RAAZ7PNFA-T>D?Y4OCT}Uu7QAHmYVsjjsp$RSuH}g zfK`#E-D-MwicWQ=_PE*ydk_~EFiwRlJUJNknL2HRjg`5>C_cKt*b18*RfasX`tjpJ zAo|CNXNu-c10@m#iv_2p*N$$ed(KhgzP{`2z+cx3b%g~2ieLf)`cFTC{=Av}V~pg9 zrcLZlBl26>pvRqGUDo&nHxgon>mX-x0cXh_v5_GxkIK1Tc%^@&Kv40RHS* zT}e>~&2z(XQ^{aNY1Fcz)~qke+N-9}3mH@=9F?l0J#GG9N^@}4r;s7V23?kbcKJm6>dbF%9t<9|zv>Id!3o{OvOW^P8pfDGQ8+Vy#_d=NAf@}iQWd}Gj>7e?D(US!+(aBFV0C28$kjeKvWyqaK zs_FsXq!)mwivqJ%p@B#;;(nY2!+oH;ICA}%kHud#NC@a0|64%k)PuE zar$`6*_}VIgdN~|1$*zn;dz1#an?=plPZ~#8)^ud3*&wwxORE_tG2f)73_UhSWTgE z{4_Wz?D>!}2re;IB2AUN2aIr3R$6uQmt~$`Hs9Gr_p;)LLFJ%vaC-&&kjOuA<(O}d zPSL{G&Gs1MY`z3;nR8*qLMY7~$4iwQ@^XPn5wxI1bm=eK{6cNuo#`}pixYdS(@6$R z#$!df^Z`BLpZd~ zg<&OoWSus>7?^&tGHN#K@UD@+*~f()sJC=1ZHL1^`qT1^i`}d<47Uqx?Cp7}9QyI9 z`e@S?Y5oW4*WRno9ub(7pH~ARharJ_6!R@8JH^fMNX+{6wS9OEsAY-M2&BLcN5eQh zK~3g%;udp+F#@(dE3FWi?};o6+YGP)A@KP~7!M{bNgNbz`M^X^-k70quUV0(9Q=hbb z0dh;KIu4TXkHZRs^#rhwqcVAs`>d=XucizJU<(X8XZ*r?}fI4|_x^q?Ijx6C}&u)o#U3IP5z z;k*E22^tHC<&G;xQOwnfKB+clwCDC3J9$i1fQdol9WF7AA=-XYw!&kNc;=|C`Q_g$DuM3PgzK|KD% z#!tw$jGlRIpkkt`Kz(K+kjx0}glnO#Dnm;3;K# zkGUxcj-p_I(lUVy~uFdEO=5Pp>hUZRomWtX7h;l!kToB z8qXn3i9n5_XE6}j6YiM(jsO=>~>Z@ zhR}O>?s3P7J{1dk^+uMe$k_bmss`&_8hoUk0iUc3Jy^j$@A2Bypk!0Yw3LG3++g%6 zRWBBNtt3BOz03N-d(Pi_MUeWH6MhiJZ_862goUa$tkh^;?gsbya%5o%+MrJ>$eA*p7fQg#^-Ve!X*ovYlZlbJ; zkkiEN63S3nw*k2ZvZ7X>@;#Oke-uEMXKDz`q0d|AIrz0j#NjpK)4}en#;u&5+|}?j zzdR>Cysy&mRfE3XqSx)ialm@;Q^Xf8B_Akc$TC&BQeFt)J+_BQavdfP>>cALW)#zh zLRYxnKoHIF6qOp>dBw-xI5*~TA$<+Vp;q^6Yae<0?&LmlnjHw;-1JBs%@?gq##jvK zZ~Z6b)3^(RE4nWS8(k+GT?AmyZI8p5^?n+ouxG)>TfGoXZRoX1z`Kdy{FH0rWO+1Cw`2zX7e`LYS0E1@ z7Fudzr^ojF2dTN(pK(RGk-_+Z0ox5zYUf$a&mS$yFquz=(C!PK$9&hpy%PxuB&Tyf z6Paw({48O~3bsNgiw;6SzPeC}R2L0!F=wvB6&(vBz}h&eCVDW=BF74b{DQoAl!~H2 zus|wWX=F|^<2%WS95G-+qs+^wVzP!$`=O7*3edKTmD;3ivyl&00wf=*w9&>l3o3Y&Bh8PEjmh8JtXM4!~i7~iYOl2WYs*&s4r;havBKRUS;{Vvf8DcMBe7LR-PMy(3_ zk|&mP0aB?et=0sJ!`~`8@W?LE*n}cB zmg*@aTmeTK%J6Nj5>&plxefKYH8+x?QX+IPg%62yoPv^2c<6ATet z5s6s$BNi;IpkPIK;^s%uG#GB`#4(|}pQZ!?A}NVl!&M*xqst zlTt~YGaAg*71Eal3x_vBr@+J}KPC6f;mq4Jp=7`cvCjhS`*}#5Idegh!_06F$Ed@c z%0kdTTKOxKW;=eSMIN+7mibu-LMM+rs{%@moVwWndH_z~Z3)?t*Hh)y#}HIbtlh-G zu<~qBjoZD6!WHzQVYi5TW#NKw@&fODd_9Tt<{c>+cpKuns6qv6X}SFk=v={ZLA!|! ze2@g4i78t{no z@&-TO1A6^VLBB`b)=2^DNQ27nIiaVZXKM&+yh5Iqok7s8*HcRvw_ltt*8=>mEbcv0 zXD>96eI5|JV1E>kej&eT`pkHHJ54)sZMpC`zsgYVC{z6O+NmsEgcO<(%LJD{55fSa zW70cS?%eW(thf!snvy=&hk6mHdAs^!{mFw5Iv$v^<3Vs^d4H`qEPXj%`2F z>U@xdQe`>;jHsC4sXaMCg0UDC=d5WU&3wP{xLyU8fb`-zEc45LJ8!MYj{n!=ii)iG zPAvR(2s1J*mvQzOE+&Uz7M3A;h=ZVD%d4pvt%hkVE?;u~ZTg2`iMsef9t5?=Pnq2qMMERo|Yt?B{XKWiMp%F29?meur)OvRU0L=d2C<(^H5)6g}Pl*$A!(wsT z!N3+PGKRzf>9Xk!UDzx3GOE^6fk-pzVeC5m+Lk+* z9Dm&ULFf|)UPn19!cl1jmEnLvSlttqT5#ujfZ zC{nO6k1lk?U?Px>>75}tO3K%LPzUQ>6Hyd9Zpj5|0g_$5k;!5i54^D2u>t^2p|QV^ z%kvsK4MA1nlf2#|-_Nh2@F!?3@G-)hR&V2&`|oK<0s{guOme~`g^@+#{3SUcavfpZ zHk;98gu+PO7_s5CXHF7Q6j);-f+2575I}JYR=9Y{xGEE8_blK&vKnQbw5vYs_-*iv z2r4A~*arx_UN@Oboze4OrFAW&ktKZBKa&1h?$G5X!p}K}EzO5OaplS5FihB5H2smf z1i?Thp14u;xIQIOGSLEO)6rT_+Y~EwpBX3&`-t~x{!8vTXMUW%h+rvs3xD;Y!_#IV zuMsrpk0!SPgNQ>J_+N_xb;WTo0)&wY*_$)eu5nBx1Y@+UU3!RtAC{X&1PpU3cKoAz z{eKM`ovxMO$}Bihy^K21^m})$`J(aT$^VKMHZW$j0tZp2E`rKy7s#k5Iz~_~@^@N@ z%sNA52FCVJ#lGXIasT|pE9Ba2j|kkj?O@1CyuWG+a1#+PeR^t4L;=*(D72bSnjcHX@;kYEDc?1E>%c^|1^sl^t7)eEi&{%#rxX!&%rFFc4Ba3}89edox*u~ER4-4Ss(7i#xBnE8f*${~SWvasu8^xM zF{y^etKp7Pu0+oFa8y(z(aa+tDzscyXNA`6vXV(>@FiGSwWcX+4RWW<0|qnCx~00r zu>OkqNEBdMB;&KojC<8awels;V99T7tQ|UZOuxGA2@6EvQ1^UyC16^Y2D59gjAWqg z!7rcb>KXZz0qD6ZC#*g0$v;Gw+jMO(*LM*vnMzmE=fHj1%5E#JA`4fJA6mcHSn22H zJ5M3{=})EF<8pC-lcgt$Qm1hCqZZKb?yp%3KK~gW(utmTQw~HW{JPju8?0IGC30L- z*EeIZ%+2EbA)-ND&D0#J_O;K|F~w8TG@+jLZPYDTB((G4F$csXaLFe{0Hh7+CCZtY z&jpc}UB7P9Q+;SCM25~U<|W#eBP3Rx=Uo2l; zF>Y~rwr;owZHJ{tj=Tl-shXIt%%`shXtNl3Y8@X>^QPwB{)DrsNArk-g(KtvyhP#9 zcyPXs>^(N)$r8h!U7;Ln6Am#me1%Ds^(;^*)&2%4-;GJGoY!D0UpbXx_V~?YqH@6TEy(thRrU>X%jv1<66|+%`L;$MFR;nw3Jx;n$8FV+L!s4sI}l+)euU* zkV&cS$|?jX3zbrg0dO{|m$FAL!JghvejpQh;zx(AL-jyc=#IRe( zDN1#QH~*^fXT)?Ns$_S<^Bj*jm#f;acyLth$9U>yVC;=ccLdn$ld+uL{B+o)F4Z`~ zsEe^~o6T3yOY+w${2f&7`D>&aWt;4om#QWsz>G`vtSlq+Fj|JdLHcYPiA$8L12EHV zh0lc=S95k?Tgp&{^Kp_67w^pTo|0P&__{d9-brSMPLSDd%=F9zIP9XI*>H@+i?YX> za?RQ79(%H3*)}<%;F?2PDqdEXEFO77daNs+ztFd6!S>jbZ4?*otHu2KW+)b)=;z_B z?UA~iT~rKcFY1IAs5?-IktNZbhAxGAJT1p{5Rhr;47GKT_HmJhoZgQ`cc}arZtSb|{lTiQD_vD4Bwu^a!xbe5w!LuF z`l`$DU;t6@aO6f$wyVTxf>!}Q;XA$L^)^sW+7%bzq$RkReJ9~EO~}8uz!U~~7cunA z;l|V7E82r9;X5Y7%(DuLr3MvLr&);af0f1`BXzl!CrRP!Sg4+z$z&5hJ8h0Vb=aMH znYU+jl(OPM?y1GG+mkLjgvVR&c%vkPe{d@SPcWmlh#Aj|IuFnnxjsz zR7Jo)9Z#9l5;8U*6J~O@5b)Ue=w__vG>|E1-4Nr9!v$!29I8&nT%H{13LACA7aFMW z?TP26I*Pd2VeG>DLR>+tH~O?v4Z8NDCX#)mECAP#iqp5W0(Rc2Ty{Prpo-g75_X*7^tlfBJH7Xr?t7TWA?0{bPh5{=&=VSQ&a$Ev* zT0Q~k^RFTHHl-u~ym6>|o!EpD56m_pLm))OP+?F|XQt!c9)FU-yS}QZC+z%<)LR`C z_0Q0^)rYNB5jny6hvN+@dYf3Q`MPHJZW}#A*8xFZXfvExC@@ufFKNvguA=Rn1BJDS z)}vLxfS6Uy&z8%Wt77y*pc5wklxN?eSa=urU%} zJ8yovXJcHp+{oOmGIR26p3`QPhtHbzMm;^(<^@icPUEB&d*vuw*8^C_iQQ(d>fR5$E+}#?%pUZGF(DtGexHdUe3>n%0Avs0xm{uZumdn=WS+r% zcos;x8pP*;YY2R&c;k#8ZbZKxQn=W8HY5!qGq;c6J}TSN3NZ=r2$PVqGdK6gF#}En z&QMb++#$n|z#6n15NTzw0`R2Uf*YE%sHW$GlKcxxI$wqHSV+6n2;T>Od~a zzF?~Zf|w;r+Ep~E9yf3ReE~$8h!_tuUpz(cE1j=&aasupdSJ!2grQ=q(DX5LvG=es z$Etl=Fwei@WB$k}(_0}$;cXbo0g?A6x1jHi~wv zkORFM(F=MT(@$5(TuN67a4HJo&4ZdcLSwhl#nru&;KjidH+!De=QkJwCdZht;hLYNe3qQ$uy^C=3WVF$M z`-PBr(Ois-u|4!$Px^D##6%I#3xH>wJ~}N-ZyBKI&wN{@`4C^DkxpbbnU?;_aP_$J z<(tAme?e2(B#Id}Iex1XGZ)PkIFH)h%fa(>U&=?jahYqxl?valQFRq*pqvOK)Mo%6 zg=_MT?`T{w9R$$N9&I|rvBY{WAQ&K}FASMfrU#jZuD zP6(R{Au8or5@z_oVDbJ7(`db^#vbubJGnKSYEB@d=}pa6EV}bh5rNv-WwRFcE@j=D z0lA55mYce{*sZGRsG=9)vZTUC^fc+v#A1*&UUOXeKBD$UrKkb*SK;9z2{Da^gNse7 z`$JI)v1g`;af$=v7QWe_L=jNo%Zbv{I6mk8T+bz-;>BX%iV7;1Sp2Zt0X52!hB6%n zTE;8Y1Pe00m)hCoAJM33Ex~h;?&^~IW*aZ}Lr|6H8 zhO8ey*3MIYEl?efQloB$x$-%F<_Q%0I-9Kf7?SvO*g@boewR1MeZE31xOm2DMRd{< zhhyj%B{y)vde!TrttZILCcOnakA4!_*;Y2{=6P&2gyQSjQ;V)C1h!>=2cQur@Mp5t z$n1jWezY&Tq4(r7>=JCWxsh#R9=9i?gD768!QYdW=oKPN7B~QoXfg$_)n>Ty z+Vb%8=yjH22Xv)jE(;dX!;g_NWqv>$#Y;e+rH-sr_Q^U3*1WY}Mrc^x3i>aAVuhNzqQ)OKg+e4_fG z7*u>Y*;v7sTOLUx#Vq<qo;yOI zvg@AZEo7$RNQcA$K#a67X9Q#F$Gixp#&N;idhA3Efat~{+^2(s^X|JUh-XsP@Au_! zE^>Evrf-0bdXRGH07k&`w8P@hI0 zG)hgFz4SMNn>bWfm$)7i-zAtPXwtA*mi;B!uv#NOHX! z27ZNP+%qW2!GDM_B3TcXnVU$-M3fd6u&n^3?=H+PEqRbFiJyywLD@UU1V5li)x!D& zE!6vIE~E+1pZ5YCtGwGBvg!&zS#Sq}iV3r6?{s-{(^$nwecZ^s&eEr_zPDsivV!Yu zB~VJFtx0js6E}Msu+V@PJt~ z`wKr8LGF>anTz;jUF+hg-c6evZ4p%bAbW@8L?ADqqEJ%@OFly|rgy+2R&)3% zB7~XFLW54g=zY?fX;be#t}yJES!~MUK&j~+>}cm;<0XtrkAS{Sh2x;DVH6cq0Qgm7HQt+GBC$Qr28;M`CQ0Gm%ebx# zo@>Mw4dG;fHL=Nli?Y~KJ$gC>Y88o6g)*Y(1ZByY086t8d9XaRFO}4LtK9DWh4kW- zBu5n+7P-S}pdM2l?z0_nlaH7}7cx=`Vli!>bV@K&=Y0aRuY|BdQfQFx+}U8w*=Sp%QOks##SFmbvf5*w~3Va=i3}m=gHIpe`r2Y8sKfTtMm?? z6!UmtnosV&3cD9YsTvS6Ir1f>G{v?LlCan+8mjYGGZ#%J3t8`_q%uII>64Ki3Be(e zr8~4dgTYfZCEx55xRUzT??`WRfH=y5nq}hTb&oUzH?rOJVjIAx?+OMDAw41w9$W?s z0p!3DKSxYqX9!7A#25!1Kw85BH85if&nya8KwbG^pHJTf4k}vaOHQ+}Je4bT9iDCl z+K}XO8yzn_exx=rT9x;b1!OTFRv8bC zMq2y3vD?msdB_agMQbw%3YSwvRGh0hXfxum!QMK=ku1}sIQS6!T*R_}QFLr}FUPxP zKt8|165v58`ylr66r5s}3ezxJNQkB66)yKvp!qxVfYRGZ4Y*3!zKqz)#l*`HfVq zIyal?UYUn({exlr&T?nvGKHBUV*(%0R-?h|~Rxl%FU%UI9Xq^^aS_H4U4JE@YsFMUy2fm}AM@meIl<`JBP?Y$- zxn^*3_}){-AR5LH?mBtf6!^s#XlR?pm={ob13T%3>epdsSKkGwkt1K7Y32y}MB<02 zmaV8D81!?tgiAb|-qjG#KXZ36Dumlhz?bSP=g@?>=w47J#%;__cV5%hs}0jgW^1mn z@D=?~5Y}KWqD9;V{}Dp)WyE0wD>Z(8Zn?ZXZ|Lh7QQ1Ap2uSD@|0$s%I)bO&=N|XB zfh;7d=o1oPaNSR2I>XL5upft3_A7&>t%#Y>M$OrHf|~lh)vINz;=@oP$2Zs7H$PV)QQpO-M?`n_D-+v)MW8i8vo zqNK(&Z#H@Oh&5IHx`N31b?)Si@MabLAgj`Qjy71zeR*CMX>0?Sa`}*8H!NESEHe9a z{!KpV<1BbIa>&I{4Vs%OL2}XkbeyF60X}Ur<9eirrOz0pMuo0~&b9~24+*)!f*CyD zI$k7FDS(23SG2+~mm>JXn=jf9t)($vdG}jTY zrUpjZZ~h}(<&jdgCoz=>pI6k2@Jn6{&6Q64uMsn;G=gyK!c4sR0@ojCXV-yIn zJ8jjk5EA?k_bQu~q|drxPs*+oiU_++Yq)}odX;pHgqbkPQNaZ=+&9?$yQ=P}m~b;U zKC*$fI|oq~eG5G~0N4n{s!ox7zJlWstqITE*SCpXr@IL-O!VYnz$B#&w)fkcsvBSg ziIilc47sAA;0g-(g<}b9g2;MP?{Uzmqj|w7t$Xa?W=RztzfGZUT}1f3nzNtS_%l{R zZRtUs8!MQBRhoIE$dsSBfSJzlHd(;!O-e%+wqF`+HErs7<%F+MI4xg=6W>hYbNA^P-9bnibXtyZ#0!Z7DfU zPFQLWaCeBi-t?U25v+~=kFS>i>ef#W``IrJO{_m(2)3t(Evo0gCM*PD(wz?#6TN;Y=F$z#$wB%44{^^`%oVB?Hr zF?W4tCK^H(W3fHih1VDDb}Wqc)AV9D-F`VpCt7(UD{EU04O?-^EY zj*b~M)-YfCl?zyr*z#a+@6WAbebLsL(#5u0t?n&U3>1n;ey$@jO-t8)C^YHn`toz3 z_Sox$W4oJ6fbfKt%cJ`C7c?PM)B2BBJmc~|hnU_s6nZmO&*pJ^VG@et5&nT>Afp{4e##x(_&nQLvBfUeJF z9_B(NamrjXMXYFNR9128vO=)p5Yp_v_J!a;M260FBA^;1U)nr|XRAj~+J?0t6Q2HZ zX=d+%!<SeNGeGzm$9ef9L+IQ$ZZ7WT%Z=sMb z#|z9k`8J6bd9tU>$?~ACX=SC~wGX_sQRiH9TC;O+bc^OsR*UZFf3X>ltcqlhIeX5AIqfvCvrZl!*!5QxKXK<{Adu7vnlFig2#_55Y zjO8Fa8{~WS`AU2?Lz*Iyvi#bj%1}(pOX_Qv*gD?)rGkMC0+6F?>G*-pF`QMdFSRp$ zyi|^qydY@7!43;?o{CaxHczI;| z#a3&zOFlb2Po4m;=udYoJ>c_jQyC^~skmU5PnpuB{3&V9MdqM{>@Z}g3zQp>t=N-2 z@i8(Z>k(w`wVynnywKKaSk9VKG0nDI<0H1W_T*&QeYHiP!5BYRE{BTM=J3Gcmf|!! zmmZIJb0=(CSHaNxC?(m&gL|?Q_BU=)G%k42l9rOlT=#6!7PZ+|L!R;?uzLr4#auRd zk45yHPqQV4j89spUPxx-G(N*P!-<}D(_T!0v>jXjGs+ZvtC9xa^>`t zargA~ohH25HQ48|zUb!VNcEEE$ZpsO#H>)Jkt+e44-dt7?U-!%RtHAMh1W^4q<{ID zM!iU;p<}GVd8qh2lNs} z2*ddYg$dHRYO9A##6MwlZo<$>jeN9KURUwN8%CFzU1A(Tvr^h#}9~sJ* zcuvD2&VN)EXqH<>_CzV2(~A|}+x)F4dDm9Kof4`7xubNoJEcV<}A?dOn?f_A7R zfwi;?Ui8O8v4GaVxPJ+{1#4B2`ub?n+)w~lF3-Ef4q+2<1m?tSk7kJMzQQ^fI*+2j zLd4IB5THIM16v|%J!uz#b~d-8;nHX`wGwSN*ZXQG1iytTCubiu4LSu0tuJ#@djdh6Xi5c}h*0wX;;BK#smAb6FHdZ(p0NBtqn{Ns3g`_JRwX$FSBsXG6TNB||*NkRkyQfK{hY}FsJeVWs7x)|H zuk%;mL*7pj`wcOa{5#~&nPTtb-@DEKj`vjmTl{bD`S*zT-q*ho4BCG~{M!lpJ>k7~ z>Td#*;ok{=by9s#dGCk$n^I`}H_D$CsQ2OTJ;8p5uUq{+{GSeC?*Z>EZ+-&=9R3FQ zw*k&?!rQs;#MXaEv;RE)c(v^LSHi!9+W)#T-%fZJ{fA2F_W|Yg|D*roCH@xj4)m|P z1Q5_4%lPykK>rkS|7$J(S<3y#TK>FDo&Ou+ufp!%U(BDl_j>BzI6m+HzqP;W#Q&kL zevf;vYW|Ib^!eYoe`uWF0l)vhw7;ro-;>^p)_#-V zgZ~@pKi+cRx6}Rxwa5M!(EqymzHcP_jYCfSFSviU6~5o$`*QPd5^MH Date: Fri, 21 Jul 2023 11:42:54 +0300 Subject: [PATCH 0570/1464] Delete discord_richpresence.py --- plugins/utilities/discord_richpresence.py | 862 ---------------------- 1 file changed, 862 deletions(-) delete mode 100644 plugins/utilities/discord_richpresence.py diff --git a/plugins/utilities/discord_richpresence.py b/plugins/utilities/discord_richpresence.py deleted file mode 100644 index 3ebccb02..00000000 --- a/plugins/utilities/discord_richpresence.py +++ /dev/null @@ -1,862 +0,0 @@ -# Released under the MIT and Apache License. See LICENSE for details. -# -"""placeholder :clown:""" - -# ba_meta require api 8 -#!"Made to you by @brostos & @Dliwk" - - -from __future__ import annotations -from urllib.request import Request, urlopen, urlretrieve -from pathlib import Path -from os import getcwd, remove -from zipfile import ZipFile -from bauiv1lib.popup import PopupWindow -from babase._mgen.enums import TimeType - -import asyncio -import http.client -import ast -import uuid -import json -import time -import threading -import shutil -import babase -import _babase -import bascenev1 as bs -import bascenev1lib -import bauiv1 as bui - -from typing import TYPE_CHECKING - -if TYPE_CHECKING: - from typing import Any, Tuple - - -ANDROID = babase.app.classic.platform == "android" -DIRPATH = Path(f"{_babase.app.python_directory_user}/image_id.json") - -if ANDROID: # !can add ios in future - - # Installing websocket - def get_module(): - install_path = Path(f"{getcwd()}/ba_data/python") # For the guys like me on windows - path = Path(f"{install_path}/websocket.zip") - file_path = Path(f"{install_path}/websocket") - if not file_path.exists(): - url = "https://github.com/brostosjoined/bombsquadrpc/releases/download/presence-1.0/websocket.zip" - try: - filename, headers = urlretrieve(url, filename=path) - with ZipFile(filename) as f: - f.extractall(install_path) - remove(path) - except: - pass - get_module() - - import websocket - - heartbeat_interval = int(41250) - resume_gateway_url: str | None = None - session_id: str | None = None - - start_time = time.time() - - class PresenceUpdate: - def __init__(self): - self.state: str | None = "In Game" - self.details: str | None = "Main Menu" - self.start_timestamp = time.time() - self.large_image_key: str | None = "bombsquadicon" - self.large_image_text: str | None = "BombSquad Icon" - self.small_image_key: str | None = None - self.small_image_text: str | None = ( - f"{_babase.app.classic.platform.capitalize()}({_babase.app.version})") - self.media_proxy = "mp:/app-assets/963434684669382696/{}.png" - self.identify: bool = False - self.party_id: str = str(uuid.uuid4()) - self.party_size = 1 - self.party_max = 8 - - def presence(self): - with open(DIRPATH, "r") as maptxt: - largetxt = json.load(maptxt)[self.large_image_key] - with open(DIRPATH, "r") as maptxt: - smalltxt = json.load(maptxt)[self.small_image_key] - - presencepayload = { - "op": 3, - "d": { - "since": None, # used to show how long the user went idle will add afk to work with this and then set the status to idle - "status": "online", - "afk": "false", - "activities": [ - { - "name": "BombSquad", - "type": 0, - "application_id": "963434684669382696", - "state": self.state, - "details": self.details, - "timestamps": { - "start": start_time - }, - "party": { - "id": self.party_id, - "size": [self.party_size, self.party_max] - }, - "assets": { - "large_image": self.media_proxy.format(largetxt), - "large_text": self.large_image_text, - "small_image": self.media_proxy.format(smalltxt), - "small_text": self.small_image_text, - }, - "client_info": { - "version": 0, - "os": "android", - "client": "mobile", - }, - "buttons": ["Discord Server", "Download BombSquad"], - "metadata": { - "button_urls": [ - "https://discord.gg/bombsquad-ballistica-official-1001896771347304639", - "https://bombsquad-community.web.app/download", - ] - }, - } - ], - }, - } - ws.send(json.dumps(presencepayload)) - - def on_message(ws, message): - global heartbeat_interval, resume_gateway_url, session_id - message = json.loads(message) - try: - heartbeat_interval = message["d"]["heartbeat_interval"] - except: - pass - try: - resume_gateway_url = message["d"]["resume_gateway_url"] - session_id = message["d"]["session_id"] - except: - pass - - def on_error(ws, error): - babase.print_exception(error) - - def on_close(ws, close_status_code, close_msg): - # print("### closed ###") - pass - - def on_open(ws): - print("Connected to Discord Websocket") - - def heartbeats(): - """Sending heartbeats to keep the connection alive""" - global heartbeat_interval - if babase.do_once(): - heartbeat_payload = { - "op": 1, - "d": 251, - } # step two keeping connection alive by sending heart beats and receiving opcode 11 - ws.send(json.dumps(heartbeat_payload)) - - def identify(): - """Identifying to the gateway and enable by using user token and the intents we will be using e.g 256->For Presence""" - with open(f"{getcwd()}/token.txt", 'r') as f: - token = bytes.fromhex(f.read()).decode('utf-8') - identify_payload = { - "op": 2, - "d": { - "token": token, - "properties": { - "os": "linux", - "browser": "Discord Android", - "device": "android", - }, - "intents": 256, - }, - } # step 3 send an identify - ws.send(json.dumps(identify_payload)) - identify() - while True: - heartbeat_payload = {"op": 1, "d": heartbeat_interval} - ws.send(json.dumps(heartbeat_payload)) - time.sleep(heartbeat_interval / 1000) - - threading.Thread(target=heartbeats, daemon=True, name="heartbeat").start() - - # websocket.enableTrace(True) - ws = websocket.WebSocketApp( - "wss://gateway.discord.gg/?encoding=json&v=10", - on_open=on_open, - on_message=on_message, - on_error=on_error, - on_close=on_close, - ) - if Path(f"{getcwd()}/token.txt").exists(): - threading.Thread(target=ws.run_forever, daemon=True, name="websocket").start() - - -if not ANDROID: - # installing pypresence - def get_module(): - install_path = Path(f"{getcwd()}/ba_data/python") - path = Path(f"{install_path}/pypresence.zip") - file_path = Path(f"{install_path}/pypresence") - if not file_path.exists(): - url = "https://github.com/brostosjoined/bombsquadrpc/releases/download/presence-1.0/pypresence.zip" - try: - filename, headers = urlretrieve(url, filename=path) - with ZipFile(filename) as f: - f.extractall(install_path) - remove(path) - except: - pass - get_module() - - # Updating pypresence - try: - from pypresence import PipeClosed, DiscordError, DiscordNotFound - except ImportError: - shutil.rmtree(Path(f"{getcwd()}/ba_data/python/pypresence")) - get_module() - - from pypresence.utils import get_event_loop - import pypresence - import socket - - DEBUG = True - - _last_server_addr = 'localhost' - _last_server_port = 43210 - - def print_error(err: str, include_exception: bool = False) -> None: - if DEBUG: - if include_exception: - babase.print_exception(err) - else: - babase.print_error(err) - else: - print(f"ERROR in discordrp.py: {err}") - - def log(msg: str) -> None: - if DEBUG: - print(f"LOG in discordrp.py: {msg}") - - def _run_overrides() -> None: - old_init = bs.Activity.__init__ - - def new_init(self, *args: Any, **kwargs: Any) -> None: # type: ignore - old_init(self, *args, **kwargs) - self._discordrp_start_time = time.mktime(time.localtime()) - - bs.Activity.__init__ = new_init # type: ignore - - old_connect = bs.connect_to_party - - def new_connect(*args, **kwargs) -> None: # type: ignore - global _last_server_addr - global _last_server_port - old_connect(*args, **kwargs) - c = kwargs.get("address") or args[0] - _last_server_port = kwargs.get("port") or args[1] - - bs.connect_to_party = new_connect - - start_time = time.time() - - class RpcThread(threading.Thread): - def __init__(self): - super().__init__(name="RpcThread") - self.rpc = pypresence.Presence(963434684669382696) - self.state: str | None = "In Game" - self.details: str | None = "Main Menu" - self.start_timestamp = time.mktime(time.localtime()) - self.large_image_key: str | None = "bombsquadicon" - self.large_image_text: str | None = "BombSquad Icon" - self.small_image_key: str | None = None - self.small_image_text: str | None = None - self.party_id: str = str(uuid.uuid4()) - self.party_size = 1 - self.party_max = 8 - self.join_secret: str | None = None - self._last_update_time: float = 0 - self._last_secret_update_time: float = 0 - self._last_connect_time: float = 0 - self.should_close = False - - @staticmethod - def is_discord_running(): - for i in range(6463, 6473): - s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) - s.settimeout(0.01) - try: - conn = s.connect_ex(('localhost', i)) - s.close() - if (conn == 0): - s.close() - return (True) - except: - s.close() - return (False) - - def _generate_join_secret(self): - # resp = requests.get('https://legacy.ballistica.net/bsAccessCheck').text - connection_info = bs.get_connection_to_host_info() - if connection_info: - addr = _last_server_addr - port = _last_server_port - else: - try: - with urlopen( - "https://legacy.ballistica.net/bsAccessCheck" - ) as resp: - resp = resp.read().decode() - resp = ast.literal_eval(resp) - addr = resp["address"] - port = 43210 - secret_dict = { - "format_version": 1, - "hostname": addr, - "port": port, - } - self.join_secret = json.dumps(secret_dict) - except: - pass - - def _update_secret(self): - threading.Thread(target=self._generate_join_secret, daemon=True).start() - self._last_secret_update_time = time.time() - - def run(self) -> None: - asyncio.set_event_loop(get_event_loop()) - while not self.should_close: - if time.time() - self._last_update_time > 0.1: - self._do_update_presence() - if time.time() - self._last_secret_update_time > 15: - self._update_secret() - # if time.time() - self._last_connect_time > 120 and is_discord_running(): #!Eric please add module manager(pip) - # self._reconnect() - time.sleep(0.03) - - def _subscribe(self, event: str, **args): - self.rpc.send_data( - 1, - { - "nonce": f"{time.time():.20f}", - "cmd": "SUBSCRIBE", - "evt": event, - "args": args, - }, - ) - data = self.rpc.loop.run_until_complete(self.rpc.read_output()) - self.handle_event(data) - - def _subscribe_events(self): - self._subscribe("ACTIVITY_JOIN") - self._subscribe("ACTIVITY_JOIN_REQUEST") - - # def _update_presence(self) -> None: - # self._last_update_time = time.time() - # try: - # self._do_update_presence() - # except (AttributeError, AssertionError): - # try: - # self._reconnect() - # except Exception: - # print_error("failed to update presence", include_exception= True) - - def _reconnect(self) -> None: - self.rpc.connect() - self._subscribe_events() - self._do_update_presence() - self._last_connect_time = time.time() - - def _do_update_presence(self) -> None: - if RpcThread.is_discord_running(): - self._last_update_time = time.time() - try: - data = self.rpc.update( - state=self.state or " ", - details=self.details, - start=start_time, - large_image=self.large_image_key, - large_text=self.large_image_text, - small_image=self.small_image_key, - small_text=self.small_image_text, - party_id=self.party_id, - party_size=[self.party_size, self.party_max], - join=self.join_secret, - # buttons = [ #!cant use buttons together with join - # { - # "label": "Discord Server", - # "url": "https://ballistica.net/discord" - # }, - # { - # "label": "Download Bombsquad", - # "url": "https://bombsquad.ga/download"} - # ] - ) - - self.handle_event(data) - except (PipeClosed, DiscordError, AssertionError, AttributeError): - try: - self._reconnect() - except (DiscordNotFound, DiscordError): - pass - - def handle_event(self, data): - evt = data["evt"] - if evt is None: - return - - data = data.get("data", {}) - - if evt == "ACTIVITY_JOIN": - secret = data.get("secret") - try: - server = json.loads(secret) - format_version = server["format_version"] - except Exception: - babase.print_exception("discordrp: unknown activity join format") - else: - try: - if format_version == 1: - hostname = server["hostname"] - port = server["port"] - self._connect_to_party(hostname, port) - except Exception: - babase.print_exception( - f"discordrp: incorrect activity join data, {format_version=}" - ) - - elif evt == "ACTIVITY_JOIN_REQUEST": - user = data.get("user", {}) - uid = user.get("id") - username = user.get("username") - discriminator = user.get("discriminator", None) - avatar = user.get("avatar") - self.on_join_request(username, uid, discriminator, avatar) - - def _connect_to_party(self, hostname, port) -> None: - babase.pushcall( - babase.Call(bs.connect_to_party, hostname, port), from_other_thread=True - ) - - def on_join_request(self, username, uid, discriminator, avatar) -> None: - del uid # unused - del avatar # unused - babase.pushcall( - babase.Call( - bui.screenmessage, - "Discord: {} wants to join!".format(username), - color=(0.0, 1.0, 0.0), - ), - from_other_thread=True, - ) - babase.pushcall(lambda: bui.getsound('bellMed').play(), from_other_thread=True) - - -class Discordlogin(PopupWindow): - - def __init__(self): - # pylint: disable=too-many-locals - _uiscale = bui.app.ui_v1.uiscale - self._transitioning_out = False - s = 1.25 if _uiscale is babase.UIScale.SMALL else 1.27 if _uiscale is babase.UIScale.MEDIUM else 1.3 - self._width = 380 * s - self._height = 150 + 150 * s - self.path = Path(f"{getcwd()}/token.txt") - bg_color = (0.5, 0.4, 0.6) - log_btn_colour = (0.10, 0.95, 0.10) if not self.path.exists() else (1.00, 0.15, 0.15) - log_txt = "LOG IN" if not self.path.exists() else "LOG OUT" - - # creates our _root_widget - PopupWindow.__init__(self, - position=(0.0, 0.0), - size=(self._width, self._height), - scale=(2.1 if _uiscale is babase.UIScale.SMALL else 1.5 - if _uiscale is babase.UIScale.MEDIUM else 1.0), - bg_color=bg_color) - - self._cancel_button = bui.buttonwidget( - parent=self.root_widget, - position=(25, self._height - 40), - size=(50, 50), - scale=0.58, - label='', - color=bg_color, - on_activate_call=self._on_cancel_press, - autoselect=True, - icon=bui.gettexture('crossOut'), - iconscale=1.2) - - bui.imagewidget(parent=self.root_widget, - position=(180, self._height - 55), - size=(32 * s, 32 * s), - texture=bui.gettexture("discordLogo"), - color=(10 - 0.32, 10 - 0.39, 10 - 0.96)) - - self.email_widget = bui.textwidget(parent=self.root_widget, - text="Email/Phone Number", - size=(400, 70), - position=(50, 180), - h_align='left', - v_align='center', - editable=True, - scale=0.8, - autoselect=True, - maxwidth=220) - - self.password_widget = bui.textwidget(parent=self.root_widget, - text="Password", - size=(400, 70), - position=(50, 120), - h_align='left', - v_align='center', - editable=True, - scale=0.8, - autoselect=True, - maxwidth=220) - - bui.containerwidget(edit=self.root_widget, - cancel_button=self._cancel_button) - - bui.textwidget( - parent=self.root_widget, - position=(265, self._height - 37), - size=(0, 0), - h_align='center', - v_align='center', - scale=1.0, - text="Discord", - maxwidth=200, - color=(0.80, 0.80, 0.80)) - - bui.textwidget( - parent=self.root_widget, - position=(265, self._height - 78), - size=(0, 0), - h_align='center', - v_align='center', - scale=1.0, - text="💀Use at your own risk💀\n ⚠️discord account might get terminated⚠️", - maxwidth=200, - color=(1.00, 0.15, 0.15)) - - self._login_button = bui.buttonwidget( - parent=self.root_widget, - position=(120, 65), - size=(400, 80), - scale=0.58, - label=log_txt, - color=log_btn_colour, - on_activate_call=self.login, - autoselect=True) - - def _on_cancel_press(self) -> None: - self._transition_out() - - def _transition_out(self) -> None: - if not self._transitioning_out: - self._transitioning_out = True - bui.containerwidget(edit=self.root_widget, transition='out_scale') - - def on_bascenev1libup_cancel(self) -> None: - bui.getsound('swish').play() - self._transition_out() - - def login(self): - if not self.path.exists(): - json_data = { - 'login': bui.textwidget(query=self.email_widget), - 'password': bui.textwidget(query=self.password_widget), - 'undelete': False, - 'captcha_key': None, - 'login_source': None, - 'gift_code_sku_id': None, - } - headers = { - 'user-agent': "Mozilla/5.0", - 'content-type': "application/json", - } - - conn = http.client.HTTPSConnection("discord.com") - - payload = json.dumps(json_data) - # conn.request("POST", "/api/v9/auth/login", payload, headers) - # res = conn.getresponse().read() - - try: - conn.request("POST", "/api/v9/auth/login", payload, headers) - res = conn.getresponse().read() - token = json.loads(res)['token'].encode().hex().encode() - with open(self.path, 'wb') as f: - f.write(token) - bui.screenmessage("Successfully logged in", (0.21, 1.0, 0.20)) - bui.getsound('shieldUp').play() - self.on_bascenev1libup_cancel() - except: - bui.screenmessage("Incorrect credentials", (1.00, 0.15, 0.15)) - bui.getsound('error').play() - - conn.close() - else: - remove(self.path) - bui.getsound('shieldDown').play() - bui.screenmessage("Account successfully removed!!", (0.10, 0.10, 1.00)) - self.on_bascenev1libup_cancel() - ws.close() - - -run_once = False - - -def get_once_asset(): - global run_once - if run_once: - return - response = Request( - "https://discordapp.com/api/oauth2/applications/963434684669382696/assets", - headers={"User-Agent": "Mozilla/5.0"}, - ) - try: - with urlopen(response) as assets: - assets = json.loads(assets.read()) - asset = [] - asset_id = [] - for x in assets: - dem = x["name"] - don = x["id"] - asset_id.append(don) - asset.append(dem) - asset_id_dict = dict(zip(asset, asset_id)) - - with open(DIRPATH, "w") as imagesets: - jsonfile = json.dumps(asset_id_dict) - json.dump(asset_id_dict, imagesets, indent=4) - except: - pass - run_once = True - - -def get_class(): - if ANDROID: - return PresenceUpdate() - elif not ANDROID: - return RpcThread() - - -# ba_meta export babase.Plugin -class DiscordRP(babase.Plugin): - def __init__(self) -> None: - self.update_timer: bs.Timer | None = None - self.rpc_thread = get_class() - self._last_server_info: str | None = None - - if not ANDROID: - _run_overrides() - get_once_asset() - - def on_app_running(self) -> None: - if not ANDROID: - self.rpc_thread.start() - self.update_timer = bs.AppTimer( - 1, bs.WeakCall(self.update_status), repeat=True - ) - if ANDROID: - self.update_timer = bs.AppTimer( - 4, bs.WeakCall(self.update_status), repeat=True - ) - - def has_settings_ui(self): - return True - - def show_settings_ui(self, button): - if not ANDROID: - bui.screenmessage("Nothing here achievement!!!", (0.26, 0.65, 0.94)) - bui.getsound('achievement').play() - if ANDROID: - Discordlogin() - - def on_app_shutdown(self) -> None: - if not ANDROID and self.rpc_thread.is_discord_running(): - self.rpc_thread.rpc.close() - self.rpc_thread.should_close = True - else: - # stupid code - ws.close() - - def _get_current_activity_name(self) -> str | None: - act = bs.get_foreground_host_activity() - if isinstance(act, bs.GameActivity): - return act.name - - this = "Lobby" - name: str | None = ( - act.__class__.__name__.replace("Activity", "") - .replace("ScoreScreen", "Ranking") - .replace("Coop", "") - .replace("MultiTeam", "") - .replace("Victory", "") - .replace("EndSession", "") - .replace("Transition", "") - .replace("Draw", "") - .replace("FreeForAll", "") - .replace("Join", this) - .replace("Team", "") - .replace("Series", "") - .replace("CustomSession", "Custom Session(mod)") - ) - - if name == "MainMenu": - name = "Main Menu" - if name == this: - self.rpc_thread.large_image_key = "lobby" - self.rpc_thread.large_image_text = "Bombing up" - #self.rpc_thread.small_image_key = "lobbysmall" - if name == "Ranking": - self.rpc_thread.large_image_key = "ranking" - self.rpc_thread.large_image_text = "Viewing Results" - return name - - def _get_current_map_name(self) -> Tuple[str | None, str | None]: - act = bs.get_foreground_host_activity() - if isinstance(act, bs.GameActivity): - texname = act.map.get_preview_texture_name() - if texname: - return act.map.name, texname.lower().removesuffix("preview") - return None, None - - def update_status(self) -> None: - roster = bs.get_game_roster() - connection_info = bs.get_connection_to_host_info() - - self.rpc_thread.large_image_key = "bombsquadicon" - self.rpc_thread.large_image_text = "BombSquad" - self.rpc_thread.small_image_key = _babase.app.classic.platform - self.rpc_thread.small_image_text = ( - f"{_babase.app.classic.platform.capitalize()}({_babase.app.version})" - ) - connection_info = bs.get_connection_to_host_info() - if not ANDROID: - svinfo = str(connection_info) - if self._last_server_info != svinfo: - self._last_server_info = svinfo - self.rpc_thread.party_id = str(uuid.uuid4()) - self.rpc_thread._update_secret() - if connection_info != {}: - servername = connection_info["name"] - self.rpc_thread.details = "Online" - self.rpc_thread.party_size = max( - 1, sum(len(client["players"]) for client in roster) - ) - self.rpc_thread.party_max = max(8, self.rpc_thread.party_size) - if len(servername) == 19 and "Private Party" in servername: - self.rpc_thread.state = "Private Party" - elif servername == "": # A local game joinable from the internet - try: - offlinename = json.loads(bs.get_game_roster()[0]["spec_string"])[ - "n" - ] - if len(offlinename) > 19: # Thanks Rikko - self.rpc_thread.state = offlinename[slice(19)] + "..." - else: - self.rpc_thread.state = offlinename - except IndexError: - pass - else: - if len(servername) > 19: - self.rpc_thread.state = servername[slice(19)] + ".." - else: - self.rpc_thread.state = servername[slice(19)] - - if connection_info == {}: - self.rpc_thread.details = "Local" # ! replace with something like ballistica github cause - self.rpc_thread.state = self._get_current_activity_name() - self.rpc_thread.party_size = max(1, len(roster)) - self.rpc_thread.party_max = max(1, bs.get_public_party_max_size()) - - if ( - bs.get_foreground_host_session() is not None - and self.rpc_thread.details == "Local" - ): - session = ( - bs.get_foreground_host_session() - .__class__.__name__.replace("MainMenuSession", "") - .replace("EndSession", "") - .replace("FreeForAllSession", ": FFA") # ! for session use small image key - .replace("DualTeamSession", ": Teams") - .replace("CoopSession", ": Coop") - ) - #! self.rpc_thread.small_image_key = session.lower() - self.rpc_thread.details = f"{self.rpc_thread.details} {session}" - if ( - self.rpc_thread.state == "NoneType" - ): # sometimes the game just breaks which means its not really watching replay FIXME - self.rpc_thread.state = "Watching Replay" - self.rpc_thread.large_image_key = "replay" - self.rpc_thread.large_image_text = "Viewing Awesomeness" - #!self.rpc_thread.small_image_key = "replaysmall" - - act = bs.get_foreground_host_activity() - session = bs.get_foreground_host_session() - if act: - from bascenev1lib.game.elimination import EliminationGame - from bascenev1lib.game.thelaststand import TheLastStandGame - from bascenev1lib.game.meteorshower import MeteorShowerGame - - # noinspection PyUnresolvedReferences,PyProtectedMember - try: - self.rpc_thread.start_timestamp = act._discordrp_start_time # type: ignore - except AttributeError: - # This can be the case if plugin launched AFTER activity - # has been created; in that case let's assume it was - # created just now. - self.rpc_thread.start_timestamp = act._discordrp_start_time = time.mktime( # type: ignore - time.localtime() - ) - if isinstance(act, EliminationGame): - alive_count = len([p for p in act.players if p.lives > 0]) - self.rpc_thread.details += f" ({alive_count} players left)" - elif isinstance(act, TheLastStandGame): - # noinspection PyProtectedMember - points = act._score - self.rpc_thread.details += f" ({points} points)" - elif isinstance(act, MeteorShowerGame): - with bs.ContextRef(act): - sec = bs.time() - act._timer.getstarttime() - secfmt = "" - if sec < 60: - secfmt = f"{sec:.2f}" - else: - secfmt = f"{int(sec) // 60:02}:{sec:.2f}" - self.rpc_thread.details += f" ({secfmt})" - - # if isinstance(session, ba.DualTeamSession): - # scores = ':'.join([ - # str(t.customdata['score']) - # for t in session.sessionteams - # ]) - # self.rpc_thread.details += f' ({scores})' - - mapname, short_map_name = self._get_current_map_name() - if mapname: - with open(DIRPATH, 'r') as asset_dict: - asset_keys = json.load(asset_dict).keys() - if short_map_name in asset_keys: - self.rpc_thread.large_image_text = mapname - self.rpc_thread.large_image_key = short_map_name - self.rpc_thread.small_image_key = 'bombsquadlogo2' - self.rpc_thread.small_image_text = 'BombSquad' - - if _babase.get_idle_time() / (1000 * 60) % 60 >= 0.4: - self.rpc_thread.details = f"AFK in {self.rpc_thread.details}" - if not ANDROID: - self.rpc_thread.large_image_key = ( - "https://media.tenor.com/uAqNn6fv7x4AAAAM/bombsquad-spaz.gif" - ) - if ANDROID and Path(f"{getcwd()}/token.txt").exists(): - self.rpc_thread.presence() From 9f82a400fd0101eebb181c7db05fb514532d56e5 Mon Sep 17 00:00:00 2001 From: brostos <67740566+brostosjoined@users.noreply.github.com> Date: Fri, 21 Jul 2023 11:43:16 +0300 Subject: [PATCH 0571/1464] Add files via upload --- plugins/utilities/discord_richpresence.py | 918 ++++++++++++++++++++++ 1 file changed, 918 insertions(+) create mode 100644 plugins/utilities/discord_richpresence.py diff --git a/plugins/utilities/discord_richpresence.py b/plugins/utilities/discord_richpresence.py new file mode 100644 index 00000000..7ea0615c --- /dev/null +++ b/plugins/utilities/discord_richpresence.py @@ -0,0 +1,918 @@ +# Released under the MIT and Apache License. See LICENSE for details. +# +"""placeholder :clown:""" + +# ba_meta require api 8 +#!"Made to you by @brostos & @Dliwk" + + +from __future__ import annotations +from urllib.request import Request, urlopen, urlretrieve +from pathlib import Path +from os import getcwd, remove +from zipfile import ZipFile +from bauiv1lib.popup import PopupWindow +from babase._mgen.enums import TimeType + +import asyncio +import http.client +import ast +import uuid +import json +import time +import threading +import shutil +import babase +import _babase +import bascenev1 as bs +import bascenev1lib +import bauiv1 as bui + +from typing import TYPE_CHECKING + +if TYPE_CHECKING: + from typing import Any, Tuple + + +ANDROID = babase.app.classic.platform == "android" +DIRPATH = Path(f"{_babase.app.python_directory_user}/image_id.json") + +if ANDROID: # !can add ios in future + + # Installing websocket + def get_module(): + install_path = Path(f"{getcwd()}/ba_data/python") # For the guys like me on windows + path = Path(f"{install_path}/websocket.zip") + file_path = Path(f"{install_path}/websocket") + source_dir = Path(f"{install_path}/websocket-client-1.6.1/websocket") + if not file_path.exists(): + url = "https://github.com/websocket-client/websocket-client/archive/refs/tags/v1.6.1.zip" + try: + filename, headers = urlretrieve(url, filename=path) + with ZipFile(filename) as f: + f.extractall(install_path) + shutil.copytree(source_dir, file_path) + shutil.rmtree(Path(f"{install_path}/websocket-client-1.6.1")) + remove(path) + except Exception as e: + if type(e) == shutil.Error: + shutil.rmtree(Path(f"{install_path}/websocket-client-1.6.1")) + else: + pass + get_module() + + import websocket + + heartbeat_interval = int(41250) + resume_gateway_url: str | None = None + session_id: str | None = None + + start_time = time.time() + + class PresenceUpdate: + def __init__(self): + self.state: str | None = "In Game" + self.details: str | None = "Main Menu" + self.start_timestamp = time.time() + self.large_image_key: str | None = "bombsquadicon" + self.large_image_text: str | None = "BombSquad Icon" + self.small_image_key: str | None = None + self.small_image_text: str | None = ( + f"{_babase.app.classic.platform.capitalize()}({_babase.app.version})") + self.media_proxy = "mp:/app-assets/963434684669382696/{}.png" + self.identify: bool = False + self.party_id: str = str(uuid.uuid4()) + self.party_size = 1 + self.party_max = 8 + + def presence(self): + with open(DIRPATH, "r") as maptxt: + largetxt = json.load(maptxt)[self.large_image_key] + with open(DIRPATH, "r") as maptxt: + smalltxt = json.load(maptxt)[self.small_image_key] + + presencepayload = { + "op": 3, + "d": { + "since": None, # used to show how long the user went idle will add afk to work with this and then set the status to idle + "status": "online", + "afk": "false", + "activities": [ + { + "name": "BombSquad", + "type": 0, + "application_id": "963434684669382696", + "state": self.state, + "details": self.details, + "timestamps": { + "start": start_time + }, + "party": { + "id": self.party_id, + "size": [self.party_size, self.party_max] + }, + "assets": { + "large_image": self.media_proxy.format(largetxt), + "large_text": self.large_image_text, + "small_image": self.media_proxy.format(smalltxt), + "small_text": self.small_image_text, + }, + "client_info": { + "version": 0, + "os": "android", + "client": "mobile", + }, + "buttons": ["Discord Server", "Download BombSquad"], + "metadata": { + "button_urls": [ + "https://discord.gg/bombsquad-ballistica-official-1001896771347304639", + "https://bombsquad-community.web.app/download", + ] + }, + } + ], + }, + } + ws.send(json.dumps(presencepayload)) + + def on_message(ws, message): + global heartbeat_interval, resume_gateway_url, session_id + message = json.loads(message) + try: + heartbeat_interval = message["d"]["heartbeat_interval"] + except: + pass + try: + resume_gateway_url = message["d"]["resume_gateway_url"] + session_id = message["d"]["session_id"] + except: + pass + + def on_error(ws, error): + babase.print_exception(error) + + def on_close(ws, close_status_code, close_msg): + # print("### closed ###") + pass + + def on_open(ws): + print("Connected to Discord Websocket") + + def heartbeats(): + """Sending heartbeats to keep the connection alive""" + global heartbeat_interval + if babase.do_once(): + heartbeat_payload = { + "op": 1, + "d": 251, + } # step two keeping connection alive by sending heart beats and receiving opcode 11 + ws.send(json.dumps(heartbeat_payload)) + + def identify(): + """Identifying to the gateway and enable by using user token and the intents we will be using e.g 256->For Presence""" + with open(f"{getcwd()}/token.txt", 'r') as f: + token = bytes.fromhex(f.read()).decode('utf-8') + identify_payload = { + "op": 2, + "d": { + "token": token, + "properties": { + "os": "linux", + "browser": "Discord Android", + "device": "android", + }, + "intents": 256, + }, + } # step 3 send an identify + ws.send(json.dumps(identify_payload)) + identify() + while True: + heartbeat_payload = {"op": 1, "d": heartbeat_interval} + try: + ws.send(json.dumps(heartbeat_payload)) + time.sleep(heartbeat_interval / 1000) + except: + pass + + threading.Thread(target=heartbeats, daemon=True, name="heartbeat").start() + + # websocket.enableTrace(True) + ws = websocket.WebSocketApp( + "wss://gateway.discord.gg/?encoding=json&v=10", + on_open=on_open, + on_message=on_message, + on_error=on_error, + on_close=on_close, + ) + if Path(f"{getcwd()}/token.txt").exists(): + threading.Thread(target=ws.run_forever, daemon=True, name="websocket").start() + + +if not ANDROID: + # installing pypresence + def get_module(): + install_path = Path(f"{getcwd()}/ba_data/python") + path = Path(f"{install_path}/pypresence.zip") + file_path = Path(f"{install_path}/pypresence") + source_dir = Path(f"{install_path}/pypresence-4.3.0/pypresence") + if not file_path.exists(): + url = "https://github.com/qwertyquerty/pypresence/archive/refs/tags/v4.3.0.zip" + try: + filename, headers = urlretrieve(url, filename=path) + with ZipFile(filename) as f: + f.extractall(install_path) + shutil.copytree(source_dir, file_path) + shutil.rmtree(Path(f"{install_path}/pypresence-4.3.0")) + remove(path) + except: + pass + + # Make modifications for it to work on windows + if babase.app.classic.platform == "windows": + with open(Path(f"{getcwd()}/ba_data/python/pypresence/utils.py"), "r") as file: + data = file.readlines() + data[45] = """ +def get_event_loop(force_fresh=False): + loop = asyncio.ProactorEventLoop() if sys.platform == 'win32' else asyncio.new_event_loop() + if force_fresh: + return loop + try: + running = asyncio.get_running_loop() + except RuntimeError: + return loop + if running.is_closed(): + return loop + else: + if sys.platform in ('linux', 'darwin'): + return running + if sys.platform == 'win32': + if isinstance(running, asyncio.ProactorEventLoop): + return running + else: + return loop""" + + with open(Path(f"{getcwd()}/ba_data/python/pypresence/utils.py"), "w") as file: + for number, line in enumerate(data): + if number not in range(46,56): + file.write(line) + get_module() + + + from pypresence import PipeClosed, DiscordError, DiscordNotFound + from pypresence.utils import get_event_loop + import pypresence + import socket + + DEBUG = True + + _last_server_addr = 'localhost' + _last_server_port = 43210 + + def print_error(err: str, include_exception: bool = False) -> None: + if DEBUG: + if include_exception: + babase.print_exception(err) + else: + babase.print_error(err) + else: + print(f"ERROR in discordrp.py: {err}") + + def log(msg: str) -> None: + if DEBUG: + print(f"LOG in discordrp.py: {msg}") + + def _run_overrides() -> None: + old_init = bs.Activity.__init__ + + def new_init(self, *args: Any, **kwargs: Any) -> None: # type: ignore + old_init(self, *args, **kwargs) + self._discordrp_start_time = time.mktime(time.localtime()) + + bs.Activity.__init__ = new_init # type: ignore + + old_connect = bs.connect_to_party + + def new_connect(*args, **kwargs) -> None: # type: ignore + global _last_server_addr + global _last_server_port + old_connect(*args, **kwargs) + c = kwargs.get("address") or args[0] + _last_server_port = kwargs.get("port") or args[1] + + bs.connect_to_party = new_connect + + start_time = time.time() + + class RpcThread(threading.Thread): + def __init__(self): + super().__init__(name="RpcThread") + self.rpc = pypresence.Presence(963434684669382696) + self.state: str | None = "In Game" + self.details: str | None = "Main Menu" + self.start_timestamp = time.mktime(time.localtime()) + self.large_image_key: str | None = "bombsquadicon" + self.large_image_text: str | None = "BombSquad Icon" + self.small_image_key: str | None = None + self.small_image_text: str | None = None + self.party_id: str = str(uuid.uuid4()) + self.party_size = 1 + self.party_max = 8 + self.join_secret: str | None = None + self._last_update_time: float = 0 + self._last_secret_update_time: float = 0 + self._last_connect_time: float = 0 + self.should_close = False + + @staticmethod + def is_discord_running(): + for i in range(6463,6473): + s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) + s.settimeout(0.01) + try: + conn = s.connect_ex(('localhost', i)) + s.close() + if (conn == 0): + s.close() + return(True) + except: + s.close() + return(False) + + def _generate_join_secret(self): + # resp = requests.get('https://legacy.ballistica.net/bsAccessCheck').text + connection_info = bs.get_connection_to_host_info() + if connection_info: + addr = _last_server_addr + port = _last_server_port + else: + try: + with urlopen( + "https://legacy.ballistica.net/bsAccessCheck" + ) as resp: + resp = resp.read().decode() + resp = ast.literal_eval(resp) + addr = resp["address"] + port = 43210 + secret_dict = { + "format_version": 1, + "hostname": addr, + "port": port, + } + self.join_secret = json.dumps(secret_dict) + except: + pass + + def _update_secret(self): + threading.Thread(target=self._generate_join_secret, daemon=True).start() + self._last_secret_update_time = time.time() + + def run(self) -> None: + asyncio.set_event_loop(get_event_loop()) + while not self.should_close: + if time.time() - self._last_update_time > 0.1: + self._do_update_presence() + if time.time() - self._last_secret_update_time > 15: + self._update_secret() + # if time.time() - self._last_connect_time > 120 and is_discord_running(): #!Eric please add module manager(pip) + # self._reconnect() + time.sleep(0.03) + + def _subscribe(self, event: str, **args): + self.rpc.send_data( + 1, + { + "nonce": f"{time.time():.20f}", + "cmd": "SUBSCRIBE", + "evt": event, + "args": args, + }, + ) + data = self.rpc.loop.run_until_complete(self.rpc.read_output()) + self.handle_event(data) + + def _subscribe_events(self): + self._subscribe("ACTIVITY_JOIN") + self._subscribe("ACTIVITY_JOIN_REQUEST") + + # def _update_presence(self) -> None: + # self._last_update_time = time.time() + # try: + # self._do_update_presence() + # except (AttributeError, AssertionError): + # try: + # self._reconnect() + # except Exception: + # print_error("failed to update presence", include_exception= True) + + + def _reconnect(self) -> None: + self.rpc.connect() + self._subscribe_events() + self._do_update_presence() + self._last_connect_time = time.time() + + def _do_update_presence(self) -> None: + if RpcThread.is_discord_running(): + self._last_update_time = time.time() + try: + data = self.rpc.update( + state=self.state or " ", + details=self.details, + start=start_time, + large_image=self.large_image_key, + large_text=self.large_image_text, + small_image=self.small_image_key, + small_text=self.small_image_text, + party_id=self.party_id, + party_size=[self.party_size, self.party_max], + join=self.join_secret, + # buttons = [ #!cant use buttons together with join + # { + # "label": "Discord Server", + # "url": "https://ballistica.net/discord" + # }, + # { + # "label": "Download Bombsquad", + # "url": "https://bombsquad.ga/download"} + # ] + ) + + self.handle_event(data) + except (PipeClosed, DiscordError, AssertionError, AttributeError): + try: + self._reconnect() + except (DiscordNotFound, DiscordError): + pass + + def handle_event(self, data): + evt = data["evt"] + if evt is None: + return + + data = data.get("data", {}) + + if evt == "ACTIVITY_JOIN": + secret = data.get("secret") + try: + server = json.loads(secret) + format_version = server["format_version"] + except Exception: + babase.print_exception("discordrp: unknown activity join format") + else: + try: + if format_version == 1: + hostname = server["hostname"] + port = server["port"] + self._connect_to_party(hostname, port) + except Exception: + babase.print_exception( + f"discordrp: incorrect activity join data, {format_version=}" + ) + + elif evt == "ACTIVITY_JOIN_REQUEST": + user = data.get("user", {}) + uid = user.get("id") + username = user.get("username") + discriminator = user.get("discriminator", None) + avatar = user.get("avatar") + self.on_join_request(username, uid, discriminator, avatar) + + def _connect_to_party(self, hostname, port) -> None: + babase.pushcall( + babase.Call(bs.connect_to_party, hostname, port), from_other_thread=True + ) + + def on_join_request(self, username, uid, discriminator, avatar) -> None: + del uid # unused + del avatar # unused + babase.pushcall( + babase.Call( + bui.screenmessage, + "Discord: {} wants to join!".format(username), + color=(0.0, 1.0, 0.0), + ), + from_other_thread=True, + ) + babase.pushcall(lambda: bui.getsound('bellMed').play(), from_other_thread=True) + + +class Discordlogin(PopupWindow): + + def __init__(self): + # pylint: disable=too-many-locals + _uiscale = bui.app.ui_v1.uiscale + self._transitioning_out = False + s = 1.25 if _uiscale is babase.UIScale.SMALL else 1.27 if _uiscale is babase.UIScale.MEDIUM else 1.3 + self._width = 380 * s + self._height = 150 + 150 * s + self.path = Path(f"{getcwd()}/token.txt") + bg_color = (0.5, 0.4, 0.6) + log_btn_colour = (0.10, 0.95, 0.10) if not self.path.exists() else (1.00, 0.15, 0.15) + log_txt = "LOG IN" if not self.path.exists() else "LOG OUT" + + + + + # creates our _root_widget + PopupWindow.__init__(self, + position=(0.0, 0.0), + size=(self._width, self._height), + scale=(2.1 if _uiscale is babase.UIScale.SMALL else 1.5 + if _uiscale is babase.UIScale.MEDIUM else 1.0), + bg_color=bg_color) + + + self._cancel_button = bui.buttonwidget( + parent=self.root_widget, + position=(25, self._height - 40), + size=(50, 50), + scale=0.58, + label='', + color=bg_color, + on_activate_call=self._on_cancel_press, + autoselect=True, + icon=bui.gettexture('crossOut'), + iconscale=1.2) + + + + bui.imagewidget(parent=self.root_widget, + position=(180, self._height - 55), + size=(32 * s, 32 * s), + texture=bui.gettexture("discordLogo"), + color=(10 - 0.32, 10 - 0.39, 10 - 0.96)) + + + + self.email_widget = bui.textwidget(parent=self.root_widget, + text="Email/Phone Number", + size=(400, 70), + position=(50, 180), + h_align='left', + v_align='center', + editable=True, + scale=0.8, + autoselect=True, + maxwidth=220) + + + self.password_widget = bui.textwidget(parent=self.root_widget, + text="Password", + size=(400, 70), + position=(50, 120), + h_align='left', + v_align='center', + editable=True, + scale=0.8, + autoselect=True, + maxwidth=220) + + + bui.containerwidget(edit=self.root_widget, + cancel_button=self._cancel_button) + + bui.textwidget( + parent=self.root_widget, + position=(265, self._height - 37), + size=(0, 0), + h_align='center', + v_align='center', + scale=1.0, + text="Discord", + maxwidth=200, + color=(0.80, 0.80, 0.80)) + + bui.textwidget( + parent=self.root_widget, + position=(265, self._height - 78), + size=(0, 0), + h_align='center', + v_align='center', + scale=1.0, + text="💀Use at your own risk💀\n ⚠️discord account might get terminated⚠️", + maxwidth=200, + color=(1.00, 0.15, 0.15)) + + + self._login_button = bui.buttonwidget( + parent=self.root_widget, + position=(120, 65), + size=(400, 80), + scale=0.58, + label=log_txt, + color=log_btn_colour, + on_activate_call=self.login, + autoselect=True) + + def _on_cancel_press(self) -> None: + self._transition_out() + + def _transition_out(self) -> None: + if not self._transitioning_out: + self._transitioning_out = True + bui.containerwidget(edit=self.root_widget, transition='out_scale') + + def on_bascenev1libup_cancel(self) -> None: + bui.getsound('swish').play() + self._transition_out() + + def login(self): + if not self.path.exists(): + json_data = { + 'login': bui.textwidget(query=self.email_widget), + 'password': bui.textwidget(query=self.password_widget), + 'undelete': False, + 'captcha_key': None, + 'login_source': None, + 'gift_code_sku_id': None, + } + headers = { + 'user-agent': "Mozilla/5.0", + 'content-type': "application/json", + } + + conn = http.client.HTTPSConnection("discord.com") + + payload = json.dumps(json_data) + # conn.request("POST", "/api/v9/auth/login", payload, headers) + # res = conn.getresponse().read() + + try: + conn.request("POST", "/api/v9/auth/login", payload, headers) + res = conn.getresponse().read() + token = json.loads(res)['token'].encode().hex().encode() + with open(self.path, 'wb') as f: + f.write(token) + bui.screenmessage("Successfully logged in", (0.21, 1.0, 0.20)) + bui.getsound('shieldUp').play() + self.on_bascenev1libup_cancel() + except: + bui.screenmessage("Incorrect credentials", (1.00, 0.15, 0.15)) + bui.getsound('error').play() + + conn.close() + else: + remove(self.path) + bui.getsound('shieldDown').play() + bui.screenmessage("Account successfully removed!!", (0.10, 0.10, 1.00)) + self.on_bascenev1libup_cancel() + ws.close() + + +run_once = False +def get_once_asset(): + global run_once + if run_once: + return + response = Request( + "https://discordapp.com/api/oauth2/applications/963434684669382696/assets", + headers={"User-Agent": "Mozilla/5.0"}, + ) + try: + with urlopen(response) as assets: + assets = json.loads(assets.read()) + asset = [] + asset_id = [] + for x in assets: + dem = x["name"] + don = x["id"] + asset_id.append(don) + asset.append(dem) + asset_id_dict = dict(zip(asset, asset_id)) + + with open(DIRPATH, "w") as imagesets: + jsonfile = json.dumps(asset_id_dict) + json.dump(asset_id_dict, imagesets, indent=4) + except: + pass + run_once = True + +def get_class(): + if ANDROID: + return PresenceUpdate() + elif not ANDROID: + return RpcThread() + + +# ba_meta export babase.Plugin +class DiscordRP(babase.Plugin): + def __init__(self) -> None: + self.update_timer: bs.Timer | None = None + self.rpc_thread = get_class() + self._last_server_info: str | None = None + + if not ANDROID: + _run_overrides() + get_once_asset() + + def on_app_running(self) -> None: + if not ANDROID: + self.rpc_thread.start() + self.update_timer = bs.AppTimer( + 1, bs.WeakCall(self.update_status), repeat=True + ) + if ANDROID: + self.update_timer = bs.AppTimer( + 4, bs.WeakCall(self.update_status), repeat=True + ) + + def has_settings_ui(self): + return True + + def show_settings_ui(self, button): + if not ANDROID: + bui.screenmessage("Nothing here achievement!!!", (0.26, 0.65, 0.94)) + bui.getsound('achievement').play() + if ANDROID: + Discordlogin() + + def on_app_shutdown(self) -> None: + if not ANDROID and self.rpc_thread.is_discord_running(): + self.rpc_thread.rpc.close() + self.rpc_thread.should_close = True + else: + raise NotImplementedError("This function does not work on android") + # stupid code + # ws.close() + + # def on_app_pause(self) -> None: + # ws.close() + + # def on_app_resume(self) -> None: + # if Path(f"{getcwd()}/token.txt").exists(): + # threading.Thread(target=ws.run_forever, daemon=True, name="websocket").start() + + + + def _get_current_activity_name(self) -> str | None: + act = bs.get_foreground_host_activity() + if isinstance(act, bs.GameActivity): + return act.name + + this = "Lobby" + name: str | None = ( + act.__class__.__name__.replace("Activity", "") + .replace("ScoreScreen", "Ranking") + .replace("Coop", "") + .replace("MultiTeam", "") + .replace("Victory", "") + .replace("EndSession", "") + .replace("Transition", "") + .replace("Draw", "") + .replace("FreeForAll", "") + .replace("Join", this) + .replace("Team", "") + .replace("Series", "") + .replace("CustomSession", "Custom Session(mod)") + ) + + if name == "MainMenu": + name = "Main Menu" + if name == this: + self.rpc_thread.large_image_key = "lobby" + self.rpc_thread.large_image_text = "Bombing up" + #self.rpc_thread.small_image_key = "lobbysmall" + if name == "Ranking": + self.rpc_thread.large_image_key = "ranking" + self.rpc_thread.large_image_text = "Viewing Results" + return name + + def _get_current_map_name(self) -> Tuple[str | None, str | None]: + act = bs.get_foreground_host_activity() + if isinstance(act, bs.GameActivity): + texname = act.map.get_preview_texture_name() + if texname: + return act.map.name, texname.lower().removesuffix("preview") + return None, None + + def update_status(self) -> None: + roster = bs.get_game_roster() + connection_info = bs.get_connection_to_host_info() + + self.rpc_thread.large_image_key = "bombsquadicon" + self.rpc_thread.large_image_text = "BombSquad" + self.rpc_thread.small_image_key = _babase.app.classic.platform + self.rpc_thread.small_image_text = ( + f"{_babase.app.classic.platform.capitalize()}({_babase.app.version})" + ) + connection_info = bs.get_connection_to_host_info() + if not ANDROID: + svinfo = str(connection_info) + if self._last_server_info != svinfo: + self._last_server_info = svinfo + self.rpc_thread.party_id = str(uuid.uuid4()) + self.rpc_thread._update_secret() + if connection_info != {}: + servername = connection_info["name"] + self.rpc_thread.details = "Online" + self.rpc_thread.party_size = max( + 1, sum(len(client["players"]) for client in roster) + ) + self.rpc_thread.party_max = max(8, self.rpc_thread.party_size) + if len(servername) == 19 and "Private Party" in servername: + self.rpc_thread.state = "Private Party" + elif servername == "": # A local game joinable from the internet + try: + offlinename = json.loads(bs.get_game_roster()[0]["spec_string"])[ + "n" + ] + if len(offlinename) > 19: # Thanks Rikko + self.rpc_thread.state = offlinename[slice(19)] + "..." + else: + self.rpc_thread.state = offlinename + except IndexError: + pass + else: + if len(servername) > 19: + self.rpc_thread.state = servername[slice(19)] + ".." + else: + self.rpc_thread.state = servername[slice(19)] + + if connection_info == {}: + self.rpc_thread.details = "Local" #! replace with something like ballistica github cause + self.rpc_thread.state = self._get_current_activity_name() + self.rpc_thread.party_size = max(1, len(roster)) + self.rpc_thread.party_max = max(1, bs.get_public_party_max_size()) + + if ( + bs.get_foreground_host_session() is not None + and self.rpc_thread.details == "Local" + ): + session = ( + bs.get_foreground_host_session() + .__class__.__name__.replace("MainMenuSession", "") + .replace("EndSession", "") + .replace("FreeForAllSession", ": FFA") #! for session use small image key + .replace("DualTeamSession", ": Teams") + .replace("CoopSession", ": Coop") + ) + #! self.rpc_thread.small_image_key = session.lower() + self.rpc_thread.details = f"{self.rpc_thread.details} {session}" + if ( + self.rpc_thread.state == "NoneType" + ): # sometimes the game just breaks which means its not really watching replay FIXME + self.rpc_thread.state = "Watching Replay" + self.rpc_thread.large_image_key = "replay" + self.rpc_thread.large_image_text = "Viewing Awesomeness" + #!self.rpc_thread.small_image_key = "replaysmall" + + act = bs.get_foreground_host_activity() + session = bs.get_foreground_host_session() + if act: + from bascenev1lib.game.elimination import EliminationGame + from bascenev1lib.game.thelaststand import TheLastStandGame + from bascenev1lib.game.meteorshower import MeteorShowerGame + + # noinspection PyUnresolvedReferences,PyProtectedMember + try: + self.rpc_thread.start_timestamp = act._discordrp_start_time # type: ignore + except AttributeError: + # This can be the case if plugin launched AFTER activity + # has been created; in that case let's assume it was + # created just now. + self.rpc_thread.start_timestamp = act._discordrp_start_time = time.mktime( # type: ignore + time.localtime() + ) + if isinstance(act, EliminationGame): + alive_count = len([p for p in act.players if p.lives > 0]) + self.rpc_thread.details += f" ({alive_count} players left)" + elif isinstance(act, TheLastStandGame): + # noinspection PyProtectedMember + points = act._score + self.rpc_thread.details += f" ({points} points)" + elif isinstance(act, MeteorShowerGame): + with bs.ContextRef(act): + sec = bs.time() - act._timer.getstarttime() + secfmt = "" + if sec < 60: + secfmt = f"{sec:.2f}" + else: + secfmt = f"{int(sec) // 60:02}:{sec:.2f}" + self.rpc_thread.details += f" ({secfmt})" + + # if isinstance(session, ba.DualTeamSession): + # scores = ':'.join([ + # str(t.customdata['score']) + # for t in session.sessionteams + # ]) + # self.rpc_thread.details += f' ({scores})' + + mapname, short_map_name = self._get_current_map_name() + if mapname: + with open(DIRPATH, 'r') as asset_dict: + asset_keys = json.load(asset_dict).keys() + if short_map_name in asset_keys: + self.rpc_thread.large_image_text = mapname + self.rpc_thread.large_image_key = short_map_name + self.rpc_thread.small_image_key = 'bombsquadlogo2' + self.rpc_thread.small_image_text = 'BombSquad' + + if _babase.get_idle_time() / (1000 * 60) % 60 >= 0.4: + self.rpc_thread.details = f"AFK in {self.rpc_thread.details}" + if not ANDROID: + self.rpc_thread.large_image_key = ( + "https://media.tenor.com/uAqNn6fv7x4AAAAM/bombsquad-spaz.gif" + ) + if ANDROID and Path(f"{getcwd()}/token.txt").exists(): + self.rpc_thread.presence() + \ No newline at end of file From 250bc1f84f89394552f38c1168661533aac1be65 Mon Sep 17 00:00:00 2001 From: brostos <67740566+brostosjoined@users.noreply.github.com> Date: Fri, 21 Jul 2023 11:48:51 +0300 Subject: [PATCH 0572/1464] Update discord_richpresence.py --- plugins/utilities/discord_richpresence.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/plugins/utilities/discord_richpresence.py b/plugins/utilities/discord_richpresence.py index 7ea0615c..21002557 100644 --- a/plugins/utilities/discord_richpresence.py +++ b/plugins/utilities/discord_richpresence.py @@ -730,10 +730,10 @@ def on_app_shutdown(self) -> None: if not ANDROID and self.rpc_thread.is_discord_running(): self.rpc_thread.rpc.close() self.rpc_thread.should_close = True - else: - raise NotImplementedError("This function does not work on android") - # stupid code - # ws.close() + # else: + # raise NotImplementedError("This function does not work on android") + # # stupid code + # # ws.close() # def on_app_pause(self) -> None: # ws.close() @@ -915,4 +915,4 @@ def update_status(self) -> None: ) if ANDROID and Path(f"{getcwd()}/token.txt").exists(): self.rpc_thread.presence() - \ No newline at end of file + From 0af7b4a66e2910a3ece24e02ffae34be1633924d Mon Sep 17 00:00:00 2001 From: brostos <67740566+brostosjoined@users.noreply.github.com> Date: Fri, 21 Jul 2023 11:51:05 +0300 Subject: [PATCH 0573/1464] Update utilities.json --- plugins/utilities.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/plugins/utilities.json b/plugins/utilities.json index 08ee3bdb..fe629cda 100644 --- a/plugins/utilities.json +++ b/plugins/utilities.json @@ -767,7 +767,7 @@ } ], "versions": { - "1.0.0": { + "1.1.0": { "api_version": 8, "commit_sha": "230d12d", "released_on": "18-07-2023", @@ -776,4 +776,4 @@ } } } -} \ No newline at end of file +} From e17dccdaa98e925c8d0d492912325377b14c6f57 Mon Sep 17 00:00:00 2001 From: brostos <67740566+brostosjoined@users.noreply.github.com> Date: Fri, 21 Jul 2023 11:56:12 +0300 Subject: [PATCH 0574/1464] Update utilities.json --- plugins/utilities.json | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/plugins/utilities.json b/plugins/utilities.json index fe629cda..5d788034 100644 --- a/plugins/utilities.json +++ b/plugins/utilities.json @@ -767,13 +767,16 @@ } ], "versions": { - "1.1.0": { + "1.0.0": { "api_version": 8, "commit_sha": "230d12d", "released_on": "18-07-2023", "md5sum": "5fa8706f36d618f8302551dd2a0403a0" - } + }, + "versions": { + "1.1.0": null } } } } + From 97885d7952ba7f233ca27c3bc1973ac532f485c1 Mon Sep 17 00:00:00 2001 From: brostosjoined Date: Fri, 21 Jul 2023 09:03:10 +0000 Subject: [PATCH 0575/1464] [ci] auto-format --- plugins/utilities/discord_richpresence.py | 127 ++++++++++------------ 1 file changed, 57 insertions(+), 70 deletions(-) diff --git a/plugins/utilities/discord_richpresence.py b/plugins/utilities/discord_richpresence.py index 21002557..9b91f39b 100644 --- a/plugins/utilities/discord_richpresence.py +++ b/plugins/utilities/discord_richpresence.py @@ -24,7 +24,7 @@ import shutil import babase import _babase -import bascenev1 as bs +import bascenev1 as bs import bascenev1lib import bauiv1 as bui @@ -226,7 +226,7 @@ def get_module(): remove(path) except: pass - + # Make modifications for it to work on windows if babase.app.classic.platform == "windows": with open(Path(f"{getcwd()}/ba_data/python/pypresence/utils.py"), "r") as file: @@ -250,24 +250,23 @@ def get_event_loop(force_fresh=False): return running else: return loop""" - + with open(Path(f"{getcwd()}/ba_data/python/pypresence/utils.py"), "w") as file: for number, line in enumerate(data): - if number not in range(46,56): + if number not in range(46, 56): file.write(line) get_module() - from pypresence import PipeClosed, DiscordError, DiscordNotFound from pypresence.utils import get_event_loop - import pypresence + import pypresence import socket - + DEBUG = True - + _last_server_addr = 'localhost' _last_server_port = 43210 - + def print_error(err: str, include_exception: bool = False) -> None: if DEBUG: if include_exception: @@ -298,8 +297,8 @@ def new_connect(*args, **kwargs) -> None: # type: ignore old_connect(*args, **kwargs) c = kwargs.get("address") or args[0] _last_server_port = kwargs.get("port") or args[1] - - bs.connect_to_party = new_connect + + bs.connect_to_party = new_connect start_time = time.time() @@ -322,10 +321,10 @@ def __init__(self): self._last_secret_update_time: float = 0 self._last_connect_time: float = 0 self.should_close = False - - @staticmethod + + @staticmethod def is_discord_running(): - for i in range(6463,6473): + for i in range(6463, 6473): s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) s.settimeout(0.01) try: @@ -333,11 +332,11 @@ def is_discord_running(): s.close() if (conn == 0): s.close() - return(True) + return (True) except: s.close() - return(False) - + return (False) + def _generate_join_secret(self): # resp = requests.get('https://legacy.ballistica.net/bsAccessCheck').text connection_info = bs.get_connection_to_host_info() @@ -394,7 +393,7 @@ def _subscribe_events(self): self._subscribe("ACTIVITY_JOIN") self._subscribe("ACTIVITY_JOIN_REQUEST") - # def _update_presence(self) -> None: + # def _update_presence(self) -> None: # self._last_update_time = time.time() # try: # self._do_update_presence() @@ -403,7 +402,6 @@ def _subscribe_events(self): # self._reconnect() # except Exception: # print_error("failed to update presence", include_exception= True) - def _reconnect(self) -> None: self.rpc.connect() @@ -480,7 +478,7 @@ def handle_event(self, data): def _connect_to_party(self, hostname, port) -> None: babase.pushcall( babase.Call(bs.connect_to_party, hostname, port), from_other_thread=True - ) + ) def on_join_request(self, username, uid, discriminator, avatar) -> None: del uid # unused @@ -508,10 +506,7 @@ def __init__(self): self.path = Path(f"{getcwd()}/token.txt") bg_color = (0.5, 0.4, 0.6) log_btn_colour = (0.10, 0.95, 0.10) if not self.path.exists() else (1.00, 0.15, 0.15) - log_txt = "LOG IN" if not self.path.exists() else "LOG OUT" - - - + log_txt = "LOG IN" if not self.path.exists() else "LOG OUT" # creates our _root_widget PopupWindow.__init__(self, @@ -520,7 +515,6 @@ def __init__(self): scale=(2.1 if _uiscale is babase.UIScale.SMALL else 1.5 if _uiscale is babase.UIScale.MEDIUM else 1.0), bg_color=bg_color) - self._cancel_button = bui.buttonwidget( parent=self.root_widget, @@ -533,44 +527,38 @@ def __init__(self): autoselect=True, icon=bui.gettexture('crossOut'), iconscale=1.2) - - - + bui.imagewidget(parent=self.root_widget, - position=(180, self._height - 55), - size=(32 * s, 32 * s), - texture=bui.gettexture("discordLogo"), - color=(10 - 0.32, 10 - 0.39, 10 - 0.96)) - + position=(180, self._height - 55), + size=(32 * s, 32 * s), + texture=bui.gettexture("discordLogo"), + color=(10 - 0.32, 10 - 0.39, 10 - 0.96)) - self.email_widget = bui.textwidget(parent=self.root_widget, - text="Email/Phone Number", - size=(400, 70), - position=(50, 180), - h_align='left', - v_align='center', - editable=True, - scale=0.8, - autoselect=True, - maxwidth=220) - - + text="Email/Phone Number", + size=(400, 70), + position=(50, 180), + h_align='left', + v_align='center', + editable=True, + scale=0.8, + autoselect=True, + maxwidth=220) + self.password_widget = bui.textwidget(parent=self.root_widget, - text="Password", - size=(400, 70), - position=(50, 120), - h_align='left', - v_align='center', - editable=True, - scale=0.8, - autoselect=True, - maxwidth=220) - - + text="Password", + size=(400, 70), + position=(50, 120), + h_align='left', + v_align='center', + editable=True, + scale=0.8, + autoselect=True, + maxwidth=220) + bui.containerwidget(edit=self.root_widget, - cancel_button=self._cancel_button) - + cancel_button=self._cancel_button) + bui.textwidget( parent=self.root_widget, position=(265, self._height - 37), @@ -581,7 +569,7 @@ def __init__(self): text="Discord", maxwidth=200, color=(0.80, 0.80, 0.80)) - + bui.textwidget( parent=self.root_widget, position=(265, self._height - 78), @@ -592,8 +580,7 @@ def __init__(self): text="💀Use at your own risk💀\n ⚠️discord account might get terminated⚠️", maxwidth=200, color=(1.00, 0.15, 0.15)) - - + self._login_button = bui.buttonwidget( parent=self.root_widget, position=(120, 65), @@ -658,8 +645,10 @@ def login(self): self.on_bascenev1libup_cancel() ws.close() - + run_once = False + + def get_once_asset(): global run_once if run_once: @@ -687,6 +676,7 @@ def get_once_asset(): pass run_once = True + def get_class(): if ANDROID: return PresenceUpdate() @@ -707,7 +697,7 @@ def __init__(self) -> None: def on_app_running(self) -> None: if not ANDROID: - self.rpc_thread.start() + self.rpc_thread.start() self.update_timer = bs.AppTimer( 1, bs.WeakCall(self.update_status), repeat=True ) @@ -742,13 +732,11 @@ def on_app_shutdown(self) -> None: # if Path(f"{getcwd()}/token.txt").exists(): # threading.Thread(target=ws.run_forever, daemon=True, name="websocket").start() - - def _get_current_activity_name(self) -> str | None: act = bs.get_foreground_host_activity() if isinstance(act, bs.GameActivity): return act.name - + this = "Lobby" name: str | None = ( act.__class__.__name__.replace("Activity", "") @@ -816,7 +804,7 @@ def update_status(self) -> None: offlinename = json.loads(bs.get_game_roster()[0]["spec_string"])[ "n" ] - if len(offlinename) > 19: # Thanks Rikko + if len(offlinename) > 19: # Thanks Rikko self.rpc_thread.state = offlinename[slice(19)] + "..." else: self.rpc_thread.state = offlinename @@ -829,7 +817,7 @@ def update_status(self) -> None: self.rpc_thread.state = servername[slice(19)] if connection_info == {}: - self.rpc_thread.details = "Local" #! replace with something like ballistica github cause + self.rpc_thread.details = "Local" # ! replace with something like ballistica github cause self.rpc_thread.state = self._get_current_activity_name() self.rpc_thread.party_size = max(1, len(roster)) self.rpc_thread.party_max = max(1, bs.get_public_party_max_size()) @@ -842,7 +830,7 @@ def update_status(self) -> None: bs.get_foreground_host_session() .__class__.__name__.replace("MainMenuSession", "") .replace("EndSession", "") - .replace("FreeForAllSession", ": FFA") #! for session use small image key + .replace("FreeForAllSession", ": FFA") # ! for session use small image key .replace("DualTeamSession", ": Teams") .replace("CoopSession", ": Coop") ) @@ -915,4 +903,3 @@ def update_status(self) -> None: ) if ANDROID and Path(f"{getcwd()}/token.txt").exists(): self.rpc_thread.presence() - From 4e926ae16859e792e88719c33de4fd5fbe9dc7e4 Mon Sep 17 00:00:00 2001 From: brostos <67740566+brostosjoined@users.noreply.github.com> Date: Fri, 21 Jul 2023 12:05:57 +0300 Subject: [PATCH 0576/1464] Update utilities.json --- plugins/utilities.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/utilities.json b/plugins/utilities.json index 5d788034..5a02b39e 100644 --- a/plugins/utilities.json +++ b/plugins/utilities.json @@ -776,7 +776,7 @@ "versions": { "1.1.0": null } - } + }, } } From 05f20a04a3f44b926f8b495a2a57151ad3c518f6 Mon Sep 17 00:00:00 2001 From: brostos <67740566+brostosjoined@users.noreply.github.com> Date: Fri, 21 Jul 2023 12:09:56 +0300 Subject: [PATCH 0577/1464] Update utilities.json --- plugins/utilities.json | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/plugins/utilities.json b/plugins/utilities.json index 5a02b39e..33a143b6 100644 --- a/plugins/utilities.json +++ b/plugins/utilities.json @@ -767,16 +767,16 @@ } ], "versions": { + "versions": { + "1.1.0": null, "1.0.0": { "api_version": 8, "commit_sha": "230d12d", "released_on": "18-07-2023", "md5sum": "5fa8706f36d618f8302551dd2a0403a0" - }, - "versions": { - "1.1.0": null + } } - }, + } } } From e20efd8541ad152d42f385b0b3f6729a6bf14792 Mon Sep 17 00:00:00 2001 From: brostos <67740566+brostosjoined@users.noreply.github.com> Date: Fri, 21 Jul 2023 12:16:14 +0300 Subject: [PATCH 0578/1464] work --- plugins/utilities.json | 1 - 1 file changed, 1 deletion(-) diff --git a/plugins/utilities.json b/plugins/utilities.json index 33a143b6..6aca9fe1 100644 --- a/plugins/utilities.json +++ b/plugins/utilities.json @@ -767,7 +767,6 @@ } ], "versions": { - "versions": { "1.1.0": null, "1.0.0": { "api_version": 8, From 81abddff28e21a548fb60a40f6a4d9c4dd78324e Mon Sep 17 00:00:00 2001 From: brostosjoined Date: Fri, 21 Jul 2023 09:16:48 +0000 Subject: [PATCH 0579/1464] [ci] apply-version-metadata --- plugins/utilities.json | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/plugins/utilities.json b/plugins/utilities.json index 6aca9fe1..4d436984 100644 --- a/plugins/utilities.json +++ b/plugins/utilities.json @@ -767,7 +767,12 @@ } ], "versions": { - "1.1.0": null, + "1.1.0": { + "api_version": 8, + "commit_sha": "e20efd8", + "released_on": "21-07-2023", + "md5sum": "f0dda27fcd396b4d3e8b35ca0ec5d251" + }, "1.0.0": { "api_version": 8, "commit_sha": "230d12d", @@ -777,5 +782,4 @@ } } } -} - +} \ No newline at end of file From 3c83efcc0559edf26ee984a0837daa75cc6ddf28 Mon Sep 17 00:00:00 2001 From: brostos <67740566+brostosjoined@users.noreply.github.com> Date: Fri, 21 Jul 2023 23:56:30 +0300 Subject: [PATCH 0580/1464] Update discord_richpresence.py --- plugins/utilities/discord_richpresence.py | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/plugins/utilities/discord_richpresence.py b/plugins/utilities/discord_richpresence.py index 9b91f39b..1e1d8850 100644 --- a/plugins/utilities/discord_richpresence.py +++ b/plugins/utilities/discord_richpresence.py @@ -227,11 +227,11 @@ def get_module(): except: pass - # Make modifications for it to work on windows - if babase.app.classic.platform == "windows": - with open(Path(f"{getcwd()}/ba_data/python/pypresence/utils.py"), "r") as file: - data = file.readlines() - data[45] = """ + # Make modifications for it to work on windows + if babase.app.classic.platform == "windows": + with open(Path(f"{getcwd()}/ba_data/python/pypresence/utils.py"), "r") as file: + data = file.readlines() + data[45] = """ def get_event_loop(force_fresh=False): loop = asyncio.ProactorEventLoop() if sys.platform == 'win32' else asyncio.new_event_loop() if force_fresh: @@ -250,11 +250,11 @@ def get_event_loop(force_fresh=False): return running else: return loop""" - - with open(Path(f"{getcwd()}/ba_data/python/pypresence/utils.py"), "w") as file: - for number, line in enumerate(data): - if number not in range(46, 56): - file.write(line) + + with open(Path(f"{getcwd()}/ba_data/python/pypresence/utils.py"), "w") as file: + for number, line in enumerate(data): + if number not in range(46, 56): + file.write(line) get_module() from pypresence import PipeClosed, DiscordError, DiscordNotFound From 16b9b546d9b82cb85cf54528acae555ddccda174 Mon Sep 17 00:00:00 2001 From: brostosjoined Date: Fri, 21 Jul 2023 20:57:04 +0000 Subject: [PATCH 0581/1464] [ci] auto-format --- plugins/utilities/discord_richpresence.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/utilities/discord_richpresence.py b/plugins/utilities/discord_richpresence.py index 1e1d8850..9b0ea84a 100644 --- a/plugins/utilities/discord_richpresence.py +++ b/plugins/utilities/discord_richpresence.py @@ -250,7 +250,7 @@ def get_event_loop(force_fresh=False): return running else: return loop""" - + with open(Path(f"{getcwd()}/ba_data/python/pypresence/utils.py"), "w") as file: for number, line in enumerate(data): if number not in range(46, 56): From 8f02db1e34bd38d0afa8423777243694340f8366 Mon Sep 17 00:00:00 2001 From: brostos <67740566+brostosjoined@users.noreply.github.com> Date: Fri, 21 Jul 2023 23:57:20 +0300 Subject: [PATCH 0582/1464] Update utilities.json --- plugins/utilities.json | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/plugins/utilities.json b/plugins/utilities.json index 4d436984..95557ec7 100644 --- a/plugins/utilities.json +++ b/plugins/utilities.json @@ -767,12 +767,7 @@ } ], "versions": { - "1.1.0": { - "api_version": 8, - "commit_sha": "e20efd8", - "released_on": "21-07-2023", - "md5sum": "f0dda27fcd396b4d3e8b35ca0ec5d251" - }, + "1.1.0": null, "1.0.0": { "api_version": 8, "commit_sha": "230d12d", @@ -782,4 +777,4 @@ } } } -} \ No newline at end of file +} From c4916e82d38bb4aec4d785854e42e4a0f05b86c5 Mon Sep 17 00:00:00 2001 From: brostosjoined Date: Fri, 21 Jul 2023 20:57:46 +0000 Subject: [PATCH 0583/1464] [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 95557ec7..5142fd43 100644 --- a/plugins/utilities.json +++ b/plugins/utilities.json @@ -767,7 +767,12 @@ } ], "versions": { - "1.1.0": null, + "1.1.0": { + "api_version": 8, + "commit_sha": "8f02db1", + "released_on": "21-07-2023", + "md5sum": "402a406cab00e6fc6687738d237aeda6" + }, "1.0.0": { "api_version": 8, "commit_sha": "230d12d", @@ -777,4 +782,4 @@ } } } -} +} \ No newline at end of file From 5bfc25cc35fed46727ec22ef75fb6c936e47dc56 Mon Sep 17 00:00:00 2001 From: brostos <67740566+brostosjoined@users.noreply.github.com> Date: Sat, 22 Jul 2023 03:54:00 +0300 Subject: [PATCH 0584/1464] Delete discord_richpresence.py --- plugins/utilities/discord_richpresence.py | 905 ---------------------- 1 file changed, 905 deletions(-) delete mode 100644 plugins/utilities/discord_richpresence.py diff --git a/plugins/utilities/discord_richpresence.py b/plugins/utilities/discord_richpresence.py deleted file mode 100644 index 9b0ea84a..00000000 --- a/plugins/utilities/discord_richpresence.py +++ /dev/null @@ -1,905 +0,0 @@ -# Released under the MIT and Apache License. See LICENSE for details. -# -"""placeholder :clown:""" - -# ba_meta require api 8 -#!"Made to you by @brostos & @Dliwk" - - -from __future__ import annotations -from urllib.request import Request, urlopen, urlretrieve -from pathlib import Path -from os import getcwd, remove -from zipfile import ZipFile -from bauiv1lib.popup import PopupWindow -from babase._mgen.enums import TimeType - -import asyncio -import http.client -import ast -import uuid -import json -import time -import threading -import shutil -import babase -import _babase -import bascenev1 as bs -import bascenev1lib -import bauiv1 as bui - -from typing import TYPE_CHECKING - -if TYPE_CHECKING: - from typing import Any, Tuple - - -ANDROID = babase.app.classic.platform == "android" -DIRPATH = Path(f"{_babase.app.python_directory_user}/image_id.json") - -if ANDROID: # !can add ios in future - - # Installing websocket - def get_module(): - install_path = Path(f"{getcwd()}/ba_data/python") # For the guys like me on windows - path = Path(f"{install_path}/websocket.zip") - file_path = Path(f"{install_path}/websocket") - source_dir = Path(f"{install_path}/websocket-client-1.6.1/websocket") - if not file_path.exists(): - url = "https://github.com/websocket-client/websocket-client/archive/refs/tags/v1.6.1.zip" - try: - filename, headers = urlretrieve(url, filename=path) - with ZipFile(filename) as f: - f.extractall(install_path) - shutil.copytree(source_dir, file_path) - shutil.rmtree(Path(f"{install_path}/websocket-client-1.6.1")) - remove(path) - except Exception as e: - if type(e) == shutil.Error: - shutil.rmtree(Path(f"{install_path}/websocket-client-1.6.1")) - else: - pass - get_module() - - import websocket - - heartbeat_interval = int(41250) - resume_gateway_url: str | None = None - session_id: str | None = None - - start_time = time.time() - - class PresenceUpdate: - def __init__(self): - self.state: str | None = "In Game" - self.details: str | None = "Main Menu" - self.start_timestamp = time.time() - self.large_image_key: str | None = "bombsquadicon" - self.large_image_text: str | None = "BombSquad Icon" - self.small_image_key: str | None = None - self.small_image_text: str | None = ( - f"{_babase.app.classic.platform.capitalize()}({_babase.app.version})") - self.media_proxy = "mp:/app-assets/963434684669382696/{}.png" - self.identify: bool = False - self.party_id: str = str(uuid.uuid4()) - self.party_size = 1 - self.party_max = 8 - - def presence(self): - with open(DIRPATH, "r") as maptxt: - largetxt = json.load(maptxt)[self.large_image_key] - with open(DIRPATH, "r") as maptxt: - smalltxt = json.load(maptxt)[self.small_image_key] - - presencepayload = { - "op": 3, - "d": { - "since": None, # used to show how long the user went idle will add afk to work with this and then set the status to idle - "status": "online", - "afk": "false", - "activities": [ - { - "name": "BombSquad", - "type": 0, - "application_id": "963434684669382696", - "state": self.state, - "details": self.details, - "timestamps": { - "start": start_time - }, - "party": { - "id": self.party_id, - "size": [self.party_size, self.party_max] - }, - "assets": { - "large_image": self.media_proxy.format(largetxt), - "large_text": self.large_image_text, - "small_image": self.media_proxy.format(smalltxt), - "small_text": self.small_image_text, - }, - "client_info": { - "version": 0, - "os": "android", - "client": "mobile", - }, - "buttons": ["Discord Server", "Download BombSquad"], - "metadata": { - "button_urls": [ - "https://discord.gg/bombsquad-ballistica-official-1001896771347304639", - "https://bombsquad-community.web.app/download", - ] - }, - } - ], - }, - } - ws.send(json.dumps(presencepayload)) - - def on_message(ws, message): - global heartbeat_interval, resume_gateway_url, session_id - message = json.loads(message) - try: - heartbeat_interval = message["d"]["heartbeat_interval"] - except: - pass - try: - resume_gateway_url = message["d"]["resume_gateway_url"] - session_id = message["d"]["session_id"] - except: - pass - - def on_error(ws, error): - babase.print_exception(error) - - def on_close(ws, close_status_code, close_msg): - # print("### closed ###") - pass - - def on_open(ws): - print("Connected to Discord Websocket") - - def heartbeats(): - """Sending heartbeats to keep the connection alive""" - global heartbeat_interval - if babase.do_once(): - heartbeat_payload = { - "op": 1, - "d": 251, - } # step two keeping connection alive by sending heart beats and receiving opcode 11 - ws.send(json.dumps(heartbeat_payload)) - - def identify(): - """Identifying to the gateway and enable by using user token and the intents we will be using e.g 256->For Presence""" - with open(f"{getcwd()}/token.txt", 'r') as f: - token = bytes.fromhex(f.read()).decode('utf-8') - identify_payload = { - "op": 2, - "d": { - "token": token, - "properties": { - "os": "linux", - "browser": "Discord Android", - "device": "android", - }, - "intents": 256, - }, - } # step 3 send an identify - ws.send(json.dumps(identify_payload)) - identify() - while True: - heartbeat_payload = {"op": 1, "d": heartbeat_interval} - try: - ws.send(json.dumps(heartbeat_payload)) - time.sleep(heartbeat_interval / 1000) - except: - pass - - threading.Thread(target=heartbeats, daemon=True, name="heartbeat").start() - - # websocket.enableTrace(True) - ws = websocket.WebSocketApp( - "wss://gateway.discord.gg/?encoding=json&v=10", - on_open=on_open, - on_message=on_message, - on_error=on_error, - on_close=on_close, - ) - if Path(f"{getcwd()}/token.txt").exists(): - threading.Thread(target=ws.run_forever, daemon=True, name="websocket").start() - - -if not ANDROID: - # installing pypresence - def get_module(): - install_path = Path(f"{getcwd()}/ba_data/python") - path = Path(f"{install_path}/pypresence.zip") - file_path = Path(f"{install_path}/pypresence") - source_dir = Path(f"{install_path}/pypresence-4.3.0/pypresence") - if not file_path.exists(): - url = "https://github.com/qwertyquerty/pypresence/archive/refs/tags/v4.3.0.zip" - try: - filename, headers = urlretrieve(url, filename=path) - with ZipFile(filename) as f: - f.extractall(install_path) - shutil.copytree(source_dir, file_path) - shutil.rmtree(Path(f"{install_path}/pypresence-4.3.0")) - remove(path) - except: - pass - - # Make modifications for it to work on windows - if babase.app.classic.platform == "windows": - with open(Path(f"{getcwd()}/ba_data/python/pypresence/utils.py"), "r") as file: - data = file.readlines() - data[45] = """ -def get_event_loop(force_fresh=False): - loop = asyncio.ProactorEventLoop() if sys.platform == 'win32' else asyncio.new_event_loop() - if force_fresh: - return loop - try: - running = asyncio.get_running_loop() - except RuntimeError: - return loop - if running.is_closed(): - return loop - else: - if sys.platform in ('linux', 'darwin'): - return running - if sys.platform == 'win32': - if isinstance(running, asyncio.ProactorEventLoop): - return running - else: - return loop""" - - with open(Path(f"{getcwd()}/ba_data/python/pypresence/utils.py"), "w") as file: - for number, line in enumerate(data): - if number not in range(46, 56): - file.write(line) - get_module() - - from pypresence import PipeClosed, DiscordError, DiscordNotFound - from pypresence.utils import get_event_loop - import pypresence - import socket - - DEBUG = True - - _last_server_addr = 'localhost' - _last_server_port = 43210 - - def print_error(err: str, include_exception: bool = False) -> None: - if DEBUG: - if include_exception: - babase.print_exception(err) - else: - babase.print_error(err) - else: - print(f"ERROR in discordrp.py: {err}") - - def log(msg: str) -> None: - if DEBUG: - print(f"LOG in discordrp.py: {msg}") - - def _run_overrides() -> None: - old_init = bs.Activity.__init__ - - def new_init(self, *args: Any, **kwargs: Any) -> None: # type: ignore - old_init(self, *args, **kwargs) - self._discordrp_start_time = time.mktime(time.localtime()) - - bs.Activity.__init__ = new_init # type: ignore - - old_connect = bs.connect_to_party - - def new_connect(*args, **kwargs) -> None: # type: ignore - global _last_server_addr - global _last_server_port - old_connect(*args, **kwargs) - c = kwargs.get("address") or args[0] - _last_server_port = kwargs.get("port") or args[1] - - bs.connect_to_party = new_connect - - start_time = time.time() - - class RpcThread(threading.Thread): - def __init__(self): - super().__init__(name="RpcThread") - self.rpc = pypresence.Presence(963434684669382696) - self.state: str | None = "In Game" - self.details: str | None = "Main Menu" - self.start_timestamp = time.mktime(time.localtime()) - self.large_image_key: str | None = "bombsquadicon" - self.large_image_text: str | None = "BombSquad Icon" - self.small_image_key: str | None = None - self.small_image_text: str | None = None - self.party_id: str = str(uuid.uuid4()) - self.party_size = 1 - self.party_max = 8 - self.join_secret: str | None = None - self._last_update_time: float = 0 - self._last_secret_update_time: float = 0 - self._last_connect_time: float = 0 - self.should_close = False - - @staticmethod - def is_discord_running(): - for i in range(6463, 6473): - s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) - s.settimeout(0.01) - try: - conn = s.connect_ex(('localhost', i)) - s.close() - if (conn == 0): - s.close() - return (True) - except: - s.close() - return (False) - - def _generate_join_secret(self): - # resp = requests.get('https://legacy.ballistica.net/bsAccessCheck').text - connection_info = bs.get_connection_to_host_info() - if connection_info: - addr = _last_server_addr - port = _last_server_port - else: - try: - with urlopen( - "https://legacy.ballistica.net/bsAccessCheck" - ) as resp: - resp = resp.read().decode() - resp = ast.literal_eval(resp) - addr = resp["address"] - port = 43210 - secret_dict = { - "format_version": 1, - "hostname": addr, - "port": port, - } - self.join_secret = json.dumps(secret_dict) - except: - pass - - def _update_secret(self): - threading.Thread(target=self._generate_join_secret, daemon=True).start() - self._last_secret_update_time = time.time() - - def run(self) -> None: - asyncio.set_event_loop(get_event_loop()) - while not self.should_close: - if time.time() - self._last_update_time > 0.1: - self._do_update_presence() - if time.time() - self._last_secret_update_time > 15: - self._update_secret() - # if time.time() - self._last_connect_time > 120 and is_discord_running(): #!Eric please add module manager(pip) - # self._reconnect() - time.sleep(0.03) - - def _subscribe(self, event: str, **args): - self.rpc.send_data( - 1, - { - "nonce": f"{time.time():.20f}", - "cmd": "SUBSCRIBE", - "evt": event, - "args": args, - }, - ) - data = self.rpc.loop.run_until_complete(self.rpc.read_output()) - self.handle_event(data) - - def _subscribe_events(self): - self._subscribe("ACTIVITY_JOIN") - self._subscribe("ACTIVITY_JOIN_REQUEST") - - # def _update_presence(self) -> None: - # self._last_update_time = time.time() - # try: - # self._do_update_presence() - # except (AttributeError, AssertionError): - # try: - # self._reconnect() - # except Exception: - # print_error("failed to update presence", include_exception= True) - - def _reconnect(self) -> None: - self.rpc.connect() - self._subscribe_events() - self._do_update_presence() - self._last_connect_time = time.time() - - def _do_update_presence(self) -> None: - if RpcThread.is_discord_running(): - self._last_update_time = time.time() - try: - data = self.rpc.update( - state=self.state or " ", - details=self.details, - start=start_time, - large_image=self.large_image_key, - large_text=self.large_image_text, - small_image=self.small_image_key, - small_text=self.small_image_text, - party_id=self.party_id, - party_size=[self.party_size, self.party_max], - join=self.join_secret, - # buttons = [ #!cant use buttons together with join - # { - # "label": "Discord Server", - # "url": "https://ballistica.net/discord" - # }, - # { - # "label": "Download Bombsquad", - # "url": "https://bombsquad.ga/download"} - # ] - ) - - self.handle_event(data) - except (PipeClosed, DiscordError, AssertionError, AttributeError): - try: - self._reconnect() - except (DiscordNotFound, DiscordError): - pass - - def handle_event(self, data): - evt = data["evt"] - if evt is None: - return - - data = data.get("data", {}) - - if evt == "ACTIVITY_JOIN": - secret = data.get("secret") - try: - server = json.loads(secret) - format_version = server["format_version"] - except Exception: - babase.print_exception("discordrp: unknown activity join format") - else: - try: - if format_version == 1: - hostname = server["hostname"] - port = server["port"] - self._connect_to_party(hostname, port) - except Exception: - babase.print_exception( - f"discordrp: incorrect activity join data, {format_version=}" - ) - - elif evt == "ACTIVITY_JOIN_REQUEST": - user = data.get("user", {}) - uid = user.get("id") - username = user.get("username") - discriminator = user.get("discriminator", None) - avatar = user.get("avatar") - self.on_join_request(username, uid, discriminator, avatar) - - def _connect_to_party(self, hostname, port) -> None: - babase.pushcall( - babase.Call(bs.connect_to_party, hostname, port), from_other_thread=True - ) - - def on_join_request(self, username, uid, discriminator, avatar) -> None: - del uid # unused - del avatar # unused - babase.pushcall( - babase.Call( - bui.screenmessage, - "Discord: {} wants to join!".format(username), - color=(0.0, 1.0, 0.0), - ), - from_other_thread=True, - ) - babase.pushcall(lambda: bui.getsound('bellMed').play(), from_other_thread=True) - - -class Discordlogin(PopupWindow): - - def __init__(self): - # pylint: disable=too-many-locals - _uiscale = bui.app.ui_v1.uiscale - self._transitioning_out = False - s = 1.25 if _uiscale is babase.UIScale.SMALL else 1.27 if _uiscale is babase.UIScale.MEDIUM else 1.3 - self._width = 380 * s - self._height = 150 + 150 * s - self.path = Path(f"{getcwd()}/token.txt") - bg_color = (0.5, 0.4, 0.6) - log_btn_colour = (0.10, 0.95, 0.10) if not self.path.exists() else (1.00, 0.15, 0.15) - log_txt = "LOG IN" if not self.path.exists() else "LOG OUT" - - # creates our _root_widget - PopupWindow.__init__(self, - position=(0.0, 0.0), - size=(self._width, self._height), - scale=(2.1 if _uiscale is babase.UIScale.SMALL else 1.5 - if _uiscale is babase.UIScale.MEDIUM else 1.0), - bg_color=bg_color) - - self._cancel_button = bui.buttonwidget( - parent=self.root_widget, - position=(25, self._height - 40), - size=(50, 50), - scale=0.58, - label='', - color=bg_color, - on_activate_call=self._on_cancel_press, - autoselect=True, - icon=bui.gettexture('crossOut'), - iconscale=1.2) - - bui.imagewidget(parent=self.root_widget, - position=(180, self._height - 55), - size=(32 * s, 32 * s), - texture=bui.gettexture("discordLogo"), - color=(10 - 0.32, 10 - 0.39, 10 - 0.96)) - - self.email_widget = bui.textwidget(parent=self.root_widget, - text="Email/Phone Number", - size=(400, 70), - position=(50, 180), - h_align='left', - v_align='center', - editable=True, - scale=0.8, - autoselect=True, - maxwidth=220) - - self.password_widget = bui.textwidget(parent=self.root_widget, - text="Password", - size=(400, 70), - position=(50, 120), - h_align='left', - v_align='center', - editable=True, - scale=0.8, - autoselect=True, - maxwidth=220) - - bui.containerwidget(edit=self.root_widget, - cancel_button=self._cancel_button) - - bui.textwidget( - parent=self.root_widget, - position=(265, self._height - 37), - size=(0, 0), - h_align='center', - v_align='center', - scale=1.0, - text="Discord", - maxwidth=200, - color=(0.80, 0.80, 0.80)) - - bui.textwidget( - parent=self.root_widget, - position=(265, self._height - 78), - size=(0, 0), - h_align='center', - v_align='center', - scale=1.0, - text="💀Use at your own risk💀\n ⚠️discord account might get terminated⚠️", - maxwidth=200, - color=(1.00, 0.15, 0.15)) - - self._login_button = bui.buttonwidget( - parent=self.root_widget, - position=(120, 65), - size=(400, 80), - scale=0.58, - label=log_txt, - color=log_btn_colour, - on_activate_call=self.login, - autoselect=True) - - def _on_cancel_press(self) -> None: - self._transition_out() - - def _transition_out(self) -> None: - if not self._transitioning_out: - self._transitioning_out = True - bui.containerwidget(edit=self.root_widget, transition='out_scale') - - def on_bascenev1libup_cancel(self) -> None: - bui.getsound('swish').play() - self._transition_out() - - def login(self): - if not self.path.exists(): - json_data = { - 'login': bui.textwidget(query=self.email_widget), - 'password': bui.textwidget(query=self.password_widget), - 'undelete': False, - 'captcha_key': None, - 'login_source': None, - 'gift_code_sku_id': None, - } - headers = { - 'user-agent': "Mozilla/5.0", - 'content-type': "application/json", - } - - conn = http.client.HTTPSConnection("discord.com") - - payload = json.dumps(json_data) - # conn.request("POST", "/api/v9/auth/login", payload, headers) - # res = conn.getresponse().read() - - try: - conn.request("POST", "/api/v9/auth/login", payload, headers) - res = conn.getresponse().read() - token = json.loads(res)['token'].encode().hex().encode() - with open(self.path, 'wb') as f: - f.write(token) - bui.screenmessage("Successfully logged in", (0.21, 1.0, 0.20)) - bui.getsound('shieldUp').play() - self.on_bascenev1libup_cancel() - except: - bui.screenmessage("Incorrect credentials", (1.00, 0.15, 0.15)) - bui.getsound('error').play() - - conn.close() - else: - remove(self.path) - bui.getsound('shieldDown').play() - bui.screenmessage("Account successfully removed!!", (0.10, 0.10, 1.00)) - self.on_bascenev1libup_cancel() - ws.close() - - -run_once = False - - -def get_once_asset(): - global run_once - if run_once: - return - response = Request( - "https://discordapp.com/api/oauth2/applications/963434684669382696/assets", - headers={"User-Agent": "Mozilla/5.0"}, - ) - try: - with urlopen(response) as assets: - assets = json.loads(assets.read()) - asset = [] - asset_id = [] - for x in assets: - dem = x["name"] - don = x["id"] - asset_id.append(don) - asset.append(dem) - asset_id_dict = dict(zip(asset, asset_id)) - - with open(DIRPATH, "w") as imagesets: - jsonfile = json.dumps(asset_id_dict) - json.dump(asset_id_dict, imagesets, indent=4) - except: - pass - run_once = True - - -def get_class(): - if ANDROID: - return PresenceUpdate() - elif not ANDROID: - return RpcThread() - - -# ba_meta export babase.Plugin -class DiscordRP(babase.Plugin): - def __init__(self) -> None: - self.update_timer: bs.Timer | None = None - self.rpc_thread = get_class() - self._last_server_info: str | None = None - - if not ANDROID: - _run_overrides() - get_once_asset() - - def on_app_running(self) -> None: - if not ANDROID: - self.rpc_thread.start() - self.update_timer = bs.AppTimer( - 1, bs.WeakCall(self.update_status), repeat=True - ) - if ANDROID: - self.update_timer = bs.AppTimer( - 4, bs.WeakCall(self.update_status), repeat=True - ) - - def has_settings_ui(self): - return True - - def show_settings_ui(self, button): - if not ANDROID: - bui.screenmessage("Nothing here achievement!!!", (0.26, 0.65, 0.94)) - bui.getsound('achievement').play() - if ANDROID: - Discordlogin() - - def on_app_shutdown(self) -> None: - if not ANDROID and self.rpc_thread.is_discord_running(): - self.rpc_thread.rpc.close() - self.rpc_thread.should_close = True - # else: - # raise NotImplementedError("This function does not work on android") - # # stupid code - # # ws.close() - - # def on_app_pause(self) -> None: - # ws.close() - - # def on_app_resume(self) -> None: - # if Path(f"{getcwd()}/token.txt").exists(): - # threading.Thread(target=ws.run_forever, daemon=True, name="websocket").start() - - def _get_current_activity_name(self) -> str | None: - act = bs.get_foreground_host_activity() - if isinstance(act, bs.GameActivity): - return act.name - - this = "Lobby" - name: str | None = ( - act.__class__.__name__.replace("Activity", "") - .replace("ScoreScreen", "Ranking") - .replace("Coop", "") - .replace("MultiTeam", "") - .replace("Victory", "") - .replace("EndSession", "") - .replace("Transition", "") - .replace("Draw", "") - .replace("FreeForAll", "") - .replace("Join", this) - .replace("Team", "") - .replace("Series", "") - .replace("CustomSession", "Custom Session(mod)") - ) - - if name == "MainMenu": - name = "Main Menu" - if name == this: - self.rpc_thread.large_image_key = "lobby" - self.rpc_thread.large_image_text = "Bombing up" - #self.rpc_thread.small_image_key = "lobbysmall" - if name == "Ranking": - self.rpc_thread.large_image_key = "ranking" - self.rpc_thread.large_image_text = "Viewing Results" - return name - - def _get_current_map_name(self) -> Tuple[str | None, str | None]: - act = bs.get_foreground_host_activity() - if isinstance(act, bs.GameActivity): - texname = act.map.get_preview_texture_name() - if texname: - return act.map.name, texname.lower().removesuffix("preview") - return None, None - - def update_status(self) -> None: - roster = bs.get_game_roster() - connection_info = bs.get_connection_to_host_info() - - self.rpc_thread.large_image_key = "bombsquadicon" - self.rpc_thread.large_image_text = "BombSquad" - self.rpc_thread.small_image_key = _babase.app.classic.platform - self.rpc_thread.small_image_text = ( - f"{_babase.app.classic.platform.capitalize()}({_babase.app.version})" - ) - connection_info = bs.get_connection_to_host_info() - if not ANDROID: - svinfo = str(connection_info) - if self._last_server_info != svinfo: - self._last_server_info = svinfo - self.rpc_thread.party_id = str(uuid.uuid4()) - self.rpc_thread._update_secret() - if connection_info != {}: - servername = connection_info["name"] - self.rpc_thread.details = "Online" - self.rpc_thread.party_size = max( - 1, sum(len(client["players"]) for client in roster) - ) - self.rpc_thread.party_max = max(8, self.rpc_thread.party_size) - if len(servername) == 19 and "Private Party" in servername: - self.rpc_thread.state = "Private Party" - elif servername == "": # A local game joinable from the internet - try: - offlinename = json.loads(bs.get_game_roster()[0]["spec_string"])[ - "n" - ] - if len(offlinename) > 19: # Thanks Rikko - self.rpc_thread.state = offlinename[slice(19)] + "..." - else: - self.rpc_thread.state = offlinename - except IndexError: - pass - else: - if len(servername) > 19: - self.rpc_thread.state = servername[slice(19)] + ".." - else: - self.rpc_thread.state = servername[slice(19)] - - if connection_info == {}: - self.rpc_thread.details = "Local" # ! replace with something like ballistica github cause - self.rpc_thread.state = self._get_current_activity_name() - self.rpc_thread.party_size = max(1, len(roster)) - self.rpc_thread.party_max = max(1, bs.get_public_party_max_size()) - - if ( - bs.get_foreground_host_session() is not None - and self.rpc_thread.details == "Local" - ): - session = ( - bs.get_foreground_host_session() - .__class__.__name__.replace("MainMenuSession", "") - .replace("EndSession", "") - .replace("FreeForAllSession", ": FFA") # ! for session use small image key - .replace("DualTeamSession", ": Teams") - .replace("CoopSession", ": Coop") - ) - #! self.rpc_thread.small_image_key = session.lower() - self.rpc_thread.details = f"{self.rpc_thread.details} {session}" - if ( - self.rpc_thread.state == "NoneType" - ): # sometimes the game just breaks which means its not really watching replay FIXME - self.rpc_thread.state = "Watching Replay" - self.rpc_thread.large_image_key = "replay" - self.rpc_thread.large_image_text = "Viewing Awesomeness" - #!self.rpc_thread.small_image_key = "replaysmall" - - act = bs.get_foreground_host_activity() - session = bs.get_foreground_host_session() - if act: - from bascenev1lib.game.elimination import EliminationGame - from bascenev1lib.game.thelaststand import TheLastStandGame - from bascenev1lib.game.meteorshower import MeteorShowerGame - - # noinspection PyUnresolvedReferences,PyProtectedMember - try: - self.rpc_thread.start_timestamp = act._discordrp_start_time # type: ignore - except AttributeError: - # This can be the case if plugin launched AFTER activity - # has been created; in that case let's assume it was - # created just now. - self.rpc_thread.start_timestamp = act._discordrp_start_time = time.mktime( # type: ignore - time.localtime() - ) - if isinstance(act, EliminationGame): - alive_count = len([p for p in act.players if p.lives > 0]) - self.rpc_thread.details += f" ({alive_count} players left)" - elif isinstance(act, TheLastStandGame): - # noinspection PyProtectedMember - points = act._score - self.rpc_thread.details += f" ({points} points)" - elif isinstance(act, MeteorShowerGame): - with bs.ContextRef(act): - sec = bs.time() - act._timer.getstarttime() - secfmt = "" - if sec < 60: - secfmt = f"{sec:.2f}" - else: - secfmt = f"{int(sec) // 60:02}:{sec:.2f}" - self.rpc_thread.details += f" ({secfmt})" - - # if isinstance(session, ba.DualTeamSession): - # scores = ':'.join([ - # str(t.customdata['score']) - # for t in session.sessionteams - # ]) - # self.rpc_thread.details += f' ({scores})' - - mapname, short_map_name = self._get_current_map_name() - if mapname: - with open(DIRPATH, 'r') as asset_dict: - asset_keys = json.load(asset_dict).keys() - if short_map_name in asset_keys: - self.rpc_thread.large_image_text = mapname - self.rpc_thread.large_image_key = short_map_name - self.rpc_thread.small_image_key = 'bombsquadlogo2' - self.rpc_thread.small_image_text = 'BombSquad' - - if _babase.get_idle_time() / (1000 * 60) % 60 >= 0.4: - self.rpc_thread.details = f"AFK in {self.rpc_thread.details}" - if not ANDROID: - self.rpc_thread.large_image_key = ( - "https://media.tenor.com/uAqNn6fv7x4AAAAM/bombsquad-spaz.gif" - ) - if ANDROID and Path(f"{getcwd()}/token.txt").exists(): - self.rpc_thread.presence() From d9b25ea772a1396a67255678b010a0db55b30a97 Mon Sep 17 00:00:00 2001 From: brostos <67740566+brostosjoined@users.noreply.github.com> Date: Sat, 22 Jul 2023 03:54:26 +0300 Subject: [PATCH 0585/1464] Add files via upload --- plugins/utilities/discord_richpresence.py | 927 ++++++++++++++++++++++ 1 file changed, 927 insertions(+) create mode 100644 plugins/utilities/discord_richpresence.py diff --git a/plugins/utilities/discord_richpresence.py b/plugins/utilities/discord_richpresence.py new file mode 100644 index 00000000..2dee9f09 --- /dev/null +++ b/plugins/utilities/discord_richpresence.py @@ -0,0 +1,927 @@ +# Released under the MIT and Apache License. See LICENSE for details. +# +"""placeholder :clown:""" + +# ba_meta require api 8 +#!"Made to you by @brostos & @Dliwk" + + +from __future__ import annotations +from urllib.request import Request, urlopen, urlretrieve +from pathlib import Path +from os import getcwd, remove +from zipfile import ZipFile +from bauiv1lib.popup import PopupWindow +from babase._mgen.enums import TimeType + +import asyncio +import http.client +import ast +import uuid +import json +import time +import threading +import shutil +import babase +import _babase +import bascenev1 as bs +import bascenev1lib +import bauiv1 as bui + +from typing import TYPE_CHECKING + +if TYPE_CHECKING: + from typing import Any, Tuple + + +ANDROID = babase.app.classic.platform == "android" +DIRPATH = Path(f"{_babase.app.python_directory_user}/image_id.json") + +if ANDROID: # !can add ios in future + + # Installing websocket + def get_module(): + install_path = Path(f"{getcwd()}/ba_data/python") # For the guys like me on windows + path = Path(f"{install_path}/websocket.zip") + file_path = Path(f"{install_path}/websocket") + source_dir = Path(f"{install_path}/websocket-client-1.6.1/websocket") + if not file_path.exists(): + url = "https://github.com/websocket-client/websocket-client/archive/refs/tags/v1.6.1.zip" + try: + filename, headers = urlretrieve(url, filename=path) + with ZipFile(filename) as f: + f.extractall(install_path) + shutil.copytree(source_dir, file_path) + shutil.rmtree(Path(f"{install_path}/websocket-client-1.6.1")) + remove(path) + except Exception as e: + if type(e) == shutil.Error: + shutil.rmtree(Path(f"{install_path}/websocket-client-1.6.1")) + else: + pass + get_module() + + from websocket import WebSocketConnectionClosedException + import websocket + + + start_time = time.time() + + class PresenceUpdate: + def __init__(self): + self.ws = websocket.WebSocketApp("wss://gateway.discord.gg/?encoding=json&v=10", + on_open=self.on_open, + on_message=self.on_message, + on_error=self.on_error, + on_close=self.on_close) + self.heartbeat_interval = int(41250) + self.resume_gateway_url: str | None = None + self.session_id: str | None = None + self.stop_heartbeat_thread = threading.Event() + self.do_once = True + self.state: str | None = "In Game" + self.details: str | None = "Main Menu" + self.start_timestamp = time.time() + self.large_image_key: str | None = "bombsquadicon" + self.large_image_text: str | None = "BombSquad Icon" + self.small_image_key: str | None = None + self.small_image_text: str | None = ( + f"{_babase.app.classic.platform.capitalize()}({_babase.app.version})") + self.media_proxy = "mp:/app-assets/963434684669382696/{}.png" + self.identify: bool = False + self.party_id: str = str(uuid.uuid4()) + self.party_size = 1 + self.party_max = 8 + + def presence(self): + with open(DIRPATH, "r") as maptxt: + largetxt = json.load(maptxt)[self.large_image_key] + with open(DIRPATH, "r") as maptxt: + smalltxt = json.load(maptxt)[self.small_image_key] + + presencepayload = { + "op": 3, + "d": { + "since": None, # used to show how long the user went idle will add afk to work with this and then set the status to idle + "status": "online", + "afk": "false", + "activities": [ + { + "name": "BombSquad", + "type": 0, + "application_id": "963434684669382696", + "state": self.state, + "details": self.details, + "timestamps": { + "start": start_time + }, + "party": { + "id": self.party_id, + "size": [self.party_size, self.party_max] + }, + "assets": { + "large_image": self.media_proxy.format(largetxt), + "large_text": self.large_image_text, + "small_image": self.media_proxy.format(smalltxt), + "small_text": self.small_image_text, + }, + "client_info": { + "version": 0, + "os": "android", + "client": "mobile", + }, + "buttons": ["Discord Server", "Download BombSquad"], + "metadata": { + "button_urls": [ + "https://discord.gg/bombsquad-ballistica-official-1001896771347304639", + "https://bombsquad-community.web.app/download", + ] + }, + } + ], + }, + } + try: + self.ws.send(json.dumps(presencepayload)) + except WebSocketConnectionClosedException: + pass + + def on_message(self, ws, message): + message = json.loads(message) + try: + self.heartbeat_interval = message["d"]["heartbeat_interval"] + except: + pass + try: + self.resume_gateway_url = message["d"]["resume_gateway_url"] + self.session_id = message["d"]["session_id"] + except: + pass + + def on_error(self, ws, error): + babase.print_exception(error) + + def on_close(self, ws, close_status_code, close_msg): + print("Closed Discord Connection Successfully") + + def on_open(self, ws): + print("Connected to Discord Websocket") + + def heartbeats(): + """Sending heartbeats to keep the connection alive""" + if self.do_once: + heartbeat_payload = { + "op": 1, + "d": 251, + } # step two keeping connection alive by sending heart beats and receiving opcode 11 + self.ws.send(json.dumps(heartbeat_payload)) + self.do_once = False + + def identify(): + """Identifying to the gateway and enable by using user token and the intents we will be using e.g 256->For Presence""" + with open(f"{getcwd()}/token.txt", 'r') as f: + token = bytes.fromhex(f.read()).decode('utf-8') + identify_payload = { + "op": 2, + "d": { + "token": token, + "properties": { + "os": "linux", + "browser": "Discord Android", + "device": "android", + }, + "intents": 256, + }, + } # step 3 send an identify + self.ws.send(json.dumps(identify_payload)) + identify() + while True: + heartbeat_payload = {"op": 1, "d": self.heartbeat_interval} + + try: + self.ws.send(json.dumps(heartbeat_payload)) + time.sleep(self.heartbeat_interval / 1000) + except: + pass + + if self.stop_heartbeat_thread.is_set(): + self.stop_heartbeat_thread.clear() + break + + threading.Thread(target=heartbeats, daemon=True, name="heartbeat").start() + + def start(self): + if Path(f"{getcwd()}/token.txt").exists(): + threading.Thread(target=self.ws.run_forever, daemon=True, name="websocket").start() + + def close(self): + self.stop_heartbeat_thread.set() + self.do_once = True + self.ws.close() + + + + + +if not ANDROID: + # installing pypresence + def get_module(): + install_path = Path(f"{getcwd()}/ba_data/python") + path = Path(f"{install_path}/pypresence.zip") + file_path = Path(f"{install_path}/pypresence") + source_dir = Path(f"{install_path}/pypresence-4.3.0/pypresence") + if not file_path.exists(): + url = "https://github.com/qwertyquerty/pypresence/archive/refs/tags/v4.3.0.zip" + try: + filename, headers = urlretrieve(url, filename=path) + with ZipFile(filename) as f: + f.extractall(install_path) + shutil.copytree(source_dir, file_path) + shutil.rmtree(Path(f"{install_path}/pypresence-4.3.0")) + remove(path) + except: + pass + + # Make modifications for it to work on windows + if babase.app.classic.platform == "windows": + with open(Path(f"{getcwd()}/ba_data/python/pypresence/utils.py"), "r") as file: + data = file.readlines() + data[45] = """ +def get_event_loop(force_fresh=False): + loop = asyncio.ProactorEventLoop() if sys.platform == 'win32' else asyncio.new_event_loop() + if force_fresh: + return loop + try: + running = asyncio.get_running_loop() + except RuntimeError: + return loop + if running.is_closed(): + return loop + else: + if sys.platform in ('linux', 'darwin'): + return running + if sys.platform == 'win32': + if isinstance(running, asyncio.ProactorEventLoop): + return running + else: + return loop""" + + with open(Path(f"{getcwd()}/ba_data/python/pypresence/utils.py"), "w") as file: + for number, line in enumerate(data): + if number not in range(46,56): + file.write(line) + get_module() + + + from pypresence import PipeClosed, DiscordError, DiscordNotFound + from pypresence.utils import get_event_loop + import pypresence + import socket + + DEBUG = True + + _last_server_addr = 'localhost' + _last_server_port = 43210 + + def print_error(err: str, include_exception: bool = False) -> None: + if DEBUG: + if include_exception: + babase.print_exception(err) + else: + babase.print_error(err) + else: + print(f"ERROR in discordrp.py: {err}") + + def log(msg: str) -> None: + if DEBUG: + print(f"LOG in discordrp.py: {msg}") + + def _run_overrides() -> None: + old_init = bs.Activity.__init__ + + def new_init(self, *args: Any, **kwargs: Any) -> None: # type: ignore + old_init(self, *args, **kwargs) + self._discordrp_start_time = time.mktime(time.localtime()) + + bs.Activity.__init__ = new_init # type: ignore + + old_connect = bs.connect_to_party + + def new_connect(*args, **kwargs) -> None: # type: ignore + global _last_server_addr + global _last_server_port + old_connect(*args, **kwargs) + c = kwargs.get("address") or args[0] + _last_server_port = kwargs.get("port") or args[1] + + bs.connect_to_party = new_connect + + start_time = time.time() + + class RpcThread(threading.Thread): + def __init__(self): + super().__init__(name="RpcThread") + self.rpc = pypresence.Presence(963434684669382696) + self.state: str | None = "In Game" + self.details: str | None = "Main Menu" + self.start_timestamp = time.mktime(time.localtime()) + self.large_image_key: str | None = "bombsquadicon" + self.large_image_text: str | None = "BombSquad Icon" + self.small_image_key: str | None = None + self.small_image_text: str | None = None + self.party_id: str = str(uuid.uuid4()) + self.party_size = 1 + self.party_max = 8 + self.join_secret: str | None = None + self._last_update_time: float = 0 + self._last_secret_update_time: float = 0 + self._last_connect_time: float = 0 + self.should_close = False + + @staticmethod + def is_discord_running(): + for i in range(6463,6473): + s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) + s.settimeout(0.01) + try: + conn = s.connect_ex(('localhost', i)) + s.close() + if (conn == 0): + s.close() + return(True) + except: + s.close() + return(False) + + def _generate_join_secret(self): + # resp = requests.get('https://legacy.ballistica.net/bsAccessCheck').text + connection_info = bs.get_connection_to_host_info() + if connection_info: + addr = _last_server_addr + port = _last_server_port + else: + try: + with urlopen( + "https://legacy.ballistica.net/bsAccessCheck" + ) as resp: + resp = resp.read().decode() + resp = ast.literal_eval(resp) + addr = resp["address"] + port = 43210 + secret_dict = { + "format_version": 1, + "hostname": addr, + "port": port, + } + self.join_secret = json.dumps(secret_dict) + except: + pass + + def _update_secret(self): + threading.Thread(target=self._generate_join_secret, daemon=True).start() + self._last_secret_update_time = time.time() + + def run(self) -> None: + asyncio.set_event_loop(get_event_loop()) + while not self.should_close: + if time.time() - self._last_update_time > 0.1: + self._do_update_presence() + if time.time() - self._last_secret_update_time > 15: + self._update_secret() + # if time.time() - self._last_connect_time > 120 and is_discord_running(): #!Eric please add module manager(pip) + # self._reconnect() + time.sleep(0.03) + + def _subscribe(self, event: str, **args): + self.rpc.send_data( + 1, + { + "nonce": f"{time.time():.20f}", + "cmd": "SUBSCRIBE", + "evt": event, + "args": args, + }, + ) + data = self.rpc.loop.run_until_complete(self.rpc.read_output()) + self.handle_event(data) + + def _subscribe_events(self): + self._subscribe("ACTIVITY_JOIN") + self._subscribe("ACTIVITY_JOIN_REQUEST") + + # def _update_presence(self) -> None: + # self._last_update_time = time.time() + # try: + # self._do_update_presence() + # except (AttributeError, AssertionError): + # try: + # self._reconnect() + # except Exception: + # print_error("failed to update presence", include_exception= True) + + + def _reconnect(self) -> None: + self.rpc.connect() + self._subscribe_events() + self._do_update_presence() + self._last_connect_time = time.time() + + def _do_update_presence(self) -> None: + if RpcThread.is_discord_running(): + self._last_update_time = time.time() + try: + data = self.rpc.update( + state=self.state or " ", + details=self.details, + start=start_time, + large_image=self.large_image_key, + large_text=self.large_image_text, + small_image=self.small_image_key, + small_text=self.small_image_text, + party_id=self.party_id, + party_size=[self.party_size, self.party_max], + join=self.join_secret, + # buttons = [ #!cant use buttons together with join + # { + # "label": "Discord Server", + # "url": "https://ballistica.net/discord" + # }, + # { + # "label": "Download Bombsquad", + # "url": "https://bombsquad.ga/download"} + # ] + ) + + self.handle_event(data) + except (PipeClosed, DiscordError, AssertionError, AttributeError): + try: + self._reconnect() + except (DiscordNotFound, DiscordError): + pass + + def handle_event(self, data): + evt = data["evt"] + if evt is None: + return + + data = data.get("data", {}) + + if evt == "ACTIVITY_JOIN": + secret = data.get("secret") + try: + server = json.loads(secret) + format_version = server["format_version"] + except Exception: + babase.print_exception("discordrp: unknown activity join format") + else: + try: + if format_version == 1: + hostname = server["hostname"] + port = server["port"] + self._connect_to_party(hostname, port) + except Exception: + babase.print_exception( + f"discordrp: incorrect activity join data, {format_version=}" + ) + + elif evt == "ACTIVITY_JOIN_REQUEST": + user = data.get("user", {}) + uid = user.get("id") + username = user.get("username") + discriminator = user.get("discriminator", None) + avatar = user.get("avatar") + self.on_join_request(username, uid, discriminator, avatar) + + def _connect_to_party(self, hostname, port) -> None: + babase.pushcall( + babase.Call(bs.connect_to_party, hostname, port), from_other_thread=True + ) + + def on_join_request(self, username, uid, discriminator, avatar) -> None: + del uid # unused + del avatar # unused + babase.pushcall( + babase.Call( + bui.screenmessage, + "Discord: {} wants to join!".format(username), + color=(0.0, 1.0, 0.0), + ), + from_other_thread=True, + ) + babase.pushcall(lambda: bui.getsound('bellMed').play(), from_other_thread=True) + + +class Discordlogin(PopupWindow): + + def __init__(self): + # pylint: disable=too-many-locals + _uiscale = bui.app.ui_v1.uiscale + self._transitioning_out = False + s = 1.25 if _uiscale is babase.UIScale.SMALL else 1.27 if _uiscale is babase.UIScale.MEDIUM else 1.3 + self._width = 380 * s + self._height = 150 + 150 * s + self.path = Path(f"{getcwd()}/token.txt") + bg_color = (0.5, 0.4, 0.6) + log_btn_colour = (0.10, 0.95, 0.10) if not self.path.exists() else (1.00, 0.15, 0.15) + log_txt = "LOG IN" if not self.path.exists() else "LOG OUT" + + + + + # creates our _root_widget + PopupWindow.__init__(self, + position=(0.0, 0.0), + size=(self._width, self._height), + scale=(2.1 if _uiscale is babase.UIScale.SMALL else 1.5 + if _uiscale is babase.UIScale.MEDIUM else 1.0), + bg_color=bg_color) + + + self._cancel_button = bui.buttonwidget( + parent=self.root_widget, + position=(25, self._height - 40), + size=(50, 50), + scale=0.58, + label='', + color=bg_color, + on_activate_call=self._on_cancel_press, + autoselect=True, + icon=bui.gettexture('crossOut'), + iconscale=1.2) + + + + bui.imagewidget(parent=self.root_widget, + position=(180, self._height - 55), + size=(32 * s, 32 * s), + texture=bui.gettexture("discordLogo"), + color=(10 - 0.32, 10 - 0.39, 10 - 0.96)) + + + + self.email_widget = bui.textwidget(parent=self.root_widget, + text="Email/Phone Number", + size=(400, 70), + position=(50, 180), + h_align='left', + v_align='center', + editable=True, + scale=0.8, + autoselect=True, + maxwidth=220) + + + self.password_widget = bui.textwidget(parent=self.root_widget, + text="Password", + size=(400, 70), + position=(50, 120), + h_align='left', + v_align='center', + editable=True, + scale=0.8, + autoselect=True, + maxwidth=220) + + + bui.containerwidget(edit=self.root_widget, + cancel_button=self._cancel_button) + + bui.textwidget( + parent=self.root_widget, + position=(265, self._height - 37), + size=(0, 0), + h_align='center', + v_align='center', + scale=1.0, + text="Discord", + maxwidth=200, + color=(0.80, 0.80, 0.80)) + + bui.textwidget( + parent=self.root_widget, + position=(265, self._height - 78), + size=(0, 0), + h_align='center', + v_align='center', + scale=1.0, + text="💀Use at your own risk💀\n ⚠️discord account might get terminated⚠️", + maxwidth=200, + color=(1.00, 0.15, 0.15)) + + + self._login_button = bui.buttonwidget( + parent=self.root_widget, + position=(120, 65), + size=(400, 80), + scale=0.58, + label=log_txt, + color=log_btn_colour, + on_activate_call=self.login, + autoselect=True) + + def _on_cancel_press(self) -> None: + self._transition_out() + + def _transition_out(self) -> None: + if not self._transitioning_out: + self._transitioning_out = True + bui.containerwidget(edit=self.root_widget, transition='out_scale') + + def on_bascenev1libup_cancel(self) -> None: + bui.getsound('swish').play() + self._transition_out() + + def login(self): + if not self.path.exists(): + json_data = { + 'login': bui.textwidget(query=self.email_widget), + 'password': bui.textwidget(query=self.password_widget), + 'undelete': False, + 'captcha_key': None, + 'login_source': None, + 'gift_code_sku_id': None, + } + headers = { + 'user-agent': "Mozilla/5.0", + 'content-type': "application/json", + } + + conn = http.client.HTTPSConnection("discord.com") + + payload = json.dumps(json_data) + # conn.request("POST", "/api/v9/auth/login", payload, headers) + # res = conn.getresponse().read() + + try: + conn.request("POST", "/api/v9/auth/login", payload, headers) + res = conn.getresponse().read() + token = json.loads(res)['token'].encode().hex().encode() + with open(self.path, 'wb') as f: + f.write(token) + bui.screenmessage("Successfully logged in", (0.21, 1.0, 0.20)) + bui.getsound('shieldUp').play() + self.on_bascenev1libup_cancel() + except: + bui.screenmessage("Incorrect credentials", (1.00, 0.15, 0.15)) + bui.getsound('error').play() + + conn.close() + else: + remove(self.path) + bui.getsound('shieldDown').play() + bui.screenmessage("Account successfully removed!!", (0.10, 0.10, 1.00)) + self.on_bascenev1libup_cancel() + PresenceUpdate().ws.close() + + +run_once = False +def get_once_asset(): + global run_once + if run_once: + return + response = Request( + "https://discordapp.com/api/oauth2/applications/963434684669382696/assets", + headers={"User-Agent": "Mozilla/5.0"}, + ) + try: + with urlopen(response) as assets: + assets = json.loads(assets.read()) + asset = [] + asset_id = [] + for x in assets: + dem = x["name"] + don = x["id"] + asset_id.append(don) + asset.append(dem) + asset_id_dict = dict(zip(asset, asset_id)) + + with open(DIRPATH, "w") as imagesets: + jsonfile = json.dumps(asset_id_dict) + json.dump(asset_id_dict, imagesets, indent=4) + except: + pass + run_once = True + +def get_class(): + if ANDROID: + return PresenceUpdate() + elif not ANDROID: + return RpcThread() + + +# ba_meta export babase.Plugin +class DiscordRP(babase.Plugin): + def __init__(self) -> None: + self.update_timer: bs.Timer | None = None + self.rpc_thread = get_class() + self._last_server_info: str | None = None + + if not ANDROID: + _run_overrides() + get_once_asset() + + def on_app_running(self) -> None: + if not ANDROID: + self.rpc_thread.start() + self.update_timer = bs.AppTimer( + 1, bs.WeakCall(self.update_status), repeat=True + ) + if ANDROID: + self.rpc_thread.start() + self.update_timer = bs.AppTimer( + 4, bs.WeakCall(self.update_status), repeat=True + ) + + def has_settings_ui(self): + return True + + def show_settings_ui(self, button): + if not ANDROID: + bui.screenmessage("Nothing here achievement!!!", (0.26, 0.65, 0.94)) + bui.getsound('achievement').play() + if ANDROID: + Discordlogin() + + def on_app_shutdown(self) -> None: + if not ANDROID and self.rpc_thread.is_discord_running(): + self.rpc_thread.rpc.close() + self.rpc_thread.should_close = True + + def on_app_pause(self) -> None: + self.rpc_thread.close() + + def on_app_resume(self) -> None: + self.rpc_thread.start() + + def _get_current_activity_name(self) -> str | None: + act = bs.get_foreground_host_activity() + if isinstance(act, bs.GameActivity): + return act.name + + this = "Lobby" + name: str | None = ( + act.__class__.__name__.replace("Activity", "") + .replace("ScoreScreen", "Ranking") + .replace("Coop", "") + .replace("MultiTeam", "") + .replace("Victory", "") + .replace("EndSession", "") + .replace("Transition", "") + .replace("Draw", "") + .replace("FreeForAll", "") + .replace("Join", this) + .replace("Team", "") + .replace("Series", "") + .replace("CustomSession", "Custom Session(mod)") + ) + + if name == "MainMenu": + name = "Main Menu" + if name == this: + self.rpc_thread.large_image_key = "lobby" + self.rpc_thread.large_image_text = "Bombing up" + #self.rpc_thread.small_image_key = "lobbysmall" + if name == "Ranking": + self.rpc_thread.large_image_key = "ranking" + self.rpc_thread.large_image_text = "Viewing Results" + return name + + def _get_current_map_name(self) -> Tuple[str | None, str | None]: + act = bs.get_foreground_host_activity() + if isinstance(act, bs.GameActivity): + texname = act.map.get_preview_texture_name() + if texname: + return act.map.name, texname.lower().removesuffix("preview") + return None, None + + def update_status(self) -> None: + roster = bs.get_game_roster() + connection_info = bs.get_connection_to_host_info() + + self.rpc_thread.large_image_key = "bombsquadicon" + self.rpc_thread.large_image_text = "BombSquad" + self.rpc_thread.small_image_key = _babase.app.classic.platform + self.rpc_thread.small_image_text = ( + f"{_babase.app.classic.platform.capitalize()}({_babase.app.version})" + ) + connection_info = bs.get_connection_to_host_info() + if not ANDROID: + svinfo = str(connection_info) + if self._last_server_info != svinfo: + self._last_server_info = svinfo + self.rpc_thread.party_id = str(uuid.uuid4()) + self.rpc_thread._update_secret() + if connection_info != {}: + servername = connection_info["name"] + self.rpc_thread.details = "Online" + self.rpc_thread.party_size = max( + 1, sum(len(client["players"]) for client in roster) + ) + self.rpc_thread.party_max = max(8, self.rpc_thread.party_size) + if len(servername) == 19 and "Private Party" in servername: + self.rpc_thread.state = "Private Party" + elif servername == "": # A local game joinable from the internet + try: + offlinename = json.loads(bs.get_game_roster()[0]["spec_string"])[ + "n" + ] + if len(offlinename) > 19: # Thanks Rikko + self.rpc_thread.state = offlinename[slice(19)] + "..." + else: + self.rpc_thread.state = offlinename + except IndexError: + pass + else: + if len(servername) > 19: + self.rpc_thread.state = servername[slice(19)] + ".." + else: + self.rpc_thread.state = servername[slice(19)] + + if connection_info == {}: + self.rpc_thread.details = "Local" #! replace with something like ballistica github cause + self.rpc_thread.state = self._get_current_activity_name() + self.rpc_thread.party_size = max(1, len(roster)) + self.rpc_thread.party_max = max(1, bs.get_public_party_max_size()) + + if ( + bs.get_foreground_host_session() is not None + and self.rpc_thread.details == "Local" + ): + session = ( + bs.get_foreground_host_session() + .__class__.__name__.replace("MainMenuSession", "") + .replace("EndSession", "") + .replace("FreeForAllSession", ": FFA") #! for session use small image key + .replace("DualTeamSession", ": Teams") + .replace("CoopSession", ": Coop") + ) + #! self.rpc_thread.small_image_key = session.lower() + self.rpc_thread.details = f"{self.rpc_thread.details} {session}" + if ( + self.rpc_thread.state == "NoneType" + ): # sometimes the game just breaks which means its not really watching replay FIXME + self.rpc_thread.state = "Watching Replay" + self.rpc_thread.large_image_key = "replay" + self.rpc_thread.large_image_text = "Viewing Awesomeness" + #!self.rpc_thread.small_image_key = "replaysmall" + + act = bs.get_foreground_host_activity() + session = bs.get_foreground_host_session() + if act: + from bascenev1lib.game.elimination import EliminationGame + from bascenev1lib.game.thelaststand import TheLastStandGame + from bascenev1lib.game.meteorshower import MeteorShowerGame + + # noinspection PyUnresolvedReferences,PyProtectedMember + try: + self.rpc_thread.start_timestamp = act._discordrp_start_time # type: ignore + except AttributeError: + # This can be the case if plugin launched AFTER activity + # has been created; in that case let's assume it was + # created just now. + self.rpc_thread.start_timestamp = act._discordrp_start_time = time.mktime( # type: ignore + time.localtime() + ) + if isinstance(act, EliminationGame): + alive_count = len([p for p in act.players if p.lives > 0]) + self.rpc_thread.details += f" ({alive_count} players left)" + elif isinstance(act, TheLastStandGame): + # noinspection PyProtectedMember + points = act._score + self.rpc_thread.details += f" ({points} points)" + elif isinstance(act, MeteorShowerGame): + with bs.ContextRef(act): + sec = bs.time() - act._timer.getstarttime() + secfmt = "" + if sec < 60: + secfmt = f"{sec:.2f}" + else: + secfmt = f"{int(sec) // 60:02}:{sec:.2f}" + self.rpc_thread.details += f" ({secfmt})" + + # if isinstance(session, ba.DualTeamSession): + # scores = ':'.join([ + # str(t.customdata['score']) + # for t in session.sessionteams + # ]) + # self.rpc_thread.details += f' ({scores})' + + mapname, short_map_name = self._get_current_map_name() + if mapname: + with open(DIRPATH, 'r') as asset_dict: + asset_keys = json.load(asset_dict).keys() + if short_map_name in asset_keys: + self.rpc_thread.large_image_text = mapname + self.rpc_thread.large_image_key = short_map_name + self.rpc_thread.small_image_key = 'bombsquadlogo2' + self.rpc_thread.small_image_text = 'BombSquad' + + if _babase.get_idle_time() / (1000 * 60) % 60 >= 0.4: + self.rpc_thread.details = f"AFK in {self.rpc_thread.details}" + if not ANDROID: + self.rpc_thread.large_image_key = ( + "https://media.tenor.com/uAqNn6fv7x4AAAAM/bombsquad-spaz.gif" + ) + if ANDROID and Path(f"{getcwd()}/token.txt").exists(): + self.rpc_thread.presence() + \ No newline at end of file From 5f2e53dc38d5c61a15c8047448617e2d57aa0f22 Mon Sep 17 00:00:00 2001 From: brostosjoined Date: Sat, 22 Jul 2023 00:54:53 +0000 Subject: [PATCH 0586/1464] [ci] auto-format --- plugins/utilities/discord_richpresence.py | 153 ++++++++++------------ 1 file changed, 69 insertions(+), 84 deletions(-) diff --git a/plugins/utilities/discord_richpresence.py b/plugins/utilities/discord_richpresence.py index 2dee9f09..e0042ed7 100644 --- a/plugins/utilities/discord_richpresence.py +++ b/plugins/utilities/discord_richpresence.py @@ -24,7 +24,7 @@ import shutil import babase import _babase -import bascenev1 as bs +import bascenev1 as bs import bascenev1lib import bauiv1 as bui @@ -64,16 +64,15 @@ def get_module(): from websocket import WebSocketConnectionClosedException import websocket - start_time = time.time() - + class PresenceUpdate: def __init__(self): self.ws = websocket.WebSocketApp("wss://gateway.discord.gg/?encoding=json&v=10", - on_open=self.on_open, - on_message=self.on_message, - on_error=self.on_error, - on_close=self.on_close) + on_open=self.on_open, + on_message=self.on_message, + on_error=self.on_error, + on_close=self.on_close) self.heartbeat_interval = int(41250) self.resume_gateway_url: str | None = None self.session_id: str | None = None @@ -197,30 +196,27 @@ def identify(): identify() while True: heartbeat_payload = {"op": 1, "d": self.heartbeat_interval} - + try: self.ws.send(json.dumps(heartbeat_payload)) time.sleep(self.heartbeat_interval / 1000) except: pass - + if self.stop_heartbeat_thread.is_set(): self.stop_heartbeat_thread.clear() break - + threading.Thread(target=heartbeats, daemon=True, name="heartbeat").start() - + def start(self): if Path(f"{getcwd()}/token.txt").exists(): threading.Thread(target=self.ws.run_forever, daemon=True, name="websocket").start() - + def close(self): self.stop_heartbeat_thread.set() self.do_once = True self.ws.close() - - - if not ANDROID: @@ -241,7 +237,7 @@ def get_module(): remove(path) except: pass - + # Make modifications for it to work on windows if babase.app.classic.platform == "windows": with open(Path(f"{getcwd()}/ba_data/python/pypresence/utils.py"), "r") as file: @@ -265,24 +261,23 @@ def get_event_loop(force_fresh=False): return running else: return loop""" - + with open(Path(f"{getcwd()}/ba_data/python/pypresence/utils.py"), "w") as file: for number, line in enumerate(data): - if number not in range(46,56): + if number not in range(46, 56): file.write(line) get_module() - from pypresence import PipeClosed, DiscordError, DiscordNotFound from pypresence.utils import get_event_loop - import pypresence + import pypresence import socket - + DEBUG = True - + _last_server_addr = 'localhost' _last_server_port = 43210 - + def print_error(err: str, include_exception: bool = False) -> None: if DEBUG: if include_exception: @@ -313,8 +308,8 @@ def new_connect(*args, **kwargs) -> None: # type: ignore old_connect(*args, **kwargs) c = kwargs.get("address") or args[0] _last_server_port = kwargs.get("port") or args[1] - - bs.connect_to_party = new_connect + + bs.connect_to_party = new_connect start_time = time.time() @@ -337,10 +332,10 @@ def __init__(self): self._last_secret_update_time: float = 0 self._last_connect_time: float = 0 self.should_close = False - - @staticmethod + + @staticmethod def is_discord_running(): - for i in range(6463,6473): + for i in range(6463, 6473): s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) s.settimeout(0.01) try: @@ -348,11 +343,11 @@ def is_discord_running(): s.close() if (conn == 0): s.close() - return(True) + return (True) except: s.close() - return(False) - + return (False) + def _generate_join_secret(self): # resp = requests.get('https://legacy.ballistica.net/bsAccessCheck').text connection_info = bs.get_connection_to_host_info() @@ -409,7 +404,7 @@ def _subscribe_events(self): self._subscribe("ACTIVITY_JOIN") self._subscribe("ACTIVITY_JOIN_REQUEST") - # def _update_presence(self) -> None: + # def _update_presence(self) -> None: # self._last_update_time = time.time() # try: # self._do_update_presence() @@ -418,7 +413,6 @@ def _subscribe_events(self): # self._reconnect() # except Exception: # print_error("failed to update presence", include_exception= True) - def _reconnect(self) -> None: self.rpc.connect() @@ -495,7 +489,7 @@ def handle_event(self, data): def _connect_to_party(self, hostname, port) -> None: babase.pushcall( babase.Call(bs.connect_to_party, hostname, port), from_other_thread=True - ) + ) def on_join_request(self, username, uid, discriminator, avatar) -> None: del uid # unused @@ -523,10 +517,7 @@ def __init__(self): self.path = Path(f"{getcwd()}/token.txt") bg_color = (0.5, 0.4, 0.6) log_btn_colour = (0.10, 0.95, 0.10) if not self.path.exists() else (1.00, 0.15, 0.15) - log_txt = "LOG IN" if not self.path.exists() else "LOG OUT" - - - + log_txt = "LOG IN" if not self.path.exists() else "LOG OUT" # creates our _root_widget PopupWindow.__init__(self, @@ -535,7 +526,6 @@ def __init__(self): scale=(2.1 if _uiscale is babase.UIScale.SMALL else 1.5 if _uiscale is babase.UIScale.MEDIUM else 1.0), bg_color=bg_color) - self._cancel_button = bui.buttonwidget( parent=self.root_widget, @@ -548,44 +538,38 @@ def __init__(self): autoselect=True, icon=bui.gettexture('crossOut'), iconscale=1.2) - - - + bui.imagewidget(parent=self.root_widget, - position=(180, self._height - 55), - size=(32 * s, 32 * s), - texture=bui.gettexture("discordLogo"), - color=(10 - 0.32, 10 - 0.39, 10 - 0.96)) - + position=(180, self._height - 55), + size=(32 * s, 32 * s), + texture=bui.gettexture("discordLogo"), + color=(10 - 0.32, 10 - 0.39, 10 - 0.96)) - self.email_widget = bui.textwidget(parent=self.root_widget, - text="Email/Phone Number", - size=(400, 70), - position=(50, 180), - h_align='left', - v_align='center', - editable=True, - scale=0.8, - autoselect=True, - maxwidth=220) - - + text="Email/Phone Number", + size=(400, 70), + position=(50, 180), + h_align='left', + v_align='center', + editable=True, + scale=0.8, + autoselect=True, + maxwidth=220) + self.password_widget = bui.textwidget(parent=self.root_widget, - text="Password", - size=(400, 70), - position=(50, 120), - h_align='left', - v_align='center', - editable=True, - scale=0.8, - autoselect=True, - maxwidth=220) - - + text="Password", + size=(400, 70), + position=(50, 120), + h_align='left', + v_align='center', + editable=True, + scale=0.8, + autoselect=True, + maxwidth=220) + bui.containerwidget(edit=self.root_widget, - cancel_button=self._cancel_button) - + cancel_button=self._cancel_button) + bui.textwidget( parent=self.root_widget, position=(265, self._height - 37), @@ -596,7 +580,7 @@ def __init__(self): text="Discord", maxwidth=200, color=(0.80, 0.80, 0.80)) - + bui.textwidget( parent=self.root_widget, position=(265, self._height - 78), @@ -607,8 +591,7 @@ def __init__(self): text="💀Use at your own risk💀\n ⚠️discord account might get terminated⚠️", maxwidth=200, color=(1.00, 0.15, 0.15)) - - + self._login_button = bui.buttonwidget( parent=self.root_widget, position=(120, 65), @@ -673,8 +656,10 @@ def login(self): self.on_bascenev1libup_cancel() PresenceUpdate().ws.close() - + run_once = False + + def get_once_asset(): global run_once if run_once: @@ -702,6 +687,7 @@ def get_once_asset(): pass run_once = True + def get_class(): if ANDROID: return PresenceUpdate() @@ -722,7 +708,7 @@ def __init__(self) -> None: def on_app_running(self) -> None: if not ANDROID: - self.rpc_thread.start() + self.rpc_thread.start() self.update_timer = bs.AppTimer( 1, bs.WeakCall(self.update_status), repeat=True ) @@ -749,15 +735,15 @@ def on_app_shutdown(self) -> None: def on_app_pause(self) -> None: self.rpc_thread.close() - + def on_app_resume(self) -> None: self.rpc_thread.start() - + def _get_current_activity_name(self) -> str | None: act = bs.get_foreground_host_activity() if isinstance(act, bs.GameActivity): return act.name - + this = "Lobby" name: str | None = ( act.__class__.__name__.replace("Activity", "") @@ -825,7 +811,7 @@ def update_status(self) -> None: offlinename = json.loads(bs.get_game_roster()[0]["spec_string"])[ "n" ] - if len(offlinename) > 19: # Thanks Rikko + if len(offlinename) > 19: # Thanks Rikko self.rpc_thread.state = offlinename[slice(19)] + "..." else: self.rpc_thread.state = offlinename @@ -838,7 +824,7 @@ def update_status(self) -> None: self.rpc_thread.state = servername[slice(19)] if connection_info == {}: - self.rpc_thread.details = "Local" #! replace with something like ballistica github cause + self.rpc_thread.details = "Local" # ! replace with something like ballistica github cause self.rpc_thread.state = self._get_current_activity_name() self.rpc_thread.party_size = max(1, len(roster)) self.rpc_thread.party_max = max(1, bs.get_public_party_max_size()) @@ -851,7 +837,7 @@ def update_status(self) -> None: bs.get_foreground_host_session() .__class__.__name__.replace("MainMenuSession", "") .replace("EndSession", "") - .replace("FreeForAllSession", ": FFA") #! for session use small image key + .replace("FreeForAllSession", ": FFA") # ! for session use small image key .replace("DualTeamSession", ": Teams") .replace("CoopSession", ": Coop") ) @@ -924,4 +910,3 @@ def update_status(self) -> None: ) if ANDROID and Path(f"{getcwd()}/token.txt").exists(): self.rpc_thread.presence() - \ No newline at end of file From 7c0740904979a0580454c49513e3d5249ce0b11e Mon Sep 17 00:00:00 2001 From: brostos <67740566+brostosjoined@users.noreply.github.com> Date: Sat, 22 Jul 2023 03:57:07 +0300 Subject: [PATCH 0587/1464] hopefully final --- plugins/utilities.json | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/plugins/utilities.json b/plugins/utilities.json index 5142fd43..95557ec7 100644 --- a/plugins/utilities.json +++ b/plugins/utilities.json @@ -767,12 +767,7 @@ } ], "versions": { - "1.1.0": { - "api_version": 8, - "commit_sha": "8f02db1", - "released_on": "21-07-2023", - "md5sum": "402a406cab00e6fc6687738d237aeda6" - }, + "1.1.0": null, "1.0.0": { "api_version": 8, "commit_sha": "230d12d", @@ -782,4 +777,4 @@ } } } -} \ No newline at end of file +} From cb862471bf3bd0367781d8479820147eb6257a5c Mon Sep 17 00:00:00 2001 From: brostosjoined Date: Sat, 22 Jul 2023 00:57:33 +0000 Subject: [PATCH 0588/1464] [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 95557ec7..3c2240ca 100644 --- a/plugins/utilities.json +++ b/plugins/utilities.json @@ -767,7 +767,12 @@ } ], "versions": { - "1.1.0": null, + "1.1.0": { + "api_version": 8, + "commit_sha": "7c07409", + "released_on": "22-07-2023", + "md5sum": "2313a4a4939508ea4a907c8f6d23d96c" + }, "1.0.0": { "api_version": 8, "commit_sha": "230d12d", @@ -777,4 +782,4 @@ } } } -} +} \ No newline at end of file From c74b47009e8fc6e624d54b9b9692fb182fee68e1 Mon Sep 17 00:00:00 2001 From: brostos <67740566+brostosjoined@users.noreply.github.com> Date: Sat, 22 Jul 2023 16:44:09 +0300 Subject: [PATCH 0589/1464] Fixed time on mobile rich presence --- plugins/utilities/discord_richpresence.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/plugins/utilities/discord_richpresence.py b/plugins/utilities/discord_richpresence.py index e0042ed7..a1893293 100644 --- a/plugins/utilities/discord_richpresence.py +++ b/plugins/utilities/discord_richpresence.py @@ -737,6 +737,8 @@ def on_app_pause(self) -> None: self.rpc_thread.close() def on_app_resume(self) -> None: + global start_time + start_time = time.time() self.rpc_thread.start() def _get_current_activity_name(self) -> str | None: From 88bb90aa92dbdaf7bc96ec84a17e54e124cadd64 Mon Sep 17 00:00:00 2001 From: brostosjoined Date: Sat, 22 Jul 2023 13:44:40 +0000 Subject: [PATCH 0590/1464] [ci] auto-format --- plugins/utilities/discord_richpresence.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/utilities/discord_richpresence.py b/plugins/utilities/discord_richpresence.py index a1893293..5b01fdb9 100644 --- a/plugins/utilities/discord_richpresence.py +++ b/plugins/utilities/discord_richpresence.py @@ -737,7 +737,7 @@ def on_app_pause(self) -> None: self.rpc_thread.close() def on_app_resume(self) -> None: - global start_time + global start_time start_time = time.time() self.rpc_thread.start() From dd28dc6467a5b5e3865cdb1e113131f7e58a409d Mon Sep 17 00:00:00 2001 From: SenjuZoro <69396975+SenjuZoro@users.noreply.github.com> Date: Sun, 23 Jul 2023 13:53:28 +0200 Subject: [PATCH 0591/1464] Add files via upload Updated dodge_the_ball minigame to api 8 --- plugins/minigames/dodge_the_ball.py | 795 ++++++++++++++-------------- 1 file changed, 398 insertions(+), 397 deletions(-) diff --git a/plugins/minigames/dodge_the_ball.py b/plugins/minigames/dodge_the_ball.py index a9501318..7d1648d6 100644 --- a/plugins/minigames/dodge_the_ball.py +++ b/plugins/minigames/dodge_the_ball.py @@ -6,18 +6,20 @@ # Feel free to edit. -# ba_meta require api 7 +# ba_meta require api 8 from __future__ import annotations from typing import TYPE_CHECKING -import ba -from random import choice +import babase +import bauiv1 as bui +import bascenev1 as bs +from random import choice from enum import Enum -from bastd.actor.bomb import Blast -from bastd.actor.popuptext import PopupText -from bastd.actor.powerupbox import PowerupBox -from bastd.actor.onscreencountdown import OnScreenCountdown -from bastd.gameutils import SharedObjects +from bascenev1lib.actor.bomb import Blast +from bascenev1lib.actor.popuptext import PopupText +from bascenev1lib.actor.powerupbox import PowerupBox +from bascenev1lib.actor.onscreencountdown import OnScreenCountdown +from bascenev1lib.gameutils import SharedObjects if TYPE_CHECKING: from typing import NoReturn, Sequence, Any @@ -39,31 +41,28 @@ class BallType(Enum): # increase the next ball speed but less than MEDIUM. # Ball color is crimson(purple+red = pinky color type). - -# this dict decide the ball_type spawning rate like powerup box +# this dict decide the ball_type spawning rate like powerup box ball_type_dict: dict[BallType, int] = { BallType.EASY: 3, BallType.MEDIUM: 2, BallType.HARD: 1, -} - +}; -class Ball(ba.Actor): +class Ball(bs.Actor): """ Shooting Ball """ - - def __init__(self, - position: Sequence[float], - velocity: Sequence[float], - texture: ba.Texture, - body_scale: float = 1.0, - gravity_scale: float = 1.0, - ) -> NoReturn: - - super().__init__() - - shared = SharedObjects.get() - - ball_material = ba.Material() + def __init__(self, + position: Sequence[float], + velocity: Sequence[float], + texture: babase.Texture, + body_scale: float = 1.0, + gravity_scale: float = 1.0, + ) -> NoReturn: + + super().__init__(); + + shared = SharedObjects.get(); + + ball_material = bs.Material(); ball_material.add_actions( conditions=( ( @@ -75,9 +74,9 @@ def __init__(self, ('they_have_material', shared.object_material), ), actions=('modify_node_collision', 'collide', False), - ) - - self.node = ba.newnode( + ); + + self.node = bs.newnode( 'prop', delegate=self, attrs={ @@ -85,41 +84,41 @@ def __init__(self, 'position': position, 'velocity': velocity, 'body_scale': body_scale, - 'model': ba.getmodel('frostyPelvis'), - 'model_scale': body_scale, + 'mesh': bs.getmesh('frostyPelvis'), + 'mesh_scale': body_scale, 'color_texture': texture, 'gravity_scale': gravity_scale, - 'density': 4.0, # increase density of ball so ball collide with player with heavy force. # ammm very bad grammer + 'density': 4.0, # increase density of ball so ball collide with player with heavy force. # ammm very bad grammer 'materials': (ball_material,), - }, - ) - + }, + ); + # die the ball manually incase the ball doesn't fall the outside of the map - ba.timer(2.5, ba.WeakCall(self.handlemessage, ba.DieMessage())) - + bs.timer(2.5, bs.WeakCall(self.handlemessage, bs.DieMessage())); + # i am not handling anything in this ball Class(except for diemessage). # all game things and logics going to be in the box class def handlemessage(self, msg: Any) -> Any: - - if isinstance(msg, ba.DieMessage): - self.node.delete() + + if isinstance(msg, bs.DieMessage): + self.node.delete(); else: - super().handlemessage(msg) - - -class Box(ba.Actor): + super().handlemessage(msg); + + +class Box(bs.Actor): """ A box that spawn midle of map as a decoration perpose """ - - def __init__(self, - position: Sequence[float], - velocity: Sequence[float], - ) -> NoReturn: - - super().__init__() - - shared = SharedObjects.get() + + def __init__(self, + position: Sequence[float], + velocity: Sequence[float], + ) -> NoReturn: + + super().__init__(); + + shared = SharedObjects.get(); # self.ball_jump = 0.0; - no_hit_material = ba.Material() + no_hit_material = bs.Material(); # we don't need that the box was move and collide with objects. no_hit_material.add_actions( conditions=( @@ -128,7 +127,7 @@ def __init__(self, ('they_have_material', shared.attack_material), ), actions=('modify_part_collision', 'collide', False), - ) + ); no_hit_material.add_actions( conditions=( @@ -140,43 +139,43 @@ def __init__(self, ('modify_part_collision', 'collide', False), ('modify_part_collision', 'physical', False), ), - ) - - self.node = ba.newnode( + ); + + self.node = bs.newnode( 'prop', delegate=self, attrs={ 'body': 'box', 'position': position, - 'model': ba.getmodel('powerup'), - 'light_model': ba.getmodel('powerupSimple'), + 'mesh': bs.getmesh('powerup'), + 'light_mesh': bs.getmesh('powerupSimple'), 'shadow_size': 0.5, 'body_scale': 1.4, - 'model_scale': 1.4, - 'color_texture': ba.gettexture('landMineLit'), + 'mesh_scale': 1.4, + 'color_texture': bs.gettexture('landMineLit'), 'reflection': 'powerup', 'reflection_scale': [1.0], 'materials': (no_hit_material,), - }, - ) + }, + ); # light - self.light = ba.newnode( + self.light = bs.newnode( "light", - owner=self.node, + owner = self.node, attrs={ - 'radius': 0.2, - 'intensity': 0.8, - 'color': (0.0, 1.0, 0.0), + 'radius' : 0.2, + 'intensity' : 0.8, + 'color': (0.0, 1.0, 0.0), } - ) - self.node.connectattr("position", self.light, "position") - # Drawing circle and circleOutline in radius of 3, - # so player can see that how close he is to the box. - # If player is inside this circle the ball speed will increase. - circle = ba.newnode( + ); + self.node.connectattr("position", self.light, "position"); + # Drawing circle and circleOutline in radius of 3, + # so player can see that how close he is to the box. + # If player is inside this circle the ball speed will increase. + circle = bs.newnode( "locator", - owner=self.node, - attrs={ + owner = self.node, + attrs = { 'shape': 'circle', 'color': (1.0, 0.0, 0.0), 'opacity': 0.1, @@ -185,12 +184,12 @@ def __init__(self, 'additive': True, }, ) - self.node.connectattr("position", circle, "position") + self.node.connectattr("position", circle, "position"); # also adding a outline cause its look nice. - circle_outline = ba.newnode( + circle_outline = bs.newnode( "locator", - owner=self.node, - attrs={ + owner = self.node, + attrs = { 'shape': 'circleOutline', 'color': (1.0, 1.0, 0.0), 'opacity': 0.1, @@ -198,185 +197,187 @@ def __init__(self, 'draw_beauty': False, 'additive': True, }, - ) - self.node.connectattr("position", circle_outline, "position") - + ); + self.node.connectattr("position", circle_outline, "position"); + # all ball attribute that we need. - self.ball_type: BallType = BallType.EASY - self.shoot_timer: ba.Timer | None = None - self.shoot_speed: float = 0.0 + self.ball_type: BallType = BallType.EASY; + self.shoot_timer: bs.Timer | None = None; + self.shoot_speed: float = 0.0; # this force the shoot if player is inside the red circle. - self.force_shoot_speed: float = 0.0 - self.ball_mag = 3000 - self.ball_gravity: float = 1.0 - self.ball_tex: ba.Texture | None = None - # only for Hard ball_type - self.player_facing_direction: list[float, float] = [0.0, 0.0] + self.force_shoot_speed: float = 0.0; + self.ball_mag = 3000; + self.ball_gravity: float = 1.0; + self.ball_tex: babase.Texture | None = None; + # only for Hard ball_type + self.player_facing_direction: list[float, float] = [0.0, 0.0]; # ball shoot soound. - self.shoot_sound = ba.getsound('laserReverse') - - # same as "powerupdist" - self.ball_type_dist: list[BallType] = [] + self.shoot_sound = bs.getsound('laserReverse'); + + # same as "powerupdist" + self.ball_type_dist: list[BallType] = []; for ball in ball_type_dict: for _ in range(ball_type_dict[ball]): - self.ball_type_dist.append(ball) - + self.ball_type_dist.append(ball); + # Here main logic of game goes here. # like shoot balls, shoot speed, anything we want goes here(except for some thing). def start_shoot(self) -> NoReturn: - + # getting all allive players in a list. - alive_players_list = self.activity.get_alive_players() - + alive_players_list = self.activity.get_alive_players(); + # make sure that list is not Empty. if len(alive_players_list) > 0: - + # choosing a random player from list. - target_player = choice(alive_players_list) - # highlight the target player - self.highlight_target_player(target_player) - + target_player = choice(alive_players_list); + # highlight the target player + self.highlight_target_player(target_player); + # to finding difference between player and box. # we just need to subtract player pos and ball pos. # Same logic as eric applied in Target Practice Gamemode. - difference = ba.Vec3(target_player.position) - ba.Vec3(self.node.position) - + difference = babase.Vec3(target_player.position) - babase.Vec3(self.node.position); + # discard Y position so ball shoot more straight. difference[1] = 0.0 - + # and now, this length method returns distance in float. # we're gonna use this value for calculating player analog stick - distance = difference.length() - + distance = difference.length(); + # shoot a random BallType - self.upgrade_ball_type(choice(self.ball_type_dist)) - + self.upgrade_ball_type(choice(self.ball_type_dist)); + # and check the ball_type and upgrade it gravity_scale, texture, next ball speed. - self.check_ball_type(self.ball_type) - + self.check_ball_type(self.ball_type); + # For HARD ball i am just focusing on player analog stick facing direction. # Not very accurate and that's we need. if self.ball_type == BallType.HARD: - self.calculate_player_analog_stick(target_player, distance) + self.calculate_player_analog_stick(target_player, distance); else: - self.player_facing_direction = [0.0, 0.0] - - pos = self.node.position - + self.player_facing_direction = [0.0, 0.0]; + + pos = self.node.position; + if self.ball_type == BallType.MEDIUM or self.ball_type == BallType.HARD: # Target head by increasing Y pos. # How this work? cause ball gravity_scale is ...... - pos = (pos[0], pos[1]+.25, pos[2]) - + pos = (pos[0], pos[1]+.25, pos[2]); + # ball is generating.. ball = Ball( - position=pos, - velocity=(0.0, 0.0, 0.0), - texture=self.ball_tex, - gravity_scale=self.ball_gravity, - body_scale=1.0, - ).autoretain() - + position = pos, + velocity = (0.0, 0.0, 0.0), + texture = self.ball_tex, + gravity_scale = self.ball_gravity, + body_scale = 1.0, + ).autoretain(); + # shoot Animation and sound. - self.shoot_animation() - + self.shoot_animation(); + # force the shoot speed if player try to go inside the red circle. if self.force_shoot_speed != 0.0: - self.shoot_speed = self.force_shoot_speed - + self.shoot_speed = self.force_shoot_speed; + # push the ball to the player ball.node.handlemessage( - 'impulse', + 'impulse', self.node.position[0], # ball spawn position X self.node.position[1], # Y self.node.position[2], # Z - 0, 0, 0, # velocity x,y,z - self.ball_mag, # magnetude - 0.000, # magnetude velocity + 0, 0, 0, # velocity x,y,z + self.ball_mag, # magnetude + 0.000, # magnetude velocity 0.000, # radius 0.000, # idk - difference[0] + self.player_facing_direction[0], # force direction X - difference[1], # force direction Y - difference[2] + self.player_facing_direction[1], # force direction Z - ) + difference[0] + self.player_facing_direction[0], # force direction X + difference[1] , # force direction Y + difference[2] + self.player_facing_direction[1], # force direction Z + ); # creating our timer and shoot the ball again.(and we create a loop) - self.shoot_timer = ba.Timer(self.shoot_speed, self.start_shoot) - + self.shoot_timer = bs.Timer(self.shoot_speed, self.start_shoot); + def upgrade_ball_type(self, ball_type: BallType) -> NoReturn: - - self.ball_type = ball_type + + self.ball_type = ball_type; def check_ball_type(self, ball_type: BallType) -> NoReturn: - - if ball_type == BallType.EASY: - self.shoot_speed = 0.8 - self.ball_gravity = 1.0 - # next ball shoot speed - self.ball_mag = 3000 - # box light color and ball tex - self.light.color = (1.0, 1.0, 0.0) - self.ball_tex = ba.gettexture('egg4') - elif ball_type == BallType.MEDIUM: - self.ball_mag = 3000 - # decrease the gravity scale so, ball shoot without falling and straight. - self.ball_gravity = 0.0 - # next ball shoot speed. - self.shoot_speed = 0.4 - # box light color and ball tex. - self.light.color = (1.0, 0.0, 1.0) - self.ball_tex = ba.gettexture('egg3') - elif ball_type == BallType.HARD: - self.ball_mag = 2500 - self.ball_gravity = 0.0 - # next ball shoot speed. - self.shoot_speed = 0.6 - # box light color and ball tex. - self.light.color = (1.0, 0.2, 1.0) - self.ball_tex = ba.gettexture('egg1') - + + if ball_type == BallType.EASY: + self.shoot_speed = 0.8; + self.ball_gravity = 1.0; + # next ball shoot speed + self.ball_mag = 3000; + # box light color and ball tex + self.light.color = (1.0, 1.0, 0.0); + self.ball_tex = bs.gettexture('egg4'); + elif ball_type == BallType.MEDIUM: + self.ball_mag = 3000; + # decrease the gravity scale so, ball shoot without falling and straight. + self.ball_gravity = 0.0; + # next ball shoot speed. + self.shoot_speed = 0.4; + # box light color and ball tex. + self.light.color = (1.0, 0.0, 1.0); + self.ball_tex = bs.gettexture('egg3'); + elif ball_type == BallType.HARD: + self.ball_mag = 2500; + self.ball_gravity = 0.0; + # next ball shoot speed. + self.shoot_speed = 0.6; + # box light color and ball tex. + self.light.color = (1.0, 0.2, 1.0); + self.ball_tex = bs.gettexture('egg1'); + def shoot_animation(self) -> NoReturn: - - ba.animate( + + bs.animate( self.node, - "model_scale", { + "mesh_scale",{ 0.00: 1.4, 0.05: 1.7, 0.10: 1.4, } - ) + ); # playing shoot sound. - ba.playsound(self.shoot_sound, position=self.node.position) - - def highlight_target_player(self, player: ba.Player) -> NoReturn: + # self.shoot_sound, position = self.node.position.play(); + self.shoot_sound.play() + + def highlight_target_player(self, player: bs.Player) -> NoReturn: + # adding light - light = ba.newnode( + light = bs.newnode( "light", - owner=self.node, + owner = self.node, attrs={ - 'radius': 0.0, - 'intensity': 1.0, - 'color': (1.0, 0.0, 0.0), - } - ) - ba.animate( - light, - "radius", { - 0.05: 0.02, - 0.10: 0.07, - 0.15: 0.15, - 0.20: 0.13, - 0.25: 0.10, - 0.30: 0.05, - 0.35: 0.02, - 0.40: 0.00, + 'radius':0.0, + 'intensity':1.0, + 'color': (1.0, 0.0, 0.0), } - ) + ); + bs.animate( + light, + "radius",{ + 0.05: 0.02, + 0.10: 0.07, + 0.15: 0.15, + 0.20: 0.13, + 0.25: 0.10, + 0.30: 0.05, + 0.35: 0.02, + 0.40: 0.00, + } + ); # And a circle outline with ugly animation. - circle_outline = ba.newnode( + circle_outline = bs.newnode( "locator", - owner=player.actor.node, + owner = player.actor.node, attrs={ 'shape': 'circleOutline', 'color': (1.0, 0.0, 0.0), @@ -384,279 +385,277 @@ def highlight_target_player(self, player: ba.Player) -> NoReturn: 'draw_beauty': False, 'additive': True, }, - ) - ba.animate_array( + ); + bs.animate_array( circle_outline, - 'size', + 'size', 1, { - 0.05: [0.5], - 0.10: [0.8], - 0.15: [1.5], - 0.20: [2.0], - 0.25: [1.8], - 0.30: [1.3], - 0.35: [0.6], - 0.40: [0.0], - } - ) - + 0.05: [0.5], + 0.10: [0.8], + 0.15: [1.5], + 0.20: [2.0], + 0.25: [1.8], + 0.30: [1.3], + 0.35: [0.6], + 0.40: [0.0], + } + ); + # coonect it and... - player.actor.node.connectattr("position", light, "position") - player.actor.node.connectattr("position", circle_outline, "position") - + player.actor.node.connectattr("position", light, "position"); + player.actor.node.connectattr("position", circle_outline, "position"); + # immediately delete the node after another player has been targeted. - self.shoot_speed = 0.5 if self.shoot_speed == 0.0 else self.shoot_speed - ba.timer(self.shoot_speed, light.delete) - ba.timer(self.shoot_speed, circle_outline.delete) - - def calculate_player_analog_stick(self, player: ba.Player, distance: float) -> NoReturn: + self.shoot_speed = 0.5 if self.shoot_speed == 0.0 else self.shoot_speed; + bs.timer(self.shoot_speed, light.delete); + bs.timer(self.shoot_speed, circle_outline.delete); + + def calculate_player_analog_stick(self, player:bs.Player, distance: float) -> NoReturn: # at first i was very confused how i can read the player analog stick \ # then i saw TheMikirog#1984 autorun plugin code. # and i got it how analog stick values are works. # just need to store analog stick facing direction and need some calculation according how far player pushed analog stick. # Notice that how vertical direction is inverted, so we need to put a minus infront of veriable.(so ball isn't shoot at wrong direction). - self.player_facing_direction[0] = player.actor.node.move_left_right - self.player_facing_direction[1] = -player.actor.node.move_up_down - + self.player_facing_direction[0] = player.actor.node.move_left_right; + self.player_facing_direction[1] = -player.actor.node.move_up_down; + # if player is too close and the player pushing his analog stick fully the ball shoot's too far away to player. # so, we need to reduce the value of "self.player_facing_direction" to fix this problem. if distance <= 3: - self.player_facing_direction[0] = 0.4 if self.player_facing_direction[0] > 0 else -0.4 - self.player_facing_direction[1] = 0.4 if self.player_facing_direction[0] > 0 else -0.4 + self.player_facing_direction[0] = 0.4 if self.player_facing_direction[0] > 0 else -0.4; + self.player_facing_direction[1] = 0.4 if self.player_facing_direction[0] > 0 else -0.4; # same problem to long distance but in reverse, the ball can't reach to the player, # its because player analog stick value is between 1 and -1, # and this value is low to shoot ball forward to Player if player is too far from the box. # so. let's increase to 1.5 if player pushed analog stick fully. elif distance > 6.5: # So many calculation according to how analog stick pushed by player. - # Horizontal(left-right) calculation + # Horizontal(left-right) calculation if self.player_facing_direction[0] > 0.4: - self.player_facing_direction[0] = 1.5 + self.player_facing_direction[0] = 1.5; elif self.player_facing_direction[0] < -0.4: - self.player_facing_direction[0] = -1.5 + self.player_facing_direction[0] = -1.5; else: if self.player_facing_direction[0] > 0.0: - self.player_facing_direction[0] = 0.2 + self.player_facing_direction[0] = 0.2; elif self.player_facing_direction[0] < 0.0: - self.player_facing_direction[0] = -0.2 + self.player_facing_direction[0] = -0.2; else: - self.player_facing_direction[0] = 0.0 - + self.player_facing_direction[0] = 0.0; + # Vertical(up-down) calculation. if self.player_facing_direction[1] > 0.4: - self.player_facing_direction[1] = 1.5 + self.player_facing_direction[1] = 1.5; elif self.player_facing_direction[1] < -0.4: - self.player_facing_direction[1] = -1.5 + self.player_facing_direction[1] = -1.5; else: if self.player_facing_direction[1] > 0.0: - self.player_facing_direction[1] = 0.2 + self.player_facing_direction[1] = 0.2; elif self.player_facing_direction[1] < 0.0: - self.player_facing_direction[1] = -0.2 + self.player_facing_direction[1] = -0.2; else: - self.player_facing_direction[1] = -0.0 - + self.player_facing_direction[1] = -0.0; + # if we want stop the ball shootes def stop_shoot(self) -> NoReturn: - # Kill the timer. - self.shoot_timer = None - + # Kill the timer. + self.shoot_timer = None; + -class Player(ba.Player['Team']): +class Player(bs.Player['Team']): """Our player type for this game.""" -class Team(ba.Team[Player]): +class Team(bs.Team[Player]): """Our team type for this game.""" # almost 80 % for game we done in box class. -# now remain things, like name, seetings, scoring, cooldonw, +# now remain things, like name, seetings, scoring, cooldonw, # and main thing don't allow player to camp inside of box are going in this class. -# ba_meta export game - - -class DodgeTheBall(ba.TeamGameActivity[Player, Team]): - +# ba_meta export bascenev1.GameActivity +class DodgeTheBall(bs.TeamGameActivity[Player, Team]): + # defining name, description and settings.. - name = 'Dodge the ball' - description = 'Survive from shooting balls' - + name = 'Dodge the ball'; + description = 'Survive from shooting balls'; + available_settings = [ - ba.IntSetting( + bs.IntSetting( 'Cooldown', - min_value=20, - default=45, - increment=5, + min_value = 20, + default = 45, + increment = 5, ), - ba.BoolSetting('Epic Mode', default=False) + bs.BoolSetting('Epic Mode', default=False) ] # Don't allow joining after we start. - allow_mid_activity_joins = False - + allow_mid_activity_joins = False; + @classmethod - def supports_session_type(cls, sessiontype: type[ba.Session]) -> bool: + def supports_session_type(cls, sessiontype: type[bs.Session]) -> bool: # We support team and ffa sessions. - return issubclass(sessiontype, ba.FreeForAllSession) or issubclass( - sessiontype, ba.DualTeamSession, - ) - + return issubclass(sessiontype, bs.FreeForAllSession) or issubclass( + sessiontype, bs.DualTeamSession, + ); + @classmethod - def get_supported_maps(cls, sessiontype: type[ba.Session]) -> list[str]: + def get_supported_maps(cls, sessiontype: type[bs.Session]) -> list[str]: # This Game mode need a flat and perfect shape map where can player fall outside map. # bombsquad have "Doom Shroom" map. # Not perfect map for this game mode but its fine for this gamemode. # the problem is that Doom Shroom is not a perfect circle and not flat also. - return ['Doom Shroom'] - + return ['Doom Shroom']; + def __init__(self, settings: dict): - super().__init__(settings) - self._epic_mode = bool(settings['Epic Mode']) - self.countdown_time = int(settings['Cooldown']) - - self.check_player_pos_timer: ba.Timer | None = None - self.shield_drop_timer: ba.Timer | None = None + super().__init__(settings); + self._epic_mode = bool(settings['Epic Mode']); + self.countdown_time = int(settings['Cooldown']); + + self.check_player_pos_timer: bs.Timer | None = None; + self.shield_drop_timer: bs.Timer | None = None; # cooldown and Box - self._countdown: OnScreenCountdown | None = None - self.box: Box | None = None - + self._countdown: OnScreenCountdown | None = None; + self.box: Box | None = None; + # this lists for scoring. - self.joined_player_list: list[ba.Player] = [] - self.dead_player_list: list[ba.Player] = [] - + self.joined_player_list: list[bs.Player] = []; + self.dead_player_list: list[bs.Player] = []; + # normally play RUN AWAY music cause is match with our gamemode at.. my point, # but in epic switch to EPIC. - self.slow_motion = self._epic_mode + self.slow_motion = self._epic_mode; self.default_music = ( - ba.MusicType.EPIC if self._epic_mode else ba.MusicType.RUN_AWAY - ) - + bs.MusicType.EPIC if self._epic_mode else bs.MusicType.RUN_AWAY + ); + def get_instance_description(self) -> str | Sequence: - return 'Keep away as possible as you can' - + return 'Keep away as possible as you can'; + # add a tiny text under our game name. def get_instance_description_short(self) -> str | Sequence: - return 'Dodge the shooting balls' + return 'Dodge the shooting balls'; def on_begin(self) -> NoReturn: - super().on_begin() - + super().on_begin(); + # spawn our box at middle of the map self.box = Box( position=(0.5, 2.7, -3.9), velocity=(0.0, 0.0, 0.0), - ).autoretain() - - # create our cooldown + ).autoretain(); + + # create our cooldown self._countdown = OnScreenCountdown( - duration=self.countdown_time, - endcall=self.play_victory_sound_and_end, - ) - + duration = self.countdown_time, + endcall = self.play_victory_sound_and_end, + ); + # and starts the cooldown and shootes. - ba.timer(5.0, self._countdown.start) - ba.timer(5.0, self.box.start_shoot) - + bs.timer(5.0, self._countdown.start); + bs.timer(5.0, self.box.start_shoot); + # start checking all player pos. - ba.timer(5.0, self.check_player_pos) - + bs.timer(5.0, self.check_player_pos); + # drop shield every ten Seconds # need five seconds delay Because shootes start after 5 seconds. - ba.timer(15.0, self.drop_shield) - + bs.timer(15.0, self.drop_shield); + # This function returns all alive players in game. # i thinck you see this function in Box class. - def get_alive_players(self) -> Sequence[ba.Player]: - - alive_players = [] - + def get_alive_players(self) -> Sequence[bs.Player]: + + alive_players = []; + for team in self.teams: for player in team.players: if player.is_alive(): - alive_players.append(player) - - return alive_players - + alive_players.append(player); + + return alive_players; + # let's disallowed camping inside of box by doing a blast and increasing ball shoot speed. def check_player_pos(self): - + for player in self.get_alive_players(): - - # same logic as applied for the ball - difference = ba.Vec3(player.position) - ba.Vec3(self.box.node.position) - - distance = difference.length() - - if distance < 3: - self.box.force_shoot_speed = 0.2 - else: - self.box.force_shoot_speed = 0.0 - - if distance < 0.5: - Blast( - position=self.box.node.position, - velocity=self.box.node.velocity, - blast_type='normal', - blast_radius=1.0, - ).autoretain() - - PopupText( - position=self.box.node.position, - text='Keep away from me', - random_offset=0.0, - scale=2.0, - color=self.box.light.color, - ).autoretain() - + + # same logic as applied for the ball + difference = babase.Vec3(player.position) - babase.Vec3(self.box.node.position); + + distance = difference.length(); + + if distance < 3: + self.box.force_shoot_speed = 0.2; + else: + self.box.force_shoot_speed = 0.0; + + if distance < 0.5: + Blast( + position = self.box.node.position, + velocity = self.box.node.velocity, + blast_type = 'normal', + blast_radius = 1.0, + ).autoretain(); + + PopupText( + position = self.box.node.position, + text = 'Keep away from me', + random_offset = 0.0, + scale = 2.0, + color = self.box.light.color, + ).autoretain(); + # create our timer and start looping it - self.check_player_pos_timer = ba.Timer(0.1, self.check_player_pos) - + self.check_player_pos_timer = bs.Timer(0.1, self.check_player_pos); + # drop useless shield's too give player temptation. def drop_shield(self) -> NoReturn: - - pos = self.box.node.position - - PowerupBox( - position=(pos[0] + 4.0, pos[1] + 3.0, pos[2]), - poweruptype='shield', - ).autoretain() - - PowerupBox( - position=(pos[0] - 4.0, pos[1] + 3.0, pos[2]), - poweruptype='shield', - ).autoretain() - - self.shield_drop_timer = ba.Timer(10.0, self.drop_shield) - + + pos = self.box.node.position; + + PowerupBox( + position = (pos[0] + 4.0, pos[1] + 3.0, pos[2]), + poweruptype = 'shield', + ).autoretain(); + + PowerupBox( + position = (pos[0] - 4.0, pos[1] + 3.0, pos[2]), + poweruptype = 'shield', + ).autoretain(); + + self.shield_drop_timer = bs.Timer(10.0, self.drop_shield); + # when cooldown time up i don't want that the game end immediately. def play_victory_sound_and_end(self) -> NoReturn: - + # kill timers - self.box.stop_shoot() + self.box.stop_shoot(); self.check_player_pos_timer = None self.shield_drop_timer = None - ba.timer(2.0, self.end_game) - + bs.timer(2.0, self.end_game); + # this function runs when A player spawn in map def spawn_player(self, player: Player) -> NoReturn: - spaz = self.spawn_player_spaz(player) + spaz = self.spawn_player_spaz(player); # reconnect this player's controls. # without bomb, punch and pickup. spaz.connect_controls_to_player( enable_punch=False, enable_bomb=False, enable_pickup=False, - ) - + ); + # storing all players for ScorinG. - self.joined_player_list.append(player) - + self.joined_player_list.append(player); + # Also lets have them make some noise when they die. - spaz.play_big_death_sound = True - + spaz.play_big_death_sound = True; + # very helpful function to check end game when player dead or leav. def _check_end_game(self) -> bool: - + living_team_count = 0 for team in self.teams: for player in team.players: @@ -674,51 +673,51 @@ def _check_end_game(self) -> bool: # this function called when player leave. def on_player_leave(self, player: Player) -> NoReturn: # Augment default behavior. - super().on_player_leave(player) + super().on_player_leave(player); # checking end game. - self._check_end_game() + self._check_end_game(); # this gamemode needs to handle only one msg "PlayerDiedMessage". def handlemessage(self, msg: Any) -> Any: - - if isinstance(msg, ba.PlayerDiedMessage): + + if isinstance(msg, bs.PlayerDiedMessage): # Augment standard behavior. - super().handlemessage(msg) - + super().handlemessage(msg); + # and storing the dead player records in our dead_player_list. - self.dead_player_list.append(msg.getplayer(Player)) - + self.dead_player_list.append(msg.getplayer(Player)); + # check the end game. - ba.timer(1.0, self._check_end_game) - + bs.timer(1.0, self._check_end_game); + def end_game(self): # kill timers self.box.stop_shoot() self.check_player_pos_timer = None self.shield_drop_timer = None - + # here the player_dead_list and joined_player_list gonna be very helpful. for team in self.teams: for player in team.players: - + # for scoring i am just following the index of the player_dead_list. # for dead list... # 0th index player dead first. # 1st index player dead second. # and so on... - # i think you got it... maybe + # i think you got it... maybe # sometime we also got a empty list # if we got a empty list that means all players are survived or maybe only one player playing and he/she survived. if len(self.dead_player_list) > 0: - + for index, dead_player in enumerate(self.dead_player_list): # if this condition is true we find the dead player \ # and his index with enumerate function. if player == dead_player: # updating with one, because i don't want to give 0 score to first dead player. - index += 1 + index += 1 break # and if this statement is true we just find a survived player. # for survived player i am giving the highest score according to how many players are joined. @@ -727,39 +726,41 @@ def end_game(self): # for survived player i am giving the highest score according to how many players are joined. else: index = len(self.joined_player_list) - + # and here i am following Table of 10 for scoring. # very lazY. score = int(10 * index) - + self.stats.player_scored(player, score, screenmessage=False) # Ok now calc game results: set a score for each team and then tell \ # the game to end. - results = ba.GameResults() + results = bs.GameResults() # Remember that 'free-for-all' mode is simply a special form \ # of 'teams' mode where each player gets their own team, so we can \ # just always deal in teams and have all cases covered. # hmmm... some eric comments might be helpful to you. for team in self.teams: - + max_index = 0 for player in team.players: - # for the team, we choose only one player who survived longest. - # same logic.. - if len(self.dead_player_list) > 0: + # for the team, we choose only one player who survived longest. + # same logic.. + if len(self.dead_player_list) > 0: for index, dead_player in enumerate(self.dead_player_list): if player == dead_player: index += 1 break elif index == len(self.dead_player_list) - 1: index = len(self.joined_player_list) - else: + else: index = len(self.joined_player_list) - - max_index = max(max_index, index) + + max_index = max(max_index, index) # set the team score - results.set_team_score(team, int(10 * max_index)) + results.set_team_score(team, int(10 * max_index)) # and end the game self.end(results=results) + + \ No newline at end of file From 4fb675cff672b0a3cfc3884b4897e7b479c286d8 Mon Sep 17 00:00:00 2001 From: SenjuZoro Date: Sun, 23 Jul 2023 12:05:54 +0000 Subject: [PATCH 0592/1464] [ci] auto-format --- plugins/minigames/dodge_the_ball.py | 708 ++++++++++++++-------------- 1 file changed, 355 insertions(+), 353 deletions(-) diff --git a/plugins/minigames/dodge_the_ball.py b/plugins/minigames/dodge_the_ball.py index 7d1648d6..2bb1d921 100644 --- a/plugins/minigames/dodge_the_ball.py +++ b/plugins/minigames/dodge_the_ball.py @@ -13,7 +13,7 @@ import babase import bauiv1 as bui import bascenev1 as bs -from random import choice +from random import choice from enum import Enum from bascenev1lib.actor.bomb import Blast from bascenev1lib.actor.popuptext import PopupText @@ -41,28 +41,31 @@ class BallType(Enum): # increase the next ball speed but less than MEDIUM. # Ball color is crimson(purple+red = pinky color type). -# this dict decide the ball_type spawning rate like powerup box + +# this dict decide the ball_type spawning rate like powerup box ball_type_dict: dict[BallType, int] = { BallType.EASY: 3, BallType.MEDIUM: 2, BallType.HARD: 1, -}; +} + class Ball(bs.Actor): """ Shooting Ball """ - def __init__(self, - position: Sequence[float], - velocity: Sequence[float], - texture: babase.Texture, - body_scale: float = 1.0, - gravity_scale: float = 1.0, - ) -> NoReturn: - - super().__init__(); - - shared = SharedObjects.get(); - - ball_material = bs.Material(); + + def __init__(self, + position: Sequence[float], + velocity: Sequence[float], + texture: babase.Texture, + body_scale: float = 1.0, + gravity_scale: float = 1.0, + ) -> NoReturn: + + super().__init__() + + shared = SharedObjects.get() + + ball_material = bs.Material() ball_material.add_actions( conditions=( ( @@ -74,8 +77,8 @@ def __init__(self, ('they_have_material', shared.object_material), ), actions=('modify_node_collision', 'collide', False), - ); - + ) + self.node = bs.newnode( 'prop', delegate=self, @@ -88,37 +91,37 @@ def __init__(self, 'mesh_scale': body_scale, 'color_texture': texture, 'gravity_scale': gravity_scale, - 'density': 4.0, # increase density of ball so ball collide with player with heavy force. # ammm very bad grammer + 'density': 4.0, # increase density of ball so ball collide with player with heavy force. # ammm very bad grammer 'materials': (ball_material,), - }, - ); - + }, + ) + # die the ball manually incase the ball doesn't fall the outside of the map - bs.timer(2.5, bs.WeakCall(self.handlemessage, bs.DieMessage())); - + bs.timer(2.5, bs.WeakCall(self.handlemessage, bs.DieMessage())) + # i am not handling anything in this ball Class(except for diemessage). # all game things and logics going to be in the box class def handlemessage(self, msg: Any) -> Any: - + if isinstance(msg, bs.DieMessage): - self.node.delete(); + self.node.delete() else: - super().handlemessage(msg); - - + super().handlemessage(msg) + + class Box(bs.Actor): """ A box that spawn midle of map as a decoration perpose """ - - def __init__(self, - position: Sequence[float], - velocity: Sequence[float], - ) -> NoReturn: - - super().__init__(); - - shared = SharedObjects.get(); + + def __init__(self, + position: Sequence[float], + velocity: Sequence[float], + ) -> NoReturn: + + super().__init__() + + shared = SharedObjects.get() # self.ball_jump = 0.0; - no_hit_material = bs.Material(); + no_hit_material = bs.Material() # we don't need that the box was move and collide with objects. no_hit_material.add_actions( conditions=( @@ -127,7 +130,7 @@ def __init__(self, ('they_have_material', shared.attack_material), ), actions=('modify_part_collision', 'collide', False), - ); + ) no_hit_material.add_actions( conditions=( @@ -139,8 +142,8 @@ def __init__(self, ('modify_part_collision', 'collide', False), ('modify_part_collision', 'physical', False), ), - ); - + ) + self.node = bs.newnode( 'prop', delegate=self, @@ -156,26 +159,26 @@ def __init__(self, 'reflection': 'powerup', 'reflection_scale': [1.0], 'materials': (no_hit_material,), - }, - ); + }, + ) # light self.light = bs.newnode( "light", - owner = self.node, + owner=self.node, attrs={ - 'radius' : 0.2, - 'intensity' : 0.8, - 'color': (0.0, 1.0, 0.0), + 'radius': 0.2, + 'intensity': 0.8, + 'color': (0.0, 1.0, 0.0), } - ); - self.node.connectattr("position", self.light, "position"); - # Drawing circle and circleOutline in radius of 3, - # so player can see that how close he is to the box. - # If player is inside this circle the ball speed will increase. + ) + self.node.connectattr("position", self.light, "position") + # Drawing circle and circleOutline in radius of 3, + # so player can see that how close he is to the box. + # If player is inside this circle the ball speed will increase. circle = bs.newnode( "locator", - owner = self.node, - attrs = { + owner=self.node, + attrs={ 'shape': 'circle', 'color': (1.0, 0.0, 0.0), 'opacity': 0.1, @@ -184,12 +187,12 @@ def __init__(self, 'additive': True, }, ) - self.node.connectattr("position", circle, "position"); + self.node.connectattr("position", circle, "position") # also adding a outline cause its look nice. circle_outline = bs.newnode( "locator", - owner = self.node, - attrs = { + owner=self.node, + attrs={ 'shape': 'circleOutline', 'color': (1.0, 1.0, 0.0), 'opacity': 0.1, @@ -197,187 +200,186 @@ def __init__(self, 'draw_beauty': False, 'additive': True, }, - ); - self.node.connectattr("position", circle_outline, "position"); - + ) + self.node.connectattr("position", circle_outline, "position") + # all ball attribute that we need. - self.ball_type: BallType = BallType.EASY; - self.shoot_timer: bs.Timer | None = None; - self.shoot_speed: float = 0.0; + self.ball_type: BallType = BallType.EASY + self.shoot_timer: bs.Timer | None = None + self.shoot_speed: float = 0.0 # this force the shoot if player is inside the red circle. - self.force_shoot_speed: float = 0.0; - self.ball_mag = 3000; - self.ball_gravity: float = 1.0; - self.ball_tex: babase.Texture | None = None; - # only for Hard ball_type - self.player_facing_direction: list[float, float] = [0.0, 0.0]; + self.force_shoot_speed: float = 0.0 + self.ball_mag = 3000 + self.ball_gravity: float = 1.0 + self.ball_tex: babase.Texture | None = None + # only for Hard ball_type + self.player_facing_direction: list[float, float] = [0.0, 0.0] # ball shoot soound. - self.shoot_sound = bs.getsound('laserReverse'); - - # same as "powerupdist" - self.ball_type_dist: list[BallType] = []; + self.shoot_sound = bs.getsound('laserReverse') + + # same as "powerupdist" + self.ball_type_dist: list[BallType] = [] for ball in ball_type_dict: for _ in range(ball_type_dict[ball]): - self.ball_type_dist.append(ball); - + self.ball_type_dist.append(ball) + # Here main logic of game goes here. # like shoot balls, shoot speed, anything we want goes here(except for some thing). def start_shoot(self) -> NoReturn: - + # getting all allive players in a list. - alive_players_list = self.activity.get_alive_players(); - + alive_players_list = self.activity.get_alive_players() + # make sure that list is not Empty. if len(alive_players_list) > 0: - + # choosing a random player from list. - target_player = choice(alive_players_list); - # highlight the target player - self.highlight_target_player(target_player); - + target_player = choice(alive_players_list) + # highlight the target player + self.highlight_target_player(target_player) + # to finding difference between player and box. # we just need to subtract player pos and ball pos. # Same logic as eric applied in Target Practice Gamemode. - difference = babase.Vec3(target_player.position) - babase.Vec3(self.node.position); - + difference = babase.Vec3(target_player.position) - babase.Vec3(self.node.position) + # discard Y position so ball shoot more straight. difference[1] = 0.0 - + # and now, this length method returns distance in float. # we're gonna use this value for calculating player analog stick - distance = difference.length(); - + distance = difference.length() + # shoot a random BallType - self.upgrade_ball_type(choice(self.ball_type_dist)); - + self.upgrade_ball_type(choice(self.ball_type_dist)) + # and check the ball_type and upgrade it gravity_scale, texture, next ball speed. - self.check_ball_type(self.ball_type); - + self.check_ball_type(self.ball_type) + # For HARD ball i am just focusing on player analog stick facing direction. # Not very accurate and that's we need. if self.ball_type == BallType.HARD: - self.calculate_player_analog_stick(target_player, distance); + self.calculate_player_analog_stick(target_player, distance) else: - self.player_facing_direction = [0.0, 0.0]; - - pos = self.node.position; - + self.player_facing_direction = [0.0, 0.0] + + pos = self.node.position + if self.ball_type == BallType.MEDIUM or self.ball_type == BallType.HARD: # Target head by increasing Y pos. # How this work? cause ball gravity_scale is ...... - pos = (pos[0], pos[1]+.25, pos[2]); - + pos = (pos[0], pos[1]+.25, pos[2]) + # ball is generating.. ball = Ball( - position = pos, - velocity = (0.0, 0.0, 0.0), - texture = self.ball_tex, - gravity_scale = self.ball_gravity, - body_scale = 1.0, - ).autoretain(); - + position=pos, + velocity=(0.0, 0.0, 0.0), + texture=self.ball_tex, + gravity_scale=self.ball_gravity, + body_scale=1.0, + ).autoretain() + # shoot Animation and sound. - self.shoot_animation(); - + self.shoot_animation() + # force the shoot speed if player try to go inside the red circle. if self.force_shoot_speed != 0.0: - self.shoot_speed = self.force_shoot_speed; - + self.shoot_speed = self.force_shoot_speed + # push the ball to the player ball.node.handlemessage( - 'impulse', + 'impulse', self.node.position[0], # ball spawn position X self.node.position[1], # Y self.node.position[2], # Z - 0, 0, 0, # velocity x,y,z - self.ball_mag, # magnetude - 0.000, # magnetude velocity + 0, 0, 0, # velocity x,y,z + self.ball_mag, # magnetude + 0.000, # magnetude velocity 0.000, # radius 0.000, # idk - difference[0] + self.player_facing_direction[0], # force direction X - difference[1] , # force direction Y - difference[2] + self.player_facing_direction[1], # force direction Z - ); + difference[0] + self.player_facing_direction[0], # force direction X + difference[1], # force direction Y + difference[2] + self.player_facing_direction[1], # force direction Z + ) # creating our timer and shoot the ball again.(and we create a loop) - self.shoot_timer = bs.Timer(self.shoot_speed, self.start_shoot); - + self.shoot_timer = bs.Timer(self.shoot_speed, self.start_shoot) + def upgrade_ball_type(self, ball_type: BallType) -> NoReturn: - - self.ball_type = ball_type; + + self.ball_type = ball_type def check_ball_type(self, ball_type: BallType) -> NoReturn: - - if ball_type == BallType.EASY: - self.shoot_speed = 0.8; - self.ball_gravity = 1.0; - # next ball shoot speed - self.ball_mag = 3000; - # box light color and ball tex - self.light.color = (1.0, 1.0, 0.0); - self.ball_tex = bs.gettexture('egg4'); - elif ball_type == BallType.MEDIUM: - self.ball_mag = 3000; - # decrease the gravity scale so, ball shoot without falling and straight. - self.ball_gravity = 0.0; - # next ball shoot speed. - self.shoot_speed = 0.4; - # box light color and ball tex. - self.light.color = (1.0, 0.0, 1.0); - self.ball_tex = bs.gettexture('egg3'); - elif ball_type == BallType.HARD: - self.ball_mag = 2500; - self.ball_gravity = 0.0; - # next ball shoot speed. - self.shoot_speed = 0.6; - # box light color and ball tex. - self.light.color = (1.0, 0.2, 1.0); - self.ball_tex = bs.gettexture('egg1'); - + + if ball_type == BallType.EASY: + self.shoot_speed = 0.8 + self.ball_gravity = 1.0 + # next ball shoot speed + self.ball_mag = 3000 + # box light color and ball tex + self.light.color = (1.0, 1.0, 0.0) + self.ball_tex = bs.gettexture('egg4') + elif ball_type == BallType.MEDIUM: + self.ball_mag = 3000 + # decrease the gravity scale so, ball shoot without falling and straight. + self.ball_gravity = 0.0 + # next ball shoot speed. + self.shoot_speed = 0.4 + # box light color and ball tex. + self.light.color = (1.0, 0.0, 1.0) + self.ball_tex = bs.gettexture('egg3') + elif ball_type == BallType.HARD: + self.ball_mag = 2500 + self.ball_gravity = 0.0 + # next ball shoot speed. + self.shoot_speed = 0.6 + # box light color and ball tex. + self.light.color = (1.0, 0.2, 1.0) + self.ball_tex = bs.gettexture('egg1') + def shoot_animation(self) -> NoReturn: - + bs.animate( self.node, - "mesh_scale",{ + "mesh_scale", { 0.00: 1.4, 0.05: 1.7, 0.10: 1.4, } - ); + ) # playing shoot sound. # self.shoot_sound, position = self.node.position.play(); self.shoot_sound.play() - def highlight_target_player(self, player: bs.Player) -> NoReturn: - + # adding light light = bs.newnode( "light", - owner = self.node, + owner=self.node, attrs={ - 'radius':0.0, - 'intensity':1.0, - 'color': (1.0, 0.0, 0.0), + 'radius': 0.0, + 'intensity': 1.0, + 'color': (1.0, 0.0, 0.0), } - ); + ) bs.animate( - light, - "radius",{ - 0.05: 0.02, - 0.10: 0.07, - 0.15: 0.15, - 0.20: 0.13, - 0.25: 0.10, - 0.30: 0.05, - 0.35: 0.02, - 0.40: 0.00, - } - ); + light, + "radius", { + 0.05: 0.02, + 0.10: 0.07, + 0.15: 0.15, + 0.20: 0.13, + 0.25: 0.10, + 0.30: 0.05, + 0.35: 0.02, + 0.40: 0.00, + } + ) # And a circle outline with ugly animation. circle_outline = bs.newnode( "locator", - owner = player.actor.node, + owner=player.actor.node, attrs={ 'shape': 'circleOutline', 'color': (1.0, 0.0, 0.0), @@ -385,82 +387,82 @@ def highlight_target_player(self, player: bs.Player) -> NoReturn: 'draw_beauty': False, 'additive': True, }, - ); + ) bs.animate_array( circle_outline, - 'size', + 'size', 1, { - 0.05: [0.5], - 0.10: [0.8], - 0.15: [1.5], - 0.20: [2.0], - 0.25: [1.8], - 0.30: [1.3], - 0.35: [0.6], - 0.40: [0.0], - } - ); - + 0.05: [0.5], + 0.10: [0.8], + 0.15: [1.5], + 0.20: [2.0], + 0.25: [1.8], + 0.30: [1.3], + 0.35: [0.6], + 0.40: [0.0], + } + ) + # coonect it and... - player.actor.node.connectattr("position", light, "position"); - player.actor.node.connectattr("position", circle_outline, "position"); - + player.actor.node.connectattr("position", light, "position") + player.actor.node.connectattr("position", circle_outline, "position") + # immediately delete the node after another player has been targeted. - self.shoot_speed = 0.5 if self.shoot_speed == 0.0 else self.shoot_speed; - bs.timer(self.shoot_speed, light.delete); - bs.timer(self.shoot_speed, circle_outline.delete); - - def calculate_player_analog_stick(self, player:bs.Player, distance: float) -> NoReturn: + self.shoot_speed = 0.5 if self.shoot_speed == 0.0 else self.shoot_speed + bs.timer(self.shoot_speed, light.delete) + bs.timer(self.shoot_speed, circle_outline.delete) + + def calculate_player_analog_stick(self, player: bs.Player, distance: float) -> NoReturn: # at first i was very confused how i can read the player analog stick \ # then i saw TheMikirog#1984 autorun plugin code. # and i got it how analog stick values are works. # just need to store analog stick facing direction and need some calculation according how far player pushed analog stick. # Notice that how vertical direction is inverted, so we need to put a minus infront of veriable.(so ball isn't shoot at wrong direction). - self.player_facing_direction[0] = player.actor.node.move_left_right; - self.player_facing_direction[1] = -player.actor.node.move_up_down; - + self.player_facing_direction[0] = player.actor.node.move_left_right + self.player_facing_direction[1] = -player.actor.node.move_up_down + # if player is too close and the player pushing his analog stick fully the ball shoot's too far away to player. # so, we need to reduce the value of "self.player_facing_direction" to fix this problem. if distance <= 3: - self.player_facing_direction[0] = 0.4 if self.player_facing_direction[0] > 0 else -0.4; - self.player_facing_direction[1] = 0.4 if self.player_facing_direction[0] > 0 else -0.4; + self.player_facing_direction[0] = 0.4 if self.player_facing_direction[0] > 0 else -0.4 + self.player_facing_direction[1] = 0.4 if self.player_facing_direction[0] > 0 else -0.4 # same problem to long distance but in reverse, the ball can't reach to the player, # its because player analog stick value is between 1 and -1, # and this value is low to shoot ball forward to Player if player is too far from the box. # so. let's increase to 1.5 if player pushed analog stick fully. elif distance > 6.5: # So many calculation according to how analog stick pushed by player. - # Horizontal(left-right) calculation + # Horizontal(left-right) calculation if self.player_facing_direction[0] > 0.4: - self.player_facing_direction[0] = 1.5; + self.player_facing_direction[0] = 1.5 elif self.player_facing_direction[0] < -0.4: - self.player_facing_direction[0] = -1.5; + self.player_facing_direction[0] = -1.5 else: if self.player_facing_direction[0] > 0.0: - self.player_facing_direction[0] = 0.2; + self.player_facing_direction[0] = 0.2 elif self.player_facing_direction[0] < 0.0: - self.player_facing_direction[0] = -0.2; + self.player_facing_direction[0] = -0.2 else: - self.player_facing_direction[0] = 0.0; - + self.player_facing_direction[0] = 0.0 + # Vertical(up-down) calculation. if self.player_facing_direction[1] > 0.4: - self.player_facing_direction[1] = 1.5; + self.player_facing_direction[1] = 1.5 elif self.player_facing_direction[1] < -0.4: - self.player_facing_direction[1] = -1.5; + self.player_facing_direction[1] = -1.5 else: if self.player_facing_direction[1] > 0.0: - self.player_facing_direction[1] = 0.2; + self.player_facing_direction[1] = 0.2 elif self.player_facing_direction[1] < 0.0: - self.player_facing_direction[1] = -0.2; + self.player_facing_direction[1] = -0.2 else: - self.player_facing_direction[1] = -0.0; - + self.player_facing_direction[1] = -0.0 + # if we want stop the ball shootes def stop_shoot(self) -> NoReturn: - # Kill the timer. - self.shoot_timer = None; - + # Kill the timer. + self.shoot_timer = None + class Player(bs.Player['Team']): """Our player type for this game.""" @@ -470,192 +472,194 @@ class Team(bs.Team[Player]): """Our team type for this game.""" # almost 80 % for game we done in box class. -# now remain things, like name, seetings, scoring, cooldonw, +# now remain things, like name, seetings, scoring, cooldonw, # and main thing don't allow player to camp inside of box are going in this class. # ba_meta export bascenev1.GameActivity + + class DodgeTheBall(bs.TeamGameActivity[Player, Team]): - + # defining name, description and settings.. - name = 'Dodge the ball'; - description = 'Survive from shooting balls'; - + name = 'Dodge the ball' + description = 'Survive from shooting balls' + available_settings = [ bs.IntSetting( 'Cooldown', - min_value = 20, - default = 45, - increment = 5, + min_value=20, + default=45, + increment=5, ), bs.BoolSetting('Epic Mode', default=False) ] # Don't allow joining after we start. - allow_mid_activity_joins = False; - + allow_mid_activity_joins = False + @classmethod def supports_session_type(cls, sessiontype: type[bs.Session]) -> bool: # We support team and ffa sessions. return issubclass(sessiontype, bs.FreeForAllSession) or issubclass( sessiontype, bs.DualTeamSession, - ); - + ) + @classmethod def get_supported_maps(cls, sessiontype: type[bs.Session]) -> list[str]: # This Game mode need a flat and perfect shape map where can player fall outside map. # bombsquad have "Doom Shroom" map. # Not perfect map for this game mode but its fine for this gamemode. # the problem is that Doom Shroom is not a perfect circle and not flat also. - return ['Doom Shroom']; - + return ['Doom Shroom'] + def __init__(self, settings: dict): - super().__init__(settings); - self._epic_mode = bool(settings['Epic Mode']); - self.countdown_time = int(settings['Cooldown']); - - self.check_player_pos_timer: bs.Timer | None = None; - self.shield_drop_timer: bs.Timer | None = None; + super().__init__(settings) + self._epic_mode = bool(settings['Epic Mode']) + self.countdown_time = int(settings['Cooldown']) + + self.check_player_pos_timer: bs.Timer | None = None + self.shield_drop_timer: bs.Timer | None = None # cooldown and Box - self._countdown: OnScreenCountdown | None = None; - self.box: Box | None = None; - + self._countdown: OnScreenCountdown | None = None + self.box: Box | None = None + # this lists for scoring. - self.joined_player_list: list[bs.Player] = []; - self.dead_player_list: list[bs.Player] = []; - + self.joined_player_list: list[bs.Player] = [] + self.dead_player_list: list[bs.Player] = [] + # normally play RUN AWAY music cause is match with our gamemode at.. my point, # but in epic switch to EPIC. - self.slow_motion = self._epic_mode; + self.slow_motion = self._epic_mode self.default_music = ( bs.MusicType.EPIC if self._epic_mode else bs.MusicType.RUN_AWAY - ); - + ) + def get_instance_description(self) -> str | Sequence: - return 'Keep away as possible as you can'; - + return 'Keep away as possible as you can' + # add a tiny text under our game name. def get_instance_description_short(self) -> str | Sequence: - return 'Dodge the shooting balls'; + return 'Dodge the shooting balls' def on_begin(self) -> NoReturn: - super().on_begin(); - + super().on_begin() + # spawn our box at middle of the map self.box = Box( position=(0.5, 2.7, -3.9), velocity=(0.0, 0.0, 0.0), - ).autoretain(); - - # create our cooldown + ).autoretain() + + # create our cooldown self._countdown = OnScreenCountdown( - duration = self.countdown_time, - endcall = self.play_victory_sound_and_end, - ); - + duration=self.countdown_time, + endcall=self.play_victory_sound_and_end, + ) + # and starts the cooldown and shootes. - bs.timer(5.0, self._countdown.start); - bs.timer(5.0, self.box.start_shoot); - + bs.timer(5.0, self._countdown.start) + bs.timer(5.0, self.box.start_shoot) + # start checking all player pos. - bs.timer(5.0, self.check_player_pos); - + bs.timer(5.0, self.check_player_pos) + # drop shield every ten Seconds # need five seconds delay Because shootes start after 5 seconds. - bs.timer(15.0, self.drop_shield); - + bs.timer(15.0, self.drop_shield) + # This function returns all alive players in game. # i thinck you see this function in Box class. def get_alive_players(self) -> Sequence[bs.Player]: - - alive_players = []; - + + alive_players = [] + for team in self.teams: for player in team.players: if player.is_alive(): - alive_players.append(player); - - return alive_players; - + alive_players.append(player) + + return alive_players + # let's disallowed camping inside of box by doing a blast and increasing ball shoot speed. def check_player_pos(self): - + for player in self.get_alive_players(): - - # same logic as applied for the ball - difference = babase.Vec3(player.position) - babase.Vec3(self.box.node.position); - - distance = difference.length(); - - if distance < 3: - self.box.force_shoot_speed = 0.2; - else: - self.box.force_shoot_speed = 0.0; - - if distance < 0.5: - Blast( - position = self.box.node.position, - velocity = self.box.node.velocity, - blast_type = 'normal', - blast_radius = 1.0, - ).autoretain(); - - PopupText( - position = self.box.node.position, - text = 'Keep away from me', - random_offset = 0.0, - scale = 2.0, - color = self.box.light.color, - ).autoretain(); - + + # same logic as applied for the ball + difference = babase.Vec3(player.position) - babase.Vec3(self.box.node.position) + + distance = difference.length() + + if distance < 3: + self.box.force_shoot_speed = 0.2 + else: + self.box.force_shoot_speed = 0.0 + + if distance < 0.5: + Blast( + position=self.box.node.position, + velocity=self.box.node.velocity, + blast_type='normal', + blast_radius=1.0, + ).autoretain() + + PopupText( + position=self.box.node.position, + text='Keep away from me', + random_offset=0.0, + scale=2.0, + color=self.box.light.color, + ).autoretain() + # create our timer and start looping it - self.check_player_pos_timer = bs.Timer(0.1, self.check_player_pos); - + self.check_player_pos_timer = bs.Timer(0.1, self.check_player_pos) + # drop useless shield's too give player temptation. def drop_shield(self) -> NoReturn: - - pos = self.box.node.position; - - PowerupBox( - position = (pos[0] + 4.0, pos[1] + 3.0, pos[2]), - poweruptype = 'shield', - ).autoretain(); - - PowerupBox( - position = (pos[0] - 4.0, pos[1] + 3.0, pos[2]), - poweruptype = 'shield', - ).autoretain(); - - self.shield_drop_timer = bs.Timer(10.0, self.drop_shield); - + + pos = self.box.node.position + + PowerupBox( + position=(pos[0] + 4.0, pos[1] + 3.0, pos[2]), + poweruptype='shield', + ).autoretain() + + PowerupBox( + position=(pos[0] - 4.0, pos[1] + 3.0, pos[2]), + poweruptype='shield', + ).autoretain() + + self.shield_drop_timer = bs.Timer(10.0, self.drop_shield) + # when cooldown time up i don't want that the game end immediately. def play_victory_sound_and_end(self) -> NoReturn: - + # kill timers - self.box.stop_shoot(); + self.box.stop_shoot() self.check_player_pos_timer = None self.shield_drop_timer = None - bs.timer(2.0, self.end_game); - + bs.timer(2.0, self.end_game) + # this function runs when A player spawn in map def spawn_player(self, player: Player) -> NoReturn: - spaz = self.spawn_player_spaz(player); + spaz = self.spawn_player_spaz(player) # reconnect this player's controls. # without bomb, punch and pickup. spaz.connect_controls_to_player( enable_punch=False, enable_bomb=False, enable_pickup=False, - ); - + ) + # storing all players for ScorinG. - self.joined_player_list.append(player); - + self.joined_player_list.append(player) + # Also lets have them make some noise when they die. - spaz.play_big_death_sound = True; - + spaz.play_big_death_sound = True + # very helpful function to check end game when player dead or leav. def _check_end_game(self) -> bool: - + living_team_count = 0 for team in self.teams: for player in team.players: @@ -673,51 +677,51 @@ def _check_end_game(self) -> bool: # this function called when player leave. def on_player_leave(self, player: Player) -> NoReturn: # Augment default behavior. - super().on_player_leave(player); + super().on_player_leave(player) # checking end game. - self._check_end_game(); + self._check_end_game() # this gamemode needs to handle only one msg "PlayerDiedMessage". def handlemessage(self, msg: Any) -> Any: - + if isinstance(msg, bs.PlayerDiedMessage): # Augment standard behavior. - super().handlemessage(msg); - + super().handlemessage(msg) + # and storing the dead player records in our dead_player_list. - self.dead_player_list.append(msg.getplayer(Player)); - + self.dead_player_list.append(msg.getplayer(Player)) + # check the end game. - bs.timer(1.0, self._check_end_game); - + bs.timer(1.0, self._check_end_game) + def end_game(self): # kill timers self.box.stop_shoot() self.check_player_pos_timer = None self.shield_drop_timer = None - + # here the player_dead_list and joined_player_list gonna be very helpful. for team in self.teams: for player in team.players: - + # for scoring i am just following the index of the player_dead_list. # for dead list... # 0th index player dead first. # 1st index player dead second. # and so on... - # i think you got it... maybe + # i think you got it... maybe # sometime we also got a empty list # if we got a empty list that means all players are survived or maybe only one player playing and he/she survived. if len(self.dead_player_list) > 0: - + for index, dead_player in enumerate(self.dead_player_list): # if this condition is true we find the dead player \ # and his index with enumerate function. if player == dead_player: # updating with one, because i don't want to give 0 score to first dead player. - index += 1 + index += 1 break # and if this statement is true we just find a survived player. # for survived player i am giving the highest score according to how many players are joined. @@ -726,11 +730,11 @@ def end_game(self): # for survived player i am giving the highest score according to how many players are joined. else: index = len(self.joined_player_list) - + # and here i am following Table of 10 for scoring. # very lazY. score = int(10 * index) - + self.stats.player_scored(player, score, screenmessage=False) # Ok now calc game results: set a score for each team and then tell \ @@ -742,25 +746,23 @@ def end_game(self): # just always deal in teams and have all cases covered. # hmmm... some eric comments might be helpful to you. for team in self.teams: - + max_index = 0 for player in team.players: - # for the team, we choose only one player who survived longest. - # same logic.. - if len(self.dead_player_list) > 0: + # for the team, we choose only one player who survived longest. + # same logic.. + if len(self.dead_player_list) > 0: for index, dead_player in enumerate(self.dead_player_list): if player == dead_player: index += 1 break elif index == len(self.dead_player_list) - 1: index = len(self.joined_player_list) - else: + else: index = len(self.joined_player_list) - - max_index = max(max_index, index) + + max_index = max(max_index, index) # set the team score - results.set_team_score(team, int(10 * max_index)) + results.set_team_score(team, int(10 * max_index)) # and end the game self.end(results=results) - - \ No newline at end of file From 8209a3eeb0550447febd188b2a8e702a60e0dce9 Mon Sep 17 00:00:00 2001 From: Rikko Date: Sun, 23 Jul 2023 20:36:51 +0530 Subject: [PATCH 0593/1464] Update plugin updation example --- README.md | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index f062de65..33f9f93f 100644 --- a/README.md +++ b/README.md @@ -149,17 +149,17 @@ diff --git a/plugins/utilities/sample_plugin.py b/plugins/utilities/sample_plugi index ebb7dcc..da2b312 100644 --- a/plugins/utilities/sample_plugin.py +++ b/plugins/utilities/sample_plugin.py -@@ -5,6 +5,7 @@ import ba - class Main(ba.Plugin): +@@ -5,6 +5,7 @@ import babase + class Main(babase.Plugin): def on_app_running(self): - ba.screenmessage("Hi! I am a sample plugin!") + babase.screenmessage("Hi! I am a sample plugin!") def has_settings_ui(self): return True def show_settings_ui(self, source_widget): -- ba.screenmessage("You tapped my settings!") -+ ba.screenmessage("Hey! This is my new screenmessage!") +- babase.screenmessage("You tapped my settings!") ++ babase.screenmessage("Hey! This is my new screenmessage!") ``` To name this new version as `1.1.0`, add `"1.1.0": null,` just above the previous plugin version in `utilities.json`: From 88841cdd4b5b6fd2521ad74dd308eba7f93f0c08 Mon Sep 17 00:00:00 2001 From: SenjuZoro <69396975+SenjuZoro@users.noreply.github.com> Date: Sun, 23 Jul 2023 17:19:22 +0200 Subject: [PATCH 0594/1464] Update minigames.json --- plugins/minigames.json | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/plugins/minigames.json b/plugins/minigames.json index de4d1409..c889daf2 100644 --- a/plugins/minigames.json +++ b/plugins/minigames.json @@ -457,6 +457,7 @@ } ], "versions": { + "2.0.0":null, "1.0.0": { "api_version": 7, "commit_sha": "7219487", @@ -618,4 +619,4 @@ } } } -} \ No newline at end of file +} From 1d5a6f3d2c3a6bc746ff5d7ece6bcbd27f903abe Mon Sep 17 00:00:00 2001 From: SenjuZoro Date: Sun, 23 Jul 2023 15:19:54 +0000 Subject: [PATCH 0595/1464] [ci] apply-version-metadata --- plugins/minigames.json | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/plugins/minigames.json b/plugins/minigames.json index c889daf2..bf184ea4 100644 --- a/plugins/minigames.json +++ b/plugins/minigames.json @@ -457,7 +457,12 @@ } ], "versions": { - "2.0.0":null, + "2.0.0": { + "api_version": 7, + "commit_sha": "88841cd", + "released_on": "23-07-2023", + "md5sum": "afca5167b564a7f7c0bdc53c3e52d198" + }, "1.0.0": { "api_version": 7, "commit_sha": "7219487", @@ -619,4 +624,4 @@ } } } -} +} \ No newline at end of file From 1a8037eedcc81561de7781c2bb94800a63976fc3 Mon Sep 17 00:00:00 2001 From: SenjuZoro <69396975+SenjuZoro@users.noreply.github.com> Date: Sun, 23 Jul 2023 17:29:34 +0200 Subject: [PATCH 0596/1464] Update minigames.json --- plugins/minigames.json | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/plugins/minigames.json b/plugins/minigames.json index bf184ea4..cb3d688c 100644 --- a/plugins/minigames.json +++ b/plugins/minigames.json @@ -457,12 +457,6 @@ } ], "versions": { - "2.0.0": { - "api_version": 7, - "commit_sha": "88841cd", - "released_on": "23-07-2023", - "md5sum": "afca5167b564a7f7c0bdc53c3e52d198" - }, "1.0.0": { "api_version": 7, "commit_sha": "7219487", @@ -482,6 +476,7 @@ } ], "versions": { + "2.0.0":null, "1.0.0": { "api_version": 7, "commit_sha": "7219487", @@ -624,4 +619,4 @@ } } } -} \ No newline at end of file +} From f39e240d0d6f06c9952e4f12a6db6af512e91f51 Mon Sep 17 00:00:00 2001 From: SenjuZoro Date: Sun, 23 Jul 2023 15:30:02 +0000 Subject: [PATCH 0597/1464] [ci] apply-version-metadata --- plugins/minigames.json | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/plugins/minigames.json b/plugins/minigames.json index cb3d688c..6303e427 100644 --- a/plugins/minigames.json +++ b/plugins/minigames.json @@ -476,7 +476,12 @@ } ], "versions": { - "2.0.0":null, + "2.0.0": { + "api_version": 8, + "commit_sha": "1a8037e", + "released_on": "23-07-2023", + "md5sum": "916e37f6e1a8a5be3dd0389ed2c4b261" + }, "1.0.0": { "api_version": 7, "commit_sha": "7219487", @@ -619,4 +624,4 @@ } } } -} +} \ No newline at end of file From 6db1bef848c5c3ee834f9e4540b7e9023d97bd30 Mon Sep 17 00:00:00 2001 From: SenjuZoro <69396975+SenjuZoro@users.noreply.github.com> Date: Sun, 23 Jul 2023 17:40:41 +0200 Subject: [PATCH 0598/1464] Collector updated Collector minigame updated to api 8 Author Mikirog --- plugins/minigames/Collector.py | 636 +++++++++++++++++++++++++++++++++ 1 file changed, 636 insertions(+) create mode 100644 plugins/minigames/Collector.py diff --git a/plugins/minigames/Collector.py b/plugins/minigames/Collector.py new file mode 100644 index 00000000..da4b4164 --- /dev/null +++ b/plugins/minigames/Collector.py @@ -0,0 +1,636 @@ +# ba_meta require api 8 +# (see https://ballistica.net/wiki/meta-tag-system) + +''' + Gamemode: Collector + Creator: TheMikirog + Website: https://bombsquadjoyride.blogspot.com/ + + This is a gamemode purely made by me just to spite unchallenged modders + out there that put out crap to the market. + We don't want gamemodes that are just the existing ones + with some novelties! Gamers deserve more! + + In this gamemode you have to kill others in order to get their Capsules. + Capsules can be collected and staked in your inventory, + how many as you please. + After you kill an enemy that carries some of them, + they drop a respective amount of Capsules they carried + two more. + Your task is to collect these Capsules, + get to the flag and score them KOTH style. + You can't score if you don't have any Capsules with you. + The first player or team to get to the required ammount wins. + This is a gamemode all about trying to stay alive + and picking your battles in order to win. + A rare skill in BombSquad, where everyone is overly aggressive. +''' + +from __future__ import annotations + +import weakref +from enum import Enum +from typing import TYPE_CHECKING + +import babase +import bauiv1 as bui +import bascenev1 as bs +import random +from bascenev1lib.actor.flag import Flag +from bascenev1lib.actor.popuptext import PopupText +from bascenev1lib.actor.playerspaz import PlayerSpaz +from bascenev1lib.actor.scoreboard import Scoreboard +from bascenev1lib.gameutils import SharedObjects + +if TYPE_CHECKING: + from typing import Any, Sequence + + +lang = bs.app.lang.language +if lang == 'Spanish': + name = 'Coleccionista' + description = ('Elimina a tus oponentes para robar sus cápsulas.\n' + '¡Recolecta y anota en el punto de depósito!') + description_ingame = 'Obtén ${ARG1} cápsulas de tus enemigos.' + description_short = 'colecciona ${ARG1} cápsulas' + tips = [( + '¡Si tu oponente cae fuera del mapa, sus cápsulas desapareceran!\n' + 'No intestes matar a tus enemigos arrojándolos al vacio.'), + 'No te apresures. ¡Puedes perder tus cápsulas rápidamente!', + ('¡No dejes que el jugador con más cápsulas anote!\n' + '¡Intenta atraparlo si puedes!'), + ('¡Las Capsulas de la Suerte te dan 4 cápsulas en lugar de 2' + 'y tienen un 8% de probabilidad de aparecer después de matar'), + ('¡No te quedes en un solo lugar! Muevete más rapido que tu enemigo, ' + '¡con suerte conseguirás algunas cápsulas!'), + ] + capsules_to_win = 'Cápsulas para Ganar' + capsules_death = 'Cápsulas al Morir' + lucky_capsules = 'Cápsulas de la Suerte' + bonus = '¡BONUS!' + full_capacity = '¡Capacidad Completa!' +else: + name = 'Collector' + description = ('Kill your opponents to steal their Capsules.\n' + 'Collect them and score at the Deposit point!') + description_ingame = 'Score ${ARG1} capsules from your enemies.' + description_short = 'collect ${ARG1} capsules' + tips = [( + 'Making you opponent fall down the pit makes his Capsules wasted!\n' + 'Try not to kill enemies by throwing them off the cliff.'), + 'Don\'t be too reckless. You can lose your loot quite quickly!', + ('Don\'t let the leading player score his Capsules ' + 'at the Deposit Point!\nTry to catch him if you can!'), + ('Lucky Capsules give 4 to your inventory and they have 8% chance ' + 'of spawning after kill!'), + ('Don\'t camp in one place! Make your move first, ' + 'so hopefully you get some dough!'), + ] + capsules_to_win = 'Capsules to Win' + capsules_death = 'Capsules on Death' + lucky_capsules = 'Allow Lucky Capsules' + bonus = 'BONUS!' + full_capacity = 'Full Capacity!' + + +class FlagState(Enum): + """States our single flag can be in.""" + + NEW = 0 + UNCONTESTED = 1 + CONTESTED = 2 + HELD = 3 + + +class Player(bs.Player['Team']): + """Our player type for this game.""" + + def __init__(self) -> None: + self.time_at_flag = 0 + self.capsules = 0 + self.light = None + + +class Team(bs.Team[Player]): + """Our team type for this game.""" + + def __init__(self) -> None: + self.score = 0 + + +# ba_meta export bascenev1.GameActivity +class CollectorGame(bs.TeamGameActivity[Player, Team]): + + name = name + description = description + tips = tips + + # Print messages when players die since it matters here. + announce_player_deaths = True + + @classmethod + def get_available_settings( + cls, sessiontype: type[bs.Session] + ) -> list[babase.Setting]: + settings = [ + bs.IntSetting( + capsules_to_win, + min_value=1, + default=10, + increment=1, + ), + bs.IntSetting( + capsules_death, + min_value=1, + max_value=10, + default=2, + increment=1, + ), + bs.IntChoiceSetting( + 'Time Limit', + choices=[ + ('None', 0), + ('1 Minute', 60), + ('2 Minutes', 120), + ('5 Minutes', 300), + ('10 Minutes', 600), + ('20 Minutes', 1200), + ], + default=0, + ), + bs.FloatChoiceSetting( + 'Respawn Times', + choices=[ + ('Shorter', 0.25), + ('Short', 0.5), + ('Normal', 1.0), + ('Long', 2.0), + ('Longer', 4.0), + ], + default=1.0, + ), + bs.BoolSetting(lucky_capsules, default=True), + bs.BoolSetting('Epic Mode', default=False), + ] + return settings + + @classmethod + def supports_session_type(cls, sessiontype: type[bs.Session]) -> bool: + return issubclass(sessiontype, bs.DualTeamSession) or issubclass( + sessiontype, bs.FreeForAllSession + ) + + @classmethod + def get_supported_maps(cls, sessiontype: type[bs.Session]) -> list[str]: + return bs.app.classic.getmaps('keep_away') + + def __init__(self, settings: dict): + super().__init__(settings) + shared = SharedObjects.get() + self._scoreboard = Scoreboard() + self._score_to_win: int | None = None + self._swipsound = bs.getsound('swip') + self._lucky_sound = bs.getsound('ding') + + self._flag_pos: Sequence[float] | None = None + self._flag_state: FlagState | None = None + self._flag: Flag | None = None + self._flag_light: bs.Node | None = None + self._scoring_team: weakref.ref[Team] | None = None + self._time_limit = float(settings['Time Limit']) + self._epic_mode = bool(settings['Epic Mode']) + + self._capsules_to_win = int(settings[capsules_to_win]) + self._capsules_death = int(settings[capsules_death]) + self._lucky_capsules = bool(settings[lucky_capsules]) + self._capsules: list[Any] = [] + + self._capsule_mesh = bs.getmesh('bomb') + self._capsule_tex = bs.gettexture('bombColor') + self._capsule_lucky_tex = bs.gettexture('bombStickyColor') + self._collect_sound = bs.getsound('powerup01') + self._lucky_collect_sound = bs.getsound('cashRegister2') + + self._capsule_material = bs.Material() + self._capsule_material.add_actions( + conditions=('they_have_material', shared.player_material), + actions=('call', 'at_connect', self._on_capsule_player_collide), + ) + + self._flag_region_material = bs.Material() + self._flag_region_material.add_actions( + conditions=('they_have_material', shared.player_material), + actions=( + ('modify_part_collision', 'collide', True), + ('modify_part_collision', 'physical', False), + ( + 'call', + 'at_connect', + babase.Call(self._handle_player_flag_region_collide, True), + ), + ( + 'call', + 'at_disconnect', + babase.Call(self._handle_player_flag_region_collide, False), + ), + ), + ) + + # Base class overrides. + self.slow_motion = self._epic_mode + self.default_music = ( + bs.MusicType.EPIC if self._epic_mode else bs.MusicType.SCARY + ) + + def get_instance_description(self) -> str | Sequence: + return description_ingame, self._score_to_win + + def get_instance_description_short(self) -> str | Sequence: + return description_short, self._score_to_win + + def create_team(self, sessionteam: bs.SessionTeam) -> Team: + return Team() + + def on_team_join(self, team: Team) -> None: + self._update_scoreboard() + + def on_begin(self) -> None: + super().on_begin() + shared = SharedObjects.get() + self.setup_standard_time_limit(self._time_limit) + self.setup_standard_powerup_drops() + + # Base kills needed to win on the size of the largest team. + self._score_to_win = self._capsules_to_win * max( + 1, max(len(t.players) for t in self.teams) + ) + self._update_scoreboard() + + if isinstance(self.session, bs.FreeForAllSession): + self._flag_pos = self.map.get_flag_position(random.randint(0, 1)) + else: + self._flag_pos = self.map.get_flag_position(None) + + bs.timer(1.0, self._tick, repeat=True) + self._flag_state = FlagState.NEW + Flag.project_stand(self._flag_pos) + self._flag = Flag( + position=self._flag_pos, touchable=False, color=(1, 1, 1) + ) + self._flag_light = bs.newnode( + 'light', + attrs={ + 'position': self._flag_pos, + 'intensity': 0.2, + 'height_attenuated': False, + 'radius': 0.4, + 'color': (0.2, 0.2, 0.2), + }, + ) + # Flag region. + flagmats = [self._flag_region_material, shared.region_material] + bs.newnode( + 'region', + attrs={ + 'position': self._flag_pos, + 'scale': (1.8, 1.8, 1.8), + 'type': 'sphere', + 'materials': flagmats, + }, + ) + self._update_flag_state() + + def _tick(self) -> None: + self._update_flag_state() + + if self._scoring_team is None: + scoring_team = None + else: + scoring_team = self._scoring_team() + + if not scoring_team: + return + + if isinstance(self.session, bs.FreeForAllSession): + players = self.players + else: + players = scoring_team.players + + for player in players: + if player.time_at_flag > 0: + self.stats.player_scored( + player, 3, screenmessage=False, display=False + ) + if player.capsules > 0: + if self._flag_state != FlagState.HELD: + return + if scoring_team.score >= self._score_to_win: + return + + player.capsules -= 1 + scoring_team.score += 1 + self._handle_capsule_storage(( + self._flag_pos[0], + self._flag_pos[1]+1, + self._flag_pos[2] + ), player) + self._collect_sound.play(0.8, position=self._flag_pos) + + self._update_scoreboard() + if player.capsules > 0: + assert self._flag is not None + self._flag.set_score_text( + str(self._score_to_win - scoring_team.score)) + + # winner + if scoring_team.score >= self._score_to_win: + self.end_game() + + def end_game(self) -> None: + results = bs.GameResults() + for team in self.teams: + results.set_team_score(team, team.score) + self.end(results=results, announce_delay=0) + + def _update_flag_state(self) -> None: + holding_teams = set( + player.team for player in self.players if player.time_at_flag + ) + prev_state = self._flag_state + assert self._flag_light + assert self._flag is not None + assert self._flag.node + if len(holding_teams) > 1: + self._flag_state = FlagState.CONTESTED + self._scoring_team = None + self._flag_light.color = (0.6, 0.6, 0.1) + self._flag.node.color = (1.0, 1.0, 0.4) + elif len(holding_teams) == 1: + holding_team = list(holding_teams)[0] + self._flag_state = FlagState.HELD + self._scoring_team = weakref.ref(holding_team) + self._flag_light.color = babase.normalized_color(holding_team.color) + self._flag.node.color = holding_team.color + else: + self._flag_state = FlagState.UNCONTESTED + self._scoring_team = None + self._flag_light.color = (0.2, 0.2, 0.2) + self._flag.node.color = (1, 1, 1) + if self._flag_state != prev_state: + self._swipsound.play() + + def _handle_player_flag_region_collide(self, colliding: bool) -> None: + try: + spaz = bs.getcollision().opposingnode.getdelegate(PlayerSpaz, True) + except bs.NotFoundError: + return + + if not spaz.is_alive(): + return + + player = spaz.getplayer(Player, True) + + # Different parts of us can collide so a single value isn't enough + # also don't count it if we're dead (flying heads shouldn't be able to + # win the game :-) + if colliding and player.is_alive(): + player.time_at_flag += 1 + else: + player.time_at_flag = max(0, player.time_at_flag - 1) + + self._update_flag_state() + + def _update_scoreboard(self) -> None: + for team in self.teams: + self._scoreboard.set_team_value( + team, team.score, self._score_to_win + ) + + def _drop_capsule(self, player: Player) -> None: + pt = player.node.position + + # Throw out capsules that the victim has + 2 more to keep the game running + for i in range(player.capsules + self._capsules_death): + # How far from each other these capsules should spawn + w = 0.6 + # How much these capsules should fly after spawning + s = 0.005 - (player.capsules * 0.01) + self._capsules.append( + Capsule( + position=(pt[0] + random.uniform(-w, w), + pt[1] + 0.75 + random.uniform(-w, w), + pt[2]), + velocity=(random.uniform(-s, s), + random.uniform(-s, s), + random.uniform(-s, s)), + lucky=False)) + if random.randint(1, 12) == 1 and self._lucky_capsules: + # How far from each other these capsules should spawn + w = 0.6 + # How much these capsules should fly after spawning + s = 0.005 + self._capsules.append( + Capsule( + position=(pt[0] + random.uniform(-w, w), + pt[1] + 0.75 + random.uniform(-w, w), + pt[2]), + velocity=(random.uniform(-s, s), + random.uniform(-s, s), + random.uniform(-s, s)), + lucky=True)) + + def _on_capsule_player_collide(self) -> None: + if self.has_ended(): + return + collision = bs.getcollision() + + # Be defensive here; we could be hitting the corpse of a player + # who just left/etc. + try: + capsule = collision.sourcenode.getdelegate(Capsule, True) + player = collision.opposingnode.getdelegate( + PlayerSpaz, True + ).getplayer(Player, True) + except bs.NotFoundError: + return + + if not player.is_alive(): + return + + if capsule.node.color_texture == self._capsule_lucky_tex: + player.capsules += 4 + PopupText( + bonus, + color=(1, 1, 0), + scale=1.5, + position=capsule.node.position + ).autoretain() + self._lucky_collect_sound.play(1.0, position=capsule.node.position) + bs.emitfx( + position=capsule.node.position, + velocity=(0, 0, 0), + count=int(6.4+random.random()*24), + scale=1.2, + spread=2.0, + chunk_type='spark') + bs.emitfx( + position=capsule.node.position, + velocity=(0, 0, 0), + count=int(4.0+random.random()*6), + emit_type='tendrils') + else: + player.capsules += 1 + self._collect_sound.play(0.6, position=capsule.node.position) + # create a flash + light = bs.newnode( + 'light', + attrs={ + 'position': capsule.node.position, + 'height_attenuated': False, + 'radius': 0.1, + 'color': (1, 1, 0)}) + + # Create a short text informing about your inventory + self._handle_capsule_storage(player.position, player) + + bs.animate(light, 'intensity', { + 0: 0, + 0.1: 0.5, + 0.2: 0 + }, loop=False) + bs.timer(0.2, light.delete) + capsule.handlemessage(bs.DieMessage()) + + def _update_player_light(self, player: Player, capsules: int) -> None: + if player.light: + intensity = 0.04 * capsules + bs.animate(player.light, 'intensity', { + 0.0: player.light.intensity, + 0.1: intensity + }) + + def newintensity(): + player.light.intensity = intensity + bs.timer(0.1, newintensity) + else: + player.light = bs.newnode( + 'light', + attrs={ + 'height_attenuated': False, + 'radius': 0.2, + 'intensity': 0.0, + 'color': (0.2, 1, 0.2) + }) + player.node.connectattr('position', player.light, 'position') + + def _handle_capsule_storage(self, pos: float, player: Player) -> None: + capsules = player.capsules + text = str(capsules) + scale = 1.75 + (0.02 * capsules) + if capsules > 10: + player.capsules = 10 + text = full_capacity + color = (1, 0.85, 0) + elif capsules > 7: + color = (1, 0, 0) + scale = 2.4 + elif capsules > 5: + color = (1, 0.4, 0.4) + scale = 2.1 + elif capsules > 3: + color = (1, 1, 0.4) + scale = 2.0 + else: + color = (1, 1, 1) + scale = 1.9 + PopupText( + text, + color=color, + scale=scale, + position=(pos[0], pos[1]-1, pos[2]) + ).autoretain() + self._update_player_light(player, capsules) + + def handlemessage(self, msg: Any) -> Any: + if isinstance(msg, bs.PlayerDiedMessage): + super().handlemessage(msg) # Augment default. + # No longer can count as time_at_flag once dead. + player = msg.getplayer(Player) + player.time_at_flag = 0 + self._update_flag_state() + self._drop_capsule(player) + player.capsules = 0 + self._update_player_light(player, 0) + self.respawn_player(player) + else: + return super().handlemessage(msg) + + +class Capsule(bs.Actor): + + def __init__(self, + position: Sequence[float] = (0.0, 1.0, 0.0), + velocity: Sequence[float] = (0.0, 0.5, 0.0), + lucky: bool = False): + super().__init__() + shared = SharedObjects.get() + activity = self.getactivity() + + # spawn just above the provided point + self._spawn_pos = (position[0], position[1], position[2]) + + if lucky: + activity._lucky_sound.play(1.0, self._spawn_pos) + + self.node = bs.newnode( + 'prop', + attrs={ + 'mesh': activity._capsule_mesh, + 'color_texture': activity._capsule_lucky_tex if lucky else ( + activity._capsule_tex), + 'body': 'crate' if lucky else 'capsule', + 'reflection': 'powerup' if lucky else 'soft', + 'body_scale': 0.65 if lucky else 0.3, + 'density': 6.0 if lucky else 4.0, + 'reflection_scale': [0.15], + 'shadow_size': 0.65 if lucky else 0.6, + 'position': self._spawn_pos, + 'velocity': velocity, + 'materials': [ + shared.object_material, activity._capsule_material] + }, + delegate=self) + bs.animate(self.node, 'mesh_scale', { + 0.0: 0.0, + 0.1: 0.9 if lucky else 0.6, + 0.16: 0.8 if lucky else 0.5 + }) + self._light_capsule = bs.newnode( + 'light', + attrs={ + 'position': self._spawn_pos, + 'height_attenuated': False, + 'radius': 0.5 if lucky else 0.1, + 'color': (0.2, 0.2, 0) if lucky else (0.2, 1, 0.2) + }) + self.node.connectattr('position', self._light_capsule, 'position') + + def handlemessage(self, msg: Any): + if isinstance(msg, bs.DieMessage): + self.node.delete() + bs.animate(self._light_capsule, 'intensity', { + 0: 1.0, + 0.05: 0.0 + }, loop=False) + bs.timer(0.05, self._light_capsule.delete) + elif isinstance(msg, bs.OutOfBoundsMessage): + self.handlemessage(bs.DieMessage()) + elif isinstance(msg, bs.HitMessage): + self.node.handlemessage( + 'impulse', + msg.pos[0], msg.pos[1], msg.pos[2], + msg.velocity[0]/8, msg.velocity[1]/8, msg.velocity[2]/8, + 1.0*msg.magnitude, 1.0*msg.velocity_magnitude, msg.radius, 0, + msg.force_direction[0], msg.force_direction[1], + msg.force_direction[2]) + else: + return super().handlemessage(msg) From 968616aad974e52f4647a25afab09dc5f0d8d640 Mon Sep 17 00:00:00 2001 From: SenjuZoro <69396975+SenjuZoro@users.noreply.github.com> Date: Sun, 23 Jul 2023 17:42:15 +0200 Subject: [PATCH 0599/1464] Update minigames.json --- plugins/minigames.json | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/plugins/minigames.json b/plugins/minigames.json index 6303e427..f91eb444 100644 --- a/plugins/minigames.json +++ b/plugins/minigames.json @@ -457,6 +457,7 @@ } ], "versions": { + "2.0.0":null, "1.0.0": { "api_version": 7, "commit_sha": "7219487", @@ -624,4 +625,4 @@ } } } -} \ No newline at end of file +} From 713f81df68eb07acc66513cd5afc02c0a55349d0 Mon Sep 17 00:00:00 2001 From: SenjuZoro <69396975+SenjuZoro@users.noreply.github.com> Date: Sun, 23 Jul 2023 17:50:18 +0200 Subject: [PATCH 0600/1464] Delete Collector.py --- plugins/minigames/Collector.py | 636 --------------------------------- 1 file changed, 636 deletions(-) delete mode 100644 plugins/minigames/Collector.py diff --git a/plugins/minigames/Collector.py b/plugins/minigames/Collector.py deleted file mode 100644 index da4b4164..00000000 --- a/plugins/minigames/Collector.py +++ /dev/null @@ -1,636 +0,0 @@ -# ba_meta require api 8 -# (see https://ballistica.net/wiki/meta-tag-system) - -''' - Gamemode: Collector - Creator: TheMikirog - Website: https://bombsquadjoyride.blogspot.com/ - - This is a gamemode purely made by me just to spite unchallenged modders - out there that put out crap to the market. - We don't want gamemodes that are just the existing ones - with some novelties! Gamers deserve more! - - In this gamemode you have to kill others in order to get their Capsules. - Capsules can be collected and staked in your inventory, - how many as you please. - After you kill an enemy that carries some of them, - they drop a respective amount of Capsules they carried + two more. - Your task is to collect these Capsules, - get to the flag and score them KOTH style. - You can't score if you don't have any Capsules with you. - The first player or team to get to the required ammount wins. - This is a gamemode all about trying to stay alive - and picking your battles in order to win. - A rare skill in BombSquad, where everyone is overly aggressive. -''' - -from __future__ import annotations - -import weakref -from enum import Enum -from typing import TYPE_CHECKING - -import babase -import bauiv1 as bui -import bascenev1 as bs -import random -from bascenev1lib.actor.flag import Flag -from bascenev1lib.actor.popuptext import PopupText -from bascenev1lib.actor.playerspaz import PlayerSpaz -from bascenev1lib.actor.scoreboard import Scoreboard -from bascenev1lib.gameutils import SharedObjects - -if TYPE_CHECKING: - from typing import Any, Sequence - - -lang = bs.app.lang.language -if lang == 'Spanish': - name = 'Coleccionista' - description = ('Elimina a tus oponentes para robar sus cápsulas.\n' - '¡Recolecta y anota en el punto de depósito!') - description_ingame = 'Obtén ${ARG1} cápsulas de tus enemigos.' - description_short = 'colecciona ${ARG1} cápsulas' - tips = [( - '¡Si tu oponente cae fuera del mapa, sus cápsulas desapareceran!\n' - 'No intestes matar a tus enemigos arrojándolos al vacio.'), - 'No te apresures. ¡Puedes perder tus cápsulas rápidamente!', - ('¡No dejes que el jugador con más cápsulas anote!\n' - '¡Intenta atraparlo si puedes!'), - ('¡Las Capsulas de la Suerte te dan 4 cápsulas en lugar de 2' - 'y tienen un 8% de probabilidad de aparecer después de matar'), - ('¡No te quedes en un solo lugar! Muevete más rapido que tu enemigo, ' - '¡con suerte conseguirás algunas cápsulas!'), - ] - capsules_to_win = 'Cápsulas para Ganar' - capsules_death = 'Cápsulas al Morir' - lucky_capsules = 'Cápsulas de la Suerte' - bonus = '¡BONUS!' - full_capacity = '¡Capacidad Completa!' -else: - name = 'Collector' - description = ('Kill your opponents to steal their Capsules.\n' - 'Collect them and score at the Deposit point!') - description_ingame = 'Score ${ARG1} capsules from your enemies.' - description_short = 'collect ${ARG1} capsules' - tips = [( - 'Making you opponent fall down the pit makes his Capsules wasted!\n' - 'Try not to kill enemies by throwing them off the cliff.'), - 'Don\'t be too reckless. You can lose your loot quite quickly!', - ('Don\'t let the leading player score his Capsules ' - 'at the Deposit Point!\nTry to catch him if you can!'), - ('Lucky Capsules give 4 to your inventory and they have 8% chance ' - 'of spawning after kill!'), - ('Don\'t camp in one place! Make your move first, ' - 'so hopefully you get some dough!'), - ] - capsules_to_win = 'Capsules to Win' - capsules_death = 'Capsules on Death' - lucky_capsules = 'Allow Lucky Capsules' - bonus = 'BONUS!' - full_capacity = 'Full Capacity!' - - -class FlagState(Enum): - """States our single flag can be in.""" - - NEW = 0 - UNCONTESTED = 1 - CONTESTED = 2 - HELD = 3 - - -class Player(bs.Player['Team']): - """Our player type for this game.""" - - def __init__(self) -> None: - self.time_at_flag = 0 - self.capsules = 0 - self.light = None - - -class Team(bs.Team[Player]): - """Our team type for this game.""" - - def __init__(self) -> None: - self.score = 0 - - -# ba_meta export bascenev1.GameActivity -class CollectorGame(bs.TeamGameActivity[Player, Team]): - - name = name - description = description - tips = tips - - # Print messages when players die since it matters here. - announce_player_deaths = True - - @classmethod - def get_available_settings( - cls, sessiontype: type[bs.Session] - ) -> list[babase.Setting]: - settings = [ - bs.IntSetting( - capsules_to_win, - min_value=1, - default=10, - increment=1, - ), - bs.IntSetting( - capsules_death, - min_value=1, - max_value=10, - default=2, - increment=1, - ), - bs.IntChoiceSetting( - 'Time Limit', - choices=[ - ('None', 0), - ('1 Minute', 60), - ('2 Minutes', 120), - ('5 Minutes', 300), - ('10 Minutes', 600), - ('20 Minutes', 1200), - ], - default=0, - ), - bs.FloatChoiceSetting( - 'Respawn Times', - choices=[ - ('Shorter', 0.25), - ('Short', 0.5), - ('Normal', 1.0), - ('Long', 2.0), - ('Longer', 4.0), - ], - default=1.0, - ), - bs.BoolSetting(lucky_capsules, default=True), - bs.BoolSetting('Epic Mode', default=False), - ] - return settings - - @classmethod - def supports_session_type(cls, sessiontype: type[bs.Session]) -> bool: - return issubclass(sessiontype, bs.DualTeamSession) or issubclass( - sessiontype, bs.FreeForAllSession - ) - - @classmethod - def get_supported_maps(cls, sessiontype: type[bs.Session]) -> list[str]: - return bs.app.classic.getmaps('keep_away') - - def __init__(self, settings: dict): - super().__init__(settings) - shared = SharedObjects.get() - self._scoreboard = Scoreboard() - self._score_to_win: int | None = None - self._swipsound = bs.getsound('swip') - self._lucky_sound = bs.getsound('ding') - - self._flag_pos: Sequence[float] | None = None - self._flag_state: FlagState | None = None - self._flag: Flag | None = None - self._flag_light: bs.Node | None = None - self._scoring_team: weakref.ref[Team] | None = None - self._time_limit = float(settings['Time Limit']) - self._epic_mode = bool(settings['Epic Mode']) - - self._capsules_to_win = int(settings[capsules_to_win]) - self._capsules_death = int(settings[capsules_death]) - self._lucky_capsules = bool(settings[lucky_capsules]) - self._capsules: list[Any] = [] - - self._capsule_mesh = bs.getmesh('bomb') - self._capsule_tex = bs.gettexture('bombColor') - self._capsule_lucky_tex = bs.gettexture('bombStickyColor') - self._collect_sound = bs.getsound('powerup01') - self._lucky_collect_sound = bs.getsound('cashRegister2') - - self._capsule_material = bs.Material() - self._capsule_material.add_actions( - conditions=('they_have_material', shared.player_material), - actions=('call', 'at_connect', self._on_capsule_player_collide), - ) - - self._flag_region_material = bs.Material() - self._flag_region_material.add_actions( - conditions=('they_have_material', shared.player_material), - actions=( - ('modify_part_collision', 'collide', True), - ('modify_part_collision', 'physical', False), - ( - 'call', - 'at_connect', - babase.Call(self._handle_player_flag_region_collide, True), - ), - ( - 'call', - 'at_disconnect', - babase.Call(self._handle_player_flag_region_collide, False), - ), - ), - ) - - # Base class overrides. - self.slow_motion = self._epic_mode - self.default_music = ( - bs.MusicType.EPIC if self._epic_mode else bs.MusicType.SCARY - ) - - def get_instance_description(self) -> str | Sequence: - return description_ingame, self._score_to_win - - def get_instance_description_short(self) -> str | Sequence: - return description_short, self._score_to_win - - def create_team(self, sessionteam: bs.SessionTeam) -> Team: - return Team() - - def on_team_join(self, team: Team) -> None: - self._update_scoreboard() - - def on_begin(self) -> None: - super().on_begin() - shared = SharedObjects.get() - self.setup_standard_time_limit(self._time_limit) - self.setup_standard_powerup_drops() - - # Base kills needed to win on the size of the largest team. - self._score_to_win = self._capsules_to_win * max( - 1, max(len(t.players) for t in self.teams) - ) - self._update_scoreboard() - - if isinstance(self.session, bs.FreeForAllSession): - self._flag_pos = self.map.get_flag_position(random.randint(0, 1)) - else: - self._flag_pos = self.map.get_flag_position(None) - - bs.timer(1.0, self._tick, repeat=True) - self._flag_state = FlagState.NEW - Flag.project_stand(self._flag_pos) - self._flag = Flag( - position=self._flag_pos, touchable=False, color=(1, 1, 1) - ) - self._flag_light = bs.newnode( - 'light', - attrs={ - 'position': self._flag_pos, - 'intensity': 0.2, - 'height_attenuated': False, - 'radius': 0.4, - 'color': (0.2, 0.2, 0.2), - }, - ) - # Flag region. - flagmats = [self._flag_region_material, shared.region_material] - bs.newnode( - 'region', - attrs={ - 'position': self._flag_pos, - 'scale': (1.8, 1.8, 1.8), - 'type': 'sphere', - 'materials': flagmats, - }, - ) - self._update_flag_state() - - def _tick(self) -> None: - self._update_flag_state() - - if self._scoring_team is None: - scoring_team = None - else: - scoring_team = self._scoring_team() - - if not scoring_team: - return - - if isinstance(self.session, bs.FreeForAllSession): - players = self.players - else: - players = scoring_team.players - - for player in players: - if player.time_at_flag > 0: - self.stats.player_scored( - player, 3, screenmessage=False, display=False - ) - if player.capsules > 0: - if self._flag_state != FlagState.HELD: - return - if scoring_team.score >= self._score_to_win: - return - - player.capsules -= 1 - scoring_team.score += 1 - self._handle_capsule_storage(( - self._flag_pos[0], - self._flag_pos[1]+1, - self._flag_pos[2] - ), player) - self._collect_sound.play(0.8, position=self._flag_pos) - - self._update_scoreboard() - if player.capsules > 0: - assert self._flag is not None - self._flag.set_score_text( - str(self._score_to_win - scoring_team.score)) - - # winner - if scoring_team.score >= self._score_to_win: - self.end_game() - - def end_game(self) -> None: - results = bs.GameResults() - for team in self.teams: - results.set_team_score(team, team.score) - self.end(results=results, announce_delay=0) - - def _update_flag_state(self) -> None: - holding_teams = set( - player.team for player in self.players if player.time_at_flag - ) - prev_state = self._flag_state - assert self._flag_light - assert self._flag is not None - assert self._flag.node - if len(holding_teams) > 1: - self._flag_state = FlagState.CONTESTED - self._scoring_team = None - self._flag_light.color = (0.6, 0.6, 0.1) - self._flag.node.color = (1.0, 1.0, 0.4) - elif len(holding_teams) == 1: - holding_team = list(holding_teams)[0] - self._flag_state = FlagState.HELD - self._scoring_team = weakref.ref(holding_team) - self._flag_light.color = babase.normalized_color(holding_team.color) - self._flag.node.color = holding_team.color - else: - self._flag_state = FlagState.UNCONTESTED - self._scoring_team = None - self._flag_light.color = (0.2, 0.2, 0.2) - self._flag.node.color = (1, 1, 1) - if self._flag_state != prev_state: - self._swipsound.play() - - def _handle_player_flag_region_collide(self, colliding: bool) -> None: - try: - spaz = bs.getcollision().opposingnode.getdelegate(PlayerSpaz, True) - except bs.NotFoundError: - return - - if not spaz.is_alive(): - return - - player = spaz.getplayer(Player, True) - - # Different parts of us can collide so a single value isn't enough - # also don't count it if we're dead (flying heads shouldn't be able to - # win the game :-) - if colliding and player.is_alive(): - player.time_at_flag += 1 - else: - player.time_at_flag = max(0, player.time_at_flag - 1) - - self._update_flag_state() - - def _update_scoreboard(self) -> None: - for team in self.teams: - self._scoreboard.set_team_value( - team, team.score, self._score_to_win - ) - - def _drop_capsule(self, player: Player) -> None: - pt = player.node.position - - # Throw out capsules that the victim has + 2 more to keep the game running - for i in range(player.capsules + self._capsules_death): - # How far from each other these capsules should spawn - w = 0.6 - # How much these capsules should fly after spawning - s = 0.005 - (player.capsules * 0.01) - self._capsules.append( - Capsule( - position=(pt[0] + random.uniform(-w, w), - pt[1] + 0.75 + random.uniform(-w, w), - pt[2]), - velocity=(random.uniform(-s, s), - random.uniform(-s, s), - random.uniform(-s, s)), - lucky=False)) - if random.randint(1, 12) == 1 and self._lucky_capsules: - # How far from each other these capsules should spawn - w = 0.6 - # How much these capsules should fly after spawning - s = 0.005 - self._capsules.append( - Capsule( - position=(pt[0] + random.uniform(-w, w), - pt[1] + 0.75 + random.uniform(-w, w), - pt[2]), - velocity=(random.uniform(-s, s), - random.uniform(-s, s), - random.uniform(-s, s)), - lucky=True)) - - def _on_capsule_player_collide(self) -> None: - if self.has_ended(): - return - collision = bs.getcollision() - - # Be defensive here; we could be hitting the corpse of a player - # who just left/etc. - try: - capsule = collision.sourcenode.getdelegate(Capsule, True) - player = collision.opposingnode.getdelegate( - PlayerSpaz, True - ).getplayer(Player, True) - except bs.NotFoundError: - return - - if not player.is_alive(): - return - - if capsule.node.color_texture == self._capsule_lucky_tex: - player.capsules += 4 - PopupText( - bonus, - color=(1, 1, 0), - scale=1.5, - position=capsule.node.position - ).autoretain() - self._lucky_collect_sound.play(1.0, position=capsule.node.position) - bs.emitfx( - position=capsule.node.position, - velocity=(0, 0, 0), - count=int(6.4+random.random()*24), - scale=1.2, - spread=2.0, - chunk_type='spark') - bs.emitfx( - position=capsule.node.position, - velocity=(0, 0, 0), - count=int(4.0+random.random()*6), - emit_type='tendrils') - else: - player.capsules += 1 - self._collect_sound.play(0.6, position=capsule.node.position) - # create a flash - light = bs.newnode( - 'light', - attrs={ - 'position': capsule.node.position, - 'height_attenuated': False, - 'radius': 0.1, - 'color': (1, 1, 0)}) - - # Create a short text informing about your inventory - self._handle_capsule_storage(player.position, player) - - bs.animate(light, 'intensity', { - 0: 0, - 0.1: 0.5, - 0.2: 0 - }, loop=False) - bs.timer(0.2, light.delete) - capsule.handlemessage(bs.DieMessage()) - - def _update_player_light(self, player: Player, capsules: int) -> None: - if player.light: - intensity = 0.04 * capsules - bs.animate(player.light, 'intensity', { - 0.0: player.light.intensity, - 0.1: intensity - }) - - def newintensity(): - player.light.intensity = intensity - bs.timer(0.1, newintensity) - else: - player.light = bs.newnode( - 'light', - attrs={ - 'height_attenuated': False, - 'radius': 0.2, - 'intensity': 0.0, - 'color': (0.2, 1, 0.2) - }) - player.node.connectattr('position', player.light, 'position') - - def _handle_capsule_storage(self, pos: float, player: Player) -> None: - capsules = player.capsules - text = str(capsules) - scale = 1.75 + (0.02 * capsules) - if capsules > 10: - player.capsules = 10 - text = full_capacity - color = (1, 0.85, 0) - elif capsules > 7: - color = (1, 0, 0) - scale = 2.4 - elif capsules > 5: - color = (1, 0.4, 0.4) - scale = 2.1 - elif capsules > 3: - color = (1, 1, 0.4) - scale = 2.0 - else: - color = (1, 1, 1) - scale = 1.9 - PopupText( - text, - color=color, - scale=scale, - position=(pos[0], pos[1]-1, pos[2]) - ).autoretain() - self._update_player_light(player, capsules) - - def handlemessage(self, msg: Any) -> Any: - if isinstance(msg, bs.PlayerDiedMessage): - super().handlemessage(msg) # Augment default. - # No longer can count as time_at_flag once dead. - player = msg.getplayer(Player) - player.time_at_flag = 0 - self._update_flag_state() - self._drop_capsule(player) - player.capsules = 0 - self._update_player_light(player, 0) - self.respawn_player(player) - else: - return super().handlemessage(msg) - - -class Capsule(bs.Actor): - - def __init__(self, - position: Sequence[float] = (0.0, 1.0, 0.0), - velocity: Sequence[float] = (0.0, 0.5, 0.0), - lucky: bool = False): - super().__init__() - shared = SharedObjects.get() - activity = self.getactivity() - - # spawn just above the provided point - self._spawn_pos = (position[0], position[1], position[2]) - - if lucky: - activity._lucky_sound.play(1.0, self._spawn_pos) - - self.node = bs.newnode( - 'prop', - attrs={ - 'mesh': activity._capsule_mesh, - 'color_texture': activity._capsule_lucky_tex if lucky else ( - activity._capsule_tex), - 'body': 'crate' if lucky else 'capsule', - 'reflection': 'powerup' if lucky else 'soft', - 'body_scale': 0.65 if lucky else 0.3, - 'density': 6.0 if lucky else 4.0, - 'reflection_scale': [0.15], - 'shadow_size': 0.65 if lucky else 0.6, - 'position': self._spawn_pos, - 'velocity': velocity, - 'materials': [ - shared.object_material, activity._capsule_material] - }, - delegate=self) - bs.animate(self.node, 'mesh_scale', { - 0.0: 0.0, - 0.1: 0.9 if lucky else 0.6, - 0.16: 0.8 if lucky else 0.5 - }) - self._light_capsule = bs.newnode( - 'light', - attrs={ - 'position': self._spawn_pos, - 'height_attenuated': False, - 'radius': 0.5 if lucky else 0.1, - 'color': (0.2, 0.2, 0) if lucky else (0.2, 1, 0.2) - }) - self.node.connectattr('position', self._light_capsule, 'position') - - def handlemessage(self, msg: Any): - if isinstance(msg, bs.DieMessage): - self.node.delete() - bs.animate(self._light_capsule, 'intensity', { - 0: 1.0, - 0.05: 0.0 - }, loop=False) - bs.timer(0.05, self._light_capsule.delete) - elif isinstance(msg, bs.OutOfBoundsMessage): - self.handlemessage(bs.DieMessage()) - elif isinstance(msg, bs.HitMessage): - self.node.handlemessage( - 'impulse', - msg.pos[0], msg.pos[1], msg.pos[2], - msg.velocity[0]/8, msg.velocity[1]/8, msg.velocity[2]/8, - 1.0*msg.magnitude, 1.0*msg.velocity_magnitude, msg.radius, 0, - msg.force_direction[0], msg.force_direction[1], - msg.force_direction[2]) - else: - return super().handlemessage(msg) From e8bbb6189bbb90c44454b8b528fde1c41aeea0b7 Mon Sep 17 00:00:00 2001 From: SenjuZoro <69396975+SenjuZoro@users.noreply.github.com> Date: Sun, 23 Jul 2023 17:51:10 +0200 Subject: [PATCH 0601/1464] Collector updated Collector minigame updated to api 8 Author: Mikirog --- plugins/minigames/collector.py | 163 ++++++++++++++++----------------- 1 file changed, 78 insertions(+), 85 deletions(-) diff --git a/plugins/minigames/collector.py b/plugins/minigames/collector.py index 0f9bbc34..da4b4164 100644 --- a/plugins/minigames/collector.py +++ b/plugins/minigames/collector.py @@ -1,4 +1,4 @@ -# ba_meta require api 7 +# ba_meta require api 8 # (see https://ballistica.net/wiki/meta-tag-system) ''' @@ -31,19 +31,21 @@ from enum import Enum from typing import TYPE_CHECKING -import ba +import babase +import bauiv1 as bui +import bascenev1 as bs import random -from bastd.actor.flag import Flag -from bastd.actor.popuptext import PopupText -from bastd.actor.playerspaz import PlayerSpaz -from bastd.actor.scoreboard import Scoreboard -from bastd.gameutils import SharedObjects +from bascenev1lib.actor.flag import Flag +from bascenev1lib.actor.popuptext import PopupText +from bascenev1lib.actor.playerspaz import PlayerSpaz +from bascenev1lib.actor.scoreboard import Scoreboard +from bascenev1lib.gameutils import SharedObjects if TYPE_CHECKING: from typing import Any, Sequence -lang = ba.app.lang.language +lang = bs.app.lang.language if lang == 'Spanish': name = 'Coleccionista' description = ('Elimina a tus oponentes para robar sus cápsulas.\n' @@ -99,7 +101,7 @@ class FlagState(Enum): HELD = 3 -class Player(ba.Player['Team']): +class Player(bs.Player['Team']): """Our player type for this game.""" def __init__(self) -> None: @@ -108,15 +110,15 @@ def __init__(self) -> None: self.light = None -class Team(ba.Team[Player]): +class Team(bs.Team[Player]): """Our team type for this game.""" def __init__(self) -> None: self.score = 0 -# ba_meta export game -class CollectorGame(ba.TeamGameActivity[Player, Team]): +# ba_meta export bascenev1.GameActivity +class CollectorGame(bs.TeamGameActivity[Player, Team]): name = name description = description @@ -127,23 +129,23 @@ class CollectorGame(ba.TeamGameActivity[Player, Team]): @classmethod def get_available_settings( - cls, sessiontype: type[ba.Session] - ) -> list[ba.Setting]: + cls, sessiontype: type[bs.Session] + ) -> list[babase.Setting]: settings = [ - ba.IntSetting( + bs.IntSetting( capsules_to_win, min_value=1, default=10, increment=1, ), - ba.IntSetting( + bs.IntSetting( capsules_death, min_value=1, max_value=10, default=2, increment=1, ), - ba.IntChoiceSetting( + bs.IntChoiceSetting( 'Time Limit', choices=[ ('None', 0), @@ -155,7 +157,7 @@ def get_available_settings( ], default=0, ), - ba.FloatChoiceSetting( + bs.FloatChoiceSetting( 'Respawn Times', choices=[ ('Shorter', 0.25), @@ -166,33 +168,33 @@ def get_available_settings( ], default=1.0, ), - ba.BoolSetting(lucky_capsules, default=True), - ba.BoolSetting('Epic Mode', default=False), + bs.BoolSetting(lucky_capsules, default=True), + bs.BoolSetting('Epic Mode', default=False), ] return settings @classmethod - def supports_session_type(cls, sessiontype: type[ba.Session]) -> bool: - return issubclass(sessiontype, ba.DualTeamSession) or issubclass( - sessiontype, ba.FreeForAllSession + def supports_session_type(cls, sessiontype: type[bs.Session]) -> bool: + return issubclass(sessiontype, bs.DualTeamSession) or issubclass( + sessiontype, bs.FreeForAllSession ) @classmethod - def get_supported_maps(cls, sessiontype: type[ba.Session]) -> list[str]: - return ba.getmaps('keep_away') + def get_supported_maps(cls, sessiontype: type[bs.Session]) -> list[str]: + return bs.app.classic.getmaps('keep_away') def __init__(self, settings: dict): super().__init__(settings) shared = SharedObjects.get() self._scoreboard = Scoreboard() self._score_to_win: int | None = None - self._swipsound = ba.getsound('swip') - self._lucky_sound = ba.getsound('ding') + self._swipsound = bs.getsound('swip') + self._lucky_sound = bs.getsound('ding') self._flag_pos: Sequence[float] | None = None self._flag_state: FlagState | None = None self._flag: Flag | None = None - self._flag_light: ba.Node | None = None + self._flag_light: bs.Node | None = None self._scoring_team: weakref.ref[Team] | None = None self._time_limit = float(settings['Time Limit']) self._epic_mode = bool(settings['Epic Mode']) @@ -202,19 +204,19 @@ def __init__(self, settings: dict): self._lucky_capsules = bool(settings[lucky_capsules]) self._capsules: list[Any] = [] - self._capsule_model = ba.getmodel('bomb') - self._capsule_tex = ba.gettexture('bombColor') - self._capsule_lucky_tex = ba.gettexture('bombStickyColor') - self._collect_sound = ba.getsound('powerup01') - self._lucky_collect_sound = ba.getsound('cashRegister2') + self._capsule_mesh = bs.getmesh('bomb') + self._capsule_tex = bs.gettexture('bombColor') + self._capsule_lucky_tex = bs.gettexture('bombStickyColor') + self._collect_sound = bs.getsound('powerup01') + self._lucky_collect_sound = bs.getsound('cashRegister2') - self._capsule_material = ba.Material() + self._capsule_material = bs.Material() self._capsule_material.add_actions( conditions=('they_have_material', shared.player_material), actions=('call', 'at_connect', self._on_capsule_player_collide), ) - self._flag_region_material = ba.Material() + self._flag_region_material = bs.Material() self._flag_region_material.add_actions( conditions=('they_have_material', shared.player_material), actions=( @@ -223,12 +225,12 @@ def __init__(self, settings: dict): ( 'call', 'at_connect', - ba.Call(self._handle_player_flag_region_collide, True), + babase.Call(self._handle_player_flag_region_collide, True), ), ( 'call', 'at_disconnect', - ba.Call(self._handle_player_flag_region_collide, False), + babase.Call(self._handle_player_flag_region_collide, False), ), ), ) @@ -236,7 +238,7 @@ def __init__(self, settings: dict): # Base class overrides. self.slow_motion = self._epic_mode self.default_music = ( - ba.MusicType.EPIC if self._epic_mode else ba.MusicType.SCARY + bs.MusicType.EPIC if self._epic_mode else bs.MusicType.SCARY ) def get_instance_description(self) -> str | Sequence: @@ -245,7 +247,7 @@ def get_instance_description(self) -> str | Sequence: def get_instance_description_short(self) -> str | Sequence: return description_short, self._score_to_win - def create_team(self, sessionteam: ba.SessionTeam) -> Team: + def create_team(self, sessionteam: bs.SessionTeam) -> Team: return Team() def on_team_join(self, team: Team) -> None: @@ -263,18 +265,18 @@ def on_begin(self) -> None: ) self._update_scoreboard() - if isinstance(self.session, ba.FreeForAllSession): + if isinstance(self.session, bs.FreeForAllSession): self._flag_pos = self.map.get_flag_position(random.randint(0, 1)) else: self._flag_pos = self.map.get_flag_position(None) - ba.timer(1.0, self._tick, repeat=True) + bs.timer(1.0, self._tick, repeat=True) self._flag_state = FlagState.NEW Flag.project_stand(self._flag_pos) self._flag = Flag( position=self._flag_pos, touchable=False, color=(1, 1, 1) ) - self._flag_light = ba.newnode( + self._flag_light = bs.newnode( 'light', attrs={ 'position': self._flag_pos, @@ -286,7 +288,7 @@ def on_begin(self) -> None: ) # Flag region. flagmats = [self._flag_region_material, shared.region_material] - ba.newnode( + bs.newnode( 'region', attrs={ 'position': self._flag_pos, @@ -308,7 +310,7 @@ def _tick(self) -> None: if not scoring_team: return - if isinstance(self.session, ba.FreeForAllSession): + if isinstance(self.session, bs.FreeForAllSession): players = self.players else: players = scoring_team.players @@ -331,10 +333,7 @@ def _tick(self) -> None: self._flag_pos[1]+1, self._flag_pos[2] ), player) - ba.playsound( - self._collect_sound, - 0.8, - position=self._flag_pos) + self._collect_sound.play(0.8, position=self._flag_pos) self._update_scoreboard() if player.capsules > 0: @@ -347,7 +346,7 @@ def _tick(self) -> None: self.end_game() def end_game(self) -> None: - results = ba.GameResults() + results = bs.GameResults() for team in self.teams: results.set_team_score(team, team.score) self.end(results=results, announce_delay=0) @@ -369,7 +368,7 @@ def _update_flag_state(self) -> None: holding_team = list(holding_teams)[0] self._flag_state = FlagState.HELD self._scoring_team = weakref.ref(holding_team) - self._flag_light.color = ba.normalized_color(holding_team.color) + self._flag_light.color = babase.normalized_color(holding_team.color) self._flag.node.color = holding_team.color else: self._flag_state = FlagState.UNCONTESTED @@ -377,12 +376,12 @@ def _update_flag_state(self) -> None: self._flag_light.color = (0.2, 0.2, 0.2) self._flag.node.color = (1, 1, 1) if self._flag_state != prev_state: - ba.playsound(self._swipsound) + self._swipsound.play() def _handle_player_flag_region_collide(self, colliding: bool) -> None: try: - spaz = ba.getcollision().opposingnode.getdelegate(PlayerSpaz, True) - except ba.NotFoundError: + spaz = bs.getcollision().opposingnode.getdelegate(PlayerSpaz, True) + except bs.NotFoundError: return if not spaz.is_alive(): @@ -442,7 +441,7 @@ def _drop_capsule(self, player: Player) -> None: def _on_capsule_player_collide(self) -> None: if self.has_ended(): return - collision = ba.getcollision() + collision = bs.getcollision() # Be defensive here; we could be hitting the corpse of a player # who just left/etc. @@ -451,7 +450,7 @@ def _on_capsule_player_collide(self) -> None: player = collision.opposingnode.getdelegate( PlayerSpaz, True ).getplayer(Player, True) - except ba.NotFoundError: + except bs.NotFoundError: return if not player.is_alive(): @@ -465,30 +464,24 @@ def _on_capsule_player_collide(self) -> None: scale=1.5, position=capsule.node.position ).autoretain() - ba.playsound( - self._lucky_collect_sound, - 1.0, - position=capsule.node.position) - ba.emitfx( + self._lucky_collect_sound.play(1.0, position=capsule.node.position) + bs.emitfx( position=capsule.node.position, velocity=(0, 0, 0), count=int(6.4+random.random()*24), scale=1.2, spread=2.0, chunk_type='spark') - ba.emitfx( + bs.emitfx( position=capsule.node.position, velocity=(0, 0, 0), count=int(4.0+random.random()*6), emit_type='tendrils') else: player.capsules += 1 - ba.playsound( - self._collect_sound, - 0.6, - position=capsule.node.position) + self._collect_sound.play(0.6, position=capsule.node.position) # create a flash - light = ba.newnode( + light = bs.newnode( 'light', attrs={ 'position': capsule.node.position, @@ -499,27 +492,27 @@ def _on_capsule_player_collide(self) -> None: # Create a short text informing about your inventory self._handle_capsule_storage(player.position, player) - ba.animate(light, 'intensity', { + bs.animate(light, 'intensity', { 0: 0, 0.1: 0.5, 0.2: 0 }, loop=False) - ba.timer(0.2, light.delete) - capsule.handlemessage(ba.DieMessage()) + bs.timer(0.2, light.delete) + capsule.handlemessage(bs.DieMessage()) def _update_player_light(self, player: Player, capsules: int) -> None: if player.light: intensity = 0.04 * capsules - ba.animate(player.light, 'intensity', { + bs.animate(player.light, 'intensity', { 0.0: player.light.intensity, 0.1: intensity }) def newintensity(): player.light.intensity = intensity - ba.timer(0.1, newintensity) + bs.timer(0.1, newintensity) else: - player.light = ba.newnode( + player.light = bs.newnode( 'light', attrs={ 'height_attenuated': False, @@ -558,7 +551,7 @@ def _handle_capsule_storage(self, pos: float, player: Player) -> None: self._update_player_light(player, capsules) def handlemessage(self, msg: Any) -> Any: - if isinstance(msg, ba.PlayerDiedMessage): + if isinstance(msg, bs.PlayerDiedMessage): super().handlemessage(msg) # Augment default. # No longer can count as time_at_flag once dead. player = msg.getplayer(Player) @@ -572,7 +565,7 @@ def handlemessage(self, msg: Any) -> Any: return super().handlemessage(msg) -class Capsule(ba.Actor): +class Capsule(bs.Actor): def __init__(self, position: Sequence[float] = (0.0, 1.0, 0.0), @@ -586,12 +579,12 @@ def __init__(self, self._spawn_pos = (position[0], position[1], position[2]) if lucky: - ba.playsound(activity._lucky_sound, 1.0, self._spawn_pos) + activity._lucky_sound.play(1.0, self._spawn_pos) - self.node = ba.newnode( + self.node = bs.newnode( 'prop', attrs={ - 'model': activity._capsule_model, + 'mesh': activity._capsule_mesh, 'color_texture': activity._capsule_lucky_tex if lucky else ( activity._capsule_tex), 'body': 'crate' if lucky else 'capsule', @@ -606,12 +599,12 @@ def __init__(self, shared.object_material, activity._capsule_material] }, delegate=self) - ba.animate(self.node, 'model_scale', { + bs.animate(self.node, 'mesh_scale', { 0.0: 0.0, 0.1: 0.9 if lucky else 0.6, 0.16: 0.8 if lucky else 0.5 }) - self._light_capsule = ba.newnode( + self._light_capsule = bs.newnode( 'light', attrs={ 'position': self._spawn_pos, @@ -622,16 +615,16 @@ def __init__(self, self.node.connectattr('position', self._light_capsule, 'position') def handlemessage(self, msg: Any): - if isinstance(msg, ba.DieMessage): + if isinstance(msg, bs.DieMessage): self.node.delete() - ba.animate(self._light_capsule, 'intensity', { + bs.animate(self._light_capsule, 'intensity', { 0: 1.0, 0.05: 0.0 }, loop=False) - ba.timer(0.05, self._light_capsule.delete) - elif isinstance(msg, ba.OutOfBoundsMessage): - self.handlemessage(ba.DieMessage()) - elif isinstance(msg, ba.HitMessage): + bs.timer(0.05, self._light_capsule.delete) + elif isinstance(msg, bs.OutOfBoundsMessage): + self.handlemessage(bs.DieMessage()) + elif isinstance(msg, bs.HitMessage): self.node.handlemessage( 'impulse', msg.pos[0], msg.pos[1], msg.pos[2], From a53a312e3f2c446f6db529d84f0295ebb8d5a2ac Mon Sep 17 00:00:00 2001 From: SenjuZoro Date: Sun, 23 Jul 2023 15:53:04 +0000 Subject: [PATCH 0602/1464] [ci] apply-version-metadata --- plugins/minigames.json | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/plugins/minigames.json b/plugins/minigames.json index f91eb444..c773c729 100644 --- a/plugins/minigames.json +++ b/plugins/minigames.json @@ -457,7 +457,12 @@ } ], "versions": { - "2.0.0":null, + "2.0.0": { + "api_version": 8, + "commit_sha": "e8bbb61", + "released_on": "23-07-2023", + "md5sum": "1acbeecffada937bdd745f4e4d43f1be" + }, "1.0.0": { "api_version": 7, "commit_sha": "7219487", @@ -625,4 +630,4 @@ } } } -} +} \ No newline at end of file From fd6c6949f87d3d10db4392e8cbc37c583dee5cd4 Mon Sep 17 00:00:00 2001 From: SenjuZoro <69396975+SenjuZoro@users.noreply.github.com> Date: Sun, 23 Jul 2023 20:33:36 +0200 Subject: [PATCH 0603/1464] boxing updated Super boxing updated to api 8 --- plugins/minigames/boxing.py | 84 +++++++++++++++++++------------------ 1 file changed, 43 insertions(+), 41 deletions(-) diff --git a/plugins/minigames/boxing.py b/plugins/minigames/boxing.py index 35a7c759..92087842 100644 --- a/plugins/minigames/boxing.py +++ b/plugins/minigames/boxing.py @@ -1,20 +1,22 @@ -# ba_meta require api 7 +# ba_meta require api 8 # (see https://ballistica.net/wiki/meta-tag-system) from __future__ import annotations from typing import TYPE_CHECKING -import ba -from bastd.actor.playerspaz import PlayerSpaz -from bastd.actor.scoreboard import Scoreboard -from bastd.game.deathmatch import DeathMatchGame +import babase +import bauiv1 as bui +import bascenev1 as bs +from bascenev1lib.actor.playerspaz import PlayerSpaz +from bascenev1lib.actor.scoreboard import Scoreboard +from bascenev1lib.game.deathmatch import DeathMatchGame if TYPE_CHECKING: from typing import Any, Sequence -lang = ba.app.lang.language +lang = bs.app.lang.language if lang == 'Spanish': name = 'Super Boxeo' @@ -33,7 +35,7 @@ class NewPlayerSpaz(PlayerSpaz): def __init__(self, - player: ba.Player, + player: bs.Player, color: Sequence[float] = (1.0, 1.0, 1.0), highlight: Sequence[float] = (0.5, 0.5, 0.5), character: str = 'Spaz', @@ -44,16 +46,16 @@ def __init__(self, highlight=highlight, character=character, powerups_expire=powerups_expire) - from bastd.gameutils import SharedObjects + from bascenev1lib.gameutils import SharedObjects shared = SharedObjects.get() self._super_jump = super_jump self.jump_mode = False - self.super_jump_material = ba.Material() + self.super_jump_material = bs.Material() self.super_jump_material.add_actions( conditions=('they_have_material', shared.footing_material), actions=( - ('call', 'at_connect', ba.Call(self.jump_state, True)), - ('call', 'at_disconnect', ba.Call(self.jump_state, False)) + ('call', 'at_connect', babase.Call(self.jump_state, True)), + ('call', 'at_disconnect', babase.Call(self.jump_state, False)) ), ) self.node.roller_materials += (self.super_jump_material, ) @@ -68,7 +70,7 @@ def on_jump_press(self) -> None: """ if not self.node: return - t_ms = ba.time(timeformat=ba.TimeFormat.MILLISECONDS) + t_ms = int(bs.time() * 1000.0) assert isinstance(t_ms, int) if t_ms - self.last_jump_time_ms >= self._jump_cooldown: self.node.jump_pressed = True @@ -81,15 +83,15 @@ def do_jump(): self.node.position[0], self.node.position[1], self.node.position[2], - 0, 0, 0, 150, 150, 0, 0, 0, 1, 0 + 0, 0, 0, 95, 95, 0, 0, 0, 1, 0 ) - ba.timer(0.0, do_jump) - ba.timer(0.1, do_jump) - ba.timer(0.2, do_jump) + bs.timer(0.0, do_jump) + bs.timer(0.1, do_jump) + bs.timer(0.2, do_jump) self._turbo_filter_add_press('jump') -# ba_meta export game +# ba_meta export bascenev1.GameActivity class BoxingGame(DeathMatchGame): name = name @@ -97,16 +99,16 @@ class BoxingGame(DeathMatchGame): @classmethod def get_available_settings( - cls, sessiontype: type[ba.Session] - ) -> list[ba.Setting]: + cls, sessiontype: type[bs.Session] + ) -> list[babase.Setting]: settings = [ - ba.IntSetting( + bs.IntSetting( 'Kills to Win Per Player', min_value=1, default=5, increment=1, ), - ba.IntChoiceSetting( + bs.IntChoiceSetting( 'Time Limit', choices=[ ('None', 0), @@ -118,7 +120,7 @@ def get_available_settings( ], default=0, ), - ba.FloatChoiceSetting( + bs.FloatChoiceSetting( 'Respawn Times', choices=[ ('Shorter', 0.25), @@ -129,9 +131,9 @@ def get_available_settings( ], default=1.0, ), - ba.BoolSetting(super_jump_text, default=False), - ba.BoolSetting(enable_powerups, default=False), - ba.BoolSetting('Epic Mode', default=False), + bs.BoolSetting(super_jump_text, default=False), + bs.BoolSetting(enable_powerups, default=False), + bs.BoolSetting('Epic Mode', default=False), ] # In teams mode, a suicide gives a point to the other team, but in @@ -139,9 +141,9 @@ def get_available_settings( # this at zero to benefit new players, but pro players might like to # be able to go negative. (to avoid a strategy of just # suiciding until you get a good drop) - if issubclass(sessiontype, ba.FreeForAllSession): + if issubclass(sessiontype, bs.FreeForAllSession): settings.append( - ba.BoolSetting('Allow Negative Scores', default=False) + bs.BoolSetting('Allow Negative Scores', default=False) ) return settings @@ -150,7 +152,7 @@ def __init__(self, settings: dict): super().__init__(settings) self._scoreboard = Scoreboard() self._score_to_win: int | None = None - self._dingsound = ba.getsound('dingSmall') + self._dingsound = bs.getsound('dingSmall') self._epic_mode = bool(settings['Epic Mode']) self._kills_to_win_per_player = int(settings['Kills to Win Per Player']) self._time_limit = float(settings['Time Limit']) @@ -163,11 +165,11 @@ def __init__(self, settings: dict): # Base class overrides. self.slow_motion = self._epic_mode self.default_music = ( - ba.MusicType.EPIC if self._epic_mode else ba.MusicType.TO_THE_DEATH + bs.MusicType.EPIC if self._epic_mode else bs.MusicType.TO_THE_DEATH ) def on_begin(self) -> None: - ba.TeamGameActivity.on_begin(self) + bs.TeamGameActivity.on_begin(self) self.setup_standard_time_limit(self._time_limit) if self._enable_powerups: self.setup_standard_powerup_drops() @@ -180,7 +182,7 @@ def on_begin(self) -> None: def _standard_drop_powerup(self, index: int, expire: bool = True) -> None: # pylint: disable=cyclic-import - from bastd.actor.powerupbox import PowerupBox, PowerupBoxFactory + from bascenev1lib.actor.powerupbox import PowerupBox, PowerupBoxFactory PowerupBox( position=self.map.powerup_spawn_points[index], @@ -191,13 +193,13 @@ def _standard_drop_powerup(self, index: int, expire: bool = True) -> None: expire=expire, ).autoretain() - def spawn_player(self, player: Player) -> ba.Actor: + def spawn_player(self, player: Player) -> bs.Actor: import random - from ba import _math - from ba._gameutils import animate - from ba._coopsession import CoopSession + from babase import _math + from bascenev1._gameutils import animate + from bascenev1._coopsession import CoopSession - if isinstance(self.session, ba.DualTeamSession): + if isinstance(self.session, bs.DualTeamSession): position = self.map.get_start_position(player.team.id) else: # otherwise do free-for-all spawn locations @@ -208,7 +210,7 @@ def spawn_player(self, player: Player) -> ba.Actor: highlight = player.highlight light_color = _math.normalized_color(color) - display_color = ba.safecolor(color, target_intensity=0.75) + display_color = babase.safecolor(color, target_intensity=0.75) spaz = NewPlayerSpaz(color=color, highlight=highlight, @@ -224,14 +226,14 @@ def spawn_player(self, player: Player) -> ba.Actor: # Move to the stand position and add a flash of light. spaz.handlemessage( - ba.StandMessage( + bs.StandMessage( position, angle if angle is not None else random.uniform(0, 360))) - ba.playsound(self._spawn_sound, 1, position=spaz.node.position) - light = ba.newnode('light', attrs={'color': light_color}) + self._spawn_sound.play(1, position=spaz.node.position) + light = bs.newnode('light', attrs={'color': light_color}) spaz.node.connectattr('position', light, 'position') animate(light, 'intensity', {0: 0, 0.25: 1, 0.5: 0}) - ba.timer(0.5, light.delete) + bs.timer(0.5, light.delete) # custom spaz.connect_controls_to_player(enable_bomb=False) From da2f43e266ce1e6f6c896679048bd29c9ea81c4e Mon Sep 17 00:00:00 2001 From: SenjuZoro <69396975+SenjuZoro@users.noreply.github.com> Date: Sun, 23 Jul 2023 20:34:43 +0200 Subject: [PATCH 0604/1464] Update minigames.json --- plugins/minigames.json | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/plugins/minigames.json b/plugins/minigames.json index c773c729..7a4e794b 100644 --- a/plugins/minigames.json +++ b/plugins/minigames.json @@ -115,6 +115,7 @@ } ], "versions": { + "2.0.0:null, "1.0.0": { "api_version": 7, "commit_sha": "2fda676", @@ -630,4 +631,4 @@ } } } -} \ No newline at end of file +} From 626387255f7d267c7fac6516941172e4353882fa Mon Sep 17 00:00:00 2001 From: SenjuZoro <69396975+SenjuZoro@users.noreply.github.com> Date: Sun, 23 Jul 2023 20:45:19 +0200 Subject: [PATCH 0605/1464] Update minigames.json --- plugins/minigames.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/minigames.json b/plugins/minigames.json index 7a4e794b..688f6c2a 100644 --- a/plugins/minigames.json +++ b/plugins/minigames.json @@ -115,7 +115,7 @@ } ], "versions": { - "2.0.0:null, + "2.0.0":null, "1.0.0": { "api_version": 7, "commit_sha": "2fda676", From 522948c26899d72d9bfd98ca07ce6142c4ea9e42 Mon Sep 17 00:00:00 2001 From: SenjuZoro Date: Sun, 23 Jul 2023 18:45:49 +0000 Subject: [PATCH 0606/1464] [ci] apply-version-metadata --- plugins/minigames.json | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/plugins/minigames.json b/plugins/minigames.json index 688f6c2a..d4b2bec9 100644 --- a/plugins/minigames.json +++ b/plugins/minigames.json @@ -115,7 +115,12 @@ } ], "versions": { - "2.0.0":null, + "2.0.0": { + "api_version": 8, + "commit_sha": "6263872", + "released_on": "23-07-2023", + "md5sum": "9789ad3583f1d92d4e4b7bc03d09591d" + }, "1.0.0": { "api_version": 7, "commit_sha": "2fda676", @@ -631,4 +636,4 @@ } } } -} +} \ No newline at end of file From 01f48c58a6b6f2442d3970289d1ffb3e627827cc Mon Sep 17 00:00:00 2001 From: brostos <67740566+brostosjoined@users.noreply.github.com> Date: Mon, 24 Jul 2023 01:20:12 +0300 Subject: [PATCH 0607/1464] md5 --- plugins/utilities/discord_richpresence.py | 30 +++++++++++++---------- 1 file changed, 17 insertions(+), 13 deletions(-) diff --git a/plugins/utilities/discord_richpresence.py b/plugins/utilities/discord_richpresence.py index 5b01fdb9..558af75c 100644 --- a/plugins/utilities/discord_richpresence.py +++ b/plugins/utilities/discord_richpresence.py @@ -10,7 +10,6 @@ from urllib.request import Request, urlopen, urlretrieve from pathlib import Path from os import getcwd, remove -from zipfile import ZipFile from bauiv1lib.popup import PopupWindow from babase._mgen.enums import TimeType @@ -22,6 +21,7 @@ import time import threading import shutil +import hashlib import babase import _babase import bascenev1 as bs @@ -42,17 +42,19 @@ # Installing websocket def get_module(): install_path = Path(f"{getcwd()}/ba_data/python") # For the guys like me on windows - path = Path(f"{install_path}/websocket.zip") + path = Path(f"{install_path}/websocket.tar.gz") file_path = Path(f"{install_path}/websocket") source_dir = Path(f"{install_path}/websocket-client-1.6.1/websocket") if not file_path.exists(): - url = "https://github.com/websocket-client/websocket-client/archive/refs/tags/v1.6.1.zip" + url = "https://files.pythonhosted.org/packages/b1/34/3a5cae1e07d9566ad073fa6d169bf22c03a3ba7b31b3c3422ec88d039108/websocket-client-1.6.1.tar.gz" try: filename, headers = urlretrieve(url, filename=path) - with ZipFile(filename) as f: - f.extractall(install_path) - shutil.copytree(source_dir, file_path) - shutil.rmtree(Path(f"{install_path}/websocket-client-1.6.1")) + with open(filename, "rb") as f: + content = f.read() + assert hashlib.md5(content).hexdigest() == "86bc69b61947943627afc1b351c0b5db" + shutil.unpack_archive( filename, install_path) + shutil.copytree(source_dir, file_path) + shutil.rmtree(Path(f"{install_path}/websocket-client-1.6.1")) remove(path) except Exception as e: if type(e) == shutil.Error: @@ -223,17 +225,19 @@ def close(self): # installing pypresence def get_module(): install_path = Path(f"{getcwd()}/ba_data/python") - path = Path(f"{install_path}/pypresence.zip") + path = Path(f"{install_path}/pypresence.tar.gz") file_path = Path(f"{install_path}/pypresence") source_dir = Path(f"{install_path}/pypresence-4.3.0/pypresence") if not file_path.exists(): - url = "https://github.com/qwertyquerty/pypresence/archive/refs/tags/v4.3.0.zip" + url = "https://files.pythonhosted.org/packages/f4/2e/d110f862720b5e3ba1b0b719657385fc4151929befa2c6981f48360aa480/pypresence-4.3.0.tar.gz" try: filename, headers = urlretrieve(url, filename=path) - with ZipFile(filename) as f: - f.extractall(install_path) - shutil.copytree(source_dir, file_path) - shutil.rmtree(Path(f"{install_path}/pypresence-4.3.0")) + with open(filename, "rb") as f: + content = f.read() + assert hashlib.md5(content).hexdigest() == "f7c163cdd001af2456c09e241b90bad7" + shutil.unpack_archive( filename, install_path) + shutil.copytree(source_dir, file_path) + shutil.rmtree(Path(f"{install_path}/pypresence-4.3.0")) remove(path) except: pass From e32326d3ab80a0221c5a54632e0a5ef3fb503778 Mon Sep 17 00:00:00 2001 From: brostosjoined Date: Sun, 23 Jul 2023 22:20:46 +0000 Subject: [PATCH 0608/1464] [ci] auto-format --- plugins/utilities/discord_richpresence.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/plugins/utilities/discord_richpresence.py b/plugins/utilities/discord_richpresence.py index 558af75c..383c5a08 100644 --- a/plugins/utilities/discord_richpresence.py +++ b/plugins/utilities/discord_richpresence.py @@ -52,7 +52,7 @@ def get_module(): with open(filename, "rb") as f: content = f.read() assert hashlib.md5(content).hexdigest() == "86bc69b61947943627afc1b351c0b5db" - shutil.unpack_archive( filename, install_path) + shutil.unpack_archive(filename, install_path) shutil.copytree(source_dir, file_path) shutil.rmtree(Path(f"{install_path}/websocket-client-1.6.1")) remove(path) @@ -235,7 +235,7 @@ def get_module(): with open(filename, "rb") as f: content = f.read() assert hashlib.md5(content).hexdigest() == "f7c163cdd001af2456c09e241b90bad7" - shutil.unpack_archive( filename, install_path) + shutil.unpack_archive(filename, install_path) shutil.copytree(source_dir, file_path) shutil.rmtree(Path(f"{install_path}/pypresence-4.3.0")) remove(path) From 90fff9b8a029eac1ee6e938955655e8c3e6008f1 Mon Sep 17 00:00:00 2001 From: brostos <67740566+brostosjoined@users.noreply.github.com> Date: Mon, 24 Jul 2023 01:20:55 +0300 Subject: [PATCH 0609/1464] Update utilities.json --- plugins/utilities.json | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/plugins/utilities.json b/plugins/utilities.json index 3c2240ca..95557ec7 100644 --- a/plugins/utilities.json +++ b/plugins/utilities.json @@ -767,12 +767,7 @@ } ], "versions": { - "1.1.0": { - "api_version": 8, - "commit_sha": "7c07409", - "released_on": "22-07-2023", - "md5sum": "2313a4a4939508ea4a907c8f6d23d96c" - }, + "1.1.0": null, "1.0.0": { "api_version": 8, "commit_sha": "230d12d", @@ -782,4 +777,4 @@ } } } -} \ No newline at end of file +} From da69d3d9e73e49fffcfc763a018b048cdf4a3be0 Mon Sep 17 00:00:00 2001 From: brostosjoined Date: Sun, 23 Jul 2023 22:21:26 +0000 Subject: [PATCH 0610/1464] [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 95557ec7..ceb32a85 100644 --- a/plugins/utilities.json +++ b/plugins/utilities.json @@ -767,7 +767,12 @@ } ], "versions": { - "1.1.0": null, + "1.1.0": { + "api_version": 8, + "commit_sha": "90fff9b", + "released_on": "23-07-2023", + "md5sum": "69723f76a0114fe99d6c85715ad4eb49" + }, "1.0.0": { "api_version": 8, "commit_sha": "230d12d", @@ -777,4 +782,4 @@ } } } -} +} \ No newline at end of file From 9a4eb7a9f5f7e490bdb745079ab1bd175695441a Mon Sep 17 00:00:00 2001 From: SenjuZoro <69396975+SenjuZoro@users.noreply.github.com> Date: Mon, 24 Jul 2023 02:17:59 +0200 Subject: [PATCH 0611/1464] quake original minigame Bringing back good ol' quake game from 1.4 Now available on latest BS (api 8) --- plugins/minigames/quake_original.py | 616 ++++++++++++++++++++++++++++ 1 file changed, 616 insertions(+) create mode 100644 plugins/minigames/quake_original.py diff --git a/plugins/minigames/quake_original.py b/plugins/minigames/quake_original.py new file mode 100644 index 00000000..6af5849a --- /dev/null +++ b/plugins/minigames/quake_original.py @@ -0,0 +1,616 @@ +# Created By Idk +# Ported to 1.7 by Yan + +# ba_meta require api 8 +from __future__ import annotations + +from typing import TYPE_CHECKING + +from bascenev1lib.actor.powerupbox import PowerupBox as Powerup +from bascenev1lib.actor.playerspaz import PlayerSpaz +from bascenev1lib.actor.scoreboard import Scoreboard +from bascenev1lib.gameutils import SharedObjects + +import bascenev1lib.actor.bomb +import bascenev1lib.actor.spaz +import weakref +import random +import math +import babase +import bauiv1 as bui +import bascenev1 as bs + +if TYPE_CHECKING: + pass + + +class TouchedToSpaz(object): + pass + +class TouchedToAnything(object): + pass + +class TouchedToFootingMaterial(object): + pass + +class QuakeBallFactory(object): + """Components used by QuakeBall stuff + + category: Game Classes + + """ + _STORENAME = babase.storagename() + @classmethod + def get(cls) -> QuakeBallFactory: + """Get/create a shared bascenev1lib.actor.bomb.BombFactory object.""" + activity = bs.getactivity() + factory = activity.customdata.get(cls._STORENAME) + if factory is None: + factory = QuakeBallFactory() + activity.customdata[cls._STORENAME] = factory + assert isinstance(factory, QuakeBallFactory) + return factory + + def __init__(self): + shared = SharedObjects.get() + + self.ball_material = bs.Material() + + self.ball_material.add_actions( + conditions=((('we_are_younger_than', 5), 'or', ('they_are_younger_than', 50)), + 'and', ('they_have_material', shared.object_material)), + actions=(('modify_node_collision', 'collide', False))) + + self.ball_material.add_actions( + conditions=('they_have_material', shared.pickup_material), + actions=(('modify_part_collision', 'use_node_collide', False))) + + self.ball_material.add_actions( + actions=('modify_part_collision', 'friction', 0)) + + self.ball_material.add_actions( + conditions=('they_have_material', shared.player_material), + actions=(('modify_part_collision', 'physical', False), + ('message', 'our_node', 'at_connect', TouchedToSpaz()))) + + self.ball_material.add_actions( + conditions=(('they_dont_have_material', shared.player_material), 'and', + ('they_have_material', shared.object_material)), + actions=('message', 'our_node', 'at_connect', TouchedToAnything())) + + self.ball_material.add_actions( + conditions=(('they_dont_have_material', shared.player_material), 'and', + ('they_have_material', shared.footing_material)), + actions=('message', 'our_node', 'at_connect', TouchedToFootingMaterial())) + + def give(self, spaz): + spaz.punch_callback = self.shot + self.last_shot = int(bs.time() * 1000) + + def shot(self, spaz): + time = int(bs.time() * 1000) + if time - self.last_shot > 0.6: + self.last_shot = time + p1 = spaz.node.position_center + p2 = spaz.node.position_forward + direction = [p1[0]-p2[0], p2[1]-p1[1], p1[2]-p2[2]] + direction[1] = 0.0 + + mag = 10.0/babase.Vec3(*direction).length() + vel = [v * mag for v in direction] + QuakeBall( + position=spaz.node.position, + velocity=(vel[0]*2, vel[1]*2, vel[2]*2), + owner=spaz._player, + source_player=spaz._player, + color=spaz.node.color).autoretain() + + +class QuakeBall(bs.Actor): + + def __init__(self, + position=(0, 5, 0), + velocity=(0, 2, 0), + source_player=None, + owner=None, + color=(random.random(), random.random(), random.random()), + light_radius=0 + ): + super().__init__() + + shared = SharedObjects.get() + b_shared = QuakeBallFactory.get() + + self.source_player = source_player + self.owner = owner + + self.node = bs.newnode('prop', delegate=self, attrs={ + 'position': position, + 'velocity': velocity, + 'mesh': bs.getmesh('impactBomb'), + 'body': 'sphere', + 'color_texture': bs.gettexture('bunnyColor'), + 'mesh_scale': 0.2, + 'is_area_of_interest': True, + 'body_scale': 0.8, + 'materials': [shared.object_material, + b_shared.ball_material]}) + + self.light_node = bs.newnode('light', attrs={ + 'position':position, + 'color': color, + 'radius': 0.1+light_radius, + 'volume_intensity_scale': 15.0}) + + self.node.connectattr('position', self.light_node, 'position') + self.emit_time = bs.Timer(0.015, bs.WeakCall(self.emit), repeat=True) + self.life_time = bs.Timer(5.0, bs.WeakCall(self.handlemessage, bs.DieMessage())) + + def emit(self): + bs.emitfx( + position=self.node.position, + velocity=self.node.velocity, + count=10, + scale=0.4, + spread=0.01, + chunk_type='spark') + + def handlemessage(self, m): + if isinstance(m, TouchedToAnything): + node = bs.getcollision().opposingnode + if node is not None and node.exists(): + v = self.node.velocity + t = self.node.position + hitdir = self.node.velocity + m = self.node + node.handlemessage( + bs.HitMessage( + pos=t, + velocity=v, + magnitude=babase.Vec3(*v).length()*40, + velocity_magnitude=babase.Vec3(*v).length()*40, + radius=0, + srcnode=self.node, + source_player=self.source_player, + force_direction=hitdir)) + + self.node.handlemessage(bs.DieMessage()) + + elif isinstance(m, bs.DieMessage): + if self.node.exists(): + velocity = self.node.velocity + explosion = bs.newnode('explosion', attrs={ + 'position': self.node.position, + 'velocity': (velocity[0], max(-1.0,velocity[1]), velocity[2]), + 'radius': 1, + 'big': False}) + + bs.getsound(random.choice(['impactHard', 'impactHard2', 'impactHard3'])).play(), + position=self.node.position + + self.emit_time = None + self.light_node.delete() + self.node.delete() + + elif isinstance(m, bs.OutOfBoundsMessage): + self.handlemessage(bs.DieMessage()) + + elif isinstance(m, bs.HitMessage): + self.node.handlemessage('impulse', m.pos[0], m.pos[1], m.pos[2], + m.velocity[0], m.velocity[1], m.velocity[2], + 1.0*m.magnitude, 1.0*m.velocity_magnitude, m.radius,0, + m.force_direction[0], m.force_direction[1], m.force_direction[2]) + + elif isinstance(m, TouchedToSpaz): + node = bs.getcollision() .opposingnode + if node is not None and node.exists() and node != self.owner \ + and node.getdelegate(object)._player.team != self.owner.team: + node.handlemessage(bs.FreezeMessage()) + v = self.node.velocity + t = self.node.position + hitdir = self.node.velocity + + node.handlemessage( + bs.HitMessage( + pos=t, + velocity=(10, 10, 10), + magnitude=50, + velocity_magnitude=50, + radius=0, + srcnode=self.node, + source_player=self.source_player, + force_direction=hitdir)) + + self.node.handlemessage(bs.DieMessage()) + + elif isinstance(m, TouchedToFootingMaterial): + bs.getsound('blip').play(), + position=self.node.position + else: + super().handlemessage(m) + + + + +class Player(bs.Player['Team']): + ... + + +class Team(bs.Team[Player]): + """Our team type for this game.""" + + def __init__(self) -> None: + self.score = 0 + +# ba_meta export bascenev1.GameActivity +class QuakeGame(bs.TeamGameActivity[Player, Team]): + """A game type based on acquiring kills.""" + + name = 'Quake' + description = 'Kill a set number of enemies to win.' + + # Print messages when players die since it matters here. + announce_player_deaths = True + + @classmethod + def supports_session_type(cls, sessiontype: type[bs.Session]) -> bool: + return issubclass(sessiontype, bs.DualTeamSession) or issubclass( + sessiontype, bs.FreeForAllSession + ) + + @classmethod + def get_supported_maps(cls, sessiontype: type[bs.Session]) -> list[str]: + return ['Doom Shroom', 'Monkey Face', 'Football Stadium'] + + @classmethod + def get_available_settings( + cls, sessiontype: type[bs.Session] + ) -> list[babase.Setting]: + settings = [ + bs.IntSetting( + 'Kills to Win Per Player', + min_value=1, + default=5, + increment=1, + ), + bs.IntChoiceSetting( + 'Time Limit', + choices=[ + ('None', 0), + ('1 Minute', 60), + ('2 Minutes', 120), + ('5 Minutes', 300), + ('10 Minutes', 600), + ('20 Minutes', 1200), + ], + default=0, + ), + bs.FloatChoiceSetting( + 'Respawn Times', + choices=[ + ('Shorter', 0.25), + ('Short', 0.5), + ('Normal', 1.0), + ('Long', 2.0), + ('Longer', 4.0), + ], + default=1.0, + ), + bs.IntChoiceSetting( + 'Graphics', + choices=[ + ('Normal', 1), + ('High', 2) + ], + default=1), + bs.BoolSetting('Fast Movespeed', default=True), + bs.BoolSetting('Enable Jump', default=False), + bs.BoolSetting('Enable Pickup', default=False), + bs.BoolSetting('Enable Bomb', default=False), + bs.BoolSetting('Obstacles', default=False), + bs.IntChoiceSetting( + 'Obstacles Shape', + choices=[ + ('Cube', 1), + ('Sphere', 2), + ('Puck', 3), + ('Egg', 4), + ('Random', 5), + ], + default=1), + bs.BoolSetting('Obstacles Bounces Shots', default=False), + bs.IntSetting( + 'Obstacle Count', + min_value=1, + default=16, + increment=1, + ), + bs.BoolSetting('Random Obstacle Color', default=True), + bs.BoolSetting('Epic Mode', default=False), + ] + return settings + + def __init__(self, settings: dict): + super().__init__(settings) + self._scoreboard = Scoreboard() + self._score_to_win: int | None = None + self._dingsound = bs.getsound('dingSmall') + self._epic_mode = bool(settings['Epic Mode']) + self._kills_to_win_per_player = int(settings['Kills to Win Per Player']) + self._time_limit = float(settings['Time Limit']) + self._allow_negative_scores = bool( + settings.get('Allow Negative Scores', False) + ) + + # Base class overrides. + self.slow_motion = self._epic_mode + self.default_music = ( + bs.MusicType.EPIC if self._epic_mode else bs.MusicType.TO_THE_DEATH + ) + self.settings = settings + + def get_instance_description(self) -> str | Sequence: + return 'Crush ${ARG1} of your enemies.', self._score_to_win + + def get_instance_description_short(self) -> str | Sequence: + return 'kill ${ARG1} enemies', self._score_to_win + + def on_team_join(self, team: Team) -> None: + if self.has_begun(): + self._update_scoreboard() + + def on_begin(self) -> None: + super().on_begin() + self.dingsound = bs.getsound('dingSmall') + self.setup_standard_time_limit(self._time_limit) + + self.drop_shield() + self.drop_shield_timer = bs.Timer(8.001, bs.WeakCall(self.drop_shield), repeat=True) + + shared = SharedObjects.get() + if self.settings['Obstacles']: + count = self.settings['Obstacle Count'] + map = bs.getactivity()._map.getname() + for i in range(count): + if map == 'Football Stadium': + radius = (random.uniform(-10, 1), + 6, + random.uniform(-4.5, 4.5)) \ + if i > count/2 else (random.uniform(10, 1), 6, random.uniform(-4.5, 4.5)) + else: + radius = (random.uniform(-10,1), + 6, + random.uniform(-8,8)) \ + if i > count/2 else (random.uniform(10, 1), 6, random.uniform(-8, 8)) + + Obstacle( + position=radius, + graphics=self.settings['Graphics'], + random_color=self.settings['Random Obstacle Color'], + rebound=self.settings['Obstacles Bounces Shots'], + shape=int(self.settings['Obstacles Shape'])).autoretain() + + if self.settings['Graphics'] == 2: + bs.getactivity().globalsnode.tint = (bs.getactivity().globalsnode.tint[0]-0.6, bs.getactivity().globalsnode.tint[1]-0.6, bs.getactivity().globalsnode.tint[2]-0.6) + light = bs.newnode('light', attrs={ + 'position': (9, 10, 0) if map == 'Football Stadium' else (6, 7, -2) \ + if not map == 'Rampage' else (6, 11, -2) if not map == 'The Pad' else (6, 8.5, -2), + 'color': (0.4, 0.4, 0.45), + 'radius': 1, + 'intensity': 6, + 'volume_intensity_scale': 10.0}) + + light2 = bs.newnode('light', attrs={ + 'position': (-9, 10, 0) if map == 'Football Stadium' else (-6, 7, -2) \ + if not map == 'Rampage' else (-6, 11, -2) if not map == 'The Pad' else (-6, 8.5, -2), + 'color': (0.4, 0.4, 0.45), + 'radius': 1, + 'intensity': 6, + 'volume_intensity_scale': 10.0}) + + if len(self.teams) > 0: + self._score_to_win = self.settings['Kills to Win Per Player']*max(1, max(len(t.players) for t in self.teams)) + else: + self._score_to_win = self.settings['Kills to Win Per Player'] + self._update_scoreboard() + + def drop_shield(self): + p = Powerup( + poweruptype='shield', + position=(random.uniform(-10, 10), 6, random.uniform(-5, 5))).autoretain() + + bs.getsound('dingSmall').play() + + p_light = bs.newnode('light', attrs={ + 'position': (0, 0, 0), + 'color': (0.3, 0.0, 0.4), + 'radius': 0.3, + 'intensity': 2, + 'volume_intensity_scale': 10.0}) + + p.node.connectattr('position', p_light, 'position') + + bs.animate(p_light, 'intensity', {0: 2, 8000: 0}) + + def check_exists(): + if p is None or p.node.exists() == False: + delete_light() + del_checker() + + self._checker = bs.Timer(0.1,babase.Call(check_exists), repeat=True) + + def del_checker(): + if self._checker is not None: + self._checker = None + + def delete_light(): + if p_light.exists(): + p_light.delete() + + bs.timer(6.9, babase.Call(del_checker)) + bs.timer(7.0, babase.Call(delete_light)) + + def spawn_player(self, player: bs.Player): + spaz = self.spawn_player_spaz(player) + QuakeBallFactory().give(spaz) + spaz.connect_controls_to_player( + enable_jump=self.settings['Enable Jump'], + enable_punch=True, + enable_pickup=self.settings['Enable Pickup'], + enable_bomb=self.settings['Enable Bomb'], + enable_run=True, + enable_fly=False) + + if self.settings['Fast Movespeed']: spaz.node.hockey = True + spaz.spaz_light = bs.newnode('light', attrs={ + 'position': (0, 0, 0), + 'color': spaz.node.color, + 'radius': 0.12, + 'intensity': 1, + 'volume_intensity_scale': 10.0}) + + spaz.node.connectattr('position', spaz.spaz_light, 'position') + + def handlemessage(self, msg: Any) -> Any: + + if isinstance(msg, bs.PlayerDiedMessage): + + # Augment standard behavior. + super().handlemessage(msg) + + player = msg.getplayer(Player) + self.respawn_player(player) + + killer = msg.getkillerplayer(Player) + if hasattr(player.actor, 'spaz_light'): + player.actor.spaz_light.delete() + if killer is None: + return None + + # Handle team-kills. + if killer.team is player.team: + + # In free-for-all, killing yourself loses you a point. + if isinstance(self.session, bs.FreeForAllSession): + new_score = player.team.score - 1 + if not self._allow_negative_scores: + new_score = max(0, new_score) + player.team.score = new_score + + # In teams-mode it gives a point to the other team. + else: + self._dingsound.play() + for team in self.teams: + if team is not killer.team: + team.score += 1 + + # Killing someone on another team nets a kill. + else: + killer.team.score += 1 + self._dingsound.play() + + # In FFA show scores since its hard to find on the scoreboard. + if isinstance(killer.actor, PlayerSpaz) and killer.actor: + killer.actor.set_score_text( + str(killer.team.score) + '/' + str(self._score_to_win), + color=killer.team.color, + flash=True, + ) + + self._update_scoreboard() + + # If someone has won, set a timer to end shortly. + # (allows the dust to clear and draws to occur if deaths are + # close enough) + assert self._score_to_win is not None + if any(team.score >= self._score_to_win for team in self.teams): + bs.timer(0.5, self.end_game) + + else: + return super().handlemessage(msg) + return None + + def _update_scoreboard(self) -> None: + for team in self.teams: + self._scoreboard.set_team_value( + team, team.score, self._score_to_win + ) + + def end_game(self) -> None: + results = bs.GameResults() + for team in self.teams: + results.set_team_score(team, team.score) + self.end(results=results) + +class Obstacle(bs.Actor): + + def __init__(self, + position: tuple(float, float, float), + graphics: bool, + random_color: bool, + rebound: bool, + shape: int) -> None: + super().__init__() + + shared = SharedObjects.get() + if shape == 1: + mesh = 'tnt' + body = 'crate' + elif shape == 2: + mesh = 'bomb' + body = 'sphere' + elif shape == 3: + mesh = 'puck' + body = 'puck' + elif shape == 4: + mesh = 'egg' + body = 'capsule' + elif shape == 5: + pair = random.choice([ + {'mesh':'tnt', 'body':'crate'}, + {'mesh':'bomb', 'body':'sphere'}, + {'mesh':'puckModel', 'body':'puck'}, + {'mesh':'egg', 'body':'capsule'} + ]) + mesh = pair['mesh'] + body = pair['body'] + + self.node = bs.newnode('prop', delegate=self, attrs={ + 'position': position, + 'mesh': bs.getmesh(mesh), + 'body': body, + 'body_scale': 1.3, + 'mesh_scale': 1.3, + 'reflection': 'powerup', + 'reflection_scale': [0.7], + 'color_texture': bs.gettexture('bunnyColor'), + 'materials': [shared.footing_material if rebound else shared.object_material, + shared.footing_material]}) + + if graphics == 2: + self.light_node = bs.newnode('light', attrs={ + 'position': (0, 0, 0), + 'color': ((0.8, 0.2, 0.2) if i < count/2 else (0.2, 0.2, 0.8)) \ + if not random_color else ((random.uniform(0, 1.1), random.uniform(0, 1.1), random.uniform(0, 1.1))), + 'radius': 0.2, + 'intensity': 1, + 'volume_intensity_scale': 10.0}) + + self.node.connectattr('position', self.light_node, 'position') + + def handlemessage(self, m): + if isinstance(m, bs.DieMessage): + if self.node.exists(): + if hasattr(self, 'light_node'): + self.light_node.delete() + self.node.delete() + + elif isinstance(m, bs.OutOfBoundsMessage): + if self.node.exists(): + self.handlemessage(bs.DieMessage()) + + elif isinstance(m, bs.HitMessage): + self.node.handlemessage('impulse', m.pos[0], m.pos[1], m.pos[2], + m.velocity[0], m.velocity[1], m.velocity[2], + m.magnitude, m.velocity_magnitude, m.radius,0, + m.velocity[0], m.velocity[1], m.velocity[2]) \ No newline at end of file From 12d51c3b1d7569bf5958b0432cbf8be2f5b81b09 Mon Sep 17 00:00:00 2001 From: SenjuZoro <69396975+SenjuZoro@users.noreply.github.com> Date: Mon, 24 Jul 2023 02:23:09 +0200 Subject: [PATCH 0612/1464] Update minigames.json --- plugins/minigames.json | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/plugins/minigames.json b/plugins/minigames.json index d4b2bec9..03ec0b35 100644 --- a/plugins/minigames.json +++ b/plugins/minigames.json @@ -597,6 +597,21 @@ } } }, + "quake_original": { + "description": "Good ol' Quake minigame", + "external_url": "", + "authors": [ + { + "name": "Unknown", + "email": "", + "discord": "" + } + ], + "versions": { + "1.0.0":null + } + } + }, "ufo_fight": { "description": "Fight the UFO boss!", "external_url": "", @@ -636,4 +651,4 @@ } } } -} \ No newline at end of file +} From 2b046cb433db749abd8380dd89fa5beacaea9bf8 Mon Sep 17 00:00:00 2001 From: SenjuZoro Date: Mon, 24 Jul 2023 00:25:32 +0000 Subject: [PATCH 0613/1464] [ci] auto-format --- plugins/minigames/quake_original.py | 82 ++++++++++++++++------------- 1 file changed, 45 insertions(+), 37 deletions(-) diff --git a/plugins/minigames/quake_original.py b/plugins/minigames/quake_original.py index 6af5849a..84ff0f68 100644 --- a/plugins/minigames/quake_original.py +++ b/plugins/minigames/quake_original.py @@ -27,19 +27,23 @@ class TouchedToSpaz(object): pass + class TouchedToAnything(object): pass + class TouchedToFootingMaterial(object): pass + class QuakeBallFactory(object): """Components used by QuakeBall stuff - + category: Game Classes - + """ _STORENAME = babase.storagename() + @classmethod def get(cls) -> QuakeBallFactory: """Get/create a shared bascenev1lib.actor.bomb.BombFactory object.""" @@ -50,7 +54,7 @@ def get(cls) -> QuakeBallFactory: activity.customdata[cls._STORENAME] = factory assert isinstance(factory, QuakeBallFactory) return factory - + def __init__(self): shared = SharedObjects.get() @@ -58,7 +62,7 @@ def __init__(self): self.ball_material.add_actions( conditions=((('we_are_younger_than', 5), 'or', ('they_are_younger_than', 50)), - 'and', ('they_have_material', shared.object_material)), + 'and', ('they_have_material', shared.object_material)), actions=(('modify_node_collision', 'collide', False))) self.ball_material.add_actions( @@ -81,7 +85,7 @@ def __init__(self): self.ball_material.add_actions( conditions=(('they_dont_have_material', shared.player_material), 'and', ('they_have_material', shared.footing_material)), - actions=('message', 'our_node', 'at_connect', TouchedToFootingMaterial())) + actions=('message', 'our_node', 'at_connect', TouchedToFootingMaterial())) def give(self, spaz): spaz.punch_callback = self.shot @@ -115,7 +119,7 @@ def __init__(self, owner=None, color=(random.random(), random.random(), random.random()), light_radius=0 - ): + ): super().__init__() shared = SharedObjects.get() @@ -137,7 +141,7 @@ def __init__(self, b_shared.ball_material]}) self.light_node = bs.newnode('light', attrs={ - 'position':position, + 'position': position, 'color': color, 'radius': 0.1+light_radius, 'volume_intensity_scale': 15.0}) @@ -181,12 +185,12 @@ def handlemessage(self, m): velocity = self.node.velocity explosion = bs.newnode('explosion', attrs={ 'position': self.node.position, - 'velocity': (velocity[0], max(-1.0,velocity[1]), velocity[2]), + 'velocity': (velocity[0], max(-1.0, velocity[1]), velocity[2]), 'radius': 1, 'big': False}) bs.getsound(random.choice(['impactHard', 'impactHard2', 'impactHard3'])).play(), - position=self.node.position + position = self.node.position self.emit_time = None self.light_node.delete() @@ -198,7 +202,7 @@ def handlemessage(self, m): elif isinstance(m, bs.HitMessage): self.node.handlemessage('impulse', m.pos[0], m.pos[1], m.pos[2], m.velocity[0], m.velocity[1], m.velocity[2], - 1.0*m.magnitude, 1.0*m.velocity_magnitude, m.radius,0, + 1.0*m.magnitude, 1.0*m.velocity_magnitude, m.radius, 0, m.force_direction[0], m.force_direction[1], m.force_direction[2]) elif isinstance(m, TouchedToSpaz): @@ -225,13 +229,11 @@ def handlemessage(self, m): elif isinstance(m, TouchedToFootingMaterial): bs.getsound('blip').play(), - position=self.node.position + position = self.node.position else: super().handlemessage(m) - - class Player(bs.Player['Team']): ... @@ -243,6 +245,8 @@ def __init__(self) -> None: self.score = 0 # ba_meta export bascenev1.GameActivity + + class QuakeGame(bs.TeamGameActivity[Player, Team]): """A game type based on acquiring kills.""" @@ -376,12 +380,12 @@ def on_begin(self) -> None: radius = (random.uniform(-10, 1), 6, random.uniform(-4.5, 4.5)) \ - if i > count/2 else (random.uniform(10, 1), 6, random.uniform(-4.5, 4.5)) + if i > count/2 else (random.uniform(10, 1), 6, random.uniform(-4.5, 4.5)) else: - radius = (random.uniform(-10,1), + radius = (random.uniform(-10, 1), 6, - random.uniform(-8,8)) \ - if i > count/2 else (random.uniform(10, 1), 6, random.uniform(-8, 8)) + random.uniform(-8, 8)) \ + if i > count/2 else (random.uniform(10, 1), 6, random.uniform(-8, 8)) Obstacle( position=radius, @@ -391,26 +395,28 @@ def on_begin(self) -> None: shape=int(self.settings['Obstacles Shape'])).autoretain() if self.settings['Graphics'] == 2: - bs.getactivity().globalsnode.tint = (bs.getactivity().globalsnode.tint[0]-0.6, bs.getactivity().globalsnode.tint[1]-0.6, bs.getactivity().globalsnode.tint[2]-0.6) + bs.getactivity().globalsnode.tint = (bs.getactivity( + ).globalsnode.tint[0]-0.6, bs.getactivity().globalsnode.tint[1]-0.6, bs.getactivity().globalsnode.tint[2]-0.6) light = bs.newnode('light', attrs={ - 'position': (9, 10, 0) if map == 'Football Stadium' else (6, 7, -2) \ - if not map == 'Rampage' else (6, 11, -2) if not map == 'The Pad' else (6, 8.5, -2), + 'position': (9, 10, 0) if map == 'Football Stadium' else (6, 7, -2) + if not map == 'Rampage' else (6, 11, -2) if not map == 'The Pad' else (6, 8.5, -2), 'color': (0.4, 0.4, 0.45), 'radius': 1, 'intensity': 6, 'volume_intensity_scale': 10.0}) light2 = bs.newnode('light', attrs={ - 'position': (-9, 10, 0) if map == 'Football Stadium' else (-6, 7, -2) \ - if not map == 'Rampage' else (-6, 11, -2) if not map == 'The Pad' else (-6, 8.5, -2), + 'position': (-9, 10, 0) if map == 'Football Stadium' else (-6, 7, -2) + if not map == 'Rampage' else (-6, 11, -2) if not map == 'The Pad' else (-6, 8.5, -2), 'color': (0.4, 0.4, 0.45), 'radius': 1, 'intensity': 6, 'volume_intensity_scale': 10.0}) if len(self.teams) > 0: - self._score_to_win = self.settings['Kills to Win Per Player']*max(1, max(len(t.players) for t in self.teams)) - else: + self._score_to_win = self.settings['Kills to Win Per Player'] * \ + max(1, max(len(t.players) for t in self.teams)) + else: self._score_to_win = self.settings['Kills to Win Per Player'] self._update_scoreboard() @@ -437,7 +443,7 @@ def check_exists(): delete_light() del_checker() - self._checker = bs.Timer(0.1,babase.Call(check_exists), repeat=True) + self._checker = bs.Timer(0.1, babase.Call(check_exists), repeat=True) def del_checker(): if self._checker is not None: @@ -461,7 +467,8 @@ def spawn_player(self, player: bs.Player): enable_run=True, enable_fly=False) - if self.settings['Fast Movespeed']: spaz.node.hockey = True + if self.settings['Fast Movespeed']: + spaz.node.hockey = True spaz.spaz_light = bs.newnode('light', attrs={ 'position': (0, 0, 0), 'color': spaz.node.color, @@ -542,6 +549,7 @@ def end_game(self) -> None: results.set_team_score(team, team.score) self.end(results=results) + class Obstacle(bs.Actor): def __init__(self, @@ -553,7 +561,7 @@ def __init__(self, super().__init__() shared = SharedObjects.get() - if shape == 1: + if shape == 1: mesh = 'tnt' body = 'crate' elif shape == 2: @@ -567,11 +575,11 @@ def __init__(self, body = 'capsule' elif shape == 5: pair = random.choice([ - {'mesh':'tnt', 'body':'crate'}, - {'mesh':'bomb', 'body':'sphere'}, - {'mesh':'puckModel', 'body':'puck'}, - {'mesh':'egg', 'body':'capsule'} - ]) + {'mesh': 'tnt', 'body': 'crate'}, + {'mesh': 'bomb', 'body': 'sphere'}, + {'mesh': 'puckModel', 'body': 'puck'}, + {'mesh': 'egg', 'body': 'capsule'} + ]) mesh = pair['mesh'] body = pair['body'] @@ -587,11 +595,11 @@ def __init__(self, 'materials': [shared.footing_material if rebound else shared.object_material, shared.footing_material]}) - if graphics == 2: + if graphics == 2: self.light_node = bs.newnode('light', attrs={ 'position': (0, 0, 0), - 'color': ((0.8, 0.2, 0.2) if i < count/2 else (0.2, 0.2, 0.8)) \ - if not random_color else ((random.uniform(0, 1.1), random.uniform(0, 1.1), random.uniform(0, 1.1))), + 'color': ((0.8, 0.2, 0.2) if i < count/2 else (0.2, 0.2, 0.8)) + if not random_color else ((random.uniform(0, 1.1), random.uniform(0, 1.1), random.uniform(0, 1.1))), 'radius': 0.2, 'intensity': 1, 'volume_intensity_scale': 10.0}) @@ -612,5 +620,5 @@ def handlemessage(self, m): elif isinstance(m, bs.HitMessage): self.node.handlemessage('impulse', m.pos[0], m.pos[1], m.pos[2], m.velocity[0], m.velocity[1], m.velocity[2], - m.magnitude, m.velocity_magnitude, m.radius,0, - m.velocity[0], m.velocity[1], m.velocity[2]) \ No newline at end of file + m.magnitude, m.velocity_magnitude, m.radius, 0, + m.velocity[0], m.velocity[1], m.velocity[2]) From 185480da2980e86979cde24daf6bd0791b5ec99e Mon Sep 17 00:00:00 2001 From: SenjuZoro <69396975+SenjuZoro@users.noreply.github.com> Date: Mon, 24 Jul 2023 02:30:29 +0200 Subject: [PATCH 0614/1464] Update minigames.json --- plugins/minigames.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/minigames.json b/plugins/minigames.json index 03ec0b35..b4fd6263 100644 --- a/plugins/minigames.json +++ b/plugins/minigames.json @@ -651,4 +651,4 @@ } } } -} + From 42c05fae0a00dbccffa75731b37cd597bfddf1c1 Mon Sep 17 00:00:00 2001 From: SenjuZoro Date: Mon, 24 Jul 2023 00:30:58 +0000 Subject: [PATCH 0615/1464] [ci] apply-version-metadata --- plugins/minigames.json | 80 ++++++++++++++++++++++-------------------- 1 file changed, 42 insertions(+), 38 deletions(-) diff --git a/plugins/minigames.json b/plugins/minigames.json index b4fd6263..510551e8 100644 --- a/plugins/minigames.json +++ b/plugins/minigames.json @@ -607,48 +607,52 @@ "discord": "" } ], - "versions": { - "1.0.0":null - } - } - }, - "ufo_fight": { - "description": "Fight the UFO boss!", - "external_url": "", - "authors": [ - { - "name": "Cross Joy", - "email": "cross.joy.official@gmail.com", - "discord": "Cross Joy#0721" - } - ], "versions": { "1.0.0": { - "api_version": 7, - "commit_sha": "7219487", - "released_on": "15-05-2023", - "md5sum": "81617b130716996368b7d8f20f3a5154" + "api_version": 8, + "commit_sha": "185480d", + "released_on": "24-07-2023", + "md5sum": "f68395cc90dc8cddb166a23b2da81b7b" } } - }, - "yeeting_party": { - "description": "Yeet your enemies out of the map!", - "external_url": "", - "authors": [ - { - "name": "Freaku", - "email": "", - "discord": "[Just] Freak#4999" - } - ], - "versions": { - "1.0.0": { - "api_version": 7, - "commit_sha": "7219487", - "released_on": "15-05-2023", - "md5sum": "197a377652ab0c3bfbe1ca07833924b4" - } + } + }, + "ufo_fight": { + "description": "Fight the UFO boss!", + "external_url": "", + "authors": [ + { + "name": "Cross Joy", + "email": "cross.joy.official@gmail.com", + "discord": "Cross Joy#0721" + } + ], + "versions": { + "1.0.0": { + "api_version": 7, + "commit_sha": "7219487", + "released_on": "15-05-2023", + "md5sum": "81617b130716996368b7d8f20f3a5154" + } + } + }, + "yeeting_party": { + "description": "Yeet your enemies out of the map!", + "external_url": "", + "authors": [ + { + "name": "Freaku", + "email": "", + "discord": "[Just] Freak#4999" + } + ], + "versions": { + "1.0.0": { + "api_version": 7, + "commit_sha": "7219487", + "released_on": "15-05-2023", + "md5sum": "197a377652ab0c3bfbe1ca07833924b4" } } } - +} \ No newline at end of file From ef5f1065988746f83e1c04c6a301372674be6333 Mon Sep 17 00:00:00 2001 From: brostos <67740566+brostosjoined@users.noreply.github.com> Date: Mon, 24 Jul 2023 10:53:42 +0300 Subject: [PATCH 0616/1464] Update discord_richpresence.py --- plugins/utilities/discord_richpresence.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/utilities/discord_richpresence.py b/plugins/utilities/discord_richpresence.py index 383c5a08..285aa408 100644 --- a/plugins/utilities/discord_richpresence.py +++ b/plugins/utilities/discord_richpresence.py @@ -53,9 +53,9 @@ def get_module(): content = f.read() assert hashlib.md5(content).hexdigest() == "86bc69b61947943627afc1b351c0b5db" shutil.unpack_archive(filename, install_path) + remove(path) shutil.copytree(source_dir, file_path) shutil.rmtree(Path(f"{install_path}/websocket-client-1.6.1")) - remove(path) except Exception as e: if type(e) == shutil.Error: shutil.rmtree(Path(f"{install_path}/websocket-client-1.6.1")) From 07f9ac7251126eec91e4943773d626a1344081de Mon Sep 17 00:00:00 2001 From: SenjuZoro <69396975+SenjuZoro@users.noreply.github.com> Date: Mon, 24 Jul 2023 12:25:05 +0200 Subject: [PATCH 0617/1464] SuperSmash minigame SuperSmash minigame updated to api 8 Note: the file consist of 2 modes --> SuperSmash: Deathmatch based supersmash --> SuperSmash Elimination: Elimination based supersmash --- plugins/minigames/SuperSmash.py | 954 ++++++++++++++++++++++++++++++++ 1 file changed, 954 insertions(+) create mode 100644 plugins/minigames/SuperSmash.py diff --git a/plugins/minigames/SuperSmash.py b/plugins/minigames/SuperSmash.py new file mode 100644 index 00000000..2ffb589b --- /dev/null +++ b/plugins/minigames/SuperSmash.py @@ -0,0 +1,954 @@ +# To learn more, see https://ballistica.net/wiki/meta-tag-system +# ba_meta require api 8 + +from __future__ import annotations + +from typing import TYPE_CHECKING + +import babase +import random +import bauiv1 as bui +import bascenev1 as bs +from babase import _math +from bascenev1lib.actor.spaz import Spaz +from bascenev1lib.actor.spazfactory import SpazFactory +from bascenev1lib.actor.scoreboard import Scoreboard +from bascenev1lib.game import elimination +from bascenev1lib.game.elimination import Icon, Player, Team +from bascenev1lib.actor.bomb import Bomb, Blast +from bascenev1lib.actor.playerspaz import PlayerSpaz, PlayerSpazHurtMessage + +if TYPE_CHECKING: + from typing import Any, Type, List, Sequence, Optional + + +class Icon(Icon): + def update_for_lives(self) -> None: + """Update for the target player's current lives.""" + if self._player: + lives = self._player.lives + else: + lives = 0 + if self._show_lives: + if lives > 1: + self._lives_text.text = 'x' + str(lives - 1) + else: + self._lives_text.text = '' + if lives == 0: + self._name_text.opacity = 0.2 + assert self.node + self.node.color = (0.7, 0.3, 0.3) + self.node.opacity = 0.2 + +class PowBox(Bomb): + + def __init__(self, + position: Sequence[float] = (0.0, 1.0, 0.0), + velocity: Sequence[float] = (0.0, 0.0, 0.0)) -> None: + Bomb.__init__(self, + position, + velocity, + bomb_type='tnt', + blast_radius=2.5, + source_player=None, + owner=None) + self.set_pow_text() + + def set_pow_text(self) -> None: + m = bs.newnode('math', + owner=self.node, + attrs={'input1': (0, 0.7, 0), + 'operation': 'add'}) + self.node.connectattr('position', m, 'input2') + + self._pow_text = bs.newnode('text', + owner=self.node, + attrs={'text':'POW!', + 'in_world': True, + 'shadow': 1.0, + 'flatness': 1.0, + 'color': (1, 1, 0.4), + 'scale':0.0, + 'h_align':'center'}) + m.connectattr('output', self._pow_text, 'position') + bs.animate(self._pow_text, 'scale', {0: 0.0, 1.0: 0.01}) + + def pow(self) -> None: + self.explode() + + def handlemessage(self, m: Any) -> Any: + if isinstance(m, babase.PickedUpMessage): + self._heldBy = m.node + elif isinstance(m, bs.DroppedMessage): + bs.timer(0.6, self.pow) + Bomb.handlemessage(self, m) + +class SSPlayerSpaz(PlayerSpaz): + multiplyer = 1 + is_dead = False + + def oob_effect(self) -> None: + if self.is_dead: + return + self.is_dead = True + if self.multiplyer > 1.25: + blast_type = 'tnt' + radius = min(self.multiplyer * 5, 20) + else: + # penalty for killing people with low multiplyer + blast_type = 'ice' + radius = 7.5 + Blast(position=self.node.position, + blast_radius=radius, + blast_type=blast_type).autoretain() + + def handlemessage(self, msg: Any) -> Any: + if isinstance(msg, bs.HitMessage): + if not self.node: + return None + if self.node.invincible: + SpazFactory.get().block_sound.play(1.0, position=self.node.position) + return True + + # If we were recently hit, don't count this as another. + # (so punch flurries and bomb pileups essentially count as 1 hit) + local_time = int(bs.time() * 1000) + assert isinstance(local_time, int) + if (self._last_hit_time is None + or local_time - self._last_hit_time > 1000): + self._num_times_hit += 1 + self._last_hit_time = local_time + + mag = msg.magnitude * self.impact_scale + velocity_mag = msg.velocity_magnitude * self.impact_scale + damage_scale = 0.22 + + # If they've got a shield, deliver it to that instead. + if self.shield: + if msg.flat_damage: + damage = msg.flat_damage * self.impact_scale + else: + # Hit our spaz with an impulse but tell it to only return + # theoretical damage; not apply the impulse. + 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], mag, + velocity_mag, msg.radius, 1, msg.force_direction[0], + msg.force_direction[1], msg.force_direction[2]) + damage = damage_scale * self.node.damage + + assert self.shield_hitpoints is not None + self.shield_hitpoints -= int(damage) + self.shield.hurt = ( + 1.0 - + float(self.shield_hitpoints) / self.shield_hitpoints_max) + + # Its a cleaner event if a hit just kills the shield + # without damaging the player. + # However, massive damage events should still be able to + # damage the player. This hopefully gives us a happy medium. + max_spillover = SpazFactory.get().max_shield_spillover_damage + if self.shield_hitpoints <= 0: + + # FIXME: Transition out perhaps? + self.shield.delete() + self.shield = None + SpazFactory.get().shield_down_sound.play(1.0, position=self.node.position) + + # Emit some cool looking sparks when the shield dies. + npos = self.node.position + bs.emitfx(position=(npos[0], npos[1] + 0.9, npos[2]), + velocity=self.node.velocity, + count=random.randrange(20, 30), + scale=1.0, + spread=0.6, + chunk_type='spark') + + else: + SpazFactory.get().shield_hit_sound.play(0.5, position=self.node.position) + + # Emit some cool looking sparks on shield hit. + assert msg.force_direction is not None + bs.emitfx(position=msg.pos, + velocity=(msg.force_direction[0] * 1.0, + msg.force_direction[1] * 1.0, + msg.force_direction[2] * 1.0), + count=min(30, 5 + int(damage * 0.005)), + scale=0.5, + spread=0.3, + chunk_type='spark') + + # If they passed our spillover threshold, + # pass damage along to spaz. + if self.shield_hitpoints <= -max_spillover: + leftover_damage = -max_spillover - self.shield_hitpoints + shield_leftover_ratio = leftover_damage / damage + + # Scale down the magnitudes applied to spaz accordingly. + mag *= shield_leftover_ratio + velocity_mag *= shield_leftover_ratio + else: + return True # Good job shield! + else: + shield_leftover_ratio = 1.0 + + if msg.flat_damage: + damage = int(msg.flat_damage * self.impact_scale * + shield_leftover_ratio) + else: + # Hit it with an impulse and get the resulting damage. + 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], mag, + velocity_mag, msg.radius, 0, msg.force_direction[0], + msg.force_direction[1], msg.force_direction[2]) + + damage = int(damage_scale * self.node.damage) + self.node.handlemessage('hurt_sound') + + # Play punch impact sound based on damage if it was a punch. + if msg.hit_type == 'punch': + self.on_punched(damage) + + # If damage was significant, lets show it. + # if damage > 350: + # assert msg.force_direction is not None + # babase.show_damage_count('-' + str(int(damage / 10)) + '%', + # msg.pos, msg.force_direction) + + # Let's always add in a super-punch sound with boxing + # gloves just to differentiate them. + if msg.hit_subtype == 'super_punch': + SpazFactory.get().punch_sound_stronger.play(1.0, position=self.node.position) + if damage > 500: + sounds = SpazFactory.get().punch_sound_strong + sound = sounds[random.randrange(len(sounds))] + else: + sound = SpazFactory.get().punch_sound + sound.play(1.0, position=self.node.position) + + # Throw up some chunks. + assert msg.force_direction is not None + bs.emitfx(position=msg.pos, + velocity=(msg.force_direction[0] * 0.5, + msg.force_direction[1] * 0.5, + msg.force_direction[2] * 0.5), + count=min(10, 1 + int(damage * 0.0025)), + scale=0.3, + spread=0.03) + + bs.emitfx(position=msg.pos, + chunk_type='sweat', + velocity=(msg.force_direction[0] * 1.3, + msg.force_direction[1] * 1.3 + 5.0, + msg.force_direction[2] * 1.3), + count=min(30, 1 + int(damage * 0.04)), + scale=0.9, + spread=0.28) + + # Momentary flash. + hurtiness = damage * 0.003 + punchpos = (msg.pos[0] + msg.force_direction[0] * 0.02, + msg.pos[1] + msg.force_direction[1] * 0.02, + msg.pos[2] + msg.force_direction[2] * 0.02) + flash_color = (1.0, 0.8, 0.4) + light = bs.newnode( + 'light', + attrs={ + 'position': punchpos, + 'radius': 0.12 + hurtiness * 0.12, + 'intensity': 0.3 * (1.0 + 1.0 * hurtiness), + 'height_attenuated': False, + 'color': flash_color + }) + bs.timer(0.06, light.delete) + + flash = bs.newnode('flash', + attrs={ + 'position': punchpos, + 'size': 0.17 + 0.17 * hurtiness, + 'color': flash_color + }) + bs.timer(0.06, flash.delete) + + if msg.hit_type == 'impact': + assert msg.force_direction is not None + bs.emitfx(position=msg.pos, + velocity=(msg.force_direction[0] * 2.0, + msg.force_direction[1] * 2.0, + msg.force_direction[2] * 2.0), + count=min(10, 1 + int(damage * 0.01)), + scale=0.4, + spread=0.1) + if self.hitpoints > 0: + + # It's kinda crappy to die from impacts, so lets reduce + # impact damage by a reasonable amount *if* it'll keep us alive + if msg.hit_type == 'impact' and damage > self.hitpoints: + # Drop damage to whatever puts us at 10 hit points, + # or 200 less than it used to be whichever is greater + # (so it *can* still kill us if its high enough) + newdamage = max(damage - 200, self.hitpoints - 10) + damage = newdamage + self.node.handlemessage('flash') + + # If we're holding something, drop it. + if damage > 0.0 and self.node.hold_node: + self.node.hold_node = None + # self.hitpoints -= damage + self.multiplyer += min(damage / 2000, 0.15) + if damage/2000 > 0.05: + self.set_score_text(str(int((self.multiplyer-1)*100))+'%') + # self.node.hurt = 1.0 - float( + # self.hitpoints) / self.hitpoints_max + self.node.hurt = 0.0 + + # If we're cursed, *any* damage blows us up. + if self._cursed and damage > 0: + bs.timer( + 0.05, + bs.WeakCall(self.curse_explode, + msg.get_source_player(bs.Player))) + + # If we're frozen, shatter.. otherwise die if we hit zero + # if self.frozen and (damage > 200 or self.hitpoints <= 0): + # self.shatter() + # elif self.hitpoints <= 0: + # self.node.handlemessage( + # bs.DieMessage(how=babase.DeathType.IMPACT)) + + # If we're dead, take a look at the smoothed damage value + # (which gives us a smoothed average of recent damage) and shatter + # us if its grown high enough. + # if self.hitpoints <= 0: + # damage_avg = self.node.damage_smoothed * damage_scale + # if damage_avg > 1000: + # self.shatter() + + source_player = msg.get_source_player(type(self._player)) + if source_player: + self.last_player_attacked_by = source_player + self.last_attacked_time = bs.time() + self.last_attacked_type = (msg.hit_type, msg.hit_subtype) + Spaz.handlemessage(self, bs.HitMessage) # Augment standard behavior. + activity = self._activity() + if activity is not None and self._player.exists(): + activity.handlemessage(PlayerSpazHurtMessage(self)) + + elif isinstance(msg, bs.DieMessage): + self.oob_effect() + super().handlemessage(msg) + elif isinstance(msg, bs.PowerupMessage): + if msg.poweruptype == 'health': + if self.multiplyer > 2: + self.multiplyer *= 0.5 + else: + self.multiplyer *= 0.75 + self.multiplyer = max(1, self.multiplyer) + self.set_score_text(str(int((self.multiplyer-1)*100))+"%") + super().handlemessage(msg) + else: + super().handlemessage(msg) + + +class Player(bs.Player['Team']): + """Our player type for this game.""" + + +class Team(bs.Team[Player]): + """Our team type for this game.""" + + def __init__(self) -> None: + self.score = 0 + + +# ba_meta export bascenev1.GameActivity +class SuperSmash(bs.TeamGameActivity[Player, Team]): + + name = 'Super Smash' + description = 'Knock everyone off the map.' + + # Print messages when players die since it matters here. + announce_player_deaths = True + + @classmethod + def get_available_settings( + cls, sessiontype: Type[bs.Session]) -> List[babase.Setting]: + settings = [ + bs.IntSetting( + 'Kills to Win Per Player', + min_value=1, + default=5, + increment=1, + ), + bs.IntChoiceSetting( + 'Time Limit', + choices=[ + ('None', 0), + ('1 Minute', 60), + ('2 Minutes', 120), + ('5 Minutes', 300), + ('10 Minutes', 600), + ('20 Minutes', 1200), + ], + default=0, + ), + bs.FloatChoiceSetting( + 'Respawn Times', + choices=[ + ('Shorter', 0.25), + ('Short', 0.5), + ('Normal', 1.0), + ('Long', 2.0), + ('Longer', 4.0), + ], + default=1.0, + ), + bs.BoolSetting('Boxing Gloves', default=False), + bs.BoolSetting('Epic Mode', default=False), + ] + if issubclass(sessiontype, bs.FreeForAllSession): + settings.append( + bs.BoolSetting('Allow Negative Scores', default=False)) + return settings + + @classmethod + def supports_session_type(cls, sessiontype: Type[bs.Session]) -> bool: + return (issubclass(sessiontype, bs.DualTeamSession) + or issubclass(sessiontype, bs.FreeForAllSession)) + + @classmethod + def get_supported_maps(cls, sessiontype: Type[bs.Session]) -> List[str]: + maps = bs.app.classic.getmaps('melee') + for m in ['Lake Frigid', 'Hockey Stadium', 'Football Stadium']: + # remove maps without bounds + maps.remove(m) + return maps + + def __init__(self, settings: dict): + super().__init__(settings) + self._scoreboard = Scoreboard() + self._score_to_win: int | None = None + self._dingsound = bs.getsound('dingSmall') + self._epic_mode = bool(settings['Epic Mode']) + self._kills_to_win_per_player = int( + settings['Kills to Win Per Player']) + self._time_limit = float(settings['Time Limit']) + self._allow_negative_scores = bool( + settings.get('Allow Negative Scores', False)) + self._boxing_gloves = bool(settings['Boxing Gloves']) + + # Base class overrides. + self.slow_motion = self._epic_mode + self.default_music = (bs.MusicType.EPIC if self._epic_mode else + bs.MusicType.SURVIVAL) + + def get_instance_description(self) -> str | Sequence: + return 'Knock everyone off the map.' + + def get_instance_description_short(self) -> str | Sequence: + return 'Knock off the map.' + + def on_begin(self) -> None: + super().on_begin() + self._start_time = bs.time() + self.setup_standard_time_limit(self._time_limit) + self.setup_standard_powerup_drops(enable_tnt=False) + self._pow = None + self._tnt_drop_timer = bs.timer(1.0 * 0.30, + bs.WeakCall(self._drop_pow_box), + repeat=True) + + # Base kills needed to win on the size of the largest team. + self._score_to_win = (self._kills_to_win_per_player * + max(1, max(len(t.players) for t in self.teams))) + self._update_scoreboard() + + def _drop_pow_box(self) -> None: + if self._pow is not None and self._pow: + return + if len(self.map.tnt_points) == 0: + return + pos = random.choice(self.map.tnt_points) + pos = (pos[0], pos[1] + 1, pos[2]) + self._pow = PowBox(position=pos, velocity=(0.0, 1.0, 0.0)) + + def spawn_player(self, player: Player) -> bs.Actor: + if isinstance(self.session, bs.DualTeamSession): + position = self.map.get_start_position(player.team.id) + else: + # otherwise do free-for-all spawn locations + position = self.map.get_ffa_start_position(self.players) + angle = None + + name = player.getname() + light_color = _math.normalized_color(player.color) + display_color = babase.safecolor(player.color, target_intensity=0.75) + + spaz = SSPlayerSpaz(color=player.color, + highlight=player.highlight, + character=player.character, + player=player) + + player.actor = spaz + assert spaz.node + + # If this is co-op and we're on Courtyard or Runaround, add the + # material that allows us to collide with the player-walls. + # FIXME: Need to generalize this. + if isinstance(self.session, bs.CoopSession) and self.map.getname() in [ + 'Courtyard', 'Tower D' + ]: + mat = self.map.preloaddata['collide_with_wall_material'] + assert isinstance(spaz.node.materials, tuple) + assert isinstance(spaz.node.roller_materials, tuple) + spaz.node.materials += (mat, ) + spaz.node.roller_materials += (mat, ) + + spaz.node.name = name + spaz.node.name_color = display_color + spaz.connect_controls_to_player() + + # Move to the stand position and add a flash of light. + spaz.handlemessage( + bs.StandMessage( + position, + angle if angle is not None else random.uniform(0, 360))) + self._spawn_sound.play(1, position=spaz.node.position) + light = bs.newnode('light', attrs={'color': light_color}) + spaz.node.connectattr('position', light, 'position') + bs.animate(light, 'intensity', {0: 0, 0.25: 1, 0.5: 0}) + bs.timer(0.5, light.delete) + + if self._boxing_gloves: + spaz.equip_boxing_gloves() + + return spaz + + def handlemessage(self, msg: Any) -> Any: + + if isinstance(msg, bs.PlayerDiedMessage): + # Augment standard behavior. + super().handlemessage(msg) + + player = msg.getplayer(Player) + self.respawn_player(player) + + killer = msg.getkillerplayer(Player) + if killer is None: + return None + + # Handle team-kills. + if killer.team is player.team: + + # In free-for-all, killing yourself loses you a point. + if isinstance(self.session, bs.FreeForAllSession): + new_score = player.team.score - 1 + if not self._allow_negative_scores: + new_score = max(0, new_score) + player.team.score = new_score + + # In teams-mode it gives a point to the other team. + else: + self._dingsound.play() + for team in self.teams: + if team is not killer.team: + team.score += 1 + + # Killing someone on another team nets a kill. + else: + killer.team.score += 1 + self._dingsound.play() + + # In FFA show scores since its hard to find on the scoreboard. + if isinstance(killer.actor, SSPlayerSpaz) and killer.actor: + killer.actor.set_score_text(str(killer.team.score) + '/' + + str(self._score_to_win), + color=killer.team.color, + flash=True) + + self._update_scoreboard() + + # If someone has won, set a timer to end shortly. + # (allows the dust to clear and draws to occur if deaths are + # close enough) + assert self._score_to_win is not None + if any(team.score >= self._score_to_win for team in self.teams): + bs.timer(0.5, self.end_game) + + else: + return super().handlemessage(msg) + return None + + def _update_scoreboard(self) -> None: + for team in self.teams: + self._scoreboard.set_team_value(team, team.score, + self._score_to_win) + + def end_game(self) -> None: + results = bs.GameResults() + for team in self.teams: + results.set_team_score(team, team.score) + self.end(results=results) + + +class Player2(bs.Player['Team']): + """Our player type for this game.""" + + def __init__(self) -> None: + self.lives = 0 + self.icons: List[Icon] = [] + + +class Team2(bs.Team[Player]): + """Our team type for this game.""" + + def __init__(self) -> None: + self.survival_seconds: Optional[int] = None + self.spawn_order: List[Player] = [] + + +# ba_meta export bascenev1.GameActivity +class SuperSmashElimination(bs.TeamGameActivity[Player2, Team2]): + + name = 'Super Smash Elimination' + description = 'Knock everyone off the map.' + scoreconfig = bs.ScoreConfig(label='Survived', + scoretype=bs.ScoreType.SECONDS, + none_is_winner=True) + + # Print messages when players die since it matters here. + announce_player_deaths = True + + @classmethod + def get_available_settings( + cls, sessiontype: Type[bs.Session]) -> List[babase.Setting]: + settings = [ + bs.IntSetting( + 'Lives (0 = Unlimited)', + min_value=0, + default=3, + increment=1, + ), + bs.IntChoiceSetting( + 'Time Limit', + choices=[ + ('None', 0), + ('1 Minute', 60), + ('2 Minutes', 120), + ('5 Minutes', 300), + ('10 Minutes', 600), + ('20 Minutes', 1200), + ], + default=0, + ), + bs.FloatChoiceSetting( + 'Respawn Times', + choices=[ + ('Shorter', 0.25), + ('Short', 0.5), + ('Normal', 1.0), + ('Long', 2.0), + ('Longer', 4.0), + ], + default=1.0, + ), + bs.BoolSetting('Boxing Gloves', default=False), + bs.BoolSetting('Epic Mode', default=False), + ] + return settings + + @classmethod + def supports_session_type(cls, sessiontype: Type[bs.Session]) -> bool: + return (issubclass(sessiontype, bs.DualTeamSession) + or issubclass(sessiontype, bs.FreeForAllSession)) + + @classmethod + def get_supported_maps(cls, sessiontype: Type[bs.Session]) -> List[str]: + maps = bs.app.classic.getmaps('melee') + for m in ['Lake Frigid', 'Hockey Stadium', 'Football Stadium']: + # remove maps without bounds + maps.remove(m) + return maps + + def __init__(self, settings: dict): + super().__init__(settings) + self.lives = int(settings['Lives (0 = Unlimited)']) + self.time_limit_only = (self.lives == 0) + if self.time_limit_only: + settings['Time Limit'] = max(60, settings['Time Limit']) + + self._epic_mode = bool(settings['Epic Mode']) + self._time_limit = float(settings['Time Limit']) + + self._start_time: Optional[float] = 1.0 + + self._boxing_gloves = bool(settings['Boxing Gloves']) + self._solo_mode = bool(settings.get('Solo Mode', False)) + + # Base class overrides. + self.slow_motion = self._epic_mode + self.default_music = (bs.MusicType.EPIC if self._epic_mode else + bs.MusicType.SURVIVAL) + + def get_instance_description(self) -> str | Sequence: + return 'Knock everyone off the map.' + + def get_instance_description_short(self) -> str | Sequence: + return 'Knock off the map.' + + def on_begin(self) -> None: + super().on_begin() + self._start_time = bs.time() + self.setup_standard_time_limit(self._time_limit) + self.setup_standard_powerup_drops(enable_tnt=False) + self._pow = None + self._tnt_drop_timer = bs.timer(1.0 * 0.30, + bs.WeakCall(self._drop_pow_box), + repeat=True) + self._update_icons() + bs.timer(1.0, self.check_end_game, repeat=True) + + def _drop_pow_box(self) -> None: + if self._pow is not None and self._pow: + return + if len(self.map.tnt_points) == 0: + return + pos = random.choice(self.map.tnt_points) + pos = (pos[0], pos[1] + 1, pos[2]) + self._pow = PowBox(position=pos, velocity=(0.0, 1.0, 0.0)) + + def on_player_join(self, player: Player) -> None: + + if self.has_begun(): + if (all(teammate.lives == 0 for teammate in player.team.players) + and player.team.survival_seconds is None): + player.team.survival_seconds = 0 + bs.broadcastmessage( + babase.Lstr(resource='playerDelayedJoinText', + subs=[('${PLAYER}', player.getname(full=True))]), + color=(0, 1, 0), + ) + return + + player.lives = self.lives + # create our icon and spawn + player.icons = [Icon(player, + position=(0.0, 50), + scale=0.8)] + if player.lives > 0 or self.time_limit_only: + self.spawn_player(player) + + # dont waste time doing this until begin + if self.has_begun(): + self._update_icons() + + def on_player_leave(self, player: Player) -> None: + super().on_player_leave(player) + player.icons = None + + # update icons in a moment since our team + # will be gone from the list then + bs.timer(0.0, self._update_icons) + bs.timer(0.1, self.check_end_game, repeat=True) + + def _update_icons(self) -> None: + # pylint: disable=too-many-branches + + # In free-for-all mode, everyone is just lined up along the bottom. + if isinstance(self.session, bs.FreeForAllSession): + count = len(self.teams) + x_offs = 85 + xval = x_offs * (count - 1) * -0.5 + for team in self.teams: + if len(team.players) > 1: + print('WTF have', len(team.players), 'players in ffa team') + elif len(team.players) == 1: + player = team.players[0] + if len(player.icons) != 1: + print( + 'WTF have', + len(player.icons), + 'icons in non-solo elim') + for icon in player.icons: + icon.set_position_and_scale((xval, 30), 0.7) + icon.update_for_lives() + xval += x_offs + + # In teams mode we split up teams. + else: + if self._solo_mode: + # First off, clear out all icons. + for player in self.players: + player.icons = [] + + # Now for each team, cycle through our available players + # adding icons. + for team in self.teams: + if team.id == 0: + xval = -60 + x_offs = -78 + else: + xval = 60 + x_offs = 78 + is_first = True + test_lives = 1 + while True: + players_with_lives = [ + p for p in team.spawn_order + if p and p.lives >= test_lives + ] + if not players_with_lives: + break + for player in players_with_lives: + player.icons.append( + Icon(player, + position=(xval, (40 if is_first else 25)), + scale=1.0 if is_first else 0.5, + name_maxwidth=130 if is_first else 75, + name_scale=0.8 if is_first else 1.0, + flatness=0.0 if is_first else 1.0, + shadow=0.5 if is_first else 1.0, + show_death=is_first, + show_lives=False)) + xval += x_offs * (0.8 if is_first else 0.56) + is_first = False + test_lives += 1 + # Non-solo mode. + else: + for team in self.teams: + if team.id == 0: + xval = -50 + x_offs = -85 + else: + xval = 50 + x_offs = 85 + for player in team.players: + if len(player.icons) != 1: + print( + 'WTF have', + len(player.icons), + 'icons in non-solo elim') + for icon in player.icons: + icon.set_position_and_scale((xval, 30), 0.7) + icon.update_for_lives() + xval += x_offs + + # overriding the default character spawning.. + def spawn_player(self, player: Player) -> bs.Actor: + if isinstance(self.session, bs.DualTeamSession): + position = self.map.get_start_position(player.team.id) + else: + # otherwise do free-for-all spawn locations + position = self.map.get_ffa_start_position(self.players) + angle = None + + name = player.getname() + light_color = _math.normalized_color(player.color) + display_color = babase.safecolor(player.color, target_intensity=0.75) + + spaz = SSPlayerSpaz(color=player.color, + highlight=player.highlight, + character=player.character, + player=player) + + player.actor = spaz + assert spaz.node + + # If this is co-op and we're on Courtyard or Runaround, add the + # material that allows us to collide with the player-walls. + # FIXME: Need to generalize this. + if isinstance(self.session, bs.CoopSession) and self.map.getname() in [ + 'Courtyard', 'Tower D' + ]: + mat = self.map.preloaddata['collide_with_wall_material'] + assert isinstance(spaz.node.materials, tuple) + assert isinstance(spaz.node.roller_materials, tuple) + spaz.node.materials += (mat, ) + spaz.node.roller_materials += (mat, ) + + spaz.node.name = name + spaz.node.name_color = display_color + spaz.connect_controls_to_player() + + # Move to the stand position and add a flash of light. + spaz.handlemessage( + bs.StandMessage( + position, + angle if angle is not None else random.uniform(0, 360))) + self._spawn_sound.play(1, position=spaz.node.position) + light = bs.newnode('light', attrs={'color': light_color}) + spaz.node.connectattr('position', light, 'position') + bs.animate(light, 'intensity', {0: 0, 0.25: 1, 0.5: 0}) + bs.timer(0.5, light.delete) + + # If we have any icons, update their state. + for icon in player.icons: + icon.handle_player_spawned() + + if self._boxing_gloves: + spaz.equip_boxing_gloves() + + return spaz + + def _get_total_team_lives(self, team: Team) -> int: + return sum(player.lives for player in team.players) + + def handlemessage(self, msg: Any) -> Any: + + if isinstance(msg, bs.PlayerDiedMessage): + # Augment standard behavior. + super().handlemessage(msg) + player: Player = msg.getplayer(Player) + + player.lives -= 1 + if player.lives < 0: + player.lives = 0 + + # if we have any icons, update their state + for icon in player.icons: + icon.handle_player_died() + + # play big death sound on our last death + # or for every one in solo mode + if player.lives == 0: + SpazFactory.get().single_player_death_sound.play() + + # if we hit zero lives we're dead and the game might be over + if player.lives == 0 and not self.time_limit_only: + # If the whole team is now dead, mark their survival time. + if self._get_total_team_lives(player.team) == 0: + assert self._start_time is not None + player.team.survival_seconds = int(bs.time() - + self._start_time) + # we still have lives; yay! + else: + self.respawn_player(player) + + bs.timer(0.1, self.check_end_game, repeat=True) + + else: + return super().handlemessage(msg) + return None + + def check_end_game(self) -> None: + if len(self._get_living_teams()) < 2: + bs.timer(0.5, self.end_game) + + def _get_living_teams(self) -> List[Team]: + return [ + team for team in self.teams + if len(team.players) > 0 and any(player.lives > 0 + for player in team.players) + ] + + def end_game(self) -> None: + if self.has_ended(): + return + results = bs.GameResults() + self._vs_text = None # Kill our 'vs' if its there. + for team in self.teams: + results.set_team_score(team, team.survival_seconds) + self.end(results=results) From d1c561992d5474301e77f438cdf27ed489f2926c Mon Sep 17 00:00:00 2001 From: SenjuZoro <69396975+SenjuZoro@users.noreply.github.com> Date: Mon, 24 Jul 2023 12:31:56 +0200 Subject: [PATCH 0618/1464] Update minigames.json --- plugins/minigames.json | 23 +++++++++++++++++++++-- 1 file changed, 21 insertions(+), 2 deletions(-) diff --git a/plugins/minigames.json b/plugins/minigames.json index 510551e8..24cf114c 100644 --- a/plugins/minigames.json +++ b/plugins/minigames.json @@ -654,5 +654,24 @@ "md5sum": "197a377652ab0c3bfbe1ca07833924b4" } } - } -} \ No newline at end of file + }, + "supersmash": { + "description": "SuperSmash", + "external_url": "", + "authors": [ + { + "name": "Mrmaxmeier", + "email": "", + "discord": "" + }, + { + "name": "JoseAngel", + "email": "", + "discord": "joseang3l" + } + ], + "versions": { + "1.0.0": null + } + }, +} From 604bbe1d6e207afe7e62a070655e8990b1d72219 Mon Sep 17 00:00:00 2001 From: SenjuZoro <69396975+SenjuZoro@users.noreply.github.com> Date: Mon, 24 Jul 2023 12:33:24 +0200 Subject: [PATCH 0619/1464] Update minigames.json --- plugins/minigames.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/minigames.json b/plugins/minigames.json index 24cf114c..52773fa6 100644 --- a/plugins/minigames.json +++ b/plugins/minigames.json @@ -673,5 +673,5 @@ "versions": { "1.0.0": null } - }, + } } From 9b885781d15987e5ea59280aa2ca67efcfabd728 Mon Sep 17 00:00:00 2001 From: SenjuZoro Date: Mon, 24 Jul 2023 10:34:30 +0000 Subject: [PATCH 0620/1464] [ci] auto-format --- plugins/minigames/SuperSmash.py | 1802 ++++++++++++++++--------------- 1 file changed, 902 insertions(+), 900 deletions(-) diff --git a/plugins/minigames/SuperSmash.py b/plugins/minigames/SuperSmash.py index 2ffb589b..37363606 100644 --- a/plugins/minigames/SuperSmash.py +++ b/plugins/minigames/SuperSmash.py @@ -19,936 +19,938 @@ from bascenev1lib.actor.playerspaz import PlayerSpaz, PlayerSpazHurtMessage if TYPE_CHECKING: - from typing import Any, Type, List, Sequence, Optional + from typing import Any, Type, List, Sequence, Optional class Icon(Icon): - def update_for_lives(self) -> None: - """Update for the target player's current lives.""" - if self._player: - lives = self._player.lives - else: - lives = 0 - if self._show_lives: - if lives > 1: - self._lives_text.text = 'x' + str(lives - 1) - else: - self._lives_text.text = '' - if lives == 0: - self._name_text.opacity = 0.2 - assert self.node - self.node.color = (0.7, 0.3, 0.3) - self.node.opacity = 0.2 + def update_for_lives(self) -> None: + """Update for the target player's current lives.""" + if self._player: + lives = self._player.lives + else: + lives = 0 + if self._show_lives: + if lives > 1: + self._lives_text.text = 'x' + str(lives - 1) + else: + self._lives_text.text = '' + if lives == 0: + self._name_text.opacity = 0.2 + assert self.node + self.node.color = (0.7, 0.3, 0.3) + self.node.opacity = 0.2 + class PowBox(Bomb): - def __init__(self, - position: Sequence[float] = (0.0, 1.0, 0.0), - velocity: Sequence[float] = (0.0, 0.0, 0.0)) -> None: - Bomb.__init__(self, - position, - velocity, - bomb_type='tnt', - blast_radius=2.5, - source_player=None, - owner=None) - self.set_pow_text() - - def set_pow_text(self) -> None: - m = bs.newnode('math', - owner=self.node, - attrs={'input1': (0, 0.7, 0), - 'operation': 'add'}) - self.node.connectattr('position', m, 'input2') - - self._pow_text = bs.newnode('text', - owner=self.node, - attrs={'text':'POW!', - 'in_world': True, - 'shadow': 1.0, - 'flatness': 1.0, - 'color': (1, 1, 0.4), - 'scale':0.0, - 'h_align':'center'}) - m.connectattr('output', self._pow_text, 'position') - bs.animate(self._pow_text, 'scale', {0: 0.0, 1.0: 0.01}) - - def pow(self) -> None: - self.explode() - - def handlemessage(self, m: Any) -> Any: - if isinstance(m, babase.PickedUpMessage): - self._heldBy = m.node - elif isinstance(m, bs.DroppedMessage): - bs.timer(0.6, self.pow) - Bomb.handlemessage(self, m) + def __init__(self, + position: Sequence[float] = (0.0, 1.0, 0.0), + velocity: Sequence[float] = (0.0, 0.0, 0.0)) -> None: + Bomb.__init__(self, + position, + velocity, + bomb_type='tnt', + blast_radius=2.5, + source_player=None, + owner=None) + self.set_pow_text() + + def set_pow_text(self) -> None: + m = bs.newnode('math', + owner=self.node, + attrs={'input1': (0, 0.7, 0), + 'operation': 'add'}) + self.node.connectattr('position', m, 'input2') + + self._pow_text = bs.newnode('text', + owner=self.node, + attrs={'text': 'POW!', + 'in_world': True, + 'shadow': 1.0, + 'flatness': 1.0, + 'color': (1, 1, 0.4), + 'scale': 0.0, + 'h_align': 'center'}) + m.connectattr('output', self._pow_text, 'position') + bs.animate(self._pow_text, 'scale', {0: 0.0, 1.0: 0.01}) + + def pow(self) -> None: + self.explode() + + def handlemessage(self, m: Any) -> Any: + if isinstance(m, babase.PickedUpMessage): + self._heldBy = m.node + elif isinstance(m, bs.DroppedMessage): + bs.timer(0.6, self.pow) + Bomb.handlemessage(self, m) + class SSPlayerSpaz(PlayerSpaz): - multiplyer = 1 - is_dead = False - - def oob_effect(self) -> None: - if self.is_dead: - return - self.is_dead = True - if self.multiplyer > 1.25: - blast_type = 'tnt' - radius = min(self.multiplyer * 5, 20) - else: - # penalty for killing people with low multiplyer - blast_type = 'ice' - radius = 7.5 - Blast(position=self.node.position, - blast_radius=radius, - blast_type=blast_type).autoretain() - - def handlemessage(self, msg: Any) -> Any: - if isinstance(msg, bs.HitMessage): - if not self.node: - return None - if self.node.invincible: - SpazFactory.get().block_sound.play(1.0, position=self.node.position) - return True - - # If we were recently hit, don't count this as another. - # (so punch flurries and bomb pileups essentially count as 1 hit) - local_time = int(bs.time() * 1000) - assert isinstance(local_time, int) - if (self._last_hit_time is None - or local_time - self._last_hit_time > 1000): - self._num_times_hit += 1 - self._last_hit_time = local_time - - mag = msg.magnitude * self.impact_scale - velocity_mag = msg.velocity_magnitude * self.impact_scale - damage_scale = 0.22 - - # If they've got a shield, deliver it to that instead. - if self.shield: - if msg.flat_damage: - damage = msg.flat_damage * self.impact_scale - else: - # Hit our spaz with an impulse but tell it to only return - # theoretical damage; not apply the impulse. - 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], mag, - velocity_mag, msg.radius, 1, msg.force_direction[0], - msg.force_direction[1], msg.force_direction[2]) - damage = damage_scale * self.node.damage - - assert self.shield_hitpoints is not None - self.shield_hitpoints -= int(damage) - self.shield.hurt = ( - 1.0 - - float(self.shield_hitpoints) / self.shield_hitpoints_max) - - # Its a cleaner event if a hit just kills the shield - # without damaging the player. - # However, massive damage events should still be able to - # damage the player. This hopefully gives us a happy medium. - max_spillover = SpazFactory.get().max_shield_spillover_damage - if self.shield_hitpoints <= 0: - - # FIXME: Transition out perhaps? - self.shield.delete() - self.shield = None - SpazFactory.get().shield_down_sound.play(1.0, position=self.node.position) - - # Emit some cool looking sparks when the shield dies. - npos = self.node.position - bs.emitfx(position=(npos[0], npos[1] + 0.9, npos[2]), - velocity=self.node.velocity, - count=random.randrange(20, 30), - scale=1.0, - spread=0.6, - chunk_type='spark') - - else: - SpazFactory.get().shield_hit_sound.play(0.5, position=self.node.position) - - # Emit some cool looking sparks on shield hit. - assert msg.force_direction is not None - bs.emitfx(position=msg.pos, - velocity=(msg.force_direction[0] * 1.0, - msg.force_direction[1] * 1.0, - msg.force_direction[2] * 1.0), - count=min(30, 5 + int(damage * 0.005)), - scale=0.5, - spread=0.3, - chunk_type='spark') - - # If they passed our spillover threshold, - # pass damage along to spaz. - if self.shield_hitpoints <= -max_spillover: - leftover_damage = -max_spillover - self.shield_hitpoints - shield_leftover_ratio = leftover_damage / damage - - # Scale down the magnitudes applied to spaz accordingly. - mag *= shield_leftover_ratio - velocity_mag *= shield_leftover_ratio - else: - return True # Good job shield! - else: - shield_leftover_ratio = 1.0 - - if msg.flat_damage: - damage = int(msg.flat_damage * self.impact_scale * - shield_leftover_ratio) - else: - # Hit it with an impulse and get the resulting damage. - 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], mag, - velocity_mag, msg.radius, 0, msg.force_direction[0], - msg.force_direction[1], msg.force_direction[2]) - - damage = int(damage_scale * self.node.damage) - self.node.handlemessage('hurt_sound') - - # Play punch impact sound based on damage if it was a punch. - if msg.hit_type == 'punch': - self.on_punched(damage) - - # If damage was significant, lets show it. - # if damage > 350: - # assert msg.force_direction is not None - # babase.show_damage_count('-' + str(int(damage / 10)) + '%', - # msg.pos, msg.force_direction) - - # Let's always add in a super-punch sound with boxing - # gloves just to differentiate them. - if msg.hit_subtype == 'super_punch': - SpazFactory.get().punch_sound_stronger.play(1.0, position=self.node.position) - if damage > 500: - sounds = SpazFactory.get().punch_sound_strong - sound = sounds[random.randrange(len(sounds))] - else: - sound = SpazFactory.get().punch_sound - sound.play(1.0, position=self.node.position) - - # Throw up some chunks. - assert msg.force_direction is not None - bs.emitfx(position=msg.pos, - velocity=(msg.force_direction[0] * 0.5, - msg.force_direction[1] * 0.5, - msg.force_direction[2] * 0.5), - count=min(10, 1 + int(damage * 0.0025)), - scale=0.3, - spread=0.03) - - bs.emitfx(position=msg.pos, - chunk_type='sweat', - velocity=(msg.force_direction[0] * 1.3, - msg.force_direction[1] * 1.3 + 5.0, - msg.force_direction[2] * 1.3), - count=min(30, 1 + int(damage * 0.04)), - scale=0.9, - spread=0.28) - - # Momentary flash. - hurtiness = damage * 0.003 - punchpos = (msg.pos[0] + msg.force_direction[0] * 0.02, - msg.pos[1] + msg.force_direction[1] * 0.02, - msg.pos[2] + msg.force_direction[2] * 0.02) - flash_color = (1.0, 0.8, 0.4) - light = bs.newnode( - 'light', - attrs={ - 'position': punchpos, - 'radius': 0.12 + hurtiness * 0.12, - 'intensity': 0.3 * (1.0 + 1.0 * hurtiness), - 'height_attenuated': False, - 'color': flash_color - }) - bs.timer(0.06, light.delete) - - flash = bs.newnode('flash', - attrs={ - 'position': punchpos, - 'size': 0.17 + 0.17 * hurtiness, - 'color': flash_color - }) - bs.timer(0.06, flash.delete) - - if msg.hit_type == 'impact': - assert msg.force_direction is not None - bs.emitfx(position=msg.pos, - velocity=(msg.force_direction[0] * 2.0, - msg.force_direction[1] * 2.0, - msg.force_direction[2] * 2.0), - count=min(10, 1 + int(damage * 0.01)), - scale=0.4, - spread=0.1) - if self.hitpoints > 0: - - # It's kinda crappy to die from impacts, so lets reduce - # impact damage by a reasonable amount *if* it'll keep us alive - if msg.hit_type == 'impact' and damage > self.hitpoints: - # Drop damage to whatever puts us at 10 hit points, - # or 200 less than it used to be whichever is greater - # (so it *can* still kill us if its high enough) - newdamage = max(damage - 200, self.hitpoints - 10) - damage = newdamage - self.node.handlemessage('flash') - - # If we're holding something, drop it. - if damage > 0.0 and self.node.hold_node: - self.node.hold_node = None - # self.hitpoints -= damage - self.multiplyer += min(damage / 2000, 0.15) - if damage/2000 > 0.05: - self.set_score_text(str(int((self.multiplyer-1)*100))+'%') - # self.node.hurt = 1.0 - float( - # self.hitpoints) / self.hitpoints_max - self.node.hurt = 0.0 - - # If we're cursed, *any* damage blows us up. - if self._cursed and damage > 0: - bs.timer( - 0.05, - bs.WeakCall(self.curse_explode, - msg.get_source_player(bs.Player))) - - # If we're frozen, shatter.. otherwise die if we hit zero - # if self.frozen and (damage > 200 or self.hitpoints <= 0): - # self.shatter() - # elif self.hitpoints <= 0: - # self.node.handlemessage( - # bs.DieMessage(how=babase.DeathType.IMPACT)) - - # If we're dead, take a look at the smoothed damage value - # (which gives us a smoothed average of recent damage) and shatter - # us if its grown high enough. - # if self.hitpoints <= 0: - # damage_avg = self.node.damage_smoothed * damage_scale - # if damage_avg > 1000: - # self.shatter() - - source_player = msg.get_source_player(type(self._player)) - if source_player: - self.last_player_attacked_by = source_player - self.last_attacked_time = bs.time() - self.last_attacked_type = (msg.hit_type, msg.hit_subtype) - Spaz.handlemessage(self, bs.HitMessage) # Augment standard behavior. - activity = self._activity() - if activity is not None and self._player.exists(): - activity.handlemessage(PlayerSpazHurtMessage(self)) - - elif isinstance(msg, bs.DieMessage): - self.oob_effect() - super().handlemessage(msg) - elif isinstance(msg, bs.PowerupMessage): - if msg.poweruptype == 'health': - if self.multiplyer > 2: - self.multiplyer *= 0.5 - else: - self.multiplyer *= 0.75 - self.multiplyer = max(1, self.multiplyer) - self.set_score_text(str(int((self.multiplyer-1)*100))+"%") - super().handlemessage(msg) - else: - super().handlemessage(msg) + multiplyer = 1 + is_dead = False + + def oob_effect(self) -> None: + if self.is_dead: + return + self.is_dead = True + if self.multiplyer > 1.25: + blast_type = 'tnt' + radius = min(self.multiplyer * 5, 20) + else: + # penalty for killing people with low multiplyer + blast_type = 'ice' + radius = 7.5 + Blast(position=self.node.position, + blast_radius=radius, + blast_type=blast_type).autoretain() + + def handlemessage(self, msg: Any) -> Any: + if isinstance(msg, bs.HitMessage): + if not self.node: + return None + if self.node.invincible: + SpazFactory.get().block_sound.play(1.0, position=self.node.position) + return True + + # If we were recently hit, don't count this as another. + # (so punch flurries and bomb pileups essentially count as 1 hit) + local_time = int(bs.time() * 1000) + assert isinstance(local_time, int) + if (self._last_hit_time is None + or local_time - self._last_hit_time > 1000): + self._num_times_hit += 1 + self._last_hit_time = local_time + + mag = msg.magnitude * self.impact_scale + velocity_mag = msg.velocity_magnitude * self.impact_scale + damage_scale = 0.22 + + # If they've got a shield, deliver it to that instead. + if self.shield: + if msg.flat_damage: + damage = msg.flat_damage * self.impact_scale + else: + # Hit our spaz with an impulse but tell it to only return + # theoretical damage; not apply the impulse. + 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], mag, + velocity_mag, msg.radius, 1, msg.force_direction[0], + msg.force_direction[1], msg.force_direction[2]) + damage = damage_scale * self.node.damage + + assert self.shield_hitpoints is not None + self.shield_hitpoints -= int(damage) + self.shield.hurt = ( + 1.0 - + float(self.shield_hitpoints) / self.shield_hitpoints_max) + + # Its a cleaner event if a hit just kills the shield + # without damaging the player. + # However, massive damage events should still be able to + # damage the player. This hopefully gives us a happy medium. + max_spillover = SpazFactory.get().max_shield_spillover_damage + if self.shield_hitpoints <= 0: + + # FIXME: Transition out perhaps? + self.shield.delete() + self.shield = None + SpazFactory.get().shield_down_sound.play(1.0, position=self.node.position) + + # Emit some cool looking sparks when the shield dies. + npos = self.node.position + bs.emitfx(position=(npos[0], npos[1] + 0.9, npos[2]), + velocity=self.node.velocity, + count=random.randrange(20, 30), + scale=1.0, + spread=0.6, + chunk_type='spark') + + else: + SpazFactory.get().shield_hit_sound.play(0.5, position=self.node.position) + + # Emit some cool looking sparks on shield hit. + assert msg.force_direction is not None + bs.emitfx(position=msg.pos, + velocity=(msg.force_direction[0] * 1.0, + msg.force_direction[1] * 1.0, + msg.force_direction[2] * 1.0), + count=min(30, 5 + int(damage * 0.005)), + scale=0.5, + spread=0.3, + chunk_type='spark') + + # If they passed our spillover threshold, + # pass damage along to spaz. + if self.shield_hitpoints <= -max_spillover: + leftover_damage = -max_spillover - self.shield_hitpoints + shield_leftover_ratio = leftover_damage / damage + + # Scale down the magnitudes applied to spaz accordingly. + mag *= shield_leftover_ratio + velocity_mag *= shield_leftover_ratio + else: + return True # Good job shield! + else: + shield_leftover_ratio = 1.0 + + if msg.flat_damage: + damage = int(msg.flat_damage * self.impact_scale * + shield_leftover_ratio) + else: + # Hit it with an impulse and get the resulting damage. + 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], mag, + velocity_mag, msg.radius, 0, msg.force_direction[0], + msg.force_direction[1], msg.force_direction[2]) + + damage = int(damage_scale * self.node.damage) + self.node.handlemessage('hurt_sound') + + # Play punch impact sound based on damage if it was a punch. + if msg.hit_type == 'punch': + self.on_punched(damage) + + # If damage was significant, lets show it. + # if damage > 350: + # assert msg.force_direction is not None + # babase.show_damage_count('-' + str(int(damage / 10)) + '%', + # msg.pos, msg.force_direction) + + # Let's always add in a super-punch sound with boxing + # gloves just to differentiate them. + if msg.hit_subtype == 'super_punch': + SpazFactory.get().punch_sound_stronger.play(1.0, position=self.node.position) + if damage > 500: + sounds = SpazFactory.get().punch_sound_strong + sound = sounds[random.randrange(len(sounds))] + else: + sound = SpazFactory.get().punch_sound + sound.play(1.0, position=self.node.position) + + # Throw up some chunks. + assert msg.force_direction is not None + bs.emitfx(position=msg.pos, + velocity=(msg.force_direction[0] * 0.5, + msg.force_direction[1] * 0.5, + msg.force_direction[2] * 0.5), + count=min(10, 1 + int(damage * 0.0025)), + scale=0.3, + spread=0.03) + + bs.emitfx(position=msg.pos, + chunk_type='sweat', + velocity=(msg.force_direction[0] * 1.3, + msg.force_direction[1] * 1.3 + 5.0, + msg.force_direction[2] * 1.3), + count=min(30, 1 + int(damage * 0.04)), + scale=0.9, + spread=0.28) + + # Momentary flash. + hurtiness = damage * 0.003 + punchpos = (msg.pos[0] + msg.force_direction[0] * 0.02, + msg.pos[1] + msg.force_direction[1] * 0.02, + msg.pos[2] + msg.force_direction[2] * 0.02) + flash_color = (1.0, 0.8, 0.4) + light = bs.newnode( + 'light', + attrs={ + 'position': punchpos, + 'radius': 0.12 + hurtiness * 0.12, + 'intensity': 0.3 * (1.0 + 1.0 * hurtiness), + 'height_attenuated': False, + 'color': flash_color + }) + bs.timer(0.06, light.delete) + + flash = bs.newnode('flash', + attrs={ + 'position': punchpos, + 'size': 0.17 + 0.17 * hurtiness, + 'color': flash_color + }) + bs.timer(0.06, flash.delete) + + if msg.hit_type == 'impact': + assert msg.force_direction is not None + bs.emitfx(position=msg.pos, + velocity=(msg.force_direction[0] * 2.0, + msg.force_direction[1] * 2.0, + msg.force_direction[2] * 2.0), + count=min(10, 1 + int(damage * 0.01)), + scale=0.4, + spread=0.1) + if self.hitpoints > 0: + + # It's kinda crappy to die from impacts, so lets reduce + # impact damage by a reasonable amount *if* it'll keep us alive + if msg.hit_type == 'impact' and damage > self.hitpoints: + # Drop damage to whatever puts us at 10 hit points, + # or 200 less than it used to be whichever is greater + # (so it *can* still kill us if its high enough) + newdamage = max(damage - 200, self.hitpoints - 10) + damage = newdamage + self.node.handlemessage('flash') + + # If we're holding something, drop it. + if damage > 0.0 and self.node.hold_node: + self.node.hold_node = None + # self.hitpoints -= damage + self.multiplyer += min(damage / 2000, 0.15) + if damage/2000 > 0.05: + self.set_score_text(str(int((self.multiplyer-1)*100))+'%') + # self.node.hurt = 1.0 - float( + # self.hitpoints) / self.hitpoints_max + self.node.hurt = 0.0 + + # If we're cursed, *any* damage blows us up. + if self._cursed and damage > 0: + bs.timer( + 0.05, + bs.WeakCall(self.curse_explode, + msg.get_source_player(bs.Player))) + + # If we're frozen, shatter.. otherwise die if we hit zero + # if self.frozen and (damage > 200 or self.hitpoints <= 0): + # self.shatter() + # elif self.hitpoints <= 0: + # self.node.handlemessage( + # bs.DieMessage(how=babase.DeathType.IMPACT)) + + # If we're dead, take a look at the smoothed damage value + # (which gives us a smoothed average of recent damage) and shatter + # us if its grown high enough. + # if self.hitpoints <= 0: + # damage_avg = self.node.damage_smoothed * damage_scale + # if damage_avg > 1000: + # self.shatter() + + source_player = msg.get_source_player(type(self._player)) + if source_player: + self.last_player_attacked_by = source_player + self.last_attacked_time = bs.time() + self.last_attacked_type = (msg.hit_type, msg.hit_subtype) + Spaz.handlemessage(self, bs.HitMessage) # Augment standard behavior. + activity = self._activity() + if activity is not None and self._player.exists(): + activity.handlemessage(PlayerSpazHurtMessage(self)) + + elif isinstance(msg, bs.DieMessage): + self.oob_effect() + super().handlemessage(msg) + elif isinstance(msg, bs.PowerupMessage): + if msg.poweruptype == 'health': + if self.multiplyer > 2: + self.multiplyer *= 0.5 + else: + self.multiplyer *= 0.75 + self.multiplyer = max(1, self.multiplyer) + self.set_score_text(str(int((self.multiplyer-1)*100))+"%") + super().handlemessage(msg) + else: + super().handlemessage(msg) class Player(bs.Player['Team']): - """Our player type for this game.""" + """Our player type for this game.""" class Team(bs.Team[Player]): - """Our team type for this game.""" + """Our team type for this game.""" - def __init__(self) -> None: - self.score = 0 + def __init__(self) -> None: + self.score = 0 # ba_meta export bascenev1.GameActivity class SuperSmash(bs.TeamGameActivity[Player, Team]): - name = 'Super Smash' - description = 'Knock everyone off the map.' - - # Print messages when players die since it matters here. - announce_player_deaths = True - - @classmethod - def get_available_settings( - cls, sessiontype: Type[bs.Session]) -> List[babase.Setting]: - settings = [ - bs.IntSetting( - 'Kills to Win Per Player', - min_value=1, - default=5, - increment=1, - ), - bs.IntChoiceSetting( - 'Time Limit', - choices=[ - ('None', 0), - ('1 Minute', 60), - ('2 Minutes', 120), - ('5 Minutes', 300), - ('10 Minutes', 600), - ('20 Minutes', 1200), - ], - default=0, - ), - bs.FloatChoiceSetting( - 'Respawn Times', - choices=[ - ('Shorter', 0.25), - ('Short', 0.5), - ('Normal', 1.0), - ('Long', 2.0), - ('Longer', 4.0), - ], - default=1.0, - ), - bs.BoolSetting('Boxing Gloves', default=False), - bs.BoolSetting('Epic Mode', default=False), - ] - if issubclass(sessiontype, bs.FreeForAllSession): - settings.append( - bs.BoolSetting('Allow Negative Scores', default=False)) - return settings - - @classmethod - def supports_session_type(cls, sessiontype: Type[bs.Session]) -> bool: - return (issubclass(sessiontype, bs.DualTeamSession) - or issubclass(sessiontype, bs.FreeForAllSession)) - - @classmethod - def get_supported_maps(cls, sessiontype: Type[bs.Session]) -> List[str]: - maps = bs.app.classic.getmaps('melee') - for m in ['Lake Frigid', 'Hockey Stadium', 'Football Stadium']: - # remove maps without bounds - maps.remove(m) - return maps - - def __init__(self, settings: dict): - super().__init__(settings) - self._scoreboard = Scoreboard() - self._score_to_win: int | None = None - self._dingsound = bs.getsound('dingSmall') - self._epic_mode = bool(settings['Epic Mode']) - self._kills_to_win_per_player = int( - settings['Kills to Win Per Player']) - self._time_limit = float(settings['Time Limit']) - self._allow_negative_scores = bool( - settings.get('Allow Negative Scores', False)) - self._boxing_gloves = bool(settings['Boxing Gloves']) - - # Base class overrides. - self.slow_motion = self._epic_mode - self.default_music = (bs.MusicType.EPIC if self._epic_mode else - bs.MusicType.SURVIVAL) - - def get_instance_description(self) -> str | Sequence: - return 'Knock everyone off the map.' - - def get_instance_description_short(self) -> str | Sequence: - return 'Knock off the map.' - - def on_begin(self) -> None: - super().on_begin() - self._start_time = bs.time() - self.setup_standard_time_limit(self._time_limit) - self.setup_standard_powerup_drops(enable_tnt=False) - self._pow = None - self._tnt_drop_timer = bs.timer(1.0 * 0.30, - bs.WeakCall(self._drop_pow_box), - repeat=True) - - # Base kills needed to win on the size of the largest team. - self._score_to_win = (self._kills_to_win_per_player * - max(1, max(len(t.players) for t in self.teams))) - self._update_scoreboard() - - def _drop_pow_box(self) -> None: - if self._pow is not None and self._pow: - return - if len(self.map.tnt_points) == 0: - return - pos = random.choice(self.map.tnt_points) - pos = (pos[0], pos[1] + 1, pos[2]) - self._pow = PowBox(position=pos, velocity=(0.0, 1.0, 0.0)) - - def spawn_player(self, player: Player) -> bs.Actor: - if isinstance(self.session, bs.DualTeamSession): - position = self.map.get_start_position(player.team.id) - else: - # otherwise do free-for-all spawn locations - position = self.map.get_ffa_start_position(self.players) - angle = None - - name = player.getname() - light_color = _math.normalized_color(player.color) - display_color = babase.safecolor(player.color, target_intensity=0.75) - - spaz = SSPlayerSpaz(color=player.color, - highlight=player.highlight, - character=player.character, - player=player) - - player.actor = spaz - assert spaz.node - - # If this is co-op and we're on Courtyard or Runaround, add the - # material that allows us to collide with the player-walls. - # FIXME: Need to generalize this. - if isinstance(self.session, bs.CoopSession) and self.map.getname() in [ - 'Courtyard', 'Tower D' - ]: - mat = self.map.preloaddata['collide_with_wall_material'] - assert isinstance(spaz.node.materials, tuple) - assert isinstance(spaz.node.roller_materials, tuple) - spaz.node.materials += (mat, ) - spaz.node.roller_materials += (mat, ) - - spaz.node.name = name - spaz.node.name_color = display_color - spaz.connect_controls_to_player() - - # Move to the stand position and add a flash of light. - spaz.handlemessage( - bs.StandMessage( - position, - angle if angle is not None else random.uniform(0, 360))) - self._spawn_sound.play(1, position=spaz.node.position) - light = bs.newnode('light', attrs={'color': light_color}) - spaz.node.connectattr('position', light, 'position') - bs.animate(light, 'intensity', {0: 0, 0.25: 1, 0.5: 0}) - bs.timer(0.5, light.delete) - - if self._boxing_gloves: - spaz.equip_boxing_gloves() - - return spaz - - def handlemessage(self, msg: Any) -> Any: - - if isinstance(msg, bs.PlayerDiedMessage): - # Augment standard behavior. - super().handlemessage(msg) - - player = msg.getplayer(Player) - self.respawn_player(player) - - killer = msg.getkillerplayer(Player) - if killer is None: - return None - - # Handle team-kills. - if killer.team is player.team: - - # In free-for-all, killing yourself loses you a point. - if isinstance(self.session, bs.FreeForAllSession): - new_score = player.team.score - 1 - if not self._allow_negative_scores: - new_score = max(0, new_score) - player.team.score = new_score - - # In teams-mode it gives a point to the other team. - else: - self._dingsound.play() - for team in self.teams: - if team is not killer.team: - team.score += 1 - - # Killing someone on another team nets a kill. - else: - killer.team.score += 1 - self._dingsound.play() - - # In FFA show scores since its hard to find on the scoreboard. - if isinstance(killer.actor, SSPlayerSpaz) and killer.actor: - killer.actor.set_score_text(str(killer.team.score) + '/' + - str(self._score_to_win), - color=killer.team.color, - flash=True) - - self._update_scoreboard() - - # If someone has won, set a timer to end shortly. - # (allows the dust to clear and draws to occur if deaths are - # close enough) - assert self._score_to_win is not None - if any(team.score >= self._score_to_win for team in self.teams): - bs.timer(0.5, self.end_game) - - else: - return super().handlemessage(msg) - return None - - def _update_scoreboard(self) -> None: - for team in self.teams: - self._scoreboard.set_team_value(team, team.score, - self._score_to_win) - - def end_game(self) -> None: - results = bs.GameResults() - for team in self.teams: - results.set_team_score(team, team.score) - self.end(results=results) + name = 'Super Smash' + description = 'Knock everyone off the map.' + + # Print messages when players die since it matters here. + announce_player_deaths = True + + @classmethod + def get_available_settings( + cls, sessiontype: Type[bs.Session]) -> List[babase.Setting]: + settings = [ + bs.IntSetting( + 'Kills to Win Per Player', + min_value=1, + default=5, + increment=1, + ), + bs.IntChoiceSetting( + 'Time Limit', + choices=[ + ('None', 0), + ('1 Minute', 60), + ('2 Minutes', 120), + ('5 Minutes', 300), + ('10 Minutes', 600), + ('20 Minutes', 1200), + ], + default=0, + ), + bs.FloatChoiceSetting( + 'Respawn Times', + choices=[ + ('Shorter', 0.25), + ('Short', 0.5), + ('Normal', 1.0), + ('Long', 2.0), + ('Longer', 4.0), + ], + default=1.0, + ), + bs.BoolSetting('Boxing Gloves', default=False), + bs.BoolSetting('Epic Mode', default=False), + ] + if issubclass(sessiontype, bs.FreeForAllSession): + settings.append( + bs.BoolSetting('Allow Negative Scores', default=False)) + return settings + + @classmethod + def supports_session_type(cls, sessiontype: Type[bs.Session]) -> bool: + return (issubclass(sessiontype, bs.DualTeamSession) + or issubclass(sessiontype, bs.FreeForAllSession)) + + @classmethod + def get_supported_maps(cls, sessiontype: Type[bs.Session]) -> List[str]: + maps = bs.app.classic.getmaps('melee') + for m in ['Lake Frigid', 'Hockey Stadium', 'Football Stadium']: + # remove maps without bounds + maps.remove(m) + return maps + + def __init__(self, settings: dict): + super().__init__(settings) + self._scoreboard = Scoreboard() + self._score_to_win: int | None = None + self._dingsound = bs.getsound('dingSmall') + self._epic_mode = bool(settings['Epic Mode']) + self._kills_to_win_per_player = int( + settings['Kills to Win Per Player']) + self._time_limit = float(settings['Time Limit']) + self._allow_negative_scores = bool( + settings.get('Allow Negative Scores', False)) + self._boxing_gloves = bool(settings['Boxing Gloves']) + + # Base class overrides. + self.slow_motion = self._epic_mode + self.default_music = (bs.MusicType.EPIC if self._epic_mode else + bs.MusicType.SURVIVAL) + + def get_instance_description(self) -> str | Sequence: + return 'Knock everyone off the map.' + + def get_instance_description_short(self) -> str | Sequence: + return 'Knock off the map.' + + def on_begin(self) -> None: + super().on_begin() + self._start_time = bs.time() + self.setup_standard_time_limit(self._time_limit) + self.setup_standard_powerup_drops(enable_tnt=False) + self._pow = None + self._tnt_drop_timer = bs.timer(1.0 * 0.30, + bs.WeakCall(self._drop_pow_box), + repeat=True) + + # Base kills needed to win on the size of the largest team. + self._score_to_win = (self._kills_to_win_per_player * + max(1, max(len(t.players) for t in self.teams))) + self._update_scoreboard() + + def _drop_pow_box(self) -> None: + if self._pow is not None and self._pow: + return + if len(self.map.tnt_points) == 0: + return + pos = random.choice(self.map.tnt_points) + pos = (pos[0], pos[1] + 1, pos[2]) + self._pow = PowBox(position=pos, velocity=(0.0, 1.0, 0.0)) + + def spawn_player(self, player: Player) -> bs.Actor: + if isinstance(self.session, bs.DualTeamSession): + position = self.map.get_start_position(player.team.id) + else: + # otherwise do free-for-all spawn locations + position = self.map.get_ffa_start_position(self.players) + angle = None + + name = player.getname() + light_color = _math.normalized_color(player.color) + display_color = babase.safecolor(player.color, target_intensity=0.75) + + spaz = SSPlayerSpaz(color=player.color, + highlight=player.highlight, + character=player.character, + player=player) + + player.actor = spaz + assert spaz.node + + # If this is co-op and we're on Courtyard or Runaround, add the + # material that allows us to collide with the player-walls. + # FIXME: Need to generalize this. + if isinstance(self.session, bs.CoopSession) and self.map.getname() in [ + 'Courtyard', 'Tower D' + ]: + mat = self.map.preloaddata['collide_with_wall_material'] + assert isinstance(spaz.node.materials, tuple) + assert isinstance(spaz.node.roller_materials, tuple) + spaz.node.materials += (mat, ) + spaz.node.roller_materials += (mat, ) + + spaz.node.name = name + spaz.node.name_color = display_color + spaz.connect_controls_to_player() + + # Move to the stand position and add a flash of light. + spaz.handlemessage( + bs.StandMessage( + position, + angle if angle is not None else random.uniform(0, 360))) + self._spawn_sound.play(1, position=spaz.node.position) + light = bs.newnode('light', attrs={'color': light_color}) + spaz.node.connectattr('position', light, 'position') + bs.animate(light, 'intensity', {0: 0, 0.25: 1, 0.5: 0}) + bs.timer(0.5, light.delete) + + if self._boxing_gloves: + spaz.equip_boxing_gloves() + + return spaz + + def handlemessage(self, msg: Any) -> Any: + + if isinstance(msg, bs.PlayerDiedMessage): + # Augment standard behavior. + super().handlemessage(msg) + + player = msg.getplayer(Player) + self.respawn_player(player) + + killer = msg.getkillerplayer(Player) + if killer is None: + return None + + # Handle team-kills. + if killer.team is player.team: + + # In free-for-all, killing yourself loses you a point. + if isinstance(self.session, bs.FreeForAllSession): + new_score = player.team.score - 1 + if not self._allow_negative_scores: + new_score = max(0, new_score) + player.team.score = new_score + + # In teams-mode it gives a point to the other team. + else: + self._dingsound.play() + for team in self.teams: + if team is not killer.team: + team.score += 1 + + # Killing someone on another team nets a kill. + else: + killer.team.score += 1 + self._dingsound.play() + + # In FFA show scores since its hard to find on the scoreboard. + if isinstance(killer.actor, SSPlayerSpaz) and killer.actor: + killer.actor.set_score_text(str(killer.team.score) + '/' + + str(self._score_to_win), + color=killer.team.color, + flash=True) + + self._update_scoreboard() + + # If someone has won, set a timer to end shortly. + # (allows the dust to clear and draws to occur if deaths are + # close enough) + assert self._score_to_win is not None + if any(team.score >= self._score_to_win for team in self.teams): + bs.timer(0.5, self.end_game) + + else: + return super().handlemessage(msg) + return None + + def _update_scoreboard(self) -> None: + for team in self.teams: + self._scoreboard.set_team_value(team, team.score, + self._score_to_win) + + def end_game(self) -> None: + results = bs.GameResults() + for team in self.teams: + results.set_team_score(team, team.score) + self.end(results=results) class Player2(bs.Player['Team']): - """Our player type for this game.""" + """Our player type for this game.""" - def __init__(self) -> None: - self.lives = 0 - self.icons: List[Icon] = [] + def __init__(self) -> None: + self.lives = 0 + self.icons: List[Icon] = [] class Team2(bs.Team[Player]): - """Our team type for this game.""" + """Our team type for this game.""" - def __init__(self) -> None: - self.survival_seconds: Optional[int] = None - self.spawn_order: List[Player] = [] + def __init__(self) -> None: + self.survival_seconds: Optional[int] = None + self.spawn_order: List[Player] = [] # ba_meta export bascenev1.GameActivity class SuperSmashElimination(bs.TeamGameActivity[Player2, Team2]): - name = 'Super Smash Elimination' - description = 'Knock everyone off the map.' - scoreconfig = bs.ScoreConfig(label='Survived', - scoretype=bs.ScoreType.SECONDS, - none_is_winner=True) - - # Print messages when players die since it matters here. - announce_player_deaths = True - - @classmethod - def get_available_settings( - cls, sessiontype: Type[bs.Session]) -> List[babase.Setting]: - settings = [ - bs.IntSetting( - 'Lives (0 = Unlimited)', - min_value=0, - default=3, - increment=1, - ), - bs.IntChoiceSetting( - 'Time Limit', - choices=[ - ('None', 0), - ('1 Minute', 60), - ('2 Minutes', 120), - ('5 Minutes', 300), - ('10 Minutes', 600), - ('20 Minutes', 1200), - ], - default=0, - ), - bs.FloatChoiceSetting( - 'Respawn Times', - choices=[ - ('Shorter', 0.25), - ('Short', 0.5), - ('Normal', 1.0), - ('Long', 2.0), - ('Longer', 4.0), - ], - default=1.0, - ), - bs.BoolSetting('Boxing Gloves', default=False), - bs.BoolSetting('Epic Mode', default=False), - ] - return settings - - @classmethod - def supports_session_type(cls, sessiontype: Type[bs.Session]) -> bool: - return (issubclass(sessiontype, bs.DualTeamSession) - or issubclass(sessiontype, bs.FreeForAllSession)) - - @classmethod - def get_supported_maps(cls, sessiontype: Type[bs.Session]) -> List[str]: - maps = bs.app.classic.getmaps('melee') - for m in ['Lake Frigid', 'Hockey Stadium', 'Football Stadium']: - # remove maps without bounds - maps.remove(m) - return maps - - def __init__(self, settings: dict): - super().__init__(settings) - self.lives = int(settings['Lives (0 = Unlimited)']) - self.time_limit_only = (self.lives == 0) - if self.time_limit_only: - settings['Time Limit'] = max(60, settings['Time Limit']) - - self._epic_mode = bool(settings['Epic Mode']) - self._time_limit = float(settings['Time Limit']) - - self._start_time: Optional[float] = 1.0 - - self._boxing_gloves = bool(settings['Boxing Gloves']) - self._solo_mode = bool(settings.get('Solo Mode', False)) - - # Base class overrides. - self.slow_motion = self._epic_mode - self.default_music = (bs.MusicType.EPIC if self._epic_mode else - bs.MusicType.SURVIVAL) - - def get_instance_description(self) -> str | Sequence: - return 'Knock everyone off the map.' - - def get_instance_description_short(self) -> str | Sequence: - return 'Knock off the map.' - - def on_begin(self) -> None: - super().on_begin() - self._start_time = bs.time() - self.setup_standard_time_limit(self._time_limit) - self.setup_standard_powerup_drops(enable_tnt=False) - self._pow = None - self._tnt_drop_timer = bs.timer(1.0 * 0.30, - bs.WeakCall(self._drop_pow_box), - repeat=True) - self._update_icons() - bs.timer(1.0, self.check_end_game, repeat=True) - - def _drop_pow_box(self) -> None: - if self._pow is not None and self._pow: - return - if len(self.map.tnt_points) == 0: - return - pos = random.choice(self.map.tnt_points) - pos = (pos[0], pos[1] + 1, pos[2]) - self._pow = PowBox(position=pos, velocity=(0.0, 1.0, 0.0)) - - def on_player_join(self, player: Player) -> None: - - if self.has_begun(): - if (all(teammate.lives == 0 for teammate in player.team.players) - and player.team.survival_seconds is None): - player.team.survival_seconds = 0 - bs.broadcastmessage( - babase.Lstr(resource='playerDelayedJoinText', - subs=[('${PLAYER}', player.getname(full=True))]), - color=(0, 1, 0), - ) - return - - player.lives = self.lives - # create our icon and spawn - player.icons = [Icon(player, - position=(0.0, 50), - scale=0.8)] - if player.lives > 0 or self.time_limit_only: - self.spawn_player(player) - - # dont waste time doing this until begin - if self.has_begun(): - self._update_icons() - - def on_player_leave(self, player: Player) -> None: - super().on_player_leave(player) - player.icons = None - - # update icons in a moment since our team - # will be gone from the list then - bs.timer(0.0, self._update_icons) - bs.timer(0.1, self.check_end_game, repeat=True) - - def _update_icons(self) -> None: - # pylint: disable=too-many-branches - - # In free-for-all mode, everyone is just lined up along the bottom. - if isinstance(self.session, bs.FreeForAllSession): - count = len(self.teams) - x_offs = 85 - xval = x_offs * (count - 1) * -0.5 - for team in self.teams: - if len(team.players) > 1: - print('WTF have', len(team.players), 'players in ffa team') - elif len(team.players) == 1: - player = team.players[0] - if len(player.icons) != 1: - print( - 'WTF have', - len(player.icons), - 'icons in non-solo elim') - for icon in player.icons: - icon.set_position_and_scale((xval, 30), 0.7) - icon.update_for_lives() - xval += x_offs - - # In teams mode we split up teams. - else: - if self._solo_mode: - # First off, clear out all icons. - for player in self.players: - player.icons = [] - - # Now for each team, cycle through our available players - # adding icons. - for team in self.teams: - if team.id == 0: - xval = -60 - x_offs = -78 - else: - xval = 60 - x_offs = 78 - is_first = True - test_lives = 1 - while True: - players_with_lives = [ - p for p in team.spawn_order - if p and p.lives >= test_lives - ] - if not players_with_lives: - break - for player in players_with_lives: - player.icons.append( - Icon(player, - position=(xval, (40 if is_first else 25)), - scale=1.0 if is_first else 0.5, - name_maxwidth=130 if is_first else 75, - name_scale=0.8 if is_first else 1.0, - flatness=0.0 if is_first else 1.0, - shadow=0.5 if is_first else 1.0, - show_death=is_first, - show_lives=False)) - xval += x_offs * (0.8 if is_first else 0.56) - is_first = False - test_lives += 1 - # Non-solo mode. - else: - for team in self.teams: - if team.id == 0: - xval = -50 - x_offs = -85 - else: - xval = 50 - x_offs = 85 - for player in team.players: - if len(player.icons) != 1: - print( - 'WTF have', - len(player.icons), - 'icons in non-solo elim') - for icon in player.icons: - icon.set_position_and_scale((xval, 30), 0.7) - icon.update_for_lives() - xval += x_offs - - # overriding the default character spawning.. - def spawn_player(self, player: Player) -> bs.Actor: - if isinstance(self.session, bs.DualTeamSession): - position = self.map.get_start_position(player.team.id) - else: - # otherwise do free-for-all spawn locations - position = self.map.get_ffa_start_position(self.players) - angle = None - - name = player.getname() - light_color = _math.normalized_color(player.color) - display_color = babase.safecolor(player.color, target_intensity=0.75) - - spaz = SSPlayerSpaz(color=player.color, - highlight=player.highlight, - character=player.character, - player=player) - - player.actor = spaz - assert spaz.node - - # If this is co-op and we're on Courtyard or Runaround, add the - # material that allows us to collide with the player-walls. - # FIXME: Need to generalize this. - if isinstance(self.session, bs.CoopSession) and self.map.getname() in [ - 'Courtyard', 'Tower D' - ]: - mat = self.map.preloaddata['collide_with_wall_material'] - assert isinstance(spaz.node.materials, tuple) - assert isinstance(spaz.node.roller_materials, tuple) - spaz.node.materials += (mat, ) - spaz.node.roller_materials += (mat, ) - - spaz.node.name = name - spaz.node.name_color = display_color - spaz.connect_controls_to_player() - - # Move to the stand position and add a flash of light. - spaz.handlemessage( - bs.StandMessage( - position, - angle if angle is not None else random.uniform(0, 360))) - self._spawn_sound.play(1, position=spaz.node.position) - light = bs.newnode('light', attrs={'color': light_color}) - spaz.node.connectattr('position', light, 'position') - bs.animate(light, 'intensity', {0: 0, 0.25: 1, 0.5: 0}) - bs.timer(0.5, light.delete) - - # If we have any icons, update their state. - for icon in player.icons: - icon.handle_player_spawned() - - if self._boxing_gloves: - spaz.equip_boxing_gloves() - - return spaz - - def _get_total_team_lives(self, team: Team) -> int: - return sum(player.lives for player in team.players) - - def handlemessage(self, msg: Any) -> Any: - - if isinstance(msg, bs.PlayerDiedMessage): - # Augment standard behavior. - super().handlemessage(msg) - player: Player = msg.getplayer(Player) - - player.lives -= 1 - if player.lives < 0: - player.lives = 0 - - # if we have any icons, update their state - for icon in player.icons: - icon.handle_player_died() - - # play big death sound on our last death - # or for every one in solo mode - if player.lives == 0: - SpazFactory.get().single_player_death_sound.play() - - # if we hit zero lives we're dead and the game might be over - if player.lives == 0 and not self.time_limit_only: - # If the whole team is now dead, mark their survival time. - if self._get_total_team_lives(player.team) == 0: - assert self._start_time is not None - player.team.survival_seconds = int(bs.time() - - self._start_time) - # we still have lives; yay! - else: - self.respawn_player(player) - - bs.timer(0.1, self.check_end_game, repeat=True) - - else: - return super().handlemessage(msg) - return None - - def check_end_game(self) -> None: - if len(self._get_living_teams()) < 2: - bs.timer(0.5, self.end_game) - - def _get_living_teams(self) -> List[Team]: - return [ - team for team in self.teams - if len(team.players) > 0 and any(player.lives > 0 - for player in team.players) - ] - - def end_game(self) -> None: - if self.has_ended(): - return - results = bs.GameResults() - self._vs_text = None # Kill our 'vs' if its there. - for team in self.teams: - results.set_team_score(team, team.survival_seconds) - self.end(results=results) + name = 'Super Smash Elimination' + description = 'Knock everyone off the map.' + scoreconfig = bs.ScoreConfig(label='Survived', + scoretype=bs.ScoreType.SECONDS, + none_is_winner=True) + + # Print messages when players die since it matters here. + announce_player_deaths = True + + @classmethod + def get_available_settings( + cls, sessiontype: Type[bs.Session]) -> List[babase.Setting]: + settings = [ + bs.IntSetting( + 'Lives (0 = Unlimited)', + min_value=0, + default=3, + increment=1, + ), + bs.IntChoiceSetting( + 'Time Limit', + choices=[ + ('None', 0), + ('1 Minute', 60), + ('2 Minutes', 120), + ('5 Minutes', 300), + ('10 Minutes', 600), + ('20 Minutes', 1200), + ], + default=0, + ), + bs.FloatChoiceSetting( + 'Respawn Times', + choices=[ + ('Shorter', 0.25), + ('Short', 0.5), + ('Normal', 1.0), + ('Long', 2.0), + ('Longer', 4.0), + ], + default=1.0, + ), + bs.BoolSetting('Boxing Gloves', default=False), + bs.BoolSetting('Epic Mode', default=False), + ] + return settings + + @classmethod + def supports_session_type(cls, sessiontype: Type[bs.Session]) -> bool: + return (issubclass(sessiontype, bs.DualTeamSession) + or issubclass(sessiontype, bs.FreeForAllSession)) + + @classmethod + def get_supported_maps(cls, sessiontype: Type[bs.Session]) -> List[str]: + maps = bs.app.classic.getmaps('melee') + for m in ['Lake Frigid', 'Hockey Stadium', 'Football Stadium']: + # remove maps without bounds + maps.remove(m) + return maps + + def __init__(self, settings: dict): + super().__init__(settings) + self.lives = int(settings['Lives (0 = Unlimited)']) + self.time_limit_only = (self.lives == 0) + if self.time_limit_only: + settings['Time Limit'] = max(60, settings['Time Limit']) + + self._epic_mode = bool(settings['Epic Mode']) + self._time_limit = float(settings['Time Limit']) + + self._start_time: Optional[float] = 1.0 + + self._boxing_gloves = bool(settings['Boxing Gloves']) + self._solo_mode = bool(settings.get('Solo Mode', False)) + + # Base class overrides. + self.slow_motion = self._epic_mode + self.default_music = (bs.MusicType.EPIC if self._epic_mode else + bs.MusicType.SURVIVAL) + + def get_instance_description(self) -> str | Sequence: + return 'Knock everyone off the map.' + + def get_instance_description_short(self) -> str | Sequence: + return 'Knock off the map.' + + def on_begin(self) -> None: + super().on_begin() + self._start_time = bs.time() + self.setup_standard_time_limit(self._time_limit) + self.setup_standard_powerup_drops(enable_tnt=False) + self._pow = None + self._tnt_drop_timer = bs.timer(1.0 * 0.30, + bs.WeakCall(self._drop_pow_box), + repeat=True) + self._update_icons() + bs.timer(1.0, self.check_end_game, repeat=True) + + def _drop_pow_box(self) -> None: + if self._pow is not None and self._pow: + return + if len(self.map.tnt_points) == 0: + return + pos = random.choice(self.map.tnt_points) + pos = (pos[0], pos[1] + 1, pos[2]) + self._pow = PowBox(position=pos, velocity=(0.0, 1.0, 0.0)) + + def on_player_join(self, player: Player) -> None: + + if self.has_begun(): + if (all(teammate.lives == 0 for teammate in player.team.players) + and player.team.survival_seconds is None): + player.team.survival_seconds = 0 + bs.broadcastmessage( + babase.Lstr(resource='playerDelayedJoinText', + subs=[('${PLAYER}', player.getname(full=True))]), + color=(0, 1, 0), + ) + return + + player.lives = self.lives + # create our icon and spawn + player.icons = [Icon(player, + position=(0.0, 50), + scale=0.8)] + if player.lives > 0 or self.time_limit_only: + self.spawn_player(player) + + # dont waste time doing this until begin + if self.has_begun(): + self._update_icons() + + def on_player_leave(self, player: Player) -> None: + super().on_player_leave(player) + player.icons = None + + # update icons in a moment since our team + # will be gone from the list then + bs.timer(0.0, self._update_icons) + bs.timer(0.1, self.check_end_game, repeat=True) + + def _update_icons(self) -> None: + # pylint: disable=too-many-branches + + # In free-for-all mode, everyone is just lined up along the bottom. + if isinstance(self.session, bs.FreeForAllSession): + count = len(self.teams) + x_offs = 85 + xval = x_offs * (count - 1) * -0.5 + for team in self.teams: + if len(team.players) > 1: + print('WTF have', len(team.players), 'players in ffa team') + elif len(team.players) == 1: + player = team.players[0] + if len(player.icons) != 1: + print( + 'WTF have', + len(player.icons), + 'icons in non-solo elim') + for icon in player.icons: + icon.set_position_and_scale((xval, 30), 0.7) + icon.update_for_lives() + xval += x_offs + + # In teams mode we split up teams. + else: + if self._solo_mode: + # First off, clear out all icons. + for player in self.players: + player.icons = [] + + # Now for each team, cycle through our available players + # adding icons. + for team in self.teams: + if team.id == 0: + xval = -60 + x_offs = -78 + else: + xval = 60 + x_offs = 78 + is_first = True + test_lives = 1 + while True: + players_with_lives = [ + p for p in team.spawn_order + if p and p.lives >= test_lives + ] + if not players_with_lives: + break + for player in players_with_lives: + player.icons.append( + Icon(player, + position=(xval, (40 if is_first else 25)), + scale=1.0 if is_first else 0.5, + name_maxwidth=130 if is_first else 75, + name_scale=0.8 if is_first else 1.0, + flatness=0.0 if is_first else 1.0, + shadow=0.5 if is_first else 1.0, + show_death=is_first, + show_lives=False)) + xval += x_offs * (0.8 if is_first else 0.56) + is_first = False + test_lives += 1 + # Non-solo mode. + else: + for team in self.teams: + if team.id == 0: + xval = -50 + x_offs = -85 + else: + xval = 50 + x_offs = 85 + for player in team.players: + if len(player.icons) != 1: + print( + 'WTF have', + len(player.icons), + 'icons in non-solo elim') + for icon in player.icons: + icon.set_position_and_scale((xval, 30), 0.7) + icon.update_for_lives() + xval += x_offs + + # overriding the default character spawning.. + def spawn_player(self, player: Player) -> bs.Actor: + if isinstance(self.session, bs.DualTeamSession): + position = self.map.get_start_position(player.team.id) + else: + # otherwise do free-for-all spawn locations + position = self.map.get_ffa_start_position(self.players) + angle = None + + name = player.getname() + light_color = _math.normalized_color(player.color) + display_color = babase.safecolor(player.color, target_intensity=0.75) + + spaz = SSPlayerSpaz(color=player.color, + highlight=player.highlight, + character=player.character, + player=player) + + player.actor = spaz + assert spaz.node + + # If this is co-op and we're on Courtyard or Runaround, add the + # material that allows us to collide with the player-walls. + # FIXME: Need to generalize this. + if isinstance(self.session, bs.CoopSession) and self.map.getname() in [ + 'Courtyard', 'Tower D' + ]: + mat = self.map.preloaddata['collide_with_wall_material'] + assert isinstance(spaz.node.materials, tuple) + assert isinstance(spaz.node.roller_materials, tuple) + spaz.node.materials += (mat, ) + spaz.node.roller_materials += (mat, ) + + spaz.node.name = name + spaz.node.name_color = display_color + spaz.connect_controls_to_player() + + # Move to the stand position and add a flash of light. + spaz.handlemessage( + bs.StandMessage( + position, + angle if angle is not None else random.uniform(0, 360))) + self._spawn_sound.play(1, position=spaz.node.position) + light = bs.newnode('light', attrs={'color': light_color}) + spaz.node.connectattr('position', light, 'position') + bs.animate(light, 'intensity', {0: 0, 0.25: 1, 0.5: 0}) + bs.timer(0.5, light.delete) + + # If we have any icons, update their state. + for icon in player.icons: + icon.handle_player_spawned() + + if self._boxing_gloves: + spaz.equip_boxing_gloves() + + return spaz + + def _get_total_team_lives(self, team: Team) -> int: + return sum(player.lives for player in team.players) + + def handlemessage(self, msg: Any) -> Any: + + if isinstance(msg, bs.PlayerDiedMessage): + # Augment standard behavior. + super().handlemessage(msg) + player: Player = msg.getplayer(Player) + + player.lives -= 1 + if player.lives < 0: + player.lives = 0 + + # if we have any icons, update their state + for icon in player.icons: + icon.handle_player_died() + + # play big death sound on our last death + # or for every one in solo mode + if player.lives == 0: + SpazFactory.get().single_player_death_sound.play() + + # if we hit zero lives we're dead and the game might be over + if player.lives == 0 and not self.time_limit_only: + # If the whole team is now dead, mark their survival time. + if self._get_total_team_lives(player.team) == 0: + assert self._start_time is not None + player.team.survival_seconds = int(bs.time() - + self._start_time) + # we still have lives; yay! + else: + self.respawn_player(player) + + bs.timer(0.1, self.check_end_game, repeat=True) + + else: + return super().handlemessage(msg) + return None + + def check_end_game(self) -> None: + if len(self._get_living_teams()) < 2: + bs.timer(0.5, self.end_game) + + def _get_living_teams(self) -> List[Team]: + return [ + team for team in self.teams + if len(team.players) > 0 and any(player.lives > 0 + for player in team.players) + ] + + def end_game(self) -> None: + if self.has_ended(): + return + results = bs.GameResults() + self._vs_text = None # Kill our 'vs' if its there. + for team in self.teams: + results.set_team_score(team, team.survival_seconds) + self.end(results=results) From 832458e8287ab2585f3ab18ee62cb754eeb0d66f Mon Sep 17 00:00:00 2001 From: SenjuZoro Date: Mon, 24 Jul 2023 10:34:31 +0000 Subject: [PATCH 0621/1464] [ci] apply-version-metadata --- plugins/minigames.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/minigames.json b/plugins/minigames.json index 52773fa6..2db4b01c 100644 --- a/plugins/minigames.json +++ b/plugins/minigames.json @@ -674,4 +674,4 @@ "1.0.0": null } } -} +} \ No newline at end of file From e99617fd0e71e19402ed6674fae21ffccd5f05fd Mon Sep 17 00:00:00 2001 From: Rikko Date: Mon, 24 Jul 2023 18:52:41 +0530 Subject: [PATCH 0622/1464] Fix supersmash --- plugins/minigames.json | 4 ++-- plugins/minigames/{SuperSmash.py => supersmash.py} | 0 2 files changed, 2 insertions(+), 2 deletions(-) rename plugins/minigames/{SuperSmash.py => supersmash.py} (100%) diff --git a/plugins/minigames.json b/plugins/minigames.json index 2db4b01c..a58c0402 100644 --- a/plugins/minigames.json +++ b/plugins/minigames.json @@ -656,7 +656,7 @@ } }, "supersmash": { - "description": "SuperSmash", + "description": "Blow up your enemies off the map!", "external_url": "", "authors": [ { @@ -674,4 +674,4 @@ "1.0.0": null } } -} \ No newline at end of file +} diff --git a/plugins/minigames/SuperSmash.py b/plugins/minigames/supersmash.py similarity index 100% rename from plugins/minigames/SuperSmash.py rename to plugins/minigames/supersmash.py From 68e77f28d8661c4ab6598883e5914fea624521e5 Mon Sep 17 00:00:00 2001 From: rikkolovescats Date: Mon, 24 Jul 2023 13:23:42 +0000 Subject: [PATCH 0623/1464] [ci] apply-version-metadata --- plugins/minigames.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/minigames.json b/plugins/minigames.json index a58c0402..e33f9635 100644 --- a/plugins/minigames.json +++ b/plugins/minigames.json @@ -674,4 +674,4 @@ "1.0.0": null } } -} +} \ No newline at end of file From 1ae512a65f6208ea32f043f3116d1199a067b88d Mon Sep 17 00:00:00 2001 From: Rikko Date: Mon, 24 Jul 2023 19:17:27 +0530 Subject: [PATCH 0624/1464] Fix JSON struct --- plugins/minigames.json | 115 +++++++++++++++++++++-------------------- 1 file changed, 60 insertions(+), 55 deletions(-) diff --git a/plugins/minigames.json b/plugins/minigames.json index e33f9635..c394833f 100644 --- a/plugins/minigames.json +++ b/plugins/minigames.json @@ -615,63 +615,68 @@ "md5sum": "f68395cc90dc8cddb166a23b2da81b7b" } } - } - }, - "ufo_fight": { - "description": "Fight the UFO boss!", - "external_url": "", - "authors": [ - { - "name": "Cross Joy", - "email": "cross.joy.official@gmail.com", - "discord": "Cross Joy#0721" - } - ], - "versions": { - "1.0.0": { - "api_version": 7, - "commit_sha": "7219487", - "released_on": "15-05-2023", - "md5sum": "81617b130716996368b7d8f20f3a5154" + }, + "ufo_fight": { + "description": "Fight the UFO boss!", + "external_url": "", + "authors": [ + { + "name": "Cross Joy", + "email": "cross.joy.official@gmail.com", + "discord": "Cross Joy#0721" + } + ], + "versions": { + "1.0.0": { + "api_version": 7, + "commit_sha": "7219487", + "released_on": "15-05-2023", + "md5sum": "81617b130716996368b7d8f20f3a5154" + } } - } - }, - "yeeting_party": { - "description": "Yeet your enemies out of the map!", - "external_url": "", - "authors": [ - { - "name": "Freaku", - "email": "", - "discord": "[Just] Freak#4999" - } - ], - "versions": { - "1.0.0": { - "api_version": 7, - "commit_sha": "7219487", - "released_on": "15-05-2023", - "md5sum": "197a377652ab0c3bfbe1ca07833924b4" + }, + "yeeting_party": { + "description": "Yeet your enemies out of the map!", + "external_url": "", + "authors": [ + { + "name": "Freaku", + "email": "", + "discord": "[Just] Freak#4999" + } + ], + "versions": { + "1.0.0": { + "api_version": 7, + "commit_sha": "7219487", + "released_on": "15-05-2023", + "md5sum": "197a377652ab0c3bfbe1ca07833924b4" + } + } + }, + "supersmash": { + "description": "Blow up your enemies off the map!", + "external_url": "", + "authors": [ + { + "name": "Mrmaxmeier", + "email": "", + "discord": "" + }, + { + "name": "JoseAngel", + "email": "", + "discord": "joseang3l" + } + ], + "versions": { + "1.0.0": { + "api_version": 8, + "commit_sha": "68e77f2", + "released_on": "24-07-2023", + "md5sum": "1cbe5b3e85b5dfcee1eb322f33568fd4" + } } - } - }, - "supersmash": { - "description": "Blow up your enemies off the map!", - "external_url": "", - "authors": [ - { - "name": "Mrmaxmeier", - "email": "", - "discord": "" - }, - { - "name": "JoseAngel", - "email": "", - "discord": "joseang3l" - } - ], - "versions": { - "1.0.0": null } } } \ No newline at end of file From cf065bea67aec10c3ea4d7b45310778d8780e622 Mon Sep 17 00:00:00 2001 From: SenjuZoro <69396975+SenjuZoro@users.noreply.github.com> Date: Mon, 24 Jul 2023 15:55:19 +0200 Subject: [PATCH 0625/1464] Handball minigame --- plugins/minigames/handball.py | 383 ++++++++++++++++++++++++++++++++++ 1 file changed, 383 insertions(+) create mode 100644 plugins/minigames/handball.py diff --git a/plugins/minigames/handball.py b/plugins/minigames/handball.py new file mode 100644 index 00000000..dfb439d8 --- /dev/null +++ b/plugins/minigames/handball.py @@ -0,0 +1,383 @@ +# Released under the MIT License. See LICENSE for details. +# +"""Hockey game and support classes.""" + +# ba_meta require api 8 +# (see https://ballistica.net/wiki/meta-tag-system) + +from __future__ import annotations + +from typing import TYPE_CHECKING + +import babase +import bauiv1 as bui +import bascenev1 as bs +from bascenev1lib.actor.playerspaz import PlayerSpaz +from bascenev1lib.actor.scoreboard import Scoreboard +from bascenev1lib.actor.powerupbox import PowerupBoxFactory +from bascenev1lib.gameutils import SharedObjects + +if TYPE_CHECKING: + from typing import Any, Sequence, Optional, Union + + +class PuckDiedMessage: + """Inform something that a puck has died.""" + + def __init__(self, puck: Puck): + self.puck = puck + + +class Puck(bs.Actor): + """A lovely giant hockey puck.""" + + def __init__(self, position: Sequence[float] = (0.0, 1.0, 0.0)): + super().__init__() + shared = SharedObjects.get() + activity = self.getactivity() + + # 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, HockeyGame) + pmats = [shared.object_material, activity.puck_material] + self.node = bs.newnode('prop', + delegate=self, + attrs={ + 'mesh': activity.puck_mesh, + 'color_texture': activity.puck_tex, + 'body': 'sphere', + 'reflection': 'soft', + 'reflection_scale': [0.2], + 'shadow_size': 0.8, + 'is_area_of_interest': True, + 'position': self._spawn_pos, + 'materials': pmats + }) + bs.animate(self.node, 'mesh_scale', {0: 0, 0.2: 1.3, 0.26: 1}) + + def handlemessage(self, msg: Any) -> Any: + if isinstance(msg, bs.DieMessage): + assert self.node + self.node.delete() + activity = self._activity() + if activity and not msg.immediate: + activity.handlemessage(PuckDiedMessage(self)) + + # If we go out of bounds, move back to where we started. + elif isinstance(msg, bs.OutOfBoundsMessage): + assert self.node + self.node.position = self._spawn_pos + + elif isinstance(msg, bs.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 + else: + super().handlemessage(msg) + + +class Player(bs.Player['Team']): + """Our player type for this game.""" + + +class Team(bs.Team[Player]): + """Our team type for this game.""" + + def __init__(self) -> None: + self.score = 0 + + +# ba_meta export bascenev1.GameActivity +class HockeyGame(bs.TeamGameActivity[Player, Team]): + """Ice hockey game.""" + + name = 'Handball' + description = 'Score some goals.' + available_settings = [ + bs.IntSetting( + 'Score to Win', + min_value=1, + default=1, + increment=1, + ), + bs.IntChoiceSetting( + 'Time Limit', + choices=[ + ('None', 0), + ('1 Minute', 60), + ('2 Minutes', 120), + ('5 Minutes', 300), + ('10 Minutes', 600), + ('20 Minutes', 1200), + ], + default=0, + ), + bs.FloatChoiceSetting( + 'Respawn Times', + choices=[ + ('Shorter', 0.25), + ('Short', 0.5), + ('Normal', 1.0), + ('Long', 2.0), + ('Longer', 4.0), + ], + default=1.0, + ), + bs.BoolSetting('Epic Mode', default=False), + + ] + default_music = bs.MusicType.HOCKEY + + @classmethod + def supports_session_type(cls, sessiontype: type[bs.Session]) -> bool: + return issubclass(sessiontype, bs.DualTeamSession) + + @classmethod + def get_supported_maps(cls, sessiontype: type[bs.Session]) -> list[str]: + return bs.app.classic.getmaps('hockey') + + def __init__(self, settings: dict): + super().__init__(settings) + shared = SharedObjects.get() + self._scoreboard = Scoreboard() + self._cheer_sound = bs.getsound('cheer') + self._chant_sound = bs.getsound('crowdChant') + self._foghorn_sound = bs.getsound('foghorn') + self._swipsound = bs.getsound('swip') + self._whistle_sound = bs.getsound('refWhistle') + self.puck_mesh = bs.getmesh('bomb') + self.puck_tex = bs.gettexture('bonesColor') + self._puck_sound = bs.getsound('metalHit') + self._epic_mode = bool(settings['Epic Mode']) + self.slow_motion = self._epic_mode + self.default_music = (bs.MusicType.EPIC + if self._epic_mode else bs.MusicType.FOOTBALL) + self.puck_material = bs.Material() + self.puck_material.add_actions(actions=(('modify_part_collision', + 'friction', 0.5))) + self.puck_material.add_actions(conditions=('they_have_material', + shared.pickup_material), + actions=('modify_part_collision', + 'collide', False)) + self.puck_material = bs.Material() + self.puck_material.add_actions(actions=(('modify_part_collision', + 'friction', 0.5))) + self.puck_material.add_actions(conditions=('they_have_material', + shared.pickup_material), + actions=('modify_part_collision', + 'collide', True)) + self.puck_material.add_actions( + conditions=( + ('we_are_younger_than', 100), + 'and', + ('they_have_material', shared.object_material), + ), + actions=('modify_node_collision', 'collide', False), + ) + self.puck_material.add_actions(conditions=('they_have_material', + shared.footing_material), + actions=('impact_sound', + self._puck_sound, 0.2, 5)) + + # Keep track of which player last touched the puck + self.puck_material.add_actions( + conditions=('they_have_material', shared.player_material), + actions=(('call', 'at_connect', + self._handle_puck_player_collide), )) + + # We want the puck to kill powerups; not get stopped by them + self.puck_material.add_actions( + conditions=('they_have_material', + PowerupBoxFactory.get().powerup_material), + actions=(('modify_part_collision', 'physical', False), + ('message', 'their_node', 'at_connect', bs.DieMessage()))) + self._score_region_material = bs.Material() + self._score_region_material.add_actions( + conditions=('they_have_material', self.puck_material), + actions=(('modify_part_collision', 'collide', + True), ('modify_part_collision', 'physical', False), + ('call', 'at_connect', self._handle_score))) + self._puck_spawn_pos: Optional[Sequence[float]] = None + self._score_regions: Optional[list[bs.NodeActor]] = None + self._puck: Optional[Puck] = 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 'Score a goal.' + return 'Score ${ARG1} goals.', self._score_to_win + + def get_instance_description_short(self) -> Union[str, Sequence]: + if self._score_to_win == 1: + return 'score a goal' + return 'score ${ARG1} goals', self._score_to_win + + def on_begin(self) -> None: + super().on_begin() + + self.setup_standard_time_limit(self._time_limit) + self.setup_standard_powerup_drops() + self._puck_spawn_pos = self.map.get_flag_position(None) + self._spawn_puck() + + # Set up the two score regions. + defs = self.map.defs + self._score_regions = [] + self._score_regions.append( + bs.NodeActor( + bs.newnode('region', + attrs={ + 'position': defs.boxes['goal1'][0:3], + 'scale': defs.boxes['goal1'][6:9], + 'type': 'box', + 'materials': [self._score_region_material] + }))) + self._score_regions.append( + bs.NodeActor( + bs.newnode('region', + attrs={ + 'position': defs.boxes['goal2'][0:3], + 'scale': defs.boxes['goal2'][6:9], + 'type': 'box', + 'materials': [self._score_region_material] + }))) + self._update_scoreboard() + self._chant_sound.play() + + def on_team_join(self, team: Team) -> None: + self._update_scoreboard() + + def _handle_puck_player_collide(self) -> None: + collision = bs.getcollision() + try: + puck = collision.sourcenode.getdelegate(Puck, True) + player = collision.opposingnode.getdelegate(PlayerSpaz, + True).getplayer( + Player, True) + except bs.NotFoundError: + return + + puck.last_players_to_touch[player.team.id] = player + + def _kill_puck(self) -> None: + self._puck = None + + def _handle_score(self) -> None: + """A point has been scored.""" + + assert self._puck is not None + assert self._score_regions is not None + + # Our puck might stick around for a second or two + # we don't want it to be able to score again. + if self._puck.scored: + return + + region = bs.getcollision().sourcenode + index = 0 + for index, score_region in enumerate(self._score_regions): + if region == score_region.node: + break + + for team in self.teams: + if team.id == index: + scoring_team = team + team.score += 1 + + # Tell all players to celebrate. + for player in team.players: + if player.actor: + player.actor.handlemessage(bs.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._puck.last_players_to_touch + and self._puck.last_players_to_touch[scoring_team.id]): + self.stats.player_scored( + self._puck.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() + + self._foghorn_sound.play() + self._cheer_sound.play() + + self._puck.scored = True + + # Kill the puck (it'll respawn itself shortly). + bs.timer(1.0, self._kill_puck) + + light = bs.newnode('light', + attrs={ + 'position': bs.getcollision().position, + 'height_attenuated': False, + 'color': (1, 0, 0) + }) + bs.animate(light, 'intensity', {0: 0, 0.5: 1, 1.0: 0}, loop=True) + bs.timer(1.0, light.delete) + + bs.cameraflash(duration=10.0) + self._update_scoreboard() + + def end_game(self) -> None: + results = bs.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, bs.PlayerDiedMessage): + # Augment standard behavior... + super().handlemessage(msg) + self.respawn_player(msg.getplayer(Player)) + + # Respawn dead pucks. + elif isinstance(msg, PuckDiedMessage): + if not self.has_ended(): + bs.timer(3.0, self._spawn_puck) + else: + super().handlemessage(msg) + + def _flash_puck_spawn(self) -> None: + light = bs.newnode('light', + attrs={ + 'position': self._puck_spawn_pos, + 'height_attenuated': False, + 'color': (1, 0, 0) + }) + bs.animate(light, 'intensity', {0.0: 0, 0.25: 1, 0.5: 0}, loop=True) + bs.timer(1.0, light.delete) + + def _spawn_puck(self) -> None: + self._swipsound.play() + self._whistle_sound.play() + self._flash_puck_spawn() + assert self._puck_spawn_pos is not None + self._puck = Puck(position=self._puck_spawn_pos) From 2309aab5b5cc61a01904ce5d17864319203ead31 Mon Sep 17 00:00:00 2001 From: SenjuZoro <69396975+SenjuZoro@users.noreply.github.com> Date: Mon, 24 Jul 2023 15:58:02 +0200 Subject: [PATCH 0626/1464] Update minigames.json --- plugins/minigames.json | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/plugins/minigames.json b/plugins/minigames.json index c394833f..3c33d173 100644 --- a/plugins/minigames.json +++ b/plugins/minigames.json @@ -654,6 +654,20 @@ } } }, + "handball": { + "description": "Score some goals with handball", + "external_url": "", + "authors": [ + { + "name": "Unknown", + "email": "", + "discord": "" + } + ], + "versions": { + "1.0.0":null + } + }, "supersmash": { "description": "Blow up your enemies off the map!", "external_url": "", @@ -679,4 +693,4 @@ } } } -} \ No newline at end of file +} From 3ae4d768c9cf18c840d3c9a2ae25560205b9f308 Mon Sep 17 00:00:00 2001 From: SenjuZoro Date: Mon, 24 Jul 2023 13:59:30 +0000 Subject: [PATCH 0627/1464] [ci] apply-version-metadata --- plugins/minigames.json | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/plugins/minigames.json b/plugins/minigames.json index 3c33d173..6a489c80 100644 --- a/plugins/minigames.json +++ b/plugins/minigames.json @@ -665,7 +665,12 @@ } ], "versions": { - "1.0.0":null + "1.0.0": { + "api_version": 8, + "commit_sha": "2309aab", + "released_on": "24-07-2023", + "md5sum": "01b85dc9ef1d464ab604387af09f05dc" + } } }, "supersmash": { @@ -693,4 +698,4 @@ } } } -} +} \ No newline at end of file From dec344efb7f946870d0e70d24c945ef06a7e5b4e Mon Sep 17 00:00:00 2001 From: brostos <67740566+brostosjoined@users.noreply.github.com> Date: Tue, 25 Jul 2023 04:00:51 +0300 Subject: [PATCH 0628/1464] Update utilities.json --- plugins/utilities.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/plugins/utilities.json b/plugins/utilities.json index ceb32a85..7598dc96 100644 --- a/plugins/utilities.json +++ b/plugins/utilities.json @@ -758,7 +758,7 @@ }, "discord_richpresence": { "description": "Discord Rich Presence for Bombsquad.", - "external_url": "https://github.com/brostosjoined/bombsquadrpc", + "external_url": "https://youtu.be/SbbG9V74_E4", "authors": [ { "name": "Dliwk&brostos", @@ -782,4 +782,4 @@ } } } -} \ No newline at end of file +} From e5efd30159d835dc824a66e1a5e41dbc8b50ff5e Mon Sep 17 00:00:00 2001 From: SenjuZoro <69396975+SenjuZoro@users.noreply.github.com> Date: Wed, 26 Jul 2023 20:52:27 +0200 Subject: [PATCH 0629/1464] arms race updated arms race updated to api 8 --- plugins/minigames/arms_race.py | 93 +++++++++++++++------------------- 1 file changed, 40 insertions(+), 53 deletions(-) diff --git a/plugins/minigames/arms_race.py b/plugins/minigames/arms_race.py index b7ea3f59..1ac367af 100644 --- a/plugins/minigames/arms_race.py +++ b/plugins/minigames/arms_race.py @@ -1,22 +1,26 @@ -# Ported by: Freaku / @[Just] Freak#4999 +#Ported by: Freaku / @[Just] Freak#4999 -# Join BCS: +#Join BCS: # https://discord.gg/ucyaesh -# ba_meta require api 7 + +# ba_meta require api 8 from __future__ import annotations from typing import TYPE_CHECKING -import ba -from bastd.actor.playerspaz import PlayerSpaz +import babase +import bauiv1 as bui +import bascenev1 as bs +from bascenev1lib.actor.playerspaz import PlayerSpaz if TYPE_CHECKING: from typing import Any, Type, List, Dict, Tuple, Union, Sequence, Optional + class State: def __init__(self, bomb=None, grab=False, punch=False, curse=False, required=False, final=False, name=''): self.bomb = bomb @@ -30,12 +34,11 @@ def __init__(self, bomb=None, grab=False, punch=False, curse=False, required=Fal self.next = None self.index = None - def apply(self, player, spaz): - + def apply(self, spaz): spaz.disconnect_controls_from_player() spaz.connect_controls_to_player(enable_punch=self.punch, - enable_bomb=self.bomb, - enable_pickup=self.grab) + enable_bomb=self.bomb, + enable_pickup=self.grab) if self.curse: spaz.curse_time = -1 spaz.curse() @@ -43,47 +46,33 @@ def apply(self, player, spaz): spaz.bomb_type = self.bomb spaz.set_score_text(self.name) - def set_controls(): - player.actor.node.bomb_pressed = True - player.actor.on_bomb_release() - - release_input = (ba.InputType.PUNCH_RELEASE, ba.InputType.PICK_UP_RELEASE) - if not self.bomb is None: - for release in release_input: - player.assigninput( - release, - set_controls - ) - def get_setting(self): return (self.name) -states = [State(bomb='normal', name='Basic Bombs'), - State(bomb='ice', name='Frozen Bombs'), - State(bomb='sticky', name='Sticky Bombs'), - State(bomb='impact', name='Impact Bombs'), - State(grab=True, name='Grabbing only'), - State(punch=True, name='Punching only'), - State(curse=True, name='Cursed', final=True)] - +states = [ State(bomb='normal', name='Basic Bombs'), + State(bomb='ice', name='Frozen Bombs'), + State(bomb='sticky', name='Sticky Bombs'), + State(bomb='impact', name='Impact Bombs'), + State(grab=True, name='Grabbing only'), + State(punch=True, name='Punching only'), + State(curse=True, name='Cursed', final=True) ] -class Player(ba.Player['Team']): +class Player(bs.Player['Team']): """Our player type for this game.""" - def __init__(self): self.state = None -class Team(ba.Team[Player]): +class Team(bs.Team[Player]): """Our team type for this game.""" def __init__(self) -> None: self.score = 0 -# ba_meta export game -class ArmsRaceGame(ba.TeamGameActivity[Player, Team]): +# ba_meta export bascenev1.GameActivity +class ArmsRaceGame(bs.TeamGameActivity[Player, Team]): """A game type based on acquiring kills.""" name = 'Arms Race' @@ -94,9 +83,9 @@ class ArmsRaceGame(ba.TeamGameActivity[Player, Team]): @classmethod def get_available_settings( - cls, sessiontype: Type[ba.Session]) -> List[ba.Setting]: + cls, sessiontype: Type[bs.Session]) -> List[babase.Setting]: settings = [ - ba.IntChoiceSetting( + bs.IntChoiceSetting( 'Time Limit', choices=[ ('None', 0), @@ -108,7 +97,7 @@ def get_available_settings( ], default=0, ), - ba.FloatChoiceSetting( + bs.FloatChoiceSetting( 'Respawn Times', choices=[ ('Shorter', 0.25), @@ -119,21 +108,21 @@ def get_available_settings( ], default=1.0, ), - ba.BoolSetting('Epic Mode', default=False)] + bs.BoolSetting('Epic Mode', default=False)] for state in states: if not state.required: - settings.append(ba.BoolSetting(state.get_setting(), default=True)) + settings.append(bs.BoolSetting(state.get_setting(), default=True)) return settings @classmethod - def supports_session_type(cls, sessiontype: Type[ba.Session]) -> bool: - return (issubclass(sessiontype, ba.DualTeamSession) - or issubclass(sessiontype, ba.FreeForAllSession)) + def supports_session_type(cls, sessiontype: Type[bs.Session]) -> bool: + return (issubclass(sessiontype, bs.DualTeamSession) + or issubclass(sessiontype, bs.FreeForAllSession)) @classmethod - def get_supported_maps(cls, sessiontype: Type[ba.Session]) -> List[str]: - return ba.getmaps('melee') + def get_supported_maps(cls, sessiontype: Type[bs.Session]) -> List[str]: + return bs.app.classic.getmaps('melee') def __init__(self, settings: dict): super().__init__(settings) @@ -142,14 +131,14 @@ def __init__(self, settings: dict): if i < len(self.states) and not state.final: state.next = self.states[i + 1] state.index = i - self._dingsound = ba.getsound('dingSmall') + self._dingsound = bs.getsound('dingSmall') self._epic_mode = bool(settings['Epic Mode']) self._time_limit = float(settings['Time Limit']) # Base class overrides. self.slow_motion = self._epic_mode - self.default_music = (ba.MusicType.EPIC if self._epic_mode else - ba.MusicType.TO_THE_DEATH) + self.default_music = (bs.MusicType.EPIC if self._epic_mode else + bs.MusicType.TO_THE_DEATH) def get_instance_description(self) -> Union[str, Sequence]: return 'Upgrade your weapon by eliminating enemies.' @@ -168,12 +157,11 @@ def on_player_join(self, player): self.spawn_player(player) # overriding the default character spawning.. - def spawn_player(self, player): if player.state is None: player.state = self.states[0] super().spawn_player(player) - player.state.apply(player, player.actor) + player.state.apply(player.actor) def isValidKill(self, m): if m.getkillerplayer(Player) is None: @@ -186,13 +174,12 @@ def isValidKill(self, m): def handlemessage(self, msg: Any) -> Any: - if isinstance(msg, ba.PlayerDiedMessage): + if isinstance(msg, bs.PlayerDiedMessage): if self.isValidKill(msg): self.stats.player_scored(msg.getkillerplayer(Player), 10, kill=True) if not msg.getkillerplayer(Player).state.final: msg.getkillerplayer(Player).state = msg.getkillerplayer(Player).state.next - msg.getkillerplayer(Player).state.apply( - msg.getkillerplayer(Player), msg.getkillerplayer(Player).actor) + msg.getkillerplayer(Player).state.apply(msg.getkillerplayer(Player).actor) else: msg.getkillerplayer(Player).team.score += 1 self.end_game() @@ -203,7 +190,7 @@ def handlemessage(self, msg: Any) -> Any: return None def end_game(self) -> None: - results = ba.GameResults() + results = bs.GameResults() for team in self.teams: results.set_team_score(team, team.score) self.end(results=results) From 693eac617291472cde0f3392f3d895ba2305e2df Mon Sep 17 00:00:00 2001 From: SenjuZoro <69396975+SenjuZoro@users.noreply.github.com> Date: Wed, 26 Jul 2023 20:53:38 +0200 Subject: [PATCH 0630/1464] Update minigames.json --- plugins/minigames.json | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/plugins/minigames.json b/plugins/minigames.json index 6a489c80..06b1391b 100644 --- a/plugins/minigames.json +++ b/plugins/minigames.json @@ -433,6 +433,7 @@ } ], "versions": { + "2.0.0":null, "1.1.0": { "api_version": 7, "commit_sha": "2e2540a", @@ -698,4 +699,4 @@ } } } -} \ No newline at end of file +} From e7a5df9aacaaa2193dd051219272772e77eed06e Mon Sep 17 00:00:00 2001 From: SenjuZoro Date: Wed, 26 Jul 2023 18:55:16 +0000 Subject: [PATCH 0631/1464] [ci] auto-format --- plugins/minigames/arms_race.py | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/plugins/minigames/arms_race.py b/plugins/minigames/arms_race.py index 1ac367af..6f7351ba 100644 --- a/plugins/minigames/arms_race.py +++ b/plugins/minigames/arms_race.py @@ -1,10 +1,9 @@ -#Ported by: Freaku / @[Just] Freak#4999 +# Ported by: Freaku / @[Just] Freak#4999 -#Join BCS: +# Join BCS: # https://discord.gg/ucyaesh - # ba_meta require api 8 from __future__ import annotations @@ -20,7 +19,6 @@ from typing import Any, Type, List, Dict, Tuple, Union, Sequence, Optional - class State: def __init__(self, bomb=None, grab=False, punch=False, curse=False, required=False, final=False, name=''): self.bomb = bomb @@ -37,8 +35,8 @@ def __init__(self, bomb=None, grab=False, punch=False, curse=False, required=Fal def apply(self, spaz): spaz.disconnect_controls_from_player() spaz.connect_controls_to_player(enable_punch=self.punch, - enable_bomb=self.bomb, - enable_pickup=self.grab) + enable_bomb=self.bomb, + enable_pickup=self.grab) if self.curse: spaz.curse_time = -1 spaz.curse() @@ -50,16 +48,18 @@ def get_setting(self): return (self.name) -states = [ State(bomb='normal', name='Basic Bombs'), - State(bomb='ice', name='Frozen Bombs'), - State(bomb='sticky', name='Sticky Bombs'), - State(bomb='impact', name='Impact Bombs'), - State(grab=True, name='Grabbing only'), - State(punch=True, name='Punching only'), - State(curse=True, name='Cursed', final=True) ] +states = [State(bomb='normal', name='Basic Bombs'), + State(bomb='ice', name='Frozen Bombs'), + State(bomb='sticky', name='Sticky Bombs'), + State(bomb='impact', name='Impact Bombs'), + State(grab=True, name='Grabbing only'), + State(punch=True, name='Punching only'), + State(curse=True, name='Cursed', final=True)] + class Player(bs.Player['Team']): """Our player type for this game.""" + def __init__(self): self.state = None From bbad78c1692e1cf1d15428e2a67167d45dd9dfb1 Mon Sep 17 00:00:00 2001 From: SenjuZoro Date: Wed, 26 Jul 2023 18:55:18 +0000 Subject: [PATCH 0632/1464] [ci] apply-version-metadata --- plugins/minigames.json | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/plugins/minigames.json b/plugins/minigames.json index 06b1391b..8d26d8c7 100644 --- a/plugins/minigames.json +++ b/plugins/minigames.json @@ -433,7 +433,12 @@ } ], "versions": { - "2.0.0":null, + "2.0.0": { + "api_version": 8, + "commit_sha": "e7a5df9", + "released_on": "26-07-2023", + "md5sum": "641732ef5c8c97cd5482b8cd56126310" + }, "1.1.0": { "api_version": 7, "commit_sha": "2e2540a", @@ -699,4 +704,4 @@ } } } -} +} \ No newline at end of file From 651fc66aff25428b7282d7d284ffc19e42a09d8f Mon Sep 17 00:00:00 2001 From: SenjuZoro <69396975+SenjuZoro@users.noreply.github.com> Date: Thu, 27 Jul 2023 12:46:41 +0200 Subject: [PATCH 0633/1464] New game mode Big Ball Works with latest api 8 --- plugins/minigames/big_ball.py | 517 ++++++++++++++++++++++++++++++++++ 1 file changed, 517 insertions(+) create mode 100644 plugins/minigames/big_ball.py diff --git a/plugins/minigames/big_ball.py b/plugins/minigames/big_ball.py new file mode 100644 index 00000000..ead66152 --- /dev/null +++ b/plugins/minigames/big_ball.py @@ -0,0 +1,517 @@ +#Made by MythB +#Ported by: MysteriousBoi + + + + + + +# ba_meta require api 8 +from __future__ import annotations +from typing import TYPE_CHECKING +import babase +import bauiv1 as bui +import bascenev1 as bs,random +from bascenev1lib.actor.playerspaz import PlayerSpaz +from bascenev1lib.actor.scoreboard import Scoreboard +from bascenev1lib.actor.powerupbox import PowerupBoxFactory +from bascenev1lib.gameutils import SharedObjects +from bascenev1lib.actor.flag import Flag +if TYPE_CHECKING: + from typing import Any, Sequence, Dict, Type, List, Optional, Union + + +class PuckDiedMessage: + """Inform something that a puck has died.""" + + def __init__(self, puck: Puck): + self.puck = puck + +#goalpost +class FlagKale(bs.Actor): + def __init__(self,position=(0,2.5,0),color=(1,1,1)): + super().__init__() + activity = self.getactivity() + shared = SharedObjects.get() + self.node = bs.newnode('flag', + attrs={'position':(position[0],position[1]+0.75,position[2]), + 'color_texture':activity._flagKaleTex, + 'color':color, + 'materials':[shared.object_material,activity._kaleMaterial], + }, + delegate=self) + + def handleMessage(self,m): + if isinstance(m,bs.DieMessage): + if self.node.exists(): + self.node.delete() + elif isinstance(m,bs.OutOfBoundsMessage): + self.handlemessage(bs.DieMessage()) + else: + super().handlemessage(msg) + + +class Puck(bs.Actor): + def __init__(self, position: Sequence[float] = (0.0, 1.0, 0.0)): + super().__init__() + shared = SharedObjects.get() + activity = self.getactivity() + + # 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, BBGame) + pmats = [shared.object_material, activity.puck_material] + self.node = bs.newnode('prop', + delegate=self, + attrs={ + 'mesh': activity._ballModel, + 'color_texture': activity._ballTex, + 'body': 'sphere', + 'reflection': 'soft', + 'reflection_scale': [0.2], + 'shadow_size': 0.8, + 'is_area_of_interest': True, + 'position': self._spawn_pos, + 'materials': pmats, + 'body_scale': 4, + 'mesh_scale': 1, + 'density': 0.02}) + bs.animate(self.node, 'mesh_scale', {0: 0, 0.2: 1.3, 0.26: 1}) + + def handlemessage(self, msg: Any) -> Any: + if isinstance(msg, bs.DieMessage): + assert self.node + self.node.delete() + activity = self._activity() + if activity and not msg.immediate: + activity.handlemessage(PuckDiedMessage(self)) + + # If we go out of bounds, move back to where we started. + elif isinstance(msg, bs.OutOfBoundsMessage): + assert self.node + self.node.position = self._spawn_pos + + elif isinstance(msg, bs.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 + else: + super().handlemessage(msg) + +#for night mode: using a actor with large shadow and little mesh scale. Better then tint i think, players and objects more visible +class NightMod(bs.Actor): + def __init__(self,position=(0,0,0)): + super().__init__() + shared = SharedObjects.get() + activity = self.getactivity() + # spawn just above the provided point + self._spawnPos = (position[0],position[1],position[2]) + self.node = bs.newnode("prop", + attrs={'mesh': activity._nightModel, + 'color_texture': activity._nightTex, + 'body':'sphere', + 'reflection':'soft', + 'body_scale': 0.1, + 'mesh_scale':0.001, + 'density':0.010, + 'reflection_scale':[0.23], + 'shadow_size': 999999.0, + 'is_area_of_interest':True, + 'position':self._spawnPos, + 'materials': [activity._nightMaterial] + }, + delegate=self) + + def handlemssage(self,m): + super().handlemessage(m) + + +class Player(bs.Player['Team']): + """Our player type for this game.""" + + +class Team(bs.Team[Player]): + """Our team type for this game.""" + + def __init__(self) -> None: + self.score = 0 + + +# ba_meta export bascenev1.GameActivity +class BBGame(bs.TeamGameActivity[Player, Team]): + name = 'Big Ball' + description = 'Score some goals.\nFlags are goalposts.\nScored team players get boxing gloves,\nNon-scored team players getting shield (if Grant Powers on Score).\nYou can also set Night Mode!' + available_settings = [ + bs.IntSetting( + 'Score to Win', + min_value=1, + default=1, + increment=1, + ), + bs.IntChoiceSetting( + 'Time Limit', + choices=[ + ('None', 0), + ('1 Minute', 60), + ('2 Minutes', 120), + ('5 Minutes', 300), + ('10 Minutes', 600), + ('20 Minutes', 1200), + ], + default=0, + ), + bs.FloatChoiceSetting( + 'Respawn Times', + choices=[ + ('Shorter', 0.25), + ('Short', 0.5), + ('Normal', 1.0), + ('Long', 2.0), + ('Longer', 4.0), + ], + default=1.0, + ), + bs.BoolSetting('Epic Mode', True), + bs.BoolSetting('Night Mode', False), + bs.BoolSetting('Grant Powers on Score', False) + ] + default_music = bs.MusicType.HOCKEY + + @classmethod + def supports_session_type(cls, sessiontype: Type[bs.Session]) -> bool: + return issubclass(sessiontype, bs.DualTeamSession) + + @classmethod + def get_supported_maps(cls, sessiontype: Type[bs.Session]) -> List[str]: + return ['Football Stadium'] + + def __init__(self, settings: dict): + super().__init__(settings) + shared = SharedObjects.get() + self._scoreboard = Scoreboard() + self._cheer_sound = bs.getsound('cheer') + self._chant_sound = bs.getsound('crowdChant') + self._foghorn_sound = bs.getsound('foghorn') + self._swipsound = bs.getsound('swip') + self._whistle_sound = bs.getsound('refWhistle') + self._ballModel = bs.getmesh("shield") + self._ballTex = bs.gettexture("eggTex1") + self._ballSound = bs.getsound("impactMedium2") + self._flagKaleTex = bs.gettexture("star") + self._kaleSound = bs.getsound("metalHit") + self._nightModel = bs.getmesh("shield") + self._nightTex = bs.gettexture("black") + self._kaleMaterial = bs.Material() + #add friction to flags for standing our position (as far as) + self._kaleMaterial.add_actions(conditions=("they_have_material",shared.footing_material), + actions=( ("modify_part_collision","friction",9999.5))) + self._kaleMaterial.add_actions(conditions=( ("we_are_younger_than",1),'and', + ("they_have_material",shared.object_material)), + actions=( ("modify_part_collision","collide",False))) + self._kaleMaterial.add_actions(conditions=("they_have_material",shared.pickup_material), + actions=( ("modify_part_collision","collide",False))) + self._kaleMaterial.add_actions( + conditions=('they_have_material',shared.object_material), + actions=(('impact_sound',self._kaleSound,2,5))) + #we dont wanna hit the night so + self._nightMaterial = bs.Material() + self._nightMaterial.add_actions(conditions=(('they_have_material',shared.pickup_material),'or', + ('they_have_material',shared.attack_material)), + actions=(('modify_part_collision','collide',False))) + # we also dont want anything moving it + self._nightMaterial.add_actions( + conditions=(('they_have_material',shared.object_material),'or', + ('they_dont_have_material',shared.footing_material)), + actions=(('modify_part_collision','collide',False), + ('modify_part_collision','physical',False))) + self.puck_material = bs.Material() + self.puck_material.add_actions(actions=(('modify_part_collision', + 'friction', 0.5))) + self.puck_material.add_actions(conditions=('they_have_material', + shared.pickup_material), + actions=('modify_part_collision', + 'collide', False)) + self.puck_material.add_actions( + conditions=( + ('we_are_younger_than', 100), + 'and', + ('they_have_material', shared.object_material), + ), + actions=('modify_node_collision', 'collide', False), + ) + self.puck_material.add_actions(conditions=('they_have_material', + shared.footing_material), + actions=('impact_sound', + self._ballSound, 0.2, 5)) + + # Keep track of which player last touched the puck + self.puck_material.add_actions( + conditions=('they_have_material', shared.player_material), + actions=(('call', 'at_connect', + self._handle_puck_player_collide), )) + + # We want the puck to kill powerups; not get stopped by them + self.puck_material.add_actions( + conditions=('they_have_material', + PowerupBoxFactory.get().powerup_material), + actions=(('modify_part_collision', 'physical', False), + ('message', 'their_node', 'at_connect', bs.DieMessage()))) + self._score_region_material = bs.Material() + self._score_region_material.add_actions( + conditions=('they_have_material', self.puck_material), + actions=(('modify_part_collision', 'collide', + True), ('modify_part_collision', 'physical', False), + ('call', 'at_connect', self._handle_score))) + self._puck_spawn_pos: Optional[Sequence[float]] = None + self._score_regions: Optional[List[bs.NodeActor]] = None + self._puck: Optional[Puck] = None + self._score_to_win = int(settings['Score to Win']) + self._time_limit = float(settings['Time Limit']) + self._nm = bool(settings['Night Mode']) + self._grant_power = bool(settings['Grant Powers on Score']) + self._epic_mode = bool(settings['Epic Mode']) + # Base class overrides. + self.slow_motion = self._epic_mode + + def get_instance_description(self) -> Union[str, Sequence]: + if self._score_to_win == 1: + return 'Score a goal.' + return 'Score ${ARG1} goals.', self._score_to_win + + def get_instance_description_short(self) -> Union[str, Sequence]: + if self._score_to_win == 1: + return 'score a goal' + return 'score ${ARG1} goals', self._score_to_win + + def on_begin(self) -> None: + super().on_begin() + + self.setup_standard_time_limit(self._time_limit) + self.setup_standard_powerup_drops() + self._puck_spawn_pos = self.map.get_flag_position(None) + self._spawn_puck() + #for night mode we need night actor. And same goodies for nigh mode + if self._nm: self._nightSpawny(),self._flagKaleFlash() + + # Set up the two score regions. + defs = self.map.defs + self._score_regions = [] + self._score_regions.append( + bs.NodeActor( + bs.newnode('region', + attrs={ + 'position': (13.75, 0.85744967453, 0.1095578275), + 'scale': (1.05,1.1,3.8), + 'type': 'box', + 'materials': [self._score_region_material] + }))) + self._score_regions.append( + bs.NodeActor( + bs.newnode('region', + attrs={ + 'position': (-13.55, 0.85744967453, 0.1095578275), + 'scale': (1.05,1.1,3.8), + 'type': 'box', + 'materials': [self._score_region_material] + }))) + self._update_scoreboard() + self._chant_sound.play() + + def _nightSpawny(self): + self.MythBrk = NightMod(position=(0, 0.05744967453, 0)) + + #spawn some goodies on nightmode for pretty visuals + def _flagKaleFlash(self): + #flags positions + kale1 = (-12.45, 0.05744967453, -2.075) + kale2 = (-12.45, 0.05744967453, 2.075) + kale3 = (12.66, 0.03986567039, 2.075) + kale4 = (12.66, 0.03986567039, -2.075) + + flash = bs.newnode("light", + attrs={'position':kale1, + 'radius':0.15, + 'color':(1.0,1.0,0.7)}) + + flash = bs.newnode("light", + attrs={'position':kale2, + 'radius':0.15, + 'color':(1.0,1.0,0.7)}) + + flash = bs.newnode("light", + attrs={'position':kale3, + 'radius':0.15, + 'color':(0.7,1.0,1.0)}) + + flash = bs.newnode("light", + attrs={'position':kale4, + 'radius':0.15, + 'color':(0.7,1.0,1.0)}) + #flags positions + def _flagKalesSpawn(self): + for team in self.teams: + if team.id == 0: + _colorTeam0 = team.color + if team.id == 1: + _colorTeam1 = team.color + + self._MythB = FlagKale(position=(-12.45, 0.05744967453, -2.075),color=_colorTeam0) + self._MythB2 =FlagKale(position=(-12.45, 0.05744967453, 2.075),color=_colorTeam0) + self._MythB3 =FlagKale(position=(12.66, 0.03986567039, 2.075),color=_colorTeam1) + self._MythB4 =FlagKale(position=(12.66, 0.03986567039, -2.075),color=_colorTeam1) + + def on_team_join(self, team: Team) -> None: + self._update_scoreboard() + + def _handle_puck_player_collide(self) -> None: + collision = bs.getcollision() + try: + puck = collision.sourcenode.getdelegate(Puck, True) + player = collision.opposingnode.getdelegate(PlayerSpaz, + True).getplayer( + Player, True) + except bs.NotFoundError: + return + + puck.last_players_to_touch[player.team.id] = player + + def _kill_puck(self) -> None: + self._puck = None + + def _handle_score(self) -> None: + """A point has been scored.""" + + assert self._puck is not None + assert self._score_regions is not None + + # Our puck might stick around for a second or two + # we don't want it to be able to score again. + if self._puck.scored: + return + + region = bs.getcollision().sourcenode + index = 0 + for index in range(len(self._score_regions)): + if region == self._score_regions[index].node: + break + + for team in self.teams: + if team.id == index: + scoring_team = team + team.score += 1 + + # tell scored team players to celebrate and give them to boxing gloves + if self._grant_power: + for player in team.players: + try: player.actor.node.handlemessage(bs.PowerupMessage('punch')) + except: pass + + # Tell all players to celebrate. + for player in team.players: + if player.actor: + player.actor.handlemessage(bs.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._puck.last_players_to_touch + and self._puck.last_players_to_touch[scoring_team.id]): + self.stats.player_scored( + self._puck.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() + else: + if self._grant_power: + for player in team.players: + try: player.actor.node.handlemessage(bs.PowerupMessage('shield')) + except: pass + + self._foghorn_sound.play() + self._cheer_sound.play() + + self._puck.scored = True + + # Kill the puck (it'll respawn itself shortly). + bs.timer(1.0, self._kill_puck) + + light = bs.newnode('light', + attrs={ + 'position': bs.getcollision().position, + 'height_attenuated': False, + 'color': (1, 0, 0) + }) + bs.animate(light, 'intensity', {0: 0, 0.5: 1, 1.0: 0}, loop=True) + bs.timer(1.0, light.delete) + + bs.cameraflash(duration=10.0) + self._update_scoreboard() + + def end_game(self) -> None: + results = bs.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, bs.PlayerDiedMessage): + # Augment standard behavior... + super().handlemessage(msg) + self.respawn_player(msg.getplayer(Player)) + + # Respawn dead pucks. + elif isinstance(msg, PuckDiedMessage): + if not self.has_ended(): + bs.timer(3.0, self._spawn_puck) + else: + super().handlemessage(msg) + + def _flash_puck_spawn(self) -> None: + light = bs.newnode('light', + attrs={ + 'position': self._puck_spawn_pos, + 'height_attenuated': False, + 'color': (1, 0, 0) + }) + bs.animate(light, 'intensity', {0.0: 0, 0.25: 1, 0.5: 0}, loop=True) + bs.timer(1.0, light.delete) + + def _spawn_puck(self) -> None: + self._swipsound.play() + self._whistle_sound.play() + self._flagKalesSpawn() + self._flash_puck_spawn() + assert self._puck_spawn_pos is not None + self._puck = Puck(position=self._puck_spawn_pos) + self._puck.light = bs.newnode('light', + owner=self._puck.node, + attrs={'intensity':0.3, + 'height_attenuated':False, + 'radius':0.2, + 'color': (0.9,0.2,0.9)}) + self._puck.node.connectattr('position',self._puck.light,'position') From 27bb489a1fd405deb025f57ff402b95b95e032a8 Mon Sep 17 00:00:00 2001 From: SenjuZoro <69396975+SenjuZoro@users.noreply.github.com> Date: Thu, 27 Jul 2023 12:49:24 +0200 Subject: [PATCH 0634/1464] Update minigames.json --- plugins/minigames.json | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/plugins/minigames.json b/plugins/minigames.json index 8d26d8c7..6fcff11a 100644 --- a/plugins/minigames.json +++ b/plugins/minigames.json @@ -660,6 +660,19 @@ } } }, + "big_ball": { + "description": "Score some goals with Big Ball on Football map", + "external_url": "", + "authors": [ + { + "name": "MythB", + "email": "", + "discord": "" + } + ], + "versions": { + "1.0.0":null + } "handball": { "description": "Score some goals with handball", "external_url": "", @@ -704,4 +717,4 @@ } } } -} \ No newline at end of file +} From 21821c0328fdcc561731f347eb32f72ad5eaee50 Mon Sep 17 00:00:00 2001 From: SenjuZoro Date: Thu, 27 Jul 2023 10:58:18 +0000 Subject: [PATCH 0635/1464] [ci] auto-format --- plugins/minigames/big_ball.py | 171 ++++++++++++++++++---------------- 1 file changed, 89 insertions(+), 82 deletions(-) diff --git a/plugins/minigames/big_ball.py b/plugins/minigames/big_ball.py index ead66152..99767228 100644 --- a/plugins/minigames/big_ball.py +++ b/plugins/minigames/big_ball.py @@ -1,9 +1,5 @@ -#Made by MythB -#Ported by: MysteriousBoi - - - - +# Made by MythB +# Ported by: MysteriousBoi # ba_meta require api 8 @@ -11,7 +7,8 @@ from typing import TYPE_CHECKING import babase import bauiv1 as bui -import bascenev1 as bs,random +import bascenev1 as bs +import random from bascenev1lib.actor.playerspaz import PlayerSpaz from bascenev1lib.actor.scoreboard import Scoreboard from bascenev1lib.actor.powerupbox import PowerupBoxFactory @@ -27,25 +24,27 @@ class PuckDiedMessage: def __init__(self, puck: Puck): self.puck = puck -#goalpost +# goalpost + + class FlagKale(bs.Actor): - def __init__(self,position=(0,2.5,0),color=(1,1,1)): + def __init__(self, position=(0, 2.5, 0), color=(1, 1, 1)): super().__init__() activity = self.getactivity() shared = SharedObjects.get() self.node = bs.newnode('flag', - attrs={'position':(position[0],position[1]+0.75,position[2]), - 'color_texture':activity._flagKaleTex, - 'color':color, - 'materials':[shared.object_material,activity._kaleMaterial], - }, + attrs={'position': (position[0], position[1]+0.75, position[2]), + 'color_texture': activity._flagKaleTex, + 'color': color, + 'materials': [shared.object_material, activity._kaleMaterial], + }, delegate=self) - def handleMessage(self,m): - if isinstance(m,bs.DieMessage): + def handleMessage(self, m): + if isinstance(m, bs.DieMessage): if self.node.exists(): self.node.delete() - elif isinstance(m,bs.OutOfBoundsMessage): + elif isinstance(m, bs.OutOfBoundsMessage): self.handlemessage(bs.DieMessage()) else: super().handlemessage(msg) @@ -76,9 +75,9 @@ def __init__(self, position: Sequence[float] = (0.0, 1.0, 0.0)): 'is_area_of_interest': True, 'position': self._spawn_pos, 'materials': pmats, - 'body_scale': 4, + 'body_scale': 4, 'mesh_scale': 1, - 'density': 0.02}) + 'density': 0.02}) bs.animate(self.node, 'mesh_scale', {0: 0, 0.2: 1.3, 0.26: 1}) def handlemessage(self, msg: Any) -> Any: @@ -114,31 +113,33 @@ def handlemessage(self, msg: Any) -> Any: else: super().handlemessage(msg) -#for night mode: using a actor with large shadow and little mesh scale. Better then tint i think, players and objects more visible +# for night mode: using a actor with large shadow and little mesh scale. Better then tint i think, players and objects more visible + + class NightMod(bs.Actor): - def __init__(self,position=(0,0,0)): + def __init__(self, position=(0, 0, 0)): super().__init__() shared = SharedObjects.get() activity = self.getactivity() # spawn just above the provided point - self._spawnPos = (position[0],position[1],position[2]) + self._spawnPos = (position[0], position[1], position[2]) self.node = bs.newnode("prop", attrs={'mesh': activity._nightModel, 'color_texture': activity._nightTex, - 'body':'sphere', - 'reflection':'soft', + 'body': 'sphere', + 'reflection': 'soft', 'body_scale': 0.1, - 'mesh_scale':0.001, - 'density':0.010, - 'reflection_scale':[0.23], + 'mesh_scale': 0.001, + 'density': 0.010, + 'reflection_scale': [0.23], 'shadow_size': 999999.0, - 'is_area_of_interest':True, - 'position':self._spawnPos, + 'is_area_of_interest': True, + 'position': self._spawnPos, 'materials': [activity._nightMaterial] }, delegate=self) - def handlemssage(self,m): + def handlemssage(self, m): super().handlemessage(m) @@ -218,28 +219,28 @@ def __init__(self, settings: dict): self._nightModel = bs.getmesh("shield") self._nightTex = bs.gettexture("black") self._kaleMaterial = bs.Material() - #add friction to flags for standing our position (as far as) - self._kaleMaterial.add_actions(conditions=("they_have_material",shared.footing_material), - actions=( ("modify_part_collision","friction",9999.5))) - self._kaleMaterial.add_actions(conditions=( ("we_are_younger_than",1),'and', - ("they_have_material",shared.object_material)), - actions=( ("modify_part_collision","collide",False))) - self._kaleMaterial.add_actions(conditions=("they_have_material",shared.pickup_material), - actions=( ("modify_part_collision","collide",False))) + # add friction to flags for standing our position (as far as) + self._kaleMaterial.add_actions(conditions=("they_have_material", shared.footing_material), + actions=(("modify_part_collision", "friction", 9999.5))) + self._kaleMaterial.add_actions(conditions=(("we_are_younger_than", 1), 'and', + ("they_have_material", shared.object_material)), + actions=(("modify_part_collision", "collide", False))) + self._kaleMaterial.add_actions(conditions=("they_have_material", shared.pickup_material), + actions=(("modify_part_collision", "collide", False))) self._kaleMaterial.add_actions( - conditions=('they_have_material',shared.object_material), - actions=(('impact_sound',self._kaleSound,2,5))) - #we dont wanna hit the night so + conditions=('they_have_material', shared.object_material), + actions=(('impact_sound', self._kaleSound, 2, 5))) + # we dont wanna hit the night so self._nightMaterial = bs.Material() - self._nightMaterial.add_actions(conditions=(('they_have_material',shared.pickup_material),'or', - ('they_have_material',shared.attack_material)), - actions=(('modify_part_collision','collide',False))) + self._nightMaterial.add_actions(conditions=(('they_have_material', shared.pickup_material), 'or', + ('they_have_material', shared.attack_material)), + actions=(('modify_part_collision', 'collide', False))) # we also dont want anything moving it self._nightMaterial.add_actions( - conditions=(('they_have_material',shared.object_material),'or', - ('they_dont_have_material',shared.footing_material)), - actions=(('modify_part_collision','collide',False), - ('modify_part_collision','physical',False))) + conditions=(('they_have_material', shared.object_material), 'or', + ('they_dont_have_material', shared.footing_material)), + actions=(('modify_part_collision', 'collide', False), + ('modify_part_collision', 'physical', False))) self.puck_material = bs.Material() self.puck_material.add_actions(actions=(('modify_part_collision', 'friction', 0.5))) @@ -306,8 +307,9 @@ def on_begin(self) -> None: self.setup_standard_powerup_drops() self._puck_spawn_pos = self.map.get_flag_position(None) self._spawn_puck() - #for night mode we need night actor. And same goodies for nigh mode - if self._nm: self._nightSpawny(),self._flagKaleFlash() + # for night mode we need night actor. And same goodies for nigh mode + if self._nm: + self._nightSpawny(), self._flagKaleFlash() # Set up the two score regions. defs = self.map.defs @@ -317,7 +319,7 @@ def on_begin(self) -> None: bs.newnode('region', attrs={ 'position': (13.75, 0.85744967453, 0.1095578275), - 'scale': (1.05,1.1,3.8), + 'scale': (1.05, 1.1, 3.8), 'type': 'box', 'materials': [self._score_region_material] }))) @@ -326,7 +328,7 @@ def on_begin(self) -> None: bs.newnode('region', attrs={ 'position': (-13.55, 0.85744967453, 0.1095578275), - 'scale': (1.05,1.1,3.8), + 'scale': (1.05, 1.1, 3.8), 'type': 'box', 'materials': [self._score_region_material] }))) @@ -336,45 +338,46 @@ def on_begin(self) -> None: def _nightSpawny(self): self.MythBrk = NightMod(position=(0, 0.05744967453, 0)) - #spawn some goodies on nightmode for pretty visuals + # spawn some goodies on nightmode for pretty visuals def _flagKaleFlash(self): - #flags positions + # flags positions kale1 = (-12.45, 0.05744967453, -2.075) kale2 = (-12.45, 0.05744967453, 2.075) kale3 = (12.66, 0.03986567039, 2.075) kale4 = (12.66, 0.03986567039, -2.075) flash = bs.newnode("light", - attrs={'position':kale1, - 'radius':0.15, - 'color':(1.0,1.0,0.7)}) + attrs={'position': kale1, + 'radius': 0.15, + 'color': (1.0, 1.0, 0.7)}) flash = bs.newnode("light", - attrs={'position':kale2, - 'radius':0.15, - 'color':(1.0,1.0,0.7)}) + attrs={'position': kale2, + 'radius': 0.15, + 'color': (1.0, 1.0, 0.7)}) flash = bs.newnode("light", - attrs={'position':kale3, - 'radius':0.15, - 'color':(0.7,1.0,1.0)}) + attrs={'position': kale3, + 'radius': 0.15, + 'color': (0.7, 1.0, 1.0)}) flash = bs.newnode("light", - attrs={'position':kale4, - 'radius':0.15, - 'color':(0.7,1.0,1.0)}) - #flags positions + attrs={'position': kale4, + 'radius': 0.15, + 'color': (0.7, 1.0, 1.0)}) + # flags positions + def _flagKalesSpawn(self): for team in self.teams: if team.id == 0: - _colorTeam0 = team.color + _colorTeam0 = team.color if team.id == 1: - _colorTeam1 = team.color + _colorTeam1 = team.color - self._MythB = FlagKale(position=(-12.45, 0.05744967453, -2.075),color=_colorTeam0) - self._MythB2 =FlagKale(position=(-12.45, 0.05744967453, 2.075),color=_colorTeam0) - self._MythB3 =FlagKale(position=(12.66, 0.03986567039, 2.075),color=_colorTeam1) - self._MythB4 =FlagKale(position=(12.66, 0.03986567039, -2.075),color=_colorTeam1) + self._MythB = FlagKale(position=(-12.45, 0.05744967453, -2.075), color=_colorTeam0) + self._MythB2 = FlagKale(position=(-12.45, 0.05744967453, 2.075), color=_colorTeam0) + self._MythB3 = FlagKale(position=(12.66, 0.03986567039, 2.075), color=_colorTeam1) + self._MythB4 = FlagKale(position=(12.66, 0.03986567039, -2.075), color=_colorTeam1) def on_team_join(self, team: Team) -> None: self._update_scoreboard() @@ -419,8 +422,10 @@ def _handle_score(self) -> None: # tell scored team players to celebrate and give them to boxing gloves if self._grant_power: for player in team.players: - try: player.actor.node.handlemessage(bs.PowerupMessage('punch')) - except: pass + try: + player.actor.node.handlemessage(bs.PowerupMessage('punch')) + except: + pass # Tell all players to celebrate. for player in team.players: @@ -442,8 +447,10 @@ def _handle_score(self) -> None: else: if self._grant_power: for player in team.players: - try: player.actor.node.handlemessage(bs.PowerupMessage('shield')) - except: pass + try: + player.actor.node.handlemessage(bs.PowerupMessage('shield')) + except: + pass self._foghorn_sound.play() self._cheer_sound.play() @@ -510,8 +517,8 @@ def _spawn_puck(self) -> None: self._puck = Puck(position=self._puck_spawn_pos) self._puck.light = bs.newnode('light', owner=self._puck.node, - attrs={'intensity':0.3, - 'height_attenuated':False, - 'radius':0.2, - 'color': (0.9,0.2,0.9)}) - self._puck.node.connectattr('position',self._puck.light,'position') + attrs={'intensity': 0.3, + 'height_attenuated': False, + 'radius': 0.2, + 'color': (0.9, 0.2, 0.9)}) + self._puck.node.connectattr('position', self._puck.light, 'position') From ca3221b0e61ac427546501e0e150c5af7b8d1d69 Mon Sep 17 00:00:00 2001 From: Rikko Date: Thu, 27 Jul 2023 20:28:51 +0530 Subject: [PATCH 0636/1464] Fix JSON struct --- plugins/minigames.json | 1 + 1 file changed, 1 insertion(+) diff --git a/plugins/minigames.json b/plugins/minigames.json index 6fcff11a..6a2f0ef9 100644 --- a/plugins/minigames.json +++ b/plugins/minigames.json @@ -673,6 +673,7 @@ "versions": { "1.0.0":null } + }, "handball": { "description": "Score some goals with handball", "external_url": "", From d3aa170d20580f01dce0e01af505b870f8437d31 Mon Sep 17 00:00:00 2001 From: rikkolovescats Date: Thu, 27 Jul 2023 15:03:13 +0000 Subject: [PATCH 0637/1464] [ci] apply-version-metadata --- plugins/minigames.json | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/plugins/minigames.json b/plugins/minigames.json index 6a2f0ef9..4c0872fe 100644 --- a/plugins/minigames.json +++ b/plugins/minigames.json @@ -671,7 +671,12 @@ } ], "versions": { - "1.0.0":null + "1.0.0": { + "api_version": 8, + "commit_sha": "ca3221b", + "released_on": "27-07-2023", + "md5sum": "39c5b18efd5d5314f30c12fc0bec4931" + } } }, "handball": { @@ -718,4 +723,4 @@ } } } -} +} \ No newline at end of file From 7501794910f95a7b9ffe96f2e8fc69c78be8dad9 Mon Sep 17 00:00:00 2001 From: SenjuZoro <69396975+SenjuZoro@users.noreply.github.com> Date: Thu, 27 Jul 2023 18:31:52 +0200 Subject: [PATCH 0638/1464] Super duel updated New game mode --> super duel --- plugins/minigames/super_duel.py | 598 ++++++++++++++++++++++++++++++++ 1 file changed, 598 insertions(+) create mode 100644 plugins/minigames/super_duel.py diff --git a/plugins/minigames/super_duel.py b/plugins/minigames/super_duel.py new file mode 100644 index 00000000..1610959a --- /dev/null +++ b/plugins/minigames/super_duel.py @@ -0,0 +1,598 @@ +"""New Duel / Created by: byANG3L""" + +# ba_meta require api 8 +# (see https://ballistica.net/wiki/meta-tag-system) + +from __future__ import annotations + +from typing import TYPE_CHECKING + +import babase +import bauiv1 as bui +import bascenev1 as bs +import random +from bascenev1lib.actor.playerspaz import PlayerSpaz +from bascenev1lib.actor.scoreboard import Scoreboard +from bascenev1lib.game.elimination import Icon + +if TYPE_CHECKING: + from typing import Any, Type, List, Dict, Tuple, Union, Sequence, Optional + + +class SuperSpaz(PlayerSpaz): + + def __init__(self, + player: bs.Player, + color: Sequence[float] = (1.0, 1.0, 1.0), + highlight: Sequence[float] = (0.5, 0.5, 0.5), + character: str = 'Spaz', + super_punch: bool = False, + powerups_expire: bool = True): + super().__init__(player=player, + color=color, + highlight=highlight, + character=character, + powerups_expire=powerups_expire) + self._super_punch = super_punch + + def handlemessage(self, msg: Any) -> Any: + from bascenev1lib.actor.spaz import PunchHitMessage + from bascenev1lib.actor.bomb import Blast + if isinstance(msg, PunchHitMessage): + super().handlemessage(msg) + node = bs.getcollision().opposingnode + if self._super_punch: + if node.getnodetype() == 'spaz': + if not node.frozen: + node.frozen = True + node.handlemessage(babase.FreezeMessage()) + bs.getsound('freeze').play() + bs.getsound('superPunch').play() + bs.getsound('punchStrong02').play() + Blast(position=node.position, + velocity=node.velocity, + blast_radius=0.0, + blast_type='normal').autoretain() + else: + return super().handlemessage(msg) + return None + + +class Player(bs.Player['Team']): + """Our player type for this game.""" + def __init__(self) -> None: + self.icons: List[Icon] = [] + self.in_game: bool = False + self.playervs1: bool = False + self.playervs2: bool = False + self.light: bool = False + + +class Team(bs.Team[Player]): + """Our team type for this game.""" + + def __init__(self) -> None: + self.score = 0 + + +lang = bs.app.lang.language +if lang == 'Spanish': + enable_powerups = 'Habilitar Potenciadores' + night_mode = 'Modo Noche' + fight_delay = 'Tiempo entre Pelea' + very_fast = 'Muy Rápido' + fast = 'Rápido' + normal = 'Normal' + slow = 'Lento' + very_slow = 'Muy Lento' + none = 'Ninguno' + super_punch = 'Super Golpe' + box_mode = 'Modo Caja' + boxing_gloves = 'Guantes de Boxeo' +else: + enable_powerups = 'Enable Powerups' + night_mode = 'Night Mode' + fight_delay = 'Fight Delay' + very_fast = 'Very Fast' + fast = 'Fast' + normal = 'Normal' + slow = 'Slow' + very_slow = 'Very Slow' + super_punch = 'Super Punch' + box_mode = 'Box Mode' + boxing_gloves = 'Boxing Gloves' + +# ba_meta export bascenev1.GameActivity +class NewDuelGame(bs.TeamGameActivity[Player, Team]): + """A game type based on acquiring kills.""" + + name = 'Duel' + description = 'Kill a set number of enemies to win.' + + # Print messages when players die since it matters here. + announce_player_deaths = True + + @classmethod + def get_available_settings( + cls, sessiontype: Type[bs.Session]) -> List[babase.Setting]: + settings = [ + bs.IntSetting( + 'Kills to Win Per Player', + min_value=1, + default=5, + increment=1, + ), + bs.IntChoiceSetting( + 'Time Limit', + choices=[ + ('None', 0), + ('1 Minute', 60), + ('2 Minutes', 120), + ('5 Minutes', 300), + ('10 Minutes', 600), + ('20 Minutes', 1200), + ], + default=0, + ), + bs.BoolSetting(enable_powerups, default=False), + bs.BoolSetting(boxing_gloves, default=False), + bs.BoolSetting(night_mode, default=False), + bs.BoolSetting(super_punch, default=False), + bs.BoolSetting(box_mode, default=False), + bs.BoolSetting('Epic Mode', default=False), + bs.BoolSetting('Allow Negative Scores', default=False), + ] + return settings + + @classmethod + def supports_session_type(cls, sessiontype: Type[bs.Session]) -> bool: + return (issubclass(sessiontype, bs.FreeForAllSession)) + + @classmethod + def get_supported_maps(cls, sessiontype: Type[bs.Session]) -> List[str]: + return bs.app.classic.getmaps('melee') + + def __init__(self, settings: dict): + super().__init__(settings) + self._scoreboard = Scoreboard() + self._score_to_win: Optional[int] = None + self._dingsound = bs.getsound('dingSmall') + self._epic_mode = bool(settings['Epic Mode']) + self._kills_to_win_per_player = int( + settings['Kills to Win Per Player']) + self._enable_powerups = bool(settings[enable_powerups]) + self._night_mode = bool(settings[night_mode]) + self._fight_delay: float = 0 + self._time_limit = float(settings['Time Limit']) + self._allow_negative_scores = bool( + settings.get('Allow Negative Scores', False)) + self._super_punch = bool(settings[super_punch]) + self._box_mode = bool(settings[box_mode]) + self._boxing_gloves = bool(settings[boxing_gloves]) + self._vs_text: Optional[bs.Actor] = None + self.spawn_order: List[Player] = [] + self._players_vs_1: bool = False + self._players_vs_2: bool = False + self._first_countdown: bool = True + self._count_1 = bs.getsound('announceOne') + self._count_2 = bs.getsound('announceTwo') + self._count_3 = bs.getsound('announceThree') + self._boxing_bell = bs.getsound('boxingBell') + + # Base class overrides. + self.slow_motion = self._epic_mode + self.default_music = (bs.MusicType.EPIC if self._epic_mode else + bs.MusicType.TO_THE_DEATH) + + def get_instance_description(self) -> Union[str, Sequence]: + return 'Crush ${ARG1} of your enemies.', self._score_to_win + + def get_instance_description_short(self) -> Union[str, Sequence]: + return 'kill ${ARG1} enemies', self._score_to_win + + def on_player_join(self, player: Player) -> None: + self.spawn_order.append(player) + self._update_order() + + def on_player_leave(self, player: Player) -> None: + super().on_player_leave(player) + player.icons = [] + if player.playervs1: + player.playervs1 = False + self._players_vs_1 = False + player.in_game = False + elif player.playervs2: + player.playervs2 = False + self._players_vs_2 = False + player.in_game = False + if player in self.spawn_order: + self.spawn_order.remove(player) + bs.timer(0.2, self._update_order) + + def on_transition_in(self) -> None: + super().on_transition_in() + if self._night_mode: + gnode = bs.getactivity().globalsnode + gnode.tint = (0.3, 0.3, 0.3) + + def on_team_join(self, team: Team) -> None: + if self.has_begun(): + self._update_scoreboard() + + def on_begin(self) -> None: + super().on_begin() + self.setup_standard_time_limit(self._time_limit) + if self._enable_powerups: + self.setup_standard_powerup_drops() + self._vs_text = bs.NodeActor( + bs.newnode('text', + attrs={ + 'position': (0, 105), + 'h_attach': 'center', + 'h_align': 'center', + 'maxwidth': 200, + 'shadow': 0.5, + 'vr_depth': 390, + 'scale': 0.6, + 'v_attach': 'bottom', + 'color': (0.8, 0.8, 0.3, 1.0), + 'text': babase.Lstr(resource='vsText') + })) + + # Base kills needed to win on the size of the largest team. + self._score_to_win = (self._kills_to_win_per_player * + max(1, max(len(t.players) for t in self.teams))) + self._update_scoreboard() + bs.timer(1.0, self._update, repeat=True) + + def _update(self) -> None: + if len(self.players) == 1: + 'self.end_game()' + + + + def spawn_player(self, player: PlayerType) -> bs.Actor: + # pylint: disable=too-many-locals + # pylint: disable=cyclic-import + from babase import _math + from bascenev1._coopsession import CoopSession + from bascenev1lib.actor.spazfactory import SpazFactory + factory = SpazFactory.get() + name = player.getname() + color = player.color + highlight = player.highlight + + light_color = _math.normalized_color(color) + display_color = babase.safecolor(color, target_intensity=0.75) + spaz = SuperSpaz(color=color, + highlight=highlight, + character=player.character, + player=player, + super_punch=True if self._super_punch else False) + + player.actor = spaz + assert spaz.node + + # If this is co-op and we're on Courtyard or Runaround, add the + # material that allows us to collide with the player-walls. + # FIXME: Need to generalize this. + if isinstance(self.session, CoopSession) and self.map.getname() in [ + 'Courtyard', 'Tower D' + ]: + mat = self.map.preloaddata['collide_with_wall_material'] + assert isinstance(spaz.node.materials, tuple) + assert isinstance(spaz.node.roller_materials, tuple) + spaz.node.materials += (mat, ) + spaz.node.roller_materials += (mat, ) + + spaz.node.name = name + spaz.node.name_color = display_color + spaz.connect_controls_to_player() + + self._spawn_sound.play(1, position=spaz.node.position) + light = bs.newnode('light', attrs={'color': light_color}) + spaz.node.connectattr('position', light, 'position') + bs.animate(light, 'intensity', {0: 0, 0.25: 1, 0.5: 0}) + bs.timer(0.5, light.delete) + + pos1 = [self.map.get_start_position(0), 90] + pos2 = [self.map.get_start_position(1), 270] + pos3 = [] + + for x in self.players: + if x.is_alive(): + if x is player: continue + p = x.actor.node.position + if 0.0 not in (p[0], p[2]): + if p[0] <= 0: + pos3.append(pos2[0]) + else: pos3.append(pos1[0]) + + spaz.handlemessage(bs.StandMessage(pos1[0] if player.playervs1 else pos2[0], + pos1[1] if player.playervs1 else pos2[1])) + + if any(pos3): + spaz.handlemessage(bs.StandMessage(pos3[0])) + + if self._super_punch: + spaz._punch_power_scale = factory.punch_power_scale_gloves = 10 + spaz.equip_boxing_gloves() + lfx = bs.newnode( + 'light', + attrs={ + 'color': color, + 'radius': 0.3, + 'intensity': 0.3}) + def sp_fx(): + if not spaz.node: + lfx.delete() + return + bs.emitfx(position=spaz.node.position, + velocity=spaz.node.velocity, + count=5, + scale=0.5, + spread=0.5, + chunk_type='spark') + bs.emitfx(position=spaz.node.position, + velocity=spaz.node.velocity, + count=2, + scale=0.8, + spread=0.3, + chunk_type='spark') + if lfx: + spaz.node.connectattr('position', lfx, 'position') + bs.timer(0.1, sp_fx, repeat=True) + + if self._box_mode: + spaz.node.color_texture = bs.gettexture('tnt') + spaz.node.color_mask_texture = bs.gettexture('tnt') + spaz.node.color = (1, 1, 1) + spaz.node.highlight = (1, 1, 1) + spaz.node.head_mesh = None + spaz.node.torso_mesh = bs.getmesh('tnt') + spaz.node.style = 'cyborg' + + if self._boxing_gloves: + spaz.equip_boxing_gloves() + + return spaz + + def _update_spawn(self) -> None: + if self._players_vs_1 or self._players_vs_2: + for player in self.players: + if player.playervs1 or player.playervs2: + if not player.is_alive(): + self.spawn_player(player) + # player.actor.disconnect_controls_from_player() + + if self._night_mode: + if not player.light: + player.light = True + light = bs.newnode( + 'light', + owner=player.node, + attrs={ + 'radius': 0.3, + 'intensity': 0.6, + 'height_attenuated': False, + 'color': player.color + }) + player.node.connectattr( + 'position', light, 'position') + else: + player.actor.disconnect_controls_from_player() + + bs.timer(0.0, self._countdown) + # bs.timer(0.1, self._clear_all_objects) + + def _countdown(self) -> None: + self._first_countdown = False + if self._fight_delay == 0: + for player in self.players: + if player.playervs1 or player.playervs2: + if not player.is_alive(): + return + else: + player.actor.connect_controls_to_player() + else: + bs.timer(self._fight_delay, self.count3) + + def start(self) -> None: + self._count_text('FIGHT') + self._boxing_bell.play() + for player in self.players: + if player.playervs1 or player.playervs2: + if not player.is_alive(): + return + else: + player.actor.connect_controls_to_player() + + def count(self) -> None: + self._count_text('1') + self._count_1.play() + bs.timer(self._fight_delay, self.start) + + def count2(self) -> None: + self._count_text('2') + self._count_2.play() + bs.timer(self._fight_delay, self.count) + + def count3(self) -> None: + self._count_text('3') + self._count_3.play() + bs.timer(self._fight_delay, self.count2) + + def _count_text(self, num: str) -> None: + self.node = bs.newnode('text', + attrs={ + 'v_attach': 'center', + 'h_attach': 'center', + 'h_align': 'center', + 'color': (1, 1, 0.5, 1), + 'flatness': 0.5, + 'shadow': 0.5, + 'position': (0, 18), + 'text': num + }) + if self._fight_delay == 0.7: + bs.animate(self.node, 'scale', + {0: 0, 0.1: 3.9, 0.64: 4.3, 0.68: 0}) + elif self._fight_delay == 0.4: + bs.animate(self.node, 'scale', + {0: 0, 0.1: 3.9, 0.34: 4.3, 0.38: 0}) + else: + bs.animate(self.node, 'scale', + {0: 0, 0.1: 3.9, 0.92: 4.3, 0.96: 0}) + cmb = bs.newnode('combine', owner=self.node, attrs={'size': 4}) + cmb.connectattr('output', self.node, 'color') + bs.animate(cmb, 'input0', {0: 1.0, 0.15: 1.0}, loop=True) + bs.animate(cmb, 'input1', {0: 1.0, 0.15: 0.5}, loop=True) + bs.animate(cmb, 'input2', {0: 0.1, 0.15: 0.0}, loop=True) + cmb.input3 = 1.0 + bs.timer(self._fight_delay, self.node.delete) + + def _update_order(self) -> None: + for player in self.spawn_order: + assert isinstance(player, Player) + if not player.is_alive(): + if not self._players_vs_1: + self._players_vs_1 = True + player.playervs1 = True + player.in_game = True + self.spawn_order.remove(player) + self._update_spawn() + elif not self._players_vs_2: + self._players_vs_2 = True + player.playervs2 = True + player.in_game = True + self.spawn_order.remove(player) + self._update_spawn() + self._update_icons() + + def _update_icons(self) -> None: + # pylint: disable=too-many-branches + + for player in self.players: + player.icons = [] + + if player.in_game: + if player.playervs1: + xval = -60 + x_offs = -78 + elif player.playervs2: + xval = 60 + x_offs = 78 + player.icons.append( + Icon(player, + position=(xval, 40), + scale=1.0, + name_maxwidth=130, + name_scale=0.8, + flatness=0.0, + shadow=0.5, + show_death=True, + show_lives=False)) + else: + xval = 125 + xval2 = -125 + x_offs = 78 + for player in self.spawn_order: + player.icons.append( + Icon(player, + position=(xval, 25), + scale=0.5, + name_maxwidth=75, + name_scale=1.0, + flatness=1.0, + shadow=1.0, + show_death=False, + show_lives=False)) + xval += x_offs * 0.56 + player.icons.append( + Icon(player, + position=(xval2, 25), + scale=0.5, + name_maxwidth=75, + name_scale=1.0, + flatness=1.0, + shadow=1.0, + show_death=False, + show_lives=False)) + xval2 -= x_offs * 0.56 + + def handlemessage(self, msg: Any) -> Any: + + if isinstance(msg, bs.PlayerDiedMessage): + + # Augment standard behavior. + super().handlemessage(msg) + + player = msg.getplayer(Player) + + if player.playervs1: + player.playervs1 = False + self._players_vs_1 = False + player.in_game = False + self.spawn_order.append(player) + elif player.playervs2: + player.playervs2 = False + self._players_vs_2 = False + player.in_game = False + self.spawn_order.append(player) + bs.timer(0.2, self._update_order) + + killer = msg.getkillerplayer(Player) + if killer is None: + return None + + # Handle team-kills. + if killer.team is player.team: + + # In free-for-all, killing yourself loses you a point. + if isinstance(self.session, bs.FreeForAllSession): + new_score = player.team.score - 1 + if not self._allow_negative_scores: + new_score = max(0, new_score) + player.team.score = new_score + + # In teams-mode it gives a point to the other team. + else: + self._dingsound.play() + for team in self.teams: + if team is not killer.team: + team.score += 1 + + # Killing someone on another team nets a kill. + else: + killer.team.score += 1 + self._dingsound.play() + + # In FFA show scores since its hard to find on the scoreboard. + if isinstance(killer.actor, PlayerSpaz) and killer.actor: + killer.actor.set_score_text(str(killer.team.score) + '/' + + str(self._score_to_win), + color=killer.team.color, + flash=True) + + self._update_scoreboard() + + # If someone has won, set a timer to end shortly. + # (allows the dust to clear and draws to occur if deaths are + # close enough) + assert self._score_to_win is not None + if any(team.score >= self._score_to_win for team in self.teams): + bs.timer(0.5, self.end_game) + else: + return super().handlemessage(msg) + return None + + def _update_scoreboard(self) -> None: + for team in self.teams: + self._scoreboard.set_team_value(team, team.score, + self._score_to_win) + + def end_game(self) -> None: + results = bs.GameResults() + for team in self.teams: + results.set_team_score(team, team.score) + self.end(results=results) \ No newline at end of file From bff7e1c89713ee9d0312bb8a2f03784d690dfda5 Mon Sep 17 00:00:00 2001 From: SenjuZoro <69396975+SenjuZoro@users.noreply.github.com> Date: Thu, 27 Jul 2023 18:34:35 +0200 Subject: [PATCH 0639/1464] Update minigames.json --- plugins/minigames.json | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/plugins/minigames.json b/plugins/minigames.json index 4c0872fe..0df9b41c 100644 --- a/plugins/minigames.json +++ b/plugins/minigames.json @@ -698,6 +698,20 @@ } } }, + "super_duel": { + "description": "Crush your enemy in a 1v1", + "external_url": "https://www.youtube.com/watch?v=hvRtiXR-oC0", + "authors": [ + { + "name": "JoseAng3l", + "email": "", + "discord": "joseang3l" + } + ], + "versions": { + "1.0.0":null + } + }, "supersmash": { "description": "Blow up your enemies off the map!", "external_url": "", @@ -723,4 +737,4 @@ } } } -} \ No newline at end of file +} From ab2678693d679d28ff721473bf3a1c80d487c3ca Mon Sep 17 00:00:00 2001 From: SenjuZoro Date: Thu, 27 Jul 2023 21:28:52 +0000 Subject: [PATCH 0640/1464] [ci] auto-format --- plugins/minigames/super_duel.py | 62 ++++++++++++++++++--------------- 1 file changed, 33 insertions(+), 29 deletions(-) diff --git a/plugins/minigames/super_duel.py b/plugins/minigames/super_duel.py index 1610959a..b6fc2394 100644 --- a/plugins/minigames/super_duel.py +++ b/plugins/minigames/super_duel.py @@ -50,9 +50,9 @@ def handlemessage(self, msg: Any) -> Any: bs.getsound('superPunch').play() bs.getsound('punchStrong02').play() Blast(position=node.position, - velocity=node.velocity, - blast_radius=0.0, - blast_type='normal').autoretain() + velocity=node.velocity, + blast_radius=0.0, + blast_type='normal').autoretain() else: return super().handlemessage(msg) return None @@ -60,6 +60,7 @@ def handlemessage(self, msg: Any) -> Any: class Player(bs.Player['Team']): """Our player type for this game.""" + def __init__(self) -> None: self.icons: List[Icon] = [] self.in_game: bool = False @@ -103,6 +104,8 @@ def __init__(self) -> None: boxing_gloves = 'Boxing Gloves' # ba_meta export bascenev1.GameActivity + + class NewDuelGame(bs.TeamGameActivity[Player, Team]): """A game type based on acquiring kills.""" @@ -225,19 +228,19 @@ def on_begin(self) -> None: if self._enable_powerups: self.setup_standard_powerup_drops() self._vs_text = bs.NodeActor( - bs.newnode('text', - attrs={ - 'position': (0, 105), - 'h_attach': 'center', - 'h_align': 'center', - 'maxwidth': 200, - 'shadow': 0.5, - 'vr_depth': 390, - 'scale': 0.6, - 'v_attach': 'bottom', - 'color': (0.8, 0.8, 0.3, 1.0), - 'text': babase.Lstr(resource='vsText') - })) + bs.newnode('text', + attrs={ + 'position': (0, 105), + 'h_attach': 'center', + 'h_align': 'center', + 'maxwidth': 200, + 'shadow': 0.5, + 'vr_depth': 390, + 'scale': 0.6, + 'v_attach': 'bottom', + 'color': (0.8, 0.8, 0.3, 1.0), + 'text': babase.Lstr(resource='vsText') + })) # Base kills needed to win on the size of the largest team. self._score_to_win = (self._kills_to_win_per_player * @@ -249,8 +252,6 @@ def _update(self) -> None: if len(self.players) == 1: 'self.end_game()' - - def spawn_player(self, player: PlayerType) -> bs.Actor: # pylint: disable=too-many-locals # pylint: disable=cyclic-import @@ -298,18 +299,20 @@ def spawn_player(self, player: PlayerType) -> bs.Actor: pos1 = [self.map.get_start_position(0), 90] pos2 = [self.map.get_start_position(1), 270] pos3 = [] - + for x in self.players: if x.is_alive(): - if x is player: continue + if x is player: + continue p = x.actor.node.position if 0.0 not in (p[0], p[2]): if p[0] <= 0: pos3.append(pos2[0]) - else: pos3.append(pos1[0]) - + else: + pos3.append(pos1[0]) + spaz.handlemessage(bs.StandMessage(pos1[0] if player.playervs1 else pos2[0], - pos1[1] if player.playervs1 else pos2[1])) + pos1[1] if player.playervs1 else pos2[1])) if any(pos3): spaz.handlemessage(bs.StandMessage(pos3[0])) @@ -323,6 +326,7 @@ def spawn_player(self, player: PlayerType) -> bs.Actor: 'color': color, 'radius': 0.3, 'intensity': 0.3}) + def sp_fx(): if not spaz.node: lfx.delete() @@ -364,7 +368,7 @@ def _update_spawn(self) -> None: if not player.is_alive(): self.spawn_player(player) # player.actor.disconnect_controls_from_player() - + if self._night_mode: if not player.light: player.light = True @@ -381,7 +385,7 @@ def _update_spawn(self) -> None: 'position', light, 'position') else: player.actor.disconnect_controls_from_player() - + bs.timer(0.0, self._countdown) # bs.timer(0.1, self._clear_all_objects) @@ -436,13 +440,13 @@ def _count_text(self, num: str) -> None: }) if self._fight_delay == 0.7: bs.animate(self.node, 'scale', - {0: 0, 0.1: 3.9, 0.64: 4.3, 0.68: 0}) + {0: 0, 0.1: 3.9, 0.64: 4.3, 0.68: 0}) elif self._fight_delay == 0.4: bs.animate(self.node, 'scale', - {0: 0, 0.1: 3.9, 0.34: 4.3, 0.38: 0}) + {0: 0, 0.1: 3.9, 0.34: 4.3, 0.38: 0}) else: bs.animate(self.node, 'scale', - {0: 0, 0.1: 3.9, 0.92: 4.3, 0.96: 0}) + {0: 0, 0.1: 3.9, 0.92: 4.3, 0.96: 0}) cmb = bs.newnode('combine', owner=self.node, attrs={'size': 4}) cmb.connectattr('output', self.node, 'color') bs.animate(cmb, 'input0', {0: 1.0, 0.15: 1.0}, loop=True) @@ -595,4 +599,4 @@ def end_game(self) -> None: results = bs.GameResults() for team in self.teams: results.set_team_score(team, team.score) - self.end(results=results) \ No newline at end of file + self.end(results=results) From 4095f4894e70b79f37be60a087c4e8d8e161cd8b Mon Sep 17 00:00:00 2001 From: SenjuZoro Date: Thu, 27 Jul 2023 21:28:53 +0000 Subject: [PATCH 0641/1464] [ci] apply-version-metadata --- plugins/minigames.json | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/plugins/minigames.json b/plugins/minigames.json index 0df9b41c..b76c9015 100644 --- a/plugins/minigames.json +++ b/plugins/minigames.json @@ -709,7 +709,12 @@ } ], "versions": { - "1.0.0":null + "1.0.0": { + "api_version": 8, + "commit_sha": "ab26786", + "released_on": "27-07-2023", + "md5sum": "d0c9c0472d7b145eadf535957a462fdf" + } } }, "supersmash": { @@ -737,4 +742,4 @@ } } } -} +} \ No newline at end of file From 5ea6a94de02396dd729a73a172e26620e5514e48 Mon Sep 17 00:00:00 2001 From: SenjuZoro <69396975+SenjuZoro@users.noreply.github.com> Date: Fri, 28 Jul 2023 00:45:23 +0200 Subject: [PATCH 0642/1464] demolition war minigame updated updated to api 8 idk if i did it correctly in line 224 --- plugins/minigames/demolition_war.py | 121 ++++++++++++++-------------- 1 file changed, 62 insertions(+), 59 deletions(-) diff --git a/plugins/minigames/demolition_war.py b/plugins/minigames/demolition_war.py index 1c264336..87ffc115 100644 --- a/plugins/minigames/demolition_war.py +++ b/plugins/minigames/demolition_war.py @@ -1,5 +1,5 @@ -# ba_meta require api 7 +# ba_meta require api 8 """ DemolitionWar - BombFight on wooden floor flying in air. Author: Mr.Smoothy @@ -12,23 +12,26 @@ from typing import TYPE_CHECKING -import ba -from bastd.game.elimination import EliminationGame, Player -from bastd.gameutils import SharedObjects -from bastd.actor.bomb import BombFactory +import babase +import bauiv1 as bui +import bascenev1 as bs +from bascenev1 import _map +from bascenev1lib.game.elimination import EliminationGame, Player +from bascenev1lib.gameutils import SharedObjects +from bascenev1lib.actor.bomb import BombFactory import random -from bastd.actor.playerspaz import PlayerSpaz +from bascenev1lib.actor.playerspaz import PlayerSpaz if TYPE_CHECKING: from typing import Any, Sequence -# ba_meta export game +# ba_meta export bascenev1.GameActivity class DemolitionWar(EliminationGame): name = 'DemolitionWar' description = 'Last remaining alive wins.' - scoreconfig = ba.ScoreConfig( - label='Survived', scoretype=ba.ScoreType.SECONDS, none_is_winner=True + scoreconfig = bs.ScoreConfig( + label='Survived', scoretype=bs.ScoreType.SECONDS, none_is_winner=True ) # Show messages when players die since it's meaningful here. announce_player_deaths = True @@ -37,17 +40,17 @@ class DemolitionWar(EliminationGame): @classmethod def get_available_settings( - cls, sessiontype: type[ba.Session] - ) -> list[ba.Setting]: + cls, sessiontype: type[bs.Session] + ) -> list[babase.Setting]: settings = [ - ba.IntSetting( + bs.IntSetting( 'Lives Per Player', default=1, min_value=1, max_value=10, increment=1, ), - ba.IntChoiceSetting( + bs.IntChoiceSetting( 'Time Limit', choices=[ ('None', 0), @@ -59,7 +62,7 @@ def get_available_settings( ], default=0, ), - ba.FloatChoiceSetting( + bs.FloatChoiceSetting( 'Respawn Times', choices=[ ('Shorter', 0.25), @@ -70,23 +73,23 @@ def get_available_settings( ], default=1.0, ), - ba.BoolSetting('Epic Mode', default=False), + bs.BoolSetting('Epic Mode', default=False), ] - if issubclass(sessiontype, ba.DualTeamSession): - settings.append(ba.BoolSetting('Solo Mode', default=False)) + if issubclass(sessiontype, bs.DualTeamSession): + settings.append(bs.BoolSetting('Solo Mode', default=False)) settings.append( - ba.BoolSetting('Balance Total Lives', default=False) + bs.BoolSetting('Balance Total Lives', default=False) ) return settings @classmethod - def supports_session_type(cls, sessiontype: type[ba.Session]) -> bool: - return issubclass(sessiontype, ba.DualTeamSession) or issubclass( - sessiontype, ba.FreeForAllSession + def supports_session_type(cls, sessiontype: type[bs.Session]) -> bool: + return issubclass(sessiontype, bs.DualTeamSession) or issubclass( + sessiontype, bs.FreeForAllSession ) @classmethod - def get_supported_maps(cls, sessiontype: type[ba.Session]) -> list[str]: + def get_supported_maps(cls, sessiontype: type[bs.Session]) -> list[str]: return ['Wooden Floor'] def __init__(self, settings: dict): @@ -95,7 +98,7 @@ def __init__(self, settings: dict): self._solo_mode = False self._balance_total_lives = False - def spawn_player(self, player: Player) -> ba.Actor: + def spawn_player(self, player: Player) -> bs.Actor: p = [-6, -4.3, -2.6, -0.9, 0.8, 2.5, 4.2, 5.9] q = [-4, -2.3, -0.6, 1.1, 2.8, 4.5] @@ -118,23 +121,23 @@ def on_begin(self) -> None: self.map_extend() def on_blast(self): - node = ba.getcollision().sourcenode - ba.emitfx((node.position[0], 0.9, node.position[2]), + node = bs.getcollision().sourcenode + bs.emitfx((node.position[0], 0.9, node.position[2]), (0, 2, 0), 30, 1, spread=1, chunk_type='splinter') - ba.timer(0.1, ba.Call(node.delete)) + bs.timer(0.1, babase.Call(node.delete)) def map_extend(self): # TODO need to improve here , so we can increase size of map easily with settings p = [-6, -4.3, -2.6, -0.9, 0.8, 2.5, 4.2, 5.9] q = [-4, -2.3, -0.6, 1.1, 2.8, 4.5] factory = BombFactory.get() - self.ramp_bomb = ba.Material() + self.ramp_bomb = bs.Material() self.ramp_bomb.add_actions( conditions=('they_have_material', factory.bomb_material), actions=( ('modify_part_collision', 'collide', True), ('modify_part_collision', 'physical', True), - ('call', 'at_connect', ba.Call(self.on_blast)) + ('call', 'at_connect', babase.Call(self.on_blast)) )) self.ramps = [] for i in p: @@ -144,7 +147,7 @@ def map_extend(self): def create_ramp(self, x, z): shared = SharedObjects.get() - self._real_collied_material = ba.Material() + self._real_collied_material = bs.Material() self._real_collied_material.add_actions( actions=( @@ -152,32 +155,32 @@ def create_ramp(self, x, z): ('modify_part_collision', 'physical', True) )) - self.mat = ba.Material() + self.mat = bs.Material() self.mat.add_actions( actions=(('modify_part_collision', 'physical', False), ('modify_part_collision', 'collide', False)) ) pos = (x, 0, z) - ud_1_r = ba.newnode('region', attrs={'position': pos, 'scale': (1.5, 1, 1.5), 'type': 'box', 'materials': [ + ud_1_r = bs.newnode('region', attrs={'position': pos, 'scale': (1.5, 1, 1.5), 'type': 'box', 'materials': [ shared.footing_material, self._real_collied_material, self.ramp_bomb]}) - node = ba.newnode('prop', + node = bs.newnode('prop', owner=ud_1_r, attrs={ - 'model': ba.getmodel('image1x1'), - 'light_model': ba.getmodel('powerupSimple'), + 'mesh': bs.getmesh('image1x1'), + 'light_mesh': bs.getmesh('powerupSimple'), 'position': (2, 7, 2), 'body': 'puck', 'shadow_size': 0.0, 'velocity': (0, 0, 0), - 'color_texture': ba.gettexture('tnt'), - 'model_scale': 1.5, + 'color_texture': bs.gettexture('tnt'), + 'mesh_scale': 1.5, 'reflection_scale': [1.5], 'materials': [self.mat, shared.object_material, shared.footing_material], 'density': 9000000000 }) - node.changerotation(1, 0, 0) - mnode = ba.newnode('math', + # node.changerotation(1, 0, 0) + mnode = bs.newnode('math', owner=ud_1_r, attrs={ 'input1': (0, 0.6, 0), @@ -218,7 +221,7 @@ class mapdefs: points['tnt1'] = (-0.08421587483, 0.9515026107, -0.7762602271) -class WoodenFloor(ba.Map): +class WoodenFloor(bs._map.Map): #ahdunno if this is correct way, change if u find better way """Stadium map for football games.""" defs = mapdefs defs.points['spawn1'] = (-12.03866341, 0.02275111462, 0.0) + (0.5, 1.0, 4.0) @@ -238,15 +241,15 @@ def get_preview_texture_name(cls) -> str: def on_preload(cls) -> Any: data: dict[str, Any] = { - 'model_bg': ba.getmodel('doomShroomBG'), - 'bg_vr_fill_model': ba.getmodel('natureBackgroundVRFill'), - 'collide_model': ba.getcollidemodel('bridgitLevelCollide'), - 'tex': ba.gettexture('bridgitLevelColor'), - 'model_bg_tex': ba.gettexture('doomShroomBGColor'), - 'collide_bg': ba.getcollidemodel('natureBackgroundCollide'), - 'railing_collide_model': - (ba.getcollidemodel('bridgitLevelRailingCollide')), - 'bg_material': ba.Material() + 'mesh_bg': bs.getmesh('doomShroomBG'), + 'bg_vr_fill_mesh': bs.getmesh('natureBackgroundVRFill'), + 'collide_mesh': bs.getcollisionmesh('bridgitLevelCollide'), + 'tex': bs.gettexture('bridgitLevelColor'), + 'mesh_bg_tex': bs.gettexture('doomShroomBGColor'), + 'collide_bg': bs.getcollisionmesh('natureBackgroundCollide'), + 'railing_collide_mesh': + (bs.getcollisionmesh('bridgitLevelRailingCollide')), + 'bg_material': bs.Material() } data['bg_material'].add_actions(actions=('modify_part_collision', 'friction', 10.0)) @@ -255,23 +258,23 @@ def on_preload(cls) -> Any: def __init__(self) -> None: super().__init__() shared = SharedObjects.get() - self.background = ba.newnode( + self.background = bs.newnode( 'terrain', attrs={ - 'model': self.preloaddata['model_bg'], + 'mesh': self.preloaddata['mesh_bg'], 'lighting': False, 'background': True, - 'color_texture': self.preloaddata['model_bg_tex'] + 'color_texture': self.preloaddata['mesh_bg_tex'] }) - self.vr = ba.newnode('terrain', + self.vr = bs.newnode('terrain', attrs={ - 'model': self.preloaddata['bg_vr_fill_model'], + 'mesh': self.preloaddata['bg_vr_fill_mesh'], 'lighting': False, 'vr_only': True, 'background': True, - 'color_texture': self.preloaddata['model_bg_tex'] + 'color_texture': self.preloaddata['mesh_bg_tex'] }) - gnode = ba.getactivity().globalsnode + gnode = bs.getactivity().globalsnode gnode.tint = (1.3, 1.2, 1.0) gnode.ambient_color = (1.3, 1.2, 1.0) gnode.vignette_outer = (0.57, 0.57, 0.57) @@ -280,7 +283,7 @@ def __init__(self) -> None: gnode.vr_near_clip = 0.5 def is_point_near_edge(self, - point: ba.Vec3, + point: babase.Vec3, running: bool = False) -> bool: box_position = self.defs.boxes['edge_box'][0:3] box_scale = self.defs.boxes['edge_box'][6:9] @@ -290,15 +293,15 @@ def is_point_near_edge(self, def _handle_player_collide(self): try: - player = ba.getcollision().opposingnode.getdelegate( + player = bs.getcollision().opposingnode.getdelegate( PlayerSpaz, True) - except ba.NotFoundError: + except bs.NotFoundError: return if player.is_alive(): player.shatter(True) try: - ba._map.register_map(WoodenFloor) + bs._map.register_map(WoodenFloor) except: pass From 9a351a3263253426b7e4fe2a6ac71ed03933963f Mon Sep 17 00:00:00 2001 From: SenjuZoro Date: Thu, 27 Jul 2023 22:45:52 +0000 Subject: [PATCH 0643/1464] [ci] auto-format --- plugins/minigames/demolition_war.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/plugins/minigames/demolition_war.py b/plugins/minigames/demolition_war.py index 87ffc115..abafe06d 100644 --- a/plugins/minigames/demolition_war.py +++ b/plugins/minigames/demolition_war.py @@ -15,7 +15,7 @@ import babase import bauiv1 as bui import bascenev1 as bs -from bascenev1 import _map +from bascenev1 import _map from bascenev1lib.game.elimination import EliminationGame, Player from bascenev1lib.gameutils import SharedObjects from bascenev1lib.actor.bomb import BombFactory @@ -221,7 +221,7 @@ class mapdefs: points['tnt1'] = (-0.08421587483, 0.9515026107, -0.7762602271) -class WoodenFloor(bs._map.Map): #ahdunno if this is correct way, change if u find better way +class WoodenFloor(bs._map.Map): # ahdunno if this is correct way, change if u find better way """Stadium map for football games.""" defs = mapdefs defs.points['spawn1'] = (-12.03866341, 0.02275111462, 0.0) + (0.5, 1.0, 4.0) From f54c993c5b02ed71b9b4e51248f002c85074121a Mon Sep 17 00:00:00 2001 From: SenjuZoro <69396975+SenjuZoro@users.noreply.github.com> Date: Fri, 28 Jul 2023 00:48:37 +0200 Subject: [PATCH 0644/1464] Update minigames.json --- plugins/minigames.json | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/plugins/minigames.json b/plugins/minigames.json index b76c9015..a30f4334 100644 --- a/plugins/minigames.json +++ b/plugins/minigames.json @@ -328,6 +328,7 @@ } ], "versions": { + "2.0.0":null, "1.0.0": { "api_version": 7, "commit_sha": "2aa1e50", @@ -742,4 +743,4 @@ } } } -} \ No newline at end of file +} From 82cba4aae7b5ad63f6ace210256920187fa47675 Mon Sep 17 00:00:00 2001 From: SenjuZoro Date: Thu, 27 Jul 2023 22:49:04 +0000 Subject: [PATCH 0645/1464] [ci] apply-version-metadata --- plugins/minigames.json | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/plugins/minigames.json b/plugins/minigames.json index a30f4334..66a58ee3 100644 --- a/plugins/minigames.json +++ b/plugins/minigames.json @@ -328,7 +328,12 @@ } ], "versions": { - "2.0.0":null, + "2.0.0": { + "api_version": 8, + "commit_sha": "f54c993", + "released_on": "27-07-2023", + "md5sum": "7699483f4c379db809676ac917943d3c" + }, "1.0.0": { "api_version": 7, "commit_sha": "2aa1e50", @@ -743,4 +748,4 @@ } } } -} +} \ No newline at end of file From cd29dacf98ffc1a36c1296410e4079bda30fff32 Mon Sep 17 00:00:00 2001 From: ! Freaku <92618708+Freaku17@users.noreply.github.com> Date: Fri, 28 Jul 2023 17:02:59 +0530 Subject: [PATCH 0646/1464] Update/Add my gamemodes for 1.7.20+ (API 8) --- plugins/minigames/arms_race.py | 29 +- plugins/minigames/frozen_one.py | 18 + plugins/minigames/icy_emits.py | 46 ++ plugins/minigames/memory_game.py | 841 ++++++++++++++--------------- plugins/minigames/musical_flags.py | 257 +++++---- plugins/minigames/volleyball.py | 490 +++++++++-------- 6 files changed, 899 insertions(+), 782 deletions(-) create mode 100644 plugins/minigames/frozen_one.py create mode 100644 plugins/minigames/icy_emits.py diff --git a/plugins/minigames/arms_race.py b/plugins/minigames/arms_race.py index 6f7351ba..7710c2ae 100644 --- a/plugins/minigames/arms_race.py +++ b/plugins/minigames/arms_race.py @@ -1,9 +1,10 @@ -# Ported by: Freaku / @[Just] Freak#4999 +# Ported by your friend: Freaku -# Join BCS: +#Join BCS: # https://discord.gg/ucyaesh + # ba_meta require api 8 from __future__ import annotations @@ -11,7 +12,6 @@ from typing import TYPE_CHECKING import babase -import bauiv1 as bui import bascenev1 as bs from bascenev1lib.actor.playerspaz import PlayerSpaz @@ -19,6 +19,7 @@ from typing import Any, Type, List, Dict, Tuple, Union, Sequence, Optional + class State: def __init__(self, bomb=None, grab=False, punch=False, curse=False, required=False, final=False, name=''): self.bomb = bomb @@ -35,8 +36,8 @@ def __init__(self, bomb=None, grab=False, punch=False, curse=False, required=Fal def apply(self, spaz): spaz.disconnect_controls_from_player() spaz.connect_controls_to_player(enable_punch=self.punch, - enable_bomb=self.bomb, - enable_pickup=self.grab) + enable_bomb=self.bomb, + enable_pickup=self.grab) if self.curse: spaz.curse_time = -1 spaz.curse() @@ -48,18 +49,16 @@ def get_setting(self): return (self.name) -states = [State(bomb='normal', name='Basic Bombs'), - State(bomb='ice', name='Frozen Bombs'), - State(bomb='sticky', name='Sticky Bombs'), - State(bomb='impact', name='Impact Bombs'), - State(grab=True, name='Grabbing only'), - State(punch=True, name='Punching only'), - State(curse=True, name='Cursed', final=True)] - +states = [ State(bomb='normal', name='Basic Bombs'), + State(bomb='ice', name='Frozen Bombs'), + State(bomb='sticky', name='Sticky Bombs'), + State(bomb='impact', name='Impact Bombs'), + State(grab=True, name='Grabbing only'), + State(punch=True, name='Punching only'), + State(curse=True, name='Cursed', final=True) ] class Player(bs.Player['Team']): """Our player type for this game.""" - def __init__(self): self.state = None @@ -193,4 +192,4 @@ def end_game(self) -> None: results = bs.GameResults() for team in self.teams: results.set_team_score(team, team.score) - self.end(results=results) + self.end(results=results) \ No newline at end of file diff --git a/plugins/minigames/frozen_one.py b/plugins/minigames/frozen_one.py new file mode 100644 index 00000000..7bfbe655 --- /dev/null +++ b/plugins/minigames/frozen_one.py @@ -0,0 +1,18 @@ +# Ported by your friend: Freaku + + +import babase +import bascenev1 as bs +from bascenev1lib.game.chosenone import Player, ChosenOneGame + + +# ba_meta require api 8 +# ba_meta export bascenev1.GameActivity +class FrozenOneGame(ChosenOneGame): + name = 'Frozen One' + + def _set_chosen_one_player(self, player: Player) -> None: + super()._set_chosen_one_player(player) + if hasattr(player, 'actor'): + player.actor.frozen = True + player.actor.node.frozen = 1 \ No newline at end of file diff --git a/plugins/minigames/icy_emits.py b/plugins/minigames/icy_emits.py new file mode 100644 index 00000000..50a883cf --- /dev/null +++ b/plugins/minigames/icy_emits.py @@ -0,0 +1,46 @@ +# Made by your friend: Freaku + + +import babase +import bascenev1 as bs, random +from bascenev1lib.actor.bomb import Bomb +from bascenev1lib.game.meteorshower import Player, MeteorShowerGame + + +# ba_meta require api 8 +# ba_meta export bascenev1.GameActivity +class IcyEmitsGame(MeteorShowerGame): + name = 'Icy Emits' + + @classmethod + def get_supported_maps(cls, sessiontype): + return ['Lake Frigid','Hockey Stadium'] + + def _drop_bomb_cluster(self) -> None: + delay = 0.0 + for _i in range(random.randrange(1, 3)): + # Drop them somewhere within our bounds with velocity pointing + # toward the opposite side. + pos = (-7.3 + 15.3 * random.random(), 5.3, + -5.5 + 2.1 * random.random()) + dropdir = (-1.0 if pos[0] > 0 else 1.0) + vel = (0,10,0) + bs.timer(delay, babase.Call(self._drop_bomb, pos, vel)) + delay += 0.1 + self._set_meteor_timer() + + def _drop_bomb(self, position, velocity): + random_xpositions = [-10,-9,-8,-7,-6,-5,-4,-3,-2,-1,0,1,2,3,4,5,6,7,8,9,10] + random_zpositions = [-5,-4.5,-4,-3.5,-3,-2.5,-2,-1.5,-1,-0.5,0,0.5,1,1.5,2,2.5,3,3.5,4,4.5,5] + bomb_position = (random.choice(random_xpositions), 0.2,random.choice(random_zpositions)) + Bomb(position=bomb_position, velocity=velocity, bomb_type = 'ice').autoretain() + + + + +# ba_meta export plugin +class byFreaku(babase.Plugin): + def __init__(self): + ## Campaign support ## + randomPic = ['lakeFrigidPreview','hockeyStadiumPreview'] + babase.app.classic.add_coop_practice_level(bs.Level(name='Icy Emits', displayname='${GAME}', gametype=IcyEmitsGame, settings={}, preview_texture_name=random.choice(randomPic))) \ No newline at end of file diff --git a/plugins/minigames/memory_game.py b/plugins/minigames/memory_game.py index c5c0204a..a433eec7 100644 --- a/plugins/minigames/memory_game.py +++ b/plugins/minigames/memory_game.py @@ -2,7 +2,7 @@ ## Original creator: byANG3L ## -## Made by: Freaku / @[Just] Freak#4999 ## +## Made by: Freaku ## ## From: BSWorld Modpack (https://youtu.be/1TN56NLlShE) ## @@ -12,77 +12,70 @@ # (& some improvements) + + + + # incase someone is wondering how is map floating. Check out # def spawnAllMap(self) -# ba_meta require api 7 + +# ba_meta require api 8 from typing import TYPE_CHECKING, overload -import _ba -import ba -import random -from bastd.gameutils import SharedObjects +import _babase, babase, random +import bascenev1 as bs +from bascenev1lib.gameutils import SharedObjects if TYPE_CHECKING: from typing import Any, Sequence, Optional, List, Dict, Type, Union, Any, Literal -class OnTimer(ba.Actor): - """Timer which counts but doesn't show on-screen""" + +class OnTimer(bs.Actor): + """Timer which counts but doesn't show on-screen""" def __init__(self) -> None: super().__init__() - self._starttime_ms: Optional[int] = None - self.node = ba.newnode('text', attrs={'v_attach': 'top', 'h_attach': 'center', 'h_align': 'center', 'color': ( - 1, 1, 0.5, 1), 'flatness': 0.5, 'shadow': 0.5, 'position': (0, -70), 'scale': 0, 'text': ''}) - self.inputnode = ba.newnode('timedisplay', attrs={ - 'timemin': 0, 'showsubseconds': True}) + self._starttime_ms: int | None = None + self.node = bs.newnode('text', attrs={ 'v_attach': 'top', 'h_attach': 'center', 'h_align': 'center', 'color': (1, 1, 0.5, 1), 'flatness': 0.5, 'shadow': 0.5, 'position': (0, -70), 'scale': 0, 'text': ''}) + self.inputnode = bs.newnode( + 'timedisplay', attrs={'timemin': 0, 'showsubseconds': True} + ) self.inputnode.connectattr('output', self.node, 'text') def start(self) -> None: - tval = ba.time(timeformat=ba.TimeFormat.MILLISECONDS) + """Start the timer.""" + tval = int(bs.time() * 1000.0) assert isinstance(tval, int) self._starttime_ms = tval self.inputnode.time1 = self._starttime_ms - ba.getactivity().globalsnode.connectattr('time', self.inputnode, 'time2') + bs.getactivity().globalsnode.connectattr( + 'time', self.inputnode, 'time2' + ) def has_started(self) -> bool: + """Return whether this timer has started yet.""" return self._starttime_ms is not None - def stop(self, - endtime: Union[int, float] = None, - timeformat: ba.TimeFormat = ba.TimeFormat.SECONDS) -> None: + def stop(self, endtime: int | float | None = None) -> None: + """End the timer. + + If 'endtime' is not None, it is used when calculating + the final display time; otherwise the current time is used. + """ if endtime is None: - endtime = ba.time(timeformat=ba.TimeFormat.MILLISECONDS) - timeformat = ba.TimeFormat.MILLISECONDS + endtime = bs.time() + if self._starttime_ms is None: - print('Warning: OnTimer.stop() called without start() first') + logging.warning( + 'OnScreenTimer.stop() called without first calling start()' + ) else: - endtime_ms: int - if timeformat is ba.TimeFormat.SECONDS: - endtime_ms = int(endtime * 1000) - elif timeformat is ba.TimeFormat.MILLISECONDS: - assert isinstance(endtime, int) - endtime_ms = endtime - else: - raise ValueError(f'invalid timeformat: {timeformat}') - + endtime_ms = int(endtime * 1000) self.inputnode.timemax = endtime_ms - self._starttime_ms - # Overloads so type checker knows our exact return type based in args. - - @overload - def getstarttime(self, timeformat: Literal[ba.TimeFormat.SECONDS] = ba.TimeFormat.SECONDS) -> float: - ... - @overload - def getstarttime(self, - timeformat: Literal[ba.TimeFormat.MILLISECONDS]) -> int: - ... - - def getstarttime( - self, - timeformat: ba.TimeFormat = ba.TimeFormat.SECONDS - ) -> Union[int, float]: - """Return the sim-time when start() was called. + def getstarttime(self) -> float: + """Return the scene-time when start() was called. Time will be returned in seconds if timeformat is SECONDS or milliseconds if it is MILLISECONDS. @@ -90,15 +83,11 @@ def getstarttime( val_ms: Any if self._starttime_ms is None: print('WARNING: getstarttime() called on un-started timer') - val_ms = ba.time(timeformat=ba.TimeFormat.MILLISECONDS) + val_ms = int(bs.time() * 1000.0) else: val_ms = self._starttime_ms assert isinstance(val_ms, int) - if timeformat is ba.TimeFormat.SECONDS: - return 0.001 * val_ms - if timeformat is ba.TimeFormat.MILLISECONDS: - return val_ms - raise ValueError(f'invalid timeformat: {timeformat}') + return 0.001 * val_ms @property def starttime(self) -> float: @@ -107,12 +96,14 @@ def starttime(self) -> float: def handlemessage(self, msg: Any) -> Any: # if we're asked to die, just kill our node/timer - if isinstance(msg, ba.DieMessage): + if isinstance(msg, bs.DieMessage): if self.node: self.node.delete() -class Player(ba.Player['Team']): + + +class Player(bs.Player['Team']): """Our player type for this game.""" def __init__(self) -> None: @@ -120,33 +111,32 @@ def __init__(self) -> None: self.death_time: Optional[float] = None -class Team(ba.Team[Player]): +class Team(bs.Team[Player]): """Our team type for this game.""" -# ba_meta export game -class MGgame(ba.TeamGameActivity[Player, Team]): +# ba_meta export bascenev1.GameActivity +class MGgame(bs.TeamGameActivity[Player, Team]): name = 'Memory Game' description = 'Memories tiles and survive till the end!' - available_settings = [ba.BoolSetting( - 'Epic Mode', default=False), ba.BoolSetting('Enable Bottom Credits', True)] - scoreconfig = ba.ScoreConfig(label='Survived', scoretype=ba.ScoreType.MILLISECONDS, version='B') + available_settings = [bs.BoolSetting('Epic Mode', default=False), bs.BoolSetting('Enable Bottom Credits', True)] + scoreconfig = bs.ScoreConfig(label='Survived', scoretype=bs.ScoreType.MILLISECONDS, version='B') # Print messages when players die (since its meaningful in this game). announce_player_deaths = True # we're currently hard-coded for one map.. @classmethod - def get_supported_maps(cls, sessiontype: Type[ba.Session]) -> List[str]: + def get_supported_maps(cls, sessiontype: Type[bs.Session]) -> List[str]: return ['Sky Tiles'] # We support teams, free-for-all, and co-op sessions. @classmethod - def supports_session_type(cls, sessiontype: Type[ba.Session]) -> bool: - return (issubclass(sessiontype, ba.DualTeamSession) - or issubclass(sessiontype, ba.FreeForAllSession) - or issubclass(sessiontype, ba.CoopSession)) + def supports_session_type(cls, sessiontype: Type[bs.Session]) -> bool: + return (issubclass(sessiontype, bs.DualTeamSession) + or issubclass(sessiontype, bs.FreeForAllSession) + or issubclass(sessiontype, babase.CoopSession)) def __init__(self, settings: dict): super().__init__(settings) @@ -157,14 +147,14 @@ def __init__(self, settings: dict): self.credit_text = bool(settings['Enable Bottom Credits']) # Some base class overrides: - self.default_music = (ba.MusicType.EPIC - if self._epic_mode else ba.MusicType.SURVIVAL) + self.default_music = (bs.MusicType.EPIC + if self._epic_mode else bs.MusicType.SURVIVAL) if self._epic_mode: self.slow_motion = True shared = SharedObjects.get() - self._collide_with_player = ba.Material() + self._collide_with_player=bs.Material() self._collide_with_player.add_actions(actions=(('modify_part_collision', 'collide', True))) - self.dont_collide = ba.Material() + self.dont_collide=bs.Material() self.dont_collide.add_actions(actions=(('modify_part_collision', 'collide', False))) self._levelStage = 0 @@ -172,100 +162,101 @@ def __init__(self, settings: dict): self._lastPlayerDeathTime = None self._spawnCenter = (-3.17358, 2.75764, -2.99124) - self._mapFGPModel = ba.getmodel('buttonSquareOpaque') - self._mapFGPDefaultTex = ba.gettexture('achievementOffYouGo') - - self._mapFGCurseTex = ba.gettexture('powerupCurse') - self._mapFGHealthTex = ba.gettexture('powerupHealth') - self._mapFGIceTex = ba.gettexture('powerupIceBombs') - self._mapFGImpactTex = ba.gettexture('powerupImpactBombs') - self._mapFGMinesTex = ba.gettexture('powerupLandMines') - self._mapFGPunchTex = ba.gettexture('powerupPunch') - self._mapFGShieldTex = ba.gettexture('powerupShield') - self._mapFGStickyTex = ba.gettexture('powerupStickyBombs') - - self._mapFGSpaz = ba.gettexture('neoSpazIcon') - self._mapFGZoe = ba.gettexture('zoeIcon') - self._mapFGSnake = ba.gettexture('ninjaIcon') - self._mapFGKronk = ba.gettexture('kronkIcon') - self._mapFGMel = ba.gettexture('melIcon') - self._mapFGJack = ba.gettexture('jackIcon') - self._mapFGSanta = ba.gettexture('santaIcon') - self._mapFGFrosty = ba.gettexture('frostyIcon') - self._mapFGBones = ba.gettexture('bonesIcon') - self._mapFGBernard = ba.gettexture('bearIcon') - self._mapFGPascal = ba.gettexture('penguinIcon') - self._mapFGAli = ba.gettexture('aliIcon') - self._mapFGRobot = ba.gettexture('cyborgIcon') - self._mapFGAgent = ba.gettexture('agentIcon') - self._mapFGGrumbledorf = ba.gettexture('wizardIcon') - self._mapFGPixel = ba.gettexture('pixieIcon') - - self._imageTextDefault = ba.gettexture('bg') - self._circleTex = ba.gettexture('circleShadow') - - self._image = ba.newnode('image', - attrs={'texture': self._imageTextDefault, - 'position': (0, -100), - 'scale': (100, 100), - 'opacity': 0.0, - 'attach': 'topCenter'}) - - self._textCounter = ba.newnode('text', - attrs={'text': '10', - 'position': (0, -100), - 'scale': 2.3, - 'shadow': 1.0, - 'flatness': 1.0, - 'opacity': 0.0, - 'v_attach': 'top', - 'h_attach': 'center', - 'h_align': 'center', - 'v_align': 'center'}) - - self._textLevel = ba.newnode('text', - attrs={'text': 'Level ' + str(self._levelStage), - 'position': (0, -28), - 'scale': 1.3, - 'shadow': 1.0, - 'flatness': 1.0, - 'color': (1.0, 0.0, 1.0), - 'opacity': 0.0, - 'v_attach': 'top', - 'h_attach': 'center', - 'h_align': 'center', - 'v_align': 'center'}) - - self._imageCircle = ba.newnode('image', - attrs={'texture': self._circleTex, - 'position': (75, -75), - 'scale': (20, 20), - 'color': (0.2, 0.2, 0.2), - 'opacity': 0.0, - 'attach': 'topCenter'}) - self._imageCircle2 = ba.newnode('image', - attrs={'texture': self._circleTex, - 'position': (75, -100), - 'scale': (20, 20), - 'color': (0.2, 0.2, 0.2), - 'opacity': 0.0, - 'attach': 'topCenter'}) - self._imageCircle3 = ba.newnode('image', - attrs={'texture': self._circleTex, - 'position': (75, -125), - 'scale': (20, 20), - 'color': (0.2, 0.2, 0.2), - 'opacity': 0.0, - 'attach': 'topCenter'}) + self._mapFGPModel = bs.getmesh('buttonSquareOpaque') + self._mapFGPDefaultTex = bs.gettexture('achievementOffYouGo') + + self._mapFGCurseTex = bs.gettexture('powerupCurse') + self._mapFGHealthTex = bs.gettexture('powerupHealth') + self._mapFGIceTex = bs.gettexture('powerupIceBombs') + self._mapFGImpactTex = bs.gettexture('powerupImpactBombs') + self._mapFGMinesTex = bs.gettexture('powerupLandMines') + self._mapFGPunchTex = bs.gettexture('powerupPunch') + self._mapFGShieldTex = bs.gettexture('powerupShield') + self._mapFGStickyTex = bs.gettexture('powerupStickyBombs') + + self._mapFGSpaz = bs.gettexture('neoSpazIcon') + self._mapFGZoe = bs.gettexture('zoeIcon') + self._mapFGSnake = bs.gettexture('ninjaIcon') + self._mapFGKronk= bs.gettexture('kronkIcon') + self._mapFGMel = bs.gettexture('melIcon') + self._mapFGJack = bs.gettexture('jackIcon') + self._mapFGSanta = bs.gettexture('santaIcon') + self._mapFGFrosty = bs.gettexture('frostyIcon') + self._mapFGBones = bs.gettexture('bonesIcon') + self._mapFGBernard = bs.gettexture('bearIcon') + self._mapFGPascal = bs.gettexture('penguinIcon') + self._mapFGAli = bs.gettexture('aliIcon') + self._mapFGRobot = bs.gettexture('cyborgIcon') + self._mapFGAgent = bs.gettexture('agentIcon') + self._mapFGGrumbledorf = bs.gettexture('wizardIcon') + self._mapFGPixel = bs.gettexture('pixieIcon') + + self._imageTextDefault = bs.gettexture('bg') + self._circleTex = bs.gettexture('circleShadow') + + self._image = bs.newnode('image', + attrs={'texture': self._imageTextDefault, + 'position':(0,-100), + 'scale':(100,100), + 'opacity': 0.0, + 'attach':'topCenter'}) + + self._textCounter = bs.newnode('text', + attrs={'text': '10', + 'position': (0, -100), + 'scale': 2.3, + 'shadow': 1.0, + 'flatness': 1.0, + 'opacity': 0.0, + 'v_attach': 'top', + 'h_attach': 'center', + 'h_align': 'center', + 'v_align': 'center'}) + + self._textLevel = bs.newnode('text', + attrs={'text': 'Level ' + str(self._levelStage), + 'position': (0, -28), + 'scale': 1.3, + 'shadow': 1.0, + 'flatness': 1.0, + 'color': (1.0, 0.0, 1.0), + 'opacity': 0.0, + 'v_attach': 'top', + 'h_attach': 'center', + 'h_align': 'center', + 'v_align': 'center'}) + + self._imageCircle = bs.newnode('image', + attrs={'texture': self._circleTex, + 'position': (75, -75), + 'scale': (20,20), + 'color': (0.2, 0.2, 0.2), + 'opacity': 0.0, + 'attach': 'topCenter'}) + self._imageCircle2 = bs.newnode('image', + attrs={'texture': self._circleTex, + 'position': (75, -100), + 'scale': (20,20), + 'color': (0.2, 0.2, 0.2), + 'opacity': 0.0, + 'attach': 'topCenter'}) + self._imageCircle3 = bs.newnode('image', + attrs={'texture': self._circleTex, + 'position': (75, -125), + 'scale': (20,20), + 'color': (0.2, 0.2, 0.2), + 'opacity': 0.0, + 'attach': 'topCenter'}) + def on_transition_in(self) -> None: super().on_transition_in() - self._bellLow = ba.getsound('bellLow') - self._bellMed = ba.getsound('bellMed') - self._bellHigh = ba.getsound('bellHigh') - self._tickSound = ba.getsound('tick') - self._tickFinal = ba.getsound('powerup01') - self._scoreSound = ba.getsound('score') + self._bellLow = bs.getsound('bellLow') + self._bellMed = bs.getsound('bellMed') + self._bellHigh = bs.getsound('bellHigh') + self._tickSound = bs.getsound('tick') + self._tickFinal = bs.getsound('powerup01') + self._scoreSound = bs.getsound('score') self._image.opacity = 1 self._textCounter.opacity = 1 @@ -282,8 +273,8 @@ def on_transition_in(self) -> None: if self._levelStage == 1: timeStart = 6 - ba.timer(timeStart, self._randomPlatform) - ba.timer(timeStart, self.startCounter) + bs.timer(timeStart, self._randomPlatform) + bs.timer(timeStart, self.startCounter) def on_begin(self) -> None: super().on_begin() @@ -308,26 +299,25 @@ def on_begin(self) -> None: self.coldel15 = True self.coldel16 = True if self.credit_text: - t = ba.newnode('text', - attrs={'text': "Made by Freaku\nOriginally for 1.4: byANG3L", # Disable 'Enable Bottom Credits' when making playlist, No need to edit this lovely... - 'scale': 0.7, - 'position': (0, 0), - 'shadow': 0.5, - 'flatness': 1.2, - 'color': (1, 1, 1), - 'h_align': 'center', - 'v_attach': 'bottom'}) - self.spawnAllMap() - self.flashHide() + t = bs.newnode('text', + attrs={ 'text':"Made by Freaku\nOriginally for 1.4: byANG3L", ## Disable 'Enable Bottom Credits' when making playlist, No need to edit this lovely... + 'scale':0.7, + 'position':(0,0), + 'shadow':0.5, + 'flatness':1.2, + 'color':(1, 1, 1), + 'h_align':'center', + 'v_attach':'bottom'}) + self.spawnAllMap() + self.flashHide() # Check for immediate end (if we've only got 1 player, etc). - ba.timer(5, self._check_end_game) - self._dingSound = ba.getsound('dingSmall') - self._dingSoundHigh = ba.getsound('dingSmallHigh') + bs.timer(5, self._check_end_game) + self._dingSound = bs.getsound('dingSmall') + self._dingSoundHigh = bs.getsound('dingSmallHigh') def startCounter(self): self._textCounter.text = '10' - def count9(): def count8(): def count7(): @@ -339,45 +329,45 @@ def count2(): def count1(): def countFinal(): self._textCounter.text = '' - ba.playsound(self._tickFinal) + self._tickFinal.play() self._stop() self._textCounter.text = '1' - ba.playsound(self._tickSound) - ba.timer(1, countFinal) + self._tickSound.play() + bs.timer(1, countFinal) self._textCounter.text = '2' - ba.playsound(self._tickSound) - ba.timer(1, count1) + self._tickSound.play() + bs.timer(1, count1) self._textCounter.text = '3' - ba.playsound(self._tickSound) - ba.timer(1, count2) + self._tickSound.play() + bs.timer(1, count2) self._textCounter.text = '4' - ba.playsound(self._tickSound) - ba.timer(1, count3) + self._tickSound.play() + bs.timer(1, count3) self._textCounter.text = '5' - ba.playsound(self._tickSound) - ba.timer(1, count4) + self._tickSound.play() + bs.timer(1, count4) self._textCounter.text = '6' - ba.playsound(self._tickSound) - ba.timer(1, count5) + self._tickSound.play() + bs.timer(1, count5) self._textCounter.text = '7' - ba.playsound(self._tickSound) - ba.timer(1, count6) + self._tickSound.play() + bs.timer(1, count6) self._textCounter.text = '8' - ba.playsound(self._tickSound) - ba.timer(1, count7) + self._tickSound.play() + bs.timer(1, count7) self._textCounter.text = '9' - ba.playsound(self._tickSound) - ba.timer(1, count8) - ba.timer(1, count9) + self._tickSound.play() + bs.timer(1, count8) + bs.timer(1, count9) def on_player_join(self, player: Player) -> None: # Don't allow joining after we start # (would enable leave/rejoin tomfoolery). if self.has_begun(): - ba.screenmessage( - ba.Lstr(resource='playerDelayedJoinText', + bs.broadcastmessage( + babase.Lstr(resource='playerDelayedJoinText', subs=[('${PLAYER}', player.getname(full=True))]), - color=(0, 1, 0), transient=True, clients=[player.sessionplayer.inputdevice.client_id]) + color=(0, 1, 0),transient=True,clients=[player.sessionplayer.inputdevice.client_id]) # For score purposes, mark them as having died right as the # game started. assert self._timer is not None @@ -393,184 +383,182 @@ def on_player_leave(self, player: Player) -> None: self._check_end_game() # overriding the default character spawning.. - def spawn_player(self, player: Player) -> ba.Actor: + def spawn_player(self, player: Player) -> bs.Actor: spaz = self.spawn_player_spaz(player) - pos = (self._spawnCenter[0] + random.uniform(-1.5, 2.5), - self._spawnCenter[1], self._spawnCenter[2] + random.uniform(-2.5, 1.5)) + pos = (self._spawnCenter[0] + random.uniform(-1.5, 2.5), self._spawnCenter[1], self._spawnCenter[2] + random.uniform(-2.5, 1.5)) spaz.connect_controls_to_player(enable_punch=False, enable_bomb=False, enable_pickup=False) - spaz.handlemessage(ba.StandMessage(pos)) + spaz.handlemessage(bs.StandMessage(pos)) return spaz def _randomSelect(self): if self._levelStage == 1: self._textureSelected = random.choice([self._mapFGMinesTex, - self._mapFGStickyTex]) + self._mapFGStickyTex]) self._image.texture = self._textureSelected elif self._levelStage == 2: self._textureSelected = random.choice([self._mapFGIceTex, - self._mapFGShieldTex]) + self._mapFGShieldTex]) self._image.texture = self._textureSelected - elif self._levelStage in [3, 4, 5]: + elif self._levelStage in [3,4,5]: self._textureSelected = random.choice([self._mapFGStickyTex, - self._mapFGIceTex, - self._mapFGImpactTex, - self._mapFGMinesTex]) + self._mapFGIceTex, + self._mapFGImpactTex, + self._mapFGMinesTex]) self._image.texture = self._textureSelected - elif self._levelStage in [6, 7, 8, 9]: + elif self._levelStage in [6,7,8,9]: self._textureSelected = random.choice([self._mapFGCurseTex, - self._mapFGHealthTex, - self._mapFGIceTex, - self._mapFGImpactTex, - self._mapFGMinesTex, - self._mapFGPunchTex, - self._mapFGShieldTex]) + self._mapFGHealthTex, + self._mapFGIceTex, + self._mapFGImpactTex, + self._mapFGMinesTex, + self._mapFGPunchTex, + self._mapFGShieldTex]) self._image.texture = self._textureSelected elif self._levelStage >= 10: self._textureSelected = random.choice([self._mapFGSpaz, - self._mapFGZoe, - self._mapFGSnake, - self._mapFGKronk, - self._mapFGMel, - self._mapFGJack, - self._mapFGSanta, - self._mapFGFrosty, - self._mapFGBones, - self._mapFGBernard, - self._mapFGPascal, - self._mapFGAli, - self._mapFGRobot, - self._mapFGAgent, - self._mapFGGrumbledorf, - self._mapFGPixel]) + self._mapFGZoe, + self._mapFGSnake, + self._mapFGKronk, + self._mapFGMel, + self._mapFGJack, + self._mapFGSanta, + self._mapFGFrosty, + self._mapFGBones, + self._mapFGBernard, + self._mapFGPascal, + self._mapFGAli, + self._mapFGRobot, + self._mapFGAgent, + self._mapFGGrumbledorf, + self._mapFGPixel]) self._image.texture = self._textureSelected return self._textureSelected def _stop(self): self._textureSelected = self._randomSelect() - def circle(): def circle2(): def circle3(): self._imageCircle3.color = (0.0, 1.0, 0.0) self._imageCircle3.opacity = 1.0 - ba.playsound(self._bellHigh) - ba.timer(0.2, self._doDelete) + self._bellHigh.play() + bs.timer(0.2, self._doDelete) self._imageCircle2.color = (1.0, 1.0, 0.0) self._imageCircle2.opacity = 1.0 - ba.playsound(self._bellMed) - ba.timer(1, circle3) + self._bellMed.play() + bs.timer(1, circle3) self._imageCircle.color = (1.0, 0.0, 0.0) self._imageCircle.opacity = 1.0 - ba.playsound(self._bellLow) - ba.timer(1, circle2) - ba.timer(1, circle) + self._bellLow.play() + bs.timer(1, circle2) + bs.timer(1, circle) def _randomPlatform(self): if self._levelStage == 1: - randomTexture = [self._mapFGMinesTex, - self._mapFGMinesTex, - self._mapFGMinesTex, - self._mapFGMinesTex, - self._mapFGMinesTex, - self._mapFGMinesTex, - self._mapFGMinesTex, - self._mapFGMinesTex, - self._mapFGStickyTex, - self._mapFGStickyTex, - self._mapFGStickyTex, - self._mapFGStickyTex, - self._mapFGStickyTex, - self._mapFGStickyTex, - self._mapFGStickyTex, - self._mapFGStickyTex] + randomTexture=[self._mapFGMinesTex, + self._mapFGMinesTex, + self._mapFGMinesTex, + self._mapFGMinesTex, + self._mapFGMinesTex, + self._mapFGMinesTex, + self._mapFGMinesTex, + self._mapFGMinesTex, + self._mapFGStickyTex, + self._mapFGStickyTex, + self._mapFGStickyTex, + self._mapFGStickyTex, + self._mapFGStickyTex, + self._mapFGStickyTex, + self._mapFGStickyTex, + self._mapFGStickyTex] elif self._levelStage == 2: - randomTexture = [self._mapFGIceTex, - self._mapFGIceTex, - self._mapFGIceTex, - self._mapFGIceTex, - self._mapFGIceTex, - self._mapFGIceTex, - self._mapFGIceTex, - self._mapFGIceTex, - self._mapFGShieldTex, - self._mapFGShieldTex, - self._mapFGShieldTex, - self._mapFGShieldTex, - self._mapFGShieldTex, - self._mapFGShieldTex, - self._mapFGShieldTex, - self._mapFGShieldTex] - elif self._levelStage in [3, 4, 5]: - randomTexture = [self._mapFGStickyTex, - self._mapFGStickyTex, - self._mapFGStickyTex, - self._mapFGStickyTex, - self._mapFGIceTex, - self._mapFGIceTex, - self._mapFGIceTex, - self._mapFGIceTex, - self._mapFGImpactTex, - self._mapFGImpactTex, - self._mapFGImpactTex, - self._mapFGImpactTex, - self._mapFGMinesTex, - self._mapFGMinesTex, - self._mapFGMinesTex, - self._mapFGMinesTex] - elif self._levelStage in [6, 7, 8, 9]: - randomTexture = [self._mapFGHealthTex, - self._mapFGShieldTex, - self._mapFGCurseTex, - self._mapFGCurseTex, - self._mapFGHealthTex, - self._mapFGHealthTex, - self._mapFGIceTex, - self._mapFGIceTex, - self._mapFGImpactTex, - self._mapFGImpactTex, - self._mapFGMinesTex, - self._mapFGMinesTex, - self._mapFGPunchTex, - self._mapFGPunchTex, - self._mapFGShieldTex, - self._mapFGShieldTex] + randomTexture=[self._mapFGIceTex, + self._mapFGIceTex, + self._mapFGIceTex, + self._mapFGIceTex, + self._mapFGIceTex, + self._mapFGIceTex, + self._mapFGIceTex, + self._mapFGIceTex, + self._mapFGShieldTex, + self._mapFGShieldTex, + self._mapFGShieldTex, + self._mapFGShieldTex, + self._mapFGShieldTex, + self._mapFGShieldTex, + self._mapFGShieldTex, + self._mapFGShieldTex] + elif self._levelStage in [3,4,5]: + randomTexture=[self._mapFGStickyTex, + self._mapFGStickyTex, + self._mapFGStickyTex, + self._mapFGStickyTex, + self._mapFGIceTex, + self._mapFGIceTex, + self._mapFGIceTex, + self._mapFGIceTex, + self._mapFGImpactTex, + self._mapFGImpactTex, + self._mapFGImpactTex, + self._mapFGImpactTex, + self._mapFGMinesTex, + self._mapFGMinesTex, + self._mapFGMinesTex, + self._mapFGMinesTex] + elif self._levelStage in [6,7,8,9]: + randomTexture=[self._mapFGHealthTex, + self._mapFGShieldTex, + self._mapFGCurseTex, + self._mapFGCurseTex, + self._mapFGHealthTex, + self._mapFGHealthTex, + self._mapFGIceTex, + self._mapFGIceTex, + self._mapFGImpactTex, + self._mapFGImpactTex, + self._mapFGMinesTex, + self._mapFGMinesTex, + self._mapFGPunchTex, + self._mapFGPunchTex, + self._mapFGShieldTex, + self._mapFGShieldTex] elif self._levelStage >= 10: - randomTexture = [self._mapFGSpaz, - self._mapFGZoe, - self._mapFGSnake, - self._mapFGKronk, - self._mapFGMel, - self._mapFGJack, - self._mapFGSanta, - self._mapFGFrosty, - self._mapFGBones, - self._mapFGBernard, - self._mapFGPascal, - self._mapFGAli, - self._mapFGRobot, - self._mapFGAgent, - self._mapFGGrumbledorf, - self._mapFGPixel] + randomTexture=[self._mapFGSpaz, + self._mapFGZoe, + self._mapFGSnake, + self._mapFGKronk, + self._mapFGMel, + self._mapFGJack, + self._mapFGSanta, + self._mapFGFrosty, + self._mapFGBones, + self._mapFGBernard, + self._mapFGPascal, + self._mapFGAli, + self._mapFGRobot, + self._mapFGAgent, + self._mapFGGrumbledorf, + self._mapFGPixel] (self.mapFGPTex, self.mapFGP2Tex, self.mapFGP3Tex, self.mapFGP4Tex, - self.mapFGP5Tex, self.mapFGP6Tex, - self.mapFGP7Tex, self.mapFGP8Tex, - self.mapFGP9Tex, self.mapFGP10Tex, - self.mapFGP11Tex, self.mapFGP12Tex, - self.mapFGP13Tex, self.mapFGP14Tex, - self.mapFGP15Tex, self.mapFGP16Tex) = ( - random.sample(randomTexture, 16)) + self.mapFGP5Tex, self.mapFGP6Tex, + self.mapFGP7Tex, self.mapFGP8Tex, + self.mapFGP9Tex,self.mapFGP10Tex, + self.mapFGP11Tex, self.mapFGP12Tex, + self.mapFGP13Tex, self.mapFGP14Tex, + self.mapFGP15Tex, self.mapFGP16Tex) = ( + random.sample(randomTexture, 16)) self._mixPlatform() def _mixPlatform(self): - ba.timer(1, self.flashShow) - ba.timer(3, self.flashHide) - ba.timer(4, self.flashShow) - ba.timer(6, self.flashHide) - ba.timer(7, self.flashShow) - ba.timer(9, self.flashHide) - ba.timer(13.2, self.flashShow) + bs.timer(1, self.flashShow) + bs.timer(3, self.flashHide) + bs.timer(4, self.flashShow) + bs.timer(6, self.flashHide) + bs.timer(7, self.flashShow) + bs.timer(9, self.flashHide) + bs.timer(13.2, self.flashShow) def flashHide(self): self.mapFGP.color_texture = self._mapFGPDefaultTex @@ -674,14 +662,14 @@ def _doDelete(self): self.mapFGP16col.delete() self.coldel16 = True - ba.timer(3.3, self._platformTexDefault) + bs.timer(3.3, self._platformTexDefault) def spawnAllMap(self): """ # Here's how it works: # First, create prop with a gravity scale of 0 - # Then use a in-game model which will suit it (For this one I didn't chose box, since it will look kinda weird) Right? - # Instead I used a 2d model (which is nothing but a button in menu) + # Then use a in-game mesh which will suit it (For this one I didn't chose box, since it will look kinda weird) Right? + # Instead I used a 2d mesh (which is nothing but a button in menu) # This prop SHOULD NOT collide with anything, since it has gravity_scale of 0 if it'll get weight it will fall down :(( # These are where we change those color-textures and is seen in-game @@ -696,131 +684,115 @@ def spawnAllMap(self): """ shared = SharedObjects.get() if self.coldel: - self.mapFGP = ba.newnode('prop', - attrs={'body': 'puck', 'position': (3, 2, -9), 'model': self._mapFGPModel, 'model_scale': 3.8, 'body_scale': 3.8, 'shadow_size': 0.5, 'gravity_scale': 0.0, 'color_texture': self._mapFGPDefaultTex, 'reflection': 'soft', 'reflection_scale': [1.0], 'is_area_of_interest': True, 'materials': [self.dont_collide]}) + self.mapFGP = bs.newnode('prop', + attrs={'body': 'puck', 'position': (4.5,2,-9), 'mesh': self._mapFGPModel, 'mesh_scale': 3.73, 'body_scale': 3.73, 'shadow_size': 0.5, 'gravity_scale':0.0, 'color_texture': self._mapFGPDefaultTex, 'reflection': 'soft', 'reflection_scale': [1.0], 'is_area_of_interest': True, 'materials': [self.dont_collide]}) self.mapFGPTex = None - self.mapFGPcol = ba.newnode('region', attrs={'position': (3, 2, -9), 'scale': ( - 3.5, 0.1, 3.5), 'type': 'box', 'materials': (self._collide_with_player, shared.footing_material)}) + self.mapFGPcol = bs.newnode('region',attrs={'position': (4.5,2,-9),'scale': (3.5,0.1,3.5),'type': 'box','materials': (self._collide_with_player, shared.footing_material)}) self.coldel = False if self.coldel2: - self.mapFGP2 = ba.newnode('prop', - attrs={'body': 'puck', 'position': (3, 2, -6), 'model': self._mapFGPModel, 'model_scale': 3.8, 'body_scale': 3.8, 'shadow_size': 0.5, 'gravity_scale': 0.0, 'color_texture': self._mapFGPDefaultTex, 'reflection': 'soft', 'reflection_scale': [1.0], 'is_area_of_interest': True, 'materials': [self.dont_collide]}) + self.mapFGP2 = bs.newnode('prop', + attrs={'body': 'puck', 'position': (4.5,2,-6), 'mesh': self._mapFGPModel, 'mesh_scale': 3.73, 'body_scale': 3.73, 'shadow_size': 0.5, 'gravity_scale':0.0, 'color_texture': self._mapFGPDefaultTex, 'reflection': 'soft', 'reflection_scale': [1.0], 'is_area_of_interest': True, 'materials': [self.dont_collide]}) self.mapFGP2Tex = None - self.mapFGP2col = ba.newnode('region', attrs={'position': (3, 2, -6), 'scale': ( - 3.5, 0.1, 3.5), 'type': 'box', 'materials': (self._collide_with_player, shared.footing_material)}) + self.mapFGP2col = bs.newnode('region',attrs={'position': (4.5,2,-6),'scale': (3.5,0.1,3.5),'type': 'box','materials': (self._collide_with_player, shared.footing_material)}) self.coldel2 = False if self.coldel3: - self.mapFGP3 = ba.newnode('prop', - attrs={'body': 'puck', 'position': (3, 2, -3), 'model': self._mapFGPModel, 'model_scale': 3.8, 'body_scale': 3.8, 'shadow_size': 0.5, 'gravity_scale': 0.0, 'color_texture': self._mapFGPDefaultTex, 'reflection': 'soft', 'reflection_scale': [1.0], 'is_area_of_interest': True, 'materials': [self.dont_collide]}) + self.mapFGP3 = bs.newnode('prop', + attrs={'body': 'puck', 'position': (4.5,2,-3), 'mesh': self._mapFGPModel, 'mesh_scale': 3.73, 'body_scale': 3.73, 'shadow_size': 0.5, 'gravity_scale':0.0, 'color_texture': self._mapFGPDefaultTex, 'reflection': 'soft', 'reflection_scale': [1.0], 'is_area_of_interest': True, 'materials': [self.dont_collide]}) self.mapFGP3Tex = None - self.mapFGP3col = ba.newnode('region', attrs={'position': (3, 2, -3), 'scale': ( - 3.5, 0.1, 3.5), 'type': 'box', 'materials': (self._collide_with_player, shared.footing_material)}) + self.mapFGP3col = bs.newnode('region',attrs={'position': (4.5,2,-3),'scale': (3.5,0.1,3.5),'type': 'box','materials': (self._collide_with_player, shared.footing_material)}) self.coldel3 = False if self.coldel4: - self.mapFGP4 = ba.newnode('prop', - attrs={'body': 'puck', 'position': (3, 2, 0), 'model': self._mapFGPModel, 'model_scale': 3.8, 'body_scale': 3.8, 'shadow_size': 0.5, 'gravity_scale': 0.0, 'color_texture': self._mapFGPDefaultTex, 'reflection': 'soft', 'reflection_scale': [1.0], 'is_area_of_interest': True, 'materials': [self.dont_collide]}) + self.mapFGP4 = bs.newnode('prop', + attrs={'body': 'puck', 'position': (4.5,2,0), 'mesh': self._mapFGPModel, 'mesh_scale': 3.73, 'body_scale': 3.73, 'shadow_size': 0.5, 'gravity_scale':0.0, 'color_texture': self._mapFGPDefaultTex, 'reflection': 'soft', 'reflection_scale': [1.0], 'is_area_of_interest': True, 'materials': [self.dont_collide]}) self.mapFGP4Tex = None - self.mapFGP4col = ba.newnode('region', attrs={'position': (3, 2, 0), 'scale': ( - 3.5, 0.1, 3.5), 'type': 'box', 'materials': (self._collide_with_player, shared.footing_material)}) + self.mapFGP4col = bs.newnode('region',attrs={'position': (4.5,2,0),'scale': (3.5,0.1,3.5),'type': 'box','materials': (self._collide_with_player, shared.footing_material)}) self.coldel4 = False if self.coldel5: - self.mapFGP5 = ba.newnode('prop', - attrs={'body': 'puck', 'position': (0, 2, -9), 'model': self._mapFGPModel, 'model_scale': 3.8, 'body_scale': 3.8, 'shadow_size': 0.5, 'gravity_scale': 0.0, 'color_texture': self._mapFGPDefaultTex, 'reflection': 'soft', 'reflection_scale': [1.0], 'is_area_of_interest': True, 'materials': [self.dont_collide]}) + self.mapFGP5 = bs.newnode('prop', + attrs={'body': 'puck', 'position': (1.5,2,-9), 'mesh': self._mapFGPModel, 'mesh_scale': 3.73, 'body_scale': 3.73, 'shadow_size': 0.5, 'gravity_scale':0.0, 'color_texture': self._mapFGPDefaultTex, 'reflection': 'soft', 'reflection_scale': [1.0], 'is_area_of_interest': True, 'materials': [self.dont_collide]}) self.mapFGP5Tex = None - self.mapFGP5col = ba.newnode('region', attrs={'position': (0, 2, -9), 'scale': ( - 3.5, 0.1, 3.5), 'type': 'box', 'materials': (self._collide_with_player, shared.footing_material)}) + self.mapFGP5col = bs.newnode('region',attrs={'position': (1.5,2,-9),'scale': (3.5,0.1,3.5),'type': 'box','materials': (self._collide_with_player, shared.footing_material)}) self.coldel5 = False if self.coldel6: - self.mapFGP6 = ba.newnode('prop', - attrs={'body': 'puck', 'position': (0, 2, -6), 'model': self._mapFGPModel, 'model_scale': 3.8, 'body_scale': 3.8, 'shadow_size': 0.5, 'gravity_scale': 0.0, 'color_texture': self._mapFGPDefaultTex, 'reflection': 'soft', 'reflection_scale': [1.0], 'is_area_of_interest': True, 'materials': [self.dont_collide]}) + self.mapFGP6 = bs.newnode('prop', + attrs={'body': 'puck', 'position': (1.5,2,-6), 'mesh': self._mapFGPModel, 'mesh_scale': 3.73, 'body_scale': 3.73, 'shadow_size': 0.5, 'gravity_scale':0.0, 'color_texture': self._mapFGPDefaultTex, 'reflection': 'soft', 'reflection_scale': [1.0], 'is_area_of_interest': True, 'materials': [self.dont_collide]}) self.mapFGP6Tex = None - self.mapFGP6col = ba.newnode('region', attrs={'position': (0, 2, -6), 'scale': ( - 3.5, 0.1, 3.5), 'type': 'box', 'materials': (self._collide_with_player, shared.footing_material)}) + self.mapFGP6col = bs.newnode('region',attrs={'position': (1.5,2,-6),'scale': (3.5,0.1,3.5),'type': 'box','materials': (self._collide_with_player, shared.footing_material)}) self.coldel6 = False if self.coldel7: - self.mapFGP7 = ba.newnode('prop', - attrs={'body': 'puck', 'position': (0, 2, -3), 'model': self._mapFGPModel, 'model_scale': 3.8, 'body_scale': 3.8, 'shadow_size': 0.5, 'gravity_scale': 0.0, 'color_texture': self._mapFGPDefaultTex, 'reflection': 'soft', 'reflection_scale': [1.0], 'is_area_of_interest': True, 'materials': [self.dont_collide]}) + self.mapFGP7 = bs.newnode('prop', + attrs={'body': 'puck', 'position': (1.5,2,-3), 'mesh': self._mapFGPModel, 'mesh_scale': 3.73, 'body_scale': 3.73, 'shadow_size': 0.5, 'gravity_scale':0.0, 'color_texture': self._mapFGPDefaultTex, 'reflection': 'soft', 'reflection_scale': [1.0], 'is_area_of_interest': True, 'materials': [self.dont_collide]}) self.mapFGP7Tex = None - self.mapFGP7col = ba.newnode('region', attrs={'position': (0, 2, -3), 'scale': ( - 3.5, 0.1, 3.5), 'type': 'box', 'materials': (self._collide_with_player, shared.footing_material)}) + self.mapFGP7col = bs.newnode('region',attrs={'position': (1.5,2,-3),'scale': (3.5,0.1,3.5),'type': 'box','materials': (self._collide_with_player, shared.footing_material)}) self.coldel7 = False if self.coldel8: - self.mapFGP8 = ba.newnode('prop', - attrs={'body': 'puck', 'position': (0, 2, 0), 'model': self._mapFGPModel, 'model_scale': 3.8, 'body_scale': 3.8, 'shadow_size': 0.5, 'gravity_scale': 0.0, 'color_texture': self._mapFGPDefaultTex, 'reflection': 'soft', 'reflection_scale': [1.0], 'is_area_of_interest': True, 'materials': [self.dont_collide]}) + self.mapFGP8 = bs.newnode('prop', + attrs={'body': 'puck', 'position': (1.5,2,0), 'mesh': self._mapFGPModel, 'mesh_scale': 3.73, 'body_scale': 3.73, 'shadow_size': 0.5, 'gravity_scale':0.0, 'color_texture': self._mapFGPDefaultTex, 'reflection': 'soft', 'reflection_scale': [1.0], 'is_area_of_interest': True, 'materials': [self.dont_collide]}) self.mapFGP8Tex = None - self.mapFGP8col = ba.newnode('region', attrs={'position': (0, 2, 0), 'scale': ( - 3.5, 0.1, 3.5), 'type': 'box', 'materials': (self._collide_with_player, shared.footing_material)}) + self.mapFGP8col = bs.newnode('region',attrs={'position': (1.5,2,0),'scale': (3.5,0.1,3.5),'type': 'box','materials': (self._collide_with_player, shared.footing_material)}) self.coldel8 = False if self.coldel9: - self.mapFGP9 = ba.newnode('prop', - attrs={'body': 'puck', 'position': (-3, 2, -9), 'model': self._mapFGPModel, 'model_scale': 3.8, 'body_scale': 3.8, 'shadow_size': 0.5, 'gravity_scale': 0.0, 'color_texture': self._mapFGPDefaultTex, 'reflection': 'soft', 'reflection_scale': [1.0], 'is_area_of_interest': True, 'materials': [self.dont_collide]}) + self.mapFGP9 = bs.newnode('prop', + attrs={'body': 'puck', 'position': (-1.5,2,-9), 'mesh': self._mapFGPModel, 'mesh_scale': 3.73, 'body_scale': 3.73, 'shadow_size': 0.5, 'gravity_scale':0.0, 'color_texture': self._mapFGPDefaultTex, 'reflection': 'soft', 'reflection_scale': [1.0], 'is_area_of_interest': True, 'materials': [self.dont_collide]}) self.mapFGP9Tex = None - self.mapFGP9col = ba.newnode('region', attrs={'position': (-3, 2, -9), 'scale': ( - 3.5, 0.1, 3.5), 'type': 'box', 'materials': (self._collide_with_player, shared.footing_material)}) + self.mapFGP9col = bs.newnode('region',attrs={'position': (-1.5,2,-9),'scale': (3.5,0.1,3.5),'type': 'box','materials': (self._collide_with_player, shared.footing_material)}) self.coldel9 = False if self.coldel10: - self.mapFGP10 = ba.newnode('prop', - attrs={'body': 'puck', 'position': (-3, 2, -6), 'model': self._mapFGPModel, 'model_scale': 3.8, 'body_scale': 3.8, 'shadow_size': 0.5, 'gravity_scale': 0.0, 'color_texture': self._mapFGPDefaultTex, 'reflection': 'soft', 'reflection_scale': [1.0], 'is_area_of_interest': True, 'materials': [self.dont_collide]}) + self.mapFGP10 = bs.newnode('prop', + attrs={'body': 'puck', 'position': (-1.5,2,-6), 'mesh': self._mapFGPModel, 'mesh_scale': 3.73, 'body_scale': 3.73, 'shadow_size': 0.5, 'gravity_scale':0.0, 'color_texture': self._mapFGPDefaultTex, 'reflection': 'soft', 'reflection_scale': [1.0], 'is_area_of_interest': True, 'materials': [self.dont_collide]}) self.mapFGP10Tex = None - self.mapFGP10col = ba.newnode('region', attrs={'position': (-3, 2, -6), 'scale': ( - 3.5, 0.1, 3.5), 'type': 'box', 'materials': (self._collide_with_player, shared.footing_material)}) + self.mapFGP10col = bs.newnode('region',attrs={'position': (-1.5,2,-6),'scale': (3.5,0.1,3.5),'type': 'box','materials': (self._collide_with_player, shared.footing_material)}) self.coldel10 = False if self.coldel11: - self.mapFGP11 = ba.newnode('prop', - attrs={'body': 'puck', 'position': (-3, 2, -3), 'model': self._mapFGPModel, 'model_scale': 3.8, 'body_scale': 3.8, 'shadow_size': 0.5, 'gravity_scale': 0.0, 'color_texture': self._mapFGPDefaultTex, 'reflection': 'soft', 'reflection_scale': [1.0], 'is_area_of_interest': True, 'materials': [self.dont_collide]}) + self.mapFGP11 = bs.newnode('prop', + attrs={'body': 'puck', 'position': (-1.5,2,-3), 'mesh': self._mapFGPModel, 'mesh_scale': 3.73, 'body_scale': 3.73, 'shadow_size': 0.5, 'gravity_scale':0.0, 'color_texture': self._mapFGPDefaultTex, 'reflection': 'soft', 'reflection_scale': [1.0], 'is_area_of_interest': True, 'materials': [self.dont_collide]}) self.mapFGP11Tex = None - self.mapFGP11col = ba.newnode('region', attrs={'position': (-3, 2, -3), 'scale': ( - 3.5, 0.1, 3.5), 'type': 'box', 'materials': (self._collide_with_player, shared.footing_material)}) + self.mapFGP11col = bs.newnode('region',attrs={'position': (-1.5,2,-3),'scale': (3.5,0.1,3.5),'type': 'box','materials': (self._collide_with_player, shared.footing_material)}) self.coldel11 = False if self.coldel12: - self.mapFGP12 = ba.newnode('prop', - attrs={'body': 'puck', 'position': (-3, 2, 0), 'model': self._mapFGPModel, 'model_scale': 3.8, 'body_scale': 3.8, 'shadow_size': 0.5, 'gravity_scale': 0.0, 'color_texture': self._mapFGPDefaultTex, 'reflection': 'soft', 'reflection_scale': [1.0], 'is_area_of_interest': True, 'materials': [self.dont_collide]}) + self.mapFGP12 = bs.newnode('prop', + attrs={'body': 'puck', 'position': (-1.5,2,0), 'mesh': self._mapFGPModel, 'mesh_scale': 3.73, 'body_scale': 3.73, 'shadow_size': 0.5, 'gravity_scale':0.0, 'color_texture': self._mapFGPDefaultTex, 'reflection': 'soft', 'reflection_scale': [1.0], 'is_area_of_interest': True, 'materials': [self.dont_collide]}) self.mapFGP12Tex = None - self.mapFGP12col = ba.newnode('region', attrs={'position': (-3, 2, 0), 'scale': ( - 3.5, 0.1, 3.5), 'type': 'box', 'materials': (self._collide_with_player, shared.footing_material)}) + self.mapFGP12col = bs.newnode('region',attrs={'position': (-1.5,2,0),'scale': (3.5,0.1,3.5),'type': 'box','materials': (self._collide_with_player, shared.footing_material)}) self.coldel12 = False if self.coldel13: - self.mapFGP13 = ba.newnode('prop', - attrs={'body': 'puck', 'position': (-6, 2, -9), 'model': self._mapFGPModel, 'model_scale': 3.8, 'body_scale': 3.8, 'shadow_size': 0.5, 'gravity_scale': 0.0, 'color_texture': self._mapFGPDefaultTex, 'reflection': 'soft', 'reflection_scale': [1.0], 'is_area_of_interest': True, 'materials': [self.dont_collide]}) + self.mapFGP13 = bs.newnode('prop', + attrs={'body': 'puck', 'position': (-4.5,2,-9), 'mesh': self._mapFGPModel, 'mesh_scale': 3.73, 'body_scale': 3.73, 'shadow_size': 0.5, 'gravity_scale':0.0, 'color_texture': self._mapFGPDefaultTex, 'reflection': 'soft', 'reflection_scale': [1.0], 'is_area_of_interest': True, 'materials': [self.dont_collide]}) self.mapFGP13Tex = None - self.mapFGP13col = ba.newnode('region', attrs={'position': (-6, 2, -9), 'scale': ( - 3.5, 0.1, 3.5), 'type': 'box', 'materials': (self._collide_with_player, shared.footing_material)}) + self.mapFGP13col = bs.newnode('region',attrs={'position': (-4.5,2,-9),'scale': (3.5,0.1,3.5),'type': 'box','materials': (self._collide_with_player, shared.footing_material)}) self.coldel13 = False if self.coldel14: - self.mapFGP14 = ba.newnode('prop', - attrs={'body': 'puck', 'position': (-6, 2, -6), 'model': self._mapFGPModel, 'model_scale': 3.8, 'body_scale': 3.8, 'shadow_size': 0.5, 'gravity_scale': 0.0, 'color_texture': self._mapFGPDefaultTex, 'reflection': 'soft', 'reflection_scale': [1.0], 'is_area_of_interest': True, 'materials': [self.dont_collide]}) + self.mapFGP14 = bs.newnode('prop', + attrs={'body': 'puck', 'position': (-4.5,2,-6), 'mesh': self._mapFGPModel, 'mesh_scale': 3.73, 'body_scale': 3.73, 'shadow_size': 0.5, 'gravity_scale':0.0, 'color_texture': self._mapFGPDefaultTex, 'reflection': 'soft', 'reflection_scale': [1.0], 'is_area_of_interest': True, 'materials': [self.dont_collide]}) self.mapFGP14Tex = None - self.mapFGP14col = ba.newnode('region', attrs={'position': (-6, 2, -6), 'scale': ( - 3.5, 0.1, 3.5), 'type': 'box', 'materials': (self._collide_with_player, shared.footing_material)}) + self.mapFGP14col = bs.newnode('region',attrs={'position': (-4.5,2,-6),'scale': (3.5,0.1,3.5),'type': 'box','materials': (self._collide_with_player, shared.footing_material)}) self.coldel14 = False if self.coldel15: - self.mapFGP15 = ba.newnode('prop', - attrs={'body': 'puck', 'position': (-6, 2, -3), 'model': self._mapFGPModel, 'model_scale': 3.8, 'body_scale': 3.8, 'shadow_size': 0.5, 'gravity_scale': 0.0, 'color_texture': self._mapFGPDefaultTex, 'reflection': 'soft', 'reflection_scale': [1.0], 'is_area_of_interest': True, 'materials': [self.dont_collide]}) + self.mapFGP15 = bs.newnode('prop', + attrs={'body': 'puck', 'position': (-4.5,2,-3), 'mesh': self._mapFGPModel, 'mesh_scale': 3.73, 'body_scale': 3.73, 'shadow_size': 0.5, 'gravity_scale':0.0, 'color_texture': self._mapFGPDefaultTex, 'reflection': 'soft', 'reflection_scale': [1.0], 'is_area_of_interest': True, 'materials': [self.dont_collide]}) self.mapFGP15Tex = None - self.mapFGP15col = ba.newnode('region', attrs={'position': (-6, 2, -3), 'scale': ( - 3.5, 0.1, 3.5), 'type': 'box', 'materials': (self._collide_with_player, shared.footing_material)}) + self.mapFGP15col = bs.newnode('region',attrs={'position': (-4.5,2,-3),'scale': (3.5,0.1,3.5),'type': 'box','materials': (self._collide_with_player, shared.footing_material)}) self.coldel15 = False if self.coldel16: - self.mapFGP16 = ba.newnode('prop', - attrs={'body': 'puck', 'position': (-6, 2, 0), 'model': self._mapFGPModel, 'model_scale': 3.8, 'body_scale': 3.8, 'shadow_size': 0.5, 'gravity_scale': 0.0, 'color_texture': self._mapFGPDefaultTex, 'reflection': 'soft', 'reflection_scale': [1.0], 'is_area_of_interest': True, 'materials': [self.dont_collide]}) + self.mapFGP16 = bs.newnode('prop', + attrs={'body': 'puck', 'position': (-4.5,2,0), 'mesh': self._mapFGPModel, 'mesh_scale': 3.73, 'body_scale': 3.73, 'shadow_size': 0.5, 'gravity_scale':0.0, 'color_texture': self._mapFGPDefaultTex, 'reflection': 'soft', 'reflection_scale': [1.0], 'is_area_of_interest': True, 'materials': [self.dont_collide]}) self.mapFGP16Tex = None - self.mapFGP16col = ba.newnode('region', attrs={'position': (-6, 2, 0), 'scale': ( - 3.5, 0.1, 3.5), 'type': 'box', 'materials': (self._collide_with_player, shared.footing_material)}) + self.mapFGP16col = bs.newnode('region',attrs={'position': (-4.5,2,0),'scale': (3.5,0.1,3.5),'type': 'box','materials': (self._collide_with_player, shared.footing_material)}) self.coldel16 = False def _platformTexDefault(self): @@ -843,27 +815,27 @@ def _platformTexDefault(self): timeStart = 6 else: timeStart = 2 - ba.playsound(self._scoreSound) - activity = _ba.get_foreground_host_activity() + self._scoreSound.play() + activity = bs.get_foreground_host_activity() for i in activity.players: try: - i.actor.node.handlemessage(ba.CelebrateMessage(2.0)) + i.actor.node.handlemessage(bs.CelebrateMessage(2.0)) except: pass - ba.timer(timeStart, self._randomPlatform) - ba.timer(timeStart, self.startCounter) + bs.timer(timeStart, self._randomPlatform) + bs.timer(timeStart, self.startCounter) self.spawnAllMap() self.flashHide() # Various high-level game events come through this method. def handlemessage(self, msg: Any) -> Any: - if isinstance(msg, ba.PlayerDiedMessage): + if isinstance(msg, bs.PlayerDiedMessage): # Augment standard behavior. super().handlemessage(msg) - curtime = ba.time() + curtime = bs.time() # Record the player's moment of death. # assert isinstance(msg.spaz.player @@ -873,15 +845,15 @@ def handlemessage(self, msg: Any) -> Any: # (more accurate looking). # In teams/ffa, allow a one-second fudge-factor so we can # get more draws if players die basically at the same time. - if isinstance(self.session, ba.CoopSession): + if isinstance(self.session, bs.CoopSession): # Teams will still show up if we check now.. check in # the next cycle. - ba.pushcall(self._check_end_game) + babase.pushcall(self._check_end_game) # Also record this for a final setting of the clock. self._last_player_death_time = curtime else: - ba.timer(1.0, self._check_end_game) + bs.timer(1.0, self._check_end_game) else: # Default handler: return super().handlemessage(msg) @@ -897,15 +869,16 @@ def _check_end_game(self) -> None: # In co-op, we go till everyone is dead.. otherwise we go # until one team remains. - if isinstance(self.session, ba.CoopSession): + if isinstance(self.session, bs.CoopSession): if living_team_count <= 0: self.end_game() else: if living_team_count <= 1: self.end_game() + def end_game(self) -> None: - cur_time = ba.time() + cur_time = bs.time() assert self._timer is not None start_time = self._timer.getstarttime() @@ -936,7 +909,7 @@ def end_game(self) -> None: # Ok now calc game results: set a score for each team and then tell # the game to end. - results = ba.GameResults() + results = bs.GameResults() # Remember that 'free-for-all' mode is simply a special form # of 'teams' mode where each player gets their own team, so we can @@ -956,16 +929,20 @@ def end_game(self) -> None: self.end(results=results) + + + + + + + class MGdefs(): points = {} boxes = {} - boxes['area_of_interest_bounds'] = ( - 0.3544110667, 4.493562578, -2.518391331) + (0.0, 0.0, 0.0) + (16.64754831, 8.06138989, 18.5029888) - boxes['map_bounds'] = (0.2608783669, 4.899663734, -3.543675157) + \ - (0.0, 0.0, 0.0) + (29.23565494, 14.19991443, 29.92689344) + boxes['area_of_interest_bounds'] = (0.3544110667, 4.493562578, -2.518391331) + (0.0, 0.0, 0.0) + (16.64754831, 8.06138989, 18.5029888) + boxes['map_bounds'] = (0.2608783669, 4.899663734, -3.543675157) + (0.0, 0.0, 0.0) + (29.23565494, 14.19991443, 29.92689344) - -class MGmap(ba.Map): +class MGmap(bs.Map): defs = MGdefs() name = 'Sky Tiles' @@ -981,23 +958,23 @@ def get_preview_texture_name(cls) -> str: @classmethod def on_preload(cls) -> Any: data: Dict[str, Any] = { - 'bgtex': ba.gettexture('menuBG'), - 'bgmodel': ba.getmodel('thePadBG') + 'bgtex': bs.gettexture('menuBG'), + 'bgmesh': bs.getmesh('thePadBG') } return data def __init__(self) -> None: super().__init__() shared = SharedObjects.get() - self.node = ba.newnode( + self.node = bs.newnode( 'terrain', attrs={ - 'model': self.preloaddata['bgmodel'], + 'mesh': self.preloaddata['bgmesh'], 'lighting': False, 'background': True, 'color_texture': self.preloaddata['bgtex'] }) - gnode = ba.getactivity().globalsnode + gnode = bs.getactivity().globalsnode gnode.tint = (1.3, 1.2, 1.0) gnode.ambient_color = (1.3, 1.2, 1.0) gnode.vignette_outer = (0.57, 0.57, 0.57) @@ -1006,12 +983,16 @@ def __init__(self) -> None: gnode.vr_near_clip = 0.5 -ba._map.register_map(MGmap) + + + +bs._map.register_map(MGmap) + + # ba_meta export plugin -class byFreaku(ba.Plugin): +class byFreaku(babase.Plugin): def __init__(self): ## Campaign support ## - ba.app.add_coop_practice_level(ba.Level(name='Memory Game', displayname='${GAME}', gametype=MGgame, settings={ - }, preview_texture_name='achievementOffYouGo')) + babase.app.classic.add_coop_practice_level(bs.Level(name='Memory Game', displayname='${GAME}', gametype=MGgame, settings={}, preview_texture_name='achievementOffYouGo')) \ No newline at end of file diff --git a/plugins/minigames/musical_flags.py b/plugins/minigames/musical_flags.py index fbe9d2e6..41828b3c 100644 --- a/plugins/minigames/musical_flags.py +++ b/plugins/minigames/musical_flags.py @@ -1,100 +1,99 @@ -# Made by MattZ45986 on GitHub -# Ported by: Freaku / @[Just] Freak#4999 +## Made by MattZ45986 on GitHub +## Ported by your friend: Freaku -# Bug Fixes & Improvements as well... +#Bug Fixes & Improvements as well... -# Join BCS: +#Join BCS: # https://discord.gg/ucyaesh + + from __future__ import annotations from typing import TYPE_CHECKING -import _ba -import ba -import random -import math -from bastd.actor.flag import Flag, FlagPickedUpMessage -from bastd.actor.playerspaz import PlayerSpaz +import _babase, random, math +import bascenev1 as bs +from bascenev1lib.actor.flag import Flag,FlagPickedUpMessage +from bascenev1lib.actor.playerspaz import PlayerSpaz if TYPE_CHECKING: from typing import Any, Type, List, Dict, Tuple, Union, Sequence, Optional -class Player(ba.Player['Team']): + +class Player(bs.Player['Team']): def __init__(self) -> None: self.done: bool = False self.survived: bool = True - -class Team(ba.Team[Player]): +class Team(bs.Team[Player]): def __init__(self) -> None: self.score = 0 -# ba_meta require api 7 -# ba_meta export game -class MFGame(ba.TeamGameActivity[Player, Team]): +# ba_meta require api 8 +# ba_meta export bascenev1.GameActivity +class MFGame(bs.TeamGameActivity[Player, Team]): name = 'Musical Flags' description = "Don't be the one stuck without a flag!" @classmethod def get_available_settings( - cls, sessiontype: Type[ba.Session]) -> List[ba.Setting]: + cls, sessiontype: Type[bs.Session]) -> List[babase.Setting]: settings = [ - ba.IntChoiceSetting( - 'Time Limit', - choices=[ - ('None', 0), - ('1 Minute', 60), - ('2 Minutes', 120), - ('5 Minutes', 300), - ('10 Minutes', 600), - ('20 Minutes', 1200), - ], - default=0, + bs.IntSetting( + 'Max Round Time', + min_value=15, + default=25, + increment=5, ), - ba.BoolSetting('Epic Mode', default=False), - ba.BoolSetting('Enable Running', default=True), - ba.BoolSetting('Enable Punching', default=False), - ba.BoolSetting('Enable Bottom Credit', True) + bs.BoolSetting('Epic Mode', default=False), + bs.BoolSetting('Enable Running', default=True), + bs.BoolSetting('Enable Punching', default=False), + bs.BoolSetting('Enable Bottom Credit', True) ] return settings @classmethod - def supports_session_type(cls, sessiontype: Type[ba.Session]) -> bool: - return (issubclass(sessiontype, ba.DualTeamSession) - or issubclass(sessiontype, ba.FreeForAllSession)) + def supports_session_type(cls, sessiontype: Type[bs.Session]) -> bool: + return (issubclass(sessiontype, bs.DualTeamSession) + or issubclass(sessiontype, bs.FreeForAllSession)) @classmethod - def get_supported_maps(cls, sessiontype: Type[ba.Session]) -> List[str]: + def get_supported_maps(cls, sessiontype: Type[bs.Session]) -> List[str]: return ['Doom Shroom'] def __init__(self, settings: dict): super().__init__(settings) self.nodes = [] - self._dingsound = ba.getsound('dingSmall') + self._dingsound = bs.getsound('dingSmall') self._epic_mode = bool(settings['Epic Mode']) self.credit_text = bool(settings['Enable Bottom Credit']) - self._time_limit = float(settings['Time Limit']) self.is_punch = bool(settings['Enable Punching']) self.is_run = bool(settings['Enable Running']) - self._textRound = ba.newnode('text', - attrs={'text': '', - 'position': (0, -38), - 'scale': 1, - 'shadow': 1.0, - 'flatness': 1.0, - 'color': (1.0, 0.0, 1.0), - 'opacity': 1, - 'v_attach': 'top', - 'h_attach': 'center', - 'h_align': 'center', - 'v_align': 'center'}) + self._textRound = bs.newnode('text', + attrs={'text': '', + 'position': (0, -38), + 'scale': 1, + 'shadow': 1.0, + 'flatness': 1.0, + 'color': (1.0, 0.0, 1.0), + 'opacity': 1, + 'v_attach': 'top', + 'h_attach': 'center', + 'h_align': 'center', + 'v_align': 'center'}) + self.round_time = int(settings['Max Round Time']) + self.reset_round_time = int(settings['Max Round Time']) + self.should_die_occur = True + self.round_time_textnode = bs.newnode('text', + attrs={ + 'text': "",'flatness':1.0,'h_align':'center','h_attach':'center','v_attach':'top','v_align':'center','position':(0,-15),'scale':0.9,'color':(1,0.7,0.9)}) self.slow_motion = self._epic_mode # A cool music, matching our gamemode theme - self.default_music = ba.MusicType.FLAG_CATCHER + self.default_music = bs.MusicType.FLAG_CATCHER def get_instance_description(self) -> Union[str, Sequence]: return 'Catch Flag for yourself' @@ -104,10 +103,10 @@ def get_instance_description_short(self) -> Union[str, Sequence]: def on_player_join(self, player: Player) -> None: if self.has_begun(): - ba.screenmessage( - ba.Lstr(resource='playerDelayedJoinText', + bs.broadcastmessage( + bs.Lstr(resource='playerDelayedJoinText', subs=[('${PLAYER}', player.getname(full=True))]), - color=(0, 1, 0), transient=True) + color=(0, 1, 0),transient=True) player.survived = False return self.spawn_player(player) @@ -115,7 +114,7 @@ def on_player_join(self, player: Player) -> None: def on_player_leave(self, player: Player) -> None: super().on_player_leave(player) # A departing player may trigger game-over. - self.checkEnd() + bs.timer(0, self.checkEnd) def on_begin(self) -> None: super().on_begin() @@ -124,74 +123,97 @@ def on_begin(self) -> None: self.nodes = [] self.flags = [] self.spawned = [] - self.setup_standard_time_limit(self._time_limit) if self.credit_text: - t = ba.newnode('text', - attrs={'text': "Ported by Freaku\nMade by MattZ45986", # Disable 'Enable Bottom Credits' when making playlist, No need to edit this lovely... - 'scale': 0.7, - 'position': (0, 0), - 'shadow': 0.5, - 'flatness': 1.2, - 'color': (1, 1, 1), - 'h_align': 'center', - 'v_attach': 'bottom'}) + t = bs.newnode('text', + attrs={ 'text':"Ported by Freaku\nMade by MattZ45986", ## Disable 'Enable Bottom Credits' when making playlist, No need to edit this lovely... + 'scale':0.7, + 'position':(0,0), + 'shadow':0.5, + 'flatness':1.2, + 'color':(1, 1, 1), + 'h_align':'center', + 'v_attach':'bottom'}) self.makeRound() self._textRound.text = 'Round ' + str(self.roundNum) - ba.timer(5, self.checkEnd) + bs.timer(3, self.checkEnd) + self.keepcalling = bs.timer(1, self._timeround, True) + + def _timeround(self): + if self.round_time == 0 and self.should_die_occur: + self.should_die_occur = False + self.round_time_textnode.opacity = 0 + bs.broadcastmessage('Proceeding Round...') + for player in self.spawned: + if not player.done: + try: + player.survived = False + player.actor.handlemessage(bs.StandMessage((0,3,-2))) + bs.timer(0.5,bs.Call(player.actor.handlemessage, bs.FreezeMessage())) + bs.timer(1.5,bs.Call(player.actor.handlemessage, bs.FreezeMessage())) + bs.timer(2.5,bs.Call(player.actor.handlemessage, bs.FreezeMessage())) + bs.timer(3,bs.Call(player.actor.handlemessage, bs.ShouldShatterMessage())) + except: pass + bs.timer(3.5,self.killRound) + bs.timer(3.55,self.makeRound) + self.round_time_textnode.opacity = 0 + self.round_time = self.reset_round_time + else: + self.round_time_textnode.text = "Time: " + str(self.round_time) + self.round_time -= 1 def makeRound(self): for player in self.players: - if player.survived: - player.team.score += 1 + if player.survived: player.team.score += 1 self.roundNum += 1 self._textRound.text = 'Round ' + str(self.roundNum) self.flags = [] self.spawned = [] - angle = random.randint(0, 359) - c = 0 + self.should_die_occur = True + self.round_time = self.reset_round_time + self.round_time_textnode.opacity = 1 + angle = random.randint(0,359) + c=0 for player in self.players: - if player.survived: - c += 1 + if player.survived: c+=1 spacing = 10 for player in self.players: player.done = False if player.survived: if not player.is_alive(): - self.spawn_player(player, (.5, 5, -4)) + self.spawn_player(player,(.5,5,-4)) self.spawned.append(player) - try: - spacing = 360 // (c) - except: - self.checkEnd() - colors = [(1, 0, 0), (0, 1, 0), (0, 0, 1), (1, 1, 0), (1, 0, 1), (0, 1, 1), (0, 0, 0), - (0.5, 0.8, 0), (0, 0.8, 0.5), (0.8, 0.25, 0.7), (0, 0.27, 0.55), (2, 2, 0.6), (0.4, 3, 0.85)] + try: spacing = 360 // (c) + except: self.checkEnd() + colors = [(1,0,0),(0,1,0),(0,0,1),(1,1,0),(1,0,1),(0,1,1),(0,0,0),(0.5,0.8,0),(0,0.8,0.5),(0.8,0.25,0.7),(0,0.27,0.55),(2,2,0.6),(0.4,3,0.85)] + + # Add support for more than 13 players + if c > 12: + for i in range(c-12): + colors.append((random.uniform(0.1, 1), random.uniform(0.1, 1), random.uniform(0.1, 1))) + # Smart Mathematics: # All Flags spawn same distance from the players for i in range(c-1): angle += spacing angle %= 360 - x = 6 * math.sin(math.degrees(angle)) - z = 6 * math.cos(math.degrees(angle)) - flag = Flag(position=(x+.5, 5, z-4), color=colors[i]).autoretain() + x=6 * math.sin(math.degrees(angle)) + z=6 * math.cos(math.degrees(angle)) + flag = Flag(position=(x+.5,5,z-4), color=colors[i]).autoretain() self.flags.append(flag) def killRound(self): self.numPickedUp = 0 for player in self.players: - if player.is_alive(): - player.actor.handlemessage(ba.DieMessage()) - for flag in self.flags: - flag.node.delete() - for light in self.nodes: - light.delete() - - def spawn_player(self, player: Player, pos: tuple = (0, 0, 0)) -> ba.Actor: + if player.is_alive(): player.actor.handlemessage(bs.DieMessage()) + for flag in self.flags: flag.node.delete() + for light in self.nodes: light.delete() + + def spawn_player(self, player: Player, pos: tuple = (0,0,0)) -> bs.Actor: spaz = self.spawn_player_spaz(player) - if pos == (0, 0, 0): - pos = (-.5+random.random()*2, 3+random.random()*2, -5+random.random()*2) - spaz.connect_controls_to_player(enable_punch=self.is_punch, - enable_bomb=False, enable_run=self.is_run) - spaz.handlemessage(ba.StandMessage(pos)) + if pos == (0,0,0): + pos = (-.5+random.random()*2,3+random.random()*2,-5+random.random()*2) + spaz.connect_controls_to_player(enable_punch=self.is_punch, enable_bomb=False, enable_run=self.is_run) + spaz.handlemessage(bs.StandMessage(pos)) return spaz def check_respawn(self, player): @@ -200,36 +222,37 @@ def check_respawn(self, player): def handlemessage(self, msg: Any) -> Any: - if isinstance(msg, ba.PlayerDiedMessage): + if isinstance(msg, bs.PlayerDiedMessage): super().handlemessage(msg) player = msg.getplayer(Player) - ba.timer(0.1, ba.Call(self.check_respawn, player)) - ba.timer(0.5, self.checkEnd) + bs.timer(0.1, bs.Call(self.check_respawn, player)) + bs.timer(0.5, self.checkEnd) elif isinstance(msg, FlagPickedUpMessage): self.numPickedUp += 1 msg.node.getdelegate(PlayerSpaz, True).getplayer(Player, True).done = True - l = ba.newnode('light', - owner=None, - attrs={'color': msg.node.color, - 'position': (msg.node.position_center), - 'intensity': 1}) + l = bs.newnode('light', + owner=None, + attrs={'color':msg.node.color, + 'position':(msg.node.position_center), + 'intensity':1}) self.nodes.append(l) - msg.flag.handlemessage(ba.DieMessage()) - msg.node.handlemessage(ba.DieMessage()) + msg.flag.handlemessage(bs.DieMessage()) + msg.node.handlemessage(bs.DieMessage()) msg.node.delete() if self.numPickedUp == len(self.flags): + self.round_time_textnode.opacity = 0 + self.round_time = self.reset_round_time for player in self.spawned: if not player.done: try: player.survived = False - ba.screenmessage("No Flag? "+player.getname()) - player.actor.handlemessage(ba.StandMessage((0, 3, -2))) - ba.timer(0.5, ba.Call(player.actor.handlemessage, ba.FreezeMessage())) - ba.timer(3, ba.Call(player.actor.handlemessage, ba.ShouldShatterMessage())) - except: - pass - ba.timer(3.5, self.killRound) - ba.timer(3.55, self.makeRound) + bs.broadcastmessage("No Flag? "+player.getname()) + player.actor.handlemessage(bs.StandMessage((0,3,-2))) + bs.timer(0.5,bs.Call(player.actor.handlemessage, bs.FreezeMessage())) + bs.timer(3,bs.Call(player.actor.handlemessage, bs.ShouldShatterMessage())) + except: pass + bs.timer(3.5,self.killRound) + bs.timer(3.55,self.makeRound) else: return super().handlemessage(msg) return None @@ -238,15 +261,15 @@ def checkEnd(self): i = 0 for player in self.players: if player.survived: - i += 1 + i+=1 if i <= 1: for player in self.players: if player.survived: player.team.score += 10 - ba.timer(2.5, self.end_game) + bs.timer(2.5, self.end_game) def end_game(self) -> None: - results = ba.GameResults() + results = bs.GameResults() for team in self.teams: results.set_team_score(team, team.score) - self.end(results=results) + self.end(results=results) \ No newline at end of file diff --git a/plugins/minigames/volleyball.py b/plugins/minigames/volleyball.py index d4aeacc1..b2559503 100644 --- a/plugins/minigames/volleyball.py +++ b/plugins/minigames/volleyball.py @@ -1,16 +1,22 @@ # Volley Ball (final) -# Made by your friend: Freaku / @[Just] Freak#4999 +# Made by your friend: Freaku + + # Join BCS: # https://discord.gg/ucyaesh + + # My GitHub: # https://github.com/Freaku17/BombSquad-Mods-byFreaku + + # CHANGELOG: """ ## 2021 @@ -28,30 +34,37 @@ ## 2022 - Code cleanup -- No longer requires a plugin - More accurate Goal positions """ -# ba_meta require api 7 + + + + + + + + +# ba_meta require api 8 from __future__ import annotations from typing import TYPE_CHECKING -import _ba -import ba -import random -from bastd.actor.playerspaz import PlayerSpaz -from bastd.actor.scoreboard import Scoreboard -from bastd.actor.powerupbox import PowerupBoxFactory -from bastd.actor.bomb import BombFactory -from bastd.gameutils import SharedObjects +import babase, random +import bascenev1 as bs +from bascenev1lib.actor.playerspaz import PlayerSpaz +from bascenev1lib.actor.scoreboard import Scoreboard +from bascenev1lib.actor.powerupbox import PowerupBoxFactory +from bascenev1lib.actor.bomb import BombFactory +from bascenev1lib.gameutils import SharedObjects if TYPE_CHECKING: from typing import Any, Sequence, Dict, Type, List, Optional, Union + class PuckDiedMessage: """Inform something that a puck has died.""" @@ -59,7 +72,7 @@ def __init__(self, puck: Puck): self.puck = puck -class Puck(ba.Actor): +class Puck(bs.Actor): def __init__(self, position: Sequence[float] = (0.0, 1.0, 0.0)): super().__init__() shared = SharedObjects.get() @@ -72,30 +85,31 @@ def __init__(self, position: Sequence[float] = (0.0, 1.0, 0.0)): assert activity is not None assert isinstance(activity, VolleyBallGame) pmats = [shared.object_material, activity.puck_material] - self.node = ba.newnode('prop', + self.node = bs.newnode('prop', delegate=self, attrs={ - 'model': activity.puck_model, + 'mesh': activity.puck_mesh, 'color_texture': activity.puck_tex, 'body': 'sphere', 'reflection': 'soft', 'reflection_scale': [0.2], 'shadow_size': 0.6, - 'model_scale': 0.4, + 'mesh_scale': 0.4, 'body_scale': 1.07, 'is_area_of_interest': True, 'position': self._spawn_pos, 'materials': pmats }) - + # Since it rolls on spawn, lets make gravity # to 0, and when another node (bomb/spaz) # touches it. It'll act back as our normie puck! - ba.animate(self.node, 'gravity_scale', {0: -0.1, 0.2: 1}, False) + bs.animate(self.node, 'gravity_scale', {0:-0.1, 0.2:1}, False) # When other node touches, it realises its new gravity_scale + def handlemessage(self, msg: Any) -> Any: - if isinstance(msg, ba.DieMessage): + if isinstance(msg, bs.DieMessage): assert self.node self.node.delete() activity = self._activity() @@ -103,11 +117,11 @@ def handlemessage(self, msg: Any) -> Any: activity.handlemessage(PuckDiedMessage(self)) # If we go out of bounds, move back to where we started. - elif isinstance(msg, ba.OutOfBoundsMessage): + elif isinstance(msg, bs.OutOfBoundsMessage): assert self.node self.node.position = self._spawn_pos - elif isinstance(msg, ba.HitMessage): + elif isinstance(msg, bs.HitMessage): assert self.node assert msg.force_direction is not None self.node.handlemessage( @@ -128,29 +142,28 @@ def handlemessage(self, msg: Any) -> Any: super().handlemessage(msg) -class Player(ba.Player['Team']): +class Player(bs.Player['Team']): """Our player type for this game.""" -class Team(ba.Team[Player]): +class Team(bs.Team[Player]): """Our team type for this game.""" - def __init__(self) -> None: self.score = 0 -# ba_meta export game -class VolleyBallGame(ba.TeamGameActivity[Player, Team]): +# ba_meta export bascenev1.GameActivity +class VolleyBallGame(bs.TeamGameActivity[Player, Team]): name = 'Volley Ball' description = 'Score some goals.\nby \ue048Freaku' available_settings = [ - ba.IntSetting( + bs.IntSetting( 'Score to Win', min_value=1, default=1, increment=1, ), - ba.IntChoiceSetting( + bs.IntChoiceSetting( 'Time Limit', choices=[ ('None', 0), @@ -162,7 +175,7 @@ class VolleyBallGame(ba.TeamGameActivity[Player, Team]): ], default=0, ), - ba.FloatChoiceSetting( + bs.FloatChoiceSetting( 'Respawn Times', choices=[ ('Shorter', 0.25), @@ -173,36 +186,36 @@ class VolleyBallGame(ba.TeamGameActivity[Player, Team]): ], default=1.0, ), - ba.BoolSetting('Epic Mode', True), - ba.BoolSetting('Night Mode', False), - ba.BoolSetting('Icy Floor', True), - ba.BoolSetting('Disable Punch', False), - ba.BoolSetting('Disable Bombs', False), - ba.BoolSetting('Enable Bottom Credits', True), + bs.BoolSetting('Epic Mode', True), + bs.BoolSetting('Night Mode', False), + bs.BoolSetting('Icy Floor', True), + bs.BoolSetting('Disable Punch', False), + bs.BoolSetting('Disable Bombs', False), + bs.BoolSetting('Enable Bottom Credits', True), ] - default_music = ba.MusicType.HOCKEY + default_music = bs.MusicType.HOCKEY @classmethod - def supports_session_type(cls, sessiontype: Type[ba.Session]) -> bool: - return issubclass(sessiontype, ba.DualTeamSession) + def supports_session_type(cls, sessiontype: Type[bs.Session]) -> bool: + return issubclass(sessiontype, bs.DualTeamSession) @classmethod - def get_supported_maps(cls, sessiontype: Type[ba.Session]) -> List[str]: + def get_supported_maps(cls, sessiontype: Type[bs.Session]) -> List[str]: return ['Open Field', 'Closed Arena'] def __init__(self, settings: dict): super().__init__(settings) 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.puck_model = ba.getmodel('shield') - self.puck_tex = ba.gettexture('gameCircleIcon') - self._puck_sound = ba.getsound('metalHit') - self.puck_material = ba.Material() + self._cheer_sound = bs.getsound('cheer') + self._chant_sound = bs.getsound('crowdChant') + self._foghorn_sound = bs.getsound('foghorn') + self._swipsound = bs.getsound('swip') + self._whistle_sound = bs.getsound('refWhistle') + self.puck_mesh = bs.getmesh('shield') + self.puck_tex = bs.gettexture('gameCircleIcon') + self._puck_sound = bs.getsound('metalHit') + self.puck_material = bs.Material() self.puck_material.add_actions(actions=(('modify_part_collision', 'friction', 0.5))) self.puck_material.add_actions(conditions=('they_have_material', @@ -233,21 +246,22 @@ def __init__(self, settings: dict): 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() + ('message', 'their_node', 'at_connect', bs.DieMessage()))) + self._score_region_material = bs.Material() self._score_region_material.add_actions( conditions=('they_have_material', self.puck_material), actions=(('modify_part_collision', 'collide', True), ('modify_part_collision', 'physical', False), ('call', 'at_connect', self._handle_score))) - - self._wall_material = ba.Material() - self._fake_wall_material = ba.Material() + + + self._wall_material=bs.Material() + self._fake_wall_material=bs.Material() self._wall_material.add_actions( - + actions=( ('modify_part_collision', 'friction', 100000), - )) + )) self._wall_material.add_actions( conditions=('they_have_material', shared.pickup_material), actions=( @@ -256,13 +270,13 @@ def __init__(self, settings: dict): self._wall_material.add_actions( conditions=(('we_are_younger_than', 100), - 'and', - ('they_have_material', shared.object_material)), + 'and', + ('they_have_material',shared.object_material)), actions=( ('modify_part_collision', 'collide', False), )) self._wall_material.add_actions( - conditions=('they_have_material', shared.footing_material), + conditions=('they_have_material',shared.footing_material), actions=( ('modify_part_collision', 'friction', 9999.5), )) @@ -271,24 +285,25 @@ def __init__(self, settings: dict): actions=( ('modify_part_collision', 'collide', False), ('modify_part_collision', 'physical', False) - + )) self._fake_wall_material.add_actions( conditions=('they_have_material', shared.player_material), actions=( ('modify_part_collision', 'collide', True), ('modify_part_collision', 'physical', True) - + )) - self.blocks = [] + self.blocks=[] + - self._net_wall_material = ba.Material() + self._net_wall_material=bs.Material() self._net_wall_material.add_actions( conditions=('they_have_material', shared.player_material), actions=( ('modify_part_collision', 'collide', True), ('modify_part_collision', 'physical', True) - + )) self._net_wall_material.add_actions( @@ -306,10 +321,11 @@ def __init__(self, settings: dict): actions=( ('modify_part_collision', 'collide', True), )) - self.net_blocc = [] + self.net_blocc=[] + self._puck_spawn_pos: Optional[Sequence[float]] = None - self._score_regions: Optional[List[ba.NodeActor]] = None + self._score_regions: Optional[List[bs.NodeActor]] = None self._puck: Optional[Puck] = None self._score_to_win = int(settings['Score to Win']) self._punchie_ = bool(settings['Disable Punch']) @@ -321,8 +337,8 @@ def __init__(self, settings: dict): self._epic_mode = bool(settings['Epic Mode']) # Base class overrides. self.slow_motion = self._epic_mode - self.default_music = (ba.MusicType.EPIC if self._epic_mode else - ba.MusicType.TO_THE_DEATH) + self.default_music = (bs.MusicType.EPIC if self._epic_mode else + bs.MusicType.TO_THE_DEATH) def get_instance_description(self) -> Union[str, Sequence]: if self._score_to_win == 1: @@ -339,60 +355,58 @@ def on_begin(self) -> None: self.setup_standard_time_limit(self._time_limit) if self._night_mode: - ba.getactivity().globalsnode.tint = (0.5, 0.7, 1) + bs.getactivity().globalsnode.tint = (0.5, 0.7, 1) self._puck_spawn_pos = self.map.get_flag_position(None) self._spawn_puck() # Set up the two score regions. self._score_regions = [] self._score_regions.append( - ba.NodeActor( - ba.newnode('region', + bs.NodeActor( + bs.newnode('region', attrs={ - 'position': (5.7, 0, -0.065), + 'position':(5.7, 0, -0.065), 'scale': (10.7, 0.001, 8), 'type': 'box', 'materials': [self._score_region_material] }))) self._score_regions.append( - ba.NodeActor( - ba.newnode('region', + bs.NodeActor( + bs.newnode('region', attrs={ - 'position': (-5.7, 0, -0.065), + 'position':(-5.7, 0, -0.065), 'scale': (10.7, 0.001, 8), 'type': 'box', 'materials': [self._score_region_material] }))) self._update_scoreboard() - ba.playsound(self._chant_sound) + self._chant_sound.play() if self.credit_text: - t = ba.newnode('text', - attrs={'text': "Created by Freaku\nVolleyBall", # Disable 'Enable Bottom Credits' when making playlist, No need to edit this lovely... - 'scale': 0.7, - 'position': (0, 0), - 'shadow': 0.5, - 'flatness': 1.2, - 'color': (1, 1, 1), - 'h_align': 'center', - 'v_attach': 'bottom'}) + t = bs.newnode('text', + attrs={ 'text':"Created by Freaku\nVolleyBall", ## Disable 'Enable Bottom Credits' when making playlist, No need to edit this lovely... + 'scale':0.7, + 'position':(0,0), + 'shadow':0.5, + 'flatness':1.2, + 'color':(1, 1, 1), + 'h_align':'center', + 'v_attach':'bottom'}) shared = SharedObjects.get() - self.blocks.append(ba.NodeActor(ba.newnode('region', attrs={'position': (0, 2.4, 0), 'scale': ( - 0.8, 6, 20), 'type': 'box', 'materials': (self._fake_wall_material, )}))) - - self.net_blocc.append(ba.NodeActor(ba.newnode('region', attrs={'position': (0, 0, 0), 'scale': ( - 0.6, 2.4, 20), 'type': 'box', 'materials': (self._net_wall_material, )}))) + self.blocks.append(bs.NodeActor(bs.newnode('region',attrs={'position': (0,2.4,0),'scale': (0.8,6,20),'type': 'box','materials': (self._fake_wall_material, )}))) + + self.net_blocc.append(bs.NodeActor(bs.newnode('region',attrs={'position': (0,0,0),'scale': (0.6,2.4,20),'type': 'box','materials': (self._net_wall_material, )}))) def on_team_join(self, team: Team) -> None: self._update_scoreboard() def _handle_puck_player_collide(self) -> None: - collision = ba.getcollision() + collision = bs.getcollision() try: puck = collision.sourcenode.getdelegate(Puck, True) player = collision.opposingnode.getdelegate(PlayerSpaz, True).getplayer( Player, True) - except ba.NotFoundError: + except bs.NotFoundError: return puck.last_players_to_touch[player.team.id] = player @@ -409,7 +423,7 @@ def _handle_score(self) -> None: if self._puck.scored: return - region = ba.getcollision().sourcenode + region = bs.getcollision().sourcenode index = 0 for index in range(len(self._score_regions)): if region == self._score_regions[index].node: @@ -420,18 +434,21 @@ def _handle_score(self) -> None: scoring_team = team team.score += 1 + + # Change puck Spawn - if team.id == 0: # left side scored - self._puck_spawn_pos = (5, 0.42, 0) - elif team.id == 1: # right side scored - self._puck_spawn_pos = (-5, 0.42, 0) - else: # normally shouldn't occur - self._puck_spawn_pos = (0, 0.42, 0) + if team.id == 0: # left side scored + self._puck_spawn_pos= (5, 0.42, 0) + elif team.id == 1: # right side scored + self._puck_spawn_pos= (-5, 0.42, 0) + else: # normally shouldn't occur + self._puck_spawn_pos= (0, 0.42, 0) # Easy pizzy - + + for player in team.players: if player.actor: - player.actor.handlemessage(ba.CelebrateMessage(2.0)) + player.actor.handlemessage(bs.CelebrateMessage(2.0)) # If we've got the player from the scoring team that last # touched us, give them points. @@ -446,28 +463,28 @@ def _handle_score(self) -> None: if team.score >= self._score_to_win: self.end_game() - ba.playsound(self._foghorn_sound) - ba.playsound(self._cheer_sound) + self._foghorn_sound.play() + self._cheer_sound.play() self._puck.scored = True # Kill the puck (it'll respawn itself shortly). - ba.emitfx(position=ba.getcollision().position, count=int( - 6.0 + 7.0 * 12), scale=3, spread=0.5, chunk_type='spark') - ba.timer(0.7, self._kill_puck) + bs.emitfx(position= bs.getcollision().position, count=int(6.0 + 7.0 * 12), scale=3, spread=0.5, chunk_type='spark') + bs.timer(0.7, self._kill_puck) + - ba.cameraflash(duration=7.0) + bs.cameraflash(duration=7.0) self._update_scoreboard() def end_game(self) -> None: - results = ba.GameResults() + results = bs.GameResults() for team in self.teams: results.set_team_score(team, team.score) self.end(results=results) def on_transition_in(self) -> None: super().on_transition_in() - activity = ba.getactivity() + activity = bs.getactivity() if self._icy_flooor: activity.map.is_hockey = True @@ -477,7 +494,7 @@ def _update_scoreboard(self) -> None: self._scoreboard.set_team_value(team, team.score, winscore) # overriding the default character spawning.. - def spawn_player(self, player: Player) -> ba.Actor: + def spawn_player(self, player: Player) -> bs.Actor: spaz = self.spawn_player_spaz(player) if self._bombies_: @@ -485,6 +502,7 @@ def spawn_player(self, player: Player) -> ba.Actor: spaz.bomb_count = 0 # Imagine not being able to swipe those colorful buttons ;( + if self._punchie_: spaz.connect_controls_to_player(enable_punch=False) @@ -493,7 +511,7 @@ def spawn_player(self, player: Player) -> ba.Actor: def handlemessage(self, msg: Any) -> Any: # Respawn dead players if they're still in the game. - if isinstance(msg, ba.PlayerDiedMessage): + if isinstance(msg, bs.PlayerDiedMessage): # Augment standard behavior... super().handlemessage(msg) self.respawn_player(msg.getplayer(Player)) @@ -501,44 +519,62 @@ def handlemessage(self, msg: Any) -> Any: # Respawn dead pucks. elif isinstance(msg, PuckDiedMessage): if not self.has_ended(): - ba.timer(2.2, self._spawn_puck) + bs.timer(2.2, self._spawn_puck) else: super().handlemessage(msg) def _flash_puck_spawn(self) -> None: # Effect >>>>>> Flashly - ba.emitfx(position=self._puck_spawn_pos, count=int( - 6.0 + 7.0 * 12), scale=1.7, spread=0.4, chunk_type='spark') + bs.emitfx(position= self._puck_spawn_pos, count=int(6.0 + 7.0 * 12), scale=1.7, spread=0.4, chunk_type='spark') def _spawn_puck(self) -> None: - ba.playsound(self._swipsound) - ba.playsound(self._whistle_sound) + self._swipsound.play() + self._whistle_sound.play() self._flash_puck_spawn() assert self._puck_spawn_pos is not None self._puck = Puck(position=self._puck_spawn_pos) + + + + + + + + + + + + + + + + + + + + + class Pointzz: points, boxes = {}, {} points['spawn1'] = (-8.03866, 0.02275, 0.0) + (0.5, 0.05, 4.0) points['spawn2'] = (8.82311, 0.01092, 0.0) + (0.5, 0.05, 4.0) - boxes['area_of_interest_bounds'] = (0.0, 1.18575, 0.43262) + \ - (0, 0, 0) + (29.81803, 11.57249, 18.89134) + boxes['area_of_interest_bounds'] = (0.0, 1.18575, 0.43262) + (0, 0, 0) + (29.81803, 11.57249, 18.89134) boxes['map_bounds'] = (0.0, 1.185751251, 0.4326226188) + (0.0, 0.0, 0.0) + ( - 42.09506485, 22.81173179, 29.76723155) - + 42.09506485, 22.81173179, 29.76723155) class PointzzforH: points, boxes = {}, {} - boxes['area_of_interest_bounds'] = (0.0, 0.7956858119, 0.0) + \ - (0.0, 0.0, 0.0) + (30.80223883, 0.5961646365, 13.88431707) + boxes['area_of_interest_bounds'] = (0.0, 0.7956858119, 0.0) + (0.0, 0.0, 0.0) + (30.80223883, 0.5961646365, 13.88431707) boxes['map_bounds'] = (0.0, 0.7956858119, -0.4689020853) + (0.0, 0.0, 0.0) + ( - 35.16182389, 12.18696164, 21.52869693) + 35.16182389, 12.18696164, 21.52869693) points['spawn1'] = (-6.835352227, 0.02305323209, 0.0) + (1.0, 1.0, 3.0) points['spawn2'] = (6.857415055, 0.03938567998, 0.0) + (1.0, 1.0, 3.0) -class VolleyBallMap(ba.Map): + +class VolleyBallMap(bs.Map): defs = Pointzz() name = "Open Field" @@ -553,72 +589,72 @@ def get_preview_texture_name(cls) -> str: @classmethod def on_preload(cls) -> Any: data: Dict[str, Any] = { - 'model': ba.getmodel('footballStadium'), - 'vr_fill_model': ba.getmodel('footballStadiumVRFill'), - 'collide_model': ba.getcollidemodel('footballStadiumCollide'), - 'tex': ba.gettexture('footballStadium') + 'mesh': bs.getmesh('footballStadium'), + 'vr_fill_mesh': bs.getmesh('footballStadiumVRFill'), + 'collision_mesh': bs.getcollisionmesh('footballStadiumCollide'), + 'tex': bs.gettexture('footballStadium') } return data - + def __init__(self): super().__init__() shared = SharedObjects.get() x = -5 - while x < 5: - self.zone = ba.newnode('locator', attrs={'shape': 'circle', 'position': (0, 0, x), - 'color': (1, 1, 0), 'opacity': 1, 'draw_beauty': True, 'additive': False, 'size': [0.40]}) - self.zone = ba.newnode('locator', attrs={'shape': 'circle', 'position': (0, .25, x), - 'color': (1, 1, 0), 'opacity': 1, 'draw_beauty': True, 'additive': False, 'size': [0.40]}) - self.zone = ba.newnode('locator', attrs={'shape': 'circle', 'position': (0, .5, x), - 'color': (1, 1, 0), 'opacity': 1, 'draw_beauty': True, 'additive': False, 'size': [0.40]}) - self.zone = ba.newnode('locator', attrs={'shape': 'circle', 'position': (0, .75, x), - 'color': (1, 1, 0), 'opacity': 1, 'draw_beauty': True, 'additive': False, 'size': [0.40]}) - self.zone = ba.newnode('locator', attrs={'shape': 'circle', 'position': (0, 1, x), - 'color': (1, 1, 0), 'opacity': 1, 'draw_beauty': True, 'additive': False, 'size': [0.40]}) + while x<5: + self.zone = bs.newnode('locator',attrs={'shape':'circle','position':(0,0,x), + 'color':(1,1,0),'opacity':1,'draw_beauty':True,'additive':False,'size':[0.40]}) + self.zone = bs.newnode('locator',attrs={'shape':'circle','position':(0,.25,x), + 'color':(1,1,0),'opacity':1,'draw_beauty':True,'additive':False,'size':[0.40]}) + self.zone = bs.newnode('locator',attrs={'shape':'circle','position':(0,.5,x), + 'color':(1,1,0),'opacity':1,'draw_beauty':True,'additive':False,'size':[0.40]}) + self.zone = bs.newnode('locator',attrs={'shape':'circle','position':(0,.75,x), + 'color':(1,1,0),'opacity':1,'draw_beauty':True,'additive':False,'size':[0.40]}) + self.zone = bs.newnode('locator',attrs={'shape':'circle','position':(0,1,x), + 'color':(1,1,0),'opacity':1,'draw_beauty':True,'additive':False,'size':[0.40]}) x = x + 0.5 y = -1 - while y > -11: - self.zone = ba.newnode('locator', attrs={'shape': 'circle', 'position': (y, 0.01, 4), - 'color': (0, 0, 1), 'opacity': 1, 'draw_beauty': True, 'additive': False, 'size': [0.40]}) - self.zone = ba.newnode('locator', attrs={'shape': 'circle', 'position': (y, 0.01, -4), - 'color': (0, 0, 1), 'opacity': 1, 'draw_beauty': True, 'additive': False, 'size': [0.40]}) - self.zone = ba.newnode('locator', attrs={'shape': 'circle', 'position': (-y, 0.01, 4), - 'color': (1, 0, 0), 'opacity': 1, 'draw_beauty': True, 'additive': False, 'size': [0.40]}) - self.zone = ba.newnode('locator', attrs={'shape': 'circle', 'position': (-y, 0.01, -4), - 'color': (1, 0, 0), 'opacity': 1, 'draw_beauty': True, 'additive': False, 'size': [0.40]}) - y -= 1 + while y>-11: + self.zone = bs.newnode('locator',attrs={'shape':'circle','position':(y,0.01,4), + 'color':(0,0,1),'opacity':1,'draw_beauty':True,'additive':False,'size':[0.40]}) + self.zone = bs.newnode('locator',attrs={'shape':'circle','position':(y,0.01,-4), + 'color':(0,0,1),'opacity':1,'draw_beauty':True,'additive':False,'size':[0.40]}) + self.zone = bs.newnode('locator',attrs={'shape':'circle','position':(-y,0.01,4), + 'color':(1,0,0),'opacity':1,'draw_beauty':True,'additive':False,'size':[0.40]}) + self.zone = bs.newnode('locator',attrs={'shape':'circle','position':(-y,0.01,-4), + 'color':(1,0,0),'opacity':1,'draw_beauty':True,'additive':False,'size':[0.40]}) + y-=1 z = 0 - while z < 5: - self.zone = ba.newnode('locator', attrs={'shape': 'circle', 'position': (11, 0.01, z), - 'color': (1, 0, 0), 'opacity': 1, 'draw_beauty': True, 'additive': False, 'size': [0.40]}) - self.zone = ba.newnode('locator', attrs={'shape': 'circle', 'position': (11, 0.01, -z), - 'color': (1, 0, 0), 'opacity': 1, 'draw_beauty': True, 'additive': False, 'size': [0.40]}) - self.zone = ba.newnode('locator', attrs={'shape': 'circle', 'position': (-11, 0.01, z), - 'color': (0, 0, 1), 'opacity': 1, 'draw_beauty': True, 'additive': False, 'size': [0.40]}) - self.zone = ba.newnode('locator', attrs={'shape': 'circle', 'position': (-11, 0.01, -z), - 'color': (0, 0, 1), 'opacity': 1, 'draw_beauty': True, 'additive': False, 'size': [0.40]}) - z += 1 - - self.node = ba.newnode( + while z<5: + self.zone = bs.newnode('locator',attrs={'shape':'circle','position':(11,0.01,z), + 'color':(1,0,0),'opacity':1,'draw_beauty':True,'additive':False,'size':[0.40]}) + self.zone = bs.newnode('locator',attrs={'shape':'circle','position':(11,0.01,-z), + 'color':(1,0,0),'opacity':1,'draw_beauty':True,'additive':False,'size':[0.40]}) + self.zone = bs.newnode('locator',attrs={'shape':'circle','position':(-11,0.01,z), + 'color':(0,0,1),'opacity':1,'draw_beauty':True,'additive':False,'size':[0.40]}) + self.zone = bs.newnode('locator',attrs={'shape':'circle','position':(-11,0.01,-z), + 'color':(0,0,1),'opacity':1,'draw_beauty':True,'additive':False,'size':[0.40]}) + z+=1 + + self.node = bs.newnode( 'terrain', delegate=self, attrs={ - 'model': self.preloaddata['model'], - 'collide_model': self.preloaddata['collide_model'], + 'mesh': self.preloaddata['mesh'], + 'collision_mesh': self.preloaddata['collision_mesh'], 'color_texture': self.preloaddata['tex'], 'materials': [shared.footing_material] }) - ba.newnode('terrain', + bs.newnode('terrain', attrs={ - 'model': self.preloaddata['vr_fill_model'], + 'mesh': self.preloaddata['vr_fill_mesh'], 'lighting': False, 'vr_only': True, 'background': True, 'color_texture': self.preloaddata['tex'] }) - gnode = ba.getactivity().globalsnode + gnode = bs.getactivity().globalsnode gnode.tint = (1.3, 1.2, 1.0) gnode.ambient_color = (1.3, 1.2, 1.0) gnode.vignette_outer = (0.57, 0.57, 0.57) @@ -627,7 +663,8 @@ def __init__(self): gnode.vr_near_clip = 0.5 -class VolleyBallMapH(ba.Map): + +class VolleyBallMapH(bs.Map): defs = PointzzforH() name = 'Closed Arena' @@ -642,13 +679,13 @@ def get_preview_texture_name(cls) -> str: @classmethod def on_preload(cls) -> Any: data: Dict[str, Any] = { - 'models': (ba.getmodel('hockeyStadiumOuter'), - ba.getmodel('hockeyStadiumInner')), - 'vr_fill_model': ba.getmodel('footballStadiumVRFill'), - 'collide_model': ba.getcollidemodel('hockeyStadiumCollide'), - 'tex': ba.gettexture('hockeyStadium'), + 'meshs': (bs.getmesh('hockeyStadiumOuter'), + bs.getmesh('hockeyStadiumInner')), + 'vr_fill_mesh': bs.getmesh('footballStadiumVRFill'), + 'collision_mesh': bs.getcollisionmesh('hockeyStadiumCollide'), + 'tex': bs.gettexture('hockeyStadium'), } - mat = ba.Material() + mat = bs.Material() mat.add_actions(actions=('modify_part_collision', 'friction', 0.01)) data['ice_material'] = mat return data @@ -657,84 +694,83 @@ def __init__(self) -> None: super().__init__() shared = SharedObjects.get() x = -5 - while x < 5: - self.zone = ba.newnode('locator', attrs={'shape': 'circle', 'position': (0, 0, x), - 'color': (1, 1, 0), 'opacity': 1, 'draw_beauty': True, 'additive': False, 'size': [0.40]}) - self.zone = ba.newnode('locator', attrs={'shape': 'circle', 'position': (0, .25, x), - 'color': (1, 1, 0), 'opacity': 1, 'draw_beauty': True, 'additive': False, 'size': [0.40]}) - self.zone = ba.newnode('locator', attrs={'shape': 'circle', 'position': (0, .5, x), - 'color': (1, 1, 0), 'opacity': 1, 'draw_beauty': True, 'additive': False, 'size': [0.40]}) - self.zone = ba.newnode('locator', attrs={'shape': 'circle', 'position': (0, .75, x), - 'color': (1, 1, 0), 'opacity': 1, 'draw_beauty': True, 'additive': False, 'size': [0.40]}) - self.zone = ba.newnode('locator', attrs={'shape': 'circle', 'position': (0, 1, x), - 'color': (1, 1, 0), 'opacity': 1, 'draw_beauty': True, 'additive': False, 'size': [0.40]}) + while x<5: + self.zone = bs.newnode('locator',attrs={'shape':'circle','position':(0,0,x), + 'color':(1,1,0),'opacity':1,'draw_beauty':True,'additive':False,'size':[0.40]}) + self.zone = bs.newnode('locator',attrs={'shape':'circle','position':(0,.25,x), + 'color':(1,1,0),'opacity':1,'draw_beauty':True,'additive':False,'size':[0.40]}) + self.zone = bs.newnode('locator',attrs={'shape':'circle','position':(0,.5,x), + 'color':(1,1,0),'opacity':1,'draw_beauty':True,'additive':False,'size':[0.40]}) + self.zone = bs.newnode('locator',attrs={'shape':'circle','position':(0,.75,x), + 'color':(1,1,0),'opacity':1,'draw_beauty':True,'additive':False,'size':[0.40]}) + self.zone = bs.newnode('locator',attrs={'shape':'circle','position':(0,1,x), + 'color':(1,1,0),'opacity':1,'draw_beauty':True,'additive':False,'size':[0.40]}) x = x + 0.5 y = -1 - while y > -11: - self.zone = ba.newnode('locator', attrs={'shape': 'circle', 'position': (y, 0.01, 4), - 'color': (0, 0, 1), 'opacity': 1, 'draw_beauty': True, 'additive': False, 'size': [0.40]}) - self.zone = ba.newnode('locator', attrs={'shape': 'circle', 'position': (y, 0.01, -4), - 'color': (0, 0, 1), 'opacity': 1, 'draw_beauty': True, 'additive': False, 'size': [0.40]}) - self.zone = ba.newnode('locator', attrs={'shape': 'circle', 'position': (-y, 0.01, 4), - 'color': (1, 0, 0), 'opacity': 1, 'draw_beauty': True, 'additive': False, 'size': [0.40]}) - self.zone = ba.newnode('locator', attrs={'shape': 'circle', 'position': (-y, 0.01, -4), - 'color': (1, 0, 0), 'opacity': 1, 'draw_beauty': True, 'additive': False, 'size': [0.40]}) - y -= 1 + while y>-11: + self.zone = bs.newnode('locator',attrs={'shape':'circle','position':(y,0.01,4), + 'color':(0,0,1),'opacity':1,'draw_beauty':True,'additive':False,'size':[0.40]}) + self.zone = bs.newnode('locator',attrs={'shape':'circle','position':(y,0.01,-4), + 'color':(0,0,1),'opacity':1,'draw_beauty':True,'additive':False,'size':[0.40]}) + self.zone = bs.newnode('locator',attrs={'shape':'circle','position':(-y,0.01,4), + 'color':(1,0,0),'opacity':1,'draw_beauty':True,'additive':False,'size':[0.40]}) + self.zone = bs.newnode('locator',attrs={'shape':'circle','position':(-y,0.01,-4), + 'color':(1,0,0),'opacity':1,'draw_beauty':True,'additive':False,'size':[0.40]}) + y-=1 z = 0 - while z < 5: - self.zone = ba.newnode('locator', attrs={'shape': 'circle', 'position': (11, 0.01, z), - 'color': (1, 0, 0), 'opacity': 1, 'draw_beauty': True, 'additive': False, 'size': [0.40]}) - self.zone = ba.newnode('locator', attrs={'shape': 'circle', 'position': (11, 0.01, -z), - 'color': (1, 0, 0), 'opacity': 1, 'draw_beauty': True, 'additive': False, 'size': [0.40]}) - self.zone = ba.newnode('locator', attrs={'shape': 'circle', 'position': (-11, 0.01, z), - 'color': (0, 0, 1), 'opacity': 1, 'draw_beauty': True, 'additive': False, 'size': [0.40]}) - self.zone = ba.newnode('locator', attrs={'shape': 'circle', 'position': (-11, 0.01, -z), - 'color': (0, 0, 1), 'opacity': 1, 'draw_beauty': True, 'additive': False, 'size': [0.40]}) - z += 1 - - self.node = ba.newnode('terrain', + while z<5: + self.zone = bs.newnode('locator',attrs={'shape':'circle','position':(11,0.01,z), + 'color':(1,0,0),'opacity':1,'draw_beauty':True,'additive':False,'size':[0.40]}) + self.zone = bs.newnode('locator',attrs={'shape':'circle','position':(11,0.01,-z), + 'color':(1,0,0),'opacity':1,'draw_beauty':True,'additive':False,'size':[0.40]}) + self.zone = bs.newnode('locator',attrs={'shape':'circle','position':(-11,0.01,z), + 'color':(0,0,1),'opacity':1,'draw_beauty':True,'additive':False,'size':[0.40]}) + self.zone = bs.newnode('locator',attrs={'shape':'circle','position':(-11,0.01,-z), + 'color':(0,0,1),'opacity':1,'draw_beauty':True,'additive':False,'size':[0.40]}) + z+=1 + + self.node = bs.newnode('terrain', delegate=self, attrs={ - 'model': + 'mesh': None, - 'collide_model': - # we dont want Goalposts... - ba.getcollidemodel('footballStadiumCollide'), + 'collision_mesh': + bs.getcollisionmesh('footballStadiumCollide'), # we dont want Goalposts... 'color_texture': self.preloaddata['tex'], 'materials': [ shared.footing_material] }) - ba.newnode('terrain', + bs.newnode('terrain', attrs={ - 'model': self.preloaddata['vr_fill_model'], + 'mesh': self.preloaddata['vr_fill_mesh'], 'vr_only': True, 'lighting': False, 'background': True, }) mats = [shared.footing_material] - self.floor = ba.newnode('terrain', + self.floor = bs.newnode('terrain', attrs={ - 'model': self.preloaddata['models'][1], + 'mesh': self.preloaddata['meshs'][1], 'color_texture': self.preloaddata['tex'], 'opacity': 0.92, 'opacity_in_low_or_medium_quality': 1.0, 'materials': mats, - 'color': (0.4, 0.9, 0) + 'color': (0.4,0.9,0) }) - self.background = ba.newnode( + self.background = bs.newnode( 'terrain', attrs={ - 'model': ba.getmodel('natureBackground'), + 'mesh': bs.getmesh('natureBackground'), 'lighting': False, 'background': True, - 'color': (0.5, 0.30, 0.4) + 'color': (0.5,0.30,0.4) }) - gnode = ba.getactivity().globalsnode + gnode = bs.getactivity().globalsnode gnode.floor_reflection = True gnode.debris_friction = 0.3 gnode.debris_kill_height = -0.3 @@ -747,5 +783,19 @@ def __init__(self) -> None: #self.is_hockey = True -ba._map.register_map(VolleyBallMap) -ba._map.register_map(VolleyBallMapH) + + +bs._map.register_map(VolleyBallMap) +bs._map.register_map(VolleyBallMapH) + + +# ba_meta export plugin +class byFreaku(babase.Plugin): + def __init__(self): + # Reason of plugin: + # To register maps. + # + # Then why not include function here? + # On server upon first launch, plugins are not activated, + # (same can be case for user if disabled auto-enable plugins) + pass \ No newline at end of file From d6dc6c246a781d416b66d5880bfa49add23b8149 Mon Sep 17 00:00:00 2001 From: ! Freaku <92618708+Freaku17@users.noreply.github.com> Date: Fri, 28 Jul 2023 17:03:36 +0530 Subject: [PATCH 0647/1464] Update my utilities for 1.7.20+ (API 8) --- plugins/utilities/floater.py | 134 ++++++++++++++-------------- plugins/utilities/icons_keyboard.py | 80 +++++++++-------- plugins/utilities/unlock_TowerD.py | 13 +-- 3 files changed, 118 insertions(+), 109 deletions(-) diff --git a/plugins/utilities/floater.py b/plugins/utilities/floater.py index d57e5931..c05b3a52 100644 --- a/plugins/utilities/floater.py +++ b/plugins/utilities/floater.py @@ -1,34 +1,35 @@ -# Ported by: Freaku / @[Just] Freak#4999 +# Ported by your friend: Freaku -# Join BCS: +#Join BCS: # https://discord.gg/ucyaesh -# My GitHub: +#My GitHub: # https://github.com/Freaku17/BombSquad-Mods-byFreaku -# ba_meta require api 7 + +# ba_meta require api 8 from __future__ import annotations from typing import TYPE_CHECKING -import _ba -import ba -import random -import math -from bastd.gameutils import SharedObjects -from bastd.actor.bomb import Bomb -from bastd.actor.popuptext import PopupText +import _babase, babase, random, math +import bauiv1 as bui +import bascenev1 as bs +from bascenev1lib.gameutils import SharedObjects +from bascenev1lib.actor.bomb import Bomb +from bascenev1lib.actor.popuptext import PopupText +from bauiv1lib.party import PartyWindow if TYPE_CHECKING: from typing import Optional -class Floater(ba.Actor): +class Floater(bs.Actor): def __init__(self, bounds): super().__init__() shared = SharedObjects.get() self.controlled = False self.source_player = None - self.floaterMaterial = ba.Material() + self.floaterMaterial = bs.Material() self.floaterMaterial.add_actions( conditions=('they_have_material', shared.player_material), @@ -48,21 +49,21 @@ def __init__(self, bounds): self.py = "random.uniform(self.pos[1],self.pos[4])" self.pz = "random.uniform(self.pos[2],self.pos[5])" - self.node = ba.newnode( + self.node = bs.newnode( 'prop', delegate=self, owner=None, attrs={ 'position': (eval(self.px), eval(self.py), eval(self.pz)), - 'model': - ba.getmodel('landMine'), - 'light_model': - ba.getmodel('landMine'), + 'mesh': + bs.getmesh('landMine'), + 'light_mesh': + bs.getmesh('landMine'), 'body': 'landMine', 'body_scale': 3, - 'model_scale': + 'mesh_scale': 3.1, 'shadow_size': 0.25, @@ -71,21 +72,21 @@ def __init__(self, bounds): 'gravity_scale': 0.0, 'color_texture': - ba.gettexture('achievementFlawlessVictory'), + bs.gettexture('achievementFlawlessVictory'), 'reflection': 'soft', 'reflection_scale': [0.25], 'materials': [shared.footing_material, self.floaterMaterial] }) - self.node2 = ba.newnode( + self.node2 = bs.newnode( 'prop', owner=self.node, attrs={ 'position': (0, 0, 0), 'body': 'sphere', - 'model': + 'mesh': None, 'color_texture': None, @@ -96,7 +97,7 @@ def __init__(self, bounds): 'density': 999999, 'reflection_scale': [1.0], - 'model_scale': + 'mesh_scale': 1.0, 'gravity_scale': 0, @@ -109,8 +110,7 @@ def __init__(self, bounds): }) self.node.connectattr('position', self.node2, 'position') - def pop(self): PopupText(text="Ported by \ue048Freaku", scale=1.3, position=( - self.node.position[0], self.node.position[1]-1, self.node.position[2]), color=(0, 1, 1)).autoretain() # Edit = YouNoob... + def pop(self): PopupText(text="Ported by \ue048Freaku", scale=1.3, position=(self.node.position[0],self.node.position[1]-1,self.node.position[2]), color=(0,1,1)).autoretain() def checkCanControl(self): if not self.node.exists(): @@ -172,7 +172,7 @@ def checkPlayerDie(self): if self.source_player is None: return if self.source_player.is_alive(): - ba.timer(1, self.checkPlayerDie) + bs.timer(1, self.checkPlayerDie) return else: self.dis() @@ -186,8 +186,7 @@ def drop(self): np = self.node.position except: np = (0, 0, 0) - self.b = Bomb(bomb_type=random.choice(['normal', 'ice', 'sticky', 'impact', 'land_mine', 'tnt']), - source_player=self.source_player, position=(np[0], np[1] - 1, np[2]), velocity=(0, -1, 0)).autoretain() + self.b = Bomb(bomb_type=random.choice(['normal', 'ice', 'sticky', 'impact', 'land_mine', 'tnt']), source_player=self.source_player, position=(np[0], np[1] - 1, np[2]), velocity=(0, -1, 0)).autoretain() if self.b.bomb_type in ['impact', 'land_mine']: self.b.arm() @@ -199,36 +198,36 @@ def move(self): pn = self.node.position dist = self.distance(pn[0], pn[1], pn[2], px, py, pz) self.node.velocity = ((px - pn[0]) / dist, (py - pn[1]) / dist, (pz - pn[2]) / dist) - ba.timer(dist-1, ba.WeakCall(self.move), suppress_format_warning=True) + bs.timer(dist-1, bs.WeakCall(self.move)) #suppress_format_warning=True) def handlemessage(self, msg): - if isinstance(msg, ba.DieMessage): + if isinstance(msg, bs.DieMessage): self.node.delete() self.node2.delete() self.controlled = False - elif isinstance(msg, ba.OutOfBoundsMessage): - self.handlemessage(ba.DieMessage()) + elif isinstance(msg, bs.OutOfBoundsMessage): + self.handlemessage(bs.DieMessage()) else: super().handlemessage(msg) + + + + def assignFloInputs(clientID: int): - with ba.Context(_ba.get_foreground_host_activity()): - activity = ba.getactivity() + activity = bs.get_foreground_host_activity() + with activity.context: if not hasattr(activity, 'flo') or not activity.flo.node.exists(): - try: - activity.flo = Floater(activity.map.get_def_bound_box('map_bounds')) - except: - return # Perhaps using in main-menu/score-screen + try: activity.flo = Floater(activity.map.get_def_bound_box('map_bounds')) + except: return #Perhaps using in main-menu/score-screen floater = activity.flo if floater.controlled: - ba.screenmessage('Floater is already being controlled', - color=(1, 0, 0), transient=True, clients=[clientID]) + bs.broadcastmessage('Floater is already being controlled', color=(1, 0, 0), transient=True, clients=[clientID]) return - ba.screenmessage('You Gained Control Over The Floater!\n Press Bomb to Throw Bombs and Punch to leave!', clients=[ - clientID], transient=True, color=(0, 1, 1)) + bs.broadcastmessage('You Gained Control Over The Floater!\n Press Bomb to Throw Bombs and Punch to leave!', clients=[clientID], transient=True, color=(0, 1, 1)) - for i in _ba.get_foreground_host_activity().players: + for i in activity.players: if i.sessionplayer.inputdevice.client_id == clientID: def dis(i, floater): i.actor.node.invincible = False @@ -238,41 +237,42 @@ def dis(i, floater): ps = i.actor.node.position i.actor.node.invincible = True floater.node.position = (ps[0], ps[1] + 1.0, ps[2]) - ba.timer(1, floater.pop) - i.actor.node.hold_node = ba.Node(None) + bs.timer(1, floater.pop) + i.actor.node.hold_node = bs.Node(None) i.actor.node.hold_node = floater.node2 i.actor.connect_controls_to_player() i.actor.disconnect_controls_from_player() i.resetinput() floater.source_player = i floater.con() - i.assigninput(ba.InputType.PICK_UP_PRESS, floater.up) - i.assigninput(ba.InputType.PICK_UP_RELEASE, floater.upR) - i.assigninput(ba.InputType.JUMP_PRESS, floater.down) - i.assigninput(ba.InputType.BOMB_PRESS, floater.drop) - i.assigninput(ba.InputType.PUNCH_PRESS, ba.Call(dis, i, floater)) - i.assigninput(ba.InputType.UP_DOWN, floater.updown) - i.assigninput(ba.InputType.LEFT_RIGHT, floater.leftright) + i.assigninput(babase.InputType.PICK_UP_PRESS, floater.up) + i.assigninput(babase.InputType.PICK_UP_RELEASE, floater.upR) + i.assigninput(babase.InputType.JUMP_PRESS, floater.down) + i.assigninput(babase.InputType.BOMB_PRESS, floater.drop) + i.assigninput(babase.InputType.PUNCH_PRESS, babase.Call(dis, i, floater)) + i.assigninput(babase.InputType.UP_DOWN, floater.updown) + i.assigninput(babase.InputType.LEFT_RIGHT, floater.leftright) -old_fcm = _ba.chatmessage +# Display chat icon, but if user open/close gather it may disappear +bui.set_party_icon_always_visible(True) -def new_chat_message(msg: Union[str, ba.Lstr], clients: Sequence[int] = None, sender_override: str = None): - old_fcm(msg, clients, sender_override) - if msg == '/floater': - try: - assignFloInputs(-1) - except: - pass +old_piv = bui.set_party_icon_always_visible +def new_piv(*args, **kwargs): + # Do not let chat icon go away + old_piv(True) +bui.set_party_icon_always_visible = new_piv -_ba.chatmessage = new_chat_message -if not _ba.is_party_icon_visible(): - _ba.set_party_icon_always_visible(True) +old_fcm = bs.chatmessage +def new_chat_message(*args, **kwargs): + old_fcm(*args, **kwargs) + if args[0] == '/floater': + try: assignFloInputs(-1) + except: pass +bs.chatmessage = new_chat_message # ba_meta export plugin - - -class byFreaku(ba.Plugin): - def __init__(self): pass +class byFreaku(babase.Plugin): + def __init__(self): pass \ No newline at end of file diff --git a/plugins/utilities/icons_keyboard.py b/plugins/utilities/icons_keyboard.py index 3033bd49..bbb48abb 100644 --- a/plugins/utilities/icons_keyboard.py +++ b/plugins/utilities/icons_keyboard.py @@ -1,4 +1,4 @@ -# Made by: Freaku / @[Just] Freak#4999 +# Made by your friend: Freaku # • Icon Keyboard • # Make your chats look even more cooler! @@ -6,51 +6,59 @@ # Double tap the space to change between keyboards... -# ba_meta require api 7 + + +# ba_meta require api 8 from __future__ import annotations from typing import TYPE_CHECKING -import ba -from _ba import charstr as uwu +import babase +import bascenev1 as bs +from babase import charstr as uwu if TYPE_CHECKING: - from typing import Any, Optional, Dict, List, Tuple, Type, Iterable + from typing import Any, Optional, Dict, List, Tuple,Type, Iterable + + + + + # ba_meta export keyboard -class IconKeyboard_byFreaku(ba.Keyboard): +class IconKeyboard_byFreaku(babase.Keyboard): """Keyboard go brrrrrrr""" name = 'Icons by \ue048Freaku' - chars = [(uwu(ba.SpecialChar.TICKET), - uwu(ba.SpecialChar.CROWN), - uwu(ba.SpecialChar.DRAGON), - uwu(ba.SpecialChar.SKULL), - uwu(ba.SpecialChar.HEART), - uwu(ba.SpecialChar.FEDORA), - uwu(ba.SpecialChar.HAL), - uwu(ba.SpecialChar.YIN_YANG), - uwu(ba.SpecialChar.EYE_BALL), - uwu(ba.SpecialChar.HELMET), - uwu(ba.SpecialChar.OUYA_BUTTON_U)), - (uwu(ba.SpecialChar.MUSHROOM), - uwu(ba.SpecialChar.NINJA_STAR), - uwu(ba.SpecialChar.VIKING_HELMET), - uwu(ba.SpecialChar.MOON), - uwu(ba.SpecialChar.SPIDER), - uwu(ba.SpecialChar.FIREBALL), - uwu(ba.SpecialChar.MIKIROG), - uwu(ba.SpecialChar.OUYA_BUTTON_O), - uwu(ba.SpecialChar.LOCAL_ACCOUNT), - uwu(ba.SpecialChar.LOGO)), - (uwu(ba.SpecialChar.TICKET), - uwu(ba.SpecialChar.FLAG_INDIA), - uwu(ba.SpecialChar.OCULUS_LOGO), - uwu(ba.SpecialChar.STEAM_LOGO), - uwu(ba.SpecialChar.NVIDIA_LOGO), - uwu(ba.SpecialChar.GAME_CENTER_LOGO), - uwu(ba.SpecialChar.GOOGLE_PLAY_GAMES_LOGO), - uwu(ba.SpecialChar.ALIBABA_LOGO))] + chars = [(uwu(babase.SpecialChar.TICKET), + uwu(babase.SpecialChar.CROWN), + uwu(babase.SpecialChar.DRAGON), + uwu(babase.SpecialChar.SKULL), + uwu(babase.SpecialChar.HEART), + uwu(babase.SpecialChar.FEDORA), + uwu(babase.SpecialChar.HAL), + uwu(babase.SpecialChar.YIN_YANG), + uwu(babase.SpecialChar.EYE_BALL), + uwu(babase.SpecialChar.HELMET), + uwu(babase.SpecialChar.OUYA_BUTTON_U)), + (uwu(babase.SpecialChar.MUSHROOM), + uwu(babase.SpecialChar.NINJA_STAR), + uwu(babase.SpecialChar.VIKING_HELMET), + uwu(babase.SpecialChar.MOON), + uwu(babase.SpecialChar.SPIDER), + uwu(babase.SpecialChar.FIREBALL), + uwu(babase.SpecialChar.MIKIROG), + uwu(babase.SpecialChar.OUYA_BUTTON_O), + uwu(babase.SpecialChar.LOCAL_ACCOUNT), + uwu(babase.SpecialChar.LOGO)), + (uwu(babase.SpecialChar.TICKET), + uwu(babase.SpecialChar.FLAG_INDIA), + uwu(babase.SpecialChar.OCULUS_LOGO), + uwu(babase.SpecialChar.STEAM_LOGO), + uwu(babase.SpecialChar.NVIDIA_LOGO), + uwu(babase.SpecialChar.GAME_CENTER_LOGO), + uwu(babase.SpecialChar.GOOGLE_PLAY_GAMES_LOGO), + uwu(babase.SpecialChar.EXPLODINARY_LOGO))] nums = [] - pages: Dict[str, Tuple[str, ...]] = {} + pages: Dict[str, Tuple[str, ...]] = {} \ No newline at end of file diff --git a/plugins/utilities/unlock_TowerD.py b/plugins/utilities/unlock_TowerD.py index e6d29b49..6a219f1b 100644 --- a/plugins/utilities/unlock_TowerD.py +++ b/plugins/utilities/unlock_TowerD.py @@ -1,8 +1,9 @@ -# By Freaku / @[Just] Freak#4999 +# Made by your friend: Freaku -import ba -from bastd.maps import TowerD +import babase +import bascenev1 as bs +from bascenev1lib.maps import TowerD @classmethod @@ -11,8 +12,8 @@ def new_play_types(cls): return ['melee', 'keep_away', 'team_flag', 'king_of_the_hill'] -# ba_meta require api 7 +# ba_meta require api 8 # ba_meta export plugin -class byFreaku(ba.Plugin): +class byFreaku(babase.Plugin): def on_app_running(self): - TowerD.get_play_types = new_play_types + TowerD.get_play_types = new_play_types \ No newline at end of file From 3f65846527694f6f9b3508cd12ceb4648e6d5fe8 Mon Sep 17 00:00:00 2001 From: ! Freaku <92618708+Freaku17@users.noreply.github.com> Date: Fri, 28 Jul 2023 17:04:23 +0530 Subject: [PATCH 0648/1464] Update JSON files --- plugins/minigames.json | 56 ++++++++++++++++++++++++++---------------- plugins/utilities.json | 12 ++++----- 2 files changed, 41 insertions(+), 27 deletions(-) diff --git a/plugins/minigames.json b/plugins/minigames.json index 66a58ee3..c7e2d6dc 100644 --- a/plugins/minigames.json +++ b/plugins/minigames.json @@ -28,6 +28,32 @@ } } }, + "icy_emits": { + "description": "Survice from icy bombs emitting through cold platform. Playable in teams/ffa/co-op", + "external_url": "", + "authors": [ + { + "name": "Freaku", + "email": "" + } + ], + "versions": { + "1.0.0": null + } + }, + "frozen_one": { + "description": "Survive until the timer runs out", + "external_url": "", + "authors": [ + { + "name": "Freaku", + "email": "" + } + ], + "versions": { + "1.0.0": null + } + }, "simon_says": { "description": "You better do what Simon says", "external_url": "", @@ -198,11 +224,11 @@ "authors": [ { "name": "Freaku", - "email": "", - "discord": "[Just] Freak#4999" + "email": "" } ], "versions": { + "2.0.0": null, "1.1.0": { "api_version": 7, "commit_sha": "0bc9522", @@ -217,11 +243,11 @@ "authors": [ { "name": "Freaku", - "email": "", - "discord": "[Just] Freak#4999" + "email": "" } ], "versions": { + "2.0.0": null, "1.0.0": { "api_version": 7, "commit_sha": "858030b", @@ -236,11 +262,11 @@ "authors": [ { "name": "Freaku", - "email": "", - "discord": "[Just] Freak#4999" + "email": "" } ], "versions": { + "2.0.0": null, "1.0.0": { "api_version": 7, "commit_sha": "858030b", @@ -429,22 +455,11 @@ }, { "name": "Freaku", - "email": "", - "discord": "[Just] Freak#4999" - }, - { - "name": "LoupGarou", - "email": "LoupGarou5418@outlook.com", - "discord": "ʟօʊքɢǟʀօʊ#3063" + "email": "" } ], "versions": { - "2.0.0": { - "api_version": 8, - "commit_sha": "e7a5df9", - "released_on": "26-07-2023", - "md5sum": "641732ef5c8c97cd5482b8cd56126310" - }, + "2.0.0": null, "1.1.0": { "api_version": 7, "commit_sha": "2e2540a", @@ -653,8 +668,7 @@ "authors": [ { "name": "Freaku", - "email": "", - "discord": "[Just] Freak#4999" + "email": "" } ], "versions": { diff --git a/plugins/utilities.json b/plugins/utilities.json index ceb32a85..20d0f716 100644 --- a/plugins/utilities.json +++ b/plugins/utilities.json @@ -292,11 +292,11 @@ "authors": [ { "name": "Freaku", - "email": "", - "discord": "[Just] Freak#4999" + "email": "" } ], "versions": { + "2.0.0": null, "1.0.0": { "api_version": 7, "commit_sha": "6beb8ddf", @@ -311,11 +311,11 @@ "authors": [ { "name": "Freaku", - "email": "", - "discord": "[Just] Freak#4999" + "email": "" } ], "versions": { + "2.0.0": null, "1.1.0": { "api_version": 7, "commit_sha": "383f774", @@ -504,11 +504,11 @@ "authors": [ { "name": "Freaku", - "email": "", - "discord": "[Just] Freak#4999" + "email": "" } ], "versions": { + "2.0.0": null, "1.0.0": { "api_version": 7, "commit_sha": "b581d90", From 7dcf3c711e859dbe7ada70685e7bf82deb9ab9d7 Mon Sep 17 00:00:00 2001 From: Freaku17 Date: Fri, 28 Jul 2023 11:37:09 +0000 Subject: [PATCH 0649/1464] [ci] auto-format --- plugins/minigames/arms_race.py | 26 +- plugins/minigames/frozen_one.py | 2 +- plugins/minigames/icy_emits.py | 24 +- plugins/minigames/memory_game.py | 507 ++++++++++++++-------------- plugins/minigames/musical_flags.py | 158 +++++---- plugins/minigames/volleyball.py | 281 +++++++-------- plugins/utilities/floater.py | 52 ++- plugins/utilities/icons_keyboard.py | 67 ++-- plugins/utilities/unlock_TowerD.py | 2 +- 9 files changed, 554 insertions(+), 565 deletions(-) diff --git a/plugins/minigames/arms_race.py b/plugins/minigames/arms_race.py index 7710c2ae..475811ae 100644 --- a/plugins/minigames/arms_race.py +++ b/plugins/minigames/arms_race.py @@ -1,10 +1,9 @@ # Ported by your friend: Freaku -#Join BCS: +# Join BCS: # https://discord.gg/ucyaesh - # ba_meta require api 8 from __future__ import annotations @@ -19,7 +18,6 @@ from typing import Any, Type, List, Dict, Tuple, Union, Sequence, Optional - class State: def __init__(self, bomb=None, grab=False, punch=False, curse=False, required=False, final=False, name=''): self.bomb = bomb @@ -36,8 +34,8 @@ def __init__(self, bomb=None, grab=False, punch=False, curse=False, required=Fal def apply(self, spaz): spaz.disconnect_controls_from_player() spaz.connect_controls_to_player(enable_punch=self.punch, - enable_bomb=self.bomb, - enable_pickup=self.grab) + enable_bomb=self.bomb, + enable_pickup=self.grab) if self.curse: spaz.curse_time = -1 spaz.curse() @@ -49,16 +47,18 @@ def get_setting(self): return (self.name) -states = [ State(bomb='normal', name='Basic Bombs'), - State(bomb='ice', name='Frozen Bombs'), - State(bomb='sticky', name='Sticky Bombs'), - State(bomb='impact', name='Impact Bombs'), - State(grab=True, name='Grabbing only'), - State(punch=True, name='Punching only'), - State(curse=True, name='Cursed', final=True) ] +states = [State(bomb='normal', name='Basic Bombs'), + State(bomb='ice', name='Frozen Bombs'), + State(bomb='sticky', name='Sticky Bombs'), + State(bomb='impact', name='Impact Bombs'), + State(grab=True, name='Grabbing only'), + State(punch=True, name='Punching only'), + State(curse=True, name='Cursed', final=True)] + class Player(bs.Player['Team']): """Our player type for this game.""" + def __init__(self): self.state = None @@ -192,4 +192,4 @@ def end_game(self) -> None: results = bs.GameResults() for team in self.teams: results.set_team_score(team, team.score) - self.end(results=results) \ No newline at end of file + self.end(results=results) diff --git a/plugins/minigames/frozen_one.py b/plugins/minigames/frozen_one.py index 7bfbe655..9b0c9ba0 100644 --- a/plugins/minigames/frozen_one.py +++ b/plugins/minigames/frozen_one.py @@ -15,4 +15,4 @@ def _set_chosen_one_player(self, player: Player) -> None: super()._set_chosen_one_player(player) if hasattr(player, 'actor'): player.actor.frozen = True - player.actor.node.frozen = 1 \ No newline at end of file + player.actor.node.frozen = 1 diff --git a/plugins/minigames/icy_emits.py b/plugins/minigames/icy_emits.py index 50a883cf..f5467e31 100644 --- a/plugins/minigames/icy_emits.py +++ b/plugins/minigames/icy_emits.py @@ -2,7 +2,8 @@ import babase -import bascenev1 as bs, random +import bascenev1 as bs +import random from bascenev1lib.actor.bomb import Bomb from bascenev1lib.game.meteorshower import Player, MeteorShowerGame @@ -14,7 +15,7 @@ class IcyEmitsGame(MeteorShowerGame): @classmethod def get_supported_maps(cls, sessiontype): - return ['Lake Frigid','Hockey Stadium'] + return ['Lake Frigid', 'Hockey Stadium'] def _drop_bomb_cluster(self) -> None: delay = 0.0 @@ -24,23 +25,24 @@ def _drop_bomb_cluster(self) -> None: pos = (-7.3 + 15.3 * random.random(), 5.3, -5.5 + 2.1 * random.random()) dropdir = (-1.0 if pos[0] > 0 else 1.0) - vel = (0,10,0) + vel = (0, 10, 0) bs.timer(delay, babase.Call(self._drop_bomb, pos, vel)) delay += 0.1 self._set_meteor_timer() def _drop_bomb(self, position, velocity): - random_xpositions = [-10,-9,-8,-7,-6,-5,-4,-3,-2,-1,0,1,2,3,4,5,6,7,8,9,10] - random_zpositions = [-5,-4.5,-4,-3.5,-3,-2.5,-2,-1.5,-1,-0.5,0,0.5,1,1.5,2,2.5,3,3.5,4,4.5,5] - bomb_position = (random.choice(random_xpositions), 0.2,random.choice(random_zpositions)) - Bomb(position=bomb_position, velocity=velocity, bomb_type = 'ice').autoretain() - - + random_xpositions = [-10, -9, -8, -7, -6, -5, - + 4, -3, -2, -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10] + random_zpositions = [-5, -4.5, -4, -3.5, -3, -2.5, -2, - + 1.5, -1, -0.5, 0, 0.5, 1, 1.5, 2, 2.5, 3, 3.5, 4, 4.5, 5] + bomb_position = (random.choice(random_xpositions), 0.2, random.choice(random_zpositions)) + Bomb(position=bomb_position, velocity=velocity, bomb_type='ice').autoretain() # ba_meta export plugin class byFreaku(babase.Plugin): def __init__(self): ## Campaign support ## - randomPic = ['lakeFrigidPreview','hockeyStadiumPreview'] - babase.app.classic.add_coop_practice_level(bs.Level(name='Icy Emits', displayname='${GAME}', gametype=IcyEmitsGame, settings={}, preview_texture_name=random.choice(randomPic))) \ No newline at end of file + randomPic = ['lakeFrigidPreview', 'hockeyStadiumPreview'] + babase.app.classic.add_coop_practice_level(bs.Level( + name='Icy Emits', displayname='${GAME}', gametype=IcyEmitsGame, settings={}, preview_texture_name=random.choice(randomPic))) diff --git a/plugins/minigames/memory_game.py b/plugins/minigames/memory_game.py index a433eec7..5ab25023 100644 --- a/plugins/minigames/memory_game.py +++ b/plugins/minigames/memory_game.py @@ -12,32 +12,29 @@ # (& some improvements) - - - - # incase someone is wondering how is map floating. Check out # def spawnAllMap(self) - # ba_meta require api 8 from typing import TYPE_CHECKING, overload -import _babase, babase, random +import _babase +import babase +import random import bascenev1 as bs from bascenev1lib.gameutils import SharedObjects if TYPE_CHECKING: from typing import Any, Sequence, Optional, List, Dict, Type, Union, Any, Literal - - class OnTimer(bs.Actor): """Timer which counts but doesn't show on-screen""" + def __init__(self) -> None: super().__init__() self._starttime_ms: int | None = None - self.node = bs.newnode('text', attrs={ 'v_attach': 'top', 'h_attach': 'center', 'h_align': 'center', 'color': (1, 1, 0.5, 1), 'flatness': 0.5, 'shadow': 0.5, 'position': (0, -70), 'scale': 0, 'text': ''}) + self.node = bs.newnode('text', attrs={'v_attach': 'top', 'h_attach': 'center', 'h_align': 'center', 'color': ( + 1, 1, 0.5, 1), 'flatness': 0.5, 'shadow': 0.5, 'position': (0, -70), 'scale': 0, 'text': ''}) self.inputnode = bs.newnode( 'timedisplay', attrs={'timemin': 0, 'showsubseconds': True} ) @@ -101,8 +98,6 @@ def handlemessage(self, msg: Any) -> Any: self.node.delete() - - class Player(bs.Player['Team']): """Our player type for this game.""" @@ -120,7 +115,8 @@ class MGgame(bs.TeamGameActivity[Player, Team]): name = 'Memory Game' description = 'Memories tiles and survive till the end!' - available_settings = [bs.BoolSetting('Epic Mode', default=False), bs.BoolSetting('Enable Bottom Credits', True)] + available_settings = [bs.BoolSetting( + 'Epic Mode', default=False), bs.BoolSetting('Enable Bottom Credits', True)] scoreconfig = bs.ScoreConfig(label='Survived', scoretype=bs.ScoreType.MILLISECONDS, version='B') # Print messages when players die (since its meaningful in this game). @@ -152,9 +148,9 @@ def __init__(self, settings: dict): if self._epic_mode: self.slow_motion = True shared = SharedObjects.get() - self._collide_with_player=bs.Material() + self._collide_with_player = bs.Material() self._collide_with_player.add_actions(actions=(('modify_part_collision', 'collide', True))) - self.dont_collide=bs.Material() + self.dont_collide = bs.Material() self.dont_collide.add_actions(actions=(('modify_part_collision', 'collide', False))) self._levelStage = 0 @@ -177,7 +173,7 @@ def __init__(self, settings: dict): self._mapFGSpaz = bs.gettexture('neoSpazIcon') self._mapFGZoe = bs.gettexture('zoeIcon') self._mapFGSnake = bs.gettexture('ninjaIcon') - self._mapFGKronk= bs.gettexture('kronkIcon') + self._mapFGKronk = bs.gettexture('kronkIcon') self._mapFGMel = bs.gettexture('melIcon') self._mapFGJack = bs.gettexture('jackIcon') self._mapFGSanta = bs.gettexture('santaIcon') @@ -195,59 +191,58 @@ def __init__(self, settings: dict): self._circleTex = bs.gettexture('circleShadow') self._image = bs.newnode('image', - attrs={'texture': self._imageTextDefault, - 'position':(0,-100), - 'scale':(100,100), - 'opacity': 0.0, - 'attach':'topCenter'}) + attrs={'texture': self._imageTextDefault, + 'position': (0, -100), + 'scale': (100, 100), + 'opacity': 0.0, + 'attach': 'topCenter'}) self._textCounter = bs.newnode('text', - attrs={'text': '10', - 'position': (0, -100), - 'scale': 2.3, - 'shadow': 1.0, - 'flatness': 1.0, - 'opacity': 0.0, - 'v_attach': 'top', - 'h_attach': 'center', - 'h_align': 'center', - 'v_align': 'center'}) + attrs={'text': '10', + 'position': (0, -100), + 'scale': 2.3, + 'shadow': 1.0, + 'flatness': 1.0, + 'opacity': 0.0, + 'v_attach': 'top', + 'h_attach': 'center', + 'h_align': 'center', + 'v_align': 'center'}) self._textLevel = bs.newnode('text', - attrs={'text': 'Level ' + str(self._levelStage), - 'position': (0, -28), - 'scale': 1.3, - 'shadow': 1.0, - 'flatness': 1.0, - 'color': (1.0, 0.0, 1.0), - 'opacity': 0.0, - 'v_attach': 'top', - 'h_attach': 'center', - 'h_align': 'center', - 'v_align': 'center'}) + attrs={'text': 'Level ' + str(self._levelStage), + 'position': (0, -28), + 'scale': 1.3, + 'shadow': 1.0, + 'flatness': 1.0, + 'color': (1.0, 0.0, 1.0), + 'opacity': 0.0, + 'v_attach': 'top', + 'h_attach': 'center', + 'h_align': 'center', + 'v_align': 'center'}) self._imageCircle = bs.newnode('image', - attrs={'texture': self._circleTex, - 'position': (75, -75), - 'scale': (20,20), - 'color': (0.2, 0.2, 0.2), - 'opacity': 0.0, - 'attach': 'topCenter'}) + attrs={'texture': self._circleTex, + 'position': (75, -75), + 'scale': (20, 20), + 'color': (0.2, 0.2, 0.2), + 'opacity': 0.0, + 'attach': 'topCenter'}) self._imageCircle2 = bs.newnode('image', - attrs={'texture': self._circleTex, - 'position': (75, -100), - 'scale': (20,20), - 'color': (0.2, 0.2, 0.2), - 'opacity': 0.0, - 'attach': 'topCenter'}) + attrs={'texture': self._circleTex, + 'position': (75, -100), + 'scale': (20, 20), + 'color': (0.2, 0.2, 0.2), + 'opacity': 0.0, + 'attach': 'topCenter'}) self._imageCircle3 = bs.newnode('image', - attrs={'texture': self._circleTex, - 'position': (75, -125), - 'scale': (20,20), - 'color': (0.2, 0.2, 0.2), - 'opacity': 0.0, - 'attach': 'topCenter'}) - + attrs={'texture': self._circleTex, + 'position': (75, -125), + 'scale': (20, 20), + 'color': (0.2, 0.2, 0.2), + 'opacity': 0.0, + 'attach': 'topCenter'}) def on_transition_in(self) -> None: super().on_transition_in() @@ -300,14 +295,14 @@ def on_begin(self) -> None: self.coldel16 = True if self.credit_text: t = bs.newnode('text', - attrs={ 'text':"Made by Freaku\nOriginally for 1.4: byANG3L", ## Disable 'Enable Bottom Credits' when making playlist, No need to edit this lovely... - 'scale':0.7, - 'position':(0,0), - 'shadow':0.5, - 'flatness':1.2, - 'color':(1, 1, 1), - 'h_align':'center', - 'v_attach':'bottom'}) + attrs={'text': "Made by Freaku\nOriginally for 1.4: byANG3L", # Disable 'Enable Bottom Credits' when making playlist, No need to edit this lovely... + 'scale': 0.7, + 'position': (0, 0), + 'shadow': 0.5, + 'flatness': 1.2, + 'color': (1, 1, 1), + 'h_align': 'center', + 'v_attach': 'bottom'}) self.spawnAllMap() self.flashHide() @@ -318,6 +313,7 @@ def on_begin(self) -> None: def startCounter(self): self._textCounter.text = '10' + def count9(): def count8(): def count7(): @@ -366,8 +362,8 @@ def on_player_join(self, player: Player) -> None: if self.has_begun(): bs.broadcastmessage( babase.Lstr(resource='playerDelayedJoinText', - subs=[('${PLAYER}', player.getname(full=True))]), - color=(0, 1, 0),transient=True,clients=[player.sessionplayer.inputdevice.client_id]) + subs=[('${PLAYER}', player.getname(full=True))]), + color=(0, 1, 0), transient=True, clients=[player.sessionplayer.inputdevice.client_id]) # For score purposes, mark them as having died right as the # game started. assert self._timer is not None @@ -385,7 +381,8 @@ def on_player_leave(self, player: Player) -> None: # overriding the default character spawning.. def spawn_player(self, player: Player) -> bs.Actor: spaz = self.spawn_player_spaz(player) - pos = (self._spawnCenter[0] + random.uniform(-1.5, 2.5), self._spawnCenter[1], self._spawnCenter[2] + random.uniform(-2.5, 1.5)) + pos = (self._spawnCenter[0] + random.uniform(-1.5, 2.5), + self._spawnCenter[1], self._spawnCenter[2] + random.uniform(-2.5, 1.5)) spaz.connect_controls_to_player(enable_punch=False, enable_bomb=False, enable_pickup=False) spaz.handlemessage(bs.StandMessage(pos)) return spaz @@ -393,49 +390,50 @@ def spawn_player(self, player: Player) -> bs.Actor: def _randomSelect(self): if self._levelStage == 1: self._textureSelected = random.choice([self._mapFGMinesTex, - self._mapFGStickyTex]) + self._mapFGStickyTex]) self._image.texture = self._textureSelected elif self._levelStage == 2: self._textureSelected = random.choice([self._mapFGIceTex, - self._mapFGShieldTex]) + self._mapFGShieldTex]) self._image.texture = self._textureSelected - elif self._levelStage in [3,4,5]: + elif self._levelStage in [3, 4, 5]: self._textureSelected = random.choice([self._mapFGStickyTex, - self._mapFGIceTex, - self._mapFGImpactTex, - self._mapFGMinesTex]) + self._mapFGIceTex, + self._mapFGImpactTex, + self._mapFGMinesTex]) self._image.texture = self._textureSelected - elif self._levelStage in [6,7,8,9]: + elif self._levelStage in [6, 7, 8, 9]: self._textureSelected = random.choice([self._mapFGCurseTex, - self._mapFGHealthTex, - self._mapFGIceTex, - self._mapFGImpactTex, - self._mapFGMinesTex, - self._mapFGPunchTex, - self._mapFGShieldTex]) + self._mapFGHealthTex, + self._mapFGIceTex, + self._mapFGImpactTex, + self._mapFGMinesTex, + self._mapFGPunchTex, + self._mapFGShieldTex]) self._image.texture = self._textureSelected elif self._levelStage >= 10: self._textureSelected = random.choice([self._mapFGSpaz, - self._mapFGZoe, - self._mapFGSnake, - self._mapFGKronk, - self._mapFGMel, - self._mapFGJack, - self._mapFGSanta, - self._mapFGFrosty, - self._mapFGBones, - self._mapFGBernard, - self._mapFGPascal, - self._mapFGAli, - self._mapFGRobot, - self._mapFGAgent, - self._mapFGGrumbledorf, - self._mapFGPixel]) + self._mapFGZoe, + self._mapFGSnake, + self._mapFGKronk, + self._mapFGMel, + self._mapFGJack, + self._mapFGSanta, + self._mapFGFrosty, + self._mapFGBones, + self._mapFGBernard, + self._mapFGPascal, + self._mapFGAli, + self._mapFGRobot, + self._mapFGAgent, + self._mapFGGrumbledorf, + self._mapFGPixel]) self._image.texture = self._textureSelected return self._textureSelected def _stop(self): self._textureSelected = self._randomSelect() + def circle(): def circle2(): def circle3(): @@ -455,100 +453,100 @@ def circle3(): def _randomPlatform(self): if self._levelStage == 1: - randomTexture=[self._mapFGMinesTex, - self._mapFGMinesTex, - self._mapFGMinesTex, - self._mapFGMinesTex, - self._mapFGMinesTex, - self._mapFGMinesTex, - self._mapFGMinesTex, - self._mapFGMinesTex, - self._mapFGStickyTex, - self._mapFGStickyTex, - self._mapFGStickyTex, - self._mapFGStickyTex, - self._mapFGStickyTex, - self._mapFGStickyTex, - self._mapFGStickyTex, - self._mapFGStickyTex] + randomTexture = [self._mapFGMinesTex, + self._mapFGMinesTex, + self._mapFGMinesTex, + self._mapFGMinesTex, + self._mapFGMinesTex, + self._mapFGMinesTex, + self._mapFGMinesTex, + self._mapFGMinesTex, + self._mapFGStickyTex, + self._mapFGStickyTex, + self._mapFGStickyTex, + self._mapFGStickyTex, + self._mapFGStickyTex, + self._mapFGStickyTex, + self._mapFGStickyTex, + self._mapFGStickyTex] elif self._levelStage == 2: - randomTexture=[self._mapFGIceTex, - self._mapFGIceTex, - self._mapFGIceTex, - self._mapFGIceTex, - self._mapFGIceTex, - self._mapFGIceTex, - self._mapFGIceTex, - self._mapFGIceTex, - self._mapFGShieldTex, - self._mapFGShieldTex, - self._mapFGShieldTex, - self._mapFGShieldTex, - self._mapFGShieldTex, - self._mapFGShieldTex, - self._mapFGShieldTex, - self._mapFGShieldTex] - elif self._levelStage in [3,4,5]: - randomTexture=[self._mapFGStickyTex, - self._mapFGStickyTex, - self._mapFGStickyTex, - self._mapFGStickyTex, - self._mapFGIceTex, - self._mapFGIceTex, - self._mapFGIceTex, - self._mapFGIceTex, - self._mapFGImpactTex, - self._mapFGImpactTex, - self._mapFGImpactTex, - self._mapFGImpactTex, - self._mapFGMinesTex, - self._mapFGMinesTex, - self._mapFGMinesTex, - self._mapFGMinesTex] - elif self._levelStage in [6,7,8,9]: - randomTexture=[self._mapFGHealthTex, - self._mapFGShieldTex, - self._mapFGCurseTex, - self._mapFGCurseTex, - self._mapFGHealthTex, - self._mapFGHealthTex, - self._mapFGIceTex, - self._mapFGIceTex, - self._mapFGImpactTex, - self._mapFGImpactTex, - self._mapFGMinesTex, - self._mapFGMinesTex, - self._mapFGPunchTex, - self._mapFGPunchTex, - self._mapFGShieldTex, - self._mapFGShieldTex] + randomTexture = [self._mapFGIceTex, + self._mapFGIceTex, + self._mapFGIceTex, + self._mapFGIceTex, + self._mapFGIceTex, + self._mapFGIceTex, + self._mapFGIceTex, + self._mapFGIceTex, + self._mapFGShieldTex, + self._mapFGShieldTex, + self._mapFGShieldTex, + self._mapFGShieldTex, + self._mapFGShieldTex, + self._mapFGShieldTex, + self._mapFGShieldTex, + self._mapFGShieldTex] + elif self._levelStage in [3, 4, 5]: + randomTexture = [self._mapFGStickyTex, + self._mapFGStickyTex, + self._mapFGStickyTex, + self._mapFGStickyTex, + self._mapFGIceTex, + self._mapFGIceTex, + self._mapFGIceTex, + self._mapFGIceTex, + self._mapFGImpactTex, + self._mapFGImpactTex, + self._mapFGImpactTex, + self._mapFGImpactTex, + self._mapFGMinesTex, + self._mapFGMinesTex, + self._mapFGMinesTex, + self._mapFGMinesTex] + elif self._levelStage in [6, 7, 8, 9]: + randomTexture = [self._mapFGHealthTex, + self._mapFGShieldTex, + self._mapFGCurseTex, + self._mapFGCurseTex, + self._mapFGHealthTex, + self._mapFGHealthTex, + self._mapFGIceTex, + self._mapFGIceTex, + self._mapFGImpactTex, + self._mapFGImpactTex, + self._mapFGMinesTex, + self._mapFGMinesTex, + self._mapFGPunchTex, + self._mapFGPunchTex, + self._mapFGShieldTex, + self._mapFGShieldTex] elif self._levelStage >= 10: - randomTexture=[self._mapFGSpaz, - self._mapFGZoe, - self._mapFGSnake, - self._mapFGKronk, - self._mapFGMel, - self._mapFGJack, - self._mapFGSanta, - self._mapFGFrosty, - self._mapFGBones, - self._mapFGBernard, - self._mapFGPascal, - self._mapFGAli, - self._mapFGRobot, - self._mapFGAgent, - self._mapFGGrumbledorf, - self._mapFGPixel] + randomTexture = [self._mapFGSpaz, + self._mapFGZoe, + self._mapFGSnake, + self._mapFGKronk, + self._mapFGMel, + self._mapFGJack, + self._mapFGSanta, + self._mapFGFrosty, + self._mapFGBones, + self._mapFGBernard, + self._mapFGPascal, + self._mapFGAli, + self._mapFGRobot, + self._mapFGAgent, + self._mapFGGrumbledorf, + self._mapFGPixel] (self.mapFGPTex, self.mapFGP2Tex, self.mapFGP3Tex, self.mapFGP4Tex, - self.mapFGP5Tex, self.mapFGP6Tex, - self.mapFGP7Tex, self.mapFGP8Tex, - self.mapFGP9Tex,self.mapFGP10Tex, - self.mapFGP11Tex, self.mapFGP12Tex, - self.mapFGP13Tex, self.mapFGP14Tex, - self.mapFGP15Tex, self.mapFGP16Tex) = ( - random.sample(randomTexture, 16)) + self.mapFGP5Tex, self.mapFGP6Tex, + self.mapFGP7Tex, self.mapFGP8Tex, + self.mapFGP9Tex, self.mapFGP10Tex, + self.mapFGP11Tex, self.mapFGP12Tex, + self.mapFGP13Tex, self.mapFGP14Tex, + self.mapFGP15Tex, self.mapFGP16Tex) = ( + random.sample(randomTexture, 16)) self._mixPlatform() def _mixPlatform(self): @@ -685,114 +683,130 @@ def spawnAllMap(self): shared = SharedObjects.get() if self.coldel: self.mapFGP = bs.newnode('prop', - attrs={'body': 'puck', 'position': (4.5,2,-9), 'mesh': self._mapFGPModel, 'mesh_scale': 3.73, 'body_scale': 3.73, 'shadow_size': 0.5, 'gravity_scale':0.0, 'color_texture': self._mapFGPDefaultTex, 'reflection': 'soft', 'reflection_scale': [1.0], 'is_area_of_interest': True, 'materials': [self.dont_collide]}) + attrs={'body': 'puck', 'position': (4.5, 2, -9), 'mesh': self._mapFGPModel, 'mesh_scale': 3.73, 'body_scale': 3.73, 'shadow_size': 0.5, 'gravity_scale': 0.0, 'color_texture': self._mapFGPDefaultTex, 'reflection': 'soft', 'reflection_scale': [1.0], 'is_area_of_interest': True, 'materials': [self.dont_collide]}) self.mapFGPTex = None - self.mapFGPcol = bs.newnode('region',attrs={'position': (4.5,2,-9),'scale': (3.5,0.1,3.5),'type': 'box','materials': (self._collide_with_player, shared.footing_material)}) + self.mapFGPcol = bs.newnode('region', attrs={'position': (4.5, 2, -9), 'scale': ( + 3.5, 0.1, 3.5), 'type': 'box', 'materials': (self._collide_with_player, shared.footing_material)}) self.coldel = False if self.coldel2: - self.mapFGP2 = bs.newnode('prop', - attrs={'body': 'puck', 'position': (4.5,2,-6), 'mesh': self._mapFGPModel, 'mesh_scale': 3.73, 'body_scale': 3.73, 'shadow_size': 0.5, 'gravity_scale':0.0, 'color_texture': self._mapFGPDefaultTex, 'reflection': 'soft', 'reflection_scale': [1.0], 'is_area_of_interest': True, 'materials': [self.dont_collide]}) + self.mapFGP2 = bs.newnode('prop', + attrs={'body': 'puck', 'position': (4.5, 2, -6), 'mesh': self._mapFGPModel, 'mesh_scale': 3.73, 'body_scale': 3.73, 'shadow_size': 0.5, 'gravity_scale': 0.0, 'color_texture': self._mapFGPDefaultTex, 'reflection': 'soft', 'reflection_scale': [1.0], 'is_area_of_interest': True, 'materials': [self.dont_collide]}) self.mapFGP2Tex = None - self.mapFGP2col = bs.newnode('region',attrs={'position': (4.5,2,-6),'scale': (3.5,0.1,3.5),'type': 'box','materials': (self._collide_with_player, shared.footing_material)}) + self.mapFGP2col = bs.newnode('region', attrs={'position': (4.5, 2, -6), 'scale': ( + 3.5, 0.1, 3.5), 'type': 'box', 'materials': (self._collide_with_player, shared.footing_material)}) self.coldel2 = False if self.coldel3: - self.mapFGP3 = bs.newnode('prop', - attrs={'body': 'puck', 'position': (4.5,2,-3), 'mesh': self._mapFGPModel, 'mesh_scale': 3.73, 'body_scale': 3.73, 'shadow_size': 0.5, 'gravity_scale':0.0, 'color_texture': self._mapFGPDefaultTex, 'reflection': 'soft', 'reflection_scale': [1.0], 'is_area_of_interest': True, 'materials': [self.dont_collide]}) + self.mapFGP3 = bs.newnode('prop', + attrs={'body': 'puck', 'position': (4.5, 2, -3), 'mesh': self._mapFGPModel, 'mesh_scale': 3.73, 'body_scale': 3.73, 'shadow_size': 0.5, 'gravity_scale': 0.0, 'color_texture': self._mapFGPDefaultTex, 'reflection': 'soft', 'reflection_scale': [1.0], 'is_area_of_interest': True, 'materials': [self.dont_collide]}) self.mapFGP3Tex = None - self.mapFGP3col = bs.newnode('region',attrs={'position': (4.5,2,-3),'scale': (3.5,0.1,3.5),'type': 'box','materials': (self._collide_with_player, shared.footing_material)}) + self.mapFGP3col = bs.newnode('region', attrs={'position': (4.5, 2, -3), 'scale': ( + 3.5, 0.1, 3.5), 'type': 'box', 'materials': (self._collide_with_player, shared.footing_material)}) self.coldel3 = False if self.coldel4: - self.mapFGP4 = bs.newnode('prop', - attrs={'body': 'puck', 'position': (4.5,2,0), 'mesh': self._mapFGPModel, 'mesh_scale': 3.73, 'body_scale': 3.73, 'shadow_size': 0.5, 'gravity_scale':0.0, 'color_texture': self._mapFGPDefaultTex, 'reflection': 'soft', 'reflection_scale': [1.0], 'is_area_of_interest': True, 'materials': [self.dont_collide]}) + self.mapFGP4 = bs.newnode('prop', + attrs={'body': 'puck', 'position': (4.5, 2, 0), 'mesh': self._mapFGPModel, 'mesh_scale': 3.73, 'body_scale': 3.73, 'shadow_size': 0.5, 'gravity_scale': 0.0, 'color_texture': self._mapFGPDefaultTex, 'reflection': 'soft', 'reflection_scale': [1.0], 'is_area_of_interest': True, 'materials': [self.dont_collide]}) self.mapFGP4Tex = None - self.mapFGP4col = bs.newnode('region',attrs={'position': (4.5,2,0),'scale': (3.5,0.1,3.5),'type': 'box','materials': (self._collide_with_player, shared.footing_material)}) + self.mapFGP4col = bs.newnode('region', attrs={'position': (4.5, 2, 0), 'scale': ( + 3.5, 0.1, 3.5), 'type': 'box', 'materials': (self._collide_with_player, shared.footing_material)}) self.coldel4 = False if self.coldel5: - self.mapFGP5 = bs.newnode('prop', - attrs={'body': 'puck', 'position': (1.5,2,-9), 'mesh': self._mapFGPModel, 'mesh_scale': 3.73, 'body_scale': 3.73, 'shadow_size': 0.5, 'gravity_scale':0.0, 'color_texture': self._mapFGPDefaultTex, 'reflection': 'soft', 'reflection_scale': [1.0], 'is_area_of_interest': True, 'materials': [self.dont_collide]}) + self.mapFGP5 = bs.newnode('prop', + attrs={'body': 'puck', 'position': (1.5, 2, -9), 'mesh': self._mapFGPModel, 'mesh_scale': 3.73, 'body_scale': 3.73, 'shadow_size': 0.5, 'gravity_scale': 0.0, 'color_texture': self._mapFGPDefaultTex, 'reflection': 'soft', 'reflection_scale': [1.0], 'is_area_of_interest': True, 'materials': [self.dont_collide]}) self.mapFGP5Tex = None - self.mapFGP5col = bs.newnode('region',attrs={'position': (1.5,2,-9),'scale': (3.5,0.1,3.5),'type': 'box','materials': (self._collide_with_player, shared.footing_material)}) + self.mapFGP5col = bs.newnode('region', attrs={'position': (1.5, 2, -9), 'scale': ( + 3.5, 0.1, 3.5), 'type': 'box', 'materials': (self._collide_with_player, shared.footing_material)}) self.coldel5 = False if self.coldel6: - self.mapFGP6 = bs.newnode('prop', - attrs={'body': 'puck', 'position': (1.5,2,-6), 'mesh': self._mapFGPModel, 'mesh_scale': 3.73, 'body_scale': 3.73, 'shadow_size': 0.5, 'gravity_scale':0.0, 'color_texture': self._mapFGPDefaultTex, 'reflection': 'soft', 'reflection_scale': [1.0], 'is_area_of_interest': True, 'materials': [self.dont_collide]}) + self.mapFGP6 = bs.newnode('prop', + attrs={'body': 'puck', 'position': (1.5, 2, -6), 'mesh': self._mapFGPModel, 'mesh_scale': 3.73, 'body_scale': 3.73, 'shadow_size': 0.5, 'gravity_scale': 0.0, 'color_texture': self._mapFGPDefaultTex, 'reflection': 'soft', 'reflection_scale': [1.0], 'is_area_of_interest': True, 'materials': [self.dont_collide]}) self.mapFGP6Tex = None - self.mapFGP6col = bs.newnode('region',attrs={'position': (1.5,2,-6),'scale': (3.5,0.1,3.5),'type': 'box','materials': (self._collide_with_player, shared.footing_material)}) + self.mapFGP6col = bs.newnode('region', attrs={'position': (1.5, 2, -6), 'scale': ( + 3.5, 0.1, 3.5), 'type': 'box', 'materials': (self._collide_with_player, shared.footing_material)}) self.coldel6 = False if self.coldel7: - self.mapFGP7 = bs.newnode('prop', - attrs={'body': 'puck', 'position': (1.5,2,-3), 'mesh': self._mapFGPModel, 'mesh_scale': 3.73, 'body_scale': 3.73, 'shadow_size': 0.5, 'gravity_scale':0.0, 'color_texture': self._mapFGPDefaultTex, 'reflection': 'soft', 'reflection_scale': [1.0], 'is_area_of_interest': True, 'materials': [self.dont_collide]}) + self.mapFGP7 = bs.newnode('prop', + attrs={'body': 'puck', 'position': (1.5, 2, -3), 'mesh': self._mapFGPModel, 'mesh_scale': 3.73, 'body_scale': 3.73, 'shadow_size': 0.5, 'gravity_scale': 0.0, 'color_texture': self._mapFGPDefaultTex, 'reflection': 'soft', 'reflection_scale': [1.0], 'is_area_of_interest': True, 'materials': [self.dont_collide]}) self.mapFGP7Tex = None - self.mapFGP7col = bs.newnode('region',attrs={'position': (1.5,2,-3),'scale': (3.5,0.1,3.5),'type': 'box','materials': (self._collide_with_player, shared.footing_material)}) + self.mapFGP7col = bs.newnode('region', attrs={'position': (1.5, 2, -3), 'scale': ( + 3.5, 0.1, 3.5), 'type': 'box', 'materials': (self._collide_with_player, shared.footing_material)}) self.coldel7 = False if self.coldel8: - self.mapFGP8 = bs.newnode('prop', - attrs={'body': 'puck', 'position': (1.5,2,0), 'mesh': self._mapFGPModel, 'mesh_scale': 3.73, 'body_scale': 3.73, 'shadow_size': 0.5, 'gravity_scale':0.0, 'color_texture': self._mapFGPDefaultTex, 'reflection': 'soft', 'reflection_scale': [1.0], 'is_area_of_interest': True, 'materials': [self.dont_collide]}) + self.mapFGP8 = bs.newnode('prop', + attrs={'body': 'puck', 'position': (1.5, 2, 0), 'mesh': self._mapFGPModel, 'mesh_scale': 3.73, 'body_scale': 3.73, 'shadow_size': 0.5, 'gravity_scale': 0.0, 'color_texture': self._mapFGPDefaultTex, 'reflection': 'soft', 'reflection_scale': [1.0], 'is_area_of_interest': True, 'materials': [self.dont_collide]}) self.mapFGP8Tex = None - self.mapFGP8col = bs.newnode('region',attrs={'position': (1.5,2,0),'scale': (3.5,0.1,3.5),'type': 'box','materials': (self._collide_with_player, shared.footing_material)}) + self.mapFGP8col = bs.newnode('region', attrs={'position': (1.5, 2, 0), 'scale': ( + 3.5, 0.1, 3.5), 'type': 'box', 'materials': (self._collide_with_player, shared.footing_material)}) self.coldel8 = False if self.coldel9: - self.mapFGP9 = bs.newnode('prop', - attrs={'body': 'puck', 'position': (-1.5,2,-9), 'mesh': self._mapFGPModel, 'mesh_scale': 3.73, 'body_scale': 3.73, 'shadow_size': 0.5, 'gravity_scale':0.0, 'color_texture': self._mapFGPDefaultTex, 'reflection': 'soft', 'reflection_scale': [1.0], 'is_area_of_interest': True, 'materials': [self.dont_collide]}) + self.mapFGP9 = bs.newnode('prop', + attrs={'body': 'puck', 'position': (-1.5, 2, -9), 'mesh': self._mapFGPModel, 'mesh_scale': 3.73, 'body_scale': 3.73, 'shadow_size': 0.5, 'gravity_scale': 0.0, 'color_texture': self._mapFGPDefaultTex, 'reflection': 'soft', 'reflection_scale': [1.0], 'is_area_of_interest': True, 'materials': [self.dont_collide]}) self.mapFGP9Tex = None - self.mapFGP9col = bs.newnode('region',attrs={'position': (-1.5,2,-9),'scale': (3.5,0.1,3.5),'type': 'box','materials': (self._collide_with_player, shared.footing_material)}) + self.mapFGP9col = bs.newnode('region', attrs={'position': (-1.5, 2, -9), 'scale': ( + 3.5, 0.1, 3.5), 'type': 'box', 'materials': (self._collide_with_player, shared.footing_material)}) self.coldel9 = False if self.coldel10: - self.mapFGP10 = bs.newnode('prop', - attrs={'body': 'puck', 'position': (-1.5,2,-6), 'mesh': self._mapFGPModel, 'mesh_scale': 3.73, 'body_scale': 3.73, 'shadow_size': 0.5, 'gravity_scale':0.0, 'color_texture': self._mapFGPDefaultTex, 'reflection': 'soft', 'reflection_scale': [1.0], 'is_area_of_interest': True, 'materials': [self.dont_collide]}) + self.mapFGP10 = bs.newnode('prop', + attrs={'body': 'puck', 'position': (-1.5, 2, -6), 'mesh': self._mapFGPModel, 'mesh_scale': 3.73, 'body_scale': 3.73, 'shadow_size': 0.5, 'gravity_scale': 0.0, 'color_texture': self._mapFGPDefaultTex, 'reflection': 'soft', 'reflection_scale': [1.0], 'is_area_of_interest': True, 'materials': [self.dont_collide]}) self.mapFGP10Tex = None - self.mapFGP10col = bs.newnode('region',attrs={'position': (-1.5,2,-6),'scale': (3.5,0.1,3.5),'type': 'box','materials': (self._collide_with_player, shared.footing_material)}) + self.mapFGP10col = bs.newnode('region', attrs={'position': (-1.5, 2, -6), 'scale': ( + 3.5, 0.1, 3.5), 'type': 'box', 'materials': (self._collide_with_player, shared.footing_material)}) self.coldel10 = False if self.coldel11: - self.mapFGP11 = bs.newnode('prop', - attrs={'body': 'puck', 'position': (-1.5,2,-3), 'mesh': self._mapFGPModel, 'mesh_scale': 3.73, 'body_scale': 3.73, 'shadow_size': 0.5, 'gravity_scale':0.0, 'color_texture': self._mapFGPDefaultTex, 'reflection': 'soft', 'reflection_scale': [1.0], 'is_area_of_interest': True, 'materials': [self.dont_collide]}) + self.mapFGP11 = bs.newnode('prop', + attrs={'body': 'puck', 'position': (-1.5, 2, -3), 'mesh': self._mapFGPModel, 'mesh_scale': 3.73, 'body_scale': 3.73, 'shadow_size': 0.5, 'gravity_scale': 0.0, 'color_texture': self._mapFGPDefaultTex, 'reflection': 'soft', 'reflection_scale': [1.0], 'is_area_of_interest': True, 'materials': [self.dont_collide]}) self.mapFGP11Tex = None - self.mapFGP11col = bs.newnode('region',attrs={'position': (-1.5,2,-3),'scale': (3.5,0.1,3.5),'type': 'box','materials': (self._collide_with_player, shared.footing_material)}) + self.mapFGP11col = bs.newnode('region', attrs={'position': (-1.5, 2, -3), 'scale': ( + 3.5, 0.1, 3.5), 'type': 'box', 'materials': (self._collide_with_player, shared.footing_material)}) self.coldel11 = False if self.coldel12: - self.mapFGP12 = bs.newnode('prop', - attrs={'body': 'puck', 'position': (-1.5,2,0), 'mesh': self._mapFGPModel, 'mesh_scale': 3.73, 'body_scale': 3.73, 'shadow_size': 0.5, 'gravity_scale':0.0, 'color_texture': self._mapFGPDefaultTex, 'reflection': 'soft', 'reflection_scale': [1.0], 'is_area_of_interest': True, 'materials': [self.dont_collide]}) + self.mapFGP12 = bs.newnode('prop', + attrs={'body': 'puck', 'position': (-1.5, 2, 0), 'mesh': self._mapFGPModel, 'mesh_scale': 3.73, 'body_scale': 3.73, 'shadow_size': 0.5, 'gravity_scale': 0.0, 'color_texture': self._mapFGPDefaultTex, 'reflection': 'soft', 'reflection_scale': [1.0], 'is_area_of_interest': True, 'materials': [self.dont_collide]}) self.mapFGP12Tex = None - self.mapFGP12col = bs.newnode('region',attrs={'position': (-1.5,2,0),'scale': (3.5,0.1,3.5),'type': 'box','materials': (self._collide_with_player, shared.footing_material)}) + self.mapFGP12col = bs.newnode('region', attrs={'position': (-1.5, 2, 0), 'scale': ( + 3.5, 0.1, 3.5), 'type': 'box', 'materials': (self._collide_with_player, shared.footing_material)}) self.coldel12 = False if self.coldel13: - self.mapFGP13 = bs.newnode('prop', - attrs={'body': 'puck', 'position': (-4.5,2,-9), 'mesh': self._mapFGPModel, 'mesh_scale': 3.73, 'body_scale': 3.73, 'shadow_size': 0.5, 'gravity_scale':0.0, 'color_texture': self._mapFGPDefaultTex, 'reflection': 'soft', 'reflection_scale': [1.0], 'is_area_of_interest': True, 'materials': [self.dont_collide]}) + self.mapFGP13 = bs.newnode('prop', + attrs={'body': 'puck', 'position': (-4.5, 2, -9), 'mesh': self._mapFGPModel, 'mesh_scale': 3.73, 'body_scale': 3.73, 'shadow_size': 0.5, 'gravity_scale': 0.0, 'color_texture': self._mapFGPDefaultTex, 'reflection': 'soft', 'reflection_scale': [1.0], 'is_area_of_interest': True, 'materials': [self.dont_collide]}) self.mapFGP13Tex = None - self.mapFGP13col = bs.newnode('region',attrs={'position': (-4.5,2,-9),'scale': (3.5,0.1,3.5),'type': 'box','materials': (self._collide_with_player, shared.footing_material)}) + self.mapFGP13col = bs.newnode('region', attrs={'position': (-4.5, 2, -9), 'scale': ( + 3.5, 0.1, 3.5), 'type': 'box', 'materials': (self._collide_with_player, shared.footing_material)}) self.coldel13 = False if self.coldel14: - self.mapFGP14 = bs.newnode('prop', - attrs={'body': 'puck', 'position': (-4.5,2,-6), 'mesh': self._mapFGPModel, 'mesh_scale': 3.73, 'body_scale': 3.73, 'shadow_size': 0.5, 'gravity_scale':0.0, 'color_texture': self._mapFGPDefaultTex, 'reflection': 'soft', 'reflection_scale': [1.0], 'is_area_of_interest': True, 'materials': [self.dont_collide]}) + self.mapFGP14 = bs.newnode('prop', + attrs={'body': 'puck', 'position': (-4.5, 2, -6), 'mesh': self._mapFGPModel, 'mesh_scale': 3.73, 'body_scale': 3.73, 'shadow_size': 0.5, 'gravity_scale': 0.0, 'color_texture': self._mapFGPDefaultTex, 'reflection': 'soft', 'reflection_scale': [1.0], 'is_area_of_interest': True, 'materials': [self.dont_collide]}) self.mapFGP14Tex = None - self.mapFGP14col = bs.newnode('region',attrs={'position': (-4.5,2,-6),'scale': (3.5,0.1,3.5),'type': 'box','materials': (self._collide_with_player, shared.footing_material)}) + self.mapFGP14col = bs.newnode('region', attrs={'position': (-4.5, 2, -6), 'scale': ( + 3.5, 0.1, 3.5), 'type': 'box', 'materials': (self._collide_with_player, shared.footing_material)}) self.coldel14 = False if self.coldel15: - self.mapFGP15 = bs.newnode('prop', - attrs={'body': 'puck', 'position': (-4.5,2,-3), 'mesh': self._mapFGPModel, 'mesh_scale': 3.73, 'body_scale': 3.73, 'shadow_size': 0.5, 'gravity_scale':0.0, 'color_texture': self._mapFGPDefaultTex, 'reflection': 'soft', 'reflection_scale': [1.0], 'is_area_of_interest': True, 'materials': [self.dont_collide]}) + self.mapFGP15 = bs.newnode('prop', + attrs={'body': 'puck', 'position': (-4.5, 2, -3), 'mesh': self._mapFGPModel, 'mesh_scale': 3.73, 'body_scale': 3.73, 'shadow_size': 0.5, 'gravity_scale': 0.0, 'color_texture': self._mapFGPDefaultTex, 'reflection': 'soft', 'reflection_scale': [1.0], 'is_area_of_interest': True, 'materials': [self.dont_collide]}) self.mapFGP15Tex = None - self.mapFGP15col = bs.newnode('region',attrs={'position': (-4.5,2,-3),'scale': (3.5,0.1,3.5),'type': 'box','materials': (self._collide_with_player, shared.footing_material)}) + self.mapFGP15col = bs.newnode('region', attrs={'position': (-4.5, 2, -3), 'scale': ( + 3.5, 0.1, 3.5), 'type': 'box', 'materials': (self._collide_with_player, shared.footing_material)}) self.coldel15 = False if self.coldel16: - self.mapFGP16 = bs.newnode('prop', - attrs={'body': 'puck', 'position': (-4.5,2,0), 'mesh': self._mapFGPModel, 'mesh_scale': 3.73, 'body_scale': 3.73, 'shadow_size': 0.5, 'gravity_scale':0.0, 'color_texture': self._mapFGPDefaultTex, 'reflection': 'soft', 'reflection_scale': [1.0], 'is_area_of_interest': True, 'materials': [self.dont_collide]}) + self.mapFGP16 = bs.newnode('prop', + attrs={'body': 'puck', 'position': (-4.5, 2, 0), 'mesh': self._mapFGPModel, 'mesh_scale': 3.73, 'body_scale': 3.73, 'shadow_size': 0.5, 'gravity_scale': 0.0, 'color_texture': self._mapFGPDefaultTex, 'reflection': 'soft', 'reflection_scale': [1.0], 'is_area_of_interest': True, 'materials': [self.dont_collide]}) self.mapFGP16Tex = None - self.mapFGP16col = bs.newnode('region',attrs={'position': (-4.5,2,0),'scale': (3.5,0.1,3.5),'type': 'box','materials': (self._collide_with_player, shared.footing_material)}) + self.mapFGP16col = bs.newnode('region', attrs={'position': (-4.5, 2, 0), 'scale': ( + 3.5, 0.1, 3.5), 'type': 'box', 'materials': (self._collide_with_player, shared.footing_material)}) self.coldel16 = False def _platformTexDefault(self): @@ -876,7 +890,6 @@ def _check_end_game(self) -> None: if living_team_count <= 1: self.end_game() - def end_game(self) -> None: cur_time = bs.time() assert self._timer is not None @@ -929,18 +942,14 @@ def end_game(self) -> None: self.end(results=results) - - - - - - - class MGdefs(): points = {} boxes = {} - boxes['area_of_interest_bounds'] = (0.3544110667, 4.493562578, -2.518391331) + (0.0, 0.0, 0.0) + (16.64754831, 8.06138989, 18.5029888) - boxes['map_bounds'] = (0.2608783669, 4.899663734, -3.543675157) + (0.0, 0.0, 0.0) + (29.23565494, 14.19991443, 29.92689344) + boxes['area_of_interest_bounds'] = ( + 0.3544110667, 4.493562578, -2.518391331) + (0.0, 0.0, 0.0) + (16.64754831, 8.06138989, 18.5029888) + boxes['map_bounds'] = (0.2608783669, 4.899663734, -3.543675157) + \ + (0.0, 0.0, 0.0) + (29.23565494, 14.19991443, 29.92689344) + class MGmap(bs.Map): defs = MGdefs() @@ -983,16 +992,12 @@ def __init__(self) -> None: gnode.vr_near_clip = 0.5 - - - bs._map.register_map(MGmap) - - # ba_meta export plugin class byFreaku(babase.Plugin): def __init__(self): ## Campaign support ## - babase.app.classic.add_coop_practice_level(bs.Level(name='Memory Game', displayname='${GAME}', gametype=MGgame, settings={}, preview_texture_name='achievementOffYouGo')) \ No newline at end of file + babase.app.classic.add_coop_practice_level(bs.Level( + name='Memory Game', displayname='${GAME}', gametype=MGgame, settings={}, preview_texture_name='achievementOffYouGo')) diff --git a/plugins/minigames/musical_flags.py b/plugins/minigames/musical_flags.py index 41828b3c..7934c100 100644 --- a/plugins/minigames/musical_flags.py +++ b/plugins/minigames/musical_flags.py @@ -1,31 +1,31 @@ -## Made by MattZ45986 on GitHub -## Ported by your friend: Freaku +# Made by MattZ45986 on GitHub +# Ported by your friend: Freaku -#Bug Fixes & Improvements as well... +# Bug Fixes & Improvements as well... -#Join BCS: +# Join BCS: # https://discord.gg/ucyaesh - - from __future__ import annotations from typing import TYPE_CHECKING -import _babase, random, math +import _babase +import random +import math import bascenev1 as bs -from bascenev1lib.actor.flag import Flag,FlagPickedUpMessage +from bascenev1lib.actor.flag import Flag, FlagPickedUpMessage from bascenev1lib.actor.playerspaz import PlayerSpaz if TYPE_CHECKING: from typing import Any, Type, List, Dict, Tuple, Union, Sequence, Optional - class Player(bs.Player['Team']): def __init__(self) -> None: self.done: bool = False self.survived: bool = True + class Team(bs.Team[Player]): def __init__(self) -> None: self.score = 0 @@ -73,23 +73,23 @@ def __init__(self, settings: dict): self.is_run = bool(settings['Enable Running']) self._textRound = bs.newnode('text', - attrs={'text': '', - 'position': (0, -38), - 'scale': 1, - 'shadow': 1.0, - 'flatness': 1.0, - 'color': (1.0, 0.0, 1.0), - 'opacity': 1, - 'v_attach': 'top', - 'h_attach': 'center', - 'h_align': 'center', - 'v_align': 'center'}) + attrs={'text': '', + 'position': (0, -38), + 'scale': 1, + 'shadow': 1.0, + 'flatness': 1.0, + 'color': (1.0, 0.0, 1.0), + 'opacity': 1, + 'v_attach': 'top', + 'h_attach': 'center', + 'h_align': 'center', + 'v_align': 'center'}) self.round_time = int(settings['Max Round Time']) self.reset_round_time = int(settings['Max Round Time']) self.should_die_occur = True self.round_time_textnode = bs.newnode('text', - attrs={ - 'text': "",'flatness':1.0,'h_align':'center','h_attach':'center','v_attach':'top','v_align':'center','position':(0,-15),'scale':0.9,'color':(1,0.7,0.9)}) + attrs={ + 'text': "", 'flatness': 1.0, 'h_align': 'center', 'h_attach': 'center', 'v_attach': 'top', 'v_align': 'center', 'position': (0, -15), 'scale': 0.9, 'color': (1, 0.7, 0.9)}) self.slow_motion = self._epic_mode # A cool music, matching our gamemode theme @@ -106,7 +106,7 @@ def on_player_join(self, player: Player) -> None: bs.broadcastmessage( bs.Lstr(resource='playerDelayedJoinText', subs=[('${PLAYER}', player.getname(full=True))]), - color=(0, 1, 0),transient=True) + color=(0, 1, 0), transient=True) player.survived = False return self.spawn_player(player) @@ -125,14 +125,14 @@ def on_begin(self) -> None: self.spawned = [] if self.credit_text: t = bs.newnode('text', - attrs={ 'text':"Ported by Freaku\nMade by MattZ45986", ## Disable 'Enable Bottom Credits' when making playlist, No need to edit this lovely... - 'scale':0.7, - 'position':(0,0), - 'shadow':0.5, - 'flatness':1.2, - 'color':(1, 1, 1), - 'h_align':'center', - 'v_attach':'bottom'}) + attrs={'text': "Ported by Freaku\nMade by MattZ45986", # Disable 'Enable Bottom Credits' when making playlist, No need to edit this lovely... + 'scale': 0.7, + 'position': (0, 0), + 'shadow': 0.5, + 'flatness': 1.2, + 'color': (1, 1, 1), + 'h_align': 'center', + 'v_attach': 'bottom'}) self.makeRound() self._textRound.text = 'Round ' + str(self.roundNum) bs.timer(3, self.checkEnd) @@ -147,14 +147,15 @@ def _timeround(self): if not player.done: try: player.survived = False - player.actor.handlemessage(bs.StandMessage((0,3,-2))) - bs.timer(0.5,bs.Call(player.actor.handlemessage, bs.FreezeMessage())) - bs.timer(1.5,bs.Call(player.actor.handlemessage, bs.FreezeMessage())) - bs.timer(2.5,bs.Call(player.actor.handlemessage, bs.FreezeMessage())) - bs.timer(3,bs.Call(player.actor.handlemessage, bs.ShouldShatterMessage())) - except: pass - bs.timer(3.5,self.killRound) - bs.timer(3.55,self.makeRound) + player.actor.handlemessage(bs.StandMessage((0, 3, -2))) + bs.timer(0.5, bs.Call(player.actor.handlemessage, bs.FreezeMessage())) + bs.timer(1.5, bs.Call(player.actor.handlemessage, bs.FreezeMessage())) + bs.timer(2.5, bs.Call(player.actor.handlemessage, bs.FreezeMessage())) + bs.timer(3, bs.Call(player.actor.handlemessage, bs.ShouldShatterMessage())) + except: + pass + bs.timer(3.5, self.killRound) + bs.timer(3.55, self.makeRound) self.round_time_textnode.opacity = 0 self.round_time = self.reset_round_time else: @@ -163,7 +164,8 @@ def _timeround(self): def makeRound(self): for player in self.players: - if player.survived: player.team.score += 1 + if player.survived: + player.team.score += 1 self.roundNum += 1 self._textRound.text = 'Round ' + str(self.roundNum) self.flags = [] @@ -171,48 +173,57 @@ def makeRound(self): self.should_die_occur = True self.round_time = self.reset_round_time self.round_time_textnode.opacity = 1 - angle = random.randint(0,359) - c=0 + angle = random.randint(0, 359) + c = 0 for player in self.players: - if player.survived: c+=1 + if player.survived: + c += 1 spacing = 10 for player in self.players: player.done = False if player.survived: if not player.is_alive(): - self.spawn_player(player,(.5,5,-4)) + self.spawn_player(player, (.5, 5, -4)) self.spawned.append(player) - try: spacing = 360 // (c) - except: self.checkEnd() - colors = [(1,0,0),(0,1,0),(0,0,1),(1,1,0),(1,0,1),(0,1,1),(0,0,0),(0.5,0.8,0),(0,0.8,0.5),(0.8,0.25,0.7),(0,0.27,0.55),(2,2,0.6),(0.4,3,0.85)] - + try: + spacing = 360 // (c) + except: + self.checkEnd() + colors = [(1, 0, 0), (0, 1, 0), (0, 0, 1), (1, 1, 0), (1, 0, 1), (0, 1, 1), (0, 0, 0), + (0.5, 0.8, 0), (0, 0.8, 0.5), (0.8, 0.25, 0.7), (0, 0.27, 0.55), (2, 2, 0.6), (0.4, 3, 0.85)] + # Add support for more than 13 players if c > 12: for i in range(c-12): - colors.append((random.uniform(0.1, 1), random.uniform(0.1, 1), random.uniform(0.1, 1))) - + colors.append((random.uniform(0.1, 1), random.uniform( + 0.1, 1), random.uniform(0.1, 1))) + # Smart Mathematics: # All Flags spawn same distance from the players for i in range(c-1): angle += spacing angle %= 360 - x=6 * math.sin(math.degrees(angle)) - z=6 * math.cos(math.degrees(angle)) - flag = Flag(position=(x+.5,5,z-4), color=colors[i]).autoretain() + x = 6 * math.sin(math.degrees(angle)) + z = 6 * math.cos(math.degrees(angle)) + flag = Flag(position=(x+.5, 5, z-4), color=colors[i]).autoretain() self.flags.append(flag) def killRound(self): self.numPickedUp = 0 for player in self.players: - if player.is_alive(): player.actor.handlemessage(bs.DieMessage()) - for flag in self.flags: flag.node.delete() - for light in self.nodes: light.delete() - - def spawn_player(self, player: Player, pos: tuple = (0,0,0)) -> bs.Actor: + if player.is_alive(): + player.actor.handlemessage(bs.DieMessage()) + for flag in self.flags: + flag.node.delete() + for light in self.nodes: + light.delete() + + def spawn_player(self, player: Player, pos: tuple = (0, 0, 0)) -> bs.Actor: spaz = self.spawn_player_spaz(player) - if pos == (0,0,0): - pos = (-.5+random.random()*2,3+random.random()*2,-5+random.random()*2) - spaz.connect_controls_to_player(enable_punch=self.is_punch, enable_bomb=False, enable_run=self.is_run) + if pos == (0, 0, 0): + pos = (-.5+random.random()*2, 3+random.random()*2, -5+random.random()*2) + spaz.connect_controls_to_player(enable_punch=self.is_punch, + enable_bomb=False, enable_run=self.is_run) spaz.handlemessage(bs.StandMessage(pos)) return spaz @@ -231,10 +242,10 @@ def handlemessage(self, msg: Any) -> Any: self.numPickedUp += 1 msg.node.getdelegate(PlayerSpaz, True).getplayer(Player, True).done = True l = bs.newnode('light', - owner=None, - attrs={'color':msg.node.color, - 'position':(msg.node.position_center), - 'intensity':1}) + owner=None, + attrs={'color': msg.node.color, + 'position': (msg.node.position_center), + 'intensity': 1}) self.nodes.append(l) msg.flag.handlemessage(bs.DieMessage()) msg.node.handlemessage(bs.DieMessage()) @@ -247,12 +258,13 @@ def handlemessage(self, msg: Any) -> Any: try: player.survived = False bs.broadcastmessage("No Flag? "+player.getname()) - player.actor.handlemessage(bs.StandMessage((0,3,-2))) - bs.timer(0.5,bs.Call(player.actor.handlemessage, bs.FreezeMessage())) - bs.timer(3,bs.Call(player.actor.handlemessage, bs.ShouldShatterMessage())) - except: pass - bs.timer(3.5,self.killRound) - bs.timer(3.55,self.makeRound) + player.actor.handlemessage(bs.StandMessage((0, 3, -2))) + bs.timer(0.5, bs.Call(player.actor.handlemessage, bs.FreezeMessage())) + bs.timer(3, bs.Call(player.actor.handlemessage, bs.ShouldShatterMessage())) + except: + pass + bs.timer(3.5, self.killRound) + bs.timer(3.55, self.makeRound) else: return super().handlemessage(msg) return None @@ -261,7 +273,7 @@ def checkEnd(self): i = 0 for player in self.players: if player.survived: - i+=1 + i += 1 if i <= 1: for player in self.players: if player.survived: @@ -272,4 +284,4 @@ def end_game(self) -> None: results = bs.GameResults() for team in self.teams: results.set_team_score(team, team.score) - self.end(results=results) \ No newline at end of file + self.end(results=results) diff --git a/plugins/minigames/volleyball.py b/plugins/minigames/volleyball.py index b2559503..df4c19a1 100644 --- a/plugins/minigames/volleyball.py +++ b/plugins/minigames/volleyball.py @@ -3,20 +3,14 @@ # Made by your friend: Freaku - - # Join BCS: # https://discord.gg/ucyaesh - - # My GitHub: # https://github.com/Freaku17/BombSquad-Mods-byFreaku - - # CHANGELOG: """ ## 2021 @@ -38,21 +32,14 @@ """ - - - - - - - - # ba_meta require api 8 from __future__ import annotations from typing import TYPE_CHECKING -import babase, random +import babase +import random import bascenev1 as bs from bascenev1lib.actor.playerspaz import PlayerSpaz from bascenev1lib.actor.scoreboard import Scoreboard @@ -64,7 +51,6 @@ from typing import Any, Sequence, Dict, Type, List, Optional, Union - class PuckDiedMessage: """Inform something that a puck has died.""" @@ -100,14 +86,13 @@ def __init__(self, position: Sequence[float] = (0.0, 1.0, 0.0)): 'position': self._spawn_pos, 'materials': pmats }) - + # Since it rolls on spawn, lets make gravity # to 0, and when another node (bomb/spaz) # touches it. It'll act back as our normie puck! - bs.animate(self.node, 'gravity_scale', {0:-0.1, 0.2:1}, False) + bs.animate(self.node, 'gravity_scale', {0: -0.1, 0.2: 1}, False) # When other node touches, it realises its new gravity_scale - def handlemessage(self, msg: Any) -> Any: if isinstance(msg, bs.DieMessage): assert self.node @@ -148,6 +133,7 @@ class Player(bs.Player['Team']): class Team(bs.Team[Player]): """Our team type for this game.""" + def __init__(self) -> None: self.score = 0 @@ -253,15 +239,14 @@ def __init__(self, settings: dict): actions=(('modify_part_collision', 'collide', True), ('modify_part_collision', 'physical', False), ('call', 'at_connect', self._handle_score))) - - - self._wall_material=bs.Material() - self._fake_wall_material=bs.Material() + + self._wall_material = bs.Material() + self._fake_wall_material = bs.Material() self._wall_material.add_actions( - + actions=( ('modify_part_collision', 'friction', 100000), - )) + )) self._wall_material.add_actions( conditions=('they_have_material', shared.pickup_material), actions=( @@ -270,13 +255,13 @@ def __init__(self, settings: dict): self._wall_material.add_actions( conditions=(('we_are_younger_than', 100), - 'and', - ('they_have_material',shared.object_material)), + 'and', + ('they_have_material', shared.object_material)), actions=( ('modify_part_collision', 'collide', False), )) self._wall_material.add_actions( - conditions=('they_have_material',shared.footing_material), + conditions=('they_have_material', shared.footing_material), actions=( ('modify_part_collision', 'friction', 9999.5), )) @@ -285,25 +270,24 @@ def __init__(self, settings: dict): actions=( ('modify_part_collision', 'collide', False), ('modify_part_collision', 'physical', False) - + )) self._fake_wall_material.add_actions( conditions=('they_have_material', shared.player_material), actions=( ('modify_part_collision', 'collide', True), ('modify_part_collision', 'physical', True) - - )) - self.blocks=[] + )) + self.blocks = [] - self._net_wall_material=bs.Material() + self._net_wall_material = bs.Material() self._net_wall_material.add_actions( conditions=('they_have_material', shared.player_material), actions=( ('modify_part_collision', 'collide', True), ('modify_part_collision', 'physical', True) - + )) self._net_wall_material.add_actions( @@ -321,8 +305,7 @@ def __init__(self, settings: dict): actions=( ('modify_part_collision', 'collide', True), )) - self.net_blocc=[] - + self.net_blocc = [] self._puck_spawn_pos: Optional[Sequence[float]] = None self._score_regions: Optional[List[bs.NodeActor]] = None @@ -365,7 +348,7 @@ def on_begin(self) -> None: bs.NodeActor( bs.newnode('region', attrs={ - 'position':(5.7, 0, -0.065), + 'position': (5.7, 0, -0.065), 'scale': (10.7, 0.001, 8), 'type': 'box', 'materials': [self._score_region_material] @@ -374,7 +357,7 @@ def on_begin(self) -> None: bs.NodeActor( bs.newnode('region', attrs={ - 'position':(-5.7, 0, -0.065), + 'position': (-5.7, 0, -0.065), 'scale': (10.7, 0.001, 8), 'type': 'box', 'materials': [self._score_region_material] @@ -383,18 +366,20 @@ def on_begin(self) -> None: self._chant_sound.play() if self.credit_text: t = bs.newnode('text', - attrs={ 'text':"Created by Freaku\nVolleyBall", ## Disable 'Enable Bottom Credits' when making playlist, No need to edit this lovely... - 'scale':0.7, - 'position':(0,0), - 'shadow':0.5, - 'flatness':1.2, - 'color':(1, 1, 1), - 'h_align':'center', - 'v_attach':'bottom'}) + attrs={'text': "Created by Freaku\nVolleyBall", # Disable 'Enable Bottom Credits' when making playlist, No need to edit this lovely... + 'scale': 0.7, + 'position': (0, 0), + 'shadow': 0.5, + 'flatness': 1.2, + 'color': (1, 1, 1), + 'h_align': 'center', + 'v_attach': 'bottom'}) shared = SharedObjects.get() - self.blocks.append(bs.NodeActor(bs.newnode('region',attrs={'position': (0,2.4,0),'scale': (0.8,6,20),'type': 'box','materials': (self._fake_wall_material, )}))) - - self.net_blocc.append(bs.NodeActor(bs.newnode('region',attrs={'position': (0,0,0),'scale': (0.6,2.4,20),'type': 'box','materials': (self._net_wall_material, )}))) + self.blocks.append(bs.NodeActor(bs.newnode('region', attrs={'position': (0, 2.4, 0), 'scale': ( + 0.8, 6, 20), 'type': 'box', 'materials': (self._fake_wall_material, )}))) + + self.net_blocc.append(bs.NodeActor(bs.newnode('region', attrs={'position': (0, 0, 0), 'scale': ( + 0.6, 2.4, 20), 'type': 'box', 'materials': (self._net_wall_material, )}))) def on_team_join(self, team: Team) -> None: self._update_scoreboard() @@ -434,18 +419,15 @@ def _handle_score(self) -> None: scoring_team = team team.score += 1 - - # Change puck Spawn - if team.id == 0: # left side scored - self._puck_spawn_pos= (5, 0.42, 0) - elif team.id == 1: # right side scored - self._puck_spawn_pos= (-5, 0.42, 0) - else: # normally shouldn't occur - self._puck_spawn_pos= (0, 0.42, 0) + if team.id == 0: # left side scored + self._puck_spawn_pos = (5, 0.42, 0) + elif team.id == 1: # right side scored + self._puck_spawn_pos = (-5, 0.42, 0) + else: # normally shouldn't occur + self._puck_spawn_pos = (0, 0.42, 0) # Easy pizzy - - + for player in team.players: if player.actor: player.actor.handlemessage(bs.CelebrateMessage(2.0)) @@ -469,10 +451,10 @@ def _handle_score(self) -> None: self._puck.scored = True # Kill the puck (it'll respawn itself shortly). - bs.emitfx(position= bs.getcollision().position, count=int(6.0 + 7.0 * 12), scale=3, spread=0.5, chunk_type='spark') + bs.emitfx(position=bs.getcollision().position, count=int( + 6.0 + 7.0 * 12), scale=3, spread=0.5, chunk_type='spark') bs.timer(0.7, self._kill_puck) - bs.cameraflash(duration=7.0) self._update_scoreboard() @@ -502,7 +484,6 @@ def spawn_player(self, player: Player) -> bs.Actor: spaz.bomb_count = 0 # Imagine not being able to swipe those colorful buttons ;( - if self._punchie_: spaz.connect_controls_to_player(enable_punch=False) @@ -525,7 +506,8 @@ def handlemessage(self, msg: Any) -> Any: def _flash_puck_spawn(self) -> None: # Effect >>>>>> Flashly - bs.emitfx(position= self._puck_spawn_pos, count=int(6.0 + 7.0 * 12), scale=1.7, spread=0.4, chunk_type='spark') + bs.emitfx(position=self._puck_spawn_pos, count=int( + 6.0 + 7.0 * 12), scale=1.7, spread=0.4, chunk_type='spark') def _spawn_puck(self) -> None: self._swipsound.play() @@ -535,45 +517,26 @@ def _spawn_puck(self) -> None: self._puck = Puck(position=self._puck_spawn_pos) - - - - - - - - - - - - - - - - - - - - - class Pointzz: points, boxes = {}, {} points['spawn1'] = (-8.03866, 0.02275, 0.0) + (0.5, 0.05, 4.0) points['spawn2'] = (8.82311, 0.01092, 0.0) + (0.5, 0.05, 4.0) - boxes['area_of_interest_bounds'] = (0.0, 1.18575, 0.43262) + (0, 0, 0) + (29.81803, 11.57249, 18.89134) + boxes['area_of_interest_bounds'] = (0.0, 1.18575, 0.43262) + \ + (0, 0, 0) + (29.81803, 11.57249, 18.89134) boxes['map_bounds'] = (0.0, 1.185751251, 0.4326226188) + (0.0, 0.0, 0.0) + ( - 42.09506485, 22.81173179, 29.76723155) + 42.09506485, 22.81173179, 29.76723155) + class PointzzforH: points, boxes = {}, {} - boxes['area_of_interest_bounds'] = (0.0, 0.7956858119, 0.0) + (0.0, 0.0, 0.0) + (30.80223883, 0.5961646365, 13.88431707) + boxes['area_of_interest_bounds'] = (0.0, 0.7956858119, 0.0) + \ + (0.0, 0.0, 0.0) + (30.80223883, 0.5961646365, 13.88431707) boxes['map_bounds'] = (0.0, 0.7956858119, -0.4689020853) + (0.0, 0.0, 0.0) + ( - 35.16182389, 12.18696164, 21.52869693) + 35.16182389, 12.18696164, 21.52869693) points['spawn1'] = (-6.835352227, 0.02305323209, 0.0) + (1.0, 1.0, 3.0) points['spawn2'] = (6.857415055, 0.03938567998, 0.0) + (1.0, 1.0, 3.0) - class VolleyBallMap(bs.Map): defs = Pointzz() name = "Open Field" @@ -595,47 +558,47 @@ def on_preload(cls) -> Any: 'tex': bs.gettexture('footballStadium') } return data - + def __init__(self): super().__init__() shared = SharedObjects.get() x = -5 - while x<5: - self.zone = bs.newnode('locator',attrs={'shape':'circle','position':(0,0,x), - 'color':(1,1,0),'opacity':1,'draw_beauty':True,'additive':False,'size':[0.40]}) - self.zone = bs.newnode('locator',attrs={'shape':'circle','position':(0,.25,x), - 'color':(1,1,0),'opacity':1,'draw_beauty':True,'additive':False,'size':[0.40]}) - self.zone = bs.newnode('locator',attrs={'shape':'circle','position':(0,.5,x), - 'color':(1,1,0),'opacity':1,'draw_beauty':True,'additive':False,'size':[0.40]}) - self.zone = bs.newnode('locator',attrs={'shape':'circle','position':(0,.75,x), - 'color':(1,1,0),'opacity':1,'draw_beauty':True,'additive':False,'size':[0.40]}) - self.zone = bs.newnode('locator',attrs={'shape':'circle','position':(0,1,x), - 'color':(1,1,0),'opacity':1,'draw_beauty':True,'additive':False,'size':[0.40]}) + while x < 5: + self.zone = bs.newnode('locator', attrs={'shape': 'circle', 'position': (0, 0, x), + 'color': (1, 1, 0), 'opacity': 1, 'draw_beauty': True, 'additive': False, 'size': [0.40]}) + self.zone = bs.newnode('locator', attrs={'shape': 'circle', 'position': (0, .25, x), + 'color': (1, 1, 0), 'opacity': 1, 'draw_beauty': True, 'additive': False, 'size': [0.40]}) + self.zone = bs.newnode('locator', attrs={'shape': 'circle', 'position': (0, .5, x), + 'color': (1, 1, 0), 'opacity': 1, 'draw_beauty': True, 'additive': False, 'size': [0.40]}) + self.zone = bs.newnode('locator', attrs={'shape': 'circle', 'position': (0, .75, x), + 'color': (1, 1, 0), 'opacity': 1, 'draw_beauty': True, 'additive': False, 'size': [0.40]}) + self.zone = bs.newnode('locator', attrs={'shape': 'circle', 'position': (0, 1, x), + 'color': (1, 1, 0), 'opacity': 1, 'draw_beauty': True, 'additive': False, 'size': [0.40]}) x = x + 0.5 y = -1 - while y>-11: - self.zone = bs.newnode('locator',attrs={'shape':'circle','position':(y,0.01,4), - 'color':(0,0,1),'opacity':1,'draw_beauty':True,'additive':False,'size':[0.40]}) - self.zone = bs.newnode('locator',attrs={'shape':'circle','position':(y,0.01,-4), - 'color':(0,0,1),'opacity':1,'draw_beauty':True,'additive':False,'size':[0.40]}) - self.zone = bs.newnode('locator',attrs={'shape':'circle','position':(-y,0.01,4), - 'color':(1,0,0),'opacity':1,'draw_beauty':True,'additive':False,'size':[0.40]}) - self.zone = bs.newnode('locator',attrs={'shape':'circle','position':(-y,0.01,-4), - 'color':(1,0,0),'opacity':1,'draw_beauty':True,'additive':False,'size':[0.40]}) - y-=1 + while y > -11: + self.zone = bs.newnode('locator', attrs={'shape': 'circle', 'position': (y, 0.01, 4), + 'color': (0, 0, 1), 'opacity': 1, 'draw_beauty': True, 'additive': False, 'size': [0.40]}) + self.zone = bs.newnode('locator', attrs={'shape': 'circle', 'position': (y, 0.01, -4), + 'color': (0, 0, 1), 'opacity': 1, 'draw_beauty': True, 'additive': False, 'size': [0.40]}) + self.zone = bs.newnode('locator', attrs={'shape': 'circle', 'position': (-y, 0.01, 4), + 'color': (1, 0, 0), 'opacity': 1, 'draw_beauty': True, 'additive': False, 'size': [0.40]}) + self.zone = bs.newnode('locator', attrs={'shape': 'circle', 'position': (-y, 0.01, -4), + 'color': (1, 0, 0), 'opacity': 1, 'draw_beauty': True, 'additive': False, 'size': [0.40]}) + y -= 1 z = 0 - while z<5: - self.zone = bs.newnode('locator',attrs={'shape':'circle','position':(11,0.01,z), - 'color':(1,0,0),'opacity':1,'draw_beauty':True,'additive':False,'size':[0.40]}) - self.zone = bs.newnode('locator',attrs={'shape':'circle','position':(11,0.01,-z), - 'color':(1,0,0),'opacity':1,'draw_beauty':True,'additive':False,'size':[0.40]}) - self.zone = bs.newnode('locator',attrs={'shape':'circle','position':(-11,0.01,z), - 'color':(0,0,1),'opacity':1,'draw_beauty':True,'additive':False,'size':[0.40]}) - self.zone = bs.newnode('locator',attrs={'shape':'circle','position':(-11,0.01,-z), - 'color':(0,0,1),'opacity':1,'draw_beauty':True,'additive':False,'size':[0.40]}) - z+=1 + while z < 5: + self.zone = bs.newnode('locator', attrs={'shape': 'circle', 'position': (11, 0.01, z), + 'color': (1, 0, 0), 'opacity': 1, 'draw_beauty': True, 'additive': False, 'size': [0.40]}) + self.zone = bs.newnode('locator', attrs={'shape': 'circle', 'position': (11, 0.01, -z), + 'color': (1, 0, 0), 'opacity': 1, 'draw_beauty': True, 'additive': False, 'size': [0.40]}) + self.zone = bs.newnode('locator', attrs={'shape': 'circle', 'position': (-11, 0.01, z), + 'color': (0, 0, 1), 'opacity': 1, 'draw_beauty': True, 'additive': False, 'size': [0.40]}) + self.zone = bs.newnode('locator', attrs={'shape': 'circle', 'position': (-11, 0.01, -z), + 'color': (0, 0, 1), 'opacity': 1, 'draw_beauty': True, 'additive': False, 'size': [0.40]}) + z += 1 self.node = bs.newnode( 'terrain', @@ -663,7 +626,6 @@ def __init__(self): gnode.vr_near_clip = 0.5 - class VolleyBallMapH(bs.Map): defs = PointzzforH() name = 'Closed Arena' @@ -680,7 +642,7 @@ def get_preview_texture_name(cls) -> str: def on_preload(cls) -> Any: data: Dict[str, Any] = { 'meshs': (bs.getmesh('hockeyStadiumOuter'), - bs.getmesh('hockeyStadiumInner')), + bs.getmesh('hockeyStadiumInner')), 'vr_fill_mesh': bs.getmesh('footballStadiumVRFill'), 'collision_mesh': bs.getcollisionmesh('hockeyStadiumCollide'), 'tex': bs.gettexture('hockeyStadium'), @@ -694,42 +656,42 @@ def __init__(self) -> None: super().__init__() shared = SharedObjects.get() x = -5 - while x<5: - self.zone = bs.newnode('locator',attrs={'shape':'circle','position':(0,0,x), - 'color':(1,1,0),'opacity':1,'draw_beauty':True,'additive':False,'size':[0.40]}) - self.zone = bs.newnode('locator',attrs={'shape':'circle','position':(0,.25,x), - 'color':(1,1,0),'opacity':1,'draw_beauty':True,'additive':False,'size':[0.40]}) - self.zone = bs.newnode('locator',attrs={'shape':'circle','position':(0,.5,x), - 'color':(1,1,0),'opacity':1,'draw_beauty':True,'additive':False,'size':[0.40]}) - self.zone = bs.newnode('locator',attrs={'shape':'circle','position':(0,.75,x), - 'color':(1,1,0),'opacity':1,'draw_beauty':True,'additive':False,'size':[0.40]}) - self.zone = bs.newnode('locator',attrs={'shape':'circle','position':(0,1,x), - 'color':(1,1,0),'opacity':1,'draw_beauty':True,'additive':False,'size':[0.40]}) + while x < 5: + self.zone = bs.newnode('locator', attrs={'shape': 'circle', 'position': (0, 0, x), + 'color': (1, 1, 0), 'opacity': 1, 'draw_beauty': True, 'additive': False, 'size': [0.40]}) + self.zone = bs.newnode('locator', attrs={'shape': 'circle', 'position': (0, .25, x), + 'color': (1, 1, 0), 'opacity': 1, 'draw_beauty': True, 'additive': False, 'size': [0.40]}) + self.zone = bs.newnode('locator', attrs={'shape': 'circle', 'position': (0, .5, x), + 'color': (1, 1, 0), 'opacity': 1, 'draw_beauty': True, 'additive': False, 'size': [0.40]}) + self.zone = bs.newnode('locator', attrs={'shape': 'circle', 'position': (0, .75, x), + 'color': (1, 1, 0), 'opacity': 1, 'draw_beauty': True, 'additive': False, 'size': [0.40]}) + self.zone = bs.newnode('locator', attrs={'shape': 'circle', 'position': (0, 1, x), + 'color': (1, 1, 0), 'opacity': 1, 'draw_beauty': True, 'additive': False, 'size': [0.40]}) x = x + 0.5 y = -1 - while y>-11: - self.zone = bs.newnode('locator',attrs={'shape':'circle','position':(y,0.01,4), - 'color':(0,0,1),'opacity':1,'draw_beauty':True,'additive':False,'size':[0.40]}) - self.zone = bs.newnode('locator',attrs={'shape':'circle','position':(y,0.01,-4), - 'color':(0,0,1),'opacity':1,'draw_beauty':True,'additive':False,'size':[0.40]}) - self.zone = bs.newnode('locator',attrs={'shape':'circle','position':(-y,0.01,4), - 'color':(1,0,0),'opacity':1,'draw_beauty':True,'additive':False,'size':[0.40]}) - self.zone = bs.newnode('locator',attrs={'shape':'circle','position':(-y,0.01,-4), - 'color':(1,0,0),'opacity':1,'draw_beauty':True,'additive':False,'size':[0.40]}) - y-=1 + while y > -11: + self.zone = bs.newnode('locator', attrs={'shape': 'circle', 'position': (y, 0.01, 4), + 'color': (0, 0, 1), 'opacity': 1, 'draw_beauty': True, 'additive': False, 'size': [0.40]}) + self.zone = bs.newnode('locator', attrs={'shape': 'circle', 'position': (y, 0.01, -4), + 'color': (0, 0, 1), 'opacity': 1, 'draw_beauty': True, 'additive': False, 'size': [0.40]}) + self.zone = bs.newnode('locator', attrs={'shape': 'circle', 'position': (-y, 0.01, 4), + 'color': (1, 0, 0), 'opacity': 1, 'draw_beauty': True, 'additive': False, 'size': [0.40]}) + self.zone = bs.newnode('locator', attrs={'shape': 'circle', 'position': (-y, 0.01, -4), + 'color': (1, 0, 0), 'opacity': 1, 'draw_beauty': True, 'additive': False, 'size': [0.40]}) + y -= 1 z = 0 - while z<5: - self.zone = bs.newnode('locator',attrs={'shape':'circle','position':(11,0.01,z), - 'color':(1,0,0),'opacity':1,'draw_beauty':True,'additive':False,'size':[0.40]}) - self.zone = bs.newnode('locator',attrs={'shape':'circle','position':(11,0.01,-z), - 'color':(1,0,0),'opacity':1,'draw_beauty':True,'additive':False,'size':[0.40]}) - self.zone = bs.newnode('locator',attrs={'shape':'circle','position':(-11,0.01,z), - 'color':(0,0,1),'opacity':1,'draw_beauty':True,'additive':False,'size':[0.40]}) - self.zone = bs.newnode('locator',attrs={'shape':'circle','position':(-11,0.01,-z), - 'color':(0,0,1),'opacity':1,'draw_beauty':True,'additive':False,'size':[0.40]}) - z+=1 + while z < 5: + self.zone = bs.newnode('locator', attrs={'shape': 'circle', 'position': (11, 0.01, z), + 'color': (1, 0, 0), 'opacity': 1, 'draw_beauty': True, 'additive': False, 'size': [0.40]}) + self.zone = bs.newnode('locator', attrs={'shape': 'circle', 'position': (11, 0.01, -z), + 'color': (1, 0, 0), 'opacity': 1, 'draw_beauty': True, 'additive': False, 'size': [0.40]}) + self.zone = bs.newnode('locator', attrs={'shape': 'circle', 'position': (-11, 0.01, z), + 'color': (0, 0, 1), 'opacity': 1, 'draw_beauty': True, 'additive': False, 'size': [0.40]}) + self.zone = bs.newnode('locator', attrs={'shape': 'circle', 'position': (-11, 0.01, -z), + 'color': (0, 0, 1), 'opacity': 1, 'draw_beauty': True, 'additive': False, 'size': [0.40]}) + z += 1 self.node = bs.newnode('terrain', delegate=self, @@ -737,7 +699,8 @@ def __init__(self) -> None: 'mesh': None, 'collision_mesh': - bs.getcollisionmesh('footballStadiumCollide'), # we dont want Goalposts... + # we dont want Goalposts... + bs.getcollisionmesh('footballStadiumCollide'), 'color_texture': self.preloaddata['tex'], 'materials': [ @@ -758,7 +721,7 @@ def __init__(self) -> None: 'opacity': 0.92, 'opacity_in_low_or_medium_quality': 1.0, 'materials': mats, - 'color': (0.4,0.9,0) + 'color': (0.4, 0.9, 0) }) self.background = bs.newnode( @@ -767,7 +730,7 @@ def __init__(self) -> None: 'mesh': bs.getmesh('natureBackground'), 'lighting': False, 'background': True, - 'color': (0.5,0.30,0.4) + 'color': (0.5, 0.30, 0.4) }) gnode = bs.getactivity().globalsnode @@ -783,8 +746,6 @@ def __init__(self) -> None: #self.is_hockey = True - - bs._map.register_map(VolleyBallMap) bs._map.register_map(VolleyBallMapH) @@ -798,4 +759,4 @@ def __init__(self): # Then why not include function here? # On server upon first launch, plugins are not activated, # (same can be case for user if disabled auto-enable plugins) - pass \ No newline at end of file + pass diff --git a/plugins/utilities/floater.py b/plugins/utilities/floater.py index c05b3a52..28e943ec 100644 --- a/plugins/utilities/floater.py +++ b/plugins/utilities/floater.py @@ -1,18 +1,20 @@ # Ported by your friend: Freaku -#Join BCS: +# Join BCS: # https://discord.gg/ucyaesh -#My GitHub: +# My GitHub: # https://github.com/Freaku17/BombSquad-Mods-byFreaku - # ba_meta require api 8 from __future__ import annotations from typing import TYPE_CHECKING -import _babase, babase, random, math +import _babase +import babase +import random +import math import bauiv1 as bui import bascenev1 as bs from bascenev1lib.gameutils import SharedObjects @@ -110,7 +112,8 @@ def __init__(self, bounds): }) self.node.connectattr('position', self.node2, 'position') - def pop(self): PopupText(text="Ported by \ue048Freaku", scale=1.3, position=(self.node.position[0],self.node.position[1]-1,self.node.position[2]), color=(0,1,1)).autoretain() + def pop(self): PopupText(text="Ported by \ue048Freaku", scale=1.3, position=( + self.node.position[0], self.node.position[1]-1, self.node.position[2]), color=(0, 1, 1)).autoretain() def checkCanControl(self): if not self.node.exists(): @@ -186,7 +189,8 @@ def drop(self): np = self.node.position except: np = (0, 0, 0) - self.b = Bomb(bomb_type=random.choice(['normal', 'ice', 'sticky', 'impact', 'land_mine', 'tnt']), source_player=self.source_player, position=(np[0], np[1] - 1, np[2]), velocity=(0, -1, 0)).autoretain() + self.b = Bomb(bomb_type=random.choice(['normal', 'ice', 'sticky', 'impact', 'land_mine', 'tnt']), + source_player=self.source_player, position=(np[0], np[1] - 1, np[2]), velocity=(0, -1, 0)).autoretain() if self.b.bomb_type in ['impact', 'land_mine']: self.b.arm() @@ -198,7 +202,7 @@ def move(self): pn = self.node.position dist = self.distance(pn[0], pn[1], pn[2], px, py, pz) self.node.velocity = ((px - pn[0]) / dist, (py - pn[1]) / dist, (pz - pn[2]) / dist) - bs.timer(dist-1, bs.WeakCall(self.move)) #suppress_format_warning=True) + bs.timer(dist-1, bs.WeakCall(self.move)) # suppress_format_warning=True) def handlemessage(self, msg): if isinstance(msg, bs.DieMessage): @@ -211,21 +215,21 @@ def handlemessage(self, msg): super().handlemessage(msg) - - - - def assignFloInputs(clientID: int): activity = bs.get_foreground_host_activity() with activity.context: if not hasattr(activity, 'flo') or not activity.flo.node.exists(): - try: activity.flo = Floater(activity.map.get_def_bound_box('map_bounds')) - except: return #Perhaps using in main-menu/score-screen + try: + activity.flo = Floater(activity.map.get_def_bound_box('map_bounds')) + except: + return # Perhaps using in main-menu/score-screen floater = activity.flo if floater.controlled: - bs.broadcastmessage('Floater is already being controlled', color=(1, 0, 0), transient=True, clients=[clientID]) + bs.broadcastmessage('Floater is already being controlled', + color=(1, 0, 0), transient=True, clients=[clientID]) return - bs.broadcastmessage('You Gained Control Over The Floater!\n Press Bomb to Throw Bombs and Punch to leave!', clients=[clientID], transient=True, color=(0, 1, 1)) + bs.broadcastmessage('You Gained Control Over The Floater!\n Press Bomb to Throw Bombs and Punch to leave!', clients=[ + clientID], transient=True, color=(0, 1, 1)) for i in activity.players: if i.sessionplayer.inputdevice.client_id == clientID: @@ -259,20 +263,32 @@ def dis(i, floater): old_piv = bui.set_party_icon_always_visible + + def new_piv(*args, **kwargs): # Do not let chat icon go away old_piv(True) + + bui.set_party_icon_always_visible = new_piv old_fcm = bs.chatmessage + + def new_chat_message(*args, **kwargs): old_fcm(*args, **kwargs) if args[0] == '/floater': - try: assignFloInputs(-1) - except: pass + try: + assignFloInputs(-1) + except: + pass + + bs.chatmessage = new_chat_message # ba_meta export plugin + + class byFreaku(babase.Plugin): - def __init__(self): pass \ No newline at end of file + def __init__(self): pass diff --git a/plugins/utilities/icons_keyboard.py b/plugins/utilities/icons_keyboard.py index bbb48abb..74476602 100644 --- a/plugins/utilities/icons_keyboard.py +++ b/plugins/utilities/icons_keyboard.py @@ -6,8 +6,6 @@ # Double tap the space to change between keyboards... - - # ba_meta require api 8 from __future__ import annotations @@ -19,12 +17,7 @@ from babase import charstr as uwu if TYPE_CHECKING: - from typing import Any, Optional, Dict, List, Tuple,Type, Iterable - - - - - + from typing import Any, Optional, Dict, List, Tuple, Type, Iterable # ba_meta export keyboard @@ -32,33 +25,33 @@ class IconKeyboard_byFreaku(babase.Keyboard): """Keyboard go brrrrrrr""" name = 'Icons by \ue048Freaku' chars = [(uwu(babase.SpecialChar.TICKET), - uwu(babase.SpecialChar.CROWN), - uwu(babase.SpecialChar.DRAGON), - uwu(babase.SpecialChar.SKULL), - uwu(babase.SpecialChar.HEART), - uwu(babase.SpecialChar.FEDORA), - uwu(babase.SpecialChar.HAL), - uwu(babase.SpecialChar.YIN_YANG), - uwu(babase.SpecialChar.EYE_BALL), - uwu(babase.SpecialChar.HELMET), - uwu(babase.SpecialChar.OUYA_BUTTON_U)), - (uwu(babase.SpecialChar.MUSHROOM), - uwu(babase.SpecialChar.NINJA_STAR), - uwu(babase.SpecialChar.VIKING_HELMET), - uwu(babase.SpecialChar.MOON), - uwu(babase.SpecialChar.SPIDER), - uwu(babase.SpecialChar.FIREBALL), - uwu(babase.SpecialChar.MIKIROG), - uwu(babase.SpecialChar.OUYA_BUTTON_O), - uwu(babase.SpecialChar.LOCAL_ACCOUNT), - uwu(babase.SpecialChar.LOGO)), - (uwu(babase.SpecialChar.TICKET), - uwu(babase.SpecialChar.FLAG_INDIA), - uwu(babase.SpecialChar.OCULUS_LOGO), - uwu(babase.SpecialChar.STEAM_LOGO), - uwu(babase.SpecialChar.NVIDIA_LOGO), - uwu(babase.SpecialChar.GAME_CENTER_LOGO), - uwu(babase.SpecialChar.GOOGLE_PLAY_GAMES_LOGO), - uwu(babase.SpecialChar.EXPLODINARY_LOGO))] + uwu(babase.SpecialChar.CROWN), + uwu(babase.SpecialChar.DRAGON), + uwu(babase.SpecialChar.SKULL), + uwu(babase.SpecialChar.HEART), + uwu(babase.SpecialChar.FEDORA), + uwu(babase.SpecialChar.HAL), + uwu(babase.SpecialChar.YIN_YANG), + uwu(babase.SpecialChar.EYE_BALL), + uwu(babase.SpecialChar.HELMET), + uwu(babase.SpecialChar.OUYA_BUTTON_U)), + (uwu(babase.SpecialChar.MUSHROOM), + uwu(babase.SpecialChar.NINJA_STAR), + uwu(babase.SpecialChar.VIKING_HELMET), + uwu(babase.SpecialChar.MOON), + uwu(babase.SpecialChar.SPIDER), + uwu(babase.SpecialChar.FIREBALL), + uwu(babase.SpecialChar.MIKIROG), + uwu(babase.SpecialChar.OUYA_BUTTON_O), + uwu(babase.SpecialChar.LOCAL_ACCOUNT), + uwu(babase.SpecialChar.LOGO)), + (uwu(babase.SpecialChar.TICKET), + uwu(babase.SpecialChar.FLAG_INDIA), + uwu(babase.SpecialChar.OCULUS_LOGO), + uwu(babase.SpecialChar.STEAM_LOGO), + uwu(babase.SpecialChar.NVIDIA_LOGO), + uwu(babase.SpecialChar.GAME_CENTER_LOGO), + uwu(babase.SpecialChar.GOOGLE_PLAY_GAMES_LOGO), + uwu(babase.SpecialChar.EXPLODINARY_LOGO))] nums = [] - pages: Dict[str, Tuple[str, ...]] = {} \ No newline at end of file + pages: Dict[str, Tuple[str, ...]] = {} diff --git a/plugins/utilities/unlock_TowerD.py b/plugins/utilities/unlock_TowerD.py index 6a219f1b..172e8c07 100644 --- a/plugins/utilities/unlock_TowerD.py +++ b/plugins/utilities/unlock_TowerD.py @@ -16,4 +16,4 @@ def new_play_types(cls): # ba_meta export plugin class byFreaku(babase.Plugin): def on_app_running(self): - TowerD.get_play_types = new_play_types \ No newline at end of file + TowerD.get_play_types = new_play_types From fd23e65ed35c6c50b8da84019d30c29de395b5e4 Mon Sep 17 00:00:00 2001 From: Freaku17 Date: Fri, 28 Jul 2023 11:37:11 +0000 Subject: [PATCH 0650/1464] [ci] apply-version-metadata --- plugins/minigames.json | 42 ++++++++++++++++++++++++++++++++++++------ plugins/utilities.json | 21 ++++++++++++++++++--- 2 files changed, 54 insertions(+), 9 deletions(-) diff --git a/plugins/minigames.json b/plugins/minigames.json index c7e2d6dc..f9e721db 100644 --- a/plugins/minigames.json +++ b/plugins/minigames.json @@ -38,7 +38,12 @@ } ], "versions": { - "1.0.0": null + "1.0.0": { + "api_version": 8, + "commit_sha": "7dcf3c7", + "released_on": "28-07-2023", + "md5sum": "cedc448a3d625065d586445e115fcd1f" + } } }, "frozen_one": { @@ -51,7 +56,12 @@ } ], "versions": { - "1.0.0": null + "1.0.0": { + "api_version": 8, + "commit_sha": "7dcf3c7", + "released_on": "28-07-2023", + "md5sum": "529c8b9c9a450317d5aa75e8eab47497" + } } }, "simon_says": { @@ -228,7 +238,12 @@ } ], "versions": { - "2.0.0": null, + "2.0.0": { + "api_version": 8, + "commit_sha": "7dcf3c7", + "released_on": "28-07-2023", + "md5sum": "2c457b80b5a35adf0cad1436af4ab3fe" + }, "1.1.0": { "api_version": 7, "commit_sha": "0bc9522", @@ -247,7 +262,12 @@ } ], "versions": { - "2.0.0": null, + "2.0.0": { + "api_version": 8, + "commit_sha": "7dcf3c7", + "released_on": "28-07-2023", + "md5sum": "49ae645a5afc390ead44d7219b388c78" + }, "1.0.0": { "api_version": 7, "commit_sha": "858030b", @@ -266,7 +286,12 @@ } ], "versions": { - "2.0.0": null, + "2.0.0": { + "api_version": 8, + "commit_sha": "7dcf3c7", + "released_on": "28-07-2023", + "md5sum": "4cb6510f9f3ce151720a53a957986864" + }, "1.0.0": { "api_version": 7, "commit_sha": "858030b", @@ -459,7 +484,12 @@ } ], "versions": { - "2.0.0": null, + "2.0.0": { + "api_version": 8, + "commit_sha": "7dcf3c7", + "released_on": "28-07-2023", + "md5sum": "22b51a147524d84fbc249e61f21ae424" + }, "1.1.0": { "api_version": 7, "commit_sha": "2e2540a", diff --git a/plugins/utilities.json b/plugins/utilities.json index 20d0f716..7efc87ee 100644 --- a/plugins/utilities.json +++ b/plugins/utilities.json @@ -296,7 +296,12 @@ } ], "versions": { - "2.0.0": null, + "2.0.0": { + "api_version": 8, + "commit_sha": "7dcf3c7", + "released_on": "28-07-2023", + "md5sum": "31df84f027c98e86336a420aa509e47f" + }, "1.0.0": { "api_version": 7, "commit_sha": "6beb8ddf", @@ -315,7 +320,12 @@ } ], "versions": { - "2.0.0": null, + "2.0.0": { + "api_version": 8, + "commit_sha": "7dcf3c7", + "released_on": "28-07-2023", + "md5sum": "ef2dbcac9190a61753e2c3c0f8afc22c" + }, "1.1.0": { "api_version": 7, "commit_sha": "383f774", @@ -508,7 +518,12 @@ } ], "versions": { - "2.0.0": null, + "2.0.0": { + "api_version": 8, + "commit_sha": "7dcf3c7", + "released_on": "28-07-2023", + "md5sum": "8a63ad58d24e2b61bb63645f74d876e8" + }, "1.0.0": { "api_version": 7, "commit_sha": "b581d90", From 48f930209cede3257ac637e77948ba128137da0c Mon Sep 17 00:00:00 2001 From: ! Freaku <92618708+Freaku17@users.noreply.github.com> Date: Fri, 28 Jul 2023 17:10:17 +0530 Subject: [PATCH 0651/1464] Fix JSON files --- plugins/minigames.json | 63 ++++++++++++++---------------------------- plugins/utilities.json | 30 ++++++-------------- 2 files changed, 29 insertions(+), 64 deletions(-) diff --git a/plugins/minigames.json b/plugins/minigames.json index f9e721db..52394012 100644 --- a/plugins/minigames.json +++ b/plugins/minigames.json @@ -34,16 +34,12 @@ "authors": [ { "name": "Freaku", - "email": "" + "email": "", + "discord": "" } ], "versions": { - "1.0.0": { - "api_version": 8, - "commit_sha": "7dcf3c7", - "released_on": "28-07-2023", - "md5sum": "cedc448a3d625065d586445e115fcd1f" - } + "1.0.0": null } }, "frozen_one": { @@ -52,16 +48,12 @@ "authors": [ { "name": "Freaku", - "email": "" + "email": "", + "discord": "" } ], "versions": { - "1.0.0": { - "api_version": 8, - "commit_sha": "7dcf3c7", - "released_on": "28-07-2023", - "md5sum": "529c8b9c9a450317d5aa75e8eab47497" - } + "1.0.0": null } }, "simon_says": { @@ -234,16 +226,12 @@ "authors": [ { "name": "Freaku", - "email": "" + "email": "", + "discord": "" } ], "versions": { - "2.0.0": { - "api_version": 8, - "commit_sha": "7dcf3c7", - "released_on": "28-07-2023", - "md5sum": "2c457b80b5a35adf0cad1436af4ab3fe" - }, + "2.0.0": null, "1.1.0": { "api_version": 7, "commit_sha": "0bc9522", @@ -258,16 +246,12 @@ "authors": [ { "name": "Freaku", - "email": "" + "email": "", + "discord": "" } ], "versions": { - "2.0.0": { - "api_version": 8, - "commit_sha": "7dcf3c7", - "released_on": "28-07-2023", - "md5sum": "49ae645a5afc390ead44d7219b388c78" - }, + "2.0.0": null, "1.0.0": { "api_version": 7, "commit_sha": "858030b", @@ -282,16 +266,12 @@ "authors": [ { "name": "Freaku", - "email": "" + "email": "", + "discord": "" } ], "versions": { - "2.0.0": { - "api_version": 8, - "commit_sha": "7dcf3c7", - "released_on": "28-07-2023", - "md5sum": "4cb6510f9f3ce151720a53a957986864" - }, + "2.0.0": null, "1.0.0": { "api_version": 7, "commit_sha": "858030b", @@ -480,16 +460,12 @@ }, { "name": "Freaku", - "email": "" + "email": "", + "discord": "" } ], "versions": { - "2.0.0": { - "api_version": 8, - "commit_sha": "7dcf3c7", - "released_on": "28-07-2023", - "md5sum": "22b51a147524d84fbc249e61f21ae424" - }, + "2.0.0": null, "1.1.0": { "api_version": 7, "commit_sha": "2e2540a", @@ -698,7 +674,8 @@ "authors": [ { "name": "Freaku", - "email": "" + "email": "", + "discord": "" } ], "versions": { diff --git a/plugins/utilities.json b/plugins/utilities.json index 7efc87ee..cc95bfd3 100644 --- a/plugins/utilities.json +++ b/plugins/utilities.json @@ -292,16 +292,12 @@ "authors": [ { "name": "Freaku", - "email": "" + "email": "", + "discord": "" } ], "versions": { - "2.0.0": { - "api_version": 8, - "commit_sha": "7dcf3c7", - "released_on": "28-07-2023", - "md5sum": "31df84f027c98e86336a420aa509e47f" - }, + "2.0.0": null, "1.0.0": { "api_version": 7, "commit_sha": "6beb8ddf", @@ -316,16 +312,12 @@ "authors": [ { "name": "Freaku", - "email": "" + "email": "", + "discord": "" } ], "versions": { - "2.0.0": { - "api_version": 8, - "commit_sha": "7dcf3c7", - "released_on": "28-07-2023", - "md5sum": "ef2dbcac9190a61753e2c3c0f8afc22c" - }, + "2.0.0": null, "1.1.0": { "api_version": 7, "commit_sha": "383f774", @@ -514,16 +506,12 @@ "authors": [ { "name": "Freaku", - "email": "" + "email": "", + "discord": "" } ], "versions": { - "2.0.0": { - "api_version": 8, - "commit_sha": "7dcf3c7", - "released_on": "28-07-2023", - "md5sum": "8a63ad58d24e2b61bb63645f74d876e8" - }, + "2.0.0": null, "1.0.0": { "api_version": 7, "commit_sha": "b581d90", From 35193f80c5e0cbe9616ba5df75d13e8df63f7086 Mon Sep 17 00:00:00 2001 From: Freaku17 Date: Fri, 28 Jul 2023 11:40:47 +0000 Subject: [PATCH 0652/1464] [ci] apply-version-metadata --- plugins/minigames.json | 42 ++++++++++++++++++++++++++++++++++++------ plugins/utilities.json | 21 ++++++++++++++++++--- 2 files changed, 54 insertions(+), 9 deletions(-) diff --git a/plugins/minigames.json b/plugins/minigames.json index 52394012..8d698fe4 100644 --- a/plugins/minigames.json +++ b/plugins/minigames.json @@ -39,7 +39,12 @@ } ], "versions": { - "1.0.0": null + "1.0.0": { + "api_version": 8, + "commit_sha": "48f9302", + "released_on": "28-07-2023", + "md5sum": "cedc448a3d625065d586445e115fcd1f" + } } }, "frozen_one": { @@ -53,7 +58,12 @@ } ], "versions": { - "1.0.0": null + "1.0.0": { + "api_version": 8, + "commit_sha": "48f9302", + "released_on": "28-07-2023", + "md5sum": "529c8b9c9a450317d5aa75e8eab47497" + } } }, "simon_says": { @@ -231,7 +241,12 @@ } ], "versions": { - "2.0.0": null, + "2.0.0": { + "api_version": 8, + "commit_sha": "48f9302", + "released_on": "28-07-2023", + "md5sum": "2c457b80b5a35adf0cad1436af4ab3fe" + }, "1.1.0": { "api_version": 7, "commit_sha": "0bc9522", @@ -251,7 +266,12 @@ } ], "versions": { - "2.0.0": null, + "2.0.0": { + "api_version": 8, + "commit_sha": "48f9302", + "released_on": "28-07-2023", + "md5sum": "49ae645a5afc390ead44d7219b388c78" + }, "1.0.0": { "api_version": 7, "commit_sha": "858030b", @@ -271,7 +291,12 @@ } ], "versions": { - "2.0.0": null, + "2.0.0": { + "api_version": 8, + "commit_sha": "48f9302", + "released_on": "28-07-2023", + "md5sum": "4cb6510f9f3ce151720a53a957986864" + }, "1.0.0": { "api_version": 7, "commit_sha": "858030b", @@ -465,7 +490,12 @@ } ], "versions": { - "2.0.0": null, + "2.0.0": { + "api_version": 8, + "commit_sha": "48f9302", + "released_on": "28-07-2023", + "md5sum": "22b51a147524d84fbc249e61f21ae424" + }, "1.1.0": { "api_version": 7, "commit_sha": "2e2540a", diff --git a/plugins/utilities.json b/plugins/utilities.json index cc95bfd3..0aabefb0 100644 --- a/plugins/utilities.json +++ b/plugins/utilities.json @@ -297,7 +297,12 @@ } ], "versions": { - "2.0.0": null, + "2.0.0": { + "api_version": 8, + "commit_sha": "48f9302", + "released_on": "28-07-2023", + "md5sum": "31df84f027c98e86336a420aa509e47f" + }, "1.0.0": { "api_version": 7, "commit_sha": "6beb8ddf", @@ -317,7 +322,12 @@ } ], "versions": { - "2.0.0": null, + "2.0.0": { + "api_version": 8, + "commit_sha": "48f9302", + "released_on": "28-07-2023", + "md5sum": "ef2dbcac9190a61753e2c3c0f8afc22c" + }, "1.1.0": { "api_version": 7, "commit_sha": "383f774", @@ -511,7 +521,12 @@ } ], "versions": { - "2.0.0": null, + "2.0.0": { + "api_version": 8, + "commit_sha": "48f9302", + "released_on": "28-07-2023", + "md5sum": "8a63ad58d24e2b61bb63645f74d876e8" + }, "1.0.0": { "api_version": 7, "commit_sha": "b581d90", From f421d4a5bd8cabb293b6cf300a90be8def4dbd61 Mon Sep 17 00:00:00 2001 From: Ayush Saini <36878972+imayushsaini@users.noreply.github.com> Date: Fri, 28 Jul 2023 22:23:37 +0530 Subject: [PATCH 0653/1464] added file share plugin --- plugins/utilities.json | 38 ++-- plugins/utilities/file_share.py | 348 ++++++++++++++++++++++++++++++++ 2 files changed, 374 insertions(+), 12 deletions(-) create mode 100644 plugins/utilities/file_share.py diff --git a/plugins/utilities.json b/plugins/utilities.json index 0aabefb0..0c7e59ae 100644 --- a/plugins/utilities.json +++ b/plugins/utilities.json @@ -348,8 +348,8 @@ "authors": [ { "name": "Mr.Smoothy", - "email": "smoothy@bombsquad.ga", - "discord": "mr.smoothy#5824" + "email": "", + "discord": "mr.smoothy" } ], "versions": { @@ -385,8 +385,8 @@ "authors": [ { "name": "Mr.Smoothy", - "email": "smoothy@bombsquad.ga", - "discord": "mr.smoothy#5824" + "email": "", + "discord": "mr.smoothy" } ], "versions": { @@ -416,8 +416,8 @@ "authors": [ { "name": "Mr.Smoothy", - "email": "smoothy@bombsquad.ga", - "discord": "mr.smoothy#5824" + "email": "", + "discord": "mr.smoothy" } ], "versions": { @@ -429,14 +429,28 @@ } } }, + "file_share": { + "description": "share/import mods, replays, custom characters/maps with link or QR code", + "external_url": "https://youtu.be/qtGsFU4cgic", + "authors": [ + { + "name": "Mr.Smoothy", + "email": "", + "discord": "mr.smoothy" + } + ], + "versions": { + "1.0.0": null + } + }, "server_switch": { "description": "Let you switch between recents servers", "external_url": "https://www.youtube.com/watch?v=QrES1jQGXF0", "authors": [ { "name": "Mr.Smoothy", - "email": "smoothy@bombsquad.ga", - "discord": "mr.smoothy#5824" + "email": "", + "discord": "mr.smoothy" } ], "versions": { @@ -466,8 +480,8 @@ "authors": [ { "name": "Mr.Smoothy", - "email": "smoothy@bombsquad.ga", - "discord": "mr.smoothy#5824" + "email": "", + "discord": "mr.smoothy" } ], "versions": { @@ -491,8 +505,8 @@ "authors": [ { "name": "Mr.Smoothy", - "email": "smoothy@bombsquad.ga", - "discord": "mr.smoothy#5824" + "email": "", + "discord": "mr.smoothy" } ], "versions": { diff --git a/plugins/utilities/file_share.py b/plugins/utilities/file_share.py new file mode 100644 index 00000000..09d1e2c6 --- /dev/null +++ b/plugins/utilities/file_share.py @@ -0,0 +1,348 @@ +# ba_meta require api 8 +''' +File Share Mod for BombSquad 1.7.23 and above. +https://youtu.be/qtGsFU4cgic +https://discord.gg/ucyaesh +by : Mr.Smoothy + +Thanks Dliwk for contributing MultiPartForm.class +''' +from __future__ import annotations + +import bascenev1 as bs +import _baplus +import _babase +import babase +from bauiv1lib.fileselector import FileSelectorWindow +from bauiv1lib.promocode import PromoCodeWindow +from bauiv1lib.confirm import ConfirmWindow +import bauiv1 as bui +import os +import urllib.request +from threading import Thread +import logging +from babase._general import Call +from typing import TYPE_CHECKING +if TYPE_CHECKING: + from typing import Any, Callable, Sequence + +app = _babase.app + +MODS_DIR = app.python_directory_user +REPLAYS_DIR = bui.get_replays_dir() +HEADERS = { + 'accept': 'application/json', + 'Content-Type': 'application/octet-stream', + 'User-Agent': 'BombSquad Client' +} + +class UploadConfirmation(ConfirmWindow): + def __init__( + self, + file_path = "", + status = "init", + text: str | bui.Lstr = 'Are you sure?', + ok_text = "", + action: Callable[[], Any] | None = None, + origin_widget: bui.Widget | None = None, + + ): + super().__init__(text=text, action=action, origin_widget=origin_widget, ok_text=ok_text) + self.status = status + self.file_path = file_path + + def _ok(self) -> None: + if self.status == "init": + self._cancel() + UploadConfirmation("", "uploading", text = "Uploading file wait !", ok_text= "Wait") + self._upload_file() + + elif self.status == "uploading": + bui.screenmessage("uploading in progress") + elif self.status == "uploaded": + pass + + def _upload_file(self): + self.status = "uploading" + print(self.root_widget) + thread = Thread(target = handle_upload, args = (self.file_path, self.uploaded, self.root_widget,)) + thread.start() + + def uploaded(self, url, root_widget): + self.status = "uploaded" + from bauiv1lib.url import ShowURLWindow + ShowURLWindow(url) + +class InputWindow(PromoCodeWindow): + def __init__( + self, modal: bool = True, origin_widget: bui.Widget | None = None, path = None): + super().__init__(modal=modal, origin_widget=origin_widget) + bui.textwidget(edit=self._text_field, max_chars=300) + self._path = path + self.message_widget = bui.textwidget( + parent=self._root_widget, + text="put only trusted link", + position=(170, 230 - 200 -30 ), + color=(0.8, 0.8, 0.8, 1.0), + size=(90, 30), + h_align='center', + ) + + def _do_enter(self): + url = bui.textwidget(query=self._text_field) + if self._path and self._path != "/bombsquad": + bui.textwidget(edit=self.message_widget, text="downloading.... wait...") + bui.screenmessage("Downloading started") + thread = Thread(target = handle_download, args = (url, self._path, self.on_download,)) + thread.start() + else: + bui.textwidget(edit=self.message_widget, text="First select folder were to save file.") + self.close() + def on_download(self, output_path): + bui.screenmessage("File Downloaded to path") + bui.screenmessage(output_path) + bui.screenmessage("GO back and reopen to refresh") + def close(self): + bui.containerwidget( + edit=self._root_widget, transition=self._transition_out + ) + +class FileSelectorExtended(FileSelectorWindow): + + def __init__( + self, + path: str, + callback: Callable[[str | None], Any] | None = None, + show_base_path: bool = True, + valid_file_extensions: Sequence[str] | None = None, + allow_folders: bool = False, + ): + super().__init__(path, callback = callback, show_base_path = show_base_path, valid_file_extensions = valid_file_extensions, allow_folders = allow_folders) + self._import_button = bui.buttonwidget( + parent=self._root_widget, + button_type='square', + position=(self._folder_center + 200, self._height - 113), + color=(0.6, 0.53, 0.63), + textcolor=(0.75, 0.7, 0.8), + enable_sound=False, + size=(55, 35), + label="Import", + on_activate_call=self._open_import_menu, + ) + def _open_import_menu(self): + InputWindow(origin_widget=self._import_button, path = self._path) + + def _on_entry_activated(self, entry: str) -> None: + # pylint: disable=too-many-branches + new_path = None + try: + assert self._path is not None + if entry == '..': + chunks = self._path.split('/') + if len(chunks) > 1: + new_path = '/'.join(chunks[:-1]) + if new_path == '': + new_path = '/' + else: + bui.getsound('error').play() + else: + if self._path == '/': + test_path = self._path + entry + else: + test_path = self._path + '/' + entry + if test_path == "/bombsquad/mods": + test_path = MODS_DIR + if test_path == "/bombsquad/replays": + test_path = REPLAYS_DIR + if os.path.isdir(test_path): + bui.getsound('swish').play() + new_path = test_path + elif os.path.isfile(test_path): + if self._is_valid_file_path(test_path): + bui.getsound('swish').play() + if self._callback is not None: + self._callback(test_path) + else: + bui.getsound('error').play() + else: + print( + ( + 'Error: FileSelectorWindow found non-file/dir:', + test_path, + ) + ) + except Exception: + logging.exception( + 'Error in FileSelectorWindow._on_entry_activated().' + ) + + if new_path is not None: + self._set_path(new_path) + +org_listdir = os.listdir +def custom_listdir(path): + if path == "/bombsquad": + return ["mods","replays"] + return org_listdir(path) +os.listdir = custom_listdir + + +import uuid +import io +import re +import json +import urllib.request +import mimetypes +class MultiPartForm: + """Accumulate the data to be used when posting a form.""" + + def __init__(self): + self.form_fields = [] + self.files = [] + # Use a large random byte string to separate + # parts of the MIME data. + self.boundary = uuid.uuid4().hex.encode('utf-8') + return + + def get_content_type(self): + return 'multipart/form-data; boundary={}'.format( + self.boundary.decode('utf-8')) + + def add_field(self, name, value): + """Add a simple field to the form data.""" + self.form_fields.append((name, value)) + + def add_file(self, fieldname, filename, fileHandle, + mimetype=None): + """Add a file to be uploaded.""" + body = fileHandle.read() + if mimetype is None: + mimetype = ( + mimetypes.guess_type(filename)[0] or + 'application/octet-stream' + ) + self.files.append((fieldname, filename, mimetype, body)) + return + + @staticmethod + def _form_data(name): + return ('Content-Disposition: form-data; ' + 'name="{}"\r\n').format(name).encode('utf-8') + + @staticmethod + def _attached_file(name, filename): + return ('Content-Disposition: form-data; ' + 'name="{}"; filename="{}"\r\n').format( + name, filename).encode('utf-8') + + @staticmethod + def _content_type(ct): + return 'Content-Type: {}\r\n'.format(ct).encode('utf-8') + + def __bytes__(self): + """Return a byte-string representing the form data, + including attached files. + """ + buffer = io.BytesIO() + boundary = b'--' + self.boundary + b'\r\n' + + # Add the form fields + for name, value in self.form_fields: + buffer.write(boundary) + buffer.write(self._form_data(name)) + buffer.write(b'\r\n') + buffer.write(value.encode('utf-8')) + buffer.write(b'\r\n') + + # Add the files to upload + for f_name, filename, f_content_type, body in self.files: + buffer.write(boundary) + buffer.write(self._attached_file(f_name, filename)) + buffer.write(self._content_type(f_content_type)) + buffer.write(b'\r\n') + buffer.write(body) + buffer.write(b'\r\n') + + buffer.write(b'--' + self.boundary + b'--\r\n') + return buffer.getvalue() + +def handle_upload(file, callback, root_widget): + file_name = file.split("/")[-1] + with open(file, "rb") as f: + file_content = f.read() + bui.screenmessage("Uploading file, wait !") + form = MultiPartForm() + form.add_file( + 'file', file_name, + fileHandle=io.BytesIO(file_content)) + + # Build the request, including the byte-string + # for the data to be posted. + data = bytes(form) + file_name = urllib.parse.quote(file_name) + r = urllib.request.Request(f'https://file.io?title={file_name}', data=data) + r.add_header('Content-type', form.get_content_type()) + r.add_header('Content-length', len(data)) + + try: + with urllib.request.urlopen(r) as response: + if response.getcode() == 200: + # callback(json.loads(response.read().decode('utf-8'))["link"]) + _babase.pushcall(Call(callback,json.loads(response.read().decode('utf-8'))["link"], root_widget), from_other_thread = True) + else: + bui.screenmessage(f"Failed to Upload file. Status code: {response.getcode()}") + except urllib.error.URLError as e: + bui.screenmessage(f"Error occurred: {e}") + + + +def handle_download(url, path, callback): + req = urllib.request.Request(url, headers={'accept': '*/*'}, method='GET') + try: + with urllib.request.urlopen(req) as response: + if response.getcode() == 200: + # Read the filename from the Content-Disposition header + filename = None + content_disposition = response.headers.get('Content-Disposition', '') + + match = re.search(r'filename\*?=(.+)', content_disposition) + + if match: + filename = urllib.parse.unquote(match.group(1), encoding='utf-8') + filename = filename.replace("UTF-8''", '') + + output_path = os.path.join(path, filename) + + with open(output_path, 'wb') as file: + file.write(response.read()) + _babase.pushcall(Call(callback, output_path),from_other_thread= True) + print(f"File downloaded and saved to: {output_path}") + else: + print(f"Failed to download file. Status code: {response.getcode()}") + except urllib.error.URLError as e: + # bui.screenmessage(f'Error occured {e}') + print(f"Error occurred: {e}") + +# ba_meta export plugin +class bySmoothy(babase.Plugin): + def on_app_running(self): + pass + + def has_settings_ui(self): + return True + + def show_settings_ui(self, source_widget): + virtual_directory_path = '/bombsquad' + FileSelectorExtended( + virtual_directory_path, + callback=self.fileSelected, + show_base_path=False, + valid_file_extensions=[ + "txt","py","json","brp" + ], + allow_folders=False, + ).get_root_widget() + + def fileSelected(self, path): + if path: + UploadConfirmation(path,"init", text= "You want to upload " + path.split("/")[-1], ok_text= "Upload") \ No newline at end of file From 09319de3e3801f0266eb95cece30a2fd8d5332c3 Mon Sep 17 00:00:00 2001 From: imayushsaini Date: Fri, 28 Jul 2023 16:54:22 +0000 Subject: [PATCH 0654/1464] [ci] auto-format --- plugins/utilities/file_share.py | 100 ++++++++++++++++++-------------- 1 file changed, 58 insertions(+), 42 deletions(-) diff --git a/plugins/utilities/file_share.py b/plugins/utilities/file_share.py index 09d1e2c6..b13ed66b 100644 --- a/plugins/utilities/file_share.py +++ b/plugins/utilities/file_share.py @@ -8,6 +8,11 @@ Thanks Dliwk for contributing MultiPartForm.class ''' from __future__ import annotations +import mimetypes +import json +import re +import io +import uuid import bascenev1 as bs import _baplus @@ -27,25 +32,26 @@ from typing import Any, Callable, Sequence app = _babase.app - + MODS_DIR = app.python_directory_user -REPLAYS_DIR = bui.get_replays_dir() +REPLAYS_DIR = bui.get_replays_dir() HEADERS = { 'accept': 'application/json', 'Content-Type': 'application/octet-stream', 'User-Agent': 'BombSquad Client' } + class UploadConfirmation(ConfirmWindow): def __init__( self, - file_path = "", - status = "init", + file_path="", + status="init", text: str | bui.Lstr = 'Are you sure?', - ok_text = "", + ok_text="", action: Callable[[], Any] | None = None, origin_widget: bui.Widget | None = None, - + ): super().__init__(text=text, action=action, origin_widget=origin_widget, ok_text=ok_text) self.status = status @@ -54,18 +60,19 @@ def __init__( def _ok(self) -> None: if self.status == "init": self._cancel() - UploadConfirmation("", "uploading", text = "Uploading file wait !", ok_text= "Wait") + UploadConfirmation("", "uploading", text="Uploading file wait !", ok_text="Wait") self._upload_file() - + elif self.status == "uploading": - bui.screenmessage("uploading in progress") + bui.screenmessage("uploading in progress") elif self.status == "uploaded": pass def _upload_file(self): self.status = "uploading" print(self.root_widget) - thread = Thread(target = handle_upload, args = (self.file_path, self.uploaded, self.root_widget,)) + thread = Thread(target=handle_upload, args=( + self.file_path, self.uploaded, self.root_widget,)) thread.start() def uploaded(self, url, root_widget): @@ -73,16 +80,17 @@ def uploaded(self, url, root_widget): from bauiv1lib.url import ShowURLWindow ShowURLWindow(url) + class InputWindow(PromoCodeWindow): def __init__( - self, modal: bool = True, origin_widget: bui.Widget | None = None, path = None): + self, modal: bool = True, origin_widget: bui.Widget | None = None, path=None): super().__init__(modal=modal, origin_widget=origin_widget) bui.textwidget(edit=self._text_field, max_chars=300) self._path = path self.message_widget = bui.textwidget( parent=self._root_widget, text="put only trusted link", - position=(170, 230 - 200 -30 ), + position=(170, 230 - 200 - 30), color=(0.8, 0.8, 0.8, 1.0), size=(90, 30), h_align='center', @@ -93,22 +101,25 @@ def _do_enter(self): if self._path and self._path != "/bombsquad": bui.textwidget(edit=self.message_widget, text="downloading.... wait...") bui.screenmessage("Downloading started") - thread = Thread(target = handle_download, args = (url, self._path, self.on_download,)) + thread = Thread(target=handle_download, args=(url, self._path, self.on_download,)) thread.start() else: bui.textwidget(edit=self.message_widget, text="First select folder were to save file.") self.close() + def on_download(self, output_path): bui.screenmessage("File Downloaded to path") bui.screenmessage(output_path) bui.screenmessage("GO back and reopen to refresh") + def close(self): bui.containerwidget( edit=self._root_widget, transition=self._transition_out ) + class FileSelectorExtended(FileSelectorWindow): - + def __init__( self, path: str, @@ -117,7 +128,8 @@ def __init__( valid_file_extensions: Sequence[str] | None = None, allow_folders: bool = False, ): - super().__init__(path, callback = callback, show_base_path = show_base_path, valid_file_extensions = valid_file_extensions, allow_folders = allow_folders) + super().__init__(path, callback=callback, show_base_path=show_base_path, + valid_file_extensions=valid_file_extensions, allow_folders=allow_folders) self._import_button = bui.buttonwidget( parent=self._root_widget, button_type='square', @@ -129,8 +141,9 @@ def __init__( label="Import", on_activate_call=self._open_import_menu, ) + def _open_import_menu(self): - InputWindow(origin_widget=self._import_button, path = self._path) + InputWindow(origin_widget=self._import_button, path=self._path) def _on_entry_activated(self, entry: str) -> None: # pylint: disable=too-many-branches @@ -179,20 +192,19 @@ def _on_entry_activated(self, entry: str) -> None: if new_path is not None: self._set_path(new_path) -org_listdir = os.listdir + +org_listdir = os.listdir + + def custom_listdir(path): if path == "/bombsquad": - return ["mods","replays"] + return ["mods", "replays"] return org_listdir(path) + + os.listdir = custom_listdir -import uuid -import io -import re -import json -import urllib.request -import mimetypes class MultiPartForm: """Accumulate the data to be used when posting a form.""" @@ -266,6 +278,7 @@ def __bytes__(self): buffer.write(b'--' + self.boundary + b'--\r\n') return buffer.getvalue() + def handle_upload(file, callback, root_widget): file_name = file.split("/")[-1] with open(file, "rb") as f: @@ -287,13 +300,13 @@ def handle_upload(file, callback, root_widget): try: with urllib.request.urlopen(r) as response: if response.getcode() == 200: - # callback(json.loads(response.read().decode('utf-8'))["link"]) - _babase.pushcall(Call(callback,json.loads(response.read().decode('utf-8'))["link"], root_widget), from_other_thread = True) + # callback(json.loads(response.read().decode('utf-8'))["link"]) + _babase.pushcall(Call(callback, json.loads(response.read().decode( + 'utf-8'))["link"], root_widget), from_other_thread=True) else: bui.screenmessage(f"Failed to Upload file. Status code: {response.getcode()}") except urllib.error.URLError as e: bui.screenmessage(f"Error occurred: {e}") - def handle_download(url, path, callback): @@ -304,9 +317,9 @@ def handle_download(url, path, callback): # Read the filename from the Content-Disposition header filename = None content_disposition = response.headers.get('Content-Disposition', '') - + match = re.search(r'filename\*?=(.+)', content_disposition) - + if match: filename = urllib.parse.unquote(match.group(1), encoding='utf-8') filename = filename.replace("UTF-8''", '') @@ -315,7 +328,7 @@ def handle_download(url, path, callback): with open(output_path, 'wb') as file: file.write(response.read()) - _babase.pushcall(Call(callback, output_path),from_other_thread= True) + _babase.pushcall(Call(callback, output_path), from_other_thread=True) print(f"File downloaded and saved to: {output_path}") else: print(f"Failed to download file. Status code: {response.getcode()}") @@ -324,6 +337,8 @@ def handle_download(url, path, callback): print(f"Error occurred: {e}") # ba_meta export plugin + + class bySmoothy(babase.Plugin): def on_app_running(self): pass @@ -332,17 +347,18 @@ def has_settings_ui(self): return True def show_settings_ui(self, source_widget): - virtual_directory_path = '/bombsquad' - FileSelectorExtended( - virtual_directory_path, - callback=self.fileSelected, - show_base_path=False, - valid_file_extensions=[ - "txt","py","json","brp" - ], - allow_folders=False, - ).get_root_widget() - + virtual_directory_path = '/bombsquad' + FileSelectorExtended( + virtual_directory_path, + callback=self.fileSelected, + show_base_path=False, + valid_file_extensions=[ + "txt", "py", "json", "brp" + ], + allow_folders=False, + ).get_root_widget() + def fileSelected(self, path): if path: - UploadConfirmation(path,"init", text= "You want to upload " + path.split("/")[-1], ok_text= "Upload") \ No newline at end of file + UploadConfirmation(path, "init", text="You want to upload " + + path.split("/")[-1], ok_text="Upload") From c94a23244e7e73504f162b3e4fab21ceaf0dea03 Mon Sep 17 00:00:00 2001 From: imayushsaini Date: Fri, 28 Jul 2023 16:54:23 +0000 Subject: [PATCH 0655/1464] [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 0c7e59ae..595a1e82 100644 --- a/plugins/utilities.json +++ b/plugins/utilities.json @@ -440,7 +440,12 @@ } ], "versions": { - "1.0.0": null + "1.0.0": { + "api_version": 8, + "commit_sha": "09319de", + "released_on": "28-07-2023", + "md5sum": "4eee80d51f8289adde5416a24749772f" + } } }, "server_switch": { From 5174e7fc57ede63c971a1ff33b9cab490de3eb4a Mon Sep 17 00:00:00 2001 From: brostos <67740566+brostosjoined@users.noreply.github.com> Date: Sat, 29 Jul 2023 02:29:34 +0300 Subject: [PATCH 0656/1464] Delete discord_richpresence.py --- plugins/utilities/discord_richpresence.py | 918 ---------------------- 1 file changed, 918 deletions(-) delete mode 100644 plugins/utilities/discord_richpresence.py diff --git a/plugins/utilities/discord_richpresence.py b/plugins/utilities/discord_richpresence.py deleted file mode 100644 index 285aa408..00000000 --- a/plugins/utilities/discord_richpresence.py +++ /dev/null @@ -1,918 +0,0 @@ -# Released under the MIT and Apache License. See LICENSE for details. -# -"""placeholder :clown:""" - -# ba_meta require api 8 -#!"Made to you by @brostos & @Dliwk" - - -from __future__ import annotations -from urllib.request import Request, urlopen, urlretrieve -from pathlib import Path -from os import getcwd, remove -from bauiv1lib.popup import PopupWindow -from babase._mgen.enums import TimeType - -import asyncio -import http.client -import ast -import uuid -import json -import time -import threading -import shutil -import hashlib -import babase -import _babase -import bascenev1 as bs -import bascenev1lib -import bauiv1 as bui - -from typing import TYPE_CHECKING - -if TYPE_CHECKING: - from typing import Any, Tuple - - -ANDROID = babase.app.classic.platform == "android" -DIRPATH = Path(f"{_babase.app.python_directory_user}/image_id.json") - -if ANDROID: # !can add ios in future - - # Installing websocket - def get_module(): - install_path = Path(f"{getcwd()}/ba_data/python") # For the guys like me on windows - path = Path(f"{install_path}/websocket.tar.gz") - file_path = Path(f"{install_path}/websocket") - source_dir = Path(f"{install_path}/websocket-client-1.6.1/websocket") - if not file_path.exists(): - url = "https://files.pythonhosted.org/packages/b1/34/3a5cae1e07d9566ad073fa6d169bf22c03a3ba7b31b3c3422ec88d039108/websocket-client-1.6.1.tar.gz" - try: - filename, headers = urlretrieve(url, filename=path) - with open(filename, "rb") as f: - content = f.read() - assert hashlib.md5(content).hexdigest() == "86bc69b61947943627afc1b351c0b5db" - shutil.unpack_archive(filename, install_path) - remove(path) - shutil.copytree(source_dir, file_path) - shutil.rmtree(Path(f"{install_path}/websocket-client-1.6.1")) - except Exception as e: - if type(e) == shutil.Error: - shutil.rmtree(Path(f"{install_path}/websocket-client-1.6.1")) - else: - pass - get_module() - - from websocket import WebSocketConnectionClosedException - import websocket - - start_time = time.time() - - class PresenceUpdate: - def __init__(self): - self.ws = websocket.WebSocketApp("wss://gateway.discord.gg/?encoding=json&v=10", - on_open=self.on_open, - on_message=self.on_message, - on_error=self.on_error, - on_close=self.on_close) - self.heartbeat_interval = int(41250) - self.resume_gateway_url: str | None = None - self.session_id: str | None = None - self.stop_heartbeat_thread = threading.Event() - self.do_once = True - self.state: str | None = "In Game" - self.details: str | None = "Main Menu" - self.start_timestamp = time.time() - self.large_image_key: str | None = "bombsquadicon" - self.large_image_text: str | None = "BombSquad Icon" - self.small_image_key: str | None = None - self.small_image_text: str | None = ( - f"{_babase.app.classic.platform.capitalize()}({_babase.app.version})") - self.media_proxy = "mp:/app-assets/963434684669382696/{}.png" - self.identify: bool = False - self.party_id: str = str(uuid.uuid4()) - self.party_size = 1 - self.party_max = 8 - - def presence(self): - with open(DIRPATH, "r") as maptxt: - largetxt = json.load(maptxt)[self.large_image_key] - with open(DIRPATH, "r") as maptxt: - smalltxt = json.load(maptxt)[self.small_image_key] - - presencepayload = { - "op": 3, - "d": { - "since": None, # used to show how long the user went idle will add afk to work with this and then set the status to idle - "status": "online", - "afk": "false", - "activities": [ - { - "name": "BombSquad", - "type": 0, - "application_id": "963434684669382696", - "state": self.state, - "details": self.details, - "timestamps": { - "start": start_time - }, - "party": { - "id": self.party_id, - "size": [self.party_size, self.party_max] - }, - "assets": { - "large_image": self.media_proxy.format(largetxt), - "large_text": self.large_image_text, - "small_image": self.media_proxy.format(smalltxt), - "small_text": self.small_image_text, - }, - "client_info": { - "version": 0, - "os": "android", - "client": "mobile", - }, - "buttons": ["Discord Server", "Download BombSquad"], - "metadata": { - "button_urls": [ - "https://discord.gg/bombsquad-ballistica-official-1001896771347304639", - "https://bombsquad-community.web.app/download", - ] - }, - } - ], - }, - } - try: - self.ws.send(json.dumps(presencepayload)) - except WebSocketConnectionClosedException: - pass - - def on_message(self, ws, message): - message = json.loads(message) - try: - self.heartbeat_interval = message["d"]["heartbeat_interval"] - except: - pass - try: - self.resume_gateway_url = message["d"]["resume_gateway_url"] - self.session_id = message["d"]["session_id"] - except: - pass - - def on_error(self, ws, error): - babase.print_exception(error) - - def on_close(self, ws, close_status_code, close_msg): - print("Closed Discord Connection Successfully") - - def on_open(self, ws): - print("Connected to Discord Websocket") - - def heartbeats(): - """Sending heartbeats to keep the connection alive""" - if self.do_once: - heartbeat_payload = { - "op": 1, - "d": 251, - } # step two keeping connection alive by sending heart beats and receiving opcode 11 - self.ws.send(json.dumps(heartbeat_payload)) - self.do_once = False - - def identify(): - """Identifying to the gateway and enable by using user token and the intents we will be using e.g 256->For Presence""" - with open(f"{getcwd()}/token.txt", 'r') as f: - token = bytes.fromhex(f.read()).decode('utf-8') - identify_payload = { - "op": 2, - "d": { - "token": token, - "properties": { - "os": "linux", - "browser": "Discord Android", - "device": "android", - }, - "intents": 256, - }, - } # step 3 send an identify - self.ws.send(json.dumps(identify_payload)) - identify() - while True: - heartbeat_payload = {"op": 1, "d": self.heartbeat_interval} - - try: - self.ws.send(json.dumps(heartbeat_payload)) - time.sleep(self.heartbeat_interval / 1000) - except: - pass - - if self.stop_heartbeat_thread.is_set(): - self.stop_heartbeat_thread.clear() - break - - threading.Thread(target=heartbeats, daemon=True, name="heartbeat").start() - - def start(self): - if Path(f"{getcwd()}/token.txt").exists(): - threading.Thread(target=self.ws.run_forever, daemon=True, name="websocket").start() - - def close(self): - self.stop_heartbeat_thread.set() - self.do_once = True - self.ws.close() - - -if not ANDROID: - # installing pypresence - def get_module(): - install_path = Path(f"{getcwd()}/ba_data/python") - path = Path(f"{install_path}/pypresence.tar.gz") - file_path = Path(f"{install_path}/pypresence") - source_dir = Path(f"{install_path}/pypresence-4.3.0/pypresence") - if not file_path.exists(): - url = "https://files.pythonhosted.org/packages/f4/2e/d110f862720b5e3ba1b0b719657385fc4151929befa2c6981f48360aa480/pypresence-4.3.0.tar.gz" - try: - filename, headers = urlretrieve(url, filename=path) - with open(filename, "rb") as f: - content = f.read() - assert hashlib.md5(content).hexdigest() == "f7c163cdd001af2456c09e241b90bad7" - shutil.unpack_archive(filename, install_path) - shutil.copytree(source_dir, file_path) - shutil.rmtree(Path(f"{install_path}/pypresence-4.3.0")) - remove(path) - except: - pass - - # Make modifications for it to work on windows - if babase.app.classic.platform == "windows": - with open(Path(f"{getcwd()}/ba_data/python/pypresence/utils.py"), "r") as file: - data = file.readlines() - data[45] = """ -def get_event_loop(force_fresh=False): - loop = asyncio.ProactorEventLoop() if sys.platform == 'win32' else asyncio.new_event_loop() - if force_fresh: - return loop - try: - running = asyncio.get_running_loop() - except RuntimeError: - return loop - if running.is_closed(): - return loop - else: - if sys.platform in ('linux', 'darwin'): - return running - if sys.platform == 'win32': - if isinstance(running, asyncio.ProactorEventLoop): - return running - else: - return loop""" - - with open(Path(f"{getcwd()}/ba_data/python/pypresence/utils.py"), "w") as file: - for number, line in enumerate(data): - if number not in range(46, 56): - file.write(line) - get_module() - - from pypresence import PipeClosed, DiscordError, DiscordNotFound - from pypresence.utils import get_event_loop - import pypresence - import socket - - DEBUG = True - - _last_server_addr = 'localhost' - _last_server_port = 43210 - - def print_error(err: str, include_exception: bool = False) -> None: - if DEBUG: - if include_exception: - babase.print_exception(err) - else: - babase.print_error(err) - else: - print(f"ERROR in discordrp.py: {err}") - - def log(msg: str) -> None: - if DEBUG: - print(f"LOG in discordrp.py: {msg}") - - def _run_overrides() -> None: - old_init = bs.Activity.__init__ - - def new_init(self, *args: Any, **kwargs: Any) -> None: # type: ignore - old_init(self, *args, **kwargs) - self._discordrp_start_time = time.mktime(time.localtime()) - - bs.Activity.__init__ = new_init # type: ignore - - old_connect = bs.connect_to_party - - def new_connect(*args, **kwargs) -> None: # type: ignore - global _last_server_addr - global _last_server_port - old_connect(*args, **kwargs) - c = kwargs.get("address") or args[0] - _last_server_port = kwargs.get("port") or args[1] - - bs.connect_to_party = new_connect - - start_time = time.time() - - class RpcThread(threading.Thread): - def __init__(self): - super().__init__(name="RpcThread") - self.rpc = pypresence.Presence(963434684669382696) - self.state: str | None = "In Game" - self.details: str | None = "Main Menu" - self.start_timestamp = time.mktime(time.localtime()) - self.large_image_key: str | None = "bombsquadicon" - self.large_image_text: str | None = "BombSquad Icon" - self.small_image_key: str | None = None - self.small_image_text: str | None = None - self.party_id: str = str(uuid.uuid4()) - self.party_size = 1 - self.party_max = 8 - self.join_secret: str | None = None - self._last_update_time: float = 0 - self._last_secret_update_time: float = 0 - self._last_connect_time: float = 0 - self.should_close = False - - @staticmethod - def is_discord_running(): - for i in range(6463, 6473): - s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) - s.settimeout(0.01) - try: - conn = s.connect_ex(('localhost', i)) - s.close() - if (conn == 0): - s.close() - return (True) - except: - s.close() - return (False) - - def _generate_join_secret(self): - # resp = requests.get('https://legacy.ballistica.net/bsAccessCheck').text - connection_info = bs.get_connection_to_host_info() - if connection_info: - addr = _last_server_addr - port = _last_server_port - else: - try: - with urlopen( - "https://legacy.ballistica.net/bsAccessCheck" - ) as resp: - resp = resp.read().decode() - resp = ast.literal_eval(resp) - addr = resp["address"] - port = 43210 - secret_dict = { - "format_version": 1, - "hostname": addr, - "port": port, - } - self.join_secret = json.dumps(secret_dict) - except: - pass - - def _update_secret(self): - threading.Thread(target=self._generate_join_secret, daemon=True).start() - self._last_secret_update_time = time.time() - - def run(self) -> None: - asyncio.set_event_loop(get_event_loop()) - while not self.should_close: - if time.time() - self._last_update_time > 0.1: - self._do_update_presence() - if time.time() - self._last_secret_update_time > 15: - self._update_secret() - # if time.time() - self._last_connect_time > 120 and is_discord_running(): #!Eric please add module manager(pip) - # self._reconnect() - time.sleep(0.03) - - def _subscribe(self, event: str, **args): - self.rpc.send_data( - 1, - { - "nonce": f"{time.time():.20f}", - "cmd": "SUBSCRIBE", - "evt": event, - "args": args, - }, - ) - data = self.rpc.loop.run_until_complete(self.rpc.read_output()) - self.handle_event(data) - - def _subscribe_events(self): - self._subscribe("ACTIVITY_JOIN") - self._subscribe("ACTIVITY_JOIN_REQUEST") - - # def _update_presence(self) -> None: - # self._last_update_time = time.time() - # try: - # self._do_update_presence() - # except (AttributeError, AssertionError): - # try: - # self._reconnect() - # except Exception: - # print_error("failed to update presence", include_exception= True) - - def _reconnect(self) -> None: - self.rpc.connect() - self._subscribe_events() - self._do_update_presence() - self._last_connect_time = time.time() - - def _do_update_presence(self) -> None: - if RpcThread.is_discord_running(): - self._last_update_time = time.time() - try: - data = self.rpc.update( - state=self.state or " ", - details=self.details, - start=start_time, - large_image=self.large_image_key, - large_text=self.large_image_text, - small_image=self.small_image_key, - small_text=self.small_image_text, - party_id=self.party_id, - party_size=[self.party_size, self.party_max], - join=self.join_secret, - # buttons = [ #!cant use buttons together with join - # { - # "label": "Discord Server", - # "url": "https://ballistica.net/discord" - # }, - # { - # "label": "Download Bombsquad", - # "url": "https://bombsquad.ga/download"} - # ] - ) - - self.handle_event(data) - except (PipeClosed, DiscordError, AssertionError, AttributeError): - try: - self._reconnect() - except (DiscordNotFound, DiscordError): - pass - - def handle_event(self, data): - evt = data["evt"] - if evt is None: - return - - data = data.get("data", {}) - - if evt == "ACTIVITY_JOIN": - secret = data.get("secret") - try: - server = json.loads(secret) - format_version = server["format_version"] - except Exception: - babase.print_exception("discordrp: unknown activity join format") - else: - try: - if format_version == 1: - hostname = server["hostname"] - port = server["port"] - self._connect_to_party(hostname, port) - except Exception: - babase.print_exception( - f"discordrp: incorrect activity join data, {format_version=}" - ) - - elif evt == "ACTIVITY_JOIN_REQUEST": - user = data.get("user", {}) - uid = user.get("id") - username = user.get("username") - discriminator = user.get("discriminator", None) - avatar = user.get("avatar") - self.on_join_request(username, uid, discriminator, avatar) - - def _connect_to_party(self, hostname, port) -> None: - babase.pushcall( - babase.Call(bs.connect_to_party, hostname, port), from_other_thread=True - ) - - def on_join_request(self, username, uid, discriminator, avatar) -> None: - del uid # unused - del avatar # unused - babase.pushcall( - babase.Call( - bui.screenmessage, - "Discord: {} wants to join!".format(username), - color=(0.0, 1.0, 0.0), - ), - from_other_thread=True, - ) - babase.pushcall(lambda: bui.getsound('bellMed').play(), from_other_thread=True) - - -class Discordlogin(PopupWindow): - - def __init__(self): - # pylint: disable=too-many-locals - _uiscale = bui.app.ui_v1.uiscale - self._transitioning_out = False - s = 1.25 if _uiscale is babase.UIScale.SMALL else 1.27 if _uiscale is babase.UIScale.MEDIUM else 1.3 - self._width = 380 * s - self._height = 150 + 150 * s - self.path = Path(f"{getcwd()}/token.txt") - bg_color = (0.5, 0.4, 0.6) - log_btn_colour = (0.10, 0.95, 0.10) if not self.path.exists() else (1.00, 0.15, 0.15) - log_txt = "LOG IN" if not self.path.exists() else "LOG OUT" - - # creates our _root_widget - PopupWindow.__init__(self, - position=(0.0, 0.0), - size=(self._width, self._height), - scale=(2.1 if _uiscale is babase.UIScale.SMALL else 1.5 - if _uiscale is babase.UIScale.MEDIUM else 1.0), - bg_color=bg_color) - - self._cancel_button = bui.buttonwidget( - parent=self.root_widget, - position=(25, self._height - 40), - size=(50, 50), - scale=0.58, - label='', - color=bg_color, - on_activate_call=self._on_cancel_press, - autoselect=True, - icon=bui.gettexture('crossOut'), - iconscale=1.2) - - bui.imagewidget(parent=self.root_widget, - position=(180, self._height - 55), - size=(32 * s, 32 * s), - texture=bui.gettexture("discordLogo"), - color=(10 - 0.32, 10 - 0.39, 10 - 0.96)) - - self.email_widget = bui.textwidget(parent=self.root_widget, - text="Email/Phone Number", - size=(400, 70), - position=(50, 180), - h_align='left', - v_align='center', - editable=True, - scale=0.8, - autoselect=True, - maxwidth=220) - - self.password_widget = bui.textwidget(parent=self.root_widget, - text="Password", - size=(400, 70), - position=(50, 120), - h_align='left', - v_align='center', - editable=True, - scale=0.8, - autoselect=True, - maxwidth=220) - - bui.containerwidget(edit=self.root_widget, - cancel_button=self._cancel_button) - - bui.textwidget( - parent=self.root_widget, - position=(265, self._height - 37), - size=(0, 0), - h_align='center', - v_align='center', - scale=1.0, - text="Discord", - maxwidth=200, - color=(0.80, 0.80, 0.80)) - - bui.textwidget( - parent=self.root_widget, - position=(265, self._height - 78), - size=(0, 0), - h_align='center', - v_align='center', - scale=1.0, - text="💀Use at your own risk💀\n ⚠️discord account might get terminated⚠️", - maxwidth=200, - color=(1.00, 0.15, 0.15)) - - self._login_button = bui.buttonwidget( - parent=self.root_widget, - position=(120, 65), - size=(400, 80), - scale=0.58, - label=log_txt, - color=log_btn_colour, - on_activate_call=self.login, - autoselect=True) - - def _on_cancel_press(self) -> None: - self._transition_out() - - def _transition_out(self) -> None: - if not self._transitioning_out: - self._transitioning_out = True - bui.containerwidget(edit=self.root_widget, transition='out_scale') - - def on_bascenev1libup_cancel(self) -> None: - bui.getsound('swish').play() - self._transition_out() - - def login(self): - if not self.path.exists(): - json_data = { - 'login': bui.textwidget(query=self.email_widget), - 'password': bui.textwidget(query=self.password_widget), - 'undelete': False, - 'captcha_key': None, - 'login_source': None, - 'gift_code_sku_id': None, - } - headers = { - 'user-agent': "Mozilla/5.0", - 'content-type': "application/json", - } - - conn = http.client.HTTPSConnection("discord.com") - - payload = json.dumps(json_data) - # conn.request("POST", "/api/v9/auth/login", payload, headers) - # res = conn.getresponse().read() - - try: - conn.request("POST", "/api/v9/auth/login", payload, headers) - res = conn.getresponse().read() - token = json.loads(res)['token'].encode().hex().encode() - with open(self.path, 'wb') as f: - f.write(token) - bui.screenmessage("Successfully logged in", (0.21, 1.0, 0.20)) - bui.getsound('shieldUp').play() - self.on_bascenev1libup_cancel() - except: - bui.screenmessage("Incorrect credentials", (1.00, 0.15, 0.15)) - bui.getsound('error').play() - - conn.close() - else: - remove(self.path) - bui.getsound('shieldDown').play() - bui.screenmessage("Account successfully removed!!", (0.10, 0.10, 1.00)) - self.on_bascenev1libup_cancel() - PresenceUpdate().ws.close() - - -run_once = False - - -def get_once_asset(): - global run_once - if run_once: - return - response = Request( - "https://discordapp.com/api/oauth2/applications/963434684669382696/assets", - headers={"User-Agent": "Mozilla/5.0"}, - ) - try: - with urlopen(response) as assets: - assets = json.loads(assets.read()) - asset = [] - asset_id = [] - for x in assets: - dem = x["name"] - don = x["id"] - asset_id.append(don) - asset.append(dem) - asset_id_dict = dict(zip(asset, asset_id)) - - with open(DIRPATH, "w") as imagesets: - jsonfile = json.dumps(asset_id_dict) - json.dump(asset_id_dict, imagesets, indent=4) - except: - pass - run_once = True - - -def get_class(): - if ANDROID: - return PresenceUpdate() - elif not ANDROID: - return RpcThread() - - -# ba_meta export babase.Plugin -class DiscordRP(babase.Plugin): - def __init__(self) -> None: - self.update_timer: bs.Timer | None = None - self.rpc_thread = get_class() - self._last_server_info: str | None = None - - if not ANDROID: - _run_overrides() - get_once_asset() - - def on_app_running(self) -> None: - if not ANDROID: - self.rpc_thread.start() - self.update_timer = bs.AppTimer( - 1, bs.WeakCall(self.update_status), repeat=True - ) - if ANDROID: - self.rpc_thread.start() - self.update_timer = bs.AppTimer( - 4, bs.WeakCall(self.update_status), repeat=True - ) - - def has_settings_ui(self): - return True - - def show_settings_ui(self, button): - if not ANDROID: - bui.screenmessage("Nothing here achievement!!!", (0.26, 0.65, 0.94)) - bui.getsound('achievement').play() - if ANDROID: - Discordlogin() - - def on_app_shutdown(self) -> None: - if not ANDROID and self.rpc_thread.is_discord_running(): - self.rpc_thread.rpc.close() - self.rpc_thread.should_close = True - - def on_app_pause(self) -> None: - self.rpc_thread.close() - - def on_app_resume(self) -> None: - global start_time - start_time = time.time() - self.rpc_thread.start() - - def _get_current_activity_name(self) -> str | None: - act = bs.get_foreground_host_activity() - if isinstance(act, bs.GameActivity): - return act.name - - this = "Lobby" - name: str | None = ( - act.__class__.__name__.replace("Activity", "") - .replace("ScoreScreen", "Ranking") - .replace("Coop", "") - .replace("MultiTeam", "") - .replace("Victory", "") - .replace("EndSession", "") - .replace("Transition", "") - .replace("Draw", "") - .replace("FreeForAll", "") - .replace("Join", this) - .replace("Team", "") - .replace("Series", "") - .replace("CustomSession", "Custom Session(mod)") - ) - - if name == "MainMenu": - name = "Main Menu" - if name == this: - self.rpc_thread.large_image_key = "lobby" - self.rpc_thread.large_image_text = "Bombing up" - #self.rpc_thread.small_image_key = "lobbysmall" - if name == "Ranking": - self.rpc_thread.large_image_key = "ranking" - self.rpc_thread.large_image_text = "Viewing Results" - return name - - def _get_current_map_name(self) -> Tuple[str | None, str | None]: - act = bs.get_foreground_host_activity() - if isinstance(act, bs.GameActivity): - texname = act.map.get_preview_texture_name() - if texname: - return act.map.name, texname.lower().removesuffix("preview") - return None, None - - def update_status(self) -> None: - roster = bs.get_game_roster() - connection_info = bs.get_connection_to_host_info() - - self.rpc_thread.large_image_key = "bombsquadicon" - self.rpc_thread.large_image_text = "BombSquad" - self.rpc_thread.small_image_key = _babase.app.classic.platform - self.rpc_thread.small_image_text = ( - f"{_babase.app.classic.platform.capitalize()}({_babase.app.version})" - ) - connection_info = bs.get_connection_to_host_info() - if not ANDROID: - svinfo = str(connection_info) - if self._last_server_info != svinfo: - self._last_server_info = svinfo - self.rpc_thread.party_id = str(uuid.uuid4()) - self.rpc_thread._update_secret() - if connection_info != {}: - servername = connection_info["name"] - self.rpc_thread.details = "Online" - self.rpc_thread.party_size = max( - 1, sum(len(client["players"]) for client in roster) - ) - self.rpc_thread.party_max = max(8, self.rpc_thread.party_size) - if len(servername) == 19 and "Private Party" in servername: - self.rpc_thread.state = "Private Party" - elif servername == "": # A local game joinable from the internet - try: - offlinename = json.loads(bs.get_game_roster()[0]["spec_string"])[ - "n" - ] - if len(offlinename) > 19: # Thanks Rikko - self.rpc_thread.state = offlinename[slice(19)] + "..." - else: - self.rpc_thread.state = offlinename - except IndexError: - pass - else: - if len(servername) > 19: - self.rpc_thread.state = servername[slice(19)] + ".." - else: - self.rpc_thread.state = servername[slice(19)] - - if connection_info == {}: - self.rpc_thread.details = "Local" # ! replace with something like ballistica github cause - self.rpc_thread.state = self._get_current_activity_name() - self.rpc_thread.party_size = max(1, len(roster)) - self.rpc_thread.party_max = max(1, bs.get_public_party_max_size()) - - if ( - bs.get_foreground_host_session() is not None - and self.rpc_thread.details == "Local" - ): - session = ( - bs.get_foreground_host_session() - .__class__.__name__.replace("MainMenuSession", "") - .replace("EndSession", "") - .replace("FreeForAllSession", ": FFA") # ! for session use small image key - .replace("DualTeamSession", ": Teams") - .replace("CoopSession", ": Coop") - ) - #! self.rpc_thread.small_image_key = session.lower() - self.rpc_thread.details = f"{self.rpc_thread.details} {session}" - if ( - self.rpc_thread.state == "NoneType" - ): # sometimes the game just breaks which means its not really watching replay FIXME - self.rpc_thread.state = "Watching Replay" - self.rpc_thread.large_image_key = "replay" - self.rpc_thread.large_image_text = "Viewing Awesomeness" - #!self.rpc_thread.small_image_key = "replaysmall" - - act = bs.get_foreground_host_activity() - session = bs.get_foreground_host_session() - if act: - from bascenev1lib.game.elimination import EliminationGame - from bascenev1lib.game.thelaststand import TheLastStandGame - from bascenev1lib.game.meteorshower import MeteorShowerGame - - # noinspection PyUnresolvedReferences,PyProtectedMember - try: - self.rpc_thread.start_timestamp = act._discordrp_start_time # type: ignore - except AttributeError: - # This can be the case if plugin launched AFTER activity - # has been created; in that case let's assume it was - # created just now. - self.rpc_thread.start_timestamp = act._discordrp_start_time = time.mktime( # type: ignore - time.localtime() - ) - if isinstance(act, EliminationGame): - alive_count = len([p for p in act.players if p.lives > 0]) - self.rpc_thread.details += f" ({alive_count} players left)" - elif isinstance(act, TheLastStandGame): - # noinspection PyProtectedMember - points = act._score - self.rpc_thread.details += f" ({points} points)" - elif isinstance(act, MeteorShowerGame): - with bs.ContextRef(act): - sec = bs.time() - act._timer.getstarttime() - secfmt = "" - if sec < 60: - secfmt = f"{sec:.2f}" - else: - secfmt = f"{int(sec) // 60:02}:{sec:.2f}" - self.rpc_thread.details += f" ({secfmt})" - - # if isinstance(session, ba.DualTeamSession): - # scores = ':'.join([ - # str(t.customdata['score']) - # for t in session.sessionteams - # ]) - # self.rpc_thread.details += f' ({scores})' - - mapname, short_map_name = self._get_current_map_name() - if mapname: - with open(DIRPATH, 'r') as asset_dict: - asset_keys = json.load(asset_dict).keys() - if short_map_name in asset_keys: - self.rpc_thread.large_image_text = mapname - self.rpc_thread.large_image_key = short_map_name - self.rpc_thread.small_image_key = 'bombsquadlogo2' - self.rpc_thread.small_image_text = 'BombSquad' - - if _babase.get_idle_time() / (1000 * 60) % 60 >= 0.4: - self.rpc_thread.details = f"AFK in {self.rpc_thread.details}" - if not ANDROID: - self.rpc_thread.large_image_key = ( - "https://media.tenor.com/uAqNn6fv7x4AAAAM/bombsquad-spaz.gif" - ) - if ANDROID and Path(f"{getcwd()}/token.txt").exists(): - self.rpc_thread.presence() From 9e473d46331db170d873362edc8c68d2509664be Mon Sep 17 00:00:00 2001 From: brostos <67740566+brostosjoined@users.noreply.github.com> Date: Sat, 29 Jul 2023 02:30:44 +0300 Subject: [PATCH 0657/1464] Add files via upload --- plugins/utilities/discord_richpresence.py | 1002 +++++++++++++++++++++ 1 file changed, 1002 insertions(+) create mode 100644 plugins/utilities/discord_richpresence.py diff --git a/plugins/utilities/discord_richpresence.py b/plugins/utilities/discord_richpresence.py new file mode 100644 index 00000000..2f360e2d --- /dev/null +++ b/plugins/utilities/discord_richpresence.py @@ -0,0 +1,1002 @@ +# Released under the MIT and Apache License. See LICENSE for details. +# +"""placeholder :clown:""" + +# ba_meta require api 8 +#!"Made to you by @brostos & @Dliwk" + + +from __future__ import annotations +from urllib.request import Request, urlopen, urlretrieve +from pathlib import Path +from os import getcwd, remove +from bauiv1lib.popup import PopupWindow +from babase._mgen.enums import TimeType + +import asyncio +import http.client +import ast +import uuid +import json +import time +import threading +import shutil +import hashlib +import babase +import _babase +import bascenev1 as bs +import bascenev1lib +import bauiv1 as bui + +from typing import TYPE_CHECKING + +if TYPE_CHECKING: + from typing import Any, Tuple + + +ANDROID = babase.app.classic.platform == "android" +DIRPATH = Path(f"{_babase.app.python_directory_user}/image_id.json") + +if ANDROID: # !can add ios in future + + # Installing websocket + def get_module(): + install_path = Path(f"{getcwd()}/ba_data/python") # For the guys like me on windows + path = Path(f"{install_path}/websocket.tar.gz") + file_path = Path(f"{install_path}/websocket") + source_dir = Path(f"{install_path}/websocket-client-1.6.1/websocket") + if not file_path.exists(): + url = "https://files.pythonhosted.org/packages/b1/34/3a5cae1e07d9566ad073fa6d169bf22c03a3ba7b31b3c3422ec88d039108/websocket-client-1.6.1.tar.gz" + try: + filename, headers = urlretrieve(url, filename=path) + with open(filename, "rb") as f: + content = f.read() + assert hashlib.md5(content).hexdigest() == "86bc69b61947943627afc1b351c0b5db" + shutil.unpack_archive(filename, install_path) + remove(path) + shutil.copytree(source_dir, file_path) + shutil.rmtree(Path(f"{install_path}/websocket-client-1.6.1")) + except Exception as e: + if type(e) == shutil.Error: + shutil.rmtree(Path(f"{install_path}/websocket-client-1.6.1")) + else: + pass + get_module() + + from websocket import WebSocketConnectionClosedException + import websocket + + + start_time = time.time() + + class PresenceUpdate: + def __init__(self): + self.ws = websocket.WebSocketApp("wss://gateway.discord.gg/?encoding=json&v=10", + on_open=self.on_open, + on_message=self.on_message, + on_error=self.on_error, + on_close=self.on_close) + self.heartbeat_interval = int(41250) + self.resume_gateway_url: str | None = None + self.session_id: str | None = None + self.stop_heartbeat_thread = threading.Event() + self.do_once = True + self.state: str | None = "In Game" + self.details: str | None = "Main Menu" + self.start_timestamp = time.time() + self.large_image_key: str | None = "bombsquadicon" + self.large_image_text: str | None = "BombSquad Icon" + self.small_image_key: str | None = None + self.small_image_text: str | None = ( + f"{_babase.app.classic.platform.capitalize()}({_babase.app.version})") + self.media_proxy = "mp:/app-assets/963434684669382696/{}.png" + self.identify: bool = False + self.party_id: str = str(uuid.uuid4()) + self.party_size = 1 + self.party_max = 8 + + def presence(self): + with open(DIRPATH, "r") as maptxt: + largetxt = json.load(maptxt)[self.large_image_key] + with open(DIRPATH, "r") as maptxt: + smalltxt = json.load(maptxt)[self.small_image_key] + + presencepayload = { + "op": 3, + "d": { + "since": None, # used to show how long the user went idle will add afk to work with this and then set the status to idle + "status": "online", + "afk": "false", + "activities": [ + { + "name": "BombSquad", + "type": 0, + "application_id": "963434684669382696", + "state": self.state, + "details": self.details, + "timestamps": { + "start": start_time + }, + "party": { + "id": self.party_id, + "size": [self.party_size, self.party_max] + }, + "assets": { + "large_image": self.media_proxy.format(largetxt), + "large_text": self.large_image_text, + "small_image": self.media_proxy.format(smalltxt), + "small_text": self.small_image_text, + }, + "client_info": { + "version": 0, + "os": "android", + "client": "mobile", + }, + "buttons": ["Discord Server", "Download BombSquad"], + "metadata": { + "button_urls": [ + "https://discord.gg/bombsquad-ballistica-official-1001896771347304639", + "https://bombsquad-community.web.app/download", + ] + }, + } + ], + }, + } + try: + self.ws.send(json.dumps(presencepayload)) + except WebSocketConnectionClosedException: + pass + + def on_message(self, ws, message): + message = json.loads(message) + try: + self.heartbeat_interval = message["d"]["heartbeat_interval"] + except: + pass + try: + self.resume_gateway_url = message["d"]["resume_gateway_url"] + self.session_id = message["d"]["session_id"] + except: + pass + + def on_error(self, ws, error): + babase.print_exception(error) + + def on_close(self, ws, close_status_code, close_msg): + print("Closed Discord Connection Successfully") + + def on_open(self, ws): + print("Connected to Discord Websocket") + + def heartbeats(): + """Sending heartbeats to keep the connection alive""" + if self.do_once: + heartbeat_payload = { + "op": 1, + "d": 251, + } # step two keeping connection alive by sending heart beats and receiving opcode 11 + self.ws.send(json.dumps(heartbeat_payload)) + self.do_once = False + + def identify(): + """Identifying to the gateway and enable by using user token and the intents we will be using e.g 256->For Presence""" + with open(f"{getcwd()}/token.txt", 'r') as f: + token = bytes.fromhex(f.read()).decode('utf-8') + identify_payload = { + "op": 2, + "d": { + "token": token, + "properties": { + "os": "linux", + "browser": "Discord Android", + "device": "android", + }, + "intents": 256, + }, + } # step 3 send an identify + self.ws.send(json.dumps(identify_payload)) + identify() + while True: + heartbeat_payload = {"op": 1, "d": self.heartbeat_interval} + + try: + self.ws.send(json.dumps(heartbeat_payload)) + time.sleep(self.heartbeat_interval / 1000) + except: + pass + + if self.stop_heartbeat_thread.is_set(): + self.stop_heartbeat_thread.clear() + break + + threading.Thread(target=heartbeats, daemon=True, name="heartbeat").start() + + def start(self): + if Path(f"{getcwd()}/token.txt").exists(): + threading.Thread(target=self.ws.run_forever, daemon=True, name="websocket").start() + + def close(self): + self.stop_heartbeat_thread.set() + self.do_once = True + self.ws.close() + + + + + +if not ANDROID: + # installing pypresence + def get_module(): + install_path = Path(f"{getcwd()}/ba_data/python") + path = Path(f"{install_path}/pypresence.tar.gz") + file_path = Path(f"{install_path}/pypresence") + source_dir = Path(f"{install_path}/pypresence-4.3.0/pypresence") + if not file_path.exists(): + url = "https://files.pythonhosted.org/packages/f4/2e/d110f862720b5e3ba1b0b719657385fc4151929befa2c6981f48360aa480/pypresence-4.3.0.tar.gz" + try: + filename, headers = urlretrieve(url, filename=path) + with open(filename, "rb") as f: + content = f.read() + assert hashlib.md5(content).hexdigest() == "f7c163cdd001af2456c09e241b90bad7" + shutil.unpack_archive( filename, install_path) + shutil.copytree(source_dir, file_path) + shutil.rmtree(Path(f"{install_path}/pypresence-4.3.0")) + remove(path) + except: + pass + + # Make modifications for it to work on windows + if babase.app.classic.platform == "windows": + with open(Path(f"{getcwd()}/ba_data/python/pypresence/utils.py"), "r") as file: + data = file.readlines() + data[45] = """ +def get_event_loop(force_fresh=False): + loop = asyncio.ProactorEventLoop() if sys.platform == 'win32' else asyncio.new_event_loop() + if force_fresh: + return loop + try: + running = asyncio.get_running_loop() + except RuntimeError: + return loop + if running.is_closed(): + return loop + else: + if sys.platform in ('linux', 'darwin'): + return running + if sys.platform == 'win32': + if isinstance(running, asyncio.ProactorEventLoop): + return running + else: + return loop""" + #Thanks Loup + with open(Path(f"{getcwd()}/ba_data/python/pypresence/utils.py"), "w") as file: + for number, line in enumerate(data): + if number not in range(46,56): + file.write(line) + get_module() + + + from pypresence import PipeClosed, DiscordError, DiscordNotFound + from pypresence.utils import get_event_loop + import pypresence + import socket + + DEBUG = True + + _last_server_addr = 'localhost' + _last_server_port = 43210 + + def print_error(err: str, include_exception: bool = False) -> None: + if DEBUG: + if include_exception: + babase.print_exception(err) + else: + babase.print_error(err) + else: + print(f"ERROR in discordrp.py: {err}") + + def log(msg: str) -> None: + if DEBUG: + print(f"LOG in discordrp.py: {msg}") + + def _run_overrides() -> None: + old_init = bs.Activity.__init__ + + def new_init(self, *args: Any, **kwargs: Any) -> None: # type: ignore + old_init(self, *args, **kwargs) + self._discordrp_start_time = time.mktime(time.localtime()) + + bs.Activity.__init__ = new_init # type: ignore + + old_connect = bs.connect_to_party + + def new_connect(*args, **kwargs) -> None: # type: ignore + global _last_server_addr + global _last_server_port + old_connect(*args, **kwargs) + c = kwargs.get("address") or args[0] + _last_server_port = kwargs.get("port") or args[1] + + bs.connect_to_party = new_connect + + start_time = time.time() + + class RpcThread(threading.Thread): + def __init__(self): + super().__init__(name="RpcThread") + self.rpc = pypresence.Presence(963434684669382696) + self.state: str | None = "In Game" + self.details: str | None = "Main Menu" + self.start_timestamp = time.mktime(time.localtime()) + self.large_image_key: str | None = "bombsquadicon" + self.large_image_text: str | None = "BombSquad Icon" + self.small_image_key: str | None = None + self.small_image_text: str | None = None + self.party_id: str = str(uuid.uuid4()) + self.party_size = 1 + self.party_max = 8 + self.join_secret: str | None = None + self._last_update_time: float = 0 + self._last_secret_update_time: float = 0 + self._last_connect_time: float = 0 + self.should_close = False + + @staticmethod + def is_discord_running(): + for i in range(6463,6473): + s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) + s.settimeout(0.01) + try: + conn = s.connect_ex(('localhost', i)) + s.close() + if (conn == 0): + s.close() + return(True) + except: + s.close() + return(False) + + def _generate_join_secret(self): + # resp = requests.get('https://legacy.ballistica.net/bsAccessCheck').text + connection_info = bs.get_connection_to_host_info() + if connection_info: + addr = _last_server_addr + port = _last_server_port + else: + try: + with urlopen( + "https://legacy.ballistica.net/bsAccessCheck" + ) as resp: + resp = resp.read().decode() + resp = ast.literal_eval(resp) + addr = resp["address"] + port = 43210 + secret_dict = { + "format_version": 1, + "hostname": addr, + "port": port, + } + self.join_secret = json.dumps(secret_dict) + except: + pass + + def _update_secret(self): + threading.Thread(target=self._generate_join_secret, daemon=True).start() + self._last_secret_update_time = time.time() + + def run(self) -> None: + asyncio.set_event_loop(get_event_loop()) + while not self.should_close: + if time.time() - self._last_update_time > 0.1: + self._do_update_presence() + if time.time() - self._last_secret_update_time > 15: + self._update_secret() + # if time.time() - self._last_connect_time > 120 and is_discord_running(): #!Eric please add module manager(pip) + # self._reconnect() + time.sleep(0.03) + + def _subscribe(self, event: str, **args): + self.rpc.send_data( + 1, + { + "nonce": f"{time.time():.20f}", + "cmd": "SUBSCRIBE", + "evt": event, + "args": args, + }, + ) + data = self.rpc.loop.run_until_complete(self.rpc.read_output()) + self.handle_event(data) + + def _subscribe_events(self): + self._subscribe("ACTIVITY_JOIN") + self._subscribe("ACTIVITY_JOIN_REQUEST") + + # def _update_presence(self) -> None: + # self._last_update_time = time.time() + # try: + # self._do_update_presence() + # except (AttributeError, AssertionError): + # try: + # self._reconnect() + # except Exception: + # print_error("failed to update presence", include_exception= True) + + + def _reconnect(self) -> None: + self.rpc.connect() + self._subscribe_events() + self._do_update_presence() + self._last_connect_time = time.time() + + def _do_update_presence(self) -> None: + if RpcThread.is_discord_running(): + self._last_update_time = time.time() + try: + data = self.rpc.update( + state=self.state or " ", + details=self.details, + start=start_time, + large_image=self.large_image_key, + large_text=self.large_image_text, + small_image=self.small_image_key, + small_text=self.small_image_text, + party_id=self.party_id, + party_size=[self.party_size, self.party_max], + join=self.join_secret, + # buttons = [ #!cant use buttons together with join + # { + # "label": "Discord Server", + # "url": "https://ballistica.net/discord" + # }, + # { + # "label": "Download Bombsquad", + # "url": "https://bombsquad.ga/download"} + # ] + ) + + self.handle_event(data) + except (PipeClosed, DiscordError, AssertionError, AttributeError): + try: + self._reconnect() + except (DiscordNotFound, DiscordError): + pass + + def handle_event(self, data): + evt = data["evt"] + if evt is None: + return + + data = data.get("data", {}) + + if evt == "ACTIVITY_JOIN": + secret = data.get("secret") + try: + server = json.loads(secret) + format_version = server["format_version"] + except Exception: + babase.print_exception("discordrp: unknown activity join format") + else: + try: + if format_version == 1: + hostname = server["hostname"] + port = server["port"] + self._connect_to_party(hostname, port) + except Exception: + babase.print_exception( + f"discordrp: incorrect activity join data, {format_version=}" + ) + + elif evt == "ACTIVITY_JOIN_REQUEST": + user = data.get("user", {}) + uid = user.get("id") + username = user.get("username") + discriminator = user.get("discriminator", None) + avatar = user.get("avatar") + self.on_join_request(username, uid, discriminator, avatar) + + def _connect_to_party(self, hostname, port) -> None: + babase.pushcall( + babase.Call(bs.connect_to_party, hostname, port), from_other_thread=True + ) + + def on_join_request(self, username, uid, discriminator, avatar) -> None: + del uid # unused + del avatar # unused + babase.pushcall( + babase.Call( + bui.screenmessage, + "Discord: {}{} wants to join!".format(username, discriminator if discriminator != "#0" else ""), + color=(0.0, 1.0, 0.0), + ), + from_other_thread=True, + ) + babase.pushcall(lambda: bui.getsound('bellMed').play(), from_other_thread=True) + + +class Discordlogin(PopupWindow): + + def __init__(self): + # pylint: disable=too-many-locals + _uiscale = bui.app.ui_v1.uiscale + self._transitioning_out = False + s = 1.25 if _uiscale is babase.UIScale.SMALL else 1.27 if _uiscale is babase.UIScale.MEDIUM else 1.3 + self._width = 380 * s + self._height = 150 + 150 * s + self.path = Path(f"{getcwd()}/token.txt") + bg_color = (0.5, 0.4, 0.6) + log_btn_colour = (0.10, 0.95, 0.10) if not self.path.exists() else (1.00, 0.15, 0.15) + log_txt = "LOG IN" if not self.path.exists() else "LOG OUT" + self.code = False + self.resp = "Placeholder" + self.headers = { + 'user-agent': "Mozilla/5.0", + 'content-type': "application/json", + } + + + + # creates our _root_widget + PopupWindow.__init__(self, + position=(0.0, 0.0), + size=(self._width, self._height), + scale=(2.1 if _uiscale is babase.UIScale.SMALL else 1.5 + if _uiscale is babase.UIScale.MEDIUM else 1.0), + bg_color=bg_color) + + + self._cancel_button = bui.buttonwidget( + parent=self.root_widget, + position=(25, self._height - 40), + size=(50, 50), + scale=0.58, + label='', + color=bg_color, + on_activate_call=self._on_cancel_press, + autoselect=True, + icon=bui.gettexture('crossOut'), + iconscale=1.2) + + + + bui.imagewidget(parent=self.root_widget, + position=(180, self._height - 55), + size=(32 * s, 32 * s), + texture=bui.gettexture("discordLogo"), + color=(10 - 0.32, 10 - 0.39, 10 - 0.96)) + + + + self.email_widget = bui.textwidget(parent=self.root_widget, + text="Email/Phone Number", + size=(400, 70), + position=(50, 180), + h_align='left', + v_align='center', + editable=True, + scale=0.8, + autoselect=True, + maxwidth=220) + + + self.password_widget = bui.textwidget(parent=self.root_widget, + text="Password", + size=(400, 70), + position=(50, 120), + h_align='left', + v_align='center', + editable=True, + scale=0.8, + autoselect=True, + maxwidth=220) + + + bui.containerwidget(edit=self.root_widget, + cancel_button=self._cancel_button) + + bui.textwidget( + parent=self.root_widget, + position=(265, self._height - 37), + size=(0, 0), + h_align='center', + v_align='center', + scale=1.0, + text="Discord", + maxwidth=200, + color=(0.80, 0.80, 0.80)) + + bui.textwidget( + parent=self.root_widget, + position=(265, self._height - 78), + size=(0, 0), + h_align='center', + v_align='center', + scale=1.0, + text="💀Use at your own risk💀\n ⚠️discord account might get terminated⚠️", + maxwidth=200, + color=(1.00, 0.15, 0.15)) + + + self._login_button = bui.buttonwidget( + parent=self.root_widget, + position=(120, 65), + size=(400, 80), + scale=0.58, + label=log_txt, + color=log_btn_colour, + on_activate_call=self.login, + autoselect=True) + + def _on_cancel_press(self) -> None: + self._transition_out() + + def _transition_out(self) -> None: + if not self._transitioning_out: + self._transitioning_out = True + bui.containerwidget(edit=self.root_widget, transition='out_scale') + + def on_bascenev1libup_cancel(self) -> None: + bui.getsound('swish').play() + self._transition_out() + + + + def backup_2fa_code(self, tickt): + if babase.do_once(): + self.email_widget.delete() + self.password_widget.delete() + + self.backup_2fa_widget = bui.textwidget(parent=self.root_widget, + text="2FA/Discord Backup code", + size=(400, 70), + position=(50, 120), + h_align='left', + v_align='center', + editable=True, + scale=0.8, + autoselect=True, + maxwidth=220) + + + + json_data_2FA = { + "code": bui.textwidget(query=self.backup_2fa_widget), + "gift_code_sku_id": None, + "ticket": tickt, + } + + if json_data_2FA['code'] != "2FA/Discord Backup code": + try: + payload_2FA = json.dumps(json_data_2FA) + conn_2FA = http.client.HTTPSConnection("discord.com") + conn_2FA.request("POST", "/api/v9/auth/mfa/totp", payload_2FA, self.headers) + res_2FA = conn_2FA.getresponse().read() + token = json.loads(res_2FA)['token'].encode().hex().encode() + + with open(self.path, 'wb') as f: + f.write(token) + bui.screenmessage("Successfully logged in", (0.21, 1.0, 0.20)) + bui.getsound('shieldUp').play() + self.on_bascenev1libup_cancel() + PresenceUpdate().start() + except: + self.code = True + bui.screenmessage("Incorrect code", (1.00, 0.15, 0.15)) + bui.getsound('error').play() + + def login(self): + if not self.path.exists() and self.code == False: + try: + + json_data = { + 'login': bui.textwidget(query=self.email_widget), + 'password': bui.textwidget(query=self.password_widget), + 'undelete': False, + 'captcha_key': None, + 'login_source': None, + 'gift_code_sku_id': None, + } + + conn = http.client.HTTPSConnection("discord.com") + + payload = json.dumps(json_data) + # conn.request("POST", "/api/v9/auth/login", payload, headers) + # res = conn.getresponse().read() + conn.request("POST", "/api/v9/auth/login", payload, self.headers) + res = conn.getresponse().read() + + + + try: + token = json.loads(res)['token'].encode().hex().encode() + with open(self.path, 'wb') as f: + f.write(token) + bui.screenmessage("Successfully logged in", (0.21, 1.0, 0.20)) + bui.getsound('shieldUp').play() + self.on_bascenev1libup_cancel() + PresenceUpdate().start() + except KeyError: + try: + ticket = json.loads(res)['ticket'] + bui.screenmessage("Input your 2FA or Discord Backup code", (0.21, 1.0, 0.20)) + bui.getsound('error').play() + self.resp = ticket + self.backup_2fa_code(tickt=ticket) + self.code = True + except KeyError: + bui.screenmessage("Incorrect credentials", (1.00, 0.15, 0.15)) + bui.getsound('error').play() + + except: + bui.screenmessage("Connect to the internet", (1.00, 0.15, 0.15)) + bui.getsound('error').play() + + conn.close() + elif self.code == True: + self.backup_2fa_code(tickt=self.resp) + + + else: + self.email_widget.delete() + self.password_widget.delete() + remove(self.path) + bui.getsound('shieldDown').play() + bui.screenmessage("Account successfully removed!!", (0.10, 0.10, 1.00)) + self.on_bascenev1libup_cancel() + PresenceUpdate().ws.close() + + +run_once = False +def get_once_asset(): + global run_once + if run_once: + return + response = Request( + "https://discordapp.com/api/oauth2/applications/963434684669382696/assets", + headers={"User-Agent": "Mozilla/5.0"}, + ) + try: + with urlopen(response) as assets: + assets = json.loads(assets.read()) + asset = [] + asset_id = [] + for x in assets: + dem = x["name"] + don = x["id"] + asset_id.append(don) + asset.append(dem) + asset_id_dict = dict(zip(asset, asset_id)) + + with open(DIRPATH, "w") as imagesets: + jsonfile = json.dumps(asset_id_dict) + json.dump(asset_id_dict, imagesets, indent=4) + except: + pass + run_once = True + +def get_class(): + if ANDROID: + return PresenceUpdate() + elif not ANDROID: + return RpcThread() + + +# ba_meta export babase.Plugin +class DiscordRP(babase.Plugin): + def __init__(self) -> None: + self.update_timer: bs.Timer | None = None + self.rpc_thread = get_class() + self._last_server_info: str | None = None + + if not ANDROID: + _run_overrides() + get_once_asset() + + def on_app_running(self) -> None: + if not ANDROID: + self.rpc_thread.start() + self.update_timer = bs.AppTimer( + 1, bs.WeakCall(self.update_status), repeat=True + ) + if ANDROID: + self.rpc_thread.start() + self.update_timer = bs.AppTimer( + 4, bs.WeakCall(self.update_status), repeat=True + ) + + def has_settings_ui(self): + return True + + def show_settings_ui(self, button): + if not ANDROID: + bui.screenmessage("Nothing here achievement!!!", (0.26, 0.65, 0.94)) + bui.getsound('achievement').play() + if ANDROID: + Discordlogin() + + def on_app_shutdown(self) -> None: + if not ANDROID and self.rpc_thread.is_discord_running(): + self.rpc_thread.rpc.close() + self.rpc_thread.should_close = True + + def on_app_pause(self) -> None: + self.rpc_thread.close() + + def on_app_resume(self) -> None: + global start_time + start_time = time.time() + self.rpc_thread.start() + + def _get_current_activity_name(self) -> str | None: + act = bs.get_foreground_host_activity() + if isinstance(act, bs.GameActivity): + return act.name + + this = "Lobby" + name: str | None = ( + act.__class__.__name__.replace("Activity", "") + .replace("ScoreScreen", "Ranking") + .replace("Coop", "") + .replace("MultiTeam", "") + .replace("Victory", "") + .replace("EndSession", "") + .replace("Transition", "") + .replace("Draw", "") + .replace("FreeForAll", "") + .replace("Join", this) + .replace("Team", "") + .replace("Series", "") + .replace("CustomSession", "Custom Session(mod)") + ) + + if name == "MainMenu": + name = "Main Menu" + if name == this: + self.rpc_thread.large_image_key = "lobby" + self.rpc_thread.large_image_text = "Bombing up" + #self.rpc_thread.small_image_key = "lobbysmall" + if name == "Ranking": + self.rpc_thread.large_image_key = "ranking" + self.rpc_thread.large_image_text = "Viewing Results" + return name + + def _get_current_map_name(self) -> Tuple[str | None, str | None]: + act = bs.get_foreground_host_activity() + if isinstance(act, bs.GameActivity): + texname = act.map.get_preview_texture_name() + if texname: + return act.map.name, texname.lower().removesuffix("preview") + return None, None + + def update_status(self) -> None: + roster = bs.get_game_roster() + connection_info = bs.get_connection_to_host_info() + + self.rpc_thread.large_image_key = "bombsquadicon" + self.rpc_thread.large_image_text = "BombSquad" + self.rpc_thread.small_image_key = _babase.app.classic.platform + self.rpc_thread.small_image_text = ( + f"{_babase.app.classic.platform.capitalize()}({_babase.app.version})" + ) + connection_info = bs.get_connection_to_host_info() + if not ANDROID: + svinfo = str(connection_info) + if self._last_server_info != svinfo: + self._last_server_info = svinfo + self.rpc_thread.party_id = str(uuid.uuid4()) + self.rpc_thread._update_secret() + if connection_info != {}: + servername = connection_info["name"] + self.rpc_thread.details = "Online" + self.rpc_thread.party_size = max( + 1, sum(len(client["players"]) for client in roster) + ) + self.rpc_thread.party_max = max(8, self.rpc_thread.party_size) + if len(servername) == 19 and "Private Party" in servername: + self.rpc_thread.state = "Private Party" + elif servername == "": # A local game joinable from the internet + try: + offlinename = json.loads(bs.get_game_roster()[0]["spec_string"])[ + "n" + ] + if len(offlinename) > 19: # Thanks Rikko + self.rpc_thread.state = offlinename[slice(19)] + "..." + else: + self.rpc_thread.state = offlinename + except IndexError: + pass + else: + if len(servername) > 19: + self.rpc_thread.state = servername[slice(19)] + ".." + else: + self.rpc_thread.state = servername[slice(19)] + + if connection_info == {}: + self.rpc_thread.details = "Local" #! replace with something like ballistica github cause + self.rpc_thread.state = self._get_current_activity_name() + self.rpc_thread.party_size = max(1, len(roster)) + self.rpc_thread.party_max = max(1, bs.get_public_party_max_size()) + + if ( + bs.get_foreground_host_session() is not None + and self.rpc_thread.details == "Local" + ): + session = ( + bs.get_foreground_host_session() + .__class__.__name__.replace("MainMenuSession", "") + .replace("EndSession", "") + .replace("FreeForAllSession", ": FFA") #! for session use small image key + .replace("DualTeamSession", ": Teams") + .replace("CoopSession", ": Coop") + ) + #! self.rpc_thread.small_image_key = session.lower() + self.rpc_thread.details = f"{self.rpc_thread.details} {session}" + if ( + self.rpc_thread.state == "NoneType" + ): # sometimes the game just breaks which means its not really watching replay FIXME + self.rpc_thread.state = "Watching Replay" + self.rpc_thread.large_image_key = "replay" + self.rpc_thread.large_image_text = "Viewing Awesomeness" + #!self.rpc_thread.small_image_key = "replaysmall" + + act = bs.get_foreground_host_activity() + session = bs.get_foreground_host_session() + if act: + from bascenev1lib.game.elimination import EliminationGame + from bascenev1lib.game.thelaststand import TheLastStandGame + from bascenev1lib.game.meteorshower import MeteorShowerGame + + # noinspection PyUnresolvedReferences,PyProtectedMember + try: + self.rpc_thread.start_timestamp = act._discordrp_start_time # type: ignore + except AttributeError: + # This can be the case if plugin launched AFTER activity + # has been created; in that case let's assume it was + # created just now. + self.rpc_thread.start_timestamp = act._discordrp_start_time = time.mktime( # type: ignore + time.localtime() + ) + if isinstance(act, EliminationGame): + alive_count = len([p for p in act.players if p.lives > 0]) + self.rpc_thread.details += f" ({alive_count} players left)" + elif isinstance(act, TheLastStandGame): + # noinspection PyProtectedMember + points = act._score + self.rpc_thread.details += f" ({points} points)" + elif isinstance(act, MeteorShowerGame): + with bs.ContextRef(act): + sec = bs.time() - act._timer.getstarttime() + secfmt = "" + if sec < 60: + secfmt = f"{sec:.2f}" + else: + secfmt = f"{int(sec) // 60:02}:{sec:.2f}" + self.rpc_thread.details += f" ({secfmt})" + + # if isinstance(session, ba.DualTeamSession): + # scores = ':'.join([ + # str(t.customdata['score']) + # for t in session.sessionteams + # ]) + # self.rpc_thread.details += f' ({scores})' + + mapname, short_map_name = self._get_current_map_name() + if mapname: + with open(DIRPATH, 'r') as asset_dict: + asset_keys = json.load(asset_dict).keys() + if short_map_name in asset_keys: + self.rpc_thread.large_image_text = mapname + self.rpc_thread.large_image_key = short_map_name + self.rpc_thread.small_image_key = 'bombsquadlogo2' + self.rpc_thread.small_image_text = 'BombSquad' + + if _babase.get_idle_time() / (1000 * 60) % 60 >= 0.4: + self.rpc_thread.details = f"AFK in {self.rpc_thread.details}" + if not ANDROID: + self.rpc_thread.large_image_key = ( + "https://media.tenor.com/uAqNn6fv7x4AAAAM/bombsquad-spaz.gif" + ) + if ANDROID and Path(f"{getcwd()}/token.txt").exists(): + self.rpc_thread.presence() + \ No newline at end of file From 7f075d02ec7b37acbc23b1a637f3237c50e0b443 Mon Sep 17 00:00:00 2001 From: brostosjoined Date: Fri, 28 Jul 2023 23:35:32 +0000 Subject: [PATCH 0658/1464] [ci] auto-format --- plugins/utilities/discord_richpresence.py | 223 ++++++++++------------ 1 file changed, 102 insertions(+), 121 deletions(-) diff --git a/plugins/utilities/discord_richpresence.py b/plugins/utilities/discord_richpresence.py index 2f360e2d..26bdd55a 100644 --- a/plugins/utilities/discord_richpresence.py +++ b/plugins/utilities/discord_richpresence.py @@ -24,7 +24,7 @@ import hashlib import babase import _babase -import bascenev1 as bs +import bascenev1 as bs import bascenev1lib import bauiv1 as bui @@ -66,16 +66,15 @@ def get_module(): from websocket import WebSocketConnectionClosedException import websocket - start_time = time.time() - + class PresenceUpdate: def __init__(self): self.ws = websocket.WebSocketApp("wss://gateway.discord.gg/?encoding=json&v=10", - on_open=self.on_open, - on_message=self.on_message, - on_error=self.on_error, - on_close=self.on_close) + on_open=self.on_open, + on_message=self.on_message, + on_error=self.on_error, + on_close=self.on_close) self.heartbeat_interval = int(41250) self.resume_gateway_url: str | None = None self.session_id: str | None = None @@ -199,30 +198,27 @@ def identify(): identify() while True: heartbeat_payload = {"op": 1, "d": self.heartbeat_interval} - + try: self.ws.send(json.dumps(heartbeat_payload)) time.sleep(self.heartbeat_interval / 1000) except: pass - + if self.stop_heartbeat_thread.is_set(): self.stop_heartbeat_thread.clear() break - + threading.Thread(target=heartbeats, daemon=True, name="heartbeat").start() - + def start(self): if Path(f"{getcwd()}/token.txt").exists(): threading.Thread(target=self.ws.run_forever, daemon=True, name="websocket").start() - + def close(self): self.stop_heartbeat_thread.set() self.do_once = True self.ws.close() - - - if not ANDROID: @@ -239,13 +235,13 @@ def get_module(): with open(filename, "rb") as f: content = f.read() assert hashlib.md5(content).hexdigest() == "f7c163cdd001af2456c09e241b90bad7" - shutil.unpack_archive( filename, install_path) + shutil.unpack_archive(filename, install_path) shutil.copytree(source_dir, file_path) shutil.rmtree(Path(f"{install_path}/pypresence-4.3.0")) remove(path) except: pass - + # Make modifications for it to work on windows if babase.app.classic.platform == "windows": with open(Path(f"{getcwd()}/ba_data/python/pypresence/utils.py"), "r") as file: @@ -269,24 +265,23 @@ def get_event_loop(force_fresh=False): return running else: return loop""" - #Thanks Loup + # Thanks Loup with open(Path(f"{getcwd()}/ba_data/python/pypresence/utils.py"), "w") as file: for number, line in enumerate(data): - if number not in range(46,56): + if number not in range(46, 56): file.write(line) get_module() - from pypresence import PipeClosed, DiscordError, DiscordNotFound from pypresence.utils import get_event_loop - import pypresence + import pypresence import socket - + DEBUG = True - + _last_server_addr = 'localhost' _last_server_port = 43210 - + def print_error(err: str, include_exception: bool = False) -> None: if DEBUG: if include_exception: @@ -317,8 +312,8 @@ def new_connect(*args, **kwargs) -> None: # type: ignore old_connect(*args, **kwargs) c = kwargs.get("address") or args[0] _last_server_port = kwargs.get("port") or args[1] - - bs.connect_to_party = new_connect + + bs.connect_to_party = new_connect start_time = time.time() @@ -341,10 +336,10 @@ def __init__(self): self._last_secret_update_time: float = 0 self._last_connect_time: float = 0 self.should_close = False - - @staticmethod + + @staticmethod def is_discord_running(): - for i in range(6463,6473): + for i in range(6463, 6473): s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) s.settimeout(0.01) try: @@ -352,11 +347,11 @@ def is_discord_running(): s.close() if (conn == 0): s.close() - return(True) + return (True) except: s.close() - return(False) - + return (False) + def _generate_join_secret(self): # resp = requests.get('https://legacy.ballistica.net/bsAccessCheck').text connection_info = bs.get_connection_to_host_info() @@ -413,7 +408,7 @@ def _subscribe_events(self): self._subscribe("ACTIVITY_JOIN") self._subscribe("ACTIVITY_JOIN_REQUEST") - # def _update_presence(self) -> None: + # def _update_presence(self) -> None: # self._last_update_time = time.time() # try: # self._do_update_presence() @@ -422,7 +417,6 @@ def _subscribe_events(self): # self._reconnect() # except Exception: # print_error("failed to update presence", include_exception= True) - def _reconnect(self) -> None: self.rpc.connect() @@ -499,7 +493,7 @@ def handle_event(self, data): def _connect_to_party(self, hostname, port) -> None: babase.pushcall( babase.Call(bs.connect_to_party, hostname, port), from_other_thread=True - ) + ) def on_join_request(self, username, uid, discriminator, avatar) -> None: del uid # unused @@ -507,7 +501,8 @@ def on_join_request(self, username, uid, discriminator, avatar) -> None: babase.pushcall( babase.Call( bui.screenmessage, - "Discord: {}{} wants to join!".format(username, discriminator if discriminator != "#0" else ""), + "Discord: {}{} wants to join!".format( + username, discriminator if discriminator != "#0" else ""), color=(0.0, 1.0, 0.0), ), from_other_thread=True, @@ -527,15 +522,13 @@ def __init__(self): self.path = Path(f"{getcwd()}/token.txt") bg_color = (0.5, 0.4, 0.6) log_btn_colour = (0.10, 0.95, 0.10) if not self.path.exists() else (1.00, 0.15, 0.15) - log_txt = "LOG IN" if not self.path.exists() else "LOG OUT" + log_txt = "LOG IN" if not self.path.exists() else "LOG OUT" self.code = False self.resp = "Placeholder" self.headers = { - 'user-agent': "Mozilla/5.0", - 'content-type': "application/json", - } - - + 'user-agent': "Mozilla/5.0", + 'content-type': "application/json", + } # creates our _root_widget PopupWindow.__init__(self, @@ -544,7 +537,6 @@ def __init__(self): scale=(2.1 if _uiscale is babase.UIScale.SMALL else 1.5 if _uiscale is babase.UIScale.MEDIUM else 1.0), bg_color=bg_color) - self._cancel_button = bui.buttonwidget( parent=self.root_widget, @@ -557,44 +549,38 @@ def __init__(self): autoselect=True, icon=bui.gettexture('crossOut'), iconscale=1.2) - - - + bui.imagewidget(parent=self.root_widget, - position=(180, self._height - 55), - size=(32 * s, 32 * s), - texture=bui.gettexture("discordLogo"), - color=(10 - 0.32, 10 - 0.39, 10 - 0.96)) - + position=(180, self._height - 55), + size=(32 * s, 32 * s), + texture=bui.gettexture("discordLogo"), + color=(10 - 0.32, 10 - 0.39, 10 - 0.96)) - self.email_widget = bui.textwidget(parent=self.root_widget, - text="Email/Phone Number", - size=(400, 70), - position=(50, 180), - h_align='left', - v_align='center', - editable=True, - scale=0.8, - autoselect=True, - maxwidth=220) - - + text="Email/Phone Number", + size=(400, 70), + position=(50, 180), + h_align='left', + v_align='center', + editable=True, + scale=0.8, + autoselect=True, + maxwidth=220) + self.password_widget = bui.textwidget(parent=self.root_widget, - text="Password", - size=(400, 70), - position=(50, 120), - h_align='left', - v_align='center', - editable=True, - scale=0.8, - autoselect=True, - maxwidth=220) - - + text="Password", + size=(400, 70), + position=(50, 120), + h_align='left', + v_align='center', + editable=True, + scale=0.8, + autoselect=True, + maxwidth=220) + bui.containerwidget(edit=self.root_widget, - cancel_button=self._cancel_button) - + cancel_button=self._cancel_button) + bui.textwidget( parent=self.root_widget, position=(265, self._height - 37), @@ -605,7 +591,7 @@ def __init__(self): text="Discord", maxwidth=200, color=(0.80, 0.80, 0.80)) - + bui.textwidget( parent=self.root_widget, position=(265, self._height - 78), @@ -616,8 +602,7 @@ def __init__(self): text="💀Use at your own risk💀\n ⚠️discord account might get terminated⚠️", maxwidth=200, color=(1.00, 0.15, 0.15)) - - + self._login_button = bui.buttonwidget( parent=self.root_widget, position=(120, 65), @@ -639,33 +624,29 @@ def _transition_out(self) -> None: def on_bascenev1libup_cancel(self) -> None: bui.getsound('swish').play() self._transition_out() - - - + def backup_2fa_code(self, tickt): if babase.do_once(): self.email_widget.delete() self.password_widget.delete() - + self.backup_2fa_widget = bui.textwidget(parent=self.root_widget, - text="2FA/Discord Backup code", - size=(400, 70), - position=(50, 120), - h_align='left', - v_align='center', - editable=True, - scale=0.8, - autoselect=True, - maxwidth=220) - - + text="2FA/Discord Backup code", + size=(400, 70), + position=(50, 120), + h_align='left', + v_align='center', + editable=True, + scale=0.8, + autoselect=True, + maxwidth=220) json_data_2FA = { - "code": bui.textwidget(query=self.backup_2fa_widget), - "gift_code_sku_id": None, - "ticket": tickt, + "code": bui.textwidget(query=self.backup_2fa_widget), + "gift_code_sku_id": None, + "ticket": tickt, } - + if json_data_2FA['code'] != "2FA/Discord Backup code": try: payload_2FA = json.dumps(json_data_2FA) @@ -673,7 +654,7 @@ def backup_2fa_code(self, tickt): conn_2FA.request("POST", "/api/v9/auth/mfa/totp", payload_2FA, self.headers) res_2FA = conn_2FA.getresponse().read() token = json.loads(res_2FA)['token'].encode().hex().encode() - + with open(self.path, 'wb') as f: f.write(token) bui.screenmessage("Successfully logged in", (0.21, 1.0, 0.20)) @@ -684,11 +665,11 @@ def backup_2fa_code(self, tickt): self.code = True bui.screenmessage("Incorrect code", (1.00, 0.15, 0.15)) bui.getsound('error').play() - + def login(self): if not self.path.exists() and self.code == False: try: - + json_data = { 'login': bui.textwidget(query=self.email_widget), 'password': bui.textwidget(query=self.password_widget), @@ -697,7 +678,7 @@ def login(self): 'login_source': None, 'gift_code_sku_id': None, } - + conn = http.client.HTTPSConnection("discord.com") payload = json.dumps(json_data) @@ -705,9 +686,7 @@ def login(self): # res = conn.getresponse().read() conn.request("POST", "/api/v9/auth/login", payload, self.headers) res = conn.getresponse().read() - - try: token = json.loads(res)['token'].encode().hex().encode() with open(self.path, 'wb') as f: @@ -716,27 +695,27 @@ def login(self): bui.getsound('shieldUp').play() self.on_bascenev1libup_cancel() PresenceUpdate().start() - except KeyError: + except KeyError: try: ticket = json.loads(res)['ticket'] - bui.screenmessage("Input your 2FA or Discord Backup code", (0.21, 1.0, 0.20)) + bui.screenmessage("Input your 2FA or Discord Backup code", + (0.21, 1.0, 0.20)) bui.getsound('error').play() - self.resp = ticket + self.resp = ticket self.backup_2fa_code(tickt=ticket) self.code = True except KeyError: bui.screenmessage("Incorrect credentials", (1.00, 0.15, 0.15)) bui.getsound('error').play() - - except: + + except: bui.screenmessage("Connect to the internet", (1.00, 0.15, 0.15)) bui.getsound('error').play() conn.close() elif self.code == True: self.backup_2fa_code(tickt=self.resp) - - + else: self.email_widget.delete() self.password_widget.delete() @@ -746,8 +725,10 @@ def login(self): self.on_bascenev1libup_cancel() PresenceUpdate().ws.close() - + run_once = False + + def get_once_asset(): global run_once if run_once: @@ -775,6 +756,7 @@ def get_once_asset(): pass run_once = True + def get_class(): if ANDROID: return PresenceUpdate() @@ -795,7 +777,7 @@ def __init__(self) -> None: def on_app_running(self) -> None: if not ANDROID: - self.rpc_thread.start() + self.rpc_thread.start() self.update_timer = bs.AppTimer( 1, bs.WeakCall(self.update_status), repeat=True ) @@ -822,17 +804,17 @@ def on_app_shutdown(self) -> None: def on_app_pause(self) -> None: self.rpc_thread.close() - + def on_app_resume(self) -> None: - global start_time + global start_time start_time = time.time() self.rpc_thread.start() - + def _get_current_activity_name(self) -> str | None: act = bs.get_foreground_host_activity() if isinstance(act, bs.GameActivity): return act.name - + this = "Lobby" name: str | None = ( act.__class__.__name__.replace("Activity", "") @@ -900,7 +882,7 @@ def update_status(self) -> None: offlinename = json.loads(bs.get_game_roster()[0]["spec_string"])[ "n" ] - if len(offlinename) > 19: # Thanks Rikko + if len(offlinename) > 19: # Thanks Rikko self.rpc_thread.state = offlinename[slice(19)] + "..." else: self.rpc_thread.state = offlinename @@ -913,7 +895,7 @@ def update_status(self) -> None: self.rpc_thread.state = servername[slice(19)] if connection_info == {}: - self.rpc_thread.details = "Local" #! replace with something like ballistica github cause + self.rpc_thread.details = "Local" # ! replace with something like ballistica github cause self.rpc_thread.state = self._get_current_activity_name() self.rpc_thread.party_size = max(1, len(roster)) self.rpc_thread.party_max = max(1, bs.get_public_party_max_size()) @@ -926,7 +908,7 @@ def update_status(self) -> None: bs.get_foreground_host_session() .__class__.__name__.replace("MainMenuSession", "") .replace("EndSession", "") - .replace("FreeForAllSession", ": FFA") #! for session use small image key + .replace("FreeForAllSession", ": FFA") # ! for session use small image key .replace("DualTeamSession", ": Teams") .replace("CoopSession", ": Coop") ) @@ -999,4 +981,3 @@ def update_status(self) -> None: ) if ANDROID and Path(f"{getcwd()}/token.txt").exists(): self.rpc_thread.presence() - \ No newline at end of file From 4b3ca387de456f33d598466ab6088a79393c5e43 Mon Sep 17 00:00:00 2001 From: brostosjoined Date: Fri, 28 Jul 2023 23:35:33 +0000 Subject: [PATCH 0659/1464] [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 462398b1..3ede5bcc 100644 --- a/plugins/utilities.json +++ b/plugins/utilities.json @@ -800,4 +800,4 @@ } } } -} +} \ No newline at end of file From 150f49f1d4f3d79114e21659951abff0b9c9a346 Mon Sep 17 00:00:00 2001 From: brostos <67740566+brostosjoined@users.noreply.github.com> Date: Sat, 29 Jul 2023 02:39:35 +0300 Subject: [PATCH 0660/1464] Update utilities.json Updated link to tutorial --- plugins/utilities.json | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/plugins/utilities.json b/plugins/utilities.json index 3ede5bcc..297fd37f 100644 --- a/plugins/utilities.json +++ b/plugins/utilities.json @@ -785,6 +785,7 @@ } ], "versions": { + "1.2.0" : null, "1.1.0": { "api_version": 8, "commit_sha": "90fff9b", @@ -800,4 +801,4 @@ } } } -} \ No newline at end of file +} From d9f5e3ecaeb7854404ade48e7e876715372f490e Mon Sep 17 00:00:00 2001 From: brostosjoined Date: Fri, 28 Jul 2023 23:40:01 +0000 Subject: [PATCH 0661/1464] [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 297fd37f..a17e3952 100644 --- a/plugins/utilities.json +++ b/plugins/utilities.json @@ -785,7 +785,12 @@ } ], "versions": { - "1.2.0" : null, + "1.2.0": { + "api_version": 8, + "commit_sha": "150f49f", + "released_on": "28-07-2023", + "md5sum": "3b13d83518865a2b07b9340d59d0ab92" + }, "1.1.0": { "api_version": 8, "commit_sha": "90fff9b", @@ -801,4 +806,4 @@ } } } -} +} \ No newline at end of file From 3cdac453ca6eec363e61ed16809b019809b51d69 Mon Sep 17 00:00:00 2001 From: ! Freaku <92618708+Freaku17@users.noreply.github.com> Date: Mon, 31 Jul 2023 00:25:41 +0530 Subject: [PATCH 0662/1464] Update gamemode for API 8 --- plugins/minigames/yeeting_party.py | 219 ++--------------------------- 1 file changed, 14 insertions(+), 205 deletions(-) diff --git a/plugins/minigames/yeeting_party.py b/plugins/minigames/yeeting_party.py index a5e79a00..18553635 100644 --- a/plugins/minigames/yeeting_party.py +++ b/plugins/minigames/yeeting_party.py @@ -1,224 +1,33 @@ -# Made by your friend: @[Just] Freak#4999 +# Made by your friend: Freaku -# ba_meta require api 7 -from __future__ import annotations -from typing import TYPE_CHECKING +import babase +import bascenev1 as bs +from bascenev1lib.game.deathmatch import Player, DeathMatchGame -import ba -from bastd.actor.playerspaz import PlayerSpaz -from bastd.actor.scoreboard import Scoreboard -if TYPE_CHECKING: - from typing import Any, Type, List, Dict, Tuple, Union, Sequence, Optional - - -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 - - -# ba_meta export game -class BoxingGame(ba.TeamGameActivity[Player, Team]): +# ba_meta require api 8 +# ba_meta export bascenev1.GameActivity +class YeetingGame(DeathMatchGame): """A game of yeeting people out of map""" name = 'Yeeting Party!' description = 'Yeet your enemies out of the map' - # Print messages when players die since it matters here. - announce_player_deaths = True - - @classmethod - def get_available_settings( - cls, sessiontype: Type[ba.Session]) -> List[ba.Setting]: - settings = [ - ba.IntSetting( - 'Kills to Win Per Player', - 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', 4.0), - ], - default=1.0, - ), - ba.BoolSetting('Epic Mode', default=False), - ] - - # In teams mode, a suicide gives a point to the other team, but in - # free-for-all it subtracts from your own score. By default we clamp - # this at zero to benefit new players, but pro players might like to - # be able to go negative. (to avoid a strategy of just - # suiciding until you get a good drop) - if issubclass(sessiontype, ba.FreeForAllSession): - settings.append( - ba.BoolSetting('Allow Negative Scores', default=False)) - - return settings - - @classmethod - def supports_session_type(cls, sessiontype: Type[ba.Session]) -> bool: - return (issubclass(sessiontype, ba.DualTeamSession) - or issubclass(sessiontype, ba.FreeForAllSession)) - @classmethod - def get_supported_maps(cls, sessiontype: Type[ba.Session]) -> List[str]: + def get_supported_maps(cls, sessiontype): return ['Bridgit', 'Rampage', 'Monkey Face'] - def __init__(self, settings: dict): - super().__init__(settings) - self._scoreboard = Scoreboard() - self._score_to_win: Optional[int] = None - self._dingsound = ba.getsound('dingSmall') - self._epic_mode = bool(settings['Epic Mode']) - self._kills_to_win_per_player = int( - settings['Kills to Win Per Player']) - self._time_limit = float(settings['Time Limit']) - self._allow_negative_scores = bool( - settings.get('Allow Negative Scores', False)) - - # Base class overrides. - self.slow_motion = self._epic_mode - self.default_music = (ba.MusicType.EPIC if self._epic_mode else - ba.MusicType.TO_THE_DEATH) - - def get_instance_description(self) -> Union[str, Sequence]: + def get_instance_description(self): return 'Yeet ${ARG1} enemies out of the map!', self._score_to_win - def get_instance_description_short(self) -> Union[str, Sequence]: + def get_instance_description_short(self): return 'yeet ${ARG1} enemies', self._score_to_win - def on_team_join(self, team: Team) -> None: - if self.has_begun(): - self._update_scoreboard() - - def getRandomPowerupPoint(self) -> None: - myMap = self.map.getname() - if myMap == 'Doom Shroom': - while True: - x = random.uniform(-1.0, 1.0) - y = random.uniform(-1.0, 1.0) - if x*x+y*y < 1.0: - break - return ((8.0*x, 2.5, -3.5+5.0*y)) - elif myMap == 'Rampage': - x = random.uniform(-6.0, 7.0) - y = random.uniform(-6.0, -2.5) - return ((x, 5.2, y)) - else: - x = random.uniform(-5.0, 5.0) - y = random.uniform(-6.0, 0.0) - return ((x, 8.0, y)) - - def on_begin(self) -> None: - super().on_begin() - ba.screenmessage("start Yeeting", color=(0.2, 1, 1)) - self.setup_standard_time_limit(self._time_limit) - # Base kills needed to win on the size of the largest team. - self._score_to_win = (self._kills_to_win_per_player * - max(1, max(len(t.players) for t in self.teams))) - self._update_scoreboard() - - def spawn_player(self, player: Player) -> ba.Actor: + def setup_standard_powerup_drops(self, enable_tnt: bool = True) -> None: + pass + def spawn_player(self, player: Player): spaz = self.spawn_player_spaz(player) - - # Let's reconnect this player's controls to this - # spaz but *without* the ability to attack or pick stuff up. - spaz.connect_controls_to_player(enable_punch=False, - enable_jump=True, - enable_bomb=False, - enable_pickup=True) + spaz.connect_controls_to_player(enable_punch=False, enable_bomb=False) return spaz - - def handlemessage(self, msg: Any) -> Any: - - if isinstance(msg, ba.PlayerDiedMessage): - - # Augment standard behavior. - super().handlemessage(msg) - - player = msg.getplayer(Player) - self.respawn_player(player) - - killer = msg.getkillerplayer(Player) - if killer is None: - return None - - # Handle team-kills. - if killer.team is player.team: - - # In free-for-all, killing yourself loses you a point. - if isinstance(self.session, ba.FreeForAllSession): - new_score = player.team.score - 1 - if not self._allow_negative_scores: - new_score = max(0, new_score) - player.team.score = new_score - - # In teams-mode it gives a point to the other team. - else: - ba.playsound(self._dingsound) - for team in self.teams: - if team is not killer.team: - team.score += 1 - - # Killing someone on another team nets a kill. - else: - killer.team.score += 1 - ba.playsound(self._dingsound) - - # In FFA show scores since its hard to find on the scoreboard. - if isinstance(killer.actor, PlayerSpaz) and killer.actor: - killer.actor.set_score_text(str(killer.team.score) + '/' + - str(self._score_to_win), - color=killer.team.color, - flash=True) - - self._update_scoreboard() - - # If someone has won, set a timer to end shortly. - # (allows the dust to clear and draws to occur if deaths are - # close enough) - assert self._score_to_win is not None - if any(team.score >= self._score_to_win for team in self.teams): - ba.timer(0.5, self.end_game) - - else: - return super().handlemessage(msg) - return None - - def _update_scoreboard(self) -> None: - for team in self.teams: - self._scoreboard.set_team_value(team, team.score, - self._score_to_win) - - def end_game(self) -> None: - results = ba.GameResults() - for team in self.teams: - results.set_team_score(team, team.score) - self.end(results=results) From 8f281f98b390fbf065a393133ca3e610e812faee Mon Sep 17 00:00:00 2001 From: ! Freaku <92618708+Freaku17@users.noreply.github.com> Date: Mon, 31 Jul 2023 00:26:10 +0530 Subject: [PATCH 0663/1464] Update JSON file --- plugins/minigames.json | 1 + 1 file changed, 1 insertion(+) diff --git a/plugins/minigames.json b/plugins/minigames.json index 8d698fe4..84612375 100644 --- a/plugins/minigames.json +++ b/plugins/minigames.json @@ -709,6 +709,7 @@ } ], "versions": { + "2.0.0": null, "1.0.0": { "api_version": 7, "commit_sha": "7219487", From 31c54448b42fb2bd1bc9cadfae3e1a8cee9fc7b8 Mon Sep 17 00:00:00 2001 From: Freaku17 Date: Sun, 30 Jul 2023 18:57:47 +0000 Subject: [PATCH 0664/1464] [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 84612375..65af0b55 100644 --- a/plugins/minigames.json +++ b/plugins/minigames.json @@ -709,7 +709,12 @@ } ], "versions": { - "2.0.0": null, + "2.0.0": { + "api_version": 8, + "commit_sha": "8f281f9", + "released_on": "30-07-2023", + "md5sum": "c512cd21244f9537b7ff98438a3e6ef8" + }, "1.0.0": { "api_version": 7, "commit_sha": "7219487", From 947b870b433ce255c0a287e0f0ed08045115bb08 Mon Sep 17 00:00:00 2001 From: brostos <67740566+brostosjoined@users.noreply.github.com> Date: Mon, 31 Jul 2023 11:03:43 +0300 Subject: [PATCH 0665/1464] Update file_share.py --- plugins/utilities/file_share.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/utilities/file_share.py b/plugins/utilities/file_share.py index b13ed66b..69200377 100644 --- a/plugins/utilities/file_share.py +++ b/plugins/utilities/file_share.py @@ -70,7 +70,7 @@ def _ok(self) -> None: def _upload_file(self): self.status = "uploading" - print(self.root_widget) + # print(self.root_widget) thread = Thread(target=handle_upload, args=( self.file_path, self.uploaded, self.root_widget,)) thread.start() From dbd41c460b2eff64edcbe767d760dcd688410d7e Mon Sep 17 00:00:00 2001 From: brostos <67740566+brostosjoined@users.noreply.github.com> Date: Mon, 31 Jul 2023 11:13:32 +0300 Subject: [PATCH 0666/1464] Update utilities.json --- plugins/utilities.json | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/plugins/utilities.json b/plugins/utilities.json index 595a1e82..0ccb1a92 100644 --- a/plugins/utilities.json +++ b/plugins/utilities.json @@ -440,12 +440,7 @@ } ], "versions": { - "1.0.0": { - "api_version": 8, - "commit_sha": "09319de", - "released_on": "28-07-2023", - "md5sum": "4eee80d51f8289adde5416a24749772f" - } + "1.0.0": null } }, "server_switch": { @@ -819,4 +814,4 @@ } } } -} \ No newline at end of file +} From f1b96b4926b0d40f9e54135eb03011fb922d5c91 Mon Sep 17 00:00:00 2001 From: brostosjoined Date: Mon, 31 Jul 2023 08:14:00 +0000 Subject: [PATCH 0667/1464] [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 0ccb1a92..557aab46 100644 --- a/plugins/utilities.json +++ b/plugins/utilities.json @@ -440,7 +440,12 @@ } ], "versions": { - "1.0.0": null + "1.0.0": { + "api_version": 8, + "commit_sha": "dbd41c4", + "released_on": "31-07-2023", + "md5sum": "e1d4852a3c2c2dbf746867016ae9fbdf" + } } }, "server_switch": { @@ -814,4 +819,4 @@ } } } -} +} \ No newline at end of file From 9340deb5f009159c2444173ffed7e9e3956f0624 Mon Sep 17 00:00:00 2001 From: CrossJoy <87638792+CrossJoy@users.noreply.github.com> Date: Sat, 29 Jul 2023 02:52:18 +0800 Subject: [PATCH 0668/1464] update practice tools to API 8 [ci] auto-format [ci] apply-version-metadata Removed debug in practice_tools.py Added .history into .gitignore Delete .history/plugins directory Update utilities.json Update utilities.json [ci] apply-version-metadata --- .gitignore | 1 + plugins/utilities.json | 6 + plugins/utilities/practice_tools.py | 1365 ++++++++++++++------------- 3 files changed, 694 insertions(+), 678 deletions(-) diff --git a/.gitignore b/.gitignore index 44e23e1b..d13b15ab 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,4 @@ reference.py __pycache__ *.pyc +.history diff --git a/plugins/utilities.json b/plugins/utilities.json index 0aabefb0..f2146394 100644 --- a/plugins/utilities.json +++ b/plugins/utilities.json @@ -666,6 +666,12 @@ } ], "versions": { + "2.0.0": { + "api_version": 8, + "commit_sha": "6e995dd", + "released_on": "31-07-2023", + "md5sum": "5cc5d2d1d775c726b6065679dcfe3bda" + }, "1.2.0": { "api_version": 7, "commit_sha": "e61958b", diff --git a/plugins/utilities/practice_tools.py b/plugins/utilities/practice_tools.py index ae9897a1..1c7fe086 100644 --- a/plugins/utilities/practice_tools.py +++ b/plugins/utilities/practice_tools.py @@ -1,4 +1,4 @@ -"""Practice Tools Mod: V1.2 +"""Practice Tools Mod: V2.0 Made by Cross Joy""" # If anyone who want to help me on giving suggestion/ fix bugs/ creating PR, @@ -12,6 +12,9 @@ # Support link: https://www.buymeacoffee.com/CrossJoy # ---------------------------------------------------------------------------- +# V2.0 update +# - Updated to API 8 (1.7.20+) + # V1.2 update # - Added New Bot: Bomber Lite and Brawler Lite. # - Added New Setting: Epic Mode Toggle. @@ -53,95 +56,86 @@ from __future__ import annotations +import math import random import weakref from enum import Enum from typing import TYPE_CHECKING -import ba -import _ba -import ba.internal -import bastd -from bastd.actor.powerupbox import PowerupBox -from bastd.actor.spaz import Spaz -from bastd.actor.spazbot import (SpazBotSet, SpazBot, BrawlerBot, TriggerBot, - ChargerBot, StickyBot, ExplodeyBot, BouncyBot, - BomberBotPro, BrawlerBotPro, TriggerBotPro, - ChargerBotPro, BomberBotProShielded, - BrawlerBotProShielded, TriggerBotProShielded, - ChargerBotProShielded, BomberBotLite, BrawlerBotLite) -from bastd.mainmenu import MainMenuSession -from bastd.ui.party import PartyWindow as OriginalPartyWindow -from ba import app, Plugin -from bastd.ui import popup -from bastd.actor.bomb import Bomb -import math -from bastd.ui.tabs import TabRow +import babase +import bascenev1 as bs +import bascenev1lib +import bauiv1 as bui +import bauiv1lib as buil +from babase import app, Plugin +from bascenev1lib.actor.powerupbox import PowerupBox +from bascenev1lib.actor.spaz import Spaz +from bascenev1lib.actor import spawner +from bascenev1lib.actor.spazbot import (SpazBotSet, SpazBot, BrawlerBot, + TriggerBot, + ChargerBot, StickyBot, ExplodeyBot, + BouncyBot, + BomberBotPro, BrawlerBotPro, + TriggerBotPro, + ChargerBotPro, BomberBotProShielded, + BrawlerBotProShielded, + TriggerBotProShielded, + ChargerBotProShielded, BomberBotLite, + BrawlerBotLite) +from bascenev1lib.mainmenu import MainMenuSession +from bauiv1lib import popup +from bauiv1lib.party import PartyWindow as OriginalPartyWindow +from bauiv1lib.tabs import TabRow if TYPE_CHECKING: from typing import Any, Sequence, Callable, Optional +version = '2.0' + try: - if ba.app.config.get("bombCountdown") is None: - ba.app.config["bombCountdown"] = False + if babase.app.config.get("bombCountdown") is None: + babase.app.config["bombCountdown"] = False else: - ba.app.config.get("bombCountdown") + babase.app.config.get("bombCountdown") except: - ba.app.config["bombCountdown"] = False + babase.app.config["bombCountdown"] = False try: - if ba.app.config.get("bombRadiusVisual") is None: - ba.app.config["bombRadiusVisual"] = False + if babase.app.config.get("bombRadiusVisual") is None: + babase.app.config["bombRadiusVisual"] = False else: - ba.app.config.get("bombRadiusVisual") + babase.app.config.get("bombRadiusVisual") except: - ba.app.config["bombRadiusVisual"] = False + babase.app.config["bombRadiusVisual"] = False try: - if ba.app.config.get("stopBots") is None: - ba.app.config["stopBots"] = False + if babase.app.config.get("stopBots") is None: + babase.app.config["stopBots"] = False else: - ba.app.config.get("stopBots") + babase.app.config.get("stopBots") except: - ba.app.config["stopBots"] = False + babase.app.config["stopBots"] = False try: - if ba.app.config.get("immortalDummy") is None: - ba.app.config["immortalDummy"] = False + if babase.app.config.get("immortalDummy") is None: + babase.app.config["immortalDummy"] = False else: - ba.app.config.get("immortalDummy") + babase.app.config.get("immortalDummy") except: - ba.app.config["immortalDummy"] = False + babase.app.config["immortalDummy"] = False try: - if ba.app.config.get("invincible") is None: - ba.app.config["invincible"] = False + if babase.app.config.get("invincible") is None: + babase.app.config["invincible"] = False else: - ba.app.config.get("invincible") + babase.app.config.get("invincible") except: - ba.app.config["invincible"] = False - -_ba.set_party_icon_always_visible(True) - - -def is_game_version_lower_than(version): - """ - Returns a boolean value indicating whether the current game - version is lower than the passed version. Useful for addressing - any breaking changes within game versions. - """ - game_version = tuple(map(int, ba.app.version.split("."))) - version = tuple(map(int, version.split("."))) - return game_version < version + babase.app.config["invincible"] = False +bui.set_party_icon_always_visible(True) -if is_game_version_lower_than("1.7.7"): - ba_internal = _ba -else: - ba_internal = ba.internal - -class PartyWindow(ba.Window): +class PartyWindow(bui.Window): _redefine_methods = ['__init__'] def __init__(self, *args, **kwargs): @@ -149,7 +143,7 @@ def __init__(self, *args, **kwargs): self.bg_color = (.5, .5, .5) - self._edit_movements_button = ba.buttonwidget( + self._edit_movements_button = bui.buttonwidget( parent=self._root_widget, scale=0.7, position=(360, self._height - 47), @@ -158,7 +152,7 @@ def __init__(self, *args, **kwargs): label='Practice', autoselect=True, button_type='square', - on_activate_call=ba.Call(doTestButton, self), + on_activate_call=bs.Call(doTestButton, self), color=self.bg_color, iconscale=1.2) @@ -183,16 +177,16 @@ def main(plugin: Plugin) -> None: redefine_class(OriginalPartyWindow, PartyWindow) -# ba_meta require api 7 +# ba_meta require api 8 # ba_meta export plugin class Practice(Plugin): - __version__ = '1.2' + __version__ = '2.0' def on_app_running(self) -> None: """Plugin start point.""" if app.build_number < 20427: - ba.screenmessage( + bui.screenmessage( 'ok', color=(.8, .1, .1)) raise RuntimeError( @@ -207,8 +201,8 @@ def setting(*args, **kwargs): bomb_type = args[0].bomb_type fuse_bomb = ('land_mine', 'tnt', 'impact') - if ba.app.config.get("bombRadiusVisual"): - args[0].radius_visualizer = ba.newnode('locator', + if babase.app.config.get("bombRadiusVisual"): + args[0].radius_visualizer = bs.newnode('locator', owner=args[0].node, # Remove itself when the bomb node dies. attrs={ @@ -221,13 +215,13 @@ def setting(*args, **kwargs): args[0].node.connectattr('position', args[0].radius_visualizer, 'position') - ba.animate_array(args[0].radius_visualizer, 'size', 1, { + bs.animate_array(args[0].radius_visualizer, 'size', 1, { 0.0: [0.0], 0.2: [args[0].blast_radius * 2.2], 0.25: [args[0].blast_radius * 2.0] }) - args[0].radius_visualizer_circle = ba.newnode( + args[0].radius_visualizer_circle = bs.newnode( 'locator', owner=args[ 0].node, @@ -247,14 +241,14 @@ def setting(*args, **kwargs): args[0].radius_visualizer_circle, 'position') - ba.animate( + bs.animate( args[0].radius_visualizer_circle, 'opacity', { 0: 0.0, 0.4: 0.1 }) if bomb_type == 'tnt': - args[0].fatal = ba.newnode('locator', + args[0].fatal = bs.newnode('locator', owner=args[0].node, # Remove itself when the bomb node dies. attrs={ @@ -269,25 +263,25 @@ def setting(*args, **kwargs): args[0].fatal, 'position') - ba.animate_array(args[0].fatal, 'size', 1, { + bs.animate_array(args[0].fatal, 'size', 1, { 0.0: [0.0], 0.2: [args[0].blast_radius * 2.2 * 0.7], 0.25: [args[0].blast_radius * 2.0 * 0.7] }) - if ba.app.config.get( + if babase.app.config.get( "bombCountdown") and bomb_type not in fuse_bomb: color = (1.0, 1.0, 0.0) count_bomb(*args, count='3', color=color) color = (1.0, 0.5, 0.0) - ba.timer(1, ba.Call(count_bomb, *args, count='2', color=color)) + bs.timer(1, bs.Call(count_bomb, *args, count='2', color=color)) color = (1.0, 0.15, 0.15) - ba.timer(2, ba.Call(count_bomb, *args, count='1', color=color)) + bs.timer(2, bs.Call(count_bomb, *args, count='1', color=color)) return setting - bastd.actor.bomb.Bomb.__init__ = new_bomb_init( - bastd.actor.bomb.Bomb.__init__) + bascenev1lib.actor.bomb.Bomb.__init__ = new_bomb_init( + bascenev1lib.actor.bomb.Bomb.__init__) Spaz._pm2_spz_old = Spaz.__init__ @@ -295,7 +289,7 @@ def setting(*args, **kwargs): def _init_spaz_(self, *args, **kwargs): self._pm2_spz_old(*args, **kwargs) - self.bot_radius = ba.newnode('locator', + self.bot_radius = bs.newnode('locator', owner=self.node, # Remove itself when the bomb node dies. attrs={ @@ -309,7 +303,7 @@ def _init_spaz_(self, *args, **kwargs): self.bot_radius, 'position') - self.radius_visualizer_circle = ba.newnode( + self.radius_visualizer_circle = bs.newnode( 'locator', owner=self.node, # Remove itself when the bomb node dies. @@ -325,7 +319,7 @@ def _init_spaz_(self, *args, **kwargs): self.node.connectattr('position', self.radius_visualizer_circle, 'position') - self.curse_visualizer = ba.newnode('locator', + self.curse_visualizer = bs.newnode('locator', owner=self.node, # Remove itself when the bomb node dies. attrs={ @@ -339,7 +333,7 @@ def _init_spaz_(self, *args, **kwargs): self.node.connectattr('position', self.curse_visualizer, 'position') - self.curse_visualizer_circle = ba.newnode( + self.curse_visualizer_circle = bs.newnode( 'locator', owner=self.node, # Remove itself when the bomb node dies. @@ -357,7 +351,7 @@ def _init_spaz_(self, *args, **kwargs): self.curse_visualizer_circle, 'position') - self.curse_visualizer_fatal = ba.newnode('locator', + self.curse_visualizer_fatal = bs.newnode('locator', owner=self.node, # Remove itself when the bomb node dies. attrs={ @@ -374,17 +368,17 @@ def _init_spaz_(self, *args, **kwargs): 'position') def invincible() -> None: - for i in _ba.get_foreground_host_activity().players: + for i in bs.get_foreground_host_activity().players: try: if i.node: - if ba.app.config.get("invincible"): + if babase.app.config.get("invincible"): i.actor.node.invincible = True else: i.actor.node.invincible = False except: pass - ba.timer(1.001, ba.Call(invincible)) + bs.timer(1.001, bs.Call(invincible)) Spaz.__init__ = _init_spaz_ @@ -396,8 +390,8 @@ def new_cursed(self): if self.node.invincible: return self.super_curse() - if ba.app.config.get("bombRadiusVisual"): - ba.animate_array(self.curse_visualizer, 'size', 1, { + if babase.app.config.get("bombRadiusVisual"): + bs.animate_array(self.curse_visualizer, 'size', 1, { 0.0: [0.0], 0.2: [3 * 2.2], 0.5: [3 * 2.0], @@ -405,7 +399,7 @@ def new_cursed(self): 5.1: [0.0], }) - ba.animate( + bs.animate( self.curse_visualizer_circle, 'opacity', { 0: 0.0, 0.4: 0.1, @@ -413,7 +407,7 @@ def new_cursed(self): 5.1: 0.0, }) - ba.animate_array(self.curse_visualizer_fatal, 'size', 1, { + bs.animate_array(self.curse_visualizer_fatal, 'size', 1, { 0.0: [0.0], 0.2: [2.2], 0.5: [2.0], @@ -428,41 +422,41 @@ def new_cursed(self): def bot_handlemessage(self, msg: Any): - if isinstance(msg, ba.PowerupMessage): + if isinstance(msg, bs.PowerupMessage): if msg.poweruptype == 'health': - if ba.app.config.get("bombRadiusVisual"): + if babase.app.config.get("bombRadiusVisual"): if self._cursed: - ba.animate_array(self.curse_visualizer, 'size', 1, { + bs.animate_array(self.curse_visualizer, 'size', 1, { 0.0: [3 * 2.0], 0.2: [0.0], }) - ba.animate( + bs.animate( self.curse_visualizer_circle, 'opacity', { 0.0: 0.1, 0.2: 0.0, }) - ba.animate_array(self.curse_visualizer_fatal, 'size', 1, { + bs.animate_array(self.curse_visualizer_fatal, 'size', 1, { 0.0: [2.0], 0.2: [0.0], }) - ba.animate_array(self.bot_radius, 'size', 1, { + bs.animate_array(self.bot_radius, 'size', 1, { 0.0: [0], 0.25: [0] }) - ba.animate(self.bot_radius, 'opacity', { + bs.animate(self.bot_radius, 'opacity', { 0.0: 0.00, 0.25: 0.0 }) - ba.animate_array(self.radius_visualizer_circle, 'size', 1, { + bs.animate_array(self.radius_visualizer_circle, 'size', 1, { 0.0: [0], 0.25: [0] }) - ba.animate( + bs.animate( self.radius_visualizer_circle, 'opacity', { 0.0: 0.00, 0.25: 0.0 @@ -470,32 +464,32 @@ def bot_handlemessage(self, msg: Any): self.super_handlemessage(msg) - if isinstance(msg, ba.HitMessage): + if isinstance(msg, bs.HitMessage): if self.hitpoints <= 0: - ba.animate(self.bot_radius, 'opacity', { + bs.animate(self.bot_radius, 'opacity', { 0.0: 0.00 }) - ba.animate( + bs.animate( self.radius_visualizer_circle, 'opacity', { 0.0: 0.00 }) - elif ba.app.config.get('bombRadiusVisual'): + elif babase.app.config.get('bombRadiusVisual'): - ba.animate_array(self.bot_radius, 'size', 1, { + bs.animate_array(self.bot_radius, 'size', 1, { 0.0: [(self.hitpoints_max - self.hitpoints) * 0.0045], 0.25: [(self.hitpoints_max - self.hitpoints) * 0.0045] }) - ba.animate(self.bot_radius, 'opacity', { + bs.animate(self.bot_radius, 'opacity', { 0.0: 0.00, 0.25: 0.05 }) - ba.animate_array(self.radius_visualizer_circle, 'size', 1, { + bs.animate_array(self.radius_visualizer_circle, 'size', 1, { 0.0: [(self.hitpoints_max - self.hitpoints) * 0.0045], 0.25: [(self.hitpoints_max - self.hitpoints) * 0.0045] }) - ba.animate( + bs.animate( self.radius_visualizer_circle, 'opacity', { 0.0: 0.00, 0.25: 0.1 @@ -506,11 +500,11 @@ def bot_handlemessage(self, msg: Any): def count_bomb(*args, count, color): - text = ba.newnode('math', owner=args[0].node, + text = bs.newnode('math', owner=args[0].node, attrs={'input1': (0, 0.7, 0), 'operation': 'add'}) args[0].node.connectattr('position', text, 'input2') - args[0].spaztext = ba.newnode('text', + args[0].spaztext = bs.newnode('text', owner=args[0].node, attrs={ 'text': count, @@ -524,20 +518,17 @@ def count_bomb(*args, count, color): args[0].node.connectattr('position', args[0].spaztext, 'position') - ba.animate(args[0].spaztext, 'scale', + bs.animate(args[0].spaztext, 'scale', {0: 0, 0.3: 0.03, 0.5: 0.025, 0.8: 0.025, 1.0: 0.0}) def doTestButton(self): - if isinstance(_ba.get_foreground_host_session(), MainMenuSession): - ba.screenmessage('Join any map to start using it.', color=(.8, .8, .1)) + if isinstance(bs.get_foreground_host_session(), MainMenuSession): + bui.screenmessage('Join any map to start using it.', color=(.8, .8, .1)) return - if ba.app.config.get("disablePractice"): - ba.containerwidget(edit=self._root_widget, transition='out_left') - ba.Call(PracticeWindow()) - else: - ba.screenmessage('Only works on local games.', color=(.8, .8, .1)) + bui.containerwidget(edit=self._root_widget, transition='out_left') + bs.Call(PracticeWindow()) # --------------------------------------------------------------- @@ -546,64 +537,68 @@ def doTestButton(self): class NewBotSet(SpazBotSet): def __init__(self): + """Create a bot-set.""" + + # We spread our bots out over a few lists so we can update + # them in a staggered fashion. super().__init__() + def start_moving(self) -> None: + """Start processing bot AI updates so they start doing their thing.""" + self._bot_update_timer = bui.AppTimer( + 0.05, bs.WeakCall(self._update), repeat=True + ) + def _update(self) -> None: - try: - with ba.Context(_ba.get_foreground_host_activity()): - # Update one of our bot lists each time through. - # First off, remove no-longer-existing bots from the list. - try: - bot_list = self._bot_lists[self._bot_update_list] = ([ - b for b in self._bot_lists[self._bot_update_list] if b - ]) - except Exception: - bot_list = [] - ba.print_exception('Error updating bot list: ' + - str(self._bot_lists[ - self._bot_update_list])) - self._bot_update_list = (self._bot_update_list + - 1) % self._bot_list_count - # Update our list of player points for the bots to use. - player_pts = [] - for player in ba.getactivity().players: - assert isinstance(player, ba.Player) - try: - # TODO: could use abstracted player.position here so we - # don't have to assume their actor type, but we have no - # abstracted velocity as of yet. - if player.is_alive(): - assert isinstance(player.actor, Spaz) - assert player.actor.node - player_pts.append( - (ba.Vec3(player.actor.node.position), - ba.Vec3( - player.actor.node.velocity))) - except Exception: - ba.print_exception('Error on bot-set _update.') - - for bot in bot_list: - if not ba.app.config.get('stopBots'): - bot.set_player_points(player_pts) - bot.update_ai() - - ba.app.config["disablePractice"] = True - except: - ba.app.config["disablePractice"] = False + # Update one of our bot lists each time through. + # First off, remove no-longer-existing bots from the list. + try: + bot_list = self._bot_lists[self._bot_update_list] = ([ + b for b in self._bot_lists[self._bot_update_list] if b + ]) + except Exception: + bot_list = [] + babase.print_exception('Error updating bot list: ' + + str(self._bot_lists[ + self._bot_update_list])) + self._bot_update_list = (self._bot_update_list + + 1) % self._bot_list_count + + # Update our list of player points for the bots to use. + player_pts = [] + for player in bs.getactivity().players: + assert isinstance(player, bs.Player) + try: + # TODO: could use abstracted player.position here so we + # don't have to assume their actor type, but we have no + # abstracted velocity as of yet. + if player.is_alive(): + assert isinstance(player.actor, Spaz) + assert player.actor.node + player_pts.append( + (bs.Vec3(player.actor.node.position), + bs.Vec3( + player.actor.node.velocity))) + except Exception: + babase.print_exception('Error on bot-set _update.') + + for bot in bot_list: + if not babase.app.config.get('stopBots'): + bot.set_player_points(player_pts) + bot.update_ai() def clear(self) -> None: """Immediately clear out any bots in the set.""" - with ba.Context(_ba.get_foreground_host_activity()): - # Don't do this if the activity is shutting down or dead. - activity = ba.getactivity(doraise=False) - if activity is None or activity.expired: - return + # Don't do this if the activity is shutting down or dead. + activity = bs.getactivity(doraise=False) + if activity is None or activity.expired: + return - for i, bot_list in enumerate(self._bot_lists): - for bot in bot_list: - bot.handlemessage(ba.DieMessage(immediate=True)) - self._bot_lists[i] = [] + for i, bot_list in enumerate(self._bot_lists): + for bot in bot_list: + bot.handlemessage(bs.DieMessage(immediate=True)) + self._bot_lists[i] = [] def spawn_bot( self, @@ -612,22 +607,25 @@ def spawn_bot( spawn_time: float = 3.0, on_spawn_call: Callable[[SpazBot], Any] | None = None) -> None: """Spawn a bot from this set.""" - from bastd.actor import spawner - spawner.Spawner(pt=pos, - spawn_time=spawn_time, - send_spawn_message=False, - spawn_callback=ba.Call(self._spawn_bot, bot_type, pos, - on_spawn_call)) + + spawner.Spawner( + pt=pos, + spawn_time=spawn_time, + send_spawn_message=False, + spawn_callback=bs.Call( + self._spawn_bot, bot_type, pos, on_spawn_call + ), + ) self._spawning_count += 1 def _spawn_bot(self, bot_type: type[SpazBot], pos: Sequence[float], on_spawn_call: Callable[[SpazBot], Any] | None) -> None: spaz = bot_type().autoretain() - ba.playsound(ba.getsound('spawn'), position=pos) + bs.getsound('spawn').play(position=pos) assert spaz.node spaz.node.handlemessage('flash') spaz.node.is_area_of_interest = False - spaz.handlemessage(ba.StandMessage(pos, random.uniform(0, 360))) + spaz.handlemessage(bs.StandMessage(pos, random.uniform(0, 360))) self.add_bot(spaz) self._spawning_count -= 1 if on_spawn_call is not None: @@ -639,19 +637,18 @@ class DummyBotSet(NewBotSet): def _update(self) -> None: try: - with ba.Context(_ba.get_foreground_host_activity()): - # Update one of our bot lists each time through. - # First off, remove no-longer-existing bots from the list. - try: - bot_list = self._bot_lists[self._bot_update_list] = ([ - b for b in self._bot_lists[self._bot_update_list] if b - ]) - except Exception: - ba.print_exception('Error updating bot list: ' + + # Update one of our bot lists each time through. + # First off, remove no-longer-existing bots from the list. + try: + bot_list = self._bot_lists[self._bot_update_list] = ([ + b for b in self._bot_lists[self._bot_update_list] if b + ]) + except Exception: + babase.print_exception('Error updating bot list: ' + str(self._bot_lists[ self._bot_update_list])) - self._bot_update_list = (self._bot_update_list + - 1) % self._bot_list_count + self._bot_update_list = (self._bot_update_list + + 1) % self._bot_list_count except: pass @@ -662,16 +659,19 @@ class DummyBot(SpazBot): def __init__(self): super().__init__() - if ba.app.config.get('immortalDummy'): - ba.timer(0.2, self.immortal, + if babase.app.config.get('immortalDummy'): + bs.timer(0.2, self.immortal, repeat=True) def immortal(self): self.hitpoints = self.hitpoints_max = 10000 - ba.emitfx( - position=self.node.position, - count=20, - emit_type='fairydust') + try: + bs.emitfx( + position=self.node.position, + count=20, + emit_type='fairydust') + except: + pass class NewChargerBotPro(ChargerBotPro): @@ -691,18 +691,18 @@ def window(self) -> PracticeWindow: """The GatherWindow that this tab belongs to.""" window = self._window() if window is None: - raise ba.NotFoundError("PracticeTab's window no longer exists.") + raise bs.NotFoundError("PracticeTab's window no longer exists.") return window def on_activate( - self, - parent_widget: ba.Widget, - tab_button: ba.Widget, - region_width: float, - region_height: float, - scroll_widget: ba.Widget, - extra_x: float, - ) -> ba.Widget: + self, + parent_widget: bs.Widget, + tab_button: bs.Widget, + region_width: float, + region_height: float, + scroll_widget: bs.Widget, + extra_x: float, + ) -> bs.Widget: """Called when the tab becomes the active one. The tab should create and return a container widget covering the @@ -720,41 +720,52 @@ def restore_state(self) -> None: """Called when the parent window is restoring state.""" -def _check_value_change(setting: int, widget: ba.Widget, +def _check_value_change(setting: int, widget: bs.Widget, value: str) -> None: - ba.textwidget(edit=widget, - text=ba.Lstr(resource='onText') if value else ba.Lstr( - resource='offText')) + bui.textwidget(edit=widget, + text=bs.Lstr(resource='onText') if value else bs.Lstr( + resource='offText')) if setting == 0: if value: - ba.app.config["stopBots"] = True + babase.app.config["stopBots"] = True else: - ba.app.config["stopBots"] = False + babase.app.config["stopBots"] = False elif setting == 1: if value: - ba.app.config["immortalDummy"] = True + babase.app.config["immortalDummy"] = True else: - ba.app.config["immortalDummy"] = False + babase.app.config["immortalDummy"] = False class BotsPracticeTab(PracticeTab): """The about tab in the practice UI""" - def __init__(self, window: PracticeWindow, - bot1=DummyBotSet(), bot2=NewBotSet()) -> None: + def __init__(self, window: PracticeWindow + ) -> None: + super().__init__(window) + activity = bs.get_foreground_host_activity() + with activity.context: + try: + if not activity.bot1 or not activity.bot2: + activity.bot1 = DummyBotSet() + activity.bot2 = NewBotSet() + except: + activity.bot1 = DummyBotSet() + activity.bot2 = NewBotSet() bot_index, count, radius = self.load_settings() - self._container: ba.Widget | None = None + self._container: bs.Widget | None = None self.count = count self.radius = radius self.radius_array = (['Small', 'Medium', 'Big']) self.parent_widget = None - self.bot1 = bot1 - self.bot2 = bot2 - self.activity = _ba.get_foreground_host_activity() + self.bot1 = activity.bot1 + self.bot2 = activity.bot2 + self.activity = bs.get_foreground_host_activity() self.image_array = ( - ['bonesIcon', 'neoSpazIcon', 'kronkIcon', 'neoSpazIcon', 'kronkIcon', + ['bonesIcon', 'neoSpazIcon', 'kronkIcon', 'neoSpazIcon', + 'kronkIcon', 'zoeIcon', 'ninjaIcon', 'melIcon', 'jackIcon', 'bunnyIcon', 'neoSpazIcon', 'kronkIcon', 'zoeIcon', 'ninjaIcon', 'neoSpazIcon', 'kronkIcon', 'zoeIcon', 'ninjaIcon']) @@ -770,7 +781,8 @@ def __init__(self, window: PracticeWindow, self.config = (['stopBots', 'immortalDummy']) self.bot_array = ( - [DummyBot, BomberBotLite, BrawlerBotLite, SpazBot, BrawlerBot, TriggerBot, + [DummyBot, BomberBotLite, BrawlerBotLite, SpazBot, BrawlerBot, + TriggerBot, ChargerBot, StickyBot, ExplodeyBot, BouncyBot, BomberBotPro, BrawlerBotPro, TriggerBotPro, NewChargerBotPro, BomberBotProShielded, BrawlerBotProShielded, @@ -779,18 +791,18 @@ def __init__(self, window: PracticeWindow, self._icon_index = bot_index def on_activate( - self, - parent_widget: ba.Widget, - tab_button: ba.Widget, - region_width: float, - region_height: float, - scroll_widget: ba.Widget, - extra_x: float, - ) -> ba.Widget: + self, + parent_widget: bs.Widget, + tab_button: bs.Widget, + region_width: float, + region_height: float, + scroll_widget: bs.Widget, + extra_x: float, + ) -> bui.Widget: b_size_2 = 100 spacing_h = -50 - mask_texture = ba.gettexture('characterIconMask') + mask_texture = bui.gettexture('characterIconMask') spacing_v = 60 self.parent_widget = parent_widget @@ -806,26 +818,26 @@ def on_activate( self.container_h = 600 bots_height = self.container_h - 50 - self._subcontainer = ba.containerwidget( + self._subcontainer = bui.containerwidget( parent=scroll_widget, size=(self._sub_width, self.container_h), background=False, selection_loops_to_parent=True) - ba.textwidget(parent=self._subcontainer, - position=(self._sub_width * 0.5, - bots_height), - size=(0, 0), - color=(1.0, 1.0, 1.0), - scale=1.3, - h_align='center', - v_align='center', - text='Spawn Bot', - maxwidth=200) + bui.textwidget(parent=self._subcontainer, + position=(self._sub_width * 0.5, + bots_height), + size=(0, 0), + color=(1.0, 1.0, 1.0), + scale=1.3, + h_align='center', + v_align='center', + text='Spawn Bot', + maxwidth=200) tint1, tint2, color = self.check_color() - self._bot_button = bot = ba.buttonwidget( + self._bot_button = bot = bui.buttonwidget( parent=self._subcontainer, autoselect=True, position=(self._sub_width * 0.5 - b_size_2 * 0.5, @@ -834,14 +846,14 @@ def on_activate( size=(b_size_2, b_size_2), label='', color=color, - tint_texture=(ba.gettexture( + tint_texture=(bui.gettexture( self.image_array[self._icon_index] + 'ColorMask')), tint_color=tint1, tint2_color=tint2, - texture=ba.gettexture(self.image_array[self._icon_index]), + texture=bui.gettexture(self.image_array[self._icon_index]), mask_texture=mask_texture) - ba.textwidget( + bui.textwidget( parent=self._subcontainer, h_align='center', v_align='center', @@ -851,34 +863,34 @@ def on_activate( draw_controller=bot, text='Bot Type', scale=1.0, - color=ba.app.ui.title_color, + color=bui.app.ui_v1.title_color, maxwidth=130) - ba.textwidget(parent=self._subcontainer, - position=( - self._sub_width * 0.005, - bots_height - + spacing_h * 7), - size=(100, 30), - text='Count', - h_align='left', - color=(0.8, 0.8, 0.8), - v_align='center', - maxwidth=200) - self.count_text = txt = ba.textwidget(parent=self._subcontainer, - position=( - self._sub_width * 0.85 - spacing_v * 2, - bots_height - + spacing_h * 7), - size=(0, 28), - text=str(self.count), - editable=False, - color=(0.6, 1.0, 0.6), - maxwidth=150, - h_align='center', - v_align='center', - padding=2) - self.button_bot_left = btn1 = ba.buttonwidget( + bui.textwidget(parent=self._subcontainer, + position=( + self._sub_width * 0.005, + bots_height + + spacing_h * 7), + size=(100, 30), + text='Count', + h_align='left', + color=(0.8, 0.8, 0.8), + v_align='center', + maxwidth=200) + self.count_text = txt = bui.textwidget(parent=self._subcontainer, + position=( + self._sub_width * 0.85 - spacing_v * 2, + bots_height + + spacing_h * 7), + size=(0, 28), + text=str(self.count), + editable=False, + color=(0.6, 1.0, 0.6), + maxwidth=150, + h_align='center', + v_align='center', + padding=2) + self.button_bot_left = btn1 = bui.buttonwidget( parent=self._subcontainer, position=( self._sub_width * 0.85 - spacing_v - 14, @@ -889,7 +901,7 @@ def on_activate( autoselect=True, on_activate_call=self.decrease_count, repeat=True) - self.button_bot_right = btn2 = ba.buttonwidget( + self.button_bot_right = btn2 = bui.buttonwidget( parent=self._subcontainer, position=( self._sub_width * 0.85 - 14, @@ -901,33 +913,33 @@ def on_activate( on_activate_call=self.increase_count, repeat=True) - ba.textwidget(parent=self._subcontainer, - position=( - self._sub_width * 0.005, - bots_height - + spacing_h * 8), - size=(100, 30), - text='Spawn Radius', - h_align='left', - color=(0.8, 0.8, 0.8), - v_align='center', - maxwidth=200) - - self.radius_text = txt = ba.textwidget(parent=self._subcontainer, - position=( - self._sub_width * 0.85 - spacing_v * 2, - bots_height - + spacing_h * 8), - size=(0, 28), - text=self.radius_array[ - self.radius], - editable=False, - color=(0.6, 1.0, 0.6), - maxwidth=50, - h_align='center', - v_align='center', - padding=2) - self.button_bot_left = btn1 = ba.buttonwidget( + bui.textwidget(parent=self._subcontainer, + position=( + self._sub_width * 0.005, + bots_height + + spacing_h * 8), + size=(100, 30), + text='Spawn Radius', + h_align='left', + color=(0.8, 0.8, 0.8), + v_align='center', + maxwidth=200) + + self.radius_text = txt = bui.textwidget(parent=self._subcontainer, + position=( + self._sub_width * 0.85 - spacing_v * 2, + bots_height + + spacing_h * 8), + size=(0, 28), + text=self.radius_array[ + self.radius], + editable=False, + color=(0.6, 1.0, 0.6), + maxwidth=50, + h_align='center', + v_align='center', + padding=2) + self.button_bot_left = btn1 = bui.buttonwidget( parent=self._subcontainer, position=( self._sub_width * 0.85 - spacing_v - 14, @@ -938,7 +950,7 @@ def on_activate( autoselect=True, on_activate_call=self.decrease_radius, repeat=True) - self.button_bot_right = btn2 = ba.buttonwidget( + self.button_bot_right = btn2 = bui.buttonwidget( parent=self._subcontainer, position=( self._sub_width * 0.85 - 14, @@ -950,7 +962,7 @@ def on_activate( on_activate_call=self.increase_radius, repeat=True) - self.button = ba.buttonwidget( + self.button = bui.buttonwidget( parent=self._subcontainer, position=( self._sub_width * 0.25 - 40, @@ -962,7 +974,7 @@ def on_activate( label='Spawn', on_activate_call=self.do_spawn_bot) - self.button = ba.buttonwidget( + self.button = bui.buttonwidget( parent=self._subcontainer, position=( self._sub_width * 0.75 - 40, @@ -977,23 +989,23 @@ def on_activate( i = 0 for name in self.setting_name: - ba.textwidget(parent=self._subcontainer, - position=(self._sub_width * 0.005, - bots_height + spacing_h * (9 + i)), - size=(100, 30), - text=name, - h_align='left', - color=(0.8, 0.8, 0.8), - v_align='center', - maxwidth=200) - value = ba.app.config.get(self.config[i]) - txt2 = ba.textwidget( + bui.textwidget(parent=self._subcontainer, + position=(self._sub_width * 0.005, + bots_height + spacing_h * (9 + i)), + size=(100, 30), + text=name, + h_align='left', + color=(0.8, 0.8, 0.8), + v_align='center', + maxwidth=200) + value = babase.app.config.get(self.config[i]) + txt2 = bui.textwidget( parent=self._subcontainer, position=(self._sub_width * 0.8 - spacing_v / 2, bots_height + spacing_h * (9 + i)), size=(0, 28), - text=ba.Lstr(resource='onText') if value else ba.Lstr( + text=bs.Lstr(resource='onText') if value else bs.Lstr( resource='offText'), editable=False, color=(0.6, 1.0, 0.6), @@ -1001,18 +1013,18 @@ def on_activate( h_align='right', v_align='center', padding=2) - ba.checkboxwidget(parent=self._subcontainer, - text='', - position=(self._sub_width * 0.8 - 15, - bots_height + - spacing_h * (9 + i)), - size=(30, 30), - autoselect=False, - textcolor=(0.8, 0.8, 0.8), - value=value, - on_value_change_call=ba.Call( - _check_value_change, - i, txt2)) + bui.checkboxwidget(parent=self._subcontainer, + text='', + position=(self._sub_width * 0.8 - 15, + bots_height + + spacing_h * (9 + i)), + size=(30, 30), + autoselect=False, + textcolor=(0.8, 0.8, 0.8), + value=value, + on_value_change_call=bs.Call( + _check_value_change, + i, txt2)) i += 1 return self._subcontainer @@ -1026,45 +1038,46 @@ def increase_count(self): if self.count < 10: self.count += 1 - ba.textwidget(edit=self.count_text, - text=str(self.count)) + bui.textwidget(edit=self.count_text, + text=str(self.count)) self.save_settings() def decrease_count(self): if self.count > 1: self.count -= 1 - ba.textwidget(edit=self.count_text, - text=str(self.count)) + bui.textwidget(edit=self.count_text, + text=str(self.count)) self.save_settings() def increase_radius(self): if self.radius < 2: self.radius += 1 - ba.textwidget(edit=self.radius_text, - text=self.radius_array[self.radius]) + bui.textwidget(edit=self.radius_text, + text=self.radius_array[self.radius]) self.save_settings() def decrease_radius(self): if self.radius > 0: self.radius -= 1 - ba.textwidget(edit=self.radius_text, - text=self.radius_array[self.radius]) + bui.textwidget(edit=self.radius_text, + text=self.radius_array[self.radius]) self.save_settings() def clear_bot(self): - ba.screenmessage('Cleared', - clients=[-1], transient=True, color=(1, 0.1, 0.1)) - self.bot1.clear() - self.bot2.clear() + bs.screenmessage('Cleared', color=(1, 0.1, 0.1)) + activity = bs.get_foreground_host_activity() + with activity.context: + self.bot1.clear() + self.bot2.clear() def do_spawn_bot(self, clid: int = -1) -> None: - with ba.Context(self.activity): - ba.screenmessage('Spawned', - clients=[-1], transient=True, color=(0.2, 1, 0.2)) - for i in _ba.get_foreground_host_activity().players: + bs.screenmessage('Spawned', color=(0.2, 1, 0.2)) + activity = bs.get_foreground_host_activity() + with activity.context: + for i in bs.get_foreground_host_activity().players: if i.sessionplayer.inputdevice.client_id == clid: if i.node: bot_type = self._icon_index @@ -1100,10 +1113,10 @@ def _update_character(self, change: int = 0) -> None: if self._bot_button: tint1, tint2, color = self.check_color() - ba.buttonwidget( + bui.buttonwidget( edit=self._bot_button, - texture=ba.gettexture(self.image_array[self._icon_index]), - tint_texture=(ba.gettexture( + texture=bui.gettexture(self.image_array[self._icon_index]), + tint_texture=(bui.gettexture( self.image_array[self._icon_index] + 'ColorMask')), color=color, tint_color=tint1, @@ -1112,33 +1125,29 @@ def _update_character(self, change: int = 0) -> None: def load_settings(self): try: - if ba.app.config.get("botsSpawnSetting") is None: - ba.app.config["botsSpawnSetting"] = (0, 1, 0) - bot_index, count, radius = ba.app.config.get( + if babase.app.config.get("botsSpawnSetting") is None: + babase.app.config["botsSpawnSetting"] = (0, 1, 0) + bot_index, count, radius = babase.app.config.get( "botsSpawnSetting") else: - bot_index, count, radius = ba.app.config.get( + bot_index, count, radius = babase.app.config.get( "botsSpawnSetting") - print(ba.app.config.get("botsSpawnSetting")) except: - ba.app.config["botsSpawnSetting"] = (0, 1, 0) - bot_index, count, radius = ba.app.config.get("botsSpawnSetting") + babase.app.config["botsSpawnSetting"] = (0, 1, 0) + bot_index, count, radius = babase.app.config.get("botsSpawnSetting") values = bot_index, count, radius - print("settings loaded") return values def save_settings(self): - ba.app.config["botsSpawnSetting"] = (self._icon_index, self.count, - self.radius) - print(ba.app.config.get("botsSpawnSetting")) - ba.app.config.commit() - print("settings saved") + babase.app.config["botsSpawnSetting"] = (self._icon_index, self.count, + self.radius) + babase.app.config.commit() def check_color(self): if self.bot_array_name[self._icon_index] in ( - 'Pro Bomber', 'Pro Brawler', - 'Pro Trigger', 'Pro Charger', - 'S.Pro Bomber', 'S.Pro Brawler', + 'Pro Bomber', 'Pro Brawler', + 'Pro Trigger', 'Pro Charger', + 'S.Pro Bomber', 'S.Pro Brawler', 'S.Pro Trigger', 'S.Pro Charger'): tint1 = (1.0, 0.2, 0.1) tint2 = (0.6, 0.1, 0.05) @@ -1154,7 +1163,7 @@ def check_color(self): tint2 = (0.1, 0.3, 0.1) if self.bot_array_name[self._icon_index] in ( - 'S.Pro Bomber', 'S.Pro Brawler', + 'S.Pro Bomber', 'S.Pro Brawler', 'S.Pro Trigger', 'S.Pro Charger'): color = (1.3, 1.2, 3.0) else: @@ -1169,10 +1178,10 @@ class PowerUpPracticeTab(PracticeTab): def __init__(self, window: PracticeWindow) -> None: super().__init__(window) - self._container: ba.Widget | None = None + self._container: bs.Widget | None = None self.count = 1 self.parent_widget = None - self.activity = _ba.get_foreground_host_activity() + self.activity = bs.get_foreground_host_activity() self.power_list = (['Bomb', 'Curse', 'Health', 'IceBombs', 'ImpactBombs', 'LandMines', 'Punch', @@ -1193,14 +1202,14 @@ def __init__(self, window: PracticeWindow) -> None: self.config = (['bombCountdown', 'bombRadiusVisual']) def on_activate( - self, - parent_widget: ba.Widget, - tab_button: ba.Widget, - region_width: float, - region_height: float, - scroll_widget: ba.Widget, - extra_x: float, - ) -> ba.Widget: + self, + parent_widget: bs.Widget, + tab_button: bs.Widget, + region_width: float, + region_height: float, + scroll_widget: bs.Widget, + extra_x: float, + ) -> bs.Widget: b_size_2 = 100 spacing_h = -50 @@ -1219,24 +1228,24 @@ def on_activate( self.container_h = 450 power_height = self.container_h - 50 - self._subcontainer = ba.containerwidget( + self._subcontainer = bui.containerwidget( parent=scroll_widget, size=(self._sub_width, self.container_h), background=False, selection_loops_to_parent=True) - ba.textwidget(parent=self._subcontainer, - position=(self._sub_width * 0.5, - power_height), - size=(0, 0), - color=(1.0, 1.0, 1.0), - scale=1.3, - h_align='center', - v_align='center', - text='Spawn Power Up', - maxwidth=200) - - self._power_button = bot = ba.buttonwidget( + bui.textwidget(parent=self._subcontainer, + position=(self._sub_width * 0.5, + power_height), + size=(0, 0), + color=(1.0, 1.0, 1.0), + scale=1.3, + h_align='center', + v_align='center', + text='Spawn Power Up', + maxwidth=200) + + self._power_button = bot = bui.buttonwidget( parent=self._subcontainer, autoselect=True, position=(self._sub_width * 0.5 - b_size_2 * 0.5, @@ -1245,11 +1254,11 @@ def on_activate( size=(b_size_2, b_size_2), label='', color=(1, 1, 1), - texture=ba.gettexture('powerup' + - self.power_list[ - self._icon_index])) + texture=bui.gettexture('powerup' + + self.power_list[ + self._icon_index])) - ba.textwidget( + bui.textwidget( parent=self._subcontainer, h_align='center', v_align='center', @@ -1259,10 +1268,10 @@ def on_activate( draw_controller=bot, text='Power Up Type', scale=1.0, - color=ba.app.ui.title_color, + color=bui.app.ui_v1.title_color, maxwidth=300) - self.button = ba.buttonwidget( + self.button = bui.buttonwidget( parent=self._subcontainer, position=( self._sub_width * 0.25 - 40, @@ -1274,7 +1283,7 @@ def on_activate( label='Spawn', on_activate_call=self.get_powerup) - self.button = ba.buttonwidget( + self.button = bui.buttonwidget( parent=self._subcontainer, position=( self._sub_width * 0.75 - 40, @@ -1289,23 +1298,23 @@ def on_activate( i = 0 for name in self.setting_name: - ba.textwidget(parent=self._subcontainer, - position=(self._sub_width * 0.005, - power_height + spacing_h * (7 + i)), - size=(100, 30), - text=name, - h_align='left', - color=(0.8, 0.8, 0.8), - v_align='center', - maxwidth=200) - value = ba.app.config.get(self.config[i]) - txt2 = ba.textwidget( + bui.textwidget(parent=self._subcontainer, + position=(self._sub_width * 0.005, + power_height + spacing_h * (7 + i)), + size=(100, 30), + text=name, + h_align='left', + color=(0.8, 0.8, 0.8), + v_align='center', + maxwidth=200) + value = babase.app.config.get(self.config[i]) + txt2 = bui.textwidget( parent=self._subcontainer, position=(self._sub_width * 0.8 - spacing_v / 2, power_height + spacing_h * (7 + i)), size=(0, 28), - text=ba.Lstr(resource='onText') if value else ba.Lstr( + text=bs.Lstr(resource='onText') if value else bs.Lstr( resource='offText'), editable=False, color=(0.6, 1.0, 0.6), @@ -1313,27 +1322,27 @@ def on_activate( h_align='right', v_align='center', padding=2) - ba.checkboxwidget(parent=self._subcontainer, - text='', - position=(self._sub_width * 0.8 - 15, - power_height + - spacing_h * (7 + i)), - size=(30, 30), - autoselect=False, - textcolor=(0.8, 0.8, 0.8), - value=value, - on_value_change_call=ba.Call( - self._check_value_change, - i, txt2)) + bui.checkboxwidget(parent=self._subcontainer, + text='', + position=(self._sub_width * 0.8 - 15, + power_height + + spacing_h * (7 + i)), + size=(30, 30), + autoselect=False, + textcolor=(0.8, 0.8, 0.8), + value=value, + on_value_change_call=bs.Call( + self._check_value_change, + i, txt2)) i += 1 return self._subcontainer def debuff(self): - ba.screenmessage('Debuffed', - clients=[-1], transient=True, color=(1, 0.1, 0.1)) - with ba.Context(_ba.get_foreground_host_activity()): - for i in _ba.get_foreground_host_activity().players: + bs.screenmessage('Debuffed', color=(1, 0.1, 0.1)) + activity = bs.get_foreground_host_activity() + with activity.context: + for i in activity.players: Spaz._gloves_wear_off(i.actor) Spaz._multi_bomb_wear_off(i.actor) Spaz._bomb_wear_off(i.actor) @@ -1347,10 +1356,10 @@ def debuff(self): i.actor.shield_hitpoints = 1 def get_powerup(self, clid: int = -1) -> None: - ba.screenmessage('Spawned', - clients=[-1], transient=True, color=(0.2, 1, 0.2)) - with ba.Context(_ba.get_foreground_host_activity()): - for i in _ba.get_foreground_host_activity().players: + bs.screenmessage('Spawned', color=(0.2, 1, 0.2)) + activity = bs.get_foreground_host_activity() + with activity.context: + for i in activity.players: if i.sessionplayer.inputdevice.client_id == clid: if i.node: x = (random.choice([-7, 7]) / 10) @@ -1379,52 +1388,49 @@ def on_power_picker_pick(self, power: str) -> None: def _update_power(self, change: int = 0) -> None: if self._power_button: - ba.buttonwidget( + bui.buttonwidget( edit=self._power_button, - texture=(ba.gettexture('powerup' + - self.power_list[ - self._icon_index]))) + texture=(bui.gettexture('powerup' + + self.power_list[ + self._icon_index]))) self.save_settings() - def _check_value_change(self, setting: int, widget: ba.Widget, + def _check_value_change(self, setting: int, widget: bs.Widget, value: str) -> None: - ba.textwidget(edit=widget, - text=ba.Lstr(resource='onText') if value else ba.Lstr( - resource='offText')) + bui.textwidget(edit=widget, + text=bs.Lstr(resource='onText') if value else bs.Lstr( + resource='offText')) - with ba.Context(self.activity): + activity = bs.get_foreground_host_activity() + with activity.context: if setting == 0: if value: - ba.app.config["bombCountdown"] = True + babase.app.config["bombCountdown"] = True else: - ba.app.config["bombCountdown"] = False + babase.app.config["bombCountdown"] = False elif setting == 1: if value: - ba.app.config["bombRadiusVisual"] = True + babase.app.config["bombRadiusVisual"] = True else: - ba.app.config["bombRadiusVisual"] = False + babase.app.config["bombRadiusVisual"] = False def load_settings(self): try: - if ba.app.config.get("powerSpawnSetting") is None: - ba.app.config["powerSpawnSetting"] = 0 - power_index = ba.app.config.get("powerSpawnSetting") + if babase.app.config.get("powerSpawnSetting") is None: + babase.app.config["powerSpawnSetting"] = 0 + power_index = babase.app.config.get("powerSpawnSetting") else: - power_index = ba.app.config.get( + power_index = babase.app.config.get( "powerSpawnSetting") - print(ba.app.config.get("powerSpawnSetting")) except: - ba.app.config["powerSpawnSetting"] = 0 - power_index = ba.app.config.get("powerSpawnSetting") + babase.app.config["powerSpawnSetting"] = 0 + power_index = babase.app.config.get("powerSpawnSetting") values = power_index - print("power settings loaded") return values def save_settings(self): - ba.app.config["powerSpawnSetting"] = self._icon_index - print(ba.app.config.get("powerSpawnSetting")) - ba.app.config.commit() - print("power settings saved") + babase.app.config["powerSpawnSetting"] = self._icon_index + babase.app.config.commit() class OthersPracticeTab(PracticeTab): @@ -1432,22 +1438,22 @@ class OthersPracticeTab(PracticeTab): def __init__(self, window: PracticeWindow) -> None: super().__init__(window) - self._container: ba.Widget | None = None + self._container: bs.Widget | None = None self.count = 1 self.parent_widget = None - self.activity = _ba.get_foreground_host_activity() + self.activity = bs.get_foreground_host_activity() self.setting_name = (['Pause On Window', 'Invincible', 'Epic Mode']) self.config = (['pause', 'invincible']) def on_activate( - self, - parent_widget: ba.Widget, - tab_button: ba.Widget, - region_width: float, - region_height: float, - scroll_widget: ba.Widget, - extra_x: float, - ) -> ba.Widget: + self, + parent_widget: bs.Widget, + tab_button: bs.Widget, + region_width: float, + region_height: float, + scroll_widget: bs.Widget, + extra_x: float, + ) -> bs.Widget: spacing_v = 60 spacing_h = -50 @@ -1463,46 +1469,46 @@ def on_activate( self.container_h = 300 other_height = self.container_h - 50 - self._subcontainer = ba.containerwidget( + self._subcontainer = bui.containerwidget( parent=scroll_widget, size=(self._sub_width, self.container_h), background=False, selection_loops_to_parent=True) - ba.textwidget(parent=self._subcontainer, - position=(self._sub_width * 0.5, - other_height), - size=(0, 0), - color=(1.0, 1.0, 1.0), - scale=1.3, - h_align='center', - v_align='center', - text='Others', - maxwidth=200) + bui.textwidget(parent=self._subcontainer, + position=(self._sub_width * 0.5, + other_height), + size=(0, 0), + color=(1.0, 1.0, 1.0), + scale=1.3, + h_align='center', + v_align='center', + text='Others', + maxwidth=200) i = 0 for name in self.setting_name: - ba.textwidget(parent=self._subcontainer, - position=(self._sub_width * 0.005, - other_height + spacing_h * (2 + i)), - size=(100, 30), - text=name, - h_align='left', - color=(0.8, 0.8, 0.8), - v_align='center', - maxwidth=200) + bui.textwidget(parent=self._subcontainer, + position=(self._sub_width * 0.005, + other_height + spacing_h * (2 + i)), + size=(100, 30), + text=name, + h_align='left', + color=(0.8, 0.8, 0.8), + v_align='center', + maxwidth=200) if name == 'Epic Mode': - activity = _ba.get_foreground_host_activity() + activity = bs.get_foreground_host_activity() value = activity.globalsnode.slow_motion else: - value = ba.app.config.get(self.config[i]) - txt2 = ba.textwidget( + value = babase.app.config.get(self.config[i]) + txt2 = bui.textwidget( parent=self._subcontainer, position=(self._sub_width * 0.8 - spacing_v / 2, other_height + spacing_h * (2 + i)), size=(0, 28), - text=ba.Lstr(resource='onText') if value else ba.Lstr( + text=bs.Lstr(resource='onText') if value else bs.Lstr( resource='offText'), editable=False, color=(0.6, 1.0, 0.6), @@ -1510,59 +1516,60 @@ def on_activate( h_align='right', v_align='center', padding=2) - ba.checkboxwidget(parent=self._subcontainer, - text='', - position=(self._sub_width * 0.8 - 15, - other_height + - spacing_h * (2 + i)), - size=(30, 30), - autoselect=False, - textcolor=(0.8, 0.8, 0.8), - value=value, - on_value_change_call=ba.Call( - self._check_value_change, - i, txt2)) + bui.checkboxwidget(parent=self._subcontainer, + text='', + position=(self._sub_width * 0.8 - 15, + other_height + + spacing_h * (2 + i)), + size=(30, 30), + autoselect=False, + textcolor=(0.8, 0.8, 0.8), + value=value, + on_value_change_call=bs.Call( + self._check_value_change, + i, txt2)) i += 1 return self._subcontainer - def _check_value_change(self, setting: int, widget: ba.Widget, + def _check_value_change(self, setting: int, widget: bs.Widget, value: str) -> None: - ba.textwidget(edit=widget, - text=ba.Lstr(resource='onText') if value else ba.Lstr( - resource='offText')) + bui.textwidget(edit=widget, + text=bs.Lstr(resource='onText') if value else bs.Lstr( + resource='offText')) - with ba.Context(self.activity): + activity = bs.get_foreground_host_activity() + with activity.context: if setting == 0: if value: - ba.app.config["pause"] = True + babase.app.config["pause"] = True self.activity.globalsnode.paused = True else: - ba.app.config["pause"] = False + babase.app.config["pause"] = False self.activity.globalsnode.paused = False elif setting == 1: if value: - ba.app.config["invincible"] = True + babase.app.config["invincible"] = True else: - ba.app.config["invincible"] = False - for i in _ba.get_foreground_host_activity().players: + babase.app.config["invincible"] = False + for i in bs.get_foreground_host_activity().players: try: if i.node: - if ba.app.config.get("invincible"): + if babase.app.config.get("invincible"): i.actor.node.invincible = True else: i.actor.node.invincible = False except: pass elif setting == 2: - activity = _ba.get_foreground_host_activity() + activity = bs.get_foreground_host_activity() if value: activity.globalsnode.slow_motion = True else: activity.globalsnode.slow_motion = False -class PracticeWindow(ba.Window): +class PracticeWindow(bui.Window): class TabID(Enum): """Our available tab types.""" @@ -1571,23 +1578,23 @@ class TabID(Enum): OTHERS = 'others' def __del__(self): - _ba.set_party_icon_always_visible(True) + bui.set_party_icon_always_visible(True) self.activity.globalsnode.paused = False def __init__(self, transition: Optional[str] = 'in_right'): - self.activity = _ba.get_foreground_host_activity() - _ba.set_party_icon_always_visible(False) - if ba.app.config.get("pause"): + self.activity = bs.get_foreground_host_activity() + bui.set_party_icon_always_visible(False) + if babase.app.config.get("pause"): self.activity.globalsnode.paused = True - uiscale = ba.app.ui.uiscale + uiscale = bui.app.ui_v1.uiscale self.pick = 0 self._width = 500 - self._height = (578 if uiscale is ba.UIScale.SMALL else - 670 if uiscale is ba.UIScale.MEDIUM else 800) - extra_x = 100 if uiscale is ba.UIScale.SMALL else 0 + self._height = (578 if uiscale is babase.UIScale.SMALL else + 670 if uiscale is babase.UIScale.MEDIUM else 800) + extra_x = 100 if uiscale is babase.UIScale.SMALL else 0 self.extra_x = extra_x self._transitioning_out = False @@ -1601,13 +1608,13 @@ def __init__(self, v = self._height - 115.0 v -= spacing_v * 3.0 - super().__init__(root_widget=ba.containerwidget( + super().__init__(root_widget=bui.containerwidget( size=(self._width, self._height), transition=transition, - scale=(1.3 if uiscale is ba.UIScale.SMALL else - 0.97 if uiscale is ba.UIScale.MEDIUM else 0.8), - stack_offset=(0, -10) if uiscale is ba.UIScale.SMALL else ( - 240, 0) if uiscale is ba.UIScale.MEDIUM else (330, 20))) + scale=(1.3 if uiscale is babase.UIScale.SMALL else + 0.97 if uiscale is babase.UIScale.MEDIUM else 0.8), + stack_offset=(0, -10) if uiscale is babase.UIScale.SMALL else ( + 240, 0) if uiscale is babase.UIScale.MEDIUM else (330, 20))) self._sub_height = 200 @@ -1616,29 +1623,29 @@ def __init__(self, self._scroll_position = ((self._width - self._scroll_width) * 0.5, (self._height - self._scroll_height) * 0.5) - self._scrollwidget = ba.scrollwidget(parent=self._root_widget, - size=(self._scroll_width, - self._scroll_height), - color=(0.55, 0.55, 0.55), - highlight=False, - position=self._scroll_position) + self._scrollwidget = bui.scrollwidget(parent=self._root_widget, + size=(self._scroll_width, + self._scroll_height), + color=(0.55, 0.55, 0.55), + highlight=False, + position=self._scroll_position) - ba.containerwidget(edit=self._scrollwidget, - claims_left_right=True) + bui.containerwidget(edit=self._scrollwidget, + claims_left_right=True) # --------------------------------------------------------- - x_offs = 100 if uiscale is ba.UIScale.SMALL else 0 + x_offs = 100 if uiscale is babase.UIScale.SMALL else 0 self._current_tab: PracticeWindow.TabID | None = None - extra_top = 20 if uiscale is ba.UIScale.SMALL else 0 + extra_top = 20 if uiscale is babase.UIScale.SMALL else 0 self._r = 'gatherWindow' tabdefs: list[tuple[PracticeWindow.TabID, str]] = [ (self.TabID.BOTS, 'Bots') ] - if ba_internal.get_v1_account_misc_read_val( - 'enablePublicParties', True + if bui.app.plus.get_v1_account_misc_read_val( + 'enablePublicParties', True ): tabdefs.append( ( @@ -1649,9 +1656,9 @@ def __init__(self, (self.TabID.OTHERS, 'Others') ) - condensed = uiscale is not ba.UIScale.LARGE + condensed = uiscale is not babase.UIScale.LARGE t_offs_y = ( - 0 if not condensed else 25 if uiscale is ba.UIScale.MEDIUM else 17 + 0 if not condensed else 25 if uiscale is babase.UIScale.MEDIUM else 17 ) tab_buffer_h = (320 if condensed else 250) + 2 * x_offs @@ -1668,7 +1675,7 @@ def __init__(self, self._width * 0.5 - self._sub_width * 0.5, self._height * 0.79), size=(self._sub_width, 50), - on_select_call=ba.WeakCall(self._set_tab), + on_select_call=bui.WeakCall(self._set_tab), ) # Now instantiate handlers for these tabs. @@ -1683,43 +1690,43 @@ def __init__(self, if tabtype is not None: self._tabs[tab_id] = tabtype(self) - if ba.app.ui.use_toolbars: - ba.widget( + if bui.app.ui_v1.use_toolbars: + bui.widget( edit=self._tab_row.tabs[tabdefs[-1][0]].button, - right_widget=ba_internal.get_special_widget('party_button'), + right_widget=babase.get_special_widget('party_button'), ) - if uiscale is ba.UIScale.SMALL: - ba.widget( + if uiscale is babase.UIScale.SMALL: + bui.widget( edit=self._tab_row.tabs[tabdefs[0][0]].button, - left_widget=ba_internal.get_special_widget('back_button'), + left_widget=babase.get_special_widget('back_button'), ) # ----------------------------------------------------------- - self._back_button = btn = ba.buttonwidget( + self.back_button = btn = bui.buttonwidget( parent=self._root_widget, autoselect=True, position=(self._width * 0.15 - 30, self._height * 0.95 - 30), size=(60, 60), scale=1.1, - label=ba.charstr(ba.SpecialChar.BACK), + label=bui.charstr(bui.SpecialChar.BACK), button_type='backSmall', on_activate_call=self.close) - ba.containerwidget(edit=self._root_widget, cancel_button=btn) - - ba.textwidget(parent=self._root_widget, - position=(self._width * 0.5, - self._height * 0.95), - size=(0, 0), - color=ba.app.ui.title_color, - scale=1.5, - h_align='center', - v_align='center', - text='Practice Tools', - maxwidth=400) - - self.info_button = ba.buttonwidget( + bui.containerwidget(edit=self._root_widget, cancel_button=btn) + + bui.textwidget(parent=self._root_widget, + position=(self._width * 0.5, + self._height * 0.95), + size=(0, 0), + color=bui.app.ui_v1.title_color, + scale=1.5, + h_align='center', + v_align='center', + text='Practice Tools', + maxwidth=400) + + self.info_button = bui.buttonwidget( parent=self._root_widget, autoselect=True, position=(self._width * 0.8 - 30, @@ -1728,16 +1735,16 @@ def __init__(self, size=(60, 60), label='') - ba.imagewidget( + bui.imagewidget( parent=self._root_widget, position=(self._width * 0.8 - 25, self._height * 0.15 - 25), size=(50, 50), draw_controller=self.info_button, - texture=ba.gettexture('achievementEmpty'), + texture=bui.gettexture('achievementEmpty'), color=(1.0, 1.0, 1.0)) - self._tab_container: ba.Widget | None = None + self._tab_container: bui.Widget | None = None self._restore_state() @@ -1748,12 +1755,12 @@ def _info_window(self): parent=self._root_widget) def _button(self) -> None: - ba.buttonwidget(edit=None, - color=(0.2, 0.4, 0.8)) + bui.buttonwidget(edit=None, + color=(0.2, 0.4, 0.8)) def close(self) -> None: """Close the window.""" - ba.containerwidget(edit=self._root_widget, transition='out_right') + bui.containerwidget(edit=self._root_widget, transition='out_right') def _set_tab(self, tab_id: TabID) -> None: if self._current_tab is tab_id: @@ -1762,7 +1769,7 @@ def _set_tab(self, tab_id: TabID) -> None: self._current_tab = tab_id # We wanna preserve our current tab between runs. - cfg = ba.app.config + cfg = babase.app.config cfg['Practice Tab'] = tab_id.value cfg.commit() @@ -1797,12 +1804,12 @@ def _restore_state(self) -> None: for tab in self._tabs.values(): tab.restore_state() - sel: ba.Widget | None - winstate = ba.app.ui.window_states.get(type(self), {}) + sel: bui.Widget | None + winstate = bui.app.ui_v1.window_states.get(type(self), {}) sel_name = winstate.get('sel_name', None) assert isinstance(sel_name, (str, type(None))) current_tab = self.TabID.BOTS - gather_tab_val = ba.app.config.get('Practice Tab') + gather_tab_val = babase.app.config.get('Practice Tab') try: stored_tab = enum_by_value(self.TabID, gather_tab_val) if stored_tab in self._tab_row.tabs: @@ -1810,8 +1817,8 @@ def _restore_state(self) -> None: except ValueError: pass self._set_tab(current_tab) - if sel_name == 'Back': - sel = self._back_button + if sel_name == 'back': + sel = self.back_button elif sel_name == 'TabContainer': sel = self._tab_container elif isinstance(sel_name, str) and sel_name.startswith('Tab:'): @@ -1824,38 +1831,38 @@ def _restore_state(self) -> None: sel = self._tab_row.tabs[sel_tab_id].button else: sel = self._tab_row.tabs[current_tab].button - ba.containerwidget(edit=self._root_widget, selected_child=sel) + bui.containerwidget(edit=self._root_widget, selected_child=sel) except Exception: - ba.print_exception('Error restoring gather-win state.') + babase.print_exception('Error restoring gather-win state.') -org_begin = ba._activity.Activity.on_begin +org_begin = bs._activity.Activity.on_begin def new_begin(self): """Runs when game is began.""" org_begin(self) - _ba.set_party_icon_always_visible(True) + bui.set_party_icon_always_visible(True) -ba._activity.Activity.on_begin = new_begin +bs._activity.Activity.on_begin = new_begin class BotPicker(popup.PopupWindow): """Popup window for selecting bots to spwan.""" def __init__(self, - parent: ba.Widget, + parent: bui.Widget, position: tuple[float, float] = (0.0, 0.0), delegate: Any = None, scale: float | None = None, offset: tuple[float, float] = (0.0, 0.0), selected_character: str | None = None): del parent # unused here - uiscale = ba.app.ui.uiscale + uiscale = bui.app.ui_v1.uiscale if scale is None: - scale = (1.85 if uiscale is ba.UIScale.SMALL else - 1.65 if uiscale is ba.UIScale.MEDIUM else 1.23) + scale = (1.85 if uiscale is babase.UIScale.SMALL else + 1.65 if uiscale is babase.UIScale.MEDIUM else 1.23) self._delegate = delegate self._transitioning_out = False @@ -1873,7 +1880,7 @@ def __init__(self, self._width = (10 + columns * (button_width + 2 * button_buffer_h) * (1.0 / 0.95) * (1.0 / 0.8)) self._height = self._width * (0.8 - if uiscale is ba.UIScale.SMALL else 1.06) + if uiscale is babase.UIScale.SMALL else 1.06) self._scroll_width = self._width * 0.8 self._scroll_height = self._height * 0.8 @@ -1891,24 +1898,24 @@ def __init__(self, focus_size=(self._scroll_width, self._scroll_height)) - self._scrollwidget = ba.scrollwidget(parent=self.root_widget, - size=(self._scroll_width, - self._scroll_height), - color=(0.55, 0.55, 0.55), - highlight=False, - position=self._scroll_position) + self._scrollwidget = bui.scrollwidget(parent=self.root_widget, + size=(self._scroll_width, + self._scroll_height), + color=(0.55, 0.55, 0.55), + highlight=False, + position=self._scroll_position) - ba.containerwidget(edit=self._scrollwidget, claims_left_right=True) + bui.containerwidget(edit=self._scrollwidget, claims_left_right=True) self._sub_width = self._scroll_width * 0.95 self._sub_height = 5 + rows * (button_height + 2 * button_buffer_v) + 100 - self._subcontainer = ba.containerwidget(parent=self._scrollwidget, - size=(self._sub_width, - self._sub_height), - background=False) + self._subcontainer = bui.containerwidget(parent=self._scrollwidget, + size=(self._sub_width, + self._sub_height), + background=False) - mask_texture = ba.gettexture('characterIconMask') + mask_texture = bui.gettexture('characterIconMask') bot_list = (['bones', 'neoSpaz', 'kronk', 'neoSpaz', 'kronk', 'zoe', 'ninja', 'mel', 'jack', 'bunny', @@ -1916,11 +1923,13 @@ def __init__(self, 'ninja', 'neoSpaz', 'kronk', 'zoe', 'ninja']) - bot_list_type = (['Dummy', 'Bomber Lite', 'Brawler Lite', 'Bomber', 'Brawler', 'Trigger', - 'Charger', 'Sticky', 'Explodey', 'Bouncy', - 'Pro Bomber', 'Pro Brawler', 'Pro Trigger', - 'Pro Charger', 'S.Pro Bomber', 'S.Pro Brawler', - 'S.Pro Trigger', 'S.Pro Charger']) + bot_list_type = ( + ['Dummy', 'Bomber Lite', 'Brawler Lite', 'Bomber', 'Brawler', + 'Trigger', + 'Charger', 'Sticky', 'Explodey', 'Bouncy', + 'Pro Bomber', 'Pro Brawler', 'Pro Trigger', + 'Pro Charger', 'S.Pro Bomber', 'S.Pro Brawler', + 'S.Pro Trigger', 'S.Pro Charger']) index = 0 for y in range(rows): @@ -1951,37 +1960,37 @@ def __init__(self, pos = (x * (button_width + 2 * button_buffer_h) + button_buffer_h, self._sub_height - (y + 1) * (button_height + 2 * button_buffer_v) + 12) - btn = ba.buttonwidget( + btn = bui.buttonwidget( parent=self._subcontainer, button_type='square', position=(pos[0], pos[1]), size=(button_width, button_height), autoselect=True, - texture=ba.gettexture(bot_list[index] + 'Icon'), - tint_texture=ba.gettexture( + texture=bui.gettexture(bot_list[index] + 'Icon'), + tint_texture=bui.gettexture( bot_list[index] + 'IconColorMask'), mask_texture=mask_texture, label='', color=color, tint_color=tint1, tint2_color=tint2, - on_activate_call=ba.Call(self._select_character, - character=bot_list_type[index])) - ba.widget(edit=btn, show_buffer_top=60, show_buffer_bottom=60) + on_activate_call=bui.Call(self._select_character, + character=bot_list_type[index])) + bui.widget(edit=btn, show_buffer_top=60, show_buffer_bottom=60) name = bot_list_type[index] - ba.textwidget(parent=self._subcontainer, - text=name, - position=(pos[0] + button_width * 0.5, - pos[1] - 12), - size=(0, 0), - scale=0.5, - maxwidth=button_width, - draw_controller=btn, - h_align='center', - v_align='center', - color=(0.8, 0.8, 0.8, 0.8)) + bui.textwidget(parent=self._subcontainer, + text=name, + position=(pos[0] + button_width * 0.5, + pos[1] - 12), + size=(0, 0), + scale=0.5, + maxwidth=button_width, + draw_controller=btn, + h_align='center', + v_align='center', + color=(0.8, 0.8, 0.8, 0.8)) index += 1 if index >= len(bot_list): @@ -1997,10 +2006,10 @@ def _select_character(self, character: str) -> None: def _transition_out(self) -> None: if not self._transitioning_out: self._transitioning_out = True - ba.containerwidget(edit=self.root_widget, transition='out_scale') + bui.containerwidget(edit=self.root_widget, transition='out_scale') def on_popup_cancel(self) -> None: - ba.playsound(ba.getsound('swish')) + bui.getsound('swish').play() self._transition_out() @@ -2008,7 +2017,7 @@ class PowerPicker(popup.PopupWindow): """Popup window for selecting power up.""" def __init__(self, - parent: ba.Widget, + parent: bui.Widget, position: tuple[float, float] = (0.0, 0.0), delegate: Any = None, scale: float | None = None, @@ -2017,9 +2026,9 @@ def __init__(self, del parent # unused here if scale is None: - uiscale = ba.app.ui.uiscale - scale = (1.85 if uiscale is ba.UIScale.SMALL else - 1.65 if uiscale is ba.UIScale.MEDIUM else 1.23) + uiscale = bui.app.ui_v1.uiscale + scale = (1.85 if uiscale is babase.UIScale.SMALL else + 1.65 if uiscale is babase.UIScale.MEDIUM else 1.23) self._delegate = delegate self._transitioning_out = False @@ -2037,7 +2046,7 @@ def __init__(self, self._width = (10 + columns * (button_width + 2 * button_buffer_h) * (1.0 / 0.95) * (1.0 / 0.8)) self._height = self._width * (0.8 - if uiscale is ba.UIScale.SMALL else 1.06) + if uiscale is babase.UIScale.SMALL else 1.06) self._scroll_width = self._width * 0.8 self._scroll_height = self._height * 0.8 @@ -2055,22 +2064,22 @@ def __init__(self, focus_size=(self._scroll_width, self._scroll_height)) - self._scrollwidget = ba.scrollwidget(parent=self.root_widget, - size=(self._scroll_width, - self._scroll_height), - color=(0.55, 0.55, 0.55), - highlight=False, - position=self._scroll_position) + self._scrollwidget = bui.scrollwidget(parent=self.root_widget, + size=(self._scroll_width, + self._scroll_height), + color=(0.55, 0.55, 0.55), + highlight=False, + position=self._scroll_position) - ba.containerwidget(edit=self._scrollwidget, claims_left_right=True) + bui.containerwidget(edit=self._scrollwidget, claims_left_right=True) self._sub_width = self._scroll_width * 0.95 self._sub_height = 5 + rows * (button_height + 2 * button_buffer_v) + 100 - self._subcontainer = ba.containerwidget(parent=self._scrollwidget, - size=(self._sub_width, - self._sub_height), - background=False) + self._subcontainer = bui.containerwidget(parent=self._scrollwidget, + size=(self._sub_width, + self._sub_height), + background=False) power_list = (['Bomb', 'Curse', 'Health', 'IceBombs', 'ImpactBombs', 'LandMines', 'Punch', @@ -2086,32 +2095,32 @@ def __init__(self, pos = (x * (button_width + 2 * button_buffer_h) + button_buffer_h, self._sub_height - (y + 1) * (button_height + 2 * button_buffer_v) + 12) - btn = ba.buttonwidget( + btn = bui.buttonwidget( parent=self._subcontainer, button_type='square', position=(pos[0], pos[1]), size=(button_width, button_height), autoselect=True, - texture=ba.gettexture('powerup' + power_list[index]), + texture=bui.gettexture('powerup' + power_list[index]), label='', color=(1, 1, 1), - on_activate_call=ba.Call(self._select_power, - power=power_list[index])) - ba.widget(edit=btn, show_buffer_top=60, show_buffer_bottom=60) + on_activate_call=bui.Call(self._select_power, + power=power_list[index])) + bui.widget(edit=btn, show_buffer_top=60, show_buffer_bottom=60) name = power_list_type[index] - ba.textwidget(parent=self._subcontainer, - text=name, - position=(pos[0] + button_width * 0.5, - pos[1] - 12), - size=(0, 0), - scale=0.5, - maxwidth=button_width, - draw_controller=btn, - h_align='center', - v_align='center', - color=(0.8, 0.8, 0.8, 0.8)) + bui.textwidget(parent=self._subcontainer, + text=name, + position=(pos[0] + button_width * 0.5, + pos[1] - 12), + size=(0, 0), + scale=0.5, + maxwidth=button_width, + draw_controller=btn, + h_align='center', + v_align='center', + color=(0.8, 0.8, 0.8, 0.8)) index += 1 if index >= len(power_list): @@ -2127,10 +2136,10 @@ def _select_power(self, power: str) -> None: def _transition_out(self) -> None: if not self._transitioning_out: self._transitioning_out = True - ba.containerwidget(edit=self.root_widget, transition='out_scale') + bui.containerwidget(edit=self.root_widget, transition='out_scale') def on_popup_cancel(self) -> None: - ba.playsound(ba.getsound('swish')) + bui.getsound('swish').play() self._transition_out() @@ -2138,7 +2147,7 @@ class InfoWindow(popup.PopupWindow): """Popup window for Infos.""" def __init__(self, - parent: ba.Widget, + parent: bs.Widget, position: tuple[float, float] = (0.0, 0.0), delegate: Any = None, scale: float | None = None, @@ -2147,16 +2156,16 @@ def __init__(self, del parent # unused here if scale is None: - uiscale = ba.app.ui.uiscale - scale = (1.85 if uiscale is ba.UIScale.SMALL else - 1.65 if uiscale is ba.UIScale.MEDIUM else 1.23) + uiscale = bui.app.ui_v1.uiscale + scale = (1.85 if uiscale is babase.UIScale.SMALL else + 1.65 if uiscale is babase.UIScale.MEDIUM else 1.23) self._delegate = delegate self._transitioning_out = False self._width = 600 self._height = self._width * (0.6 - if uiscale is ba.UIScale.SMALL else 0.795) + if uiscale is babase.UIScale.SMALL else 0.795) # creates our _root_widget popup.PopupWindow.__init__(self, @@ -2168,20 +2177,20 @@ def __init__(self, focus_size=(self._width, self._height)) - ba.textwidget(parent=self.root_widget, - position=(self._width * 0.5, - self._height * 0.9), - size=(0, 0), - color=ba.app.ui.title_color, - scale=1.3, - h_align='center', - v_align='center', - text='About', - maxwidth=200) + bui.textwidget(parent=self.root_widget, + position=(self._width * 0.5, + self._height * 0.9), + size=(0, 0), + color=bui.app.ui_v1.title_color, + scale=1.3, + h_align='center', + v_align='center', + text='About', + maxwidth=200) text = ('Practice Tools Mod\n' 'Made By Cross Joy\n' - 'version 1.2\n' + 'version v' + version + '\n' '\n' 'Thx to\n' 'Mikirog for the Bomb radius visualizer mod.\n' @@ -2200,7 +2209,7 @@ def __init__(self, else: color = (0.4, 1.0, 1.4, 1.0) - ba.textwidget( + bui.textwidget( parent=self.root_widget, padding=4, color=color, @@ -2215,7 +2224,7 @@ def __init__(self, text_spacing = 70 - self.button_discord = ba.buttonwidget( + self.button_discord = bui.buttonwidget( parent=self.root_widget, position=( self._width * 0.25 - 40, self._height * 0.2 - 40), @@ -2225,15 +2234,15 @@ def __init__(self, color=(0.447, 0.537, 0.854), label='', on_activate_call=self._discord) - ba.imagewidget( + bui.imagewidget( parent=self.root_widget, position=(self._width * 0.25 - 25, self._height * 0.2 - 25), size=(50, 50), draw_controller=self.button_discord, - texture=ba.gettexture('discordLogo'), + texture=bui.gettexture('discordLogo'), color=(5, 5, 5)) - ba.textwidget( + bui.textwidget( parent=self.root_widget, position=(self._width * 0.25, self._height * 0.2 + text_spacing), @@ -2246,7 +2255,7 @@ def __init__(self, maxwidth=150, color=(0.447, 0.537, 0.854)) - self.button_github = ba.buttonwidget( + self.button_github = bui.buttonwidget( parent=self.root_widget, position=( self._width * 0.5 - 40, self._height * 0.2 - 40), @@ -2256,15 +2265,15 @@ def __init__(self, color=(0.129, 0.122, 0.122), label='', on_activate_call=self._github) - ba.imagewidget( + bui.imagewidget( parent=self.root_widget, position=(self._width * 0.5 - 25, self._height * 0.2 - 25), size=(50, 50), draw_controller=self.button_github, - texture=ba.gettexture('githubLogo'), + texture=bui.gettexture('githubLogo'), color=(1, 1, 1)) - ba.textwidget( + bui.textwidget( parent=self.root_widget, position=(self._width * 0.5, self._height * 0.2 + text_spacing), @@ -2277,7 +2286,7 @@ def __init__(self, maxwidth=150, color=(0.129, 0.122, 0.122)) - self.button_support = ba.buttonwidget( + self.button_support = bui.buttonwidget( parent=self.root_widget, position=( self._width * 0.75 - 40, self._height * 0.2 - 40), @@ -2287,15 +2296,15 @@ def __init__(self, color=(0.83, 0.69, 0.21), label='', on_activate_call=self._support) - ba.imagewidget( + bui.imagewidget( parent=self.root_widget, position=(self._width * 0.75 - 25, self._height * 0.2 - 25), size=(50, 50), draw_controller=self.button_support, - texture=ba.gettexture('heart'), + texture=bui.gettexture('heart'), color=(1, 1, 1)) - ba.textwidget( + bui.textwidget( parent=self.root_widget, position=(self._width * 0.75, self._height * 0.2 + text_spacing), @@ -2309,19 +2318,19 @@ def __init__(self, color=(0.83, 0.69, 0.21)) def _discord(self): - ba.open_url('https://discord.gg/JyBY6haARJ') + bui.open_url('https://discord.gg/JyBY6haARJ') def _github(self): - ba.open_url('https://github.com/CrossJoy/Bombsquad-Modding') + bui.open_url('https://github.com/CrossJoy/Bombsquad-Modding') def _support(self): - ba.open_url('https://www.buymeacoffee.com/CrossJoy') + bui.open_url('https://www.buymeacoffee.com/CrossJoy') def _transition_out(self) -> None: if not self._transitioning_out: self._transitioning_out = True - ba.containerwidget(edit=self.root_widget, transition='out_scale') + bui.containerwidget(edit=self.root_widget, transition='out_scale') def on_popup_cancel(self) -> None: - ba.playsound(ba.getsound('swish')) + bui.getsound('swish').play() self._transition_out() From b9a41c4f6c615de302e5cbb9697bccaa32ccd8e0 Mon Sep 17 00:00:00 2001 From: Rikko Date: Mon, 31 Jul 2023 21:10:42 +0530 Subject: [PATCH 0669/1464] Add metadata --- plugins/utilities.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/utilities.json b/plugins/utilities.json index f2146394..04ed9674 100644 --- a/plugins/utilities.json +++ b/plugins/utilities.json @@ -668,7 +668,7 @@ "versions": { "2.0.0": { "api_version": 8, - "commit_sha": "6e995dd", + "commit_sha": "9340deb", "released_on": "31-07-2023", "md5sum": "5cc5d2d1d775c726b6065679dcfe3bda" }, From 037ee6e25cc850a07177d8b98d02854539ed8139 Mon Sep 17 00:00:00 2001 From: brostos <67740566+brostosjoined@users.noreply.github.com> Date: Tue, 1 Aug 2023 03:31:00 +0300 Subject: [PATCH 0670/1464] Add files via upload --- plugins/utilities/discord_richpresence.py | 240 ++++++++++++---------- 1 file changed, 136 insertions(+), 104 deletions(-) diff --git a/plugins/utilities/discord_richpresence.py b/plugins/utilities/discord_richpresence.py index 26bdd55a..c4916220 100644 --- a/plugins/utilities/discord_richpresence.py +++ b/plugins/utilities/discord_richpresence.py @@ -24,7 +24,7 @@ import hashlib import babase import _babase -import bascenev1 as bs +import bascenev1 as bs import bascenev1lib import bauiv1 as bui @@ -45,9 +45,14 @@ def get_module(): path = Path(f"{install_path}/websocket.tar.gz") file_path = Path(f"{install_path}/websocket") source_dir = Path(f"{install_path}/websocket-client-1.6.1/websocket") - if not file_path.exists(): + if not f"{file_path}/__init__.py".exists(): url = "https://files.pythonhosted.org/packages/b1/34/3a5cae1e07d9566ad073fa6d169bf22c03a3ba7b31b3c3422ec88d039108/websocket-client-1.6.1.tar.gz" try: + # fix issue where the file delete themselves + try: + shutil.rmtree(file_path) + except: + pass filename, headers = urlretrieve(url, filename=path) with open(filename, "rb") as f: content = f.read() @@ -66,15 +71,16 @@ def get_module(): from websocket import WebSocketConnectionClosedException import websocket + start_time = time.time() - + class PresenceUpdate: def __init__(self): self.ws = websocket.WebSocketApp("wss://gateway.discord.gg/?encoding=json&v=10", - on_open=self.on_open, - on_message=self.on_message, - on_error=self.on_error, - on_close=self.on_close) + on_open=self.on_open, + on_message=self.on_message, + on_error=self.on_error, + on_close=self.on_close) self.heartbeat_interval = int(41250) self.resume_gateway_url: str | None = None self.session_id: str | None = None @@ -198,27 +204,30 @@ def identify(): identify() while True: heartbeat_payload = {"op": 1, "d": self.heartbeat_interval} - + try: self.ws.send(json.dumps(heartbeat_payload)) time.sleep(self.heartbeat_interval / 1000) except: pass - + if self.stop_heartbeat_thread.is_set(): self.stop_heartbeat_thread.clear() break - + threading.Thread(target=heartbeats, daemon=True, name="heartbeat").start() - + def start(self): if Path(f"{getcwd()}/token.txt").exists(): threading.Thread(target=self.ws.run_forever, daemon=True, name="websocket").start() - + def close(self): self.stop_heartbeat_thread.set() self.do_once = True self.ws.close() + + + if not ANDROID: @@ -235,13 +244,13 @@ def get_module(): with open(filename, "rb") as f: content = f.read() assert hashlib.md5(content).hexdigest() == "f7c163cdd001af2456c09e241b90bad7" - shutil.unpack_archive(filename, install_path) + shutil.unpack_archive( filename, install_path) shutil.copytree(source_dir, file_path) shutil.rmtree(Path(f"{install_path}/pypresence-4.3.0")) remove(path) except: pass - + # Make modifications for it to work on windows if babase.app.classic.platform == "windows": with open(Path(f"{getcwd()}/ba_data/python/pypresence/utils.py"), "r") as file: @@ -265,23 +274,32 @@ def get_event_loop(force_fresh=False): return running else: return loop""" - # Thanks Loup + #Thanks Loup with open(Path(f"{getcwd()}/ba_data/python/pypresence/utils.py"), "w") as file: for number, line in enumerate(data): - if number not in range(46, 56): + if number not in range(46,56): file.write(line) + #fix the mess i did with the previous + elif file_path.exists(): + with open(Path(f"{getcwd()}/ba_data/python/pypresence/utils.py"), "r") as file: + data = file.readlines() + first_line = data[0].rstrip("\n") + if not first_line == '"""Util functions that are needed but messy."""': + shutil.rmtree(file_path) + get_module() get_module() + from pypresence import PipeClosed, DiscordError, DiscordNotFound from pypresence.utils import get_event_loop - import pypresence + import pypresence import socket - + DEBUG = True - + _last_server_addr = 'localhost' _last_server_port = 43210 - + def print_error(err: str, include_exception: bool = False) -> None: if DEBUG: if include_exception: @@ -312,8 +330,8 @@ def new_connect(*args, **kwargs) -> None: # type: ignore old_connect(*args, **kwargs) c = kwargs.get("address") or args[0] _last_server_port = kwargs.get("port") or args[1] - - bs.connect_to_party = new_connect + + bs.connect_to_party = new_connect start_time = time.time() @@ -336,10 +354,10 @@ def __init__(self): self._last_secret_update_time: float = 0 self._last_connect_time: float = 0 self.should_close = False - - @staticmethod + + @staticmethod def is_discord_running(): - for i in range(6463, 6473): + for i in range(6463,6473): s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) s.settimeout(0.01) try: @@ -347,11 +365,11 @@ def is_discord_running(): s.close() if (conn == 0): s.close() - return (True) + return(True) except: s.close() - return (False) - + return(False) + def _generate_join_secret(self): # resp = requests.get('https://legacy.ballistica.net/bsAccessCheck').text connection_info = bs.get_connection_to_host_info() @@ -408,7 +426,7 @@ def _subscribe_events(self): self._subscribe("ACTIVITY_JOIN") self._subscribe("ACTIVITY_JOIN_REQUEST") - # def _update_presence(self) -> None: + # def _update_presence(self) -> None: # self._last_update_time = time.time() # try: # self._do_update_presence() @@ -417,6 +435,7 @@ def _subscribe_events(self): # self._reconnect() # except Exception: # print_error("failed to update presence", include_exception= True) + def _reconnect(self) -> None: self.rpc.connect() @@ -493,7 +512,7 @@ def handle_event(self, data): def _connect_to_party(self, hostname, port) -> None: babase.pushcall( babase.Call(bs.connect_to_party, hostname, port), from_other_thread=True - ) + ) def on_join_request(self, username, uid, discriminator, avatar) -> None: del uid # unused @@ -501,8 +520,7 @@ def on_join_request(self, username, uid, discriminator, avatar) -> None: babase.pushcall( babase.Call( bui.screenmessage, - "Discord: {}{} wants to join!".format( - username, discriminator if discriminator != "#0" else ""), + "Discord: {}{} wants to join!".format(username, discriminator if discriminator != "#0" else ""), color=(0.0, 1.0, 0.0), ), from_other_thread=True, @@ -522,13 +540,15 @@ def __init__(self): self.path = Path(f"{getcwd()}/token.txt") bg_color = (0.5, 0.4, 0.6) log_btn_colour = (0.10, 0.95, 0.10) if not self.path.exists() else (1.00, 0.15, 0.15) - log_txt = "LOG IN" if not self.path.exists() else "LOG OUT" + log_txt = "LOG IN" if not self.path.exists() else "LOG OUT" self.code = False self.resp = "Placeholder" self.headers = { - 'user-agent': "Mozilla/5.0", - 'content-type': "application/json", - } + 'user-agent': "Mozilla/5.0", + 'content-type': "application/json", + } + + # creates our _root_widget PopupWindow.__init__(self, @@ -537,6 +557,7 @@ def __init__(self): scale=(2.1 if _uiscale is babase.UIScale.SMALL else 1.5 if _uiscale is babase.UIScale.MEDIUM else 1.0), bg_color=bg_color) + self._cancel_button = bui.buttonwidget( parent=self.root_widget, @@ -549,38 +570,44 @@ def __init__(self): autoselect=True, icon=bui.gettexture('crossOut'), iconscale=1.2) - + + + bui.imagewidget(parent=self.root_widget, - position=(180, self._height - 55), - size=(32 * s, 32 * s), - texture=bui.gettexture("discordLogo"), - color=(10 - 0.32, 10 - 0.39, 10 - 0.96)) + position=(180, self._height - 55), + size=(32 * s, 32 * s), + texture=bui.gettexture("discordLogo"), + color=(10 - 0.32, 10 - 0.39, 10 - 0.96)) + + self.email_widget = bui.textwidget(parent=self.root_widget, - text="Email/Phone Number", - size=(400, 70), - position=(50, 180), - h_align='left', - v_align='center', - editable=True, - scale=0.8, - autoselect=True, - maxwidth=220) - + text="Email/Phone Number", + size=(400, 70), + position=(50, 180), + h_align='left', + v_align='center', + editable=True, + scale=0.8, + autoselect=True, + maxwidth=220) + + self.password_widget = bui.textwidget(parent=self.root_widget, - text="Password", - size=(400, 70), - position=(50, 120), - h_align='left', - v_align='center', - editable=True, - scale=0.8, - autoselect=True, - maxwidth=220) - + text="Password", + size=(400, 70), + position=(50, 120), + h_align='left', + v_align='center', + editable=True, + scale=0.8, + autoselect=True, + maxwidth=220) + + bui.containerwidget(edit=self.root_widget, - cancel_button=self._cancel_button) - + cancel_button=self._cancel_button) + bui.textwidget( parent=self.root_widget, position=(265, self._height - 37), @@ -591,7 +618,7 @@ def __init__(self): text="Discord", maxwidth=200, color=(0.80, 0.80, 0.80)) - + bui.textwidget( parent=self.root_widget, position=(265, self._height - 78), @@ -602,7 +629,8 @@ def __init__(self): text="💀Use at your own risk💀\n ⚠️discord account might get terminated⚠️", maxwidth=200, color=(1.00, 0.15, 0.15)) - + + self._login_button = bui.buttonwidget( parent=self.root_widget, position=(120, 65), @@ -624,29 +652,33 @@ def _transition_out(self) -> None: def on_bascenev1libup_cancel(self) -> None: bui.getsound('swish').play() self._transition_out() - + + + def backup_2fa_code(self, tickt): if babase.do_once(): self.email_widget.delete() self.password_widget.delete() - + self.backup_2fa_widget = bui.textwidget(parent=self.root_widget, - text="2FA/Discord Backup code", - size=(400, 70), - position=(50, 120), - h_align='left', - v_align='center', - editable=True, - scale=0.8, - autoselect=True, - maxwidth=220) + text="2FA/Discord Backup code", + size=(400, 70), + position=(50, 120), + h_align='left', + v_align='center', + editable=True, + scale=0.8, + autoselect=True, + maxwidth=220) + + json_data_2FA = { - "code": bui.textwidget(query=self.backup_2fa_widget), - "gift_code_sku_id": None, - "ticket": tickt, + "code": bui.textwidget(query=self.backup_2fa_widget), + "gift_code_sku_id": None, + "ticket": tickt, } - + if json_data_2FA['code'] != "2FA/Discord Backup code": try: payload_2FA = json.dumps(json_data_2FA) @@ -654,7 +686,7 @@ def backup_2fa_code(self, tickt): conn_2FA.request("POST", "/api/v9/auth/mfa/totp", payload_2FA, self.headers) res_2FA = conn_2FA.getresponse().read() token = json.loads(res_2FA)['token'].encode().hex().encode() - + with open(self.path, 'wb') as f: f.write(token) bui.screenmessage("Successfully logged in", (0.21, 1.0, 0.20)) @@ -665,11 +697,11 @@ def backup_2fa_code(self, tickt): self.code = True bui.screenmessage("Incorrect code", (1.00, 0.15, 0.15)) bui.getsound('error').play() - + def login(self): if not self.path.exists() and self.code == False: try: - + json_data = { 'login': bui.textwidget(query=self.email_widget), 'password': bui.textwidget(query=self.password_widget), @@ -678,7 +710,7 @@ def login(self): 'login_source': None, 'gift_code_sku_id': None, } - + conn = http.client.HTTPSConnection("discord.com") payload = json.dumps(json_data) @@ -686,7 +718,9 @@ def login(self): # res = conn.getresponse().read() conn.request("POST", "/api/v9/auth/login", payload, self.headers) res = conn.getresponse().read() + + try: token = json.loads(res)['token'].encode().hex().encode() with open(self.path, 'wb') as f: @@ -695,27 +729,27 @@ def login(self): bui.getsound('shieldUp').play() self.on_bascenev1libup_cancel() PresenceUpdate().start() - except KeyError: + except KeyError: try: ticket = json.loads(res)['ticket'] - bui.screenmessage("Input your 2FA or Discord Backup code", - (0.21, 1.0, 0.20)) + bui.screenmessage("Input your 2FA or Discord Backup code", (0.21, 1.0, 0.20)) bui.getsound('error').play() - self.resp = ticket + self.resp = ticket self.backup_2fa_code(tickt=ticket) self.code = True except KeyError: bui.screenmessage("Incorrect credentials", (1.00, 0.15, 0.15)) bui.getsound('error').play() - - except: + + except: bui.screenmessage("Connect to the internet", (1.00, 0.15, 0.15)) bui.getsound('error').play() conn.close() elif self.code == True: self.backup_2fa_code(tickt=self.resp) - + + else: self.email_widget.delete() self.password_widget.delete() @@ -723,12 +757,10 @@ def login(self): bui.getsound('shieldDown').play() bui.screenmessage("Account successfully removed!!", (0.10, 0.10, 1.00)) self.on_bascenev1libup_cancel() - PresenceUpdate().ws.close() - + PresenceUpdate().close() + run_once = False - - def get_once_asset(): global run_once if run_once: @@ -756,7 +788,6 @@ def get_once_asset(): pass run_once = True - def get_class(): if ANDROID: return PresenceUpdate() @@ -777,7 +808,7 @@ def __init__(self) -> None: def on_app_running(self) -> None: if not ANDROID: - self.rpc_thread.start() + self.rpc_thread.start() self.update_timer = bs.AppTimer( 1, bs.WeakCall(self.update_status), repeat=True ) @@ -804,17 +835,17 @@ def on_app_shutdown(self) -> None: def on_app_pause(self) -> None: self.rpc_thread.close() - + def on_app_resume(self) -> None: - global start_time + global start_time start_time = time.time() self.rpc_thread.start() - + def _get_current_activity_name(self) -> str | None: act = bs.get_foreground_host_activity() if isinstance(act, bs.GameActivity): return act.name - + this = "Lobby" name: str | None = ( act.__class__.__name__.replace("Activity", "") @@ -882,7 +913,7 @@ def update_status(self) -> None: offlinename = json.loads(bs.get_game_roster()[0]["spec_string"])[ "n" ] - if len(offlinename) > 19: # Thanks Rikko + if len(offlinename) > 19: # Thanks Rikko self.rpc_thread.state = offlinename[slice(19)] + "..." else: self.rpc_thread.state = offlinename @@ -895,7 +926,7 @@ def update_status(self) -> None: self.rpc_thread.state = servername[slice(19)] if connection_info == {}: - self.rpc_thread.details = "Local" # ! replace with something like ballistica github cause + self.rpc_thread.details = "Local" #! replace with something like ballistica github cause self.rpc_thread.state = self._get_current_activity_name() self.rpc_thread.party_size = max(1, len(roster)) self.rpc_thread.party_max = max(1, bs.get_public_party_max_size()) @@ -908,7 +939,7 @@ def update_status(self) -> None: bs.get_foreground_host_session() .__class__.__name__.replace("MainMenuSession", "") .replace("EndSession", "") - .replace("FreeForAllSession", ": FFA") # ! for session use small image key + .replace("FreeForAllSession", ": FFA") #! for session use small image key .replace("DualTeamSession", ": Teams") .replace("CoopSession", ": Coop") ) @@ -981,3 +1012,4 @@ def update_status(self) -> None: ) if ANDROID and Path(f"{getcwd()}/token.txt").exists(): self.rpc_thread.presence() + \ No newline at end of file From fbe8a1afb30ba18fe6dfa85f2f443e2eb209a9ee Mon Sep 17 00:00:00 2001 From: brostosjoined Date: Tue, 1 Aug 2023 00:36:34 +0000 Subject: [PATCH 0671/1464] [ci] auto-format --- plugins/utilities/discord_richpresence.py | 225 ++++++++++------------ 1 file changed, 103 insertions(+), 122 deletions(-) diff --git a/plugins/utilities/discord_richpresence.py b/plugins/utilities/discord_richpresence.py index c4916220..eb018db3 100644 --- a/plugins/utilities/discord_richpresence.py +++ b/plugins/utilities/discord_richpresence.py @@ -24,7 +24,7 @@ import hashlib import babase import _babase -import bascenev1 as bs +import bascenev1 as bs import bascenev1lib import bauiv1 as bui @@ -71,16 +71,15 @@ def get_module(): from websocket import WebSocketConnectionClosedException import websocket - start_time = time.time() - + class PresenceUpdate: def __init__(self): self.ws = websocket.WebSocketApp("wss://gateway.discord.gg/?encoding=json&v=10", - on_open=self.on_open, - on_message=self.on_message, - on_error=self.on_error, - on_close=self.on_close) + on_open=self.on_open, + on_message=self.on_message, + on_error=self.on_error, + on_close=self.on_close) self.heartbeat_interval = int(41250) self.resume_gateway_url: str | None = None self.session_id: str | None = None @@ -204,30 +203,27 @@ def identify(): identify() while True: heartbeat_payload = {"op": 1, "d": self.heartbeat_interval} - + try: self.ws.send(json.dumps(heartbeat_payload)) time.sleep(self.heartbeat_interval / 1000) except: pass - + if self.stop_heartbeat_thread.is_set(): self.stop_heartbeat_thread.clear() break - + threading.Thread(target=heartbeats, daemon=True, name="heartbeat").start() - + def start(self): if Path(f"{getcwd()}/token.txt").exists(): threading.Thread(target=self.ws.run_forever, daemon=True, name="websocket").start() - + def close(self): self.stop_heartbeat_thread.set() self.do_once = True self.ws.close() - - - if not ANDROID: @@ -244,13 +240,13 @@ def get_module(): with open(filename, "rb") as f: content = f.read() assert hashlib.md5(content).hexdigest() == "f7c163cdd001af2456c09e241b90bad7" - shutil.unpack_archive( filename, install_path) + shutil.unpack_archive(filename, install_path) shutil.copytree(source_dir, file_path) shutil.rmtree(Path(f"{install_path}/pypresence-4.3.0")) remove(path) except: pass - + # Make modifications for it to work on windows if babase.app.classic.platform == "windows": with open(Path(f"{getcwd()}/ba_data/python/pypresence/utils.py"), "r") as file: @@ -274,12 +270,12 @@ def get_event_loop(force_fresh=False): return running else: return loop""" - #Thanks Loup + # Thanks Loup with open(Path(f"{getcwd()}/ba_data/python/pypresence/utils.py"), "w") as file: for number, line in enumerate(data): - if number not in range(46,56): + if number not in range(46, 56): file.write(line) - #fix the mess i did with the previous + # fix the mess i did with the previous elif file_path.exists(): with open(Path(f"{getcwd()}/ba_data/python/pypresence/utils.py"), "r") as file: data = file.readlines() @@ -289,17 +285,16 @@ def get_event_loop(force_fresh=False): get_module() get_module() - from pypresence import PipeClosed, DiscordError, DiscordNotFound from pypresence.utils import get_event_loop - import pypresence + import pypresence import socket - + DEBUG = True - + _last_server_addr = 'localhost' _last_server_port = 43210 - + def print_error(err: str, include_exception: bool = False) -> None: if DEBUG: if include_exception: @@ -330,8 +325,8 @@ def new_connect(*args, **kwargs) -> None: # type: ignore old_connect(*args, **kwargs) c = kwargs.get("address") or args[0] _last_server_port = kwargs.get("port") or args[1] - - bs.connect_to_party = new_connect + + bs.connect_to_party = new_connect start_time = time.time() @@ -354,10 +349,10 @@ def __init__(self): self._last_secret_update_time: float = 0 self._last_connect_time: float = 0 self.should_close = False - - @staticmethod + + @staticmethod def is_discord_running(): - for i in range(6463,6473): + for i in range(6463, 6473): s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) s.settimeout(0.01) try: @@ -365,11 +360,11 @@ def is_discord_running(): s.close() if (conn == 0): s.close() - return(True) + return (True) except: s.close() - return(False) - + return (False) + def _generate_join_secret(self): # resp = requests.get('https://legacy.ballistica.net/bsAccessCheck').text connection_info = bs.get_connection_to_host_info() @@ -426,7 +421,7 @@ def _subscribe_events(self): self._subscribe("ACTIVITY_JOIN") self._subscribe("ACTIVITY_JOIN_REQUEST") - # def _update_presence(self) -> None: + # def _update_presence(self) -> None: # self._last_update_time = time.time() # try: # self._do_update_presence() @@ -435,7 +430,6 @@ def _subscribe_events(self): # self._reconnect() # except Exception: # print_error("failed to update presence", include_exception= True) - def _reconnect(self) -> None: self.rpc.connect() @@ -512,7 +506,7 @@ def handle_event(self, data): def _connect_to_party(self, hostname, port) -> None: babase.pushcall( babase.Call(bs.connect_to_party, hostname, port), from_other_thread=True - ) + ) def on_join_request(self, username, uid, discriminator, avatar) -> None: del uid # unused @@ -520,7 +514,8 @@ def on_join_request(self, username, uid, discriminator, avatar) -> None: babase.pushcall( babase.Call( bui.screenmessage, - "Discord: {}{} wants to join!".format(username, discriminator if discriminator != "#0" else ""), + "Discord: {}{} wants to join!".format( + username, discriminator if discriminator != "#0" else ""), color=(0.0, 1.0, 0.0), ), from_other_thread=True, @@ -540,15 +535,13 @@ def __init__(self): self.path = Path(f"{getcwd()}/token.txt") bg_color = (0.5, 0.4, 0.6) log_btn_colour = (0.10, 0.95, 0.10) if not self.path.exists() else (1.00, 0.15, 0.15) - log_txt = "LOG IN" if not self.path.exists() else "LOG OUT" + log_txt = "LOG IN" if not self.path.exists() else "LOG OUT" self.code = False self.resp = "Placeholder" self.headers = { - 'user-agent': "Mozilla/5.0", - 'content-type': "application/json", - } - - + 'user-agent': "Mozilla/5.0", + 'content-type': "application/json", + } # creates our _root_widget PopupWindow.__init__(self, @@ -557,7 +550,6 @@ def __init__(self): scale=(2.1 if _uiscale is babase.UIScale.SMALL else 1.5 if _uiscale is babase.UIScale.MEDIUM else 1.0), bg_color=bg_color) - self._cancel_button = bui.buttonwidget( parent=self.root_widget, @@ -570,44 +562,38 @@ def __init__(self): autoselect=True, icon=bui.gettexture('crossOut'), iconscale=1.2) - - - + bui.imagewidget(parent=self.root_widget, - position=(180, self._height - 55), - size=(32 * s, 32 * s), - texture=bui.gettexture("discordLogo"), - color=(10 - 0.32, 10 - 0.39, 10 - 0.96)) - + position=(180, self._height - 55), + size=(32 * s, 32 * s), + texture=bui.gettexture("discordLogo"), + color=(10 - 0.32, 10 - 0.39, 10 - 0.96)) - self.email_widget = bui.textwidget(parent=self.root_widget, - text="Email/Phone Number", - size=(400, 70), - position=(50, 180), - h_align='left', - v_align='center', - editable=True, - scale=0.8, - autoselect=True, - maxwidth=220) - - + text="Email/Phone Number", + size=(400, 70), + position=(50, 180), + h_align='left', + v_align='center', + editable=True, + scale=0.8, + autoselect=True, + maxwidth=220) + self.password_widget = bui.textwidget(parent=self.root_widget, - text="Password", - size=(400, 70), - position=(50, 120), - h_align='left', - v_align='center', - editable=True, - scale=0.8, - autoselect=True, - maxwidth=220) - - + text="Password", + size=(400, 70), + position=(50, 120), + h_align='left', + v_align='center', + editable=True, + scale=0.8, + autoselect=True, + maxwidth=220) + bui.containerwidget(edit=self.root_widget, - cancel_button=self._cancel_button) - + cancel_button=self._cancel_button) + bui.textwidget( parent=self.root_widget, position=(265, self._height - 37), @@ -618,7 +604,7 @@ def __init__(self): text="Discord", maxwidth=200, color=(0.80, 0.80, 0.80)) - + bui.textwidget( parent=self.root_widget, position=(265, self._height - 78), @@ -629,8 +615,7 @@ def __init__(self): text="💀Use at your own risk💀\n ⚠️discord account might get terminated⚠️", maxwidth=200, color=(1.00, 0.15, 0.15)) - - + self._login_button = bui.buttonwidget( parent=self.root_widget, position=(120, 65), @@ -652,33 +637,29 @@ def _transition_out(self) -> None: def on_bascenev1libup_cancel(self) -> None: bui.getsound('swish').play() self._transition_out() - - - + def backup_2fa_code(self, tickt): if babase.do_once(): self.email_widget.delete() self.password_widget.delete() - + self.backup_2fa_widget = bui.textwidget(parent=self.root_widget, - text="2FA/Discord Backup code", - size=(400, 70), - position=(50, 120), - h_align='left', - v_align='center', - editable=True, - scale=0.8, - autoselect=True, - maxwidth=220) - - + text="2FA/Discord Backup code", + size=(400, 70), + position=(50, 120), + h_align='left', + v_align='center', + editable=True, + scale=0.8, + autoselect=True, + maxwidth=220) json_data_2FA = { - "code": bui.textwidget(query=self.backup_2fa_widget), - "gift_code_sku_id": None, - "ticket": tickt, + "code": bui.textwidget(query=self.backup_2fa_widget), + "gift_code_sku_id": None, + "ticket": tickt, } - + if json_data_2FA['code'] != "2FA/Discord Backup code": try: payload_2FA = json.dumps(json_data_2FA) @@ -686,7 +667,7 @@ def backup_2fa_code(self, tickt): conn_2FA.request("POST", "/api/v9/auth/mfa/totp", payload_2FA, self.headers) res_2FA = conn_2FA.getresponse().read() token = json.loads(res_2FA)['token'].encode().hex().encode() - + with open(self.path, 'wb') as f: f.write(token) bui.screenmessage("Successfully logged in", (0.21, 1.0, 0.20)) @@ -697,11 +678,11 @@ def backup_2fa_code(self, tickt): self.code = True bui.screenmessage("Incorrect code", (1.00, 0.15, 0.15)) bui.getsound('error').play() - + def login(self): if not self.path.exists() and self.code == False: try: - + json_data = { 'login': bui.textwidget(query=self.email_widget), 'password': bui.textwidget(query=self.password_widget), @@ -710,7 +691,7 @@ def login(self): 'login_source': None, 'gift_code_sku_id': None, } - + conn = http.client.HTTPSConnection("discord.com") payload = json.dumps(json_data) @@ -718,9 +699,7 @@ def login(self): # res = conn.getresponse().read() conn.request("POST", "/api/v9/auth/login", payload, self.headers) res = conn.getresponse().read() - - try: token = json.loads(res)['token'].encode().hex().encode() with open(self.path, 'wb') as f: @@ -729,27 +708,27 @@ def login(self): bui.getsound('shieldUp').play() self.on_bascenev1libup_cancel() PresenceUpdate().start() - except KeyError: + except KeyError: try: ticket = json.loads(res)['ticket'] - bui.screenmessage("Input your 2FA or Discord Backup code", (0.21, 1.0, 0.20)) + bui.screenmessage("Input your 2FA or Discord Backup code", + (0.21, 1.0, 0.20)) bui.getsound('error').play() - self.resp = ticket + self.resp = ticket self.backup_2fa_code(tickt=ticket) self.code = True except KeyError: bui.screenmessage("Incorrect credentials", (1.00, 0.15, 0.15)) bui.getsound('error').play() - - except: + + except: bui.screenmessage("Connect to the internet", (1.00, 0.15, 0.15)) bui.getsound('error').play() conn.close() elif self.code == True: self.backup_2fa_code(tickt=self.resp) - - + else: self.email_widget.delete() self.password_widget.delete() @@ -759,8 +738,10 @@ def login(self): self.on_bascenev1libup_cancel() PresenceUpdate().close() - + run_once = False + + def get_once_asset(): global run_once if run_once: @@ -788,6 +769,7 @@ def get_once_asset(): pass run_once = True + def get_class(): if ANDROID: return PresenceUpdate() @@ -808,7 +790,7 @@ def __init__(self) -> None: def on_app_running(self) -> None: if not ANDROID: - self.rpc_thread.start() + self.rpc_thread.start() self.update_timer = bs.AppTimer( 1, bs.WeakCall(self.update_status), repeat=True ) @@ -835,17 +817,17 @@ def on_app_shutdown(self) -> None: def on_app_pause(self) -> None: self.rpc_thread.close() - + def on_app_resume(self) -> None: - global start_time + global start_time start_time = time.time() self.rpc_thread.start() - + def _get_current_activity_name(self) -> str | None: act = bs.get_foreground_host_activity() if isinstance(act, bs.GameActivity): return act.name - + this = "Lobby" name: str | None = ( act.__class__.__name__.replace("Activity", "") @@ -913,7 +895,7 @@ def update_status(self) -> None: offlinename = json.loads(bs.get_game_roster()[0]["spec_string"])[ "n" ] - if len(offlinename) > 19: # Thanks Rikko + if len(offlinename) > 19: # Thanks Rikko self.rpc_thread.state = offlinename[slice(19)] + "..." else: self.rpc_thread.state = offlinename @@ -926,7 +908,7 @@ def update_status(self) -> None: self.rpc_thread.state = servername[slice(19)] if connection_info == {}: - self.rpc_thread.details = "Local" #! replace with something like ballistica github cause + self.rpc_thread.details = "Local" # ! replace with something like ballistica github cause self.rpc_thread.state = self._get_current_activity_name() self.rpc_thread.party_size = max(1, len(roster)) self.rpc_thread.party_max = max(1, bs.get_public_party_max_size()) @@ -939,7 +921,7 @@ def update_status(self) -> None: bs.get_foreground_host_session() .__class__.__name__.replace("MainMenuSession", "") .replace("EndSession", "") - .replace("FreeForAllSession", ": FFA") #! for session use small image key + .replace("FreeForAllSession", ": FFA") # ! for session use small image key .replace("DualTeamSession", ": Teams") .replace("CoopSession", ": Coop") ) @@ -1012,4 +994,3 @@ def update_status(self) -> None: ) if ANDROID and Path(f"{getcwd()}/token.txt").exists(): self.rpc_thread.presence() - \ No newline at end of file From 7c8953ce83af755d966ce036a5942f04eca61bf7 Mon Sep 17 00:00:00 2001 From: brostos <67740566+brostosjoined@users.noreply.github.com> Date: Tue, 1 Aug 2023 03:40:05 +0300 Subject: [PATCH 0672/1464] Update utilities.json --- plugins/utilities.json | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/plugins/utilities.json b/plugins/utilities.json index d7e356d5..5038dcfd 100644 --- a/plugins/utilities.json +++ b/plugins/utilities.json @@ -810,6 +810,7 @@ } ], "versions": { + "1.3.0": null, "1.2.0": { "api_version": 8, "commit_sha": "150f49f", @@ -831,4 +832,4 @@ } } } -} \ No newline at end of file +} From 17718a7220fcb7855c6c1793fce30f27d228625c Mon Sep 17 00:00:00 2001 From: brostosjoined Date: Tue, 1 Aug 2023 00:40:36 +0000 Subject: [PATCH 0673/1464] [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 5038dcfd..4106fd02 100644 --- a/plugins/utilities.json +++ b/plugins/utilities.json @@ -810,7 +810,12 @@ } ], "versions": { - "1.3.0": null, + "1.3.0": { + "api_version": 8, + "commit_sha": "7c8953c", + "released_on": "01-08-2023", + "md5sum": "1db3733c3d7d26165d75091cd8887db6" + }, "1.2.0": { "api_version": 8, "commit_sha": "150f49f", @@ -832,4 +837,4 @@ } } } -} +} \ No newline at end of file From 8a558e6a29283c44d698f5e5777175f1ded5acd3 Mon Sep 17 00:00:00 2001 From: Rikko Date: Thu, 3 Aug 2023 20:17:18 +0530 Subject: [PATCH 0674/1464] Update autopep8 version --- .github/workflows/ci.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index b4bf4629..23daee89 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -25,8 +25,8 @@ jobs: python-version: ${{ matrix.python-version }} - name: Install Dependencies run: | - python -m pip install --upgrade pip - pip install autopep8==2.0.0 + python -m pip install -U pip + pip install -U autopep8 pip install -r test/pip_reqs.txt - name: Apply AutoPEP8 run: | From ba4bde5a55adfad4971e818c8f00bda6ccb78743 Mon Sep 17 00:00:00 2001 From: Rikko Date: Thu, 3 Aug 2023 20:25:29 +0530 Subject: [PATCH 0675/1464] Update plugins as per new style --- plugins/minigames.json | 4 +++- plugins/minigames/basket_bomb.py | 6 +++--- plugins/minigames/volleyball.py | 2 +- plugins/utilities.json | 4 +++- plugins/utilities/advanced_party_window.py | 4 ++-- plugins/utilities/share_replay.py | 2 +- 6 files changed, 13 insertions(+), 9 deletions(-) diff --git a/plugins/minigames.json b/plugins/minigames.json index 65af0b55..f2926ef8 100644 --- a/plugins/minigames.json +++ b/plugins/minigames.json @@ -178,6 +178,7 @@ } ], "versions": { + "1.0.1": null, "1.0.0": { "api_version": 7, "commit_sha": "2fda676", @@ -241,6 +242,7 @@ } ], "versions": { + "2.0.1": null, "2.0.0": { "api_version": 8, "commit_sha": "48f9302", @@ -805,4 +807,4 @@ } } } -} \ No newline at end of file +} diff --git a/plugins/minigames/basket_bomb.py b/plugins/minigames/basket_bomb.py index 78c35b8e..4da374d1 100644 --- a/plugins/minigames/basket_bomb.py +++ b/plugins/minigames/basket_bomb.py @@ -488,7 +488,7 @@ def __init__(self, team: int = 0, 'materials': [self._score_region_material]}) ] self.regions[0].connectattr('position', self.node, 'position') - #self.regions[0].connectattr('position', self.regions[1], 'position') + # self.regions[0].connectattr('position', self.regions[1], 'position') locs_count = 9 pos = list(position) @@ -555,8 +555,8 @@ def __init__(self, team: int = 0, 'materials': [self.collision, shared.footing_material]}) - #self.shield = ba.newnode('shield', attrs={'radius': 1.0, 'color': (0,10,0)}) - #self.region.connectattr('position', self.shield, 'position') + # self.shield = ba.newnode('shield', attrs={'radius': 1.0, 'color': (0,10,0)}) + # self.region.connectattr('position', self.shield, 'position') position = (position[0], position[1], position[2]+0.09) pos = list(position) diff --git a/plugins/minigames/volleyball.py b/plugins/minigames/volleyball.py index df4c19a1..5642d854 100644 --- a/plugins/minigames/volleyball.py +++ b/plugins/minigames/volleyball.py @@ -743,7 +743,7 @@ def __init__(self) -> None: gnode.vignette_inner = (0.93, 0.93, 0.95) gnode.vr_camera_offset = (0, -0.8, -1.1) gnode.vr_near_clip = 0.5 - #self.is_hockey = True + # self.is_hockey = True bs._map.register_map(VolleyBallMap) diff --git a/plugins/utilities.json b/plugins/utilities.json index 4106fd02..d6233aac 100644 --- a/plugins/utilities.json +++ b/plugins/utilities.json @@ -38,6 +38,7 @@ } ], "versions": { + "1.3.1": null, "1.3.0": { "api_version": 7, "commit_sha": "ec116b3", @@ -390,6 +391,7 @@ } ], "versions": { + "2.0.1": null, "2.0.0": { "api_version": 8, "commit_sha": "da0e63d", @@ -837,4 +839,4 @@ } } } -} \ No newline at end of file +} diff --git a/plugins/utilities/advanced_party_window.py b/plugins/utilities/advanced_party_window.py index e5c74b2b..f9db1b80 100644 --- a/plugins/utilities/advanced_party_window.py +++ b/plugins/utilities/advanced_party_window.py @@ -828,7 +828,7 @@ def _reset_game_record(self) -> None: newFileName = str(babase.Lstr(resource="replayNameDefaultText").evaluate( )+" (%s)" % (datetime.datetime.strftime(datetime.datetime.now(), "%Y_%m_%d_%H_%M_%S"))+".brp") newFilePath = os.path.join(dir_path+os.sep, newFileName).encode(SystemEncode) - #print(curFilePath, newFilePath) + # print(curFilePath, newFilePath) # os.rename(curFilePath,newFilePath) shutil.copyfile(curFilePath, newFilePath) bs.broadcastmessage(_getTransText("Game_Record_Saved") % newFileName, color=(1, 1, 1)) @@ -1182,7 +1182,7 @@ def _kick_selected_player(self): babase.Lstr(resource='internal.cantKickHostError'), color=(1, 0, 0)) - #NewShareCodeWindow(origin_widget=self.get_root_widget(), delegate=None,code = "300",execText = u"_babase._disconnectClient(%d,{Value})"%self._popup_party_member_client_id) + # NewShareCodeWindow(origin_widget=self.get_root_widget(), delegate=None,code = "300",execText = u"_babase._disconnectClient(%d,{Value})"%self._popup_party_member_client_id) def joinbombspot(self): bui.open_url("https://discord.gg/ucyaesh") diff --git a/plugins/utilities/share_replay.py b/plugins/utilities/share_replay.py index cbf94bf7..b0a2af34 100644 --- a/plugins/utilities/share_replay.py +++ b/plugins/utilities/share_replay.py @@ -332,7 +332,7 @@ def close(self): # ++++++++++++++++for keyboard navigation++++++++++++++++ - #ba.widget(edit=self.enable_button, up_widget=decrease_button, down_widget=self.lower_text,left_widget=save_button, right_widget=save_button) + # ba.widget(edit=self.enable_button, up_widget=decrease_button, down_widget=self.lower_text,left_widget=save_button, right_widget=save_button) # ---------------------------------------------------------------------------------------------------- From d511c15c2e6ebe2515a912dc8935dfb740e8ebb7 Mon Sep 17 00:00:00 2001 From: rikkolovescats Date: Thu, 3 Aug 2023 14:56:26 +0000 Subject: [PATCH 0676/1464] [ci] auto-format --- plugins/utilities/discord_richpresence.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/utilities/discord_richpresence.py b/plugins/utilities/discord_richpresence.py index eb018db3..85d5c0db 100644 --- a/plugins/utilities/discord_richpresence.py +++ b/plugins/utilities/discord_richpresence.py @@ -850,7 +850,7 @@ def _get_current_activity_name(self) -> str | None: if name == this: self.rpc_thread.large_image_key = "lobby" self.rpc_thread.large_image_text = "Bombing up" - #self.rpc_thread.small_image_key = "lobbysmall" + # self.rpc_thread.small_image_key = "lobbysmall" if name == "Ranking": self.rpc_thread.large_image_key = "ranking" self.rpc_thread.large_image_text = "Viewing Results" From 3967d2ac6e3987a3893d3ddc6ffeb64fd9b3c6a5 Mon Sep 17 00:00:00 2001 From: rikkolovescats Date: Thu, 3 Aug 2023 14:56:27 +0000 Subject: [PATCH 0677/1464] [ci] apply-version-metadata --- plugins/minigames.json | 16 +++++++++++++--- plugins/utilities.json | 16 +++++++++++++--- 2 files changed, 26 insertions(+), 6 deletions(-) diff --git a/plugins/minigames.json b/plugins/minigames.json index f2926ef8..3181af4f 100644 --- a/plugins/minigames.json +++ b/plugins/minigames.json @@ -178,7 +178,12 @@ } ], "versions": { - "1.0.1": null, + "1.0.1": { + "api_version": 7, + "commit_sha": "d511c15", + "released_on": "03-08-2023", + "md5sum": "a352bee7d9be68773bb056d94486a299" + }, "1.0.0": { "api_version": 7, "commit_sha": "2fda676", @@ -242,7 +247,12 @@ } ], "versions": { - "2.0.1": null, + "2.0.1": { + "api_version": 8, + "commit_sha": "d511c15", + "released_on": "03-08-2023", + "md5sum": "9277227c0f267f0d7d9e9d744f14688b" + }, "2.0.0": { "api_version": 8, "commit_sha": "48f9302", @@ -807,4 +817,4 @@ } } } -} +} \ No newline at end of file diff --git a/plugins/utilities.json b/plugins/utilities.json index d6233aac..3048d1c3 100644 --- a/plugins/utilities.json +++ b/plugins/utilities.json @@ -38,7 +38,12 @@ } ], "versions": { - "1.3.1": null, + "1.3.1": { + "api_version": 7, + "commit_sha": "d511c15", + "released_on": "03-08-2023", + "md5sum": "c1dea54adc0136638ff56993a7196519" + }, "1.3.0": { "api_version": 7, "commit_sha": "ec116b3", @@ -391,7 +396,12 @@ } ], "versions": { - "2.0.1": null, + "2.0.1": { + "api_version": 8, + "commit_sha": "d511c15", + "released_on": "03-08-2023", + "md5sum": "6a9f37d78e2293aa0bf8eb6e5d60e702" + }, "2.0.0": { "api_version": 8, "commit_sha": "da0e63d", @@ -839,4 +849,4 @@ } } } -} +} \ No newline at end of file From 8e8521528b22a03f5abcc5704af9663188bfc3e6 Mon Sep 17 00:00:00 2001 From: brostos <67740566+brostosjoined@users.noreply.github.com> Date: Thu, 3 Aug 2023 17:11:13 +0300 Subject: [PATCH 0678/1464] Update discord_richpresence.py --- plugins/utilities/discord_richpresence.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/utilities/discord_richpresence.py b/plugins/utilities/discord_richpresence.py index 85d5c0db..c24b51e8 100644 --- a/plugins/utilities/discord_richpresence.py +++ b/plugins/utilities/discord_richpresence.py @@ -45,7 +45,7 @@ def get_module(): path = Path(f"{install_path}/websocket.tar.gz") file_path = Path(f"{install_path}/websocket") source_dir = Path(f"{install_path}/websocket-client-1.6.1/websocket") - if not f"{file_path}/__init__.py".exists(): + if not Path(f"{file_path}/__init__.py").exists(): #YouKnowDev url = "https://files.pythonhosted.org/packages/b1/34/3a5cae1e07d9566ad073fa6d169bf22c03a3ba7b31b3c3422ec88d039108/websocket-client-1.6.1.tar.gz" try: # fix issue where the file delete themselves From a6bfc290f31236554ed11b7e7dd239adecc21f4b Mon Sep 17 00:00:00 2001 From: brostosjoined Date: Thu, 3 Aug 2023 14:17:02 +0000 Subject: [PATCH 0679/1464] [ci] auto-format --- plugins/utilities/discord_richpresence.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/utilities/discord_richpresence.py b/plugins/utilities/discord_richpresence.py index c24b51e8..5f3d378a 100644 --- a/plugins/utilities/discord_richpresence.py +++ b/plugins/utilities/discord_richpresence.py @@ -45,7 +45,7 @@ def get_module(): path = Path(f"{install_path}/websocket.tar.gz") file_path = Path(f"{install_path}/websocket") source_dir = Path(f"{install_path}/websocket-client-1.6.1/websocket") - if not Path(f"{file_path}/__init__.py").exists(): #YouKnowDev + if not Path(f"{file_path}/__init__.py").exists(): # YouKnowDev url = "https://files.pythonhosted.org/packages/b1/34/3a5cae1e07d9566ad073fa6d169bf22c03a3ba7b31b3c3422ec88d039108/websocket-client-1.6.1.tar.gz" try: # fix issue where the file delete themselves From 53fe1a071a3cb6c36c895db45a273177cc89415b Mon Sep 17 00:00:00 2001 From: brostos <67740566+brostosjoined@users.noreply.github.com> Date: Thu, 3 Aug 2023 17:18:07 +0300 Subject: [PATCH 0680/1464] Update utilities.json --- plugins/utilities.json | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/plugins/utilities.json b/plugins/utilities.json index 3048d1c3..1a3733cc 100644 --- a/plugins/utilities.json +++ b/plugins/utilities.json @@ -822,6 +822,7 @@ } ], "versions": { + "1.4.0": null, "1.3.0": { "api_version": 8, "commit_sha": "7c8953c", @@ -849,4 +850,4 @@ } } } -} \ No newline at end of file +} From c526fc01135714d8feb5bfadeaa925356dd8b60f Mon Sep 17 00:00:00 2001 From: brostosjoined Date: Thu, 3 Aug 2023 14:18:37 +0000 Subject: [PATCH 0681/1464] [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 1a3733cc..64bad69f 100644 --- a/plugins/utilities.json +++ b/plugins/utilities.json @@ -822,7 +822,12 @@ } ], "versions": { - "1.4.0": null, + "1.4.0": { + "api_version": 8, + "commit_sha": "875732f", + "released_on": "03-08-2023", + "md5sum": "6b2ccd5b75e2c75ced47da11582d693f" + }, "1.3.0": { "api_version": 8, "commit_sha": "7c8953c", @@ -850,4 +855,4 @@ } } } -} +} \ No newline at end of file From 69477775e1194fd08cf64067940f9a6b0a93fa33 Mon Sep 17 00:00:00 2001 From: Rikko Date: Thu, 3 Aug 2023 20:31:44 +0530 Subject: [PATCH 0682/1464] Refresh metadata --- plugins/utilities.json | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/plugins/utilities.json b/plugins/utilities.json index 64bad69f..1a3733cc 100644 --- a/plugins/utilities.json +++ b/plugins/utilities.json @@ -822,12 +822,7 @@ } ], "versions": { - "1.4.0": { - "api_version": 8, - "commit_sha": "875732f", - "released_on": "03-08-2023", - "md5sum": "6b2ccd5b75e2c75ced47da11582d693f" - }, + "1.4.0": null, "1.3.0": { "api_version": 8, "commit_sha": "7c8953c", @@ -855,4 +850,4 @@ } } } -} \ No newline at end of file +} From 72479808763cf00a42c68e33dc60ace9dab203d2 Mon Sep 17 00:00:00 2001 From: rikkolovescats Date: Thu, 3 Aug 2023 15:02:35 +0000 Subject: [PATCH 0683/1464] [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 1a3733cc..c305391c 100644 --- a/plugins/utilities.json +++ b/plugins/utilities.json @@ -822,7 +822,12 @@ } ], "versions": { - "1.4.0": null, + "1.4.0": { + "api_version": 8, + "commit_sha": "6947777", + "released_on": "03-08-2023", + "md5sum": "1b8a85ed902e0cc7e6cebad63c984544" + }, "1.3.0": { "api_version": 8, "commit_sha": "7c8953c", @@ -850,4 +855,4 @@ } } } -} +} \ No newline at end of file From cc616c616032ac16744c1812fe02a0dce4267a38 Mon Sep 17 00:00:00 2001 From: Rikko Date: Thu, 3 Aug 2023 20:43:11 +0530 Subject: [PATCH 0684/1464] Don't use cached dependencies? --- .github/workflows/ci.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 23daee89..c3dd1b22 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -26,8 +26,8 @@ jobs: - name: Install Dependencies run: | python -m pip install -U pip - pip install -U autopep8 - pip install -r test/pip_reqs.txt + python -m pip install -U autopep8 + python -m pip install -U -r test/pip_reqs.txt - name: Apply AutoPEP8 run: | autopep8 --in-place --recursive --max-line-length=100 . From 1d50d58119eefb43d6fc74f8e67db2499e3d4b9c Mon Sep 17 00:00:00 2001 From: Rikko Date: Thu, 3 Aug 2023 20:50:27 +0530 Subject: [PATCH 0685/1464] Pin pycodestyle version --- .github/workflows/ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index c3dd1b22..2816e52c 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -26,7 +26,7 @@ jobs: - name: Install Dependencies run: | python -m pip install -U pip - python -m pip install -U autopep8 + python -m pip install -U pycodestyle==2.10.0 autopep8 python -m pip install -U -r test/pip_reqs.txt - name: Apply AutoPEP8 run: | From 93ab4f7422763016c9acdd9d3d374e2ee711b998 Mon Sep 17 00:00:00 2001 From: Rikko Date: Thu, 3 Aug 2023 20:12:51 +0530 Subject: [PATCH 0686/1464] Character Maker to API 8 --- plugins/utilities.json | 3 +- plugins/utilities/character_maker.py | 1284 +++++++++++++++----------- 2 files changed, 760 insertions(+), 527 deletions(-) diff --git a/plugins/utilities.json b/plugins/utilities.json index c305391c..44ac0ca7 100644 --- a/plugins/utilities.json +++ b/plugins/utilities.json @@ -527,6 +527,7 @@ } ], "versions": { + "2.0.0": null, "1.0.1": { "api_version": 7, "commit_sha": "da10318", @@ -855,4 +856,4 @@ } } } -} \ No newline at end of file +} diff --git a/plugins/utilities/character_maker.py b/plugins/utilities/character_maker.py index ba011676..0aded4f7 100644 --- a/plugins/utilities/character_maker.py +++ b/plugins/utilities/character_maker.py @@ -1,526 +1,758 @@ -# Released under the MIT License. See LICENSE for details. - - -''' -Character Builder/Maker by Mr.Smoothy -Plugin helps to mix character models and textures in interactive way. - -Watch tutorial : https://www.youtube.com/c/HeySmoothy -Join discord: https://discord.gg/ucyaesh for help -https://github.com/imayushsaini/Bombsquad-Ballistica-Modded-Server/ - -> create team playlist and add character maker mini game -> Use export command to save character -> Character will be saved in CustomCharacter folder inside Bombsquad Mods folder - -*Only one player in that mini game supported ... - -Characters can be used offline or online -for online you need to share character file with server owners. - -*For server owners:_ - You might know what to do with that file, - Still , - refer code after line 455 in this file , add it as a plugin to import characters from json file. - -*For modders:- - You can add more models and texture , check line near 400 and add asset names , you can also modify sounds and icon in json file (optional) . - -To share your character with friends , - send them character .json file and tell them to put file in same location i.e Bombsquad/CustomCharacter or for PC appdata/Local/Bombsquad/Mods/CustomCharacter - this plugin should be installed on their device too - -Dont forget to share your creativity with me , -send your character screenshot discord: mr.smoothy#5824 https://discord.gg/ucyaesh - -Register your character in above discord server , so other server owners can add your characters. - - -Released on 28 May 2021 - - -Update 2 june : use import -''' - - -# ba_meta require api 7 - - -from __future__ import annotations - -from typing import TYPE_CHECKING - -import ba -import _ba -from bastd.actor.playerspaz import PlayerSpaz -from bastd.actor.scoreboard import Scoreboard - -if TYPE_CHECKING: - from typing import Any, Type, List, Dict, Tuple, Union, Sequence, Optional - -import os -import json -from bastd.actor.spazappearance import * -spazoutfit = { - "color_mask": "neoSpazColorMask", - "color_texture": "neoSpazColor", - "head": "neoSpazHead", - "hand": "neoSpazHand", - "torso": "neoSpazTorso", - "pelvis": "neoSpazTorso", - "upper_arm": "neoSpazUpperArm", - "forearm": "neoSpazForeArm", - "upper_leg": "neoSpazUpperLeg", - "lower_leg": "neoSpazLowerLeg", - "toes_model": "neoSpazToes", - "jump_sounds": ['spazJump01', 'spazJump02', 'spazJump03', 'spazJump04'], - "attack_sounds": ['spazAttack01', 'spazAttack02', 'spazAttack03', 'spazAttack04'], - "impact_sounds": ['spazImpact01', 'spazImpact02', 'spazImpact03', 'spazImpact04'], - "death_sounds": ['spazDeath01'], - "pickup_sounds": ['spazPickup01'], - "fall_sounds": ['spazFall01'], - "icon_texture": "neoSpazIcon", - "icon_mask_texture": "neoSpazIconColorMask", - "style": "spaz" -} -character = None - - -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 - - -# ba_meta export game -class CharacterBuilder(ba.TeamGameActivity[Player, Team]): - """A game type based on acquiring kills.""" - - name = 'Character Maker' - description = 'Create your own custom Characters' - - # Print messages when players die since it matters here. - announce_player_deaths = True - - @classmethod - def get_available_settings( - cls, sessiontype: Type[ba.Session]) -> List[ba.Setting]: - settings = [ - ba.IntSetting( - 'Kills to Win Per Player', - 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', 4.0), - ], - default=1.0, - ), - ba.BoolSetting('Epic Mode', default=False), - ] - - if issubclass(sessiontype, ba.FreeForAllSession): - settings.append( - ba.BoolSetting('Allow Negative Scores', default=False)) - - return settings - - @classmethod - def supports_session_type(cls, sessiontype: Type[ba.Session]) -> bool: - return (issubclass(sessiontype, ba.DualTeamSession) - or issubclass(sessiontype, ba.FreeForAllSession)) - - @classmethod - def get_supported_maps(cls, sessiontype: Type[ba.Session]) -> List[str]: - return ['Rampage'] - - def __init__(self, settings: dict): - - super().__init__(settings) - - self.initdic() - _ba.set_party_icon_always_visible(True) - self._score_to_win: Optional[int] = None - self._dingsound = ba.getsound('dingSmall') - self._epic_mode = bool(settings['Epic Mode']) - self._kills_to_win_per_player = int( - settings['Kills to Win Per Player']) - self._time_limit = float(settings['Time Limit']) - self._allow_negative_scores = bool( - settings.get('Allow Negative Scores', False)) - self.bodyindex = 0 - self.modelindex = 0 - self.youtube = ba.newnode( - 'text', - attrs={ - 'text': "youtube.com/c/HeySmoothy", - 'in_world': True, - 'scale': 0.02, - 'color': (1, 0, 0, 0.4), - 'h_align': 'center', - 'position': (0, 4, -1.9) - }) - self.discordservere = ba.newnode( - 'text', - attrs={ - 'text': "discord.gg/ucyaesh", - 'in_world': True, - 'scale': 0.02, - 'color': (0.12, 0.3, 0.6, 0.4), - 'h_align': 'center', - 'position': (-3, 2.7, -1.9) - }) - # self.discord= ba.newnode( - # 'text', - # attrs={ - # 'text': "mr.smoothy#5824", - # 'in_world': True, - # 'scale': 0.02, - # 'color': (01.2, 0.3, 0.7, 0.4), - # 'h_align': 'center', - # 'position': (4,2.7,-1.9) - # }) - # Base class overrides. - self.bodypart = ba.newnode( - 'text', - attrs={ - 'text': "", - 'in_world': True, - 'scale': 0.02, - 'color': (1, 1, 0, 1), - 'h_align': 'center', - 'position': (-4, 6, -4) - }) - self.newmodel = ba.newnode( - 'text', - attrs={ - 'text': "", - 'in_world': True, - 'scale': 0.02, - 'color': (1, 1, 0, 1), - 'h_align': 'center', - 'position': (6, 6, -4) - }) - self.slow_motion = self._epic_mode - self.default_music = (ba.MusicType.EPIC if self._epic_mode else - ba.MusicType.TO_THE_DEATH) - - def get_instance_description(self) -> Union[str, Sequence]: - return '' - - def get_instance_description_short(self) -> Union[str, Sequence]: - return '' - - def on_team_join(self, team: Team) -> None: - if self.has_begun(): - pass - - def on_begin(self) -> None: - super().on_begin() - - def nextBodyPart(self): - self.bodyindex = (self.bodyindex+1) % len(self.dic.keys()) - self.bodypart.delete() - PART = list(self.dic.keys())[self.bodyindex] - self.bodypart = ba.newnode( - 'text', - attrs={ - 'text': PART, - 'in_world': True, - 'scale': 0.02, - 'color': (1, 1, 1, 1), - 'h_align': 'center', - 'position': (-4, 6, -4) - }) - - def prevBodyPart(self): - self.bodyindex = (self.bodyindex-1) % len(self.dic.keys()) - self.bodypart.delete() - PART = list(self.dic.keys())[self.bodyindex] - self.bodypart = ba.newnode( - 'text', - attrs={ - 'text': PART, - 'in_world': True, - 'scale': 0.02, - 'color': (1, 1, 1, 1), - 'h_align': 'center', - 'position': (-4, 6, -4) - }) - - def nextModel(self): - - self.newmodel.delete() - PART = list(self.dic.keys())[self.bodyindex] - self.modelindex = (self.modelindex+1) % len(self.dic[PART]) - model = self.dic[PART][self.modelindex] - self.newmodel = ba.newnode( - 'text', - attrs={ - 'text': model, - 'in_world': True, - 'scale': 0.02, - 'color': (1, 1, 1, 1), - 'h_align': 'center', - 'position': (6, 6, -4) - }) - - self.setModel(PART, model) - - def prevModel(self): - - self.newmodel.delete() - PART = list(self.dic.keys())[self.bodyindex] - self.modelindex = (self.modelindex-1) % len(self.dic[PART]) - model = self.dic[PART][self.modelindex] - self.newmodel = ba.newnode( - 'text', - attrs={ - 'text': model, - 'in_world': True, - 'scale': 0.02, - 'color': (1, 1, 1, 1), - 'h_align': 'center', - 'position': (6, 6, -4) - }) - self.setModel(PART, model) - - def setModel(self, bodypart, modelname): - global spazoutfit - body = _ba.get_foreground_host_activity().players[0].actor.node - if bodypart == 'head': - body.head_model = ba.getmodel(modelname) - elif bodypart == 'torso': - body.torso_model = ba.getmodel(modelname) - elif bodypart == 'pelvis': - body.pelvis_model = ba.getmodel(modelname) - elif bodypart == 'upper_arm': - body.upper_arm_model = ba.getmodel(modelname) - elif bodypart == 'forearm': - body.forearm_model = ba.getmodel(modelname) - elif bodypart == 'hand': - body.hand_model = ba.getmodel(modelname) - elif bodypart == 'upper_leg': - body.upper_leg_model = ba.getmodel(modelname) - elif bodypart == 'lower_leg': - body.lower_leg_model = ba.getmodel(modelname) - elif bodypart == 'toes_model': - body.toes_model = ba.getmodel(modelname) - elif bodypart == 'style': - body.style = modelname - elif bodypart == 'color_texture': - body.color_texture = ba.gettexture(modelname) - elif bodypart == 'color_mask': - body.color_mask_texture = ba.gettexture(modelname) - spazoutfit[bodypart] = modelname - - def spawn_player(self, player: Player) -> ba.Actor: - global character - if character != None: - player.character = character - - self.setcurrentcharacter(player.character) - - spaz = self.spawn_player_spaz(player) - - # Let's reconnect this player's controls to this - # spaz but *without* the ability to attack or pick stuff up. - spaz.connect_controls_to_player(enable_punch=False, - enable_jump=False, - enable_bomb=False, - enable_pickup=False) - intp = ba.InputType - player.assigninput(intp.JUMP_PRESS, self.nextBodyPart) - player.assigninput(intp.PICK_UP_PRESS, self.prevBodyPart) - player.assigninput(intp.PUNCH_PRESS, self.nextModel) - player.assigninput(intp.BOMB_PRESS, self.prevModel) - # Also lets have them make some noise when they die. - spaz.play_big_death_sound = True - return spaz - - def handlemessage(self, msg: Any) -> Any: - - if isinstance(msg, ba.PlayerDiedMessage): - - # Augment standard behavior. - super().handlemessage(msg) - - player = msg.getplayer(Player) - self.respawn_player(player) - - else: - return super().handlemessage(msg) - return None - - def setcurrentcharacter(self, charname): - global spazoutfit - char = ba.app.spaz_appearances[charname] - spazoutfit['head'] = char.head_model - spazoutfit['hand'] = char.hand_model - spazoutfit['torso'] = char.torso_model - spazoutfit['pelvis'] = char.pelvis_model - spazoutfit['upper_arm'] = char.upper_arm_model - spazoutfit['forearm'] = char.forearm_model - spazoutfit['upper_leg'] = char.upper_leg_model - spazoutfit['lower_leg'] = char.lower_leg_model - spazoutfit['toes_model'] = char.toes_model - spazoutfit['style'] = char.style - spazoutfit['color_mask'] = char.color_mask_texture - spazoutfit['color_texture'] = char.color_texture - - def _update_scoreboard(self) -> None: - for team in self.teams: - self._scoreboard.set_team_value(team, team.score, - self._score_to_win) - - 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 initdic(self): - self.dic = {"head": ["bomb", "landMine", "trees", "wing", "eyeLid", "impactBomb"], - "hand": ["hairTuft3", "bomb", "powerup"], - "torso": ["bomb", "landMine", "bomb"], - "pelvis": ["hairTuft4", "bomb"], - "upper_arm": ["wing", "locator", "bomb"], - "forearm": ["flagPole", "bomb"], - "upper_leg": ["bomb"], - "lower_leg": ["bomb"], - "toes_model": ["bomb"], - "style": ["spaz", "female", "ninja", "kronk", "mel", "pirate", "santa", "frosty", "bones", "bear", "penguin", "ali", "cyborg", "agent", "pixie", "bunny"], - "color_texture": ["kronk", "egg1", "egg2", "egg3", "achievementGotTheMoves", "bombColor", "crossOut", "explosion", "rgbStripes", "powerupCurse", "powerupHealth", "impactBombColorLit"], - "color_mask": ["egg1", "egg2", "egg3", "bombColor", "crossOutMask", "fontExtras3"] - - } - chars = ["neoSpaz", "zoe", "ninja", "kronk", "mel", "jack", "santa", "frosty", - "bones", "bear", "penguin", "ali", "cyborg", "agent", "wizard", "pixie", "bunny"] - for char in chars: - self.dic["head"].append(char+"Head") - self.dic["hand"].append(char+"Hand") - self.dic["torso"].append(char+"Torso") - if char not in ['mel', "jack", "santa"]: - self.dic["pelvis"].append(char+"Pelvis") - self.dic["upper_arm"].append(char+"UpperArm") - self.dic["forearm"].append(char+"ForeArm") - self.dic["upper_leg"].append(char+"UpperLeg") - self.dic["lower_leg"].append(char+"LowerLeg") - self.dic["toes_model"].append(char+"Toes") - self.dic["color_mask"].append(char+"ColorMask") - if char != "kronk": - self.dic["color_texture"].append(char+"Color") - - -cm = _ba.chatmessage - - -def _new_chatmessage(msg: str | ba.Lstr, clients: Sequence[int] | None = None, sender_override: str | None = None): - if msg.split(" ")[0] == "export": - if len(msg.split(" ")) > 1: - savecharacter(msg.split(" ")[1]) - else: - _ba.screenmessage("Enter name of character") - elif msg.split(" ")[0] == "import": - importcharacter(msg[7:]) - - else: - cm(msg, clients, sender_override) - - -_ba.chatmessage = _new_chatmessage - - -def savecharacter(name): - path = os.path.join(_ba.env()["python_directory_user"], "CustomCharacters" + os.sep) - if not os.path.isdir(path): - os.makedirs(path) - if _ba.get_foreground_host_activity() != None: - - with open(path+name+".json", 'w') as f: - json.dump(spazoutfit, f, indent=4) - registercharacter(name, spazoutfit) - ba.playsound(ba.getsound("gunCocking")) - _ba.screenmessage("Character Saved") - else: - _ba.screenmessage("Works offline with Character Maker") - - -def importcharacter(name): - if name in ba.app.spaz_appearances: - global character - character = name - try: - _ba.get_foreground_host_activity().players[0].actor.node.handlemessage(ba.DieMessage()) - _ba.screenmessage("Imported") - except: - _ba.screenmessage("works offline with character maker") - - else: - _ba.screenmessage("invalid name check typo \n name is case sensitive") - - -def registercharacter(name, char): - t = Appearance(name.split(".")[0]) - t.color_texture = char['color_texture'] - t.color_mask_texture = char['color_mask'] - t.default_color = (0.6, 0.6, 0.6) - t.default_highlight = (0, 1, 0) - t.icon_texture = char['icon_texture'] - t.icon_mask_texture = char['icon_mask_texture'] - t.head_model = char['head'] - t.torso_model = char['torso'] - t.pelvis_model = char['pelvis'] - t.upper_arm_model = char['upper_arm'] - t.forearm_model = char['forearm'] - t.hand_model = char['hand'] - t.upper_leg_model = char['upper_leg'] - t.lower_leg_model = char['lower_leg'] - t.toes_model = char['toes_model'] - t.jump_sounds = char['jump_sounds'] - t.attack_sounds = char['attack_sounds'] - t.impact_sounds = char['impact_sounds'] - t.death_sounds = char['death_sounds'] - t.pickup_sounds = char['pickup_sounds'] - t.fall_sounds = char['fall_sounds'] - t.style = char['style'] - - -# ba_meta export plugin -class HeySmoothy(ba.Plugin): - - def __init__(self): - _ba.set_party_icon_always_visible(True) - - path = os.path.join(_ba.env()["python_directory_user"], "CustomCharacters" + os.sep) - if not os.path.isdir(path): - os.makedirs(path) - files = os.listdir(path) - for file in files: - with open(path+file, 'r') as f: - character = json.load(f) - registercharacter(file, character) +# Released under the MIT License. See LICENSE for details. + +# ba_meta require api 8 + + +''' +Character Builder/Maker by Mr.Smoothy +Plugin helps to mix character models and textures in interactive way. + +Watch tutorial : https://youtu.be/q0KxY1hfMPQ +Join discord: https://discord.gg/ucyaesh for help +https://bombsquad-community.web.app/home + +> create team playlist and add character maker mini game +> Use export command to save character +> Character will be saved in CustomCharacter folder inside Bombsquad Mods folder + + +Characters can be used offline or online +for online you need to share character file with server owners. + +*For server owners:_ + You might know what to do with that file, + Still , + refer code after line 455 in this file , add it as a plugin to import characters from json file. + +*For modders:- + You can add more models and texture , check line near 400 and add asset names , you can also modify sounds and icon in json file (optional) . + +To share your character with friends , + send them character .json file and tell them to put file in same location i.e mods/CustomCharacter or for PC appdata/Local/Bombsquad/Mods/CustomCharacter + this plugin should be installed on their device too. + +Dont forget to share your creativity with me , +send your character screenshot discord: mr.smoothy#5824 https://discord.gg/ucyaesh + +Register your character in above discord server , so other server owners can add your characters. + + +Released on 28 May 2021 +Update 2 june : use import +Update 29 July 2023: updated to API 8 , multiplayer support +''' + +from typing import Sequence +import _babase +import babase +import bauiv1 as bui +from bascenev1lib.actor.spazappearance import * +from bascenev1lib.actor.text import Text +from bascenev1lib.actor.image import Image + +import os +import copy +import json + +GAME_USER_DIRECTORY = _babase.env()["python_directory_user"] +CUSTOM_CHARACTERS = os.path.join(GAME_USER_DIRECTORY, "CustomCharacters") +os.makedirs(CUSTOM_CHARACTERS, exist_ok=True) + + +SPAZ_PRESET = { + "color_mask" : "neoSpazColorMask", + "color_texture" : "neoSpazColor", + "head" : "neoSpazHead", + "hand" : "neoSpazHand", + "torso" : "neoSpazTorso", + "pelvis" : "neoSpazTorso", + "upper_arm" : "neoSpazUpperArm", + "forearm" : "neoSpazForeArm", + "upper_leg" : "neoSpazUpperLeg", + "lower_leg" : "neoSpazLowerLeg", + "toes_mesh" : "neoSpazToes", + "jump_sounds" : ['spazJump01', 'spazJump02', 'spazJump03', 'spazJump04'], + "attack_sounds" : ['spazAttack01', 'spazAttack02', 'spazAttack03', 'spazAttack04'], + "impact_sounds" : ['spazImpact01', 'spazImpact02', 'spazImpact03', 'spazImpact04'], + "death_sounds" : ['spazDeath01'], + "pickup_sounds" : ['spazPickup01'], + "fall_sounds" : ['spazFall01'], + "icon_texture" : "neoSpazIcon", + "icon_mask_texture": "neoSpazIconColorMask", + "style" : "spaz" +} + +class Player(bs.Player['Team']): + """Our player type for this game.""" + + +class Team(bs.Team[Player]): + """Our team type for this game.""" + + def __init__(self): + self.score = 0 + + +# ba_meta export bascenev1.GameActivity +class CharacterBuilder(bs.TeamGameActivity[Player, Team]): + """A game type based on acquiring kills.""" + + name = 'Character Maker' + description = 'Create your own custom Characters' + + # Print messages when players die since it matters here. + announce_player_deaths = True + + @classmethod + def get_available_settings(cls, sessiontype): + settings = [ + bs.IntSetting( + 'Kills to Win Per Player', + min_value=1, + default=5, + increment=1, + ), + bs.IntChoiceSetting( + 'Time Limit', + choices=[ + ('None', 0), + ('1 Minute', 60), + ('2 Minutes', 120), + ('5 Minutes', 300), + ('10 Minutes', 600), + ('20 Minutes', 1200), + ], + default=0, + ), + bs.FloatChoiceSetting( + 'Respawn Times', + choices=[ + ('Shorter', 0.25), + ('Short', 0.5), + ('Normal', 1.0), + ('Long', 2.0), + ('Longer', 4.0), + ], + default=1.0, + ), + bs.BoolSetting('Epic Mode', default=False), + ] + + if issubclass(sessiontype, bs.FreeForAllSession): + settings.append( + bs.BoolSetting('Allow Negative Scores', default=False)) + + return settings + + @classmethod + def supports_session_type(cls, sessiontype): + return (issubclass(sessiontype, bs.DualTeamSession) + or issubclass(sessiontype, bs.FreeForAllSession)) + + @classmethod + def get_supported_maps(cls, sessiontype): + return ['Rampage'] + + def __init__(self, settings): + super().__init__(settings) + + self.initialize_meshs() + bui.set_party_icon_always_visible(True) + self._score_to_win = None + self._dingsound = bs.getsound('dingSmall') + self._epic_mode = bool(settings['Epic Mode']) + self._kills_to_win_per_player = int( + settings['Kills to Win Per Player']) + self._time_limit = float(settings['Time Limit']) + self._allow_negative_scores = bool( + settings.get('Allow Negative Scores', False)) + + self._punch_image = Image( + bs.gettexture('buttonPunch'), + position=(345,200), + scale=(50,50), + color= (0.9,0.9,0,0.9) + ) + self._punch_text = Text( + "Model+", + scale=0.7, + shadow=0.5, + flatness=0.5, + color=(0.9, 0.9, 0, 0.9), + position=(263,190)) + + self._grab_image = Image( + bs.gettexture('buttonPickUp'), + position=(385,240), + scale=(50,50), + color= (0,0.7,0.9) + ) + self._grab_text = Text( + "Component-", + scale=0.7, + shadow=0.5, + flatness=0.5, + color=(0, 0.7, 1, 0.9), + position=(340,265)) + + self._jump_image = Image( + bs.gettexture('buttonJump'), + position=(385,160), + scale=(50,50), + color= (0.2,0.9,0.2,0.9) + ) + self._jump_text = Text( + "Component+", + scale=0.7, + shadow=0.5, + flatness=0.5, + color=(0.2, 0.9, 0.2, 0.9), + position=(340,113)) + + self._bomb_image = Image( + bs.gettexture('buttonBomb'), + position=(425,200), + scale=(50,50), + color= (0.9,0.2,0.2,0.9) + ) + self._bomb_text = Text( + "Model-", + scale=0.7, + shadow=0.5, + flatness=0.5, + color=(0.9, 0.2, 0.2, 0.9), + position=(452,190)) + + + self._host = Text( + "Originally created by \ue020HeySmoothy\nhttps://youtu.be/q0KxY1hfMPQ\nhttps://youtu.be/3l2dxWEhrzE\n\nModified for multiplayer by \ue047Nyaa! :3", + flash=False, + maxwidth=0, + scale=0.65, + shadow=0.5, + flatness=0.5, + h_align=Text.HAlign.RIGHT, + v_attach=Text.VAttach.BOTTOM, + h_attach=Text.HAttach.RIGHT, + color=(1.0, 0.4, 0.95, 0.8), + position=(-2, 82)) + self._discord = Text( + "Join discord.gg/ucyaesh to provide feedback or to use this Character Maker offline!", + flash=False, + maxwidth=0, + scale=0.85, + shadow=0.5, + flatness=0.5, + h_align=Text.HAlign.CENTER, + v_attach=Text.VAttach.BOTTOM, + h_attach=Text.HAttach.CENTER, + color=(1.0, 0.4, 0, 1), + position=(0, 110)) + self._website = Text( + "check mods folder to get JSON character file ever exported from here!", + flash=False, + maxwidth=0, + scale=0.85, + shadow=0.5, + flatness=0.5, + h_align=Text.HAlign.CENTER, + v_attach=Text.VAttach.BOTTOM, + h_attach=Text.HAttach.CENTER, + color=(0.2, 0.9, 1.0, 1), + position=(0, 150)) + self._commands = Text( + "Commands:\n\n\t1. /info\n\t2. /export \n\t3. /import \n\t", + flash=False, + maxwidth=0, + scale=0.8, + shadow=0.5, + flatness=0.5, + h_align=Text.HAlign.LEFT, + v_attach=Text.VAttach.TOP, + h_attach=Text.HAttach.LEFT, + color=(0.3, 0.9, 0.3, 0.8), + position=(30, -112)) + # Base class overrides. + self.slow_motion = self._epic_mode + self.default_music = bs.MusicType.MARCHING + + def get_instance_description(self): + return '' + + def get_instance_description_short(self): + return '' + + def on_team_join(self, team: Team): + if self.has_begun(): + pass + + def on_begin(self): + super().on_begin() + + def nextBodyPart(self, spaz): + spaz.bodyindex = (spaz.bodyindex+1)%len(self.cache.keys()) + try: + spaz.bodypart.delete() + except AttributeError: + pass + part = list(self.cache.keys())[spaz.bodyindex] + spaz.bodypart = bs.newnode( + 'text', + owner=spaz.node, + attrs={ + 'text': str(part), + 'in_world': True, + 'color':(1,1,1), + 'scale': 0.011, + 'shadow': 0.5, + 'flatness': 0.5, + 'h_align': 'center',}) + math = bs.newnode('math', + owner=spaz.node, + attrs={ + 'input1': (0,1.7,0.5), + 'operation': 'add', + }) + spaz.node.connectattr('position', math, 'input2') + math.connectattr('output', spaz.bodypart, 'position') + bs.getsound('deek').play() + + def prevBodyPart(self, spaz): + spaz.bodyindex = (spaz.bodyindex-1)%len(self.cache.keys()) + try: + spaz.bodypart.delete() + except AttributeError: + pass + part=list(self.cache.keys())[spaz.bodyindex] + spaz.bodypart=bs.newnode( + 'text', + owner=spaz.node, + attrs={ + 'text': str(part), + 'in_world': True, + 'color':(1,1,1), + 'scale': 0.011, + 'shadow': 0.5, + 'flatness': 0.5, + 'h_align': 'center',}) + math = bs.newnode('math', + owner=spaz.node, + attrs={ + 'input1': (0,1.7,0.5), + 'operation': 'add', + }) + spaz.node.connectattr('position', math, 'input2') + math.connectattr('output', spaz.bodypart, 'position') + bs.getsound('deek').play() + + def nextModel(self, spaz): + try: + spaz.newmesh.delete() + except AttributeError: + pass + part = list(self.cache.keys())[spaz.bodyindex] + spaz.meshindex = (spaz.meshindex+1)%len(self.cache[part]) + mesh = self.cache[part][spaz.meshindex] + spaz.newmesh = bs.newnode( + 'text', + owner=spaz.node, + attrs={ + 'text': str(mesh), + 'in_world': True, + 'color':(1,1,1), + 'scale': 0.011, + 'shadow': 0.5, + 'flatness': 0.5, + 'h_align': 'center' + }) + math = bs.newnode('math', + owner=spaz.node, + attrs={ + 'input1': (0,-0.6,0.5), + 'operation': 'add', + }) + spaz.node.connectattr('position', math, 'input2') + math.connectattr('output', spaz.newmesh, 'position') + if part == "main_color": + self.setColor(spaz,mesh) + elif part == "highlight_color": + self.setHighlight(spaz,mesh) + else: + self.setModel(spaz,part,mesh) + bs.getsound('click01').play() + + def prevModel(self, spaz): + try: + spaz.newmesh.delete() + except AttributeError: + pass + part = list(self.cache.keys())[spaz.bodyindex] + spaz.meshindex = (spaz.meshindex-1)%len(self.cache[part]) + mesh = self.cache[part][spaz.meshindex] + spaz.newmesh = bs.newnode( + 'text', + owner=spaz.node, + attrs={ + 'text': str(mesh), + 'in_world': True, + 'color':(1,1,1), + 'scale': 0.011, + 'shadow': 0.5, + 'flatness': 0.5, + 'h_align': 'center' + }) + math = bs.newnode('math', + owner=spaz.node, + attrs={ + 'input1': (0,-0.6,0.5), + 'operation': 'add', + }) + spaz.node.connectattr('position', math, 'input2') + math.connectattr('output', spaz.newmesh, 'position') + if part == "main_color": + self.setColor(spaz,mesh) + elif part == "highlight_color": + self.setHighlight(spaz,mesh) + else: + self.setModel(spaz,part,mesh) + bs.getsound('click01').play() + + def setColor(self, spaz, color): + spaz.node.color = color + + def setHighlight(self, spaz, highlight): + spaz.node.highlight = highlight + + def setModel(self, spaz, bodypart, meshname): + if bodypart=='head': + spaz.node.head_mesh = bs.getmesh(meshname) + elif bodypart=='torso': + spaz.node.torso_mesh = bs.getmesh(meshname) + elif bodypart=='pelvis': + spaz.node.pelvis_mesh = bs.getmesh(meshname) + elif bodypart=='upper_arm': + spaz.node.upper_arm_mesh = bs.getmesh(meshname) + elif bodypart=='forearm': + spaz.node.forearm_mesh = bs.getmesh(meshname) + elif bodypart=='hand': + spaz.node.hand_mesh = bs.getmesh(meshname) + elif bodypart=='upper_leg': + spaz.node.upper_leg_mesh = bs.getmesh(meshname) + elif bodypart=='lower_leg': + spaz.node.lower_leg_mesh = bs.getmesh(meshname) + elif bodypart=='toes_mesh': + spaz.node.toes_mesh = bs.getmesh(meshname) + elif bodypart=='style': + spaz.node.style = meshname + elif bodypart=='color_texture': + spaz.node.color_texture = bs.gettexture(meshname) + elif bodypart=='color_mask': + spaz.node.color_mask_texture = bs.gettexture(meshname) + + def spawn_player(self, player): + spaz = self.spawn_player_spaz(player) + spaz.bodyindex=0 + spaz.meshindex=0 + spaz.bodypart= bs.newnode( + 'text', + owner=spaz.node, + attrs={ + 'text': "", + 'in_world': True, + 'scale': 0.011, + 'color': (1, 0.4, 0.9, 1), + 'h_align': 'center', + 'shadow': 0.7, + 'flatness': 0.5, + }) + math = bs.newnode('math', + owner=spaz.node, + attrs={ + 'input1': (0,1.7,0.5), + 'operation': 'add', + }) + spaz.node.connectattr('position', math, 'input2') + math.connectattr('output', spaz.bodypart, 'position') + spaz.newmesh = bs.newnode( + 'text', + owner=spaz.node, + attrs={ + 'text': "", + 'in_world': True, + 'scale': 0.011, + 'color': (1, 0.4, 0.9, 1), + 'h_align': 'center', + 'shadow': 0.7, + 'flatness': 0.5, + }) + math = bs.newnode('math', + owner=spaz.node, + attrs={ + 'input1': (0,-0.6,0.5), + 'operation': 'add', + }) + spaz.node.connectattr('position', math, 'input2') + math.connectattr('output', spaz.newmesh, 'position') + + # Let's reconnect this player's controls to this + # spaz but *without* the ability to attack or pick stuff up. + # spaz.connect_controls_to_player(enable_punch=False, + # enable_jump=False, + # enable_bomb=False, + # enable_pickup=False) + + intp = babase.InputType + player.assigninput(intp.JUMP_PRESS, lambda: self.nextBodyPart(spaz)) + player.assigninput(intp.PICK_UP_PRESS, lambda: self.prevBodyPart(spaz)) + player.assigninput(intp.PUNCH_PRESS, lambda: self.nextModel(spaz)) + player.assigninput(intp.BOMB_PRESS, lambda: self.prevModel(spaz)) + # Also lets have them make some noise when they die. + spaz.play_big_death_sound = True + return spaz + + def handlemessage(self, msg): + if isinstance(msg, bs.PlayerDiedMessage): + # Augment standard behavior. + super().handlemessage(msg) + player = msg.getplayer(Player) + self.respawn_player(player) + else: + return super().handlemessage(msg) + return None + + def _update_scoreboard(self): + for team in self.teams: + self._scoreboard.set_team_value(team, team.score, + self._score_to_win) + + def end_game(self): + results = bs.GameResults() + for team in self.teams: + results.set_team_score(team, team.score) + self.end(results=results) + + def initialize_meshs(self): + self.cache = { + "head" : ["bomb","landMine","wing","eyeLid","impactBomb"], + "hand" : ["hairTuft3","bomb","powerup"], + "torso" : ["bomb","landMine","bomb"], + "pelvis" : ["hairTuft4","bomb"], + "upper_arm" : ["wing","locator","bomb"], + "forearm" : ["flagPole","bomb"], + "upper_leg" : ["bomb"], + "lower_leg" : ["bomb"], + "toes_mesh" : ["bomb"], + "style" : ["spaz","female","ninja","kronk","mel","pirate","santa","frosty","bones","bear","penguin","ali","cyborg","agent","pixie","bunny"], + "color_texture": ["kronk","egg1","egg2","egg3","achievementGotTheMoves","bombColor","crossOut","explosion","rgbStripes","powerupCurse","powerupHealth","impactBombColorLit"], + "color_mask" : ["egg1","egg2","egg3","bombColor","crossOutMask","fontExtras3"], + "main_color" : [(0,0,0),(1,0,0),(0,1,0),(0,0,1),(1,1,0),(1,0,1),(0,1,1),(1,1,1)], + "highlight_color" : [(0,0,0),(1,0,0),(0,1,0),(0,0,1),(1,1,0),(1,0,1),(0,1,1),(1,1,1)], + } + chars = ["neoSpaz","zoe","ninja","kronk","mel","jack","santa","frosty","bones","bear","penguin","ali","cyborg","agent","wizard","pixie","bunny"] + + for char in chars: + self.cache["head"].append(char + "Head") + self.cache["hand"].append(char + "Hand") + self.cache["torso"].append(char + "Torso") + if char not in ['mel',"jack","santa"]: + self.cache["pelvis"].append(char + "Pelvis") + self.cache["upper_arm"].append(char + "UpperArm") + self.cache["forearm"].append(char + "ForeArm") + self.cache["upper_leg"].append(char + "UpperLeg") + self.cache["lower_leg"].append(char + "LowerLeg") + self.cache["toes_mesh"].append(char + "Toes") + self.cache["color_mask"].append(char + "ColorMask") + if char !="kronk": + self.cache["color_texture"].append(char + "Color") + + +def mesh_to_string(mesh): + return str(mesh)[17:-2] + + +def texture_to_string(texture): + return str(texture)[20:-2] + + +def spaz_to_json(spaz): + spaz_json = copy.deepcopy(SPAZ_PRESET) + spaz_json['head'] = mesh_to_string(spaz.node.head_mesh) + spaz_json['hand'] = mesh_to_string(spaz.node.hand_mesh) + spaz_json['torso'] = mesh_to_string(spaz.node.torso_mesh) + spaz_json['pelvis'] = mesh_to_string(spaz.node.pelvis_mesh) + spaz_json['upper_arm'] = mesh_to_string(spaz.node.upper_arm_mesh) + spaz_json['forearm'] = mesh_to_string(spaz.node.forearm_mesh) + spaz_json['upper_leg'] = mesh_to_string(spaz.node.upper_leg_mesh) + spaz_json['lower_leg'] = mesh_to_string(spaz.node.lower_leg_mesh) + spaz_json['toes_mesh'] = mesh_to_string(spaz.node.toes_mesh) + spaz_json['style'] = spaz.node.style + spaz_json['color_mask'] = texture_to_string(spaz.node.color_mask_texture) + spaz_json['color_texture'] = texture_to_string(spaz.node.color_texture) + return spaz_json + + +def import_character(name, spaz): + if not name: + bs.screenmessage("Inavlid character name") + return + character = None + for appearance_name, appearance_character in bs.app.classic.spaz_appearances.items(): + if name.lower() == appearance_name.lower(): + character = appearance_character + break + if not character: + return (False, name) + activity = bs.get_foreground_host_activity() + with activity.context: + spaz.node.head_mesh = bs.getmesh(character.head_mesh) + spaz.node.hand_mesh = bs.getmesh(character.hand_mesh) + spaz.node.torso_mesh = bs.getmesh(character.torso_mesh) + spaz.node.pelvis_mesh = bs.getmesh(character.pelvis_mesh) + spaz.node.upper_arm_mesh = bs.getmesh(character.upper_arm_mesh) + spaz.node.forearm_mesh = bs.getmesh(character.forearm_mesh) + spaz.node.upper_leg_mesh = bs.getmesh(character.upper_leg_mesh) + spaz.node.lower_leg_mesh = bs.getmesh(character.lower_leg_mesh) + spaz.node.toes_mesh = bs.getmesh(character.toes_mesh) + spaz.node.style = character.style + spaz.node.color_mask_texture = bs.gettexture(character.color_mask_texture) + spaz.node.color_texture = bs.gettexture(character.color_texture) + return (True, appearance_name) + + +def export_character(name, spaz): + default_characters = tuple(bs.app.classic.spaz_appearances.keys())[:30] + os.makedirs(CUSTOM_CHARACTERS, exist_ok=True) + character_file = name + ".json" + for saved_character_file in os.listdir(CUSTOM_CHARACTERS): + if character_file.lower() == saved_character_file.lower(): + return (False, os.path.splitext(saved_character_file)[0]) + for default_character in default_characters: + if name.lower() == default_character.lower(): + return (False, default_character) + spaz_json = spaz_to_json(spaz) + with open(os.path.join(CUSTOM_CHARACTERS, character_file), "w") as fout: + json.dump(spaz_json, fout, indent=4) + register_character_json(name, spaz_json) + return (True, name) + + +def register_character_json(name, character): + appearance = Appearance(name) + appearance.color_texture = character['color_texture'] + appearance.color_mask_texture = character['color_mask'] + appearance.default_color = (0.6, 0.6, 0.6) + appearance.default_highlight = (0, 1, 0) + appearance.icon_texture = character['icon_texture'] + appearance.icon_mask_texture = character['icon_mask_texture'] + appearance.head_mesh = character['head'] + appearance.torso_mesh = character['torso'] + appearance.pelvis_mesh = character['pelvis'] + appearance.upper_arm_mesh = character['upper_arm'] + appearance.forearm_mesh = character['forearm'] + appearance.hand_mesh = character['hand'] + appearance.upper_leg_mesh = character['upper_leg'] + appearance.lower_leg_mesh = character['lower_leg'] + appearance.toes_mesh = character['toes_mesh'] + appearance.jump_sounds = character['jump_sounds'] + appearance.attack_sounds = character['attack_sounds'] + appearance.impact_sounds = character['impact_sounds'] + appearance.death_sounds = character['death_sounds'] + appearance.pickup_sounds = character['pickup_sounds'] + appearance.fall_sounds = character['fall_sounds'] + appearance.style = character['style'] + +cm = bs.chatmessage +def _new_chatmessage(msg: str | babase.Lstr, *args, **kwargs): + activity = bs.get_foreground_host_activity() + if not activity: + cm(msg, *args, **kwargs) + return + + is_a_command = any(msg.startswith(command) for command in ("/export", "/import", "/info")) + if not is_a_command: + cm(msg, *args, **kwargs) + return + + player = get_player(msg, activity) + if not player: + cm("no player exists in game, try adding client id at last of command", *args, **kwargs) + cm(msg, *args, **kwargs) + return + + if msg.startswith("/export"): + if len(msg.split(" ")) > 1: + success, character_name = export_character(" ".join(msg.split(" ")[1:]), player.actor) + if success: + bs.screenmessage( + 'Exported character "{}"'.format(character_name), + color=(0,1,0) + ) + bui.getsound("gunCocking").play() + else: + bs.screenmessage( + 'Character "{}" already exists'.format(character_name), + color=(1,0,0) + ) + bui.getsound("error").play() + else: + cm("Enter name of character, Usage: /export ", *args, **kwargs) + elif msg.startswith("/import"): + if len(msg.split(" ")) > 1: + success, character_name = import_character(" ".join(msg.split(" ")[1:]), player.actor) + if success: + bs.screenmessage( + 'Imported character "{}"'.format(character_name), + color=(0,1,0) + ) + bui.getsound("gunCocking").play() + else: + bs.screenmessage( + 'Character "{}" doesn\'t exist'.format(character_name), + color=(1,0,0) + ) + bui.getsound("error").play() + else: + cm("Usage: /import ", *args, **kwargs) + elif msg.startswith("/info"): + spaz_json = spaz_to_json(player.actor) + del spaz_json["jump_sounds"] + del spaz_json["attack_sounds"] + del spaz_json["impact_sounds"] + del spaz_json["death_sounds"] + del spaz_json["pickup_sounds"] + del spaz_json["fall_sounds"] + spaz_str = "" + for key, value in spaz_json.items(): + spaz_str += "{}: {}\n".format(key, value) + bs.screenmessage(spaz_str, color=(1,1,1)) + + cm(msg, *args, **kwargs) + +bs.chatmessage = _new_chatmessage + +def get_player(msg, activity): + client_id = -1 + words = msg.split(" ") + last_word = words[-1] + if last_word.isdigit(): + client_id = int(last_word) + for player in activity.players: + player_client_id = player.sessionplayer.inputdevice.client_id + if client_id == player_client_id: + return player + +# ba_meta export plugin +class bySmoothy(babase.Plugin): + def __init__(self): + bui.set_party_icon_always_visible(True) + _babase.import_character = import_character + _babase.export_character = export_character + _babase.spaz_to_json = spaz_to_json + character_files = os.listdir(CUSTOM_CHARACTERS) + for character_file in character_files: + if character_file.lower().endswith(".json"): + name, _ = os.path.splitext(character_file) + with open(os.path.join(CUSTOM_CHARACTERS, character_file), "r") as fin: + character = json.load(fin) + register_character_json(name, character) + From f7ae8062955fb9a358263d98fd666f2b78d079eb Mon Sep 17 00:00:00 2001 From: rikkolovescats Date: Thu, 3 Aug 2023 15:21:30 +0000 Subject: [PATCH 0687/1464] [ci] auto-format --- plugins/utilities/character_maker.py | 417 ++++++++++++++------------- 1 file changed, 212 insertions(+), 205 deletions(-) diff --git a/plugins/utilities/character_maker.py b/plugins/utilities/character_maker.py index 0aded4f7..7a3e7ecd 100644 --- a/plugins/utilities/character_maker.py +++ b/plugins/utilities/character_maker.py @@ -60,28 +60,29 @@ SPAZ_PRESET = { - "color_mask" : "neoSpazColorMask", - "color_texture" : "neoSpazColor", - "head" : "neoSpazHead", - "hand" : "neoSpazHand", - "torso" : "neoSpazTorso", - "pelvis" : "neoSpazTorso", - "upper_arm" : "neoSpazUpperArm", - "forearm" : "neoSpazForeArm", - "upper_leg" : "neoSpazUpperLeg", - "lower_leg" : "neoSpazLowerLeg", - "toes_mesh" : "neoSpazToes", - "jump_sounds" : ['spazJump01', 'spazJump02', 'spazJump03', 'spazJump04'], - "attack_sounds" : ['spazAttack01', 'spazAttack02', 'spazAttack03', 'spazAttack04'], - "impact_sounds" : ['spazImpact01', 'spazImpact02', 'spazImpact03', 'spazImpact04'], - "death_sounds" : ['spazDeath01'], - "pickup_sounds" : ['spazPickup01'], - "fall_sounds" : ['spazFall01'], - "icon_texture" : "neoSpazIcon", + "color_mask": "neoSpazColorMask", + "color_texture": "neoSpazColor", + "head": "neoSpazHead", + "hand": "neoSpazHand", + "torso": "neoSpazTorso", + "pelvis": "neoSpazTorso", + "upper_arm": "neoSpazUpperArm", + "forearm": "neoSpazForeArm", + "upper_leg": "neoSpazUpperLeg", + "lower_leg": "neoSpazLowerLeg", + "toes_mesh": "neoSpazToes", + "jump_sounds": ['spazJump01', 'spazJump02', 'spazJump03', 'spazJump04'], + "attack_sounds": ['spazAttack01', 'spazAttack02', 'spazAttack03', 'spazAttack04'], + "impact_sounds": ['spazImpact01', 'spazImpact02', 'spazImpact03', 'spazImpact04'], + "death_sounds": ['spazDeath01'], + "pickup_sounds": ['spazPickup01'], + "fall_sounds": ['spazFall01'], + "icon_texture": "neoSpazIcon", "icon_mask_texture": "neoSpazIconColorMask", - "style" : "spaz" + "style": "spaz" } + class Player(bs.Player['Team']): """Our player type for this game.""" @@ -123,7 +124,7 @@ def get_available_settings(cls, sessiontype): ('20 Minutes', 1200), ], default=0, - ), + ), bs.FloatChoiceSetting( 'Respawn Times', choices=[ @@ -169,9 +170,9 @@ def __init__(self, settings): self._punch_image = Image( bs.gettexture('buttonPunch'), - position=(345,200), - scale=(50,50), - color= (0.9,0.9,0,0.9) + position=(345, 200), + scale=(50, 50), + color=(0.9, 0.9, 0, 0.9) ) self._punch_text = Text( "Model+", @@ -179,13 +180,13 @@ def __init__(self, settings): shadow=0.5, flatness=0.5, color=(0.9, 0.9, 0, 0.9), - position=(263,190)) + position=(263, 190)) self._grab_image = Image( bs.gettexture('buttonPickUp'), - position=(385,240), - scale=(50,50), - color= (0,0.7,0.9) + position=(385, 240), + scale=(50, 50), + color=(0, 0.7, 0.9) ) self._grab_text = Text( "Component-", @@ -193,13 +194,13 @@ def __init__(self, settings): shadow=0.5, flatness=0.5, color=(0, 0.7, 1, 0.9), - position=(340,265)) + position=(340, 265)) self._jump_image = Image( bs.gettexture('buttonJump'), - position=(385,160), - scale=(50,50), - color= (0.2,0.9,0.2,0.9) + position=(385, 160), + scale=(50, 50), + color=(0.2, 0.9, 0.2, 0.9) ) self._jump_text = Text( "Component+", @@ -207,13 +208,13 @@ def __init__(self, settings): shadow=0.5, flatness=0.5, color=(0.2, 0.9, 0.2, 0.9), - position=(340,113)) + position=(340, 113)) self._bomb_image = Image( bs.gettexture('buttonBomb'), - position=(425,200), - scale=(50,50), - color= (0.9,0.2,0.2,0.9) + position=(425, 200), + scale=(50, 50), + color=(0.9, 0.2, 0.2, 0.9) ) self._bomb_text = Text( "Model-", @@ -221,8 +222,7 @@ def __init__(self, settings): shadow=0.5, flatness=0.5, color=(0.9, 0.2, 0.2, 0.9), - position=(452,190)) - + position=(452, 190)) self._host = Text( "Originally created by \ue020HeySmoothy\nhttps://youtu.be/q0KxY1hfMPQ\nhttps://youtu.be/3l2dxWEhrzE\n\nModified for multiplayer by \ue047Nyaa! :3", @@ -290,57 +290,57 @@ def on_begin(self): super().on_begin() def nextBodyPart(self, spaz): - spaz.bodyindex = (spaz.bodyindex+1)%len(self.cache.keys()) + spaz.bodyindex = (spaz.bodyindex+1) % len(self.cache.keys()) try: spaz.bodypart.delete() except AttributeError: pass part = list(self.cache.keys())[spaz.bodyindex] spaz.bodypart = bs.newnode( - 'text', - owner=spaz.node, - attrs={ - 'text': str(part), - 'in_world': True, - 'color':(1,1,1), - 'scale': 0.011, - 'shadow': 0.5, - 'flatness': 0.5, - 'h_align': 'center',}) - math = bs.newnode('math', + 'text', owner=spaz.node, attrs={ - 'input1': (0,1.7,0.5), - 'operation': 'add', - }) + 'text': str(part), + 'in_world': True, + 'color': (1, 1, 1), + 'scale': 0.011, + 'shadow': 0.5, + 'flatness': 0.5, + 'h_align': 'center', }) + math = bs.newnode('math', + owner=spaz.node, + attrs={ + 'input1': (0, 1.7, 0.5), + 'operation': 'add', + }) spaz.node.connectattr('position', math, 'input2') math.connectattr('output', spaz.bodypart, 'position') bs.getsound('deek').play() def prevBodyPart(self, spaz): - spaz.bodyindex = (spaz.bodyindex-1)%len(self.cache.keys()) + spaz.bodyindex = (spaz.bodyindex-1) % len(self.cache.keys()) try: spaz.bodypart.delete() except AttributeError: pass - part=list(self.cache.keys())[spaz.bodyindex] - spaz.bodypart=bs.newnode( - 'text', - owner=spaz.node, - attrs={ - 'text': str(part), - 'in_world': True, - 'color':(1,1,1), - 'scale': 0.011, - 'shadow': 0.5, - 'flatness': 0.5, - 'h_align': 'center',}) - math = bs.newnode('math', + part = list(self.cache.keys())[spaz.bodyindex] + spaz.bodypart = bs.newnode( + 'text', owner=spaz.node, attrs={ - 'input1': (0,1.7,0.5), - 'operation': 'add', - }) + 'text': str(part), + 'in_world': True, + 'color': (1, 1, 1), + 'scale': 0.011, + 'shadow': 0.5, + 'flatness': 0.5, + 'h_align': 'center', }) + math = bs.newnode('math', + owner=spaz.node, + attrs={ + 'input1': (0, 1.7, 0.5), + 'operation': 'add', + }) spaz.node.connectattr('position', math, 'input2') math.connectattr('output', spaz.bodypart, 'position') bs.getsound('deek').play() @@ -351,7 +351,7 @@ def nextModel(self, spaz): except AttributeError: pass part = list(self.cache.keys())[spaz.bodyindex] - spaz.meshindex = (spaz.meshindex+1)%len(self.cache[part]) + spaz.meshindex = (spaz.meshindex+1) % len(self.cache[part]) mesh = self.cache[part][spaz.meshindex] spaz.newmesh = bs.newnode( 'text', @@ -359,26 +359,26 @@ def nextModel(self, spaz): attrs={ 'text': str(mesh), 'in_world': True, - 'color':(1,1,1), + 'color': (1, 1, 1), 'scale': 0.011, 'shadow': 0.5, 'flatness': 0.5, 'h_align': 'center' }) math = bs.newnode('math', - owner=spaz.node, - attrs={ - 'input1': (0,-0.6,0.5), - 'operation': 'add', - }) + owner=spaz.node, + attrs={ + 'input1': (0, -0.6, 0.5), + 'operation': 'add', + }) spaz.node.connectattr('position', math, 'input2') math.connectattr('output', spaz.newmesh, 'position') if part == "main_color": - self.setColor(spaz,mesh) + self.setColor(spaz, mesh) elif part == "highlight_color": - self.setHighlight(spaz,mesh) + self.setHighlight(spaz, mesh) else: - self.setModel(spaz,part,mesh) + self.setModel(spaz, part, mesh) bs.getsound('click01').play() def prevModel(self, spaz): @@ -387,7 +387,7 @@ def prevModel(self, spaz): except AttributeError: pass part = list(self.cache.keys())[spaz.bodyindex] - spaz.meshindex = (spaz.meshindex-1)%len(self.cache[part]) + spaz.meshindex = (spaz.meshindex-1) % len(self.cache[part]) mesh = self.cache[part][spaz.meshindex] spaz.newmesh = bs.newnode( 'text', @@ -395,26 +395,26 @@ def prevModel(self, spaz): attrs={ 'text': str(mesh), 'in_world': True, - 'color':(1,1,1), + 'color': (1, 1, 1), 'scale': 0.011, 'shadow': 0.5, 'flatness': 0.5, 'h_align': 'center' }) math = bs.newnode('math', - owner=spaz.node, - attrs={ - 'input1': (0,-0.6,0.5), - 'operation': 'add', - }) + owner=spaz.node, + attrs={ + 'input1': (0, -0.6, 0.5), + 'operation': 'add', + }) spaz.node.connectattr('position', math, 'input2') math.connectattr('output', spaz.newmesh, 'position') if part == "main_color": - self.setColor(spaz,mesh) + self.setColor(spaz, mesh) elif part == "highlight_color": - self.setHighlight(spaz,mesh) + self.setHighlight(spaz, mesh) else: - self.setModel(spaz,part,mesh) + self.setModel(spaz, part, mesh) bs.getsound('click01').play() def setColor(self, spaz, color): @@ -424,73 +424,73 @@ def setHighlight(self, spaz, highlight): spaz.node.highlight = highlight def setModel(self, spaz, bodypart, meshname): - if bodypart=='head': + if bodypart == 'head': spaz.node.head_mesh = bs.getmesh(meshname) - elif bodypart=='torso': + elif bodypart == 'torso': spaz.node.torso_mesh = bs.getmesh(meshname) - elif bodypart=='pelvis': + elif bodypart == 'pelvis': spaz.node.pelvis_mesh = bs.getmesh(meshname) - elif bodypart=='upper_arm': + elif bodypart == 'upper_arm': spaz.node.upper_arm_mesh = bs.getmesh(meshname) - elif bodypart=='forearm': + elif bodypart == 'forearm': spaz.node.forearm_mesh = bs.getmesh(meshname) - elif bodypart=='hand': + elif bodypart == 'hand': spaz.node.hand_mesh = bs.getmesh(meshname) - elif bodypart=='upper_leg': + elif bodypart == 'upper_leg': spaz.node.upper_leg_mesh = bs.getmesh(meshname) - elif bodypart=='lower_leg': + elif bodypart == 'lower_leg': spaz.node.lower_leg_mesh = bs.getmesh(meshname) - elif bodypart=='toes_mesh': + elif bodypart == 'toes_mesh': spaz.node.toes_mesh = bs.getmesh(meshname) - elif bodypart=='style': + elif bodypart == 'style': spaz.node.style = meshname - elif bodypart=='color_texture': + elif bodypart == 'color_texture': spaz.node.color_texture = bs.gettexture(meshname) - elif bodypart=='color_mask': + elif bodypart == 'color_mask': spaz.node.color_mask_texture = bs.gettexture(meshname) def spawn_player(self, player): spaz = self.spawn_player_spaz(player) - spaz.bodyindex=0 - spaz.meshindex=0 - spaz.bodypart= bs.newnode( - 'text', - owner=spaz.node, - attrs={ - 'text': "", - 'in_world': True, - 'scale': 0.011, - 'color': (1, 0.4, 0.9, 1), - 'h_align': 'center', - 'shadow': 0.7, - 'flatness': 0.5, - }) - math = bs.newnode('math', + spaz.bodyindex = 0 + spaz.meshindex = 0 + spaz.bodypart = bs.newnode( + 'text', owner=spaz.node, attrs={ - 'input1': (0,1.7,0.5), - 'operation': 'add', + 'text': "", + 'in_world': True, + 'scale': 0.011, + 'color': (1, 0.4, 0.9, 1), + 'h_align': 'center', + 'shadow': 0.7, + 'flatness': 0.5, }) + math = bs.newnode('math', + owner=spaz.node, + attrs={ + 'input1': (0, 1.7, 0.5), + 'operation': 'add', + }) spaz.node.connectattr('position', math, 'input2') math.connectattr('output', spaz.bodypart, 'position') spaz.newmesh = bs.newnode( - 'text', - owner=spaz.node, - attrs={ - 'text': "", - 'in_world': True, - 'scale': 0.011, - 'color': (1, 0.4, 0.9, 1), - 'h_align': 'center', - 'shadow': 0.7, - 'flatness': 0.5, - }) - math = bs.newnode('math', + 'text', owner=spaz.node, attrs={ - 'input1': (0,-0.6,0.5), - 'operation': 'add', + 'text': "", + 'in_world': True, + 'scale': 0.011, + 'color': (1, 0.4, 0.9, 1), + 'h_align': 'center', + 'shadow': 0.7, + 'flatness': 0.5, }) + math = bs.newnode('math', + owner=spaz.node, + attrs={ + 'input1': (0, -0.6, 0.5), + 'operation': 'add', + }) spaz.node.connectattr('position', math, 'input2') math.connectattr('output', spaz.newmesh, 'position') @@ -533,28 +533,29 @@ def end_game(self): def initialize_meshs(self): self.cache = { - "head" : ["bomb","landMine","wing","eyeLid","impactBomb"], - "hand" : ["hairTuft3","bomb","powerup"], - "torso" : ["bomb","landMine","bomb"], - "pelvis" : ["hairTuft4","bomb"], - "upper_arm" : ["wing","locator","bomb"], - "forearm" : ["flagPole","bomb"], - "upper_leg" : ["bomb"], - "lower_leg" : ["bomb"], - "toes_mesh" : ["bomb"], - "style" : ["spaz","female","ninja","kronk","mel","pirate","santa","frosty","bones","bear","penguin","ali","cyborg","agent","pixie","bunny"], - "color_texture": ["kronk","egg1","egg2","egg3","achievementGotTheMoves","bombColor","crossOut","explosion","rgbStripes","powerupCurse","powerupHealth","impactBombColorLit"], - "color_mask" : ["egg1","egg2","egg3","bombColor","crossOutMask","fontExtras3"], - "main_color" : [(0,0,0),(1,0,0),(0,1,0),(0,0,1),(1,1,0),(1,0,1),(0,1,1),(1,1,1)], - "highlight_color" : [(0,0,0),(1,0,0),(0,1,0),(0,0,1),(1,1,0),(1,0,1),(0,1,1),(1,1,1)], + "head": ["bomb", "landMine", "wing", "eyeLid", "impactBomb"], + "hand": ["hairTuft3", "bomb", "powerup"], + "torso": ["bomb", "landMine", "bomb"], + "pelvis": ["hairTuft4", "bomb"], + "upper_arm": ["wing", "locator", "bomb"], + "forearm": ["flagPole", "bomb"], + "upper_leg": ["bomb"], + "lower_leg": ["bomb"], + "toes_mesh": ["bomb"], + "style": ["spaz", "female", "ninja", "kronk", "mel", "pirate", "santa", "frosty", "bones", "bear", "penguin", "ali", "cyborg", "agent", "pixie", "bunny"], + "color_texture": ["kronk", "egg1", "egg2", "egg3", "achievementGotTheMoves", "bombColor", "crossOut", "explosion", "rgbStripes", "powerupCurse", "powerupHealth", "impactBombColorLit"], + "color_mask": ["egg1", "egg2", "egg3", "bombColor", "crossOutMask", "fontExtras3"], + "main_color": [(0, 0, 0), (1, 0, 0), (0, 1, 0), (0, 0, 1), (1, 1, 0), (1, 0, 1), (0, 1, 1), (1, 1, 1)], + "highlight_color": [(0, 0, 0), (1, 0, 0), (0, 1, 0), (0, 0, 1), (1, 1, 0), (1, 0, 1), (0, 1, 1), (1, 1, 1)], } - chars = ["neoSpaz","zoe","ninja","kronk","mel","jack","santa","frosty","bones","bear","penguin","ali","cyborg","agent","wizard","pixie","bunny"] + chars = ["neoSpaz", "zoe", "ninja", "kronk", "mel", "jack", "santa", "frosty", + "bones", "bear", "penguin", "ali", "cyborg", "agent", "wizard", "pixie", "bunny"] for char in chars: self.cache["head"].append(char + "Head") self.cache["hand"].append(char + "Hand") self.cache["torso"].append(char + "Torso") - if char not in ['mel',"jack","santa"]: + if char not in ['mel', "jack", "santa"]: self.cache["pelvis"].append(char + "Pelvis") self.cache["upper_arm"].append(char + "UpperArm") self.cache["forearm"].append(char + "ForeArm") @@ -562,7 +563,7 @@ def initialize_meshs(self): self.cache["lower_leg"].append(char + "LowerLeg") self.cache["toes_mesh"].append(char + "Toes") self.cache["color_mask"].append(char + "ColorMask") - if char !="kronk": + if char != "kronk": self.cache["color_texture"].append(char + "Color") @@ -576,17 +577,17 @@ def texture_to_string(texture): def spaz_to_json(spaz): spaz_json = copy.deepcopy(SPAZ_PRESET) - spaz_json['head'] = mesh_to_string(spaz.node.head_mesh) - spaz_json['hand'] = mesh_to_string(spaz.node.hand_mesh) - spaz_json['torso'] = mesh_to_string(spaz.node.torso_mesh) - spaz_json['pelvis'] = mesh_to_string(spaz.node.pelvis_mesh) - spaz_json['upper_arm'] = mesh_to_string(spaz.node.upper_arm_mesh) - spaz_json['forearm'] = mesh_to_string(spaz.node.forearm_mesh) - spaz_json['upper_leg'] = mesh_to_string(spaz.node.upper_leg_mesh) - spaz_json['lower_leg'] = mesh_to_string(spaz.node.lower_leg_mesh) - spaz_json['toes_mesh'] = mesh_to_string(spaz.node.toes_mesh) - spaz_json['style'] = spaz.node.style - spaz_json['color_mask'] = texture_to_string(spaz.node.color_mask_texture) + spaz_json['head'] = mesh_to_string(spaz.node.head_mesh) + spaz_json['hand'] = mesh_to_string(spaz.node.hand_mesh) + spaz_json['torso'] = mesh_to_string(spaz.node.torso_mesh) + spaz_json['pelvis'] = mesh_to_string(spaz.node.pelvis_mesh) + spaz_json['upper_arm'] = mesh_to_string(spaz.node.upper_arm_mesh) + spaz_json['forearm'] = mesh_to_string(spaz.node.forearm_mesh) + spaz_json['upper_leg'] = mesh_to_string(spaz.node.upper_leg_mesh) + spaz_json['lower_leg'] = mesh_to_string(spaz.node.lower_leg_mesh) + spaz_json['toes_mesh'] = mesh_to_string(spaz.node.toes_mesh) + spaz_json['style'] = spaz.node.style + spaz_json['color_mask'] = texture_to_string(spaz.node.color_mask_texture) spaz_json['color_texture'] = texture_to_string(spaz.node.color_texture) return spaz_json @@ -604,18 +605,18 @@ def import_character(name, spaz): return (False, name) activity = bs.get_foreground_host_activity() with activity.context: - spaz.node.head_mesh = bs.getmesh(character.head_mesh) - spaz.node.hand_mesh = bs.getmesh(character.hand_mesh) - spaz.node.torso_mesh = bs.getmesh(character.torso_mesh) - spaz.node.pelvis_mesh = bs.getmesh(character.pelvis_mesh) - spaz.node.upper_arm_mesh = bs.getmesh(character.upper_arm_mesh) - spaz.node.forearm_mesh = bs.getmesh(character.forearm_mesh) - spaz.node.upper_leg_mesh = bs.getmesh(character.upper_leg_mesh) - spaz.node.lower_leg_mesh = bs.getmesh(character.lower_leg_mesh) - spaz.node.toes_mesh = bs.getmesh(character.toes_mesh) - spaz.node.style = character.style - spaz.node.color_mask_texture = bs.gettexture(character.color_mask_texture) - spaz.node.color_texture = bs.gettexture(character.color_texture) + spaz.node.head_mesh = bs.getmesh(character.head_mesh) + spaz.node.hand_mesh = bs.getmesh(character.hand_mesh) + spaz.node.torso_mesh = bs.getmesh(character.torso_mesh) + spaz.node.pelvis_mesh = bs.getmesh(character.pelvis_mesh) + spaz.node.upper_arm_mesh = bs.getmesh(character.upper_arm_mesh) + spaz.node.forearm_mesh = bs.getmesh(character.forearm_mesh) + spaz.node.upper_leg_mesh = bs.getmesh(character.upper_leg_mesh) + spaz.node.lower_leg_mesh = bs.getmesh(character.lower_leg_mesh) + spaz.node.toes_mesh = bs.getmesh(character.toes_mesh) + spaz.node.style = character.style + spaz.node.color_mask_texture = bs.gettexture(character.color_mask_texture) + spaz.node.color_texture = bs.gettexture(character.color_texture) return (True, appearance_name) @@ -637,31 +638,34 @@ def export_character(name, spaz): def register_character_json(name, character): - appearance = Appearance(name) - appearance.color_texture = character['color_texture'] + appearance = Appearance(name) + appearance.color_texture = character['color_texture'] appearance.color_mask_texture = character['color_mask'] - appearance.default_color = (0.6, 0.6, 0.6) - appearance.default_highlight = (0, 1, 0) - appearance.icon_texture = character['icon_texture'] - appearance.icon_mask_texture = character['icon_mask_texture'] - appearance.head_mesh = character['head'] - appearance.torso_mesh = character['torso'] - appearance.pelvis_mesh = character['pelvis'] - appearance.upper_arm_mesh = character['upper_arm'] - appearance.forearm_mesh = character['forearm'] - appearance.hand_mesh = character['hand'] - appearance.upper_leg_mesh = character['upper_leg'] - appearance.lower_leg_mesh = character['lower_leg'] - appearance.toes_mesh = character['toes_mesh'] - appearance.jump_sounds = character['jump_sounds'] - appearance.attack_sounds = character['attack_sounds'] - appearance.impact_sounds = character['impact_sounds'] - appearance.death_sounds = character['death_sounds'] - appearance.pickup_sounds = character['pickup_sounds'] - appearance.fall_sounds = character['fall_sounds'] - appearance.style = character['style'] + appearance.default_color = (0.6, 0.6, 0.6) + appearance.default_highlight = (0, 1, 0) + appearance.icon_texture = character['icon_texture'] + appearance.icon_mask_texture = character['icon_mask_texture'] + appearance.head_mesh = character['head'] + appearance.torso_mesh = character['torso'] + appearance.pelvis_mesh = character['pelvis'] + appearance.upper_arm_mesh = character['upper_arm'] + appearance.forearm_mesh = character['forearm'] + appearance.hand_mesh = character['hand'] + appearance.upper_leg_mesh = character['upper_leg'] + appearance.lower_leg_mesh = character['lower_leg'] + appearance.toes_mesh = character['toes_mesh'] + appearance.jump_sounds = character['jump_sounds'] + appearance.attack_sounds = character['attack_sounds'] + appearance.impact_sounds = character['impact_sounds'] + appearance.death_sounds = character['death_sounds'] + appearance.pickup_sounds = character['pickup_sounds'] + appearance.fall_sounds = character['fall_sounds'] + appearance.style = character['style'] + cm = bs.chatmessage + + def _new_chatmessage(msg: str | babase.Lstr, *args, **kwargs): activity = bs.get_foreground_host_activity() if not activity: @@ -681,34 +685,34 @@ def _new_chatmessage(msg: str | babase.Lstr, *args, **kwargs): if msg.startswith("/export"): if len(msg.split(" ")) > 1: - success, character_name = export_character(" ".join(msg.split(" ")[1:]), player.actor) + success, character_name = export_character(" ".join(msg.split(" ")[1:]), player.actor) if success: bs.screenmessage( 'Exported character "{}"'.format(character_name), - color=(0,1,0) + color=(0, 1, 0) ) bui.getsound("gunCocking").play() else: bs.screenmessage( 'Character "{}" already exists'.format(character_name), - color=(1,0,0) + color=(1, 0, 0) ) bui.getsound("error").play() else: cm("Enter name of character, Usage: /export ", *args, **kwargs) elif msg.startswith("/import"): if len(msg.split(" ")) > 1: - success, character_name = import_character(" ".join(msg.split(" ")[1:]), player.actor) + success, character_name = import_character(" ".join(msg.split(" ")[1:]), player.actor) if success: bs.screenmessage( 'Imported character "{}"'.format(character_name), - color=(0,1,0) + color=(0, 1, 0) ) bui.getsound("gunCocking").play() else: bs.screenmessage( 'Character "{}" doesn\'t exist'.format(character_name), - color=(1,0,0) + color=(1, 0, 0) ) bui.getsound("error").play() else: @@ -724,12 +728,14 @@ def _new_chatmessage(msg: str | babase.Lstr, *args, **kwargs): spaz_str = "" for key, value in spaz_json.items(): spaz_str += "{}: {}\n".format(key, value) - bs.screenmessage(spaz_str, color=(1,1,1)) + bs.screenmessage(spaz_str, color=(1, 1, 1)) cm(msg, *args, **kwargs) + bs.chatmessage = _new_chatmessage + def get_player(msg, activity): client_id = -1 words = msg.split(" ") @@ -737,11 +743,13 @@ def get_player(msg, activity): if last_word.isdigit(): client_id = int(last_word) for player in activity.players: - player_client_id = player.sessionplayer.inputdevice.client_id - if client_id == player_client_id: - return player + player_client_id = player.sessionplayer.inputdevice.client_id + if client_id == player_client_id: + return player # ba_meta export plugin + + class bySmoothy(babase.Plugin): def __init__(self): bui.set_party_icon_always_visible(True) @@ -755,4 +763,3 @@ def __init__(self): with open(os.path.join(CUSTOM_CHARACTERS, character_file), "r") as fin: character = json.load(fin) register_character_json(name, character) - From 9cbf91b35b2cb17ac640d9b4a8e24ff3ad7eb952 Mon Sep 17 00:00:00 2001 From: rikkolovescats Date: Thu, 3 Aug 2023 15:21:31 +0000 Subject: [PATCH 0688/1464] [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 44ac0ca7..d8e07102 100644 --- a/plugins/utilities.json +++ b/plugins/utilities.json @@ -527,7 +527,12 @@ } ], "versions": { - "2.0.0": null, + "2.0.0": { + "api_version": 8, + "commit_sha": "f7ae806", + "released_on": "03-08-2023", + "md5sum": "57e79be044430139f6218a61e3a107a4" + }, "1.0.1": { "api_version": 7, "commit_sha": "da10318", @@ -856,4 +861,4 @@ } } } -} +} \ No newline at end of file From d3df12110f1d1406bbbbc4f1519485ed538c76af Mon Sep 17 00:00:00 2001 From: ! Freaku <92618708+Freaku17@users.noreply.github.com> Date: Sat, 5 Aug 2023 19:10:03 +0530 Subject: [PATCH 0689/1464] Add new mod: Manual Camera --- plugins/utilities/manual_camera.py | 226 +++++++++++++++++++++++++++++ 1 file changed, 226 insertions(+) create mode 100644 plugins/utilities/manual_camera.py diff --git a/plugins/utilities/manual_camera.py b/plugins/utilities/manual_camera.py new file mode 100644 index 00000000..0fbab3fb --- /dev/null +++ b/plugins/utilities/manual_camera.py @@ -0,0 +1,226 @@ +# ba_meta require api 8 + +################### +# Credits - Droopy#3730. # +################### + +# Don't edit . + + +from __future__ import annotations +import _babase, babase +import bascenev1 as bs +import bauiv1 as bui +from bauiv1lib.mainmenu import MainMenuWindow + + +class Manual_camera_window: + def __init__(self): + self._root_widget = bui.containerwidget( + on_outside_click_call=None, + size=(0,0)) + button_size = (50,50) + self._text = bui.textwidget(parent=self._root_widget, + scale=0.65, + color = (0.75, 0.75, 0.75), + text='Cam Position', + size=(0, 0), + position=(500, 185), + h_align='center', + v_align='center') + self._xminus = bui.buttonwidget(parent=self._root_widget, + size=button_size, + label=babase.charstr(babase.SpecialChar.LEFT_ARROW), + button_type='square', + autoselect=True, + position=(429, 60), + on_activate_call=babase.Call(self._change_camera_position, 'x-')) + self._xplus = bui.buttonwidget(parent=self._root_widget, + size=button_size, + label=babase.charstr(babase.SpecialChar.RIGHT_ARROW), + button_type='square', + autoselect=True, + position=(538, 60), + on_activate_call=babase.Call(self._change_camera_position, 'x')) + self._yplus = bui.buttonwidget(parent=self._root_widget, + size=button_size, + label=babase.charstr(babase.SpecialChar.UP_ARROW), + button_type='square', + autoselect=True, + position=(482, 120), + on_activate_call=babase.Call(self._change_camera_position, 'y')) + self._yminus = bui.buttonwidget(parent=self._root_widget, + size=button_size, + label=babase.charstr(babase.SpecialChar.DOWN_ARROW), + button_type='square', + autoselect=True, + position=(482, 2), + on_activate_call=babase.Call(self._change_camera_position, 'y-')) + self.inwards = bui.buttonwidget(parent=self._root_widget, + size=(100,30), + label='Zoom +', + button_type='square', + autoselect=True, + position=(-550, -60), + on_activate_call=babase.Call(self._change_camera_position, 'z-')) + self._outwards = bui.buttonwidget(parent=self._root_widget, + size=(100,30), + label='Zoom -', + button_type='square', + autoselect=True, + position=(-550, -100), + on_activate_call=babase.Call(self._change_camera_position, 'z')) + self.target_text = bui.textwidget(parent=self._root_widget, + scale=0.65, + color = (0.75, 0.75, 0.75), + text='Cam Angle', + size=(0, 0), + position=(-462, 185), + h_align='center', + v_align='center') + self.target_xminus = bui.buttonwidget(parent=self._root_widget, + size=button_size, + label=babase.charstr(babase.SpecialChar.LEFT_ARROW), + button_type='square', + autoselect=True, + position=(-538, 60), + on_activate_call=babase.Call(self._change_camera_target, 'x-')) + self.target_xplus = bui.buttonwidget(parent=self._root_widget, + size=button_size, + label=babase.charstr(babase.SpecialChar.RIGHT_ARROW), + button_type='square', + autoselect=True, + position=(-429, 60), + on_activate_call=babase.Call(self._change_camera_target, 'x')) + self.target_yplus = bui.buttonwidget(parent=self._root_widget, + size=button_size, + label=babase.charstr(babase.SpecialChar.UP_ARROW), + button_type='square', + autoselect=True, + position=(-482, 120), + on_activate_call=babase.Call(self._change_camera_target, 'y')) + self.target_yminus = bui.buttonwidget(parent=self._root_widget, + size=button_size, + label=babase.charstr(babase.SpecialChar.DOWN_ARROW), + button_type='square', + autoselect=True, + position=(-482, 2), + on_activate_call=babase.Call(self._change_camera_target, 'y-')) + self._step_text = bui.textwidget(parent=self._root_widget, + scale=0.85, + color=(1,1,1), + text='Step:', + size=(0, 0), + position=(450, -38), + h_align='center', + v_align='center') + self._text_field = bui.textwidget( + parent=self._root_widget, + editable=True, + size=(100, 40), + position=(480, -55), + text='', + maxwidth=120, + flatness=1.0, + autoselect=True, + v_align='center', + corner_scale=0.7) + self._reset = bui.buttonwidget(parent=self._root_widget, + size=(50,30), + label='Reset', + button_type='square', + autoselect=True, + position=(450, -100), + on_activate_call=babase.Call(self._change_camera_position, 'reset')) + self._done = bui.buttonwidget(parent=self._root_widget, + size=(50,30), + label='Done', + button_type='square', + autoselect=True, + position=(520, -100), + on_activate_call=self._close) + bui.containerwidget(edit=self._root_widget, + cancel_button=self._done) + def _close(self): + bui.containerwidget(edit=self._root_widget, + transition=('out_scale')) + MainMenuWindow() + + def _change_camera_position(self, direction): + camera = _babase.get_camera_position() + x = camera[0] + y = camera[1] + z = camera[2] + + try: + increment = float(bui.textwidget(query=self._text_field)) + except: + increment = 1 + + if direction == 'x': + x += increment + elif direction == 'x-': + x -= increment + elif direction == 'y': + y += increment + elif direction == 'y-': + y -= increment + elif direction == 'z': + z += increment + elif direction == 'z-': + z -= increment + elif direction == 'reset': + _babase.set_camera_manual(False) + return + + _babase.set_camera_manual(True) + _babase.set_camera_position(x, y, z) + + def _change_camera_target(self, direction): + camera = _babase.get_camera_target() + x = camera[0] + y = camera[1] + z = camera[2] + + try: + increment = float(bui.textwidget(query=self._text_field)) + except: + increment = 1 + + if direction == 'x': + x += increment + elif direction == 'x-': + x -= increment + elif direction == 'y': + y += increment + elif direction == 'y-': + y -= increment + + _babase.set_camera_manual(True) + _babase.set_camera_target(x, y, z) + + +old_refresh_in_game = MainMenuWindow._refresh_in_game + +def my_refresh_in_game(self, *args, **kwargs): + value = old_refresh_in_game.__get__(self)(*args, **kwargs) + camera_button = bui.buttonwidget( + parent=self._root_widget, + autoselect=True, + position=(-65, 100), + size=(70, 50), + button_type='square', + label='Manual\nCamera', + text_scale=1.5, + on_activate_call=self._manual_camera) + return value + +def _manual_camera(self): + bui.containerwidget(edit=self._root_widget, transition='out_scale') + Manual_camera_window() + +# ba_meta export plugin +class ByDroopy(babase.Plugin): + def __init__(self): + MainMenuWindow._refresh_in_game = my_refresh_in_game + MainMenuWindow._manual_camera = _manual_camera From 6bd0adc2c31aac0912b5646afc7aad2bb90f6d60 Mon Sep 17 00:00:00 2001 From: ! Freaku <92618708+Freaku17@users.noreply.github.com> Date: Sat, 5 Aug 2023 19:10:26 +0530 Subject: [PATCH 0690/1464] Update JSON file --- plugins/utilities.json | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/plugins/utilities.json b/plugins/utilities.json index d8e07102..14b68f77 100644 --- a/plugins/utilities.json +++ b/plugins/utilities.json @@ -27,6 +27,20 @@ } } }, + "manual_camera": { + "description": "Adjust the games camera angle/position. Open pause menu and press 'Manual Camera' button. Useable in OFFLINE/ONLINE/REPLAYS", + "external_url": "", + "authors": [ + { + "name": "Droopy", + "email": "", + "discord": "Droopy#3730" + } + ], + "versions": { + "1.0.0": null + } + }, "share_replay": { "description": "Export replays to mods folder and share them with friends or have a backup", "external_url": "", From 59b55cb152cdb0c6fa24250487fd8b050fd85ee1 Mon Sep 17 00:00:00 2001 From: Freaku17 Date: Sat, 5 Aug 2023 13:43:03 +0000 Subject: [PATCH 0691/1464] [ci] auto-format --- plugins/utilities/manual_camera.py | 248 +++++++++++++++-------------- 1 file changed, 127 insertions(+), 121 deletions(-) diff --git a/plugins/utilities/manual_camera.py b/plugins/utilities/manual_camera.py index 0fbab3fb..f6b26d2a 100644 --- a/plugins/utilities/manual_camera.py +++ b/plugins/utilities/manual_camera.py @@ -8,7 +8,8 @@ from __future__ import annotations -import _babase, babase +import _babase +import babase import bascenev1 as bs import bauiv1 as bui from bauiv1lib.mainmenu import MainMenuWindow @@ -16,134 +17,135 @@ class Manual_camera_window: def __init__(self): - self._root_widget = bui.containerwidget( - on_outside_click_call=None, - size=(0,0)) - button_size = (50,50) - self._text = bui.textwidget(parent=self._root_widget, - scale=0.65, - color = (0.75, 0.75, 0.75), - text='Cam Position', - size=(0, 0), - position=(500, 185), - h_align='center', - v_align='center') - self._xminus = bui.buttonwidget(parent=self._root_widget, - size=button_size, - label=babase.charstr(babase.SpecialChar.LEFT_ARROW), - button_type='square', - autoselect=True, - position=(429, 60), - on_activate_call=babase.Call(self._change_camera_position, 'x-')) - self._xplus = bui.buttonwidget(parent=self._root_widget, - size=button_size, - label=babase.charstr(babase.SpecialChar.RIGHT_ARROW), - button_type='square', - autoselect=True, - position=(538, 60), - on_activate_call=babase.Call(self._change_camera_position, 'x')) - self._yplus = bui.buttonwidget(parent=self._root_widget, - size=button_size, - label=babase.charstr(babase.SpecialChar.UP_ARROW), - button_type='square', - autoselect=True, - position=(482, 120), - on_activate_call=babase.Call(self._change_camera_position, 'y')) - self._yminus = bui.buttonwidget(parent=self._root_widget, - size=button_size, - label=babase.charstr(babase.SpecialChar.DOWN_ARROW), - button_type='square', - autoselect=True, - position=(482, 2), - on_activate_call=babase.Call(self._change_camera_position, 'y-')) - self.inwards = bui.buttonwidget(parent=self._root_widget, - size=(100,30), - label='Zoom +', - button_type='square', - autoselect=True, - position=(-550, -60), - on_activate_call=babase.Call(self._change_camera_position, 'z-')) - self._outwards = bui.buttonwidget(parent=self._root_widget, - size=(100,30), - label='Zoom -', - button_type='square', - autoselect=True, - position=(-550, -100), - on_activate_call=babase.Call(self._change_camera_position, 'z')) - self.target_text = bui.textwidget(parent=self._root_widget, - scale=0.65, - color = (0.75, 0.75, 0.75), - text='Cam Angle', - size=(0, 0), - position=(-462, 185), - h_align='center', - v_align='center') - self.target_xminus = bui.buttonwidget(parent=self._root_widget, - size=button_size, - label=babase.charstr(babase.SpecialChar.LEFT_ARROW), - button_type='square', - autoselect=True, - position=(-538, 60), - on_activate_call=babase.Call(self._change_camera_target, 'x-')) - self.target_xplus = bui.buttonwidget(parent=self._root_widget, - size=button_size, - label=babase.charstr(babase.SpecialChar.RIGHT_ARROW), - button_type='square', - autoselect=True, - position=(-429, 60), - on_activate_call=babase.Call(self._change_camera_target, 'x')) - self.target_yplus = bui.buttonwidget(parent=self._root_widget, - size=button_size, - label=babase.charstr(babase.SpecialChar.UP_ARROW), - button_type='square', - autoselect=True, - position=(-482, 120), - on_activate_call=babase.Call(self._change_camera_target, 'y')) - self.target_yminus = bui.buttonwidget(parent=self._root_widget, - size=button_size, - label=babase.charstr(babase.SpecialChar.DOWN_ARROW), - button_type='square', - autoselect=True, - position=(-482, 2), - on_activate_call=babase.Call(self._change_camera_target, 'y-')) - self._step_text = bui.textwidget(parent=self._root_widget, + self._root_widget = bui.containerwidget( + on_outside_click_call=None, + size=(0, 0)) + button_size = (50, 50) + self._text = bui.textwidget(parent=self._root_widget, + scale=0.65, + color=(0.75, 0.75, 0.75), + text='Cam Position', + size=(0, 0), + position=(500, 185), + h_align='center', + v_align='center') + self._xminus = bui.buttonwidget(parent=self._root_widget, + size=button_size, + label=babase.charstr(babase.SpecialChar.LEFT_ARROW), + button_type='square', + autoselect=True, + position=(429, 60), + on_activate_call=babase.Call(self._change_camera_position, 'x-')) + self._xplus = bui.buttonwidget(parent=self._root_widget, + size=button_size, + label=babase.charstr(babase.SpecialChar.RIGHT_ARROW), + button_type='square', + autoselect=True, + position=(538, 60), + on_activate_call=babase.Call(self._change_camera_position, 'x')) + self._yplus = bui.buttonwidget(parent=self._root_widget, + size=button_size, + label=babase.charstr(babase.SpecialChar.UP_ARROW), + button_type='square', + autoselect=True, + position=(482, 120), + on_activate_call=babase.Call(self._change_camera_position, 'y')) + self._yminus = bui.buttonwidget(parent=self._root_widget, + size=button_size, + label=babase.charstr(babase.SpecialChar.DOWN_ARROW), + button_type='square', + autoselect=True, + position=(482, 2), + on_activate_call=babase.Call(self._change_camera_position, 'y-')) + self.inwards = bui.buttonwidget(parent=self._root_widget, + size=(100, 30), + label='Zoom +', + button_type='square', + autoselect=True, + position=(-550, -60), + on_activate_call=babase.Call(self._change_camera_position, 'z-')) + self._outwards = bui.buttonwidget(parent=self._root_widget, + size=(100, 30), + label='Zoom -', + button_type='square', + autoselect=True, + position=(-550, -100), + on_activate_call=babase.Call(self._change_camera_position, 'z')) + self.target_text = bui.textwidget(parent=self._root_widget, + scale=0.65, + color=(0.75, 0.75, 0.75), + text='Cam Angle', + size=(0, 0), + position=(-462, 185), + h_align='center', + v_align='center') + self.target_xminus = bui.buttonwidget(parent=self._root_widget, + size=button_size, + label=babase.charstr(babase.SpecialChar.LEFT_ARROW), + button_type='square', + autoselect=True, + position=(-538, 60), + on_activate_call=babase.Call(self._change_camera_target, 'x-')) + self.target_xplus = bui.buttonwidget(parent=self._root_widget, + size=button_size, + label=babase.charstr(babase.SpecialChar.RIGHT_ARROW), + button_type='square', + autoselect=True, + position=(-429, 60), + on_activate_call=babase.Call(self._change_camera_target, 'x')) + self.target_yplus = bui.buttonwidget(parent=self._root_widget, + size=button_size, + label=babase.charstr(babase.SpecialChar.UP_ARROW), + button_type='square', + autoselect=True, + position=(-482, 120), + on_activate_call=babase.Call(self._change_camera_target, 'y')) + self.target_yminus = bui.buttonwidget(parent=self._root_widget, + size=button_size, + label=babase.charstr(babase.SpecialChar.DOWN_ARROW), + button_type='square', + autoselect=True, + position=(-482, 2), + on_activate_call=babase.Call(self._change_camera_target, 'y-')) + self._step_text = bui.textwidget(parent=self._root_widget, scale=0.85, - color=(1,1,1), + color=(1, 1, 1), text='Step:', size=(0, 0), position=(450, -38), h_align='center', v_align='center') - self._text_field = bui.textwidget( - parent=self._root_widget, - editable=True, - size=(100, 40), - position=(480, -55), - text='', - maxwidth=120, - flatness=1.0, - autoselect=True, - v_align='center', - corner_scale=0.7) - self._reset = bui.buttonwidget(parent=self._root_widget, - size=(50,30), - label='Reset', - button_type='square', - autoselect=True, - position=(450, -100), - on_activate_call=babase.Call(self._change_camera_position, 'reset')) - self._done = bui.buttonwidget(parent=self._root_widget, - size=(50,30), - label='Done', - button_type='square', - autoselect=True, - position=(520, -100), - on_activate_call=self._close) - bui.containerwidget(edit=self._root_widget, - cancel_button=self._done) + self._text_field = bui.textwidget( + parent=self._root_widget, + editable=True, + size=(100, 40), + position=(480, -55), + text='', + maxwidth=120, + flatness=1.0, + autoselect=True, + v_align='center', + corner_scale=0.7) + self._reset = bui.buttonwidget(parent=self._root_widget, + size=(50, 30), + label='Reset', + button_type='square', + autoselect=True, + position=(450, -100), + on_activate_call=babase.Call(self._change_camera_position, 'reset')) + self._done = bui.buttonwidget(parent=self._root_widget, + size=(50, 30), + label='Done', + button_type='square', + autoselect=True, + position=(520, -100), + on_activate_call=self._close) + bui.containerwidget(edit=self._root_widget, + cancel_button=self._done) + def _close(self): bui.containerwidget(edit=self._root_widget, - transition=('out_scale')) + transition=('out_scale')) MainMenuWindow() def _change_camera_position(self, direction): @@ -202,6 +204,7 @@ def _change_camera_target(self, direction): old_refresh_in_game = MainMenuWindow._refresh_in_game + def my_refresh_in_game(self, *args, **kwargs): value = old_refresh_in_game.__get__(self)(*args, **kwargs) camera_button = bui.buttonwidget( @@ -215,11 +218,14 @@ def my_refresh_in_game(self, *args, **kwargs): on_activate_call=self._manual_camera) return value + def _manual_camera(self): bui.containerwidget(edit=self._root_widget, transition='out_scale') Manual_camera_window() # ba_meta export plugin + + class ByDroopy(babase.Plugin): def __init__(self): MainMenuWindow._refresh_in_game = my_refresh_in_game From 2feb98f018ad1dbe21096f4230fa910916809794 Mon Sep 17 00:00:00 2001 From: Freaku17 Date: Sat, 5 Aug 2023 13:43:05 +0000 Subject: [PATCH 0692/1464] [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 14b68f77..36edc6e1 100644 --- a/plugins/utilities.json +++ b/plugins/utilities.json @@ -38,7 +38,12 @@ } ], "versions": { - "1.0.0": null + "1.0.0": { + "api_version": 8, + "commit_sha": "59b55cb", + "released_on": "05-08-2023", + "md5sum": "aafd4729caf456285cce48ad34944052" + } } }, "share_replay": { From 060d2a6f41c1b9b395aa2649604bb431e798fda3 Mon Sep 17 00:00:00 2001 From: ! Freaku <92618708+Freaku17@users.noreply.github.com> Date: Sat, 5 Aug 2023 23:15:28 +0530 Subject: [PATCH 0693/1464] Add a suggested feature --- plugins/utilities/manual_camera.py | 258 +++++++++++++++-------------- 1 file changed, 131 insertions(+), 127 deletions(-) diff --git a/plugins/utilities/manual_camera.py b/plugins/utilities/manual_camera.py index f6b26d2a..b16e45ba 100644 --- a/plugins/utilities/manual_camera.py +++ b/plugins/utilities/manual_camera.py @@ -8,8 +8,7 @@ from __future__ import annotations -import _babase -import babase +import _babase, babase import bascenev1 as bs import bauiv1 as bui from bauiv1lib.mainmenu import MainMenuWindow @@ -17,135 +16,144 @@ class Manual_camera_window: def __init__(self): - self._root_widget = bui.containerwidget( - on_outside_click_call=None, - size=(0, 0)) - button_size = (50, 50) - self._text = bui.textwidget(parent=self._root_widget, - scale=0.65, - color=(0.75, 0.75, 0.75), - text='Cam Position', - size=(0, 0), - position=(500, 185), - h_align='center', - v_align='center') - self._xminus = bui.buttonwidget(parent=self._root_widget, - size=button_size, - label=babase.charstr(babase.SpecialChar.LEFT_ARROW), - button_type='square', - autoselect=True, - position=(429, 60), - on_activate_call=babase.Call(self._change_camera_position, 'x-')) - self._xplus = bui.buttonwidget(parent=self._root_widget, - size=button_size, - label=babase.charstr(babase.SpecialChar.RIGHT_ARROW), - button_type='square', - autoselect=True, - position=(538, 60), - on_activate_call=babase.Call(self._change_camera_position, 'x')) - self._yplus = bui.buttonwidget(parent=self._root_widget, - size=button_size, - label=babase.charstr(babase.SpecialChar.UP_ARROW), - button_type='square', - autoselect=True, - position=(482, 120), - on_activate_call=babase.Call(self._change_camera_position, 'y')) - self._yminus = bui.buttonwidget(parent=self._root_widget, - size=button_size, - label=babase.charstr(babase.SpecialChar.DOWN_ARROW), - button_type='square', - autoselect=True, - position=(482, 2), - on_activate_call=babase.Call(self._change_camera_position, 'y-')) - self.inwards = bui.buttonwidget(parent=self._root_widget, - size=(100, 30), - label='Zoom +', - button_type='square', - autoselect=True, - position=(-550, -60), - on_activate_call=babase.Call(self._change_camera_position, 'z-')) - self._outwards = bui.buttonwidget(parent=self._root_widget, - size=(100, 30), - label='Zoom -', - button_type='square', - autoselect=True, - position=(-550, -100), - on_activate_call=babase.Call(self._change_camera_position, 'z')) - self.target_text = bui.textwidget(parent=self._root_widget, - scale=0.65, - color=(0.75, 0.75, 0.75), - text='Cam Angle', - size=(0, 0), - position=(-462, 185), - h_align='center', - v_align='center') - self.target_xminus = bui.buttonwidget(parent=self._root_widget, - size=button_size, - label=babase.charstr(babase.SpecialChar.LEFT_ARROW), - button_type='square', - autoselect=True, - position=(-538, 60), - on_activate_call=babase.Call(self._change_camera_target, 'x-')) - self.target_xplus = bui.buttonwidget(parent=self._root_widget, - size=button_size, - label=babase.charstr(babase.SpecialChar.RIGHT_ARROW), - button_type='square', - autoselect=True, - position=(-429, 60), - on_activate_call=babase.Call(self._change_camera_target, 'x')) - self.target_yplus = bui.buttonwidget(parent=self._root_widget, - size=button_size, - label=babase.charstr(babase.SpecialChar.UP_ARROW), - button_type='square', - autoselect=True, - position=(-482, 120), - on_activate_call=babase.Call(self._change_camera_target, 'y')) - self.target_yminus = bui.buttonwidget(parent=self._root_widget, - size=button_size, - label=babase.charstr(babase.SpecialChar.DOWN_ARROW), - button_type='square', - autoselect=True, - position=(-482, 2), - on_activate_call=babase.Call(self._change_camera_target, 'y-')) - self._step_text = bui.textwidget(parent=self._root_widget, + self._root_widget = bui.containerwidget( + on_outside_click_call=None, + size=(0,0)) + button_size = (50,50) + self._text = bui.textwidget(parent=self._root_widget, + scale=0.65, + color = (0.75, 0.75, 0.75), + text='Cam Position', + size=(0, 0), + position=(500, 185), + h_align='center', + v_align='center') + self._xminus = bui.buttonwidget(parent=self._root_widget, + size=button_size, + label=babase.charstr(babase.SpecialChar.LEFT_ARROW), + repeat = True, + button_type='square', + autoselect=True, + position=(429, 60), + on_activate_call=babase.Call(self._change_camera_position, 'x-')) + self._xplus = bui.buttonwidget(parent=self._root_widget, + size=button_size, + label=babase.charstr(babase.SpecialChar.RIGHT_ARROW), + repeat = True, + button_type='square', + autoselect=True, + position=(538, 60), + on_activate_call=babase.Call(self._change_camera_position, 'x')) + self._yplus = bui.buttonwidget(parent=self._root_widget, + size=button_size, + label=babase.charstr(babase.SpecialChar.UP_ARROW), + repeat = True, + button_type='square', + autoselect=True, + position=(482, 120), + on_activate_call=babase.Call(self._change_camera_position, 'y')) + self._yminus = bui.buttonwidget(parent=self._root_widget, + size=button_size, + label=babase.charstr(babase.SpecialChar.DOWN_ARROW), + repeat = True, + button_type='square', + autoselect=True, + position=(482, 2), + on_activate_call=babase.Call(self._change_camera_position, 'y-')) + self.inwards = bui.buttonwidget(parent=self._root_widget, + size=(100,30), + label='Zoom +', + repeat = True, + button_type='square', + autoselect=True, + position=(-550, -60), + on_activate_call=babase.Call(self._change_camera_position, 'z-')) + self._outwards = bui.buttonwidget(parent=self._root_widget, + size=(100,30), + label='Zoom -', + repeat = True, + button_type='square', + autoselect=True, + position=(-550, -100), + on_activate_call=babase.Call(self._change_camera_position, 'z')) + self.target_text = bui.textwidget(parent=self._root_widget, + scale=0.65, + color = (0.75, 0.75, 0.75), + text='Cam Angle', + size=(0, 0), + position=(-462, 185), + h_align='center', + v_align='center') + self.target_xminus = bui.buttonwidget(parent=self._root_widget, + size=button_size, + label=babase.charstr(babase.SpecialChar.LEFT_ARROW), + repeat = True, + button_type='square', + autoselect=True, + position=(-538, 60), + on_activate_call=babase.Call(self._change_camera_target, 'x-')) + self.target_xplus = bui.buttonwidget(parent=self._root_widget, + size=button_size, + label=babase.charstr(babase.SpecialChar.RIGHT_ARROW), + repeat = True, + button_type='square', + autoselect=True, + position=(-429, 60), + on_activate_call=babase.Call(self._change_camera_target, 'x')) + self.target_yplus = bui.buttonwidget(parent=self._root_widget, + size=button_size, + label=babase.charstr(babase.SpecialChar.UP_ARROW), + repeat = True, + button_type='square', + autoselect=True, + position=(-482, 120), + on_activate_call=babase.Call(self._change_camera_target, 'y')) + self.target_yminus = bui.buttonwidget(parent=self._root_widget, + size=button_size, + label=babase.charstr(babase.SpecialChar.DOWN_ARROW), + repeat = True, + button_type='square', + autoselect=True, + position=(-482, 2), + on_activate_call=babase.Call(self._change_camera_target, 'y-')) + self._step_text = bui.textwidget(parent=self._root_widget, scale=0.85, - color=(1, 1, 1), + color=(1,1,1), text='Step:', size=(0, 0), position=(450, -38), h_align='center', v_align='center') - self._text_field = bui.textwidget( - parent=self._root_widget, - editable=True, - size=(100, 40), - position=(480, -55), - text='', - maxwidth=120, - flatness=1.0, - autoselect=True, - v_align='center', - corner_scale=0.7) - self._reset = bui.buttonwidget(parent=self._root_widget, - size=(50, 30), - label='Reset', - button_type='square', - autoselect=True, - position=(450, -100), - on_activate_call=babase.Call(self._change_camera_position, 'reset')) - self._done = bui.buttonwidget(parent=self._root_widget, - size=(50, 30), - label='Done', - button_type='square', - autoselect=True, - position=(520, -100), - on_activate_call=self._close) - bui.containerwidget(edit=self._root_widget, - cancel_button=self._done) - + self._text_field = bui.textwidget( + parent=self._root_widget, + editable=True, + size=(100, 40), + position=(480, -55), + text='', + maxwidth=120, + flatness=1.0, + autoselect=True, + v_align='center', + corner_scale=0.7) + self._reset = bui.buttonwidget(parent=self._root_widget, + size=(50,30), + label='Reset', + button_type='square', + autoselect=True, + position=(450, -100), + on_activate_call=babase.Call(self._change_camera_position, 'reset')) + self._done = bui.buttonwidget(parent=self._root_widget, + size=(50,30), + label='Done', + button_type='square', + autoselect=True, + position=(520, -100), + on_activate_call=self._close) + bui.containerwidget(edit=self._root_widget, + cancel_button=self._done) def _close(self): bui.containerwidget(edit=self._root_widget, - transition=('out_scale')) + transition=('out_scale')) MainMenuWindow() def _change_camera_position(self, direction): @@ -204,7 +212,6 @@ def _change_camera_target(self, direction): old_refresh_in_game = MainMenuWindow._refresh_in_game - def my_refresh_in_game(self, *args, **kwargs): value = old_refresh_in_game.__get__(self)(*args, **kwargs) camera_button = bui.buttonwidget( @@ -218,14 +225,11 @@ def my_refresh_in_game(self, *args, **kwargs): on_activate_call=self._manual_camera) return value - def _manual_camera(self): bui.containerwidget(edit=self._root_widget, transition='out_scale') Manual_camera_window() # ba_meta export plugin - - class ByDroopy(babase.Plugin): def __init__(self): MainMenuWindow._refresh_in_game = my_refresh_in_game From 020cae53f17b3f3c8b4e319d8eb7c52f75ca7d45 Mon Sep 17 00:00:00 2001 From: ! Freaku <92618708+Freaku17@users.noreply.github.com> Date: Sat, 5 Aug 2023 23:15:46 +0530 Subject: [PATCH 0694/1464] Update JSON file --- plugins/utilities.json | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/plugins/utilities.json b/plugins/utilities.json index 36edc6e1..14b68f77 100644 --- a/plugins/utilities.json +++ b/plugins/utilities.json @@ -38,12 +38,7 @@ } ], "versions": { - "1.0.0": { - "api_version": 8, - "commit_sha": "59b55cb", - "released_on": "05-08-2023", - "md5sum": "aafd4729caf456285cce48ad34944052" - } + "1.0.0": null } }, "share_replay": { From c26342d320932380d79079087d1211b99ff443b3 Mon Sep 17 00:00:00 2001 From: Freaku17 Date: Sat, 5 Aug 2023 17:46:09 +0000 Subject: [PATCH 0695/1464] [ci] auto-format --- plugins/utilities/manual_camera.py | 268 +++++++++++++++-------------- 1 file changed, 137 insertions(+), 131 deletions(-) diff --git a/plugins/utilities/manual_camera.py b/plugins/utilities/manual_camera.py index b16e45ba..cb944b4d 100644 --- a/plugins/utilities/manual_camera.py +++ b/plugins/utilities/manual_camera.py @@ -8,7 +8,8 @@ from __future__ import annotations -import _babase, babase +import _babase +import babase import bascenev1 as bs import bauiv1 as bui from bauiv1lib.mainmenu import MainMenuWindow @@ -16,144 +17,145 @@ class Manual_camera_window: def __init__(self): - self._root_widget = bui.containerwidget( - on_outside_click_call=None, - size=(0,0)) - button_size = (50,50) - self._text = bui.textwidget(parent=self._root_widget, - scale=0.65, - color = (0.75, 0.75, 0.75), - text='Cam Position', - size=(0, 0), - position=(500, 185), - h_align='center', - v_align='center') - self._xminus = bui.buttonwidget(parent=self._root_widget, - size=button_size, - label=babase.charstr(babase.SpecialChar.LEFT_ARROW), - repeat = True, - button_type='square', - autoselect=True, - position=(429, 60), - on_activate_call=babase.Call(self._change_camera_position, 'x-')) - self._xplus = bui.buttonwidget(parent=self._root_widget, - size=button_size, - label=babase.charstr(babase.SpecialChar.RIGHT_ARROW), - repeat = True, - button_type='square', - autoselect=True, - position=(538, 60), - on_activate_call=babase.Call(self._change_camera_position, 'x')) - self._yplus = bui.buttonwidget(parent=self._root_widget, - size=button_size, - label=babase.charstr(babase.SpecialChar.UP_ARROW), - repeat = True, - button_type='square', - autoselect=True, - position=(482, 120), - on_activate_call=babase.Call(self._change_camera_position, 'y')) - self._yminus = bui.buttonwidget(parent=self._root_widget, - size=button_size, - label=babase.charstr(babase.SpecialChar.DOWN_ARROW), - repeat = True, - button_type='square', - autoselect=True, - position=(482, 2), - on_activate_call=babase.Call(self._change_camera_position, 'y-')) - self.inwards = bui.buttonwidget(parent=self._root_widget, - size=(100,30), - label='Zoom +', - repeat = True, - button_type='square', - autoselect=True, - position=(-550, -60), - on_activate_call=babase.Call(self._change_camera_position, 'z-')) - self._outwards = bui.buttonwidget(parent=self._root_widget, - size=(100,30), - label='Zoom -', - repeat = True, - button_type='square', - autoselect=True, - position=(-550, -100), - on_activate_call=babase.Call(self._change_camera_position, 'z')) - self.target_text = bui.textwidget(parent=self._root_widget, - scale=0.65, - color = (0.75, 0.75, 0.75), - text='Cam Angle', - size=(0, 0), - position=(-462, 185), - h_align='center', - v_align='center') - self.target_xminus = bui.buttonwidget(parent=self._root_widget, - size=button_size, - label=babase.charstr(babase.SpecialChar.LEFT_ARROW), - repeat = True, - button_type='square', - autoselect=True, - position=(-538, 60), - on_activate_call=babase.Call(self._change_camera_target, 'x-')) - self.target_xplus = bui.buttonwidget(parent=self._root_widget, - size=button_size, - label=babase.charstr(babase.SpecialChar.RIGHT_ARROW), - repeat = True, - button_type='square', - autoselect=True, - position=(-429, 60), - on_activate_call=babase.Call(self._change_camera_target, 'x')) - self.target_yplus = bui.buttonwidget(parent=self._root_widget, - size=button_size, - label=babase.charstr(babase.SpecialChar.UP_ARROW), - repeat = True, - button_type='square', - autoselect=True, - position=(-482, 120), - on_activate_call=babase.Call(self._change_camera_target, 'y')) - self.target_yminus = bui.buttonwidget(parent=self._root_widget, - size=button_size, - label=babase.charstr(babase.SpecialChar.DOWN_ARROW), - repeat = True, - button_type='square', - autoselect=True, - position=(-482, 2), - on_activate_call=babase.Call(self._change_camera_target, 'y-')) - self._step_text = bui.textwidget(parent=self._root_widget, + self._root_widget = bui.containerwidget( + on_outside_click_call=None, + size=(0, 0)) + button_size = (50, 50) + self._text = bui.textwidget(parent=self._root_widget, + scale=0.65, + color=(0.75, 0.75, 0.75), + text='Cam Position', + size=(0, 0), + position=(500, 185), + h_align='center', + v_align='center') + self._xminus = bui.buttonwidget(parent=self._root_widget, + size=button_size, + label=babase.charstr(babase.SpecialChar.LEFT_ARROW), + repeat=True, + button_type='square', + autoselect=True, + position=(429, 60), + on_activate_call=babase.Call(self._change_camera_position, 'x-')) + self._xplus = bui.buttonwidget(parent=self._root_widget, + size=button_size, + label=babase.charstr(babase.SpecialChar.RIGHT_ARROW), + repeat=True, + button_type='square', + autoselect=True, + position=(538, 60), + on_activate_call=babase.Call(self._change_camera_position, 'x')) + self._yplus = bui.buttonwidget(parent=self._root_widget, + size=button_size, + label=babase.charstr(babase.SpecialChar.UP_ARROW), + repeat=True, + button_type='square', + autoselect=True, + position=(482, 120), + on_activate_call=babase.Call(self._change_camera_position, 'y')) + self._yminus = bui.buttonwidget(parent=self._root_widget, + size=button_size, + label=babase.charstr(babase.SpecialChar.DOWN_ARROW), + repeat=True, + button_type='square', + autoselect=True, + position=(482, 2), + on_activate_call=babase.Call(self._change_camera_position, 'y-')) + self.inwards = bui.buttonwidget(parent=self._root_widget, + size=(100, 30), + label='Zoom +', + repeat=True, + button_type='square', + autoselect=True, + position=(-550, -60), + on_activate_call=babase.Call(self._change_camera_position, 'z-')) + self._outwards = bui.buttonwidget(parent=self._root_widget, + size=(100, 30), + label='Zoom -', + repeat=True, + button_type='square', + autoselect=True, + position=(-550, -100), + on_activate_call=babase.Call(self._change_camera_position, 'z')) + self.target_text = bui.textwidget(parent=self._root_widget, + scale=0.65, + color=(0.75, 0.75, 0.75), + text='Cam Angle', + size=(0, 0), + position=(-462, 185), + h_align='center', + v_align='center') + self.target_xminus = bui.buttonwidget(parent=self._root_widget, + size=button_size, + label=babase.charstr(babase.SpecialChar.LEFT_ARROW), + repeat=True, + button_type='square', + autoselect=True, + position=(-538, 60), + on_activate_call=babase.Call(self._change_camera_target, 'x-')) + self.target_xplus = bui.buttonwidget(parent=self._root_widget, + size=button_size, + label=babase.charstr(babase.SpecialChar.RIGHT_ARROW), + repeat=True, + button_type='square', + autoselect=True, + position=(-429, 60), + on_activate_call=babase.Call(self._change_camera_target, 'x')) + self.target_yplus = bui.buttonwidget(parent=self._root_widget, + size=button_size, + label=babase.charstr(babase.SpecialChar.UP_ARROW), + repeat=True, + button_type='square', + autoselect=True, + position=(-482, 120), + on_activate_call=babase.Call(self._change_camera_target, 'y')) + self.target_yminus = bui.buttonwidget(parent=self._root_widget, + size=button_size, + label=babase.charstr(babase.SpecialChar.DOWN_ARROW), + repeat=True, + button_type='square', + autoselect=True, + position=(-482, 2), + on_activate_call=babase.Call(self._change_camera_target, 'y-')) + self._step_text = bui.textwidget(parent=self._root_widget, scale=0.85, - color=(1,1,1), + color=(1, 1, 1), text='Step:', size=(0, 0), position=(450, -38), h_align='center', v_align='center') - self._text_field = bui.textwidget( - parent=self._root_widget, - editable=True, - size=(100, 40), - position=(480, -55), - text='', - maxwidth=120, - flatness=1.0, - autoselect=True, - v_align='center', - corner_scale=0.7) - self._reset = bui.buttonwidget(parent=self._root_widget, - size=(50,30), - label='Reset', - button_type='square', - autoselect=True, - position=(450, -100), - on_activate_call=babase.Call(self._change_camera_position, 'reset')) - self._done = bui.buttonwidget(parent=self._root_widget, - size=(50,30), - label='Done', - button_type='square', - autoselect=True, - position=(520, -100), - on_activate_call=self._close) - bui.containerwidget(edit=self._root_widget, - cancel_button=self._done) + self._text_field = bui.textwidget( + parent=self._root_widget, + editable=True, + size=(100, 40), + position=(480, -55), + text='', + maxwidth=120, + flatness=1.0, + autoselect=True, + v_align='center', + corner_scale=0.7) + self._reset = bui.buttonwidget(parent=self._root_widget, + size=(50, 30), + label='Reset', + button_type='square', + autoselect=True, + position=(450, -100), + on_activate_call=babase.Call(self._change_camera_position, 'reset')) + self._done = bui.buttonwidget(parent=self._root_widget, + size=(50, 30), + label='Done', + button_type='square', + autoselect=True, + position=(520, -100), + on_activate_call=self._close) + bui.containerwidget(edit=self._root_widget, + cancel_button=self._done) + def _close(self): bui.containerwidget(edit=self._root_widget, - transition=('out_scale')) + transition=('out_scale')) MainMenuWindow() def _change_camera_position(self, direction): @@ -212,6 +214,7 @@ def _change_camera_target(self, direction): old_refresh_in_game = MainMenuWindow._refresh_in_game + def my_refresh_in_game(self, *args, **kwargs): value = old_refresh_in_game.__get__(self)(*args, **kwargs) camera_button = bui.buttonwidget( @@ -225,11 +228,14 @@ def my_refresh_in_game(self, *args, **kwargs): on_activate_call=self._manual_camera) return value + def _manual_camera(self): bui.containerwidget(edit=self._root_widget, transition='out_scale') Manual_camera_window() # ba_meta export plugin + + class ByDroopy(babase.Plugin): def __init__(self): MainMenuWindow._refresh_in_game = my_refresh_in_game From e3cf069507f6871b903ec7eb031d107107dd9a41 Mon Sep 17 00:00:00 2001 From: Freaku17 Date: Sat, 5 Aug 2023 17:46:10 +0000 Subject: [PATCH 0696/1464] [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 14b68f77..ea3bf6fd 100644 --- a/plugins/utilities.json +++ b/plugins/utilities.json @@ -38,7 +38,12 @@ } ], "versions": { - "1.0.0": null + "1.0.0": { + "api_version": 8, + "commit_sha": "c26342d", + "released_on": "05-08-2023", + "md5sum": "8d6716d2fca5848a39909ef6bb87ce35" + } } }, "share_replay": { From ca3e6683aa9b5ab187467ddb5dfe843d5da8b2a2 Mon Sep 17 00:00:00 2001 From: SenjuZoro <69396975+SenjuZoro@users.noreply.github.com> Date: Tue, 22 Aug 2023 02:47:13 +0200 Subject: [PATCH 0697/1464] Infection updated to api 8 --- plugins/minigames/infection.py | 520 +++++++++++++++++++++++++++++++++ 1 file changed, 520 insertions(+) create mode 100644 plugins/minigames/infection.py diff --git a/plugins/minigames/infection.py b/plugins/minigames/infection.py new file mode 100644 index 00000000..017892c5 --- /dev/null +++ b/plugins/minigames/infection.py @@ -0,0 +1,520 @@ +"""New Duel / Created by: byANG3L""" + +# ba_meta require api 8 +# (see https://ballistica.net/wiki/meta-tag-system) + +from __future__ import annotations + +from typing import TYPE_CHECKING + +import babase +import bauiv1 as bui +import bascenev1 as bs +import _babase +import random +from bascenev1lib.actor.bomb import Bomb +from bascenev1lib.actor.playerspaz import PlayerSpaz +from bascenev1lib.actor.onscreentimer import OnScreenTimer + +if TYPE_CHECKING: + pass + +lang = bs.app.lang.language +if lang == 'Spanish': + name = 'Infección' + description = '¡Se está extendiendo!' + instance_description = '¡Evite la propagación!' + mines = 'Minas' + enable_bombs = 'Habilitar Bombas' + extra_mines = 'Seg/Mina Extra' + max_infected_size = 'Tamaño Máx. de Infección' + max_size_increases = 'Incrementar Tamaño Cada' + infection_spread_rate = 'Velocidad de Infección' + faster = 'Muy Rápido' + fast = 'Rápido' + normal = 'Normal' + slow = 'Lento' + slowest = 'Muy Lento' + insane = 'Insano' +else: + name = 'Infection' + description = "It's spreading!" + instance_description = 'Avoid the spread!' + mines = 'Mines' + enable_bombs = 'Enable Bombs' + extra_mines = 'Sec/Extra Mine' + max_infected_size = 'Max Infected Size' + max_size_increases = 'Max Size Increases Every' + infection_spread_rate = 'Infection Spread Rate' + faster = 'Faster' + fast = 'Fast' + normal = 'Normal' + slow = 'Slow' + slowest = 'Slowest' + insane = 'Insane' + +def ba_get_api_version(): + return 6 + +def ba_get_levels(): + return [babase._level.Level( + name, + gametype=Infection, + settings={}, + preview_texture_name='footballStadiumPreview')] + +class myMine(Bomb): + #reason for the mine class is so we can add the death zone + def __init__(self, + pos: Sequence[float] = (0.0, 1.0, 0.0)): + Bomb.__init__(self, position=pos, bomb_type='land_mine') + showInSpace = False + self.died = False + self.rad = 0.3 + self.zone = bs.newnode( + 'locator', + attrs={ + 'shape':'circle', + 'position':self.node.position, + 'color':(1,0,0), + 'opacity':0.5, + 'draw_beauty':showInSpace, + 'additive':True}) + bs.animate_array( + self.zone, + 'size', + 1, + {0:[0.0], 0.05:[2*self.rad]}) + + def handlemessage(self, msg: Any) -> Any: + if isinstance(msg, bs.DieMessage): + if not self.died: + self.getactivity().mine_count -= 1 + self.died = True + bs.animate_array( + self.zone, + 'size', + 1, + {0:[2*self.rad], 0.05:[0]}) + self.zone = None + super().handlemessage(msg) + else: + super().handlemessage(msg) + +class Player(bs.Player['Team']): + """Our player type for this game.""" + def __init__(self) -> None: + self.survival_seconds: Optional[int] = None + self.death_time: Optional[float] = None + +class Team(bs.Team[Player]): + """Our team type for this game.""" + + +# ba_meta export bascenev1.GameActivity +class Infection(bs.TeamGameActivity[Player, Team]): + """A game type based on acquiring kills.""" + + name = name + description = description + + # Print messages when players die since it matters here. + announce_player_deaths = True + allow_mid_activity_joins = False + + + @classmethod + def get_available_settings( + cls, sessiontype: Type[bs.Session]) -> List[babase.Setting]: + settings = [ + bs.IntSetting( + mines, + min_value=5, + default=10, + increment=5, + ), + bs.BoolSetting(enable_bombs, default=True), + bs.IntSetting( + extra_mines, + min_value=1, + default=10, + increment=1, + ), + bs.IntSetting( + max_infected_size, + min_value=4, + default=6, + increment=1, + ), + bs.IntChoiceSetting( + max_size_increases, + choices=[ + ('10s', 10), + ('20s', 20), + ('30s',30), + ('1 Minute', 60), + ], + default=20, + ), + bs.IntChoiceSetting( + infection_spread_rate, + choices=[ + (slowest, 0.01), + (slow, 0.02), + (normal, 0.03), + (fast, 0.04), + (faster, 0.05), + (insane, 0.08), + ], + default=0.03, + ), + bs.BoolSetting('Epic Mode', default=False), + ] + return settings + + @classmethod + def supports_session_type(cls, sessiontype: Type[bs.Session]) -> bool: + return (issubclass(sessiontype, bs.CoopSession) + or issubclass(sessiontype, bs.MultiTeamSession)) + + @classmethod + def get_supported_maps(cls, sessiontype: Type[bs.Session]) -> List[str]: + return ['Doom Shroom', 'Rampage', 'Hockey Stadium', + 'Crag Castle', 'Big G', 'Football Stadium'] + + def __init__(self, settings: dict): + super().__init__(settings) + self.mines: List = [] + self._update_rate = 0.1 + self._last_player_death_time = None + self._start_time: Optional[float] = None + self._timer: Optional[OnScreenTimer] = None + self._epic_mode = bool(settings['Epic Mode']) + self._max_mines = int(settings[mines]) + self._extra_mines = int(settings[extra_mines]) + self._enable_bombs = bool(settings[enable_bombs]) + self._max_size = int(settings[max_infected_size]) + self._max_size_increases = float(settings[max_size_increases]) + self._growth_rate = float(settings[infection_spread_rate]) + + # Base class overrides. + self.slow_motion = self._epic_mode + self.default_music = (bs.MusicType.EPIC if self._epic_mode else + bs.MusicType.SURVIVAL) + + def get_instance_description(self) -> Union[str, Sequence]: + return instance_description + + def get_instance_description_short(self) -> Union[str, Sequence]: + return instance_description + + def on_begin(self) -> None: + super().on_begin() + self._start_time = bs.time() + self.mine_count = 0 + bs.timer(self._update_rate, + bs.WeakCall(self._mine_update), + repeat=True) + bs.timer(self._max_size_increases*1.0, + bs.WeakCall(self._max_size_update), + repeat=True) + bs.timer(self._extra_mines*1.0, + bs.WeakCall(self._max_mine_update), + repeat=True) + self._timer = OnScreenTimer() + self._timer.start() + + # Check for immediate end (if we've only got 1 player, etc). + bs.timer(5.0, self._check_end_game) + + def on_player_join(self, player: Player) -> None: + if self.has_begun(): + assert self._timer is not None + player.survival_seconds = self._timer.getstarttime() + bs.broadcastmessage( + babase.Lstr(resource='playerDelayedJoinText', + subs=[('${PLAYER}', player.getname(full=True))]), + color=(0, 1, 0), + ) + return + self.spawn_player(player) + + def on_player_leave(self, player: Player) -> None: + super().on_player_leave(player) + self._check_end_game() + + def _max_mine_update(self) -> None: + self._max_mines += 1 + + def _max_size_update(self) -> None: + self._max_size += 1 + + def _mine_update(self) -> None: + # print self.mineCount + # purge dead mines, update their animantion, check if players died + for m in self.mines: + if not m.node: + self.mines.remove(m) + else: + #First, check if any player is within the current death zone + for player in self.players: + if not player.actor is None: + if player.actor.is_alive(): + p1 = player.actor.node.position + p2 = m.node.position + diff = (babase.Vec3(p1[0]-p2[0], + 0.0, + p1[2]-p2[2])) + dist = (diff.length()) + if dist < m.rad: + player.actor.handlemessage(bs.DieMessage()) + #Now tell the circle to grow to the new size + if m.rad < self._max_size: + bs.animate_array( + m.zone, 'size' ,1, + {0:[m.rad*2], + self._update_rate:[(m.rad+self._growth_rate)*2]}) + # Tell the circle to be the new size. + # This will be the new check radius next time. + m.rad += self._growth_rate + #make a new mine if needed. + if self.mine_count < self._max_mines: + pos = self.getRandomPowerupPoint() + self.mine_count += 1 + self._flash_mine(pos) + bs.timer(0.95, babase.Call(self._make_mine, pos)) + + def _make_mine(self,posn: Sequence[float]) -> None: + m = myMine(pos=posn) + m.arm() + self.mines.append(m) + + def _flash_mine(self, pos: Sequence[float]) -> None: + light = bs.newnode('light', + attrs={ + 'position': pos, + 'color': (1, 0.2, 0.2), + 'radius': 0.1, + 'height_attenuated': False + }) + bs.animate(light, 'intensity', {0.0: 0, 0.1: 1.0, 0.2: 0}, loop=True) + bs.timer(1.0, light.delete) + + def end_game(self) -> None: + results = bs.GameResults() + for team in self.teams: + results.set_team_score(team, int(team.survival_seconds)) + self.end(results=results, announce_delay=0.8) + + def _flash_player(self, player: Player, scale: float) -> None: + assert isinstance(player.actor, PlayerSpaz) + assert player.actor.node + pos = player.actor.node.position + light = bs.newnode('light', + attrs={ + 'position': pos, + 'color': (1, 1, 0), + 'height_attenuated': False, + 'radius': 0.4 + }) + bs.timer(0.5, light.delete) + bs.animate(light, 'intensity', {0: 0, 0.1: 1.0 * scale, 0.5: 0}) + + def handlemessage(self, msg: Any) -> Any: + + if isinstance(msg, bs.PlayerDiedMessage): + + # Augment standard behavior. + super().handlemessage(msg) + + death_time = bs.time() + msg.getplayer(Player).death_time = death_time + + if isinstance(self.session, bs.CoopSession): + # Teams will still show up if we check now.. check in + # the next cycle. + babase.pushcall(self._check_end_game) + + # Also record this for a final setting of the clock. + self._last_player_death_time = death_time + else: + bs.timer(1.0, self._check_end_game) + + else: + # Default handler: + return super().handlemessage(msg) + return None + + def _check_end_game(self) -> None: + living_team_count = 0 + for team in self.teams: + for player in team.players: + if player.is_alive(): + living_team_count += 1 + break + + # In co-op, we go till everyone is dead.. otherwise we go + # until one team remains. + if isinstance(self.session, bs.CoopSession): + if living_team_count <= 0: + self.end_game() + else: + if living_team_count <= 1: + self.end_game() + + def spawn_player(self, player: PlayerType) -> bs.Actor: + spaz = self.spawn_player_spaz(player) + + # Let's reconnect this player's controls to this + # spaz but *without* the ability to attack or pick stuff up. + spaz.connect_controls_to_player(enable_punch=False, + enable_bomb=self._enable_bombs, + enable_pickup=False) + + # Also lets have them make some noise when they die. + spaz.play_big_death_sound = True + return spaz + + def spawn_player_spaz(self, + player: PlayerType, + position: Sequence[float] = (0, 0, 0), + angle: float = None) -> PlayerSpaz: + """Create and wire up a bs.PlayerSpaz for the provided bs.Player.""" + # pylint: disable=too-many-locals + # pylint: disable=cyclic-import + position = self.map.get_ffa_start_position(self.players) + name = player.getname() + color = player.color + highlight = player.highlight + + light_color = babase._math.normalized_color(color) + display_color = _babase.safecolor(color, target_intensity=0.75) + spaz = PlayerSpaz(color=color, + highlight=highlight, + character=player.character, + player=player) + + player.actor = spaz + assert spaz.node + + # If this is co-op and we're on Courtyard or Runaround, add the + # material that allows us to collide with the player-walls. + # FIXME: Need to generalize this. + if isinstance(self.session, bs.CoopSession) and self.map.getname() in [ + 'Courtyard', 'Tower D' + ]: + mat = self.map.preloaddata['collide_with_wall_material'] + assert isinstance(spaz.node.materials, tuple) + assert isinstance(spaz.node.roller_materials, tuple) + spaz.node.materials += (mat, ) + spaz.node.roller_materials += (mat, ) + + spaz.node.name = name + spaz.node.name_color = display_color + spaz.connect_controls_to_player() + + # Move to the stand position and add a flash of light. + spaz.handlemessage( + bs.StandMessage( + position, + angle if angle is not None else random.uniform(0, 360))) + self._spawn_sound.play(1, position=spaz.node.position) + light = bs.newnode('light', attrs={'color': light_color}) + spaz.node.connectattr('position', light, 'position') + bs.animate(light, 'intensity', {0: 0, 0.25: 1, 0.5: 0}) + bs.timer(0.5, light.delete) + return spaz + + def getRandomPowerupPoint(self) -> None: + #So far, randomized points only figured out for mostly rectangular maps. + #Boxes will still fall through holes, but shouldn't be terrible problem (hopefully) + #If you add stuff here, need to add to "supported maps" above. + #['Doom Shroom', 'Rampage', 'Hockey Stadium', 'Courtyard', 'Crag Castle', 'Big G', 'Football Stadium'] + myMap = self.map.getname() + #print(myMap) + if myMap == 'Doom Shroom': + while True: + x = random.uniform(-1.0,1.0) + y = random.uniform(-1.0,1.0) + if x*x+y*y < 1.0: break + return ((8.0*x,2.5,-3.5+5.0*y)) + elif myMap == 'Rampage': + x = random.uniform(-6.0,7.0) + y = random.uniform(-6.0,-2.5) + return ((x, 5.2, y)) + elif myMap == 'Hockey Stadium': + x = random.uniform(-11.5,11.5) + y = random.uniform(-4.5,4.5) + return ((x, 0.2, y)) + elif myMap == 'Courtyard': + x = random.uniform(-4.3,4.3) + y = random.uniform(-4.4,0.3) + return ((x, 3.0, y)) + elif myMap == 'Crag Castle': + x = random.uniform(-6.7,8.0) + y = random.uniform(-6.0,0.0) + return ((x, 10.0, y)) + elif myMap == 'Big G': + x = random.uniform(-8.7,8.0) + y = random.uniform(-7.5,6.5) + return ((x, 3.5, y)) + elif myMap == 'Football Stadium': + x = random.uniform(-12.5,12.5) + y = random.uniform(-5.0,5.5) + return ((x, 0.32, y)) + else: + x = random.uniform(-5.0,5.0) + y = random.uniform(-6.0,0.0) + return ((x, 8.0, y)) + + def end_game(self) -> None: + cur_time = bs.time() + assert self._timer is not None + start_time = self._timer.getstarttime() + + # Mark death-time as now for any still-living players + # and award players points for how long they lasted. + # (these per-player scores are only meaningful in team-games) + for team in self.teams: + for player in team.players: + survived = False + + # Throw an extra fudge factor in so teams that + # didn't die come out ahead of teams that did. + if player.death_time is None: + survived = True + player.death_time = cur_time + 1 + + # Award a per-player score depending on how many seconds + # they lasted (per-player scores only affect teams mode; + # everywhere else just looks at the per-team score). + score = int(player.death_time - self._timer.getstarttime()) + if survived: + score += 50 # A bit extra for survivors. + self.stats.player_scored(player, score, screenmessage=False) + + # Stop updating our time text, and set the final time to match + # exactly when our last guy died. + self._timer.stop(endtime=self._last_player_death_time) + + # Ok now calc game results: set a score for each team and then tell + # the game to end. + results = bs.GameResults() + + # Remember that 'free-for-all' mode is simply a special form + # of 'teams' mode where each player gets their own team, so we can + # just always deal in teams and have all cases covered. + for team in self.teams: + + # Set the team score to the max time survived by any player on + # that team. + longest_life = 0.0 + for player in team.players: + assert player.death_time is not None + longest_life = max(longest_life, + player.death_time - start_time) + + # Submit the score value in milliseconds. + results.set_team_score(team, int(1000.0 * longest_life)) + + self.end(results=results) From 27d77b6afd19e54b953dca6a9fed2f923a143a02 Mon Sep 17 00:00:00 2001 From: SenjuZoro <69396975+SenjuZoro@users.noreply.github.com> Date: Tue, 22 Aug 2023 02:49:23 +0200 Subject: [PATCH 0698/1464] Update minigames.json --- plugins/minigames.json | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/plugins/minigames.json b/plugins/minigames.json index 3181af4f..c27493a4 100644 --- a/plugins/minigames.json +++ b/plugins/minigames.json @@ -773,6 +773,20 @@ } } }, + "infection": { + "description": "It's spreading, avoid the spread!", + "external_url": "", + "authors": [ + { + "name": "JoseAng3l", + "email": "", + "discord": "joseang3l" + } + ], + "versions": { + "1.0.0": null + } + }, "super_duel": { "description": "Crush your enemy in a 1v1", "external_url": "https://www.youtube.com/watch?v=hvRtiXR-oC0", @@ -817,4 +831,4 @@ } } } -} \ No newline at end of file +} From 47a1ca8c54f6b4efd730e129717af557bfd666f9 Mon Sep 17 00:00:00 2001 From: SenjuZoro Date: Tue, 22 Aug 2023 00:51:19 +0000 Subject: [PATCH 0699/1464] [ci] auto-format --- plugins/minigames/infection.py | 112 +++++++++++++++++---------------- 1 file changed, 59 insertions(+), 53 deletions(-) diff --git a/plugins/minigames/infection.py b/plugins/minigames/infection.py index 017892c5..a509ec89 100644 --- a/plugins/minigames/infection.py +++ b/plugins/minigames/infection.py @@ -52,19 +52,22 @@ slow = 'Slow' slowest = 'Slowest' insane = 'Insane' - + + def ba_get_api_version(): return 6 + def ba_get_levels(): - return [babase._level.Level( - name, - gametype=Infection, - settings={}, - preview_texture_name='footballStadiumPreview')] + return [babase._level.Level( + name, + gametype=Infection, + settings={}, + preview_texture_name='footballStadiumPreview')] + class myMine(Bomb): - #reason for the mine class is so we can add the death zone + # reason for the mine class is so we can add the death zone def __init__(self, pos: Sequence[float] = (0.0, 1.0, 0.0)): Bomb.__init__(self, position=pos, bomb_type='land_mine') @@ -74,17 +77,17 @@ def __init__(self, self.zone = bs.newnode( 'locator', attrs={ - 'shape':'circle', - 'position':self.node.position, - 'color':(1,0,0), - 'opacity':0.5, - 'draw_beauty':showInSpace, - 'additive':True}) + 'shape': 'circle', + 'position': self.node.position, + 'color': (1, 0, 0), + 'opacity': 0.5, + 'draw_beauty': showInSpace, + 'additive': True}) bs.animate_array( self.zone, 'size', 1, - {0:[0.0], 0.05:[2*self.rad]}) + {0: [0.0], 0.05: [2*self.rad]}) def handlemessage(self, msg: Any) -> Any: if isinstance(msg, bs.DieMessage): @@ -95,18 +98,21 @@ def handlemessage(self, msg: Any) -> Any: self.zone, 'size', 1, - {0:[2*self.rad], 0.05:[0]}) + {0: [2*self.rad], 0.05: [0]}) self.zone = None super().handlemessage(msg) else: super().handlemessage(msg) + class Player(bs.Player['Team']): """Our player type for this game.""" + def __init__(self) -> None: self.survival_seconds: Optional[int] = None self.death_time: Optional[float] = None + class Team(bs.Team[Player]): """Our team type for this game.""" @@ -122,7 +128,6 @@ class Infection(bs.TeamGameActivity[Player, Team]): announce_player_deaths = True allow_mid_activity_joins = False - @classmethod def get_available_settings( cls, sessiontype: Type[bs.Session]) -> List[babase.Setting]: @@ -151,7 +156,7 @@ def get_available_settings( choices=[ ('10s', 10), ('20s', 20), - ('30s',30), + ('30s', 30), ('1 Minute', 60), ], default=20, @@ -233,7 +238,7 @@ def on_player_join(self, player: Player) -> None: player.survival_seconds = self._timer.getstarttime() bs.broadcastmessage( babase.Lstr(resource='playerDelayedJoinText', - subs=[('${PLAYER}', player.getname(full=True))]), + subs=[('${PLAYER}', player.getname(full=True))]), color=(0, 1, 0), ) return @@ -256,35 +261,35 @@ def _mine_update(self) -> None: if not m.node: self.mines.remove(m) else: - #First, check if any player is within the current death zone + # First, check if any player is within the current death zone for player in self.players: if not player.actor is None: if player.actor.is_alive(): p1 = player.actor.node.position p2 = m.node.position diff = (babase.Vec3(p1[0]-p2[0], - 0.0, - p1[2]-p2[2])) + 0.0, + p1[2]-p2[2])) dist = (diff.length()) if dist < m.rad: player.actor.handlemessage(bs.DieMessage()) - #Now tell the circle to grow to the new size + # Now tell the circle to grow to the new size if m.rad < self._max_size: bs.animate_array( - m.zone, 'size' ,1, - {0:[m.rad*2], - self._update_rate:[(m.rad+self._growth_rate)*2]}) + m.zone, 'size', 1, + {0: [m.rad*2], + self._update_rate: [(m.rad+self._growth_rate)*2]}) # Tell the circle to be the new size. # This will be the new check radius next time. m.rad += self._growth_rate - #make a new mine if needed. + # make a new mine if needed. if self.mine_count < self._max_mines: pos = self.getRandomPowerupPoint() self.mine_count += 1 self._flash_mine(pos) bs.timer(0.95, babase.Call(self._make_mine, pos)) - def _make_mine(self,posn: Sequence[float]) -> None: + def _make_mine(self, posn: Sequence[float]) -> None: m = myMine(pos=posn) m.arm() self.mines.append(m) @@ -390,9 +395,9 @@ def spawn_player_spaz(self, light_color = babase._math.normalized_color(color) display_color = _babase.safecolor(color, target_intensity=0.75) spaz = PlayerSpaz(color=color, - highlight=highlight, - character=player.character, - player=player) + highlight=highlight, + character=player.character, + player=player) player.actor = spaz assert spaz.node @@ -426,45 +431,46 @@ def spawn_player_spaz(self, return spaz def getRandomPowerupPoint(self) -> None: - #So far, randomized points only figured out for mostly rectangular maps. - #Boxes will still fall through holes, but shouldn't be terrible problem (hopefully) - #If you add stuff here, need to add to "supported maps" above. - #['Doom Shroom', 'Rampage', 'Hockey Stadium', 'Courtyard', 'Crag Castle', 'Big G', 'Football Stadium'] + # So far, randomized points only figured out for mostly rectangular maps. + # Boxes will still fall through holes, but shouldn't be terrible problem (hopefully) + # If you add stuff here, need to add to "supported maps" above. + # ['Doom Shroom', 'Rampage', 'Hockey Stadium', 'Courtyard', 'Crag Castle', 'Big G', 'Football Stadium'] myMap = self.map.getname() - #print(myMap) + # print(myMap) if myMap == 'Doom Shroom': while True: - x = random.uniform(-1.0,1.0) - y = random.uniform(-1.0,1.0) - if x*x+y*y < 1.0: break - return ((8.0*x,2.5,-3.5+5.0*y)) + x = random.uniform(-1.0, 1.0) + y = random.uniform(-1.0, 1.0) + if x*x+y*y < 1.0: + break + return ((8.0*x, 2.5, -3.5+5.0*y)) elif myMap == 'Rampage': - x = random.uniform(-6.0,7.0) - y = random.uniform(-6.0,-2.5) + x = random.uniform(-6.0, 7.0) + y = random.uniform(-6.0, -2.5) return ((x, 5.2, y)) elif myMap == 'Hockey Stadium': - x = random.uniform(-11.5,11.5) - y = random.uniform(-4.5,4.5) + x = random.uniform(-11.5, 11.5) + y = random.uniform(-4.5, 4.5) return ((x, 0.2, y)) elif myMap == 'Courtyard': - x = random.uniform(-4.3,4.3) - y = random.uniform(-4.4,0.3) + x = random.uniform(-4.3, 4.3) + y = random.uniform(-4.4, 0.3) return ((x, 3.0, y)) elif myMap == 'Crag Castle': - x = random.uniform(-6.7,8.0) - y = random.uniform(-6.0,0.0) + x = random.uniform(-6.7, 8.0) + y = random.uniform(-6.0, 0.0) return ((x, 10.0, y)) elif myMap == 'Big G': - x = random.uniform(-8.7,8.0) - y = random.uniform(-7.5,6.5) + x = random.uniform(-8.7, 8.0) + y = random.uniform(-7.5, 6.5) return ((x, 3.5, y)) elif myMap == 'Football Stadium': - x = random.uniform(-12.5,12.5) - y = random.uniform(-5.0,5.5) + x = random.uniform(-12.5, 12.5) + y = random.uniform(-5.0, 5.5) return ((x, 0.32, y)) else: - x = random.uniform(-5.0,5.0) - y = random.uniform(-6.0,0.0) + x = random.uniform(-5.0, 5.0) + y = random.uniform(-6.0, 0.0) return ((x, 8.0, y)) def end_game(self) -> None: From 6269539ba754d0c4454e5e5bd3e7291b85dacc31 Mon Sep 17 00:00:00 2001 From: SenjuZoro Date: Tue, 22 Aug 2023 00:51:20 +0000 Subject: [PATCH 0700/1464] [ci] apply-version-metadata --- plugins/minigames.json | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/plugins/minigames.json b/plugins/minigames.json index c27493a4..f66e5cae 100644 --- a/plugins/minigames.json +++ b/plugins/minigames.json @@ -784,7 +784,12 @@ } ], "versions": { - "1.0.0": null + "1.0.0": { + "api_version": 8, + "commit_sha": "47a1ca8", + "released_on": "22-08-2023", + "md5sum": "398cf911195c4904b281ed05767e25f4" + } } }, "super_duel": { @@ -831,4 +836,4 @@ } } } -} +} \ No newline at end of file From c3eea1c56f57c63e0555cefcdeb9200227dc66ae Mon Sep 17 00:00:00 2001 From: SenjuZoro <69396975+SenjuZoro@users.noreply.github.com> Date: Tue, 22 Aug 2023 19:58:53 +0200 Subject: [PATCH 0701/1464] Bomb on my Head minigame --- plugins/minigames/bomb_on_my_head.py | 340 +++++++++++++++++++++++++++ 1 file changed, 340 insertions(+) create mode 100644 plugins/minigames/bomb_on_my_head.py diff --git a/plugins/minigames/bomb_on_my_head.py b/plugins/minigames/bomb_on_my_head.py new file mode 100644 index 00000000..c8aba909 --- /dev/null +++ b/plugins/minigames/bomb_on_my_head.py @@ -0,0 +1,340 @@ +# ba_meta require api 8 +# (see https://ballistica.net/wiki/meta-tag-system) + +from __future__ import annotations + +from typing import TYPE_CHECKING + +import babase +import bauiv1 as bui +import bascenev1 as bs +import random +from bascenev1lib.actor.onscreentimer import OnScreenTimer +from bascenev1lib.actor.spaz import BombDiedMessage +from bascenev1lib.actor.playerspaz import PlayerSpaz +from bascenev1lib.actor import bomb as stdbomb + +if TYPE_CHECKING: + from typing import Any, Sequence + + +lang = bs.app.lang.language + +if lang == 'Spanish': + name = 'Bomba en mi Cabeza' + description = ('Siempre tendrás una bomba en la cabeza.\n' + '¡Sobrevive tanto como puedas!') + description_ingame = '¡Sobrevive tanto como puedas!' + # description_short = 'Elimina {} Jugadores para ganar' + maxbomblimit = 'Límite Máximo de Bombas' + mbltwo = 'Dos' + mblthree = 'Tres' + mblfour = 'Cuatro' +else: + name = 'Bomb on my Head' + description = ('You\'ll always have a bomb on your head.\n' + 'Survive as long as you can!') + description_ingame = 'Survive as long as you can!' + # description_short = 'Kill {} Players to win' + maxbomblimit = 'Max Bomb Limit' + mbltwo = 'Two' + mblthree = 'Three' + mblfour = 'Four' + + +class NewPlayerSpaz(PlayerSpaz): + + def handlemessage(self, msg: Any) -> Any: + if isinstance(msg, BombDiedMessage): + self.bomb_count += 1 + self.check_avalible_bombs() + else: + return super().handlemessage(msg) + + def check_avalible_bombs(self) -> None: + if not self.node: + return + if self.bomb_count <= 0: + return + if not self.node.hold_node: + self.on_bomb_press() + self.on_bomb_release() + + def start_bomb_checking(self) -> None: + self.check_avalible_bombs() + self._bomb_check_timer = bs.timer( + 0.5, + bs.WeakCall(self.check_avalible_bombs), + repeat=True) + + def drop_bomb(self) -> stdbomb.Bomb | None: + lifespan = 3.0 + + if self.bomb_count <= 0 or self.frozen: + return None + assert self.node + pos = self.node.position_forward + vel = self.node.velocity + + bomb_type = 'normal' + + bomb = stdbomb.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() + + bs.animate(bomb.node, 'mesh_scale', { + 0.0: 0.0, + lifespan*0.1: 1.5, + lifespan*0.5: 1.0 + }) + + self.bomb_count -= 1 + bomb.node.add_death_action( + bs.WeakCall(self.handlemessage, BombDiedMessage()) + ) + self._pick_up(bomb.node) + + for clb in self._dropped_bomb_callbacks: + clb(self, bomb) + + return bomb + + +class Player(bs.Player['Team']): + """Our player type for this game.""" + + def __init__(self) -> None: + super().__init__() + self.death_time: float | None = None + + +class Team(bs.Team[Player]): + """Our team type for this game.""" + + +# ba_meta export bascenev1.GameActivity +class BombOnMyHeadGame(bs.TeamGameActivity[Player, Team]): + + name = name + description = description + scoreconfig = bs.ScoreConfig( + label='Survived', scoretype=bs.ScoreType.MILLISECONDS, version='B' + ) + # Show messages when players die since it's meaningful here. + announce_player_deaths = True + + allow_mid_activity_joins = False + + @classmethod + def get_available_settings( + cls, sessiontype: type[bs.Session] + ) -> list[babase.Setting]: + settings = [ + bs.IntChoiceSetting( + maxbomblimit, + choices=[ + ('Normal', 1), + (mbltwo, 2), + (mblthree, 3), + (mblfour, 4), + ], + default=1, + ), + bs.IntChoiceSetting( + 'Time Limit', + choices=[ + ('None', 0), + ('1 Minute', 60), + ('2 Minutes', 120), + ('5 Minutes', 300), + ('10 Minutes', 600), + ('20 Minutes', 1200), + ], + default=0, + ), + bs.BoolSetting('Epic Mode', default=False), + ] + return settings + + @classmethod + def supports_session_type(cls, sessiontype: type[bs.Session]) -> bool: + return issubclass(sessiontype, bs.DualTeamSession) or issubclass( + sessiontype, bs.FreeForAllSession + ) + + @classmethod + def get_supported_maps(cls, sessiontype: type[bs.Session]) -> list[str]: + return bs.app.classic.getmaps('melee') + + def __init__(self, settings: dict): + super().__init__(settings) + self._max_bomb_limit = int(settings[maxbomblimit]) + self._epic_mode = bool(settings['Epic Mode']) + self._time_limit = float(settings['Time Limit']) + self._last_player_death_time: float | None = None + self._timer: OnScreenTimer | None = None + + # Some base class overrides: + self.default_music = ( + bs.MusicType.EPIC if self._epic_mode else bs.MusicType.SURVIVAL + ) + if self._epic_mode: + self.slow_motion = True + + def get_instance_description(self) -> str | Sequence: + return description_ingame + + def on_begin(self) -> None: + super().on_begin() + self.setup_standard_time_limit(self._time_limit) + self._timer = OnScreenTimer() + self._timer.start() + + def spawn_player(self, player: Player) -> bs.Actor: + from babase import _math + from bascenev1._gameutils import animate + from bascenev1._coopsession import CoopSession + + if isinstance(self.session, bs.DualTeamSession): + position = self.map.get_start_position(player.team.id) + else: + # otherwise do free-for-all spawn locations + position = self.map.get_ffa_start_position(self.players) + angle = None + name = player.getname() + color = player.color + highlight = player.highlight + + light_color = _math.normalized_color(color) + display_color = babase.safecolor(color, target_intensity=0.75) + + spaz = NewPlayerSpaz(color=color, + highlight=highlight, + character=player.character, + player=player) + + player.actor = spaz + assert spaz.node + + spaz.node.name = name + spaz.node.name_color = display_color + spaz.connect_controls_to_player() + + # Move to the stand position and add a flash of light. + spaz.handlemessage( + bs.StandMessage( + position, + angle if angle is not None else random.uniform(0, 360))) + self._spawn_sound.play(1, position=spaz.node.position) + light = bs.newnode('light', attrs={'color': light_color}) + spaz.node.connectattr('position', light, 'position') + animate(light, 'intensity', {0: 0, 0.25: 1, 0.5: 0}) + bs.timer(0.5, light.delete) + + bs.timer(1.0, bs.WeakCall(spaz.start_bomb_checking)) + spaz.set_bomb_count(self._max_bomb_limit) + + def handlemessage(self, msg: Any) -> Any: + if isinstance(msg, bs.PlayerDiedMessage): + + # Augment standard behavior. + super().handlemessage(msg) + + curtime = bs.time() + + # Record the player's moment of death. + # assert isinstance(msg.spaz.player + msg.getplayer(Player).death_time = curtime + + # In co-op mode, end the game the instant everyone dies + # (more accurate looking). + # In teams/ffa, allow a one-second fudge-factor so we can + # get more draws if players die basically at the same time. + if isinstance(self.session, bs.CoopSession): + # Teams will still show up if we check now.. check in + # the next cycle. + babase.pushcall(self._check_end_game) + + # Also record this for a final setting of the clock. + self._last_player_death_time = curtime + else: + bs.timer(1.0, self._check_end_game) + + else: + # Default handler: + return super().handlemessage(msg) + return None + + def _check_end_game(self) -> None: + living_team_count = 0 + for team in self.teams: + for player in team.players: + if player.is_alive(): + living_team_count += 1 + break + + # In co-op, we go till everyone is dead.. otherwise we go + # until one team remains. + if isinstance(self.session, bs.CoopSession): + if living_team_count <= 0: + self.end_game() + else: + if living_team_count <= 1: + self.end_game() + + + def end_game(self) -> None: + cur_time = bs.time() + assert self._timer is not None + start_time = self._timer.getstarttime() + + # Mark death-time as now for any still-living players + # and award players points for how long they lasted. + # (these per-player scores are only meaningful in team-games) + for team in self.teams: + for player in team.players: + survived = False + + # Throw an extra fudge factor in so teams that + # didn't die come out ahead of teams that did. + if player.death_time is None: + survived = True + player.death_time = cur_time + 1 + + # Award a per-player score depending on how many seconds + # they lasted (per-player scores only affect teams mode; + # everywhere else just looks at the per-team score). + score = int(player.death_time - self._timer.getstarttime()) + if survived: + score += 50 # A bit extra for survivors. + self.stats.player_scored(player, score, screenmessage=False) + + # Stop updating our time text, and set the final time to match + # exactly when our last guy died. + self._timer.stop(endtime=self._last_player_death_time) + + # Ok now calc game results: set a score for each team and then tell + # the game to end. + results = bs.GameResults() + + # Remember that 'free-for-all' mode is simply a special form + # of 'teams' mode where each player gets their own team, so we can + # just always deal in teams and have all cases covered. + for team in self.teams: + + # Set the team score to the max time survived by any player on + # that team. + longest_life = 0.0 + for player in team.players: + assert player.death_time is not None + longest_life = max(longest_life, player.death_time - start_time) + + # Submit the score value in milliseconds. + results.set_team_score(team, int(1000.0 * longest_life)) + + self.end(results=results) From 73ca16f1899127655ba52a662fcf26b0871f0d6e Mon Sep 17 00:00:00 2001 From: SenjuZoro <69396975+SenjuZoro@users.noreply.github.com> Date: Tue, 22 Aug 2023 20:01:29 +0200 Subject: [PATCH 0702/1464] Update minigames.json --- plugins/minigames.json | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/plugins/minigames.json b/plugins/minigames.json index f66e5cae..de4d2561 100644 --- a/plugins/minigames.json +++ b/plugins/minigames.json @@ -773,6 +773,20 @@ } } }, + "bomb_on_my_head": { + "description": "Bomb on your head, Survive as long as you can!", + "external_url": "", + "authors": [ + { + "name": "", + "email": "", + "discord": "" + } + ], + "versions": { + "1.0.0": null + } + }, "infection": { "description": "It's spreading, avoid the spread!", "external_url": "", @@ -836,4 +850,4 @@ } } } -} \ No newline at end of file +} From c39664c24c8ee4ad388938888bba0a430e9e4c41 Mon Sep 17 00:00:00 2001 From: SenjuZoro Date: Tue, 22 Aug 2023 18:02:36 +0000 Subject: [PATCH 0703/1464] [ci] auto-format --- plugins/minigames/bomb_on_my_head.py | 601 +++++++++++++-------------- 1 file changed, 300 insertions(+), 301 deletions(-) diff --git a/plugins/minigames/bomb_on_my_head.py b/plugins/minigames/bomb_on_my_head.py index c8aba909..91a6a621 100644 --- a/plugins/minigames/bomb_on_my_head.py +++ b/plugins/minigames/bomb_on_my_head.py @@ -15,326 +15,325 @@ from bascenev1lib.actor import bomb as stdbomb if TYPE_CHECKING: - from typing import Any, Sequence + from typing import Any, Sequence lang = bs.app.lang.language if lang == 'Spanish': - name = 'Bomba en mi Cabeza' - description = ('Siempre tendrás una bomba en la cabeza.\n' - '¡Sobrevive tanto como puedas!') - description_ingame = '¡Sobrevive tanto como puedas!' - # description_short = 'Elimina {} Jugadores para ganar' - maxbomblimit = 'Límite Máximo de Bombas' - mbltwo = 'Dos' - mblthree = 'Tres' - mblfour = 'Cuatro' + name = 'Bomba en mi Cabeza' + description = ('Siempre tendrás una bomba en la cabeza.\n' + '¡Sobrevive tanto como puedas!') + description_ingame = '¡Sobrevive tanto como puedas!' + # description_short = 'Elimina {} Jugadores para ganar' + maxbomblimit = 'Límite Máximo de Bombas' + mbltwo = 'Dos' + mblthree = 'Tres' + mblfour = 'Cuatro' else: - name = 'Bomb on my Head' - description = ('You\'ll always have a bomb on your head.\n' - 'Survive as long as you can!') - description_ingame = 'Survive as long as you can!' - # description_short = 'Kill {} Players to win' - maxbomblimit = 'Max Bomb Limit' - mbltwo = 'Two' - mblthree = 'Three' - mblfour = 'Four' + name = 'Bomb on my Head' + description = ('You\'ll always have a bomb on your head.\n' + 'Survive as long as you can!') + description_ingame = 'Survive as long as you can!' + # description_short = 'Kill {} Players to win' + maxbomblimit = 'Max Bomb Limit' + mbltwo = 'Two' + mblthree = 'Three' + mblfour = 'Four' class NewPlayerSpaz(PlayerSpaz): - def handlemessage(self, msg: Any) -> Any: - if isinstance(msg, BombDiedMessage): - self.bomb_count += 1 - self.check_avalible_bombs() - else: - return super().handlemessage(msg) - - def check_avalible_bombs(self) -> None: - if not self.node: - return - if self.bomb_count <= 0: - return - if not self.node.hold_node: - self.on_bomb_press() - self.on_bomb_release() - - def start_bomb_checking(self) -> None: - self.check_avalible_bombs() - self._bomb_check_timer = bs.timer( - 0.5, - bs.WeakCall(self.check_avalible_bombs), - repeat=True) - - def drop_bomb(self) -> stdbomb.Bomb | None: - lifespan = 3.0 - - if self.bomb_count <= 0 or self.frozen: - return None - assert self.node - pos = self.node.position_forward - vel = self.node.velocity - - bomb_type = 'normal' - - bomb = stdbomb.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() - - bs.animate(bomb.node, 'mesh_scale', { - 0.0: 0.0, - lifespan*0.1: 1.5, - lifespan*0.5: 1.0 - }) - - self.bomb_count -= 1 - bomb.node.add_death_action( - bs.WeakCall(self.handlemessage, BombDiedMessage()) - ) - self._pick_up(bomb.node) - - for clb in self._dropped_bomb_callbacks: - clb(self, bomb) - - return bomb + def handlemessage(self, msg: Any) -> Any: + if isinstance(msg, BombDiedMessage): + self.bomb_count += 1 + self.check_avalible_bombs() + else: + return super().handlemessage(msg) + + def check_avalible_bombs(self) -> None: + if not self.node: + return + if self.bomb_count <= 0: + return + if not self.node.hold_node: + self.on_bomb_press() + self.on_bomb_release() + + def start_bomb_checking(self) -> None: + self.check_avalible_bombs() + self._bomb_check_timer = bs.timer( + 0.5, + bs.WeakCall(self.check_avalible_bombs), + repeat=True) + + def drop_bomb(self) -> stdbomb.Bomb | None: + lifespan = 3.0 + + if self.bomb_count <= 0 or self.frozen: + return None + assert self.node + pos = self.node.position_forward + vel = self.node.velocity + + bomb_type = 'normal' + + bomb = stdbomb.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() + + bs.animate(bomb.node, 'mesh_scale', { + 0.0: 0.0, + lifespan*0.1: 1.5, + lifespan*0.5: 1.0 + }) + + self.bomb_count -= 1 + bomb.node.add_death_action( + bs.WeakCall(self.handlemessage, BombDiedMessage()) + ) + self._pick_up(bomb.node) + + for clb in self._dropped_bomb_callbacks: + clb(self, bomb) + + return bomb class Player(bs.Player['Team']): - """Our player type for this game.""" + """Our player type for this game.""" - def __init__(self) -> None: - super().__init__() - self.death_time: float | None = None + def __init__(self) -> None: + super().__init__() + self.death_time: float | None = None class Team(bs.Team[Player]): - """Our team type for this game.""" + """Our team type for this game.""" # ba_meta export bascenev1.GameActivity class BombOnMyHeadGame(bs.TeamGameActivity[Player, Team]): - name = name - description = description - scoreconfig = bs.ScoreConfig( - label='Survived', scoretype=bs.ScoreType.MILLISECONDS, version='B' - ) - # Show messages when players die since it's meaningful here. - announce_player_deaths = True - - allow_mid_activity_joins = False - - @classmethod - def get_available_settings( - cls, sessiontype: type[bs.Session] - ) -> list[babase.Setting]: - settings = [ - bs.IntChoiceSetting( - maxbomblimit, - choices=[ - ('Normal', 1), - (mbltwo, 2), - (mblthree, 3), - (mblfour, 4), - ], - default=1, - ), - bs.IntChoiceSetting( - 'Time Limit', - choices=[ - ('None', 0), - ('1 Minute', 60), - ('2 Minutes', 120), - ('5 Minutes', 300), - ('10 Minutes', 600), - ('20 Minutes', 1200), - ], - default=0, - ), - bs.BoolSetting('Epic Mode', default=False), - ] - return settings - - @classmethod - def supports_session_type(cls, sessiontype: type[bs.Session]) -> bool: - return issubclass(sessiontype, bs.DualTeamSession) or issubclass( - sessiontype, bs.FreeForAllSession - ) - - @classmethod - def get_supported_maps(cls, sessiontype: type[bs.Session]) -> list[str]: - return bs.app.classic.getmaps('melee') - - def __init__(self, settings: dict): - super().__init__(settings) - self._max_bomb_limit = int(settings[maxbomblimit]) - self._epic_mode = bool(settings['Epic Mode']) - self._time_limit = float(settings['Time Limit']) - self._last_player_death_time: float | None = None - self._timer: OnScreenTimer | None = None - - # Some base class overrides: - self.default_music = ( - bs.MusicType.EPIC if self._epic_mode else bs.MusicType.SURVIVAL - ) - if self._epic_mode: - self.slow_motion = True - - def get_instance_description(self) -> str | Sequence: - return description_ingame - - def on_begin(self) -> None: - super().on_begin() - self.setup_standard_time_limit(self._time_limit) - self._timer = OnScreenTimer() - self._timer.start() - - def spawn_player(self, player: Player) -> bs.Actor: - from babase import _math - from bascenev1._gameutils import animate - from bascenev1._coopsession import CoopSession - - if isinstance(self.session, bs.DualTeamSession): - position = self.map.get_start_position(player.team.id) - else: - # otherwise do free-for-all spawn locations - position = self.map.get_ffa_start_position(self.players) - angle = None - name = player.getname() - color = player.color - highlight = player.highlight - - light_color = _math.normalized_color(color) - display_color = babase.safecolor(color, target_intensity=0.75) - - spaz = NewPlayerSpaz(color=color, - highlight=highlight, - character=player.character, - player=player) - - player.actor = spaz - assert spaz.node - - spaz.node.name = name - spaz.node.name_color = display_color - spaz.connect_controls_to_player() - - # Move to the stand position and add a flash of light. - spaz.handlemessage( - bs.StandMessage( - position, - angle if angle is not None else random.uniform(0, 360))) - self._spawn_sound.play(1, position=spaz.node.position) - light = bs.newnode('light', attrs={'color': light_color}) - spaz.node.connectattr('position', light, 'position') - animate(light, 'intensity', {0: 0, 0.25: 1, 0.5: 0}) - bs.timer(0.5, light.delete) - - bs.timer(1.0, bs.WeakCall(spaz.start_bomb_checking)) - spaz.set_bomb_count(self._max_bomb_limit) - - def handlemessage(self, msg: Any) -> Any: - if isinstance(msg, bs.PlayerDiedMessage): - - # Augment standard behavior. - super().handlemessage(msg) - - curtime = bs.time() - - # Record the player's moment of death. - # assert isinstance(msg.spaz.player - msg.getplayer(Player).death_time = curtime - - # In co-op mode, end the game the instant everyone dies - # (more accurate looking). - # In teams/ffa, allow a one-second fudge-factor so we can - # get more draws if players die basically at the same time. - if isinstance(self.session, bs.CoopSession): - # Teams will still show up if we check now.. check in - # the next cycle. - babase.pushcall(self._check_end_game) - - # Also record this for a final setting of the clock. - self._last_player_death_time = curtime - else: - bs.timer(1.0, self._check_end_game) - - else: - # Default handler: - return super().handlemessage(msg) - return None - - def _check_end_game(self) -> None: - living_team_count = 0 - for team in self.teams: - for player in team.players: - if player.is_alive(): - living_team_count += 1 - break - - # In co-op, we go till everyone is dead.. otherwise we go - # until one team remains. - if isinstance(self.session, bs.CoopSession): - if living_team_count <= 0: - self.end_game() - else: - if living_team_count <= 1: - self.end_game() - - - def end_game(self) -> None: - cur_time = bs.time() - assert self._timer is not None - start_time = self._timer.getstarttime() - - # Mark death-time as now for any still-living players - # and award players points for how long they lasted. - # (these per-player scores are only meaningful in team-games) - for team in self.teams: - for player in team.players: - survived = False - - # Throw an extra fudge factor in so teams that - # didn't die come out ahead of teams that did. - if player.death_time is None: - survived = True - player.death_time = cur_time + 1 - - # Award a per-player score depending on how many seconds - # they lasted (per-player scores only affect teams mode; - # everywhere else just looks at the per-team score). - score = int(player.death_time - self._timer.getstarttime()) - if survived: - score += 50 # A bit extra for survivors. - self.stats.player_scored(player, score, screenmessage=False) - - # Stop updating our time text, and set the final time to match - # exactly when our last guy died. - self._timer.stop(endtime=self._last_player_death_time) - - # Ok now calc game results: set a score for each team and then tell - # the game to end. - results = bs.GameResults() - - # Remember that 'free-for-all' mode is simply a special form - # of 'teams' mode where each player gets their own team, so we can - # just always deal in teams and have all cases covered. - for team in self.teams: - - # Set the team score to the max time survived by any player on - # that team. - longest_life = 0.0 - for player in team.players: - assert player.death_time is not None - longest_life = max(longest_life, player.death_time - start_time) - - # Submit the score value in milliseconds. - results.set_team_score(team, int(1000.0 * longest_life)) - - self.end(results=results) + name = name + description = description + scoreconfig = bs.ScoreConfig( + label='Survived', scoretype=bs.ScoreType.MILLISECONDS, version='B' + ) + # Show messages when players die since it's meaningful here. + announce_player_deaths = True + + allow_mid_activity_joins = False + + @classmethod + def get_available_settings( + cls, sessiontype: type[bs.Session] + ) -> list[babase.Setting]: + settings = [ + bs.IntChoiceSetting( + maxbomblimit, + choices=[ + ('Normal', 1), + (mbltwo, 2), + (mblthree, 3), + (mblfour, 4), + ], + default=1, + ), + bs.IntChoiceSetting( + 'Time Limit', + choices=[ + ('None', 0), + ('1 Minute', 60), + ('2 Minutes', 120), + ('5 Minutes', 300), + ('10 Minutes', 600), + ('20 Minutes', 1200), + ], + default=0, + ), + bs.BoolSetting('Epic Mode', default=False), + ] + return settings + + @classmethod + def supports_session_type(cls, sessiontype: type[bs.Session]) -> bool: + return issubclass(sessiontype, bs.DualTeamSession) or issubclass( + sessiontype, bs.FreeForAllSession + ) + + @classmethod + def get_supported_maps(cls, sessiontype: type[bs.Session]) -> list[str]: + return bs.app.classic.getmaps('melee') + + def __init__(self, settings: dict): + super().__init__(settings) + self._max_bomb_limit = int(settings[maxbomblimit]) + self._epic_mode = bool(settings['Epic Mode']) + self._time_limit = float(settings['Time Limit']) + self._last_player_death_time: float | None = None + self._timer: OnScreenTimer | None = None + + # Some base class overrides: + self.default_music = ( + bs.MusicType.EPIC if self._epic_mode else bs.MusicType.SURVIVAL + ) + if self._epic_mode: + self.slow_motion = True + + def get_instance_description(self) -> str | Sequence: + return description_ingame + + def on_begin(self) -> None: + super().on_begin() + self.setup_standard_time_limit(self._time_limit) + self._timer = OnScreenTimer() + self._timer.start() + + def spawn_player(self, player: Player) -> bs.Actor: + from babase import _math + from bascenev1._gameutils import animate + from bascenev1._coopsession import CoopSession + + if isinstance(self.session, bs.DualTeamSession): + position = self.map.get_start_position(player.team.id) + else: + # otherwise do free-for-all spawn locations + position = self.map.get_ffa_start_position(self.players) + angle = None + name = player.getname() + color = player.color + highlight = player.highlight + + light_color = _math.normalized_color(color) + display_color = babase.safecolor(color, target_intensity=0.75) + + spaz = NewPlayerSpaz(color=color, + highlight=highlight, + character=player.character, + player=player) + + player.actor = spaz + assert spaz.node + + spaz.node.name = name + spaz.node.name_color = display_color + spaz.connect_controls_to_player() + + # Move to the stand position and add a flash of light. + spaz.handlemessage( + bs.StandMessage( + position, + angle if angle is not None else random.uniform(0, 360))) + self._spawn_sound.play(1, position=spaz.node.position) + light = bs.newnode('light', attrs={'color': light_color}) + spaz.node.connectattr('position', light, 'position') + animate(light, 'intensity', {0: 0, 0.25: 1, 0.5: 0}) + bs.timer(0.5, light.delete) + + bs.timer(1.0, bs.WeakCall(spaz.start_bomb_checking)) + spaz.set_bomb_count(self._max_bomb_limit) + + def handlemessage(self, msg: Any) -> Any: + if isinstance(msg, bs.PlayerDiedMessage): + + # Augment standard behavior. + super().handlemessage(msg) + + curtime = bs.time() + + # Record the player's moment of death. + # assert isinstance(msg.spaz.player + msg.getplayer(Player).death_time = curtime + + # In co-op mode, end the game the instant everyone dies + # (more accurate looking). + # In teams/ffa, allow a one-second fudge-factor so we can + # get more draws if players die basically at the same time. + if isinstance(self.session, bs.CoopSession): + # Teams will still show up if we check now.. check in + # the next cycle. + babase.pushcall(self._check_end_game) + + # Also record this for a final setting of the clock. + self._last_player_death_time = curtime + else: + bs.timer(1.0, self._check_end_game) + + else: + # Default handler: + return super().handlemessage(msg) + return None + + def _check_end_game(self) -> None: + living_team_count = 0 + for team in self.teams: + for player in team.players: + if player.is_alive(): + living_team_count += 1 + break + + # In co-op, we go till everyone is dead.. otherwise we go + # until one team remains. + if isinstance(self.session, bs.CoopSession): + if living_team_count <= 0: + self.end_game() + else: + if living_team_count <= 1: + self.end_game() + + def end_game(self) -> None: + cur_time = bs.time() + assert self._timer is not None + start_time = self._timer.getstarttime() + + # Mark death-time as now for any still-living players + # and award players points for how long they lasted. + # (these per-player scores are only meaningful in team-games) + for team in self.teams: + for player in team.players: + survived = False + + # Throw an extra fudge factor in so teams that + # didn't die come out ahead of teams that did. + if player.death_time is None: + survived = True + player.death_time = cur_time + 1 + + # Award a per-player score depending on how many seconds + # they lasted (per-player scores only affect teams mode; + # everywhere else just looks at the per-team score). + score = int(player.death_time - self._timer.getstarttime()) + if survived: + score += 50 # A bit extra for survivors. + self.stats.player_scored(player, score, screenmessage=False) + + # Stop updating our time text, and set the final time to match + # exactly when our last guy died. + self._timer.stop(endtime=self._last_player_death_time) + + # Ok now calc game results: set a score for each team and then tell + # the game to end. + results = bs.GameResults() + + # Remember that 'free-for-all' mode is simply a special form + # of 'teams' mode where each player gets their own team, so we can + # just always deal in teams and have all cases covered. + for team in self.teams: + + # Set the team score to the max time survived by any player on + # that team. + longest_life = 0.0 + for player in team.players: + assert player.death_time is not None + longest_life = max(longest_life, player.death_time - start_time) + + # Submit the score value in milliseconds. + results.set_team_score(team, int(1000.0 * longest_life)) + + self.end(results=results) From c0bbcd898602caed04fbaa0375dff533ebfb70e7 Mon Sep 17 00:00:00 2001 From: SenjuZoro Date: Tue, 22 Aug 2023 18:02:37 +0000 Subject: [PATCH 0704/1464] [ci] apply-version-metadata --- plugins/minigames.json | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/plugins/minigames.json b/plugins/minigames.json index de4d2561..1f982212 100644 --- a/plugins/minigames.json +++ b/plugins/minigames.json @@ -784,7 +784,12 @@ } ], "versions": { - "1.0.0": null + "1.0.0": { + "api_version": 8, + "commit_sha": "c39664c", + "released_on": "22-08-2023", + "md5sum": "daf75409557f12146c1a63d61f429e10" + } } }, "infection": { @@ -850,4 +855,4 @@ } } } -} +} \ No newline at end of file From 81a06b68b22cd3b678682371413fffb2c5b52571 Mon Sep 17 00:00:00 2001 From: Juleskie <141720829+heLlow-step-sis@users.noreply.github.com> Date: Sat, 26 Aug 2023 09:27:47 +0800 Subject: [PATCH 0705/1464] Add files via upload --- plugins/utilities/menu_theme.py | 1976 +++++++++++++++++++++++++++++++ 1 file changed, 1976 insertions(+) create mode 100644 plugins/utilities/menu_theme.py diff --git a/plugins/utilities/menu_theme.py b/plugins/utilities/menu_theme.py new file mode 100644 index 00000000..5c2b0813 --- /dev/null +++ b/plugins/utilities/menu_theme.py @@ -0,0 +1,1976 @@ +# ba_meta require api 8 +""" +Working for v1.7.20+ only +——————————————————————————————————————— +• Menu Theme v1.0.9 +• discord: riyukiiyan + +I appreciate any kind of modification. So feel free to share, edit and change credit string... no problem +Credits are unnecessary but are a much-appreciated gesture to show support to others :D + +[CHANGELOG]: +~ Support for BombSquad v1.7.26 +~ Fixed "Show Logo Text" checkmark not updating on imports and reset +~ Music changes: + >> Turn off music by selecting 'None' + >> Removed dupes, renamed some and added 2 new musics + +Special thanks to: +snowee, rikko, & unknown +——————————————————————————————————————— +""" +from __future__ import annotations + +from typing import List, Sequence, Callable, Any, cast + +from bascenev1lib.mainmenu import MainMenuActivity, NewsDisplay, _preload1 +from bauiv1lib.mainmenu import MainMenuWindow +from bauiv1lib.account.settings import AccountSettingsWindow +from bauiv1lib.colorpicker import ColorPicker, ColorPickerExact +from bauiv1lib.fileselector import FileSelectorWindow +from bauiv1lib.popup import PopupMenuWindow + +import _babase as _ba, babase as ba, bascenev1 as bs, bauiv1 as bui +import bascenev1lib.mainmenu as menu +import json +import os +import shutil +import random +import weakref + + +# defined version and author +__author__ = "Yann" +__version__ = "1.0.9" + +# frequently used variables references +config = bs.app.config +ui_type = bs.app.ui_v1.uiscale +ui_small = bs.UIScale.SMALL +ui_medium = bs.UIScale.MEDIUM +ui_large = bs.UIScale.LARGE + +# method references +original_unlocked_pro = bs.app.classic.accounts.have_pro +original_account_init = AccountSettingsWindow.__init__ + +# define globals +GLOBALS_REFLECTION = { + 'Powerup': 'powerup', + 'Character': 'char', + 'Soft': 'soft', + 'None': 'none' +} +GLOBALS_MUSIC = { + 'Menu': bs.MusicType.MENU, + 'Epic': bs.MusicType.EPIC, + 'Flag Catcher': bs.MusicType.FLAG_CATCHER, + 'Flying': bs.MusicType.FLYING, + 'Grand Romp': bs.MusicType.GRAND_ROMP, + 'Lobby': bs.MusicType.CHAR_SELECT, + 'Lobby Epic': bs.MusicType.SCORES, + 'Marching Forward': bs.MusicType.FORWARD_MARCH, + 'Marching Home': bs.MusicType.MARCHING, + 'Run Away': bs.MusicType.RUN_AWAY, + 'Scary': bs.MusicType.SCARY, + 'Sports': bs.MusicType.SPORTS, + 'Survival': bs.MusicType.SURVIVAL, + 'To The Death': bs.MusicType.TO_THE_DEATH, + 'None': None, +} +GLOBALS_MAPDATA = { + "The Pad (with trees)": { + "Camera Bounds": (0.3544110667, 4.493562578, -2.518391331, 16.64754831, 8.06138989, 18.5029888), + "Map Color": (1.0, 1.0, 1.0), + "Map Reflection Scale": 0.3, + "Ambient": (1.14, 1.1, 1.0), + "Tint": (1.06, 1.04, 1.03), + "Vignette Outer": (0.45, 0.55, 0.54), + "Vignette Inner": (0.99, 0.98, 0.98) + }, + "The Pad": { + "Camera Bounds": (0.3544110667, 4.493562578, -2.518391331, 16.64754831, 8.06138989, 18.5029888), + "Map Color": (1.0, 1.0, 1.0), + "Map Reflection Scale": 0.3, + "Ambient": (1.1, 1.1, 1.0), + "Tint": (1.1, 1.1, 1.0), + "Vignette Outer": (0.7, 0.65, 0.75), + "Vignette Inner": (0.95, 0.95, 0.93) + }, + "Big G": { + "Camera Bounds": (-0.4011866709, 2.331310176, -0.5426286416, 19.11746262, 10.19675564, 23.50119277), + "Map Color": (0.7, 0.7, 0.7), + "Map Reflection Scale": 0.0, + "Ambient": (1.1, 1.2, 1.3), + "Tint": (1.1, 1.2, 1.3), + "Vignette Outer": (0.65, 0.6, 0.55), + "Vignette Inner": (0.9, 0.9, 0.93) + }, + "Bridgit": { + "Camera Bounds": (-0.2457963347, 3.828181068, -1.528362695, 19.14849937, 7.312788846, 8.436232726), + "Map Color": (1.0, 1.0, 1.0), + "Map Reflection Scale": 0.0, + "Ambient": (1.1, 1.2, 1.3), + "Tint": (1.1, 1.2, 1.3), + "Vignette Outer": (0.65, 0.6, 0.55), + "Vignette Inner": (0.9, 0.9, 0.93) + }, + "Courtyard": { + "Camera Bounds": (0.3544110667, 3.958431362, -2.175025358, 16.37702017, 7.755670126, 13.38680645), + "Map Color": (1.0, 1.0, 1.0), + "Map Reflection Scale": 0.0, + "Ambient": (1.2, 1.17, 1.1), + "Tint": (1.2, 1.17, 1.1), + "Vignette Outer": (0.6, 0.6, 0.64), + "Vignette Inner": (0.95, 0.95, 0.93) + }, + "Crag Castle": { + "Camera Bounds": (0.7033834902, 6.55869393, -3.153439808, 16.73648528, 14.94789935, 11.60063102), + "Map Color": (1.0, 1.0, 1.0), + "Map Reflection Scale": 0.0, + "Ambient": (1.15, 1.05, 0.75), + "Tint": (1.15, 1.05, 0.75), + "Vignette Outer": (0.6, 0.65, 0.6), + "Vignette Inner": (0.95, 0.95, 0.95) + }, + "Doom Shroom": { + "Camera Bounds": (0.4687647786, 2.320345088, -3.219423694, 21.34898078, 10.25529817, 14.67298352), + "Map Color": (1.0, 1.0, 1.0), + "Map Reflection Scale": 0.0, + "Ambient": (0.9, 1.3, 1.1), + "Tint": (0.82, 1.10, 1.15), + "Vignette Outer": (0.76, 0.76, 0.76), + "Vignette Inner": (0.95, 0.95, 0.99) + }, + "Happy Thoughts": { + "Camera Bounds": (-1.045859963, 12.67722855, -5.401537075, 34.46156851, 20.94044653, 0.6931564611), + "Map Color": (1.0, 1.0, 1.0), + "Map Reflection Scale": 0.0, + "Ambient": (1.3, 1.23, 1.0), + "Tint": (1.3, 1.23, 1.0), + "Vignette Outer": (0.64, 0.59, 0.69), + "Vignette Inner": (0.95, 0.95, 0.93) + }, + "Football Stadium": { + "Camera Bounds": (0.0, 1.185751251, 0.4326226188, 29.8180273, 11.57249038, 18.89134176), + "Map Color": (1.0, 1.0, 1.0), + "Map Reflection Scale": 0.0, + "Ambient": (1.3, 1.2, 1.0), + "Tint": (1.3, 1.2, 1.0), + "Vignette Outer": (0.57, 0.57, 0.57), + "Vignette Inner": (0.9, 0.9, 0.9) + }, + "Hockey Stadium": { + "Camera Bounds": (0.0, 0.7956858119, 0.0, 30.80223883, 0.5961646365, 13.88431707), + "Map Color": (1.0, 1.0, 1.0), + "Map Reflection Scale": 0.3, + "Ambient": (1.15, 1.25, 1.6), + "Tint": (1.2, 1.3, 1.33), + "Vignette Outer": (0.66, 0.67, 0.73), + "Vignette Inner": (0.93, 0.93, 0.95) + }, + "Lake Frigid": { + "Camera Bounds": (0.622753268, 3.958431362, -2.48708008, 20.62310543, 7.755670126, 12.33155049), + "Map Color": (1.0, 1.0, 1.0), + "Map Reflection Scale": 0.0, + "Ambient": (1, 1, 1), + "Tint": (1, 1, 1), + "Vignette Outer": (0.86, 0.86, 0.86), + "Vignette Inner": (0.95, 0.95, 0.99) + }, + "Monkey Face": { + "Camera Bounds": (-1.657177611, 4.132574186, -1.580485661, 17.36258946, 10.49020453, 12.31460338), + "Map Color": (1.0, 1.0, 1.0), + "Map Reflection Scale": 0.0, + "Ambient": (1.1, 1.2, 1.2), + "Tint": (1.1, 1.2, 1.2), + "Vignette Outer": (0.60, 0.62, 0.66), + "Vignette Inner": (0.97, 0.95, 0.93) + }, + "Rampage": { + "Camera Bounds": (0.3544110667, 5.616383286, -4.066055072, 19.90053969, 10.34051135, 8.16221072), + "Map Color": (1.0, 1.0, 1.0), + "Map Reflection Scale": 0.0, + "Ambient": (1.3, 1.2, 1.03), + "Tint": (1.2, 1.1, 0.97), + "Vignette Outer": (0.62, 0.64, 0.69), + "Vignette Inner": (0.97, 0.95, 0.93) + }, + "Roundabout": { + "Camera Bounds": (-1.552280404, 3.189001207, -2.40908495, 11.96255385, 8.857531648, 9.531689995), + "Map Color": (0.7, 0.7, 0.7), + "Map Reflection Scale": 0.0, + "Ambient": (1.0, 1.05, 1.1), + "Tint": (1.0, 1.05, 1.1), + "Vignette Outer": (0.63, 0.65, 0.7), + "Vignette Inner": (0.97, 0.95, 0.93) + }, + "Step Right Up": { + "Camera Bounds": (0.3544110667, 6.07676405, -2.271833016, 22.55121262, 10.14644532, 14.66087273), + "Map Color": (1.0, 1.0, 1.0), + "Map Reflection Scale": 0.0, + "Ambient": (1.2, 1.1, 1.0), + "Tint": (1.2, 1.1, 1.0), + "Vignette Outer": (1.2, 1.1, 1.0), + "Vignette Inner": (0.95, 0.95, 0.93) + }, + "Tower D": { + "Camera Bounds": (-0.4714933293, 2.887077774, -1.505479919, 17.90145968, 6.188484831, 15.96149117), + "Map Color": (1.0, 1.0, 1.0), + "Map Reflection Scale": 0.0, + "Ambient": (1.2, 1.1, 1.0), + "Tint": (1.15, 1.11, 1.03), + "Vignette Outer": (1.2, 1.1, 1.0), + "Vignette Inner": (0.95, 0.95, 0.95) + }, + "Tip Top": { + "Camera Bounds": (0.004375512593, 7.141135803, -0.01745294675, 21.12506141, 4.959977313, 16.6885592), + "Map Color": (0.7, 0.7, 0.7), + "Map Reflection Scale": 0.0, + "Ambient": (0.8, 0.9, 1.3), + "Tint": (0.8, 0.9, 1.3), + "Vignette Outer": (0.79, 0.79, 0.69), + "Vignette Inner": (0.97, 0.97, 0.99) + }, + "Zig Zag": { + "Camera Bounds": (-1.807378035, 3.943412768, -1.61304303, 23.01413538, 13.27980464, 10.0098376), + "Map Color": (1.0, 1.0, 1.0), + "Map Reflection Scale": 0.0, + "Ambient": (1.0, 1.15, 1.15), + "Tint": (1.0, 1.15, 1.15), + "Vignette Outer": (0.57, 0.59, 0.63), + "Vignette Inner": (0.97, 0.95, 0.93) + } +} + +class CustomColorPicker(ColorPicker): + + def _select_other(self): + from bauiv1lib import purchase + + CustomColorPickerExact(parent=self._parent, + position=self._position, + initial_color=self._initial_color, + delegate=self._delegate, + scale=self._scale, + offset=self._offset, + tag=self._tag) + self._delegate = None + self._transition_out() + + +class CustomColorPickerExact(ColorPickerExact): + + def _color_change_press(self, color_name: str, increasing: bool): + current_time = bui.apptime() + since_last = current_time - self._last_press_time + if ( + since_last < 0.2 + and self._last_press_color_name == color_name + and self._last_press_increasing == increasing + ): + self._change_speed += 0.25 + else: + self._change_speed = 1.0 + self._last_press_time = current_time + self._last_press_color_name = color_name + self._last_press_increasing = increasing + + color_index = ('r', 'g', 'b').index(color_name) + offs = int(self._change_speed) * (0.01 if increasing else -0.01) + self._color[color_index] = max( + -1.0, min(2.55, self._color[color_index] + offs) + ) + self._update_for_color() + + +class ConfigCheckBox: + widget: bui.Widget + + def __init__( + self, + parent: bui.Widget, + configkey: str, + position: tuple[float, float], + size: tuple[float, float], + displayname: str | bs.Lstr | None = None, + scale: float | None = None, + maxwidth: float | None = None, + autoselect: bool = True, + value_change_call: Callable[[Any], Any] | None = None): + + if displayname is None: + displayname = configkey + self._value_change_call = value_change_call + self._configkey = configkey + self.widget = bui.checkboxwidget( + parent=parent, + autoselect=autoselect, + position=position, + size=size, + text=displayname, + textcolor=(0.8, 0.8, 0.8), + value=bs.app.config[configkey], + on_value_change_call=self._value_changed, + scale=scale, + maxwidth=maxwidth, + ) + # complain if we outlive our checkbox + bui.uicleanupcheck(self, self.widget) + + def _value_changed(self, val: bool): + cfg = bs.app.config + cfg[self._configkey] = val + if self._value_change_call is not None: + self._value_change_call(val) + cfg.apply_and_commit() + + +class FreeEditWindow(bui.Window): + + def _do_enter(self): + + def _error() -> None: + bui.getsound('error').play(volume=2.0) + bui.screenmessage('error ' + u'😑😑', color=(1.0, 0.0, 0.0)) + + try: + if self.name_only: + value = bui.textwidget(query=self._text_field) + if not value.strip(): + return _error() + + self.delegate._export(self, txt=value) + else: + value = round(float(bui.textwidget(query=self._text_field)), 4) + self.delegate.free_edit_enter(self, c=self.config_name, txt=value) + + except ValueError: + return _error() + bui.containerwidget(edit=self._root_widget, transition=self._transition_out) + + def _activate_enter_button(self): + self._enter_button.activate() + + def _do_back(self): + bui.containerwidget(edit=self._root_widget, transition=self._transition_out) + + def __init__(self, delegate: Any = None, config_name: str = 'Menu Map', whitelist: List = [], name_only: bool = False, origin_widget: bui.widget = None): + self._transition_out = 'out_scale' if origin_widget else 'out_right' + scale_origin = origin_widget.get_screen_space_center() if origin_widget else None + transition = 'in_scale' if origin_widget else 'in_right' + width, height = 450, 230 + uiscale = bs.app.ui_v1.uiscale + + super().__init__(root_widget=bui.containerwidget( + size=(width, height), + transition=transition, + toolbar_visibility='menu_minimal_no_back', + scale_origin_stack_offset=scale_origin, + scale=(2.0 if uiscale is bs.UIScale.SMALL else + 1.5 if uiscale is bs.UIScale.MEDIUM else 1.0))) + + btn = bui.buttonwidget(parent=self._root_widget, + scale=0.5, + position=(40, height - 40), + size=(60, 60), + label='', + on_activate_call=self._do_back, + autoselect=True, + color=(0.55, 0.5, 0.6), + icon=bui.gettexture('crossOut'), + iconscale=1.2) + + self.config_name, self.delegate, self.name_only = config_name, delegate, name_only + + self._text_field = bui.textwidget( + parent=self._root_widget, + position=(125, height - 121), + size=(280, 46), + text='', + h_align='left', + v_align='center', + color=(0.9, 0.9, 0.9, 1.0), + description='', + editable=True, + padding=4, + max_chars=20 if name_only else 5, + on_return_press_call=self._activate_enter_button) + + bui.textwidget(parent=self._root_widget, + text='Current: ' + str(config[config_name]) if not name_only else 'Save as', + position=(220, height - 44), + color=(0.5, 0.5, 0.5, 1.0), + size=(90, 30), + h_align='right') + + bui.widget(edit=btn, down_widget=self._text_field) + + b_width = 200 + self._enter_button = btn2 = bui.buttonwidget( + parent=self._root_widget, + position=(width * 0.5 - b_width * 0.5, height - 200), + size=(b_width, 60), + scale=1.0, + label='Enter', + on_activate_call=self._do_enter) + bui.containerwidget(edit=self._root_widget, + cancel_button=btn, + start_button=btn2, + selected_child=self._text_field) + + +class MenuThemeWindow: + def __init__(self, origin_widget: bui.widget = None, accounts_window=None): + if origin_widget is not None: + self._transition_out = 'out_scale' + scale_origin = origin_widget.get_screen_space_center() + transition = 'in_scale' + else: + self._transition_out = 'out_right' + scale_origin = None + transition = 'in_right' + + self._choice_page: str = None + self._accounts_window = accounts_window + height = 500 if ui_type is ui_small else 772 + + self._root_widget = bui.containerwidget( + size=(445, 365) if ui_type is ui_small else (799, 576), + transition=transition, + toolbar_visibility='menu_minimal', + scale_origin_stack_offset=scale_origin, + scale=2.23 if ui_type is ui_small else 1.0, + stack_offset=(0, -35) if ui_type is ui_small else (0, 0) + ) + + self._scroll_border_parent = bui.scrollwidget( + parent=self._root_widget, + position=(39, 58) if ui_type is ui_small else (86, 39), + size=(375, 240) if ui_type is ui_small else (645, 463), + color=(0.52, 0.48, 0.63) + ) + + self._scroll_parent = bui.containerwidget( + parent=self._scroll_border_parent, + size=(450, height), + background=False, + claims_left_right=False, + claims_tab=False + ) + + self._back_button = bui.buttonwidget( + parent=self._root_widget, + position=(23, 310) if ui_type is ui_small else (80, 511), + size=(35, 35) if ui_type is ui_small else (55, 55), + color=(0.76, 0.42, 0.38), + button_type="backSmall", + textcolor=(1, 1, 1), + text_scale=0.8 if ui_type is ui_small else 1.0, + label="", + autoselect=True, + on_activate_call=bs.Call(self.close) + ) + + self._home_button = bui.buttonwidget( + parent=self._root_widget, + position=(383, 308) if ui_type is ui_small else (688, 511), + size=(60, 60) if ui_type is ui_small else (55, 55), + color=(0.76, 0.42, 0.38), + icon=bui.gettexture('crossOut'), + iconscale=1.2, + scale=0.59 if ui_type is ui_small else 0.92, + label="", + autoselect=True, + on_activate_call=bs.Call(self.close_all) + ) + + # menutheme title + bui.textwidget( + parent=self._root_widget, + position=(225, 327) if ui_type is ui_small else (415, 547), + size=(0, 0), + text="Menu Theme", + color=(0.8, 0.8, 0.8, 0.76), + maxwidth=290, + scale=0.95 if ui_type is ui_small else 1.25, + h_align='center', + v_align='center' + ) + + bui.textwidget( + parent=self._root_widget, + position=(225, 309) if ui_type is ui_small else (415, 517), + size=(0, 0), + text=f"version: {__version__}", + color=(0.6, 0.6, 0.6, 0.8), + maxwidth=290, + scale=0.454 if ui_type is ui_small else 0.653, + h_align='center', + v_align='center' + ) + + # settings txt + bui.textwidget( + parent=self._scroll_parent, + position=(10, height - 27) if ui_type is ui_small else (30, height - 47), + size=(0, 0), + text="Map Type:", + color=(1, 1, 1, 0.8), + maxwidth=290, + scale=0.7 if ui_type is ui_small else 1.3, + h_align='left', + v_align='center' + ) + + bui.textwidget( + parent=self._scroll_parent, + position=(10, height - 65) if ui_type is ui_small else (30, height - 104), + size=(0, 0), + text="Music:", + color=(1, 1, 1, 0.8), + maxwidth=290, + scale=0.7 if ui_type is ui_small else 1.3, + h_align='left', + v_align='center' + ) + + bui.textwidget( + parent=self._scroll_parent, + position=(25, height - 147) if ui_type is ui_small else (45, height - 239), + size=(0, 0), + text="tint", + color=(1, 1, 1, 0.8), + maxwidth=290, + scale=0.5 if ui_type is ui_small else 1.0, + h_align='left', + v_align='center' + ) + + bui.textwidget( + parent=self._scroll_parent, + position=(81, height - 147) if ui_type is ui_small else (140, height - 239), + size=(0, 0), + text="ambient", + color=(1, 1, 1, 0.8), + maxwidth=290, + scale=0.5 if ui_type is ui_small else 1.0, + h_align='left', + v_align='center' + ) + + bui.textwidget( + parent=self._scroll_parent, + position=(147, height - 156) if ui_type is ui_small else (262, height - 258), + size=(0, 0), + text="vignette\n outer", + color=(1, 1, 1, 0.8), + maxwidth=290, + scale=0.5 if ui_type is ui_small else 1.0, + h_align='left', + v_align='center' + ) + + bui.textwidget( + parent=self._scroll_parent, + position=(213, height - 156) if ui_type is ui_small else (382, height - 258), + size=(0, 0), + text="vignette\n inner", + color=(1, 1, 1, 0.8), + maxwidth=290, + scale=0.5 if ui_type is ui_small else 1.0, + h_align='left', + v_align='center' + ) + + bui.textwidget( + parent=self._scroll_parent, + position=(279, height - 156) if ui_type is ui_small else (500, height - 258), + size=(0, 0), + text="reflection\n color", + color=(1, 1, 1, 0.8), + maxwidth=290, + scale=0.5 if ui_type is ui_small else 1.0, + h_align='left', + v_align='center' + ) + + bui.textwidget( + parent=self._scroll_parent, + position=(10, height - 193) if ui_type is ui_small else (30, height - 320), + size=(0, 0), + text="Reflection Type:", + color=(1, 1, 1, 0.8), + maxwidth=290, + scale=0.7 if ui_type is ui_small else 1.3, + h_align='left', + v_align='center' + ) + + bui.textwidget( + parent=self._scroll_parent, + position=(10, height - 227) if ui_type is ui_small else (30, height - 373), + size=(0, 0), + text="Reflection Scale:", + color=(1, 1, 1, 0.8), + maxwidth=290, + scale=0.7 if ui_type is ui_small else 1.3, + h_align='left', + v_align='center' + ) + + bui.textwidget( + parent=self._scroll_parent, + position=(10, height - 260) if ui_type is ui_small else (30, height - 423), + size=(0, 0), + text="Camera Mode:", + color=(1, 1, 1, 0.8), + maxwidth=290, + scale=0.7 if ui_type is ui_small else 1.3, + h_align='left', + v_align='center' + ) + + bui.textwidget( + parent=self._scroll_parent, + position=(10, height - 294) if ui_type is ui_small else (30, height - 480), + size=(0, 0), + text="Show Logo Text:", + color=(1, 1, 1, 0.8), + maxwidth=290, + scale=0.7 if ui_type is ui_small else 1.3, + h_align='left', + v_align='center' + ) + + # prioritize this first for: + # >> handling config-errors + # >> debugging + self._menu_configreset_button = bui.buttonwidget( + parent=self._scroll_parent, + position=(5, height - 486) if ui_type is ui_small else (12, height - 765) , + size=(329, 50) if ui_type is ui_small else (600, 80), + color=(0.0, 0.67, 0.85), + textcolor=(0.8, 0.8, 0.8), + button_type="regular", + label="Reset to Default Settings", + text_scale=0.7 if ui_type is ui_small else 1.0, + on_activate_call=bs.Call(self.reset_config) + ) + + # settings buttons + self._menu_map_button = bui.buttonwidget( + parent=self._scroll_parent, + position=(112, height - 38) if ui_type is ui_small else (206, height - 67), + size=(87, 24) if ui_type is ui_small else (149, 40), + button_type="regular", + label=config["Menu Map"], + on_activate_call=bs.Call(self.choice_window, 'Map') + ) + + self._menu_music_button = bui.buttonwidget( + parent=self._scroll_parent, + position=(85, height - 75) if ui_type is ui_small else (149, height - 123), + size=(87, 24) if ui_type is ui_small else (149, 40), + button_type="regular", + label=config["Menu Music"], + text_scale=0.6 if ui_type is ui_small else 1.0, + on_activate_call=bs.Call(self.choice_window, 'Music') + ) + + self._menu_tint_button = bui.buttonwidget( + parent=self._scroll_parent, + color=config["Menu Tint"], + position=(15, height - 136) if ui_type is ui_small else (30, height - 220), + size=(40, 40) if ui_type is ui_small else (70, 70), + button_type="square", + label="", + on_activate_call=bs.WeakCall(self.color_picker_popup, "Menu Tint") + ) + + self._menu_ambient_button = bui.buttonwidget( + parent=self._scroll_parent, + color=config["Menu Ambient"], + position=(81, height - 136) if ui_type is ui_small else (150, height - 220), + size=(40, 40) if ui_type is ui_small else (70, 70), + button_type="square", + label="", + on_activate_call=bs.WeakCall(self.color_picker_popup, "Menu Ambient") + ) + + self._menu_vignetteO_button = bui.buttonwidget( + parent=self._scroll_parent, + color=config["Menu Vignette Outer"], + position=(147, height - 136) if ui_type is ui_small else (270, height - 220), + size=(40, 40) if ui_type is ui_small else (70, 70), + button_type="square", + label="", + on_activate_call=bs.WeakCall(self.color_picker_popup, "Menu Vignette Outer") + ) + + self._menu_vignetteI_button = bui.buttonwidget( + parent=self._scroll_parent, + color=config["Menu Vignette Inner"], + position=(213, height - 136) if ui_type is ui_small else (390, height - 220), + size=(40, 40) if ui_type is ui_small else (70, 70), + button_type="square", + label="", + on_activate_call=bs.WeakCall(self.color_picker_popup, "Menu Vignette Inner") + ) + + self._menu_rcolor_button = bui.buttonwidget( + parent=self._scroll_parent, + color=config["Menu Map Color"], + position=(279, height - 136) if ui_type is ui_small else (510, height - 220), + size=(40, 40) if ui_type is ui_small else (70, 70), + button_type="square", + label="", + on_activate_call=bs.WeakCall(self.color_picker_popup, "Menu Map Color") + ) + + self._menu_reflectiont_button = bui.buttonwidget( + parent=self._scroll_parent, + position=(148, height - 204) if ui_type is ui_small else (287, height - 339), + size=(87, 24) if ui_type is ui_small else (149, 40), + button_type="regular", + label=config["Menu Reflection Type"], + text_scale=0.6 if ui_type is ui_small else 1.0, + on_activate_call=bs.Call(self.choice_window, 'Reflection Type') + ) + + self._menu_reflections_button = bui.buttonwidget( + parent=self._scroll_parent, + position=(153, height - 237) if ui_type is ui_small else (289, height - 392), + size=(87, 24) if ui_type is ui_small else (149, 40), + button_type="regular", + label=str(config["Menu Reflection Scale"]), + text_scale=0.6 if ui_type is ui_small else 1.0, + on_activate_call=lambda: FreeEditWindow(delegate=self, whitelist=['num'], config_name='Menu Reflection Scale') + ) + + self._menu_cameramode_button = bui.buttonwidget( + parent=self._scroll_parent, + position=(138, height - 272) if ui_type is ui_small else (265, height - 444), + size=(87, 24) if ui_type is ui_small else (149, 40), + button_type="regular", + label=str(config["Menu Camera Mode"]), + text_scale=0.6 if ui_type is ui_small else 1.0, + on_activate_call=bs.Call(self.choice_window, 'Camera Mode') + ) + + self._menu_logotext_button = ConfigCheckBox( + parent=self._scroll_parent, + configkey="Menu Logo Text", + position=(151, height - 308) if ui_type is ui_small else (287, height - 520), + size=(40, 40) if ui_type is ui_small else (56, 56), + scale=0.62 if ui_type is ui_small else 1.4, + displayname="" + ) + + self._menu_load_button = bui.buttonwidget( + parent=self._scroll_parent, + position=(11, height - 365) if ui_type is ui_small else (22, height - 590), + size=(155, 45) if ui_type is ui_small else (280, 75), + textcolor=(0.8, 0.8, 0.8), + button_type="regular", + label="Load Theme", + text_scale=0.7 if ui_type is ui_small else 1.0, + on_activate_call=bs.Call(self.popup_fileselector) + ) + + self._menu_save_button = bui.buttonwidget( + parent=self._scroll_parent, + position=(178, height - 365) if ui_type is ui_small else (312, height - 590), + size=(155, 45) if ui_type is ui_small else (280, 75), + textcolor=(0.8, 0.8, 0.8), + button_type="regular", + label="Save Theme", + text_scale=0.7 if ui_type is ui_small else 1.0, + on_activate_call=lambda: FreeEditWindow(delegate=self, name_only=True) + ) + + self._menu_mapdata_button = bui.buttonwidget( + parent=self._scroll_parent, + position=(5, height - 425) if ui_type is ui_small else (12, height - 677), + size=(329, 50) if ui_type is ui_small else (600, 80), + color=(0.23, 0.27, 0.55), + textcolor=(0.8, 0.8, 0.8), + button_type="regular", + label="Map Data Overrides", + text_scale=0.7 if ui_type is ui_small else 1.0, + on_activate_call=bs.Call(self.checkbox_window) + ) + + + + def checkbox_window(self): + self._root_widget_checkbox = bui.containerwidget( + size=(800, 740), + transition='in_scale', + toolbar_visibility='menu_minimal', + scale_origin_stack_offset=(0, 0), + scale=0.6 if ui_type is ui_large else 0.88 if ui_type is ui_small else 0.76, + color=(0.17, 0.2, 0.25), + on_outside_click_call=bs.Call(self.checkbox_window_out), + claim_outside_clicks=True, + stack_offset=(0, -35) if ui_type is ui_small else (0, 0) + ) + self._button_tint = ConfigCheckBox( + parent=self._root_widget_checkbox, + configkey="tint", + position=(88, 600), + size=(380, 40), + scale=1.9, + displayname='Tint' + ) + self._button_ambient = ConfigCheckBox( + parent=self._root_widget_checkbox, + configkey="ambient_color", + position=(88, 510), + size=(380, 40), + scale=1.9, + displayname='Ambient Color' + ) + self._button_vignette_outer = ConfigCheckBox( + parent=self._root_widget_checkbox, + configkey="vignette_outer", + position=(88, 420), + size=(380, 40), + scale=1.9, + displayname='Vignette Outer' + ) + self._button_vignette_inner = ConfigCheckBox( + parent=self._root_widget_checkbox, + configkey="vignette_inner", + position=(88, 330), + size=(380, 40), + scale=1.9, + displayname='Vignette Inner' + ) + self._button_map_color = ConfigCheckBox( + parent=self._root_widget_checkbox, + configkey="map_color", + position=(88, 240), + size=(380, 40), + scale=1.9, + displayname='Map Color' + ) + self._button_map_reflection_scale = ConfigCheckBox( + parent=self._root_widget_checkbox, + configkey="map_reflection_scale", + position=(88, 150), + size=(380, 40), + scale=1.9, + displayname='Map Reflection Scale' + ) + self._button_map_reflection_type = ConfigCheckBox( + parent=self._root_widget_checkbox, + configkey="map_reflection_type", + position=(88, 60), + size=(380, 40), + scale=1.9, + displayname='Map Reflection Type' + ) + + def checkbox_window_out(self): + # Memory-leak prevention + bui.containerwidget(edit=self._root_widget_checkbox, transition='out_scale') + del self._button_tint + del self._button_ambient + del self._button_vignette_outer + del self._button_vignette_inner + del self._button_map_color + del self._button_map_reflection_scale + del self._button_map_reflection_type + + def choice_window(self, category: str): + choices_map = { + 'Map': [ + 'Big G', + 'Bridgit', + 'Courtyard', + 'Crag Castle', + 'Doom Shroom', + 'Football Stadium', + 'Happy Thoughts', + 'Hockey Stadium', + 'Lake Frigid', + 'Monkey Face', + 'Rampage', + 'Roundabout', + 'Step Right Up', + 'The Pad', + 'The Pad (with trees)', + 'Tower D', + 'Tip Top', + 'Zig Zag' + ], + 'Camera Mode': [ + 'rotate', + 'static' + ], + 'Reflection Type': [ + 'Soft', + 'None', + 'Powerup', + 'Character' + ], + 'Music': [ + 'Menu', + 'Epic', + 'Flag Catcher', + 'Flying', + 'Grand Romp', + 'Lobby', + 'Lobby Epic', + 'Marching Forward', + 'Marching Home', + 'Run Away', + 'Scary', + 'Sports', + 'Survival', + 'To The Death', + 'None' + ] + } + + if category in choices_map: + PopupMenuWindow( + position=(0, 0), + scale=2.0 if ui_type is ui_small else 1.0, + delegate=self, + current_choice=bs.app.config[f"Menu {category}"], + choices=choices_map[category] + ) + self._choice_page = category + + def popup_menu_selected_choice(self, window: PopupMenuWindow, choice: str): + if self._choice_page == 'Map': + bs.app.config['Menu Map'] = choice + if config["tint"]: + bs.app.config["Menu Tint"] = GLOBALS_MAPDATA.get(config["Menu Map"]).get("Tint") + if config["ambient_color"]: + bs.app.config["Menu Ambient"] = GLOBALS_MAPDATA.get(config["Menu Map"]).get("Ambient") + if config["vignette_outer"]: + bs.app.config["Menu Vignette Outer"] = GLOBALS_MAPDATA.get(config["Menu Map"]).get("Vignette Outer") + if config["vignette_inner"]: + bs.app.config["Menu Vignette Inner"] = GLOBALS_MAPDATA.get(config["Menu Map"]).get("Vignette Inner") + if config["map_color"]: + bs.app.config["Menu Map Color"] = GLOBALS_MAPDATA.get(config["Menu Map"]).get("Map Color") + if config["map_reflection_scale"]: + bs.app.config["Menu Reflection Scale"] = GLOBALS_MAPDATA.get(config["Menu Map"]).get("Map Reflection Scale") + if config["map_reflection_type"]: + bs.app.config["Menu Reflection Type"] = 'Soft' + + elif self._choice_page == 'Music': + bs.app.config['Menu Music'] = choice + + elif self._choice_page == 'Reflection Type': + bs.app.config['Menu Reflection Type'] = choice + + elif self._choice_page == 'Camera Mode': + bs.app.config['Menu Camera Mode'] = choice + bs.app.config.apply_and_commit() + self.update_buttons() + + def popup_menu_closing(self, window: PopupMenuWindow): + self._choice_page = None + self.update_buttons() + + def popup_fileselector(self): + self._file_selector = FileSelectorWindow( + path=str(_ba.env()['python_directory_user']), + callback=self._import, + show_base_path=True, + valid_file_extensions=['json'], + allow_folders=False + ) + + def _import(self, path: str = None): + try: + self.path = path + '/' + self.path = self.path[:-1] + with open(self.path, 'r') as imported: + selected = json.load(imported) + handle_config([ + selected["Menu Map"], + selected["Menu Tint"], + selected["Menu Ambient"], + selected["Menu Vignette Outer"], + selected["Menu Vignette Inner"], + selected["Menu Music"], + selected["Menu Map Color"], + selected["Menu Reflection Scale"], + selected["Menu Reflection Type"], + selected["Menu Camera Mode"], + selected["Menu Logo Text"], + selected["vignette_outer"], + selected["vignette_inner"], + selected["ambient_color"], + selected["tint"], + selected["map_reflection_scale"], + selected["map_reflection_type"], + selected["map_color"]], + False + ) + self.update_buttons() + bui.screenmessage(f"Loaded {os.path.splitext(os.path.basename(self.path))[0]}!", color=(0.2, 0.4, 1.0)) + except: pass + del self._file_selector + + def _export(self, window: FreeEditWindow, txt: Any): + path = _ba.env()['python_directory_user'] + "/_menutheme/" + try: + a = _ba.env()['python_directory_user'] + "/_menutheme" + os.makedirs(a, exist_ok = False) + except: pass + + with open(path + txt + '.json', 'w') as file: + my_config = { + "Menu Map": config["Menu Map"], + "Menu Tint": config["Menu Tint"], + "Menu Ambient": config["Menu Ambient"], + "Menu Vignette Outer": config["Menu Vignette Outer"], + "Menu Vignette Inner": config["Menu Vignette Inner"], + "Menu Music": config["Menu Music"], + "Menu Map Color": config["Menu Map Color"], + "Menu Reflection Scale": config["Menu Reflection Scale"], + "Menu Reflection Type": config["Menu Reflection Type"], + "Menu Camera Mode": config["Menu Camera Mode"], + "Menu Logo Text": config["Menu Logo Text"], + "vignette_outer": config["vignette_outer"], + "vignette_inner": config["vignette_inner"], + "ambient_color": config["ambient_color"], + "tint": config["tint"], + "map_color": config["map_color"], + "map_reflection_scale": config["map_reflection_scale"], + "map_reflection_type": config["map_reflection_type"] + } + json.dump(my_config, file, indent=4) + bui.screenmessage(f"Saved {os.path.splitext(os.path.basename(path+txt+'.json'))[0]}!", color=(0.2, 0.4, 1.0)) + bui.getsound('gunCocking').play() + + def color_picker_popup(self, tag: str): + bs.app.classic.accounts.have_pro = lambda: True + CustomColorPicker(parent=self._root_widget, + position=(0,0), + initial_color=config[tag], + delegate=self, + tag=tag) + + def color_picker_selected_color(self, picker: CustomColorPicker, color: Sequence[float, float, float]): + if not self._root_widget: + return + self.update_color(tag=picker.get_tag(), color=color) + self.update_buttons() + + def color_picker_closing(self, picker: ColorPicker): + bs.app.classic.accounts.have_pro = original_unlocked_pro + + def free_edit_enter(self, window: FreeEditWindow, c: Any, txt: Any): + bs.app.config[c] = float(txt) + bs.app.config.apply_and_commit() + self.update_buttons() + + def update_buttons(self): + # menu labels + bui.buttonwidget(edit=self._menu_map_button, label=config['Menu Map']) + bui.buttonwidget(edit=self._menu_music_button, label=config['Menu Music']) + bui.buttonwidget(edit=self._menu_reflectiont_button, label=config['Menu Reflection Type']) + + # menu colors + bui.buttonwidget(edit=self._menu_tint_button, color=config['Menu Tint']) + bui.buttonwidget(edit=self._menu_ambient_button, color=config['Menu Ambient']) + bui.buttonwidget(edit=self._menu_vignetteO_button, color=config['Menu Vignette Outer']) + bui.buttonwidget(edit=self._menu_vignetteI_button, color=config['Menu Vignette Inner']) + bui.buttonwidget(edit=self._menu_rcolor_button, color=config['Menu Map Color']) + + # menu values + bui.buttonwidget(edit=self._menu_reflections_button, label=str(config['Menu Reflection Scale'])) + bui.buttonwidget(edit=self._menu_cameramode_button, label=str(config['Menu Camera Mode'])) + bui.checkboxwidget(edit=self._menu_logotext_button.widget, value=config['Menu Logo Text']) + + def update_color(self, tag: str, color: tuple[float, float, float]): + bs.app.config[tag] = color + bs.app.config.apply_and_commit() + + def reset_config(self): + handle_config([ + "The Pad (with trees)", + (1.14, 1.1, 1.0), (1.06, 1.04, 1.03), + (0.45, 0.55, 0.54), (0.99, 0.98, 0.98), "Menu", + (1.0, 1.0, 1.0), 0.3, 'None', 'rotate', + True, True, True, True, True, True, True, True, True + ],False + ) + self.update_buttons() + bui.screenmessage('Reset Settings', color=(0, 1, 0)) + + def close(self): + self._accounts_window = None + bui.containerwidget(edit=self._root_widget, transition='out_scale') + + def close_all(self): + accounts_window = self._accounts_window + bui.containerwidget(edit=self._root_widget, transition='out_scale') + accounts_window._back(False) + + +class MainMenuTheme(MainMenuActivity): + + def _start_preloads(self): + if self.expired: + return + with self.context: + _preload1() + + bui.apptimer(0.5, self._start_menu_music) + + def _start_menu_music(self): + music = GLOBALS_MUSIC.get(config['Menu Music']) + if music is not None: + bs.setmusic(music) + + def _make_word(self, *args, **kwargs) -> None: + if not config['Menu Logo Text']: return + super()._make_word(*args, **kwargs) + + def _make_logo(self, *args, **kwargs) -> None: + if not config['Menu Logo Text']: return + super()._make_logo(*args, **kwargs) + + def on_transition_in(self): + bs.Activity.on_transition_in(self) + random.seed(123) + app = bs.app + assert app.classic is not None + + plus = bui.app.plus + assert plus is not None + + vr_mode = bs.app.vr_mode + + if not bs.app.toolbar_test: + color = (1.0, 1.0, 1.0, 1.0) if vr_mode else (0.5, 0.6, 0.5, 0.6) + + scale = ( + 0.9 + if (app.ui_v1.uiscale is bs.UIScale.SMALL or vr_mode) + else 0.7 + ) + self.my_name = bs.NodeActor( + bs.newnode( + 'text', + attrs={ + 'v_attach': 'bottom', + 'h_align': 'center', + 'color': color, + 'flatness': 1.0, + 'shadow': 1.0 if vr_mode else 0.5, + 'scale': scale, + 'position': (0, 10), + 'vr_depth': -10, + 'text': '\xa9 2011-2023 Eric Froemling', + }, + ) + ) + + tval = bs.Lstr( + resource='hostIsNavigatingMenusText', + subs=[('${HOST}', plus.get_v1_account_display_string())], + ) + self._host_is_navigating_text = bs.NodeActor( + bs.newnode( + 'text', + attrs={ + 'text': tval, + 'client_only': True, + 'position': (0, -200), + 'flatness': 1.0, + 'h_align': 'center', + }, + ) + ) + if not app.classic.main_menu_did_initial_transition and hasattr( + self, 'my_name' + ): + assert self.my_name is not None + assert self.my_name.node + bs.animate(self.my_name.node, 'opacity', {2.3: 0, 3.0: 1.0}) + + vr_mode = app.vr_mode + uiscale = app.ui_v1.uiscale + + force_show_build_number = False + + if not bs.app.toolbar_test: + if app.debug_build or app.test_build or force_show_build_number: + if app.debug_build: + text = bs.Lstr( + value='${V} (${B}) (${D})', + subs=[ + ('${V}', app.version), + ('${B}', str(app.build_number)), + ('${D}', bs.Lstr(resource='debugText')), + ], + ) + else: + text = bs.Lstr( + value='${V} (${B})', + subs=[ + ('${V}', app.version), + ('${B}', str(app.build_number)), + ], + ) + else: + text = bs.Lstr(value='${V}', subs=[('${V}', app.version)]) + scale = 0.9 if (uiscale is bs.UIScale.SMALL or vr_mode) else 0.7 + color = (1, 1, 1, 1) if vr_mode else (0.5, 0.6, 0.5, 0.7) + self.version = bs.NodeActor( + bs.newnode( + 'text', + attrs={ + 'v_attach': 'bottom', + 'h_attach': 'right', + 'h_align': 'right', + 'flatness': 1.0, + 'vr_depth': -10, + 'shadow': 1.0 if vr_mode else 0.5, + 'color': color, + 'scale': scale, + 'position': (-260, 10) if vr_mode else (-10, 10), + 'text': text, + }, + ) + ) + if not app.classic.main_menu_did_initial_transition: + assert self.version.node + bs.animate(self.version.node, 'opacity', {2.3: 0, 3.0: 1.0}) + + self.beta_info = self.beta_info_2 = None + if app.test_build and not (app.demo_mode or app.arcade_mode) and config['Menu Logo Text']: + pos = (230, 35) + self.beta_info = bs.NodeActor( + bs.newnode( + 'text', + attrs={ + 'v_attach': 'center', + 'h_align': 'center', + 'color': (1, 1, 1, 1), + 'shadow': 0.5, + 'flatness': 0.5, + 'scale': 1, + 'vr_depth': -60, + 'position': pos, + 'text': bs.Lstr(resource='testBuildText'), + }, + ) + ) + if not app.classic.main_menu_did_initial_transition: + assert self.beta_info.node + bs.animate(self.beta_info.node, 'opacity', {1.3: 0, 1.8: 1.0}) + + b = GLOBALS_MAPDATA.get(config["Menu Map"]).get("Camera Bounds") + b = ( + b[0] - b[3] / 2.0, + b[1] - b[4] / 2.0, + b[2] - b[5] / 2.0, + b[0] + b[3] / 2.0, + b[1] + b[4] / 2.0, + b[2] + b[5] / 2.0 + ) + + gnode = self.globalsnode + gnode.camera_mode = 'follow' if config["Menu Camera Mode"] == 'static' else 'rotate' + + self.load_map_stuff() + gnode.tint = config["Menu Tint"] + gnode.ambient_color = config["Menu Ambient"] + gnode.vignette_outer = config["Menu Vignette Outer"] + gnode.vignette_inner = config["Menu Vignette Inner"] + gnode.area_of_interest_bounds = b + + self.main.node.color = config["Menu Map Color"] + self.main.node.reflection = GLOBALS_REFLECTION[config["Menu Reflection Type"]] + self.main.node.reflection_scale = [float(config["Menu Reflection Scale"])] + + self._update_timer = bs.Timer(1.0, self._update, repeat=True) + self._update() + + bui.add_clean_frame_callback(bs.WeakCall(self._start_preloads)) + + random.seed() + + if not (app.demo_mode or app.arcade_mode) and not app.toolbar_test: + self._news = NewsDisplay(self) + + with bs.ContextRef.empty(): + from bauiv1lib import specialoffer + + assert bs.app.classic is not None + if bool(False): + uicontroller = bs.app.ui_v1.controller + assert uicontroller is not None + uicontroller.show_main_menu() + else: + main_menu_location = bs.app.ui_v1.get_main_menu_location() + + # When coming back from a kiosk-mode game, jump to + # the kiosk start screen. + if bs.app.demo_mode or bs.app.arcade_mode: + # pylint: disable=cyclic-import + from bauiv1lib.kiosk import KioskWindow + + bs.app.ui_v1.set_main_menu_window( + KioskWindow().get_root_widget() + ) + # ..or in normal cases go back to the main menu + else: + if main_menu_location == 'Gather': + # pylint: disable=cyclic-import + from bauiv1lib.gather import GatherWindow + + bs.app.ui_v1.set_main_menu_window( + GatherWindow(transition=None).get_root_widget() + ) + elif main_menu_location == 'Watch': + # pylint: disable=cyclic-import + from bauiv1lib.watch import WatchWindow + + bs.app.ui_v1.set_main_menu_window( + WatchWindow(transition=None).get_root_widget() + ) + elif main_menu_location == 'Team Game Select': + # pylint: disable=cyclic-import + from bauiv1lib.playlist.browser import ( + PlaylistBrowserWindow, + ) + + bs.app.ui_v1.set_main_menu_window( + PlaylistBrowserWindow( + sessiontype=bs.DualTeamSession, transition=None + ).get_root_widget() + ) + elif main_menu_location == 'Free-for-All Game Select': + # pylint: disable=cyclic-import + from bauiv1lib.playlist.browser import ( + PlaylistBrowserWindow, + ) + + bs.app.ui_v1.set_main_menu_window( + PlaylistBrowserWindow( + sessiontype=bs.FreeForAllSession, + transition=None, + ).get_root_widget() + ) + elif main_menu_location == 'Coop Select': + # pylint: disable=cyclic-import + from bauiv1lib.coop.browser import CoopBrowserWindow + + bs.app.ui_v1.set_main_menu_window( + CoopBrowserWindow(transition=None).get_root_widget() + ) + elif main_menu_location == 'Benchmarks & Stress Tests': + # pylint: disable=cyclic-import + from bauiv1lib.debug import DebugWindow + + bs.app.ui_v1.set_main_menu_window( + DebugWindow(transition=None).get_root_widget() + ) + else: + # pylint: disable=cyclic-import + from bauiv1lib.mainmenu import MainMenuWindow + + bs.app.ui_v1.set_main_menu_window( + MainMenuWindow(transition=None).get_root_widget() + ) + + if not specialoffer.show_offer(): + + def try_again(): + if not specialoffer.show_offer(): + bui.apptimer(2.0, specialoffer.show_offer) + + bui.apptimer(2.0, try_again) + app.classic.main_menu_did_initial_transition = True + + def load_map_stuff(self): + m = bs.getmesh + t = bs.gettexture + map_type = config["Menu Map"] + if map_type == "The Pad (with trees)": + self.main = bs.NodeActor(bs.newnode( + 'terrain', + delegate=self, + attrs={ + 'mesh': m('thePadLevel'), + 'color_texture': t('thePadLevelColor'), + 'reflection': 'soft', + 'reflection_scale': [0.3] + })) + self.trees = bs.NodeActor(bs.newnode( + 'terrain', + attrs={ + 'mesh': m('trees'), + 'lighting': False, + 'reflection': 'char', + 'reflection_scale': [0.1], + 'color_texture': t('treesColor') + })) + self.bgterrain = bs.NodeActor(bs.newnode( + 'terrain', + attrs={ + 'mesh': m('thePadBG'), + 'color': (0.92, 0.91, 0.9), + 'lighting': False, + 'background': True, + 'color_texture': t('menuBG'), + })) + self.bottom = bs.NodeActor(bs.newnode( + 'terrain', + attrs={ + 'mesh': m('thePadLevelBottom'), + 'lighting': False, + 'reflection': 'soft', + 'reflection_scale': [0.45], + 'color_texture': t('thePadLevelColor') + })) + elif map_type == "The Pad": + self.main = bs.NodeActor(bs.newnode( + 'terrain', + delegate=self, + attrs={ + 'mesh': m('thePadLevel'), + 'color_texture': t('thePadLevelColor'), + 'reflection': 'soft', + 'reflection_scale': [0.3] + })) + self.bgterrain = bs.NodeActor(bs.newnode( + 'terrain', + attrs={ + 'mesh': m('thePadBG'), + 'color': (0.92, 0.91, 0.9), + 'lighting': False, + 'background': True, + 'color_texture': t("menuBG") + })) + self.bottom = bs.NodeActor(bs.newnode( + 'terrain', + attrs={ + 'mesh': m('thePadLevelBottom'), + 'lighting': False, + 'reflection': 'soft', + 'reflection_scale': [0.45], + 'color_texture': t('thePadLevelColor') + })) + elif map_type == "Hockey Stadium": + self.main = bs.NodeActor(bs.newnode( + 'terrain', + delegate=self, + attrs={ + 'mesh': m('hockeyStadiumOuter'), + 'color_texture': t('hockeyStadium'), + 'reflection': 'soft', + 'reflection_scale': [0.3] + })) + self.inner = bs.NodeActor(bs.newnode( + 'terrain', + attrs={ + 'mesh': m('hockeyStadiumInner'), + 'opacity': 0.92, + 'opacity_in_low_or_ui_medium_quality': 1.0, + 'color_texture': t('hockeyStadium') + })) + self.stands = bs.NodeActor(bs.newnode( + 'terrain', + attrs={ + 'mesh': m('hockeyStadiumStands'), + 'visible_in_reflections': False, + 'color_texture': t('footballStadium') + })) + elif map_type == "Football Stadium": + self.main = bs.NodeActor(bs.newnode( + 'terrain', + delegate=self, + attrs={ + 'mesh': m('footballStadium'), + 'color_texture': t('footballStadium'), + })) + elif map_type == "Bridgit": + self.main = bs.NodeActor(bs.newnode( + 'terrain', + delegate=self, + attrs={ + 'mesh': m('bridgitLevelTop'), + 'color_texture': t('bridgitLevelColor'), + })) + self.bottom = bs.NodeActor(bs.newnode( + 'terrain', + attrs={ + 'mesh': m('bridgitLevelBottom'), + 'lighting': False, + 'color_texture': t('bridgitLevelColor'), + })) + self.background = bs.NodeActor(bs.newnode( + 'terrain', + attrs={ + 'mesh': m('natureBackground'), + 'lighting': False, + 'background': True, + 'color_texture': t('natureBackgroundColor'), + })) + elif map_type == "Big G": + self.main = bs.NodeActor(bs.newnode( + 'terrain', + delegate=self, + attrs={ + 'mesh': m('bigG'), + 'color': (0.7, 0.7, 0.7), + 'color_texture': t('bigG'), + })) + self.bottom = bs.NodeActor(bs.newnode( + 'terrain', + attrs={ + 'mesh': m('bigGBottom'), + 'lighting': False, + 'color': (0.7, 0.7, 0.7), + 'color_texture': t('bigG'), + })) + self.background = bs.NodeActor(bs.newnode( + 'terrain', + attrs={ + 'mesh': m('natureBackground'), + 'lighting': False, + 'background': True, + 'color_texture': t('natureBackgroundColor'), + })) + elif map_type == "Roundabout": + self.main = bs.NodeActor(bs.newnode( + 'terrain', + delegate=self, + attrs={ + 'mesh': m('roundaboutLevel'), + 'color': (0.7, 0.7, 0.7), + 'color_texture': t('roundaboutLevelColor'), + })) + self.bottom = bs.NodeActor(bs.newnode( + 'terrain', + attrs={ + 'mesh': m('roundaboutLevelBottom'), + 'lighting': False, + 'color': (0.7, 0.7, 0.7), + 'color_texture': t('roundaboutLevelColor'), + })) + self.background = bs.NodeActor(bs.newnode( + 'terrain', + attrs={ + 'mesh': m('natureBackground'), + 'lighting': False, + 'background': True, + 'color_texture': t('natureBackgroundColor'), + })) + elif map_type == "Monkey Face": + self.main = bs.NodeActor(bs.newnode( + 'terrain', + delegate=self, + attrs={ + 'mesh': m('monkeyFaceLevel'), + 'color_texture': t('monkeyFaceLevelColor'), + })) + self.bottom = bs.NodeActor(bs.newnode( + 'terrain', + attrs={ + 'mesh': m('monkeyFaceLevelBottom'), + 'lighting': False, + 'color_texture': t('monkeyFaceLevelColor'), + })) + self.background = bs.NodeActor(bs.newnode( + 'terrain', + attrs={ + 'mesh': m('natureBackground'), + 'lighting': False, + 'color_texture': t('natureBackgroundColor'), + })) + elif map_type == "Monkey Face": + self.main = bs.NodeActor(bs.newnode( + 'terrain', + delegate=self, + attrs={ + 'mesh': m('monkeyFaceLevel'), + 'color_texture': t('monkeyFaceLevelColor'), + })) + self.bottom = bs.NodeActor(bs.newnode( + 'terrain', + attrs={ + 'mesh': m('monkeyFaceLevelBottom'), + 'lighting': False, + 'color_texture': t('monkeyFaceLevelColor'), + })) + self.background = bs.NodeActor(bs.newnode( + 'terrain', + attrs={ + 'mesh': m('natureBackground'), + 'lighting': False, + 'color_texture': t('natureBackgroundColor'), + })) + elif map_type == "Zig Zag": + self.main = bs.NodeActor(bs.newnode( + 'terrain', + delegate=self, + attrs={ + 'mesh': m('zigZagLevel'), + 'color_texture': t('zigZagLevelColor'), + })) + self.bottom = bs.NodeActor(bs.newnode( + 'terrain', + attrs={ + 'mesh': m('zigZagLevelBottom'), + 'lighting': False, + 'color_texture': t('zigZagLevelColor'), + })) + self.background = bs.NodeActor(bs.newnode( + 'terrain', + attrs={ + 'mesh': m('natureBackground'), + 'lighting': False, + 'color_texture': t('natureBackgroundColor'), + })) + elif map_type == "Doom Shroom": + self.main = bs.NodeActor(bs.newnode( + 'terrain', + delegate=self, + attrs={ + 'mesh': m('doomShroomLevel'), + 'color_texture': t('doomShroomLevelColor'), + })) + self.stem = bs.NodeActor(bs.newnode( + 'terrain', + attrs={ + 'mesh': m('doomShroomStem'), + 'lighting': False, + 'color_texture': t('doomShroomLevelColor'), + })) + self.background = bs.NodeActor(bs.newnode( + 'terrain', + attrs={ + 'mesh': m('doomShroomBG'), + 'lighting': False, + 'background': True, + 'color_texture': t('doomShroomBGColor'), + })) + elif map_type == "Lake Frigid": + self.main = bs.NodeActor(bs.newnode( + 'terrain', + delegate=self, + attrs={ + 'mesh': m('lakeFrigid'), + 'color_texture': t('lakeFrigid'), + })) + self.top = bs.NodeActor(bs.newnode( + 'terrain', + attrs={ + 'mesh': m('lakeFrigidTop'), + 'lighting': False, + 'color_texture': t('lakeFrigid'), + })) + self.reflections = bs.NodeActor(bs.newnode( + 'terrain', + attrs={ + 'mesh': m('lakeFrigidReflections'), + 'lighting': False, + 'overlay': True, + 'opacity': 0.15, + 'color_texture': t('lakeFrigidReflections'), + })) + elif map_type == "Tip Top": + self.main = bs.NodeActor(bs.newnode( + 'terrain', + delegate=self, + attrs={ + 'mesh': m('tipTopLevel'), + 'color': (0.7, 0.7, 0.7), + 'color_texture': t('tipTopLevelColor'), + })) + self.bottom = bs.NodeActor(bs.newnode( + 'terrain', + attrs={ + 'mesh': m('tipTopLevelBottom'), + 'lighting': False, + 'color': (0.7, 0.7, 0.7), + 'color_texture': t('tipTopLevelColor'), + })) + self.background = bs.NodeActor(bs.newnode( + 'terrain', + attrs={ + 'mesh': m('tipTopBG'), + 'lighting': False, + 'color': (0.4, 0.4, 0.4), + 'background': True, + 'color_texture': t('tipTopBGColor'), + })) + elif map_type == "Crag Castle": + self.main = bs.NodeActor(bs.newnode( + 'terrain', + delegate=self, + attrs={ + 'mesh': m('cragCastleLevel'), + 'color_texture': t('cragCastleLevelColor'), + })) + self.bottom = bs.NodeActor(bs.newnode( + 'terrain', + attrs={ + 'mesh': m('cragCastleLevelBottom'), + 'lighting': False, + 'color_texture': t('cragCastleLevelColor'), + })) + self.background = bs.NodeActor(bs.newnode( + 'terrain', + attrs={ + 'mesh': m('thePadBG'), + 'lighting': False, + 'background': True, + 'color_texture': t('menuBG'), + })) + elif map_type == "Tower D": + self.main = bs.NodeActor(bs.newnode( + 'terrain', + delegate=self, + attrs={ + 'mesh': m('towerDLevel'), + 'color_texture': t('towerDLevelColor'), + })) + self.bottom = bs.NodeActor(bs.newnode( + 'terrain', + attrs={ + 'mesh': m('towerDLevelBottom'), + 'lighting': False, + 'color_texture': t('towerDLevelColor'), + })) + self.background = bs.NodeActor(bs.newnode( + 'terrain', + attrs={ + 'mesh': m('thePadBG'), + 'lighting': False, + 'background': True, + 'color_texture': t('menuBG'), + })) + elif map_type == "Happy Thoughts": + self.main = bs.NodeActor(bs.newnode( + 'terrain', + delegate=self, + attrs={ + 'mesh': m('alwaysLandLevel'), + 'color_texture': t('alwaysLandLevelColor'), + })) + self.bottom = bs.NodeActor(bs.newnode( + 'terrain', + attrs={ + 'mesh': m('alwaysLandLevelBottom'), + 'lighting': False, + 'color_texture': t('alwaysLandLevelColor'), + })) + self.background = bs.NodeActor(bs.newnode( + 'terrain', + attrs={ + 'mesh': m('alwaysLandBG'), + 'lighting': False, + 'background': True, + 'color_texture': t('alwaysLandBGColor'), + })) + elif map_type == "Step Right Up": + self.main = bs.NodeActor(bs.newnode( + 'terrain', + delegate=self, + attrs={ + 'mesh': m('stepRightUpLevel'), + 'color_texture': t('stepRightUpLevelColor'), + })) + self.bottom = bs.NodeActor(bs.newnode( + 'terrain', + attrs={ + 'mesh': m('stepRightUpLevelBottom'), + 'lighting': False, + 'color_texture': t('stepRightUpLevelColor'), + })) + self.background = bs.NodeActor(bs.newnode( + 'terrain', + attrs={ + 'mesh': m('thePadBG'), + 'lighting': False, + 'background': True, + 'color_texture': t('menuBG'), + })) + elif map_type == "Courtyard": + self.main = bs.NodeActor(bs.newnode( + 'terrain', + delegate=self, + attrs={ + 'mesh': m('courtyardLevel'), + 'color_texture': t('courtyardLevelColor'), + })) + self.bottom = bs.NodeActor(bs.newnode( + 'terrain', + attrs={ + 'mesh': m('courtyardLevelBottom'), + 'lighting': False, + 'color_texture': t('courtyardLevelColor'), + })) + self.background = bs.NodeActor(bs.newnode( + 'terrain', + attrs={ + 'mesh': m('thePadBG'), + 'lighting': False, + 'background': True, + 'color_texture': t('menuBG'), + })) + elif map_type == "Rampage": + self.main = bs.NodeActor(bs.newnode( + 'terrain', + delegate=self, + attrs={ + 'mesh': m('rampageLevel'), + 'color_texture': t('rampageLevelColor'), + })) + self.bottom = bs.NodeActor(bs.newnode( + 'terrain', + attrs={ + 'mesh': m('rampageLevelBottom'), + 'lighting': False, + 'color_texture': t('rampageLevelColor'), + })) + self.background = bs.NodeActor(bs.newnode( + 'terrain', + attrs={ + 'mesh': m('rampageBG'), + 'lighting': False, + 'background': True, + 'color_texture': t('rampageBGColor'), + })) + self.background_2 = bs.NodeActor(bs.newnode( + 'terrain', + attrs={ + 'mesh': m('rampageBG2'), + 'lighting': False, + 'background': True, + 'color_texture': t('rampageBGColor2'), + })) + + +def menu_theme(self): + this_class = self + MenuThemeWindow(accounts_window = this_class) + +def handle_config(keys: List[str], adding: bool = False): + our_config = { + "Menu Map": keys[0], + "Menu Tint": keys[1], + "Menu Ambient": keys[2], + "Menu Vignette Outer": keys[3], + "Menu Vignette Inner": keys[4], + "Menu Music": keys[5], + "Menu Map Color": keys[6], + "Menu Reflection Scale": keys[7], + "Menu Reflection Type": keys[8], + "Menu Camera Mode": keys[9], + "Menu Logo Text": keys[10], + "vignette_outer": keys[11], + "vignette_inner": keys[12], + "ambient_color": keys[13], + "tint": keys[14], + "map_color": keys[15], + "map_reflection_scale": keys[16], + "map_reflection_type": keys[17] + } + config_keys = list(our_config.keys()) + p = 0 + + for cf in config_keys: + if cf not in bs.app.config and adding: + config[cf] = keys[p] + elif our_config[cf] is not None and not adding: + config[cf] = keys[p] + p += 1 + bs.app.config.apply_and_commit() + + +def new_init(self, *args, **kwargs): + original_account_init(self, *args, **kwargs) + + self._menu_theme = bui.buttonwidget( + parent=self._root_widget, + position=((470, 330) if ui_type is ui_small else + (420, 434) if ui_type is ui_large else (445, 374)), + scale=(1.2 if ui_type is ui_small else + 1.3 if ui_type is ui_large else 1.0), + size=(160, 30) if ui_type is ui_small else (167, 30), + color=(0.55, 0.7, 0.63), + text_scale=(0.7 if ui_type is ui_medium else + 0.65 if ui_type is ui_large else 0.5), + autoselect=False, + button_type="regular", + label="Menu Theme", + on_activate_call=self.menu_theme + ) + self.previous_config = { + "Menu Map": config["Menu Map"], + "Menu Tint": config["Menu Tint"], + "Menu Ambient": config["Menu Ambient"], + "Menu Vignette Outer": config["Menu Vignette Outer"], + "Menu Vignette Inner": config["Menu Vignette Inner"], + "Menu Music": config["Menu Music"], + "Menu Map Color": config["Menu Map Color"], + "Menu Reflection Scale": config["Menu Reflection Scale"], + "Menu Reflection Type": config["Menu Reflection Type"], + "Menu Camera Mode": config["Menu Camera Mode"], + "Menu Logo Text": config["Menu Logo Text"] + } + + +def new_back(self, save_state: bool = True): + assert bui.app.classic is not None + if save_state: + self._save_state() + + bui.containerwidget(edit=self._root_widget, transition=self._transition_out) + + main_menu_window = MainMenuWindow(transition='in_left').get_root_widget() + bui.app.ui_v1.set_main_menu_window(main_menu_window) + + current_config = { + "Menu Map": config["Menu Map"], + "Menu Tint": config["Menu Tint"], + "Menu Ambient": config["Menu Ambient"], + "Menu Vignette Outer": config["Menu Vignette Outer"], + "Menu Vignette Inner": config["Menu Vignette Inner"], + "Menu Music": config["Menu Music"], + "Menu Map Color": config["Menu Map Color"], + "Menu Reflection Scale": config["Menu Reflection Scale"], + "Menu Reflection Type": config["Menu Reflection Type"], + "Menu Camera Mode": config["Menu Camera Mode"], + "Menu Logo Text": config["Menu Logo Text"] + } + + for x in self.previous_config: + if current_config[x] != self.previous_config[x]: + bs.pushcall(lambda: bs.new_host_session(menu.MainMenuSession)) + break + + +# ba_meta export plugin +class Plugin(ba.Plugin): + def on_app_running(self): + AccountSettingsWindow.__init__ = new_init + AccountSettingsWindow._back = new_back + AccountSettingsWindow.menu_theme = menu_theme + + menu.MainMenuActivity = MainMenuTheme + + handle_config([ + "The Pad (with trees)", + (1.14, 1.1, 1.0), (1.06, 1.04, 1.03), + (0.45, 0.55, 0.54), (0.99, 0.98, 0.98), "Menu", + (1.0, 1.0, 1.0), 0.3, 'None', 'rotate', + True, True, True, True, True, True, True, True, True + ],True + ) + \ No newline at end of file From 0df2c5e0dc2e675716e6116df23790959a903294 Mon Sep 17 00:00:00 2001 From: Juleskie <141720829+heLlow-step-sis@users.noreply.github.com> Date: Sat, 26 Aug 2023 09:51:20 +0800 Subject: [PATCH 0706/1464] 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 ea3bf6fd..511c8d6c 100644 --- a/plugins/utilities.json +++ b/plugins/utilities.json @@ -836,6 +836,20 @@ } } }, + "menu_theme": { + "description": "A simple UI mod for customizing the Main Menu's appearance. Go to your profiles for use", + "external_url": "", + "authors": [ + { + "name": "Yann", + "email": "", + "discord": "riyukiiyan" + } + ], + "versions": { + "1.0.0": null + } + }, "discord_richpresence": { "description": "Discord Rich Presence for Bombsquad.", "external_url": "https://youtu.be/SbbG9V74_E4", @@ -880,4 +894,4 @@ } } } -} \ No newline at end of file +} From f829acae3a5518467bc65b0b8c2c58be3a578f82 Mon Sep 17 00:00:00 2001 From: heLlow-step-sis Date: Sat, 26 Aug 2023 02:01:09 +0000 Subject: [PATCH 0707/1464] [ci] auto-format --- plugins/utilities/menu_theme.py | 981 ++++++++++++++++---------------- 1 file changed, 498 insertions(+), 483 deletions(-) diff --git a/plugins/utilities/menu_theme.py b/plugins/utilities/menu_theme.py index 5c2b0813..4a1163ea 100644 --- a/plugins/utilities/menu_theme.py +++ b/plugins/utilities/menu_theme.py @@ -30,8 +30,11 @@ from bauiv1lib.fileselector import FileSelectorWindow from bauiv1lib.popup import PopupMenuWindow -import _babase as _ba, babase as ba, bascenev1 as bs, bauiv1 as bui -import bascenev1lib.mainmenu as menu +import _babase as _ba +import babase as ba +import bascenev1 as bs +import bauiv1 as bui +import bascenev1lib.mainmenu as menu import json import os import shutil @@ -50,7 +53,7 @@ ui_medium = bs.UIScale.MEDIUM ui_large = bs.UIScale.LARGE -# method references +# method references original_unlocked_pro = bs.app.classic.accounts.have_pro original_account_init = AccountSettingsWindow.__init__ @@ -243,6 +246,7 @@ } } + class CustomColorPicker(ColorPicker): def _select_other(self): @@ -260,7 +264,7 @@ def _select_other(self): class CustomColorPickerExact(ColorPickerExact): - + def _color_change_press(self, color_name: str, increasing: bool): current_time = bui.apptime() since_last = current_time - self._last_press_time @@ -298,7 +302,7 @@ def __init__( maxwidth: float | None = None, autoselect: bool = True, value_change_call: Callable[[Any], Any] | None = None): - + if displayname is None: displayname = configkey self._value_change_call = value_change_call @@ -329,11 +333,11 @@ def _value_changed(self, val: bool): class FreeEditWindow(bui.Window): def _do_enter(self): - + def _error() -> None: bui.getsound('error').play(volume=2.0) bui.screenmessage('error ' + u'😑😑', color=(1.0, 0.0, 0.0)) - + try: if self.name_only: value = bui.textwidget(query=self._text_field) @@ -344,7 +348,7 @@ def _error() -> None: else: value = round(float(bui.textwidget(query=self._text_field)), 4) self.delegate.free_edit_enter(self, c=self.config_name, txt=value) - + except ValueError: return _error() bui.containerwidget(edit=self._root_widget, transition=self._transition_out) @@ -371,16 +375,16 @@ def __init__(self, delegate: Any = None, config_name: str = 'Menu Map', whitelis 1.5 if uiscale is bs.UIScale.MEDIUM else 1.0))) btn = bui.buttonwidget(parent=self._root_widget, - scale=0.5, - position=(40, height - 40), - size=(60, 60), - label='', - on_activate_call=self._do_back, - autoselect=True, - color=(0.55, 0.5, 0.6), - icon=bui.gettexture('crossOut'), - iconscale=1.2) - + scale=0.5, + position=(40, height - 40), + size=(60, 60), + label='', + on_activate_call=self._do_back, + autoselect=True, + color=(0.55, 0.5, 0.6), + icon=bui.gettexture('crossOut'), + iconscale=1.2) + self.config_name, self.delegate, self.name_only = config_name, delegate, name_only self._text_field = bui.textwidget( @@ -398,11 +402,11 @@ def __init__(self, delegate: Any = None, config_name: str = 'Menu Map', whitelis on_return_press_call=self._activate_enter_button) bui.textwidget(parent=self._root_widget, - text='Current: ' + str(config[config_name]) if not name_only else 'Save as', - position=(220, height - 44), - color=(0.5, 0.5, 0.5, 1.0), - size=(90, 30), - h_align='right') + text='Current: ' + str(config[config_name]) if not name_only else 'Save as', + position=(220, height - 44), + color=(0.5, 0.5, 0.5, 1.0), + size=(90, 30), + h_align='right') bui.widget(edit=btn, down_widget=self._text_field) @@ -415,9 +419,9 @@ def __init__(self, delegate: Any = None, config_name: str = 'Menu Map', whitelis label='Enter', on_activate_call=self._do_enter) bui.containerwidget(edit=self._root_widget, - cancel_button=btn, - start_button=btn2, - selected_child=self._text_field) + cancel_button=btn, + start_button=btn2, + selected_child=self._text_field) class MenuThemeWindow: @@ -458,7 +462,7 @@ def __init__(self, origin_widget: bui.widget = None, accounts_window=None): claims_left_right=False, claims_tab=False ) - + self._back_button = bui.buttonwidget( parent=self._root_widget, position=(23, 310) if ui_type is ui_small else (80, 511), @@ -648,7 +652,7 @@ def __init__(self, origin_widget: bui.widget = None, accounts_window=None): # >> debugging self._menu_configreset_button = bui.buttonwidget( parent=self._scroll_parent, - position=(5, height - 486) if ui_type is ui_small else (12, height - 765) , + position=(5, height - 486) if ui_type is ui_small else (12, height - 765), size=(329, 50) if ui_type is ui_small else (600, 80), color=(0.0, 0.67, 0.85), textcolor=(0.8, 0.8, 0.8), @@ -745,7 +749,8 @@ def __init__(self, origin_widget: bui.widget = None, accounts_window=None): button_type="regular", label=str(config["Menu Reflection Scale"]), text_scale=0.6 if ui_type is ui_small else 1.0, - on_activate_call=lambda: FreeEditWindow(delegate=self, whitelist=['num'], config_name='Menu Reflection Scale') + on_activate_call=lambda: FreeEditWindow( + delegate=self, whitelist=['num'], config_name='Menu Reflection Scale') ) self._menu_cameramode_button = bui.buttonwidget( @@ -763,7 +768,7 @@ def __init__(self, origin_widget: bui.widget = None, accounts_window=None): configkey="Menu Logo Text", position=(151, height - 308) if ui_type is ui_small else (287, height - 520), size=(40, 40) if ui_type is ui_small else (56, 56), - scale=0.62 if ui_type is ui_small else 1.4, + scale=0.62 if ui_type is ui_small else 1.4, displayname="" ) @@ -801,8 +806,6 @@ def __init__(self, origin_widget: bui.widget = None, accounts_window=None): on_activate_call=bs.Call(self.checkbox_window) ) - - def checkbox_window(self): self._root_widget_checkbox = bui.containerwidget( size=(800, 740), @@ -950,15 +953,20 @@ def popup_menu_selected_choice(self, window: PopupMenuWindow, choice: str): if config["tint"]: bs.app.config["Menu Tint"] = GLOBALS_MAPDATA.get(config["Menu Map"]).get("Tint") if config["ambient_color"]: - bs.app.config["Menu Ambient"] = GLOBALS_MAPDATA.get(config["Menu Map"]).get("Ambient") + bs.app.config["Menu Ambient"] = GLOBALS_MAPDATA.get( + config["Menu Map"]).get("Ambient") if config["vignette_outer"]: - bs.app.config["Menu Vignette Outer"] = GLOBALS_MAPDATA.get(config["Menu Map"]).get("Vignette Outer") + bs.app.config["Menu Vignette Outer"] = GLOBALS_MAPDATA.get( + config["Menu Map"]).get("Vignette Outer") if config["vignette_inner"]: - bs.app.config["Menu Vignette Inner"] = GLOBALS_MAPDATA.get(config["Menu Map"]).get("Vignette Inner") + bs.app.config["Menu Vignette Inner"] = GLOBALS_MAPDATA.get( + config["Menu Map"]).get("Vignette Inner") if config["map_color"]: - bs.app.config["Menu Map Color"] = GLOBALS_MAPDATA.get(config["Menu Map"]).get("Map Color") + bs.app.config["Menu Map Color"] = GLOBALS_MAPDATA.get( + config["Menu Map"]).get("Map Color") if config["map_reflection_scale"]: - bs.app.config["Menu Reflection Scale"] = GLOBALS_MAPDATA.get(config["Menu Map"]).get("Map Reflection Scale") + bs.app.config["Menu Reflection Scale"] = GLOBALS_MAPDATA.get( + config["Menu Map"]).get("Map Reflection Scale") if config["map_reflection_type"]: bs.app.config["Menu Reflection Type"] = 'Soft' @@ -979,12 +987,12 @@ def popup_menu_closing(self, window: PopupMenuWindow): def popup_fileselector(self): self._file_selector = FileSelectorWindow( - path=str(_ba.env()['python_directory_user']), - callback=self._import, - show_base_path=True, - valid_file_extensions=['json'], - allow_folders=False - ) + path=str(_ba.env()['python_directory_user']), + callback=self._import, + show_base_path=True, + valid_file_extensions=['json'], + allow_folders=False + ) def _import(self, path: str = None): try: @@ -993,67 +1001,71 @@ def _import(self, path: str = None): with open(self.path, 'r') as imported: selected = json.load(imported) handle_config([ - selected["Menu Map"], - selected["Menu Tint"], - selected["Menu Ambient"], - selected["Menu Vignette Outer"], - selected["Menu Vignette Inner"], - selected["Menu Music"], - selected["Menu Map Color"], - selected["Menu Reflection Scale"], - selected["Menu Reflection Type"], - selected["Menu Camera Mode"], - selected["Menu Logo Text"], - selected["vignette_outer"], - selected["vignette_inner"], - selected["ambient_color"], - selected["tint"], - selected["map_reflection_scale"], - selected["map_reflection_type"], - selected["map_color"]], - False + selected["Menu Map"], + selected["Menu Tint"], + selected["Menu Ambient"], + selected["Menu Vignette Outer"], + selected["Menu Vignette Inner"], + selected["Menu Music"], + selected["Menu Map Color"], + selected["Menu Reflection Scale"], + selected["Menu Reflection Type"], + selected["Menu Camera Mode"], + selected["Menu Logo Text"], + selected["vignette_outer"], + selected["vignette_inner"], + selected["ambient_color"], + selected["tint"], + selected["map_reflection_scale"], + selected["map_reflection_type"], + selected["map_color"]], + False ) self.update_buttons() - bui.screenmessage(f"Loaded {os.path.splitext(os.path.basename(self.path))[0]}!", color=(0.2, 0.4, 1.0)) - except: pass + bui.screenmessage( + f"Loaded {os.path.splitext(os.path.basename(self.path))[0]}!", color=(0.2, 0.4, 1.0)) + except: + pass del self._file_selector def _export(self, window: FreeEditWindow, txt: Any): path = _ba.env()['python_directory_user'] + "/_menutheme/" try: a = _ba.env()['python_directory_user'] + "/_menutheme" - os.makedirs(a, exist_ok = False) - except: pass + os.makedirs(a, exist_ok=False) + except: + pass with open(path + txt + '.json', 'w') as file: my_config = { - "Menu Map": config["Menu Map"], - "Menu Tint": config["Menu Tint"], - "Menu Ambient": config["Menu Ambient"], - "Menu Vignette Outer": config["Menu Vignette Outer"], - "Menu Vignette Inner": config["Menu Vignette Inner"], - "Menu Music": config["Menu Music"], - "Menu Map Color": config["Menu Map Color"], - "Menu Reflection Scale": config["Menu Reflection Scale"], - "Menu Reflection Type": config["Menu Reflection Type"], - "Menu Camera Mode": config["Menu Camera Mode"], - "Menu Logo Text": config["Menu Logo Text"], - "vignette_outer": config["vignette_outer"], - "vignette_inner": config["vignette_inner"], - "ambient_color": config["ambient_color"], - "tint": config["tint"], - "map_color": config["map_color"], - "map_reflection_scale": config["map_reflection_scale"], - "map_reflection_type": config["map_reflection_type"] - } + "Menu Map": config["Menu Map"], + "Menu Tint": config["Menu Tint"], + "Menu Ambient": config["Menu Ambient"], + "Menu Vignette Outer": config["Menu Vignette Outer"], + "Menu Vignette Inner": config["Menu Vignette Inner"], + "Menu Music": config["Menu Music"], + "Menu Map Color": config["Menu Map Color"], + "Menu Reflection Scale": config["Menu Reflection Scale"], + "Menu Reflection Type": config["Menu Reflection Type"], + "Menu Camera Mode": config["Menu Camera Mode"], + "Menu Logo Text": config["Menu Logo Text"], + "vignette_outer": config["vignette_outer"], + "vignette_inner": config["vignette_inner"], + "ambient_color": config["ambient_color"], + "tint": config["tint"], + "map_color": config["map_color"], + "map_reflection_scale": config["map_reflection_scale"], + "map_reflection_type": config["map_reflection_type"] + } json.dump(my_config, file, indent=4) - bui.screenmessage(f"Saved {os.path.splitext(os.path.basename(path+txt+'.json'))[0]}!", color=(0.2, 0.4, 1.0)) + bui.screenmessage( + f"Saved {os.path.splitext(os.path.basename(path+txt+'.json'))[0]}!", color=(0.2, 0.4, 1.0)) bui.getsound('gunCocking').play() def color_picker_popup(self, tag: str): bs.app.classic.accounts.have_pro = lambda: True CustomColorPicker(parent=self._root_widget, - position=(0,0), + position=(0, 0), initial_color=config[tag], delegate=self, tag=tag) @@ -1086,7 +1098,8 @@ def update_buttons(self): bui.buttonwidget(edit=self._menu_rcolor_button, color=config['Menu Map Color']) # menu values - bui.buttonwidget(edit=self._menu_reflections_button, label=str(config['Menu Reflection Scale'])) + bui.buttonwidget(edit=self._menu_reflections_button, + label=str(config['Menu Reflection Scale'])) bui.buttonwidget(edit=self._menu_cameramode_button, label=str(config['Menu Camera Mode'])) bui.checkboxwidget(edit=self._menu_logotext_button.widget, value=config['Menu Logo Text']) @@ -1101,7 +1114,7 @@ def reset_config(self): (0.45, 0.55, 0.54), (0.99, 0.98, 0.98), "Menu", (1.0, 1.0, 1.0), 0.3, 'None', 'rotate', True, True, True, True, True, True, True, True, True - ],False + ], False ) self.update_buttons() bui.screenmessage('Reset Settings', color=(0, 1, 0)) @@ -1132,11 +1145,13 @@ def _start_menu_music(self): bs.setmusic(music) def _make_word(self, *args, **kwargs) -> None: - if not config['Menu Logo Text']: return + if not config['Menu Logo Text']: + return super()._make_word(*args, **kwargs) def _make_logo(self, *args, **kwargs) -> None: - if not config['Menu Logo Text']: return + if not config['Menu Logo Text']: + return super()._make_logo(*args, **kwargs) def on_transition_in(self): @@ -1272,13 +1287,13 @@ def on_transition_in(self): b = GLOBALS_MAPDATA.get(config["Menu Map"]).get("Camera Bounds") b = ( - b[0] - b[3] / 2.0, - b[1] - b[4] / 2.0, - b[2] - b[5] / 2.0, - b[0] + b[3] / 2.0, - b[1] + b[4] / 2.0, - b[2] + b[5] / 2.0 - ) + b[0] - b[3] / 2.0, + b[1] - b[4] / 2.0, + b[2] - b[5] / 2.0, + b[0] + b[3] / 2.0, + b[1] + b[4] / 2.0, + b[2] + b[5] / 2.0 + ) gnode = self.globalsnode gnode.camera_mode = 'follow' if config["Menu Camera Mode"] == 'static' else 'rotate' @@ -1400,465 +1415,466 @@ def load_map_stuff(self): map_type = config["Menu Map"] if map_type == "The Pad (with trees)": self.main = bs.NodeActor(bs.newnode( - 'terrain', - delegate=self, - attrs={ - 'mesh': m('thePadLevel'), - 'color_texture': t('thePadLevelColor'), - 'reflection': 'soft', - 'reflection_scale': [0.3] - })) + 'terrain', + delegate=self, + attrs={ + 'mesh': m('thePadLevel'), + 'color_texture': t('thePadLevelColor'), + 'reflection': 'soft', + 'reflection_scale': [0.3] + })) self.trees = bs.NodeActor(bs.newnode( - 'terrain', - attrs={ - 'mesh': m('trees'), - 'lighting': False, - 'reflection': 'char', - 'reflection_scale': [0.1], - 'color_texture': t('treesColor') - })) + 'terrain', + attrs={ + 'mesh': m('trees'), + 'lighting': False, + 'reflection': 'char', + 'reflection_scale': [0.1], + 'color_texture': t('treesColor') + })) self.bgterrain = bs.NodeActor(bs.newnode( - 'terrain', - attrs={ - 'mesh': m('thePadBG'), - 'color': (0.92, 0.91, 0.9), - 'lighting': False, - 'background': True, - 'color_texture': t('menuBG'), - })) + 'terrain', + attrs={ + 'mesh': m('thePadBG'), + 'color': (0.92, 0.91, 0.9), + 'lighting': False, + 'background': True, + 'color_texture': t('menuBG'), + })) self.bottom = bs.NodeActor(bs.newnode( - 'terrain', - attrs={ - 'mesh': m('thePadLevelBottom'), - 'lighting': False, - 'reflection': 'soft', - 'reflection_scale': [0.45], - 'color_texture': t('thePadLevelColor') - })) + 'terrain', + attrs={ + 'mesh': m('thePadLevelBottom'), + 'lighting': False, + 'reflection': 'soft', + 'reflection_scale': [0.45], + 'color_texture': t('thePadLevelColor') + })) elif map_type == "The Pad": self.main = bs.NodeActor(bs.newnode( - 'terrain', - delegate=self, - attrs={ - 'mesh': m('thePadLevel'), - 'color_texture': t('thePadLevelColor'), - 'reflection': 'soft', - 'reflection_scale': [0.3] - })) + 'terrain', + delegate=self, + attrs={ + 'mesh': m('thePadLevel'), + 'color_texture': t('thePadLevelColor'), + 'reflection': 'soft', + 'reflection_scale': [0.3] + })) self.bgterrain = bs.NodeActor(bs.newnode( - 'terrain', - attrs={ - 'mesh': m('thePadBG'), - 'color': (0.92, 0.91, 0.9), - 'lighting': False, - 'background': True, - 'color_texture': t("menuBG") - })) + 'terrain', + attrs={ + 'mesh': m('thePadBG'), + 'color': (0.92, 0.91, 0.9), + 'lighting': False, + 'background': True, + 'color_texture': t("menuBG") + })) self.bottom = bs.NodeActor(bs.newnode( - 'terrain', - attrs={ - 'mesh': m('thePadLevelBottom'), - 'lighting': False, - 'reflection': 'soft', - 'reflection_scale': [0.45], - 'color_texture': t('thePadLevelColor') - })) + 'terrain', + attrs={ + 'mesh': m('thePadLevelBottom'), + 'lighting': False, + 'reflection': 'soft', + 'reflection_scale': [0.45], + 'color_texture': t('thePadLevelColor') + })) elif map_type == "Hockey Stadium": self.main = bs.NodeActor(bs.newnode( - 'terrain', - delegate=self, - attrs={ - 'mesh': m('hockeyStadiumOuter'), - 'color_texture': t('hockeyStadium'), - 'reflection': 'soft', - 'reflection_scale': [0.3] - })) + 'terrain', + delegate=self, + attrs={ + 'mesh': m('hockeyStadiumOuter'), + 'color_texture': t('hockeyStadium'), + 'reflection': 'soft', + 'reflection_scale': [0.3] + })) self.inner = bs.NodeActor(bs.newnode( - 'terrain', - attrs={ - 'mesh': m('hockeyStadiumInner'), - 'opacity': 0.92, - 'opacity_in_low_or_ui_medium_quality': 1.0, - 'color_texture': t('hockeyStadium') - })) + 'terrain', + attrs={ + 'mesh': m('hockeyStadiumInner'), + 'opacity': 0.92, + 'opacity_in_low_or_ui_medium_quality': 1.0, + 'color_texture': t('hockeyStadium') + })) self.stands = bs.NodeActor(bs.newnode( - 'terrain', - attrs={ - 'mesh': m('hockeyStadiumStands'), - 'visible_in_reflections': False, - 'color_texture': t('footballStadium') - })) + 'terrain', + attrs={ + 'mesh': m('hockeyStadiumStands'), + 'visible_in_reflections': False, + 'color_texture': t('footballStadium') + })) elif map_type == "Football Stadium": self.main = bs.NodeActor(bs.newnode( - 'terrain', - delegate=self, - attrs={ - 'mesh': m('footballStadium'), - 'color_texture': t('footballStadium'), - })) + 'terrain', + delegate=self, + attrs={ + 'mesh': m('footballStadium'), + 'color_texture': t('footballStadium'), + })) elif map_type == "Bridgit": self.main = bs.NodeActor(bs.newnode( - 'terrain', - delegate=self, - attrs={ - 'mesh': m('bridgitLevelTop'), - 'color_texture': t('bridgitLevelColor'), - })) + 'terrain', + delegate=self, + attrs={ + 'mesh': m('bridgitLevelTop'), + 'color_texture': t('bridgitLevelColor'), + })) self.bottom = bs.NodeActor(bs.newnode( - 'terrain', - attrs={ - 'mesh': m('bridgitLevelBottom'), - 'lighting': False, - 'color_texture': t('bridgitLevelColor'), - })) + 'terrain', + attrs={ + 'mesh': m('bridgitLevelBottom'), + 'lighting': False, + 'color_texture': t('bridgitLevelColor'), + })) self.background = bs.NodeActor(bs.newnode( - 'terrain', - attrs={ - 'mesh': m('natureBackground'), - 'lighting': False, - 'background': True, - 'color_texture': t('natureBackgroundColor'), - })) + 'terrain', + attrs={ + 'mesh': m('natureBackground'), + 'lighting': False, + 'background': True, + 'color_texture': t('natureBackgroundColor'), + })) elif map_type == "Big G": self.main = bs.NodeActor(bs.newnode( - 'terrain', - delegate=self, - attrs={ - 'mesh': m('bigG'), - 'color': (0.7, 0.7, 0.7), - 'color_texture': t('bigG'), - })) + 'terrain', + delegate=self, + attrs={ + 'mesh': m('bigG'), + 'color': (0.7, 0.7, 0.7), + 'color_texture': t('bigG'), + })) self.bottom = bs.NodeActor(bs.newnode( - 'terrain', - attrs={ - 'mesh': m('bigGBottom'), - 'lighting': False, - 'color': (0.7, 0.7, 0.7), - 'color_texture': t('bigG'), - })) + 'terrain', + attrs={ + 'mesh': m('bigGBottom'), + 'lighting': False, + 'color': (0.7, 0.7, 0.7), + 'color_texture': t('bigG'), + })) self.background = bs.NodeActor(bs.newnode( - 'terrain', - attrs={ - 'mesh': m('natureBackground'), - 'lighting': False, - 'background': True, - 'color_texture': t('natureBackgroundColor'), - })) + 'terrain', + attrs={ + 'mesh': m('natureBackground'), + 'lighting': False, + 'background': True, + 'color_texture': t('natureBackgroundColor'), + })) elif map_type == "Roundabout": self.main = bs.NodeActor(bs.newnode( - 'terrain', - delegate=self, - attrs={ - 'mesh': m('roundaboutLevel'), - 'color': (0.7, 0.7, 0.7), - 'color_texture': t('roundaboutLevelColor'), - })) + 'terrain', + delegate=self, + attrs={ + 'mesh': m('roundaboutLevel'), + 'color': (0.7, 0.7, 0.7), + 'color_texture': t('roundaboutLevelColor'), + })) self.bottom = bs.NodeActor(bs.newnode( - 'terrain', - attrs={ - 'mesh': m('roundaboutLevelBottom'), - 'lighting': False, - 'color': (0.7, 0.7, 0.7), - 'color_texture': t('roundaboutLevelColor'), - })) + 'terrain', + attrs={ + 'mesh': m('roundaboutLevelBottom'), + 'lighting': False, + 'color': (0.7, 0.7, 0.7), + 'color_texture': t('roundaboutLevelColor'), + })) self.background = bs.NodeActor(bs.newnode( - 'terrain', - attrs={ - 'mesh': m('natureBackground'), - 'lighting': False, - 'background': True, - 'color_texture': t('natureBackgroundColor'), - })) + 'terrain', + attrs={ + 'mesh': m('natureBackground'), + 'lighting': False, + 'background': True, + 'color_texture': t('natureBackgroundColor'), + })) elif map_type == "Monkey Face": self.main = bs.NodeActor(bs.newnode( - 'terrain', - delegate=self, - attrs={ - 'mesh': m('monkeyFaceLevel'), - 'color_texture': t('monkeyFaceLevelColor'), - })) + 'terrain', + delegate=self, + attrs={ + 'mesh': m('monkeyFaceLevel'), + 'color_texture': t('monkeyFaceLevelColor'), + })) self.bottom = bs.NodeActor(bs.newnode( - 'terrain', - attrs={ - 'mesh': m('monkeyFaceLevelBottom'), - 'lighting': False, - 'color_texture': t('monkeyFaceLevelColor'), - })) + 'terrain', + attrs={ + 'mesh': m('monkeyFaceLevelBottom'), + 'lighting': False, + 'color_texture': t('monkeyFaceLevelColor'), + })) self.background = bs.NodeActor(bs.newnode( - 'terrain', - attrs={ - 'mesh': m('natureBackground'), - 'lighting': False, - 'color_texture': t('natureBackgroundColor'), - })) + 'terrain', + attrs={ + 'mesh': m('natureBackground'), + 'lighting': False, + 'color_texture': t('natureBackgroundColor'), + })) elif map_type == "Monkey Face": self.main = bs.NodeActor(bs.newnode( - 'terrain', - delegate=self, - attrs={ - 'mesh': m('monkeyFaceLevel'), - 'color_texture': t('monkeyFaceLevelColor'), - })) + 'terrain', + delegate=self, + attrs={ + 'mesh': m('monkeyFaceLevel'), + 'color_texture': t('monkeyFaceLevelColor'), + })) self.bottom = bs.NodeActor(bs.newnode( - 'terrain', - attrs={ - 'mesh': m('monkeyFaceLevelBottom'), - 'lighting': False, - 'color_texture': t('monkeyFaceLevelColor'), - })) + 'terrain', + attrs={ + 'mesh': m('monkeyFaceLevelBottom'), + 'lighting': False, + 'color_texture': t('monkeyFaceLevelColor'), + })) self.background = bs.NodeActor(bs.newnode( - 'terrain', - attrs={ - 'mesh': m('natureBackground'), - 'lighting': False, - 'color_texture': t('natureBackgroundColor'), - })) + 'terrain', + attrs={ + 'mesh': m('natureBackground'), + 'lighting': False, + 'color_texture': t('natureBackgroundColor'), + })) elif map_type == "Zig Zag": self.main = bs.NodeActor(bs.newnode( - 'terrain', - delegate=self, - attrs={ - 'mesh': m('zigZagLevel'), - 'color_texture': t('zigZagLevelColor'), - })) + 'terrain', + delegate=self, + attrs={ + 'mesh': m('zigZagLevel'), + 'color_texture': t('zigZagLevelColor'), + })) self.bottom = bs.NodeActor(bs.newnode( - 'terrain', - attrs={ - 'mesh': m('zigZagLevelBottom'), - 'lighting': False, - 'color_texture': t('zigZagLevelColor'), - })) + 'terrain', + attrs={ + 'mesh': m('zigZagLevelBottom'), + 'lighting': False, + 'color_texture': t('zigZagLevelColor'), + })) self.background = bs.NodeActor(bs.newnode( - 'terrain', - attrs={ - 'mesh': m('natureBackground'), - 'lighting': False, - 'color_texture': t('natureBackgroundColor'), - })) + 'terrain', + attrs={ + 'mesh': m('natureBackground'), + 'lighting': False, + 'color_texture': t('natureBackgroundColor'), + })) elif map_type == "Doom Shroom": self.main = bs.NodeActor(bs.newnode( - 'terrain', - delegate=self, - attrs={ - 'mesh': m('doomShroomLevel'), - 'color_texture': t('doomShroomLevelColor'), - })) + 'terrain', + delegate=self, + attrs={ + 'mesh': m('doomShroomLevel'), + 'color_texture': t('doomShroomLevelColor'), + })) self.stem = bs.NodeActor(bs.newnode( - 'terrain', - attrs={ - 'mesh': m('doomShroomStem'), - 'lighting': False, - 'color_texture': t('doomShroomLevelColor'), - })) + 'terrain', + attrs={ + 'mesh': m('doomShroomStem'), + 'lighting': False, + 'color_texture': t('doomShroomLevelColor'), + })) self.background = bs.NodeActor(bs.newnode( - 'terrain', - attrs={ - 'mesh': m('doomShroomBG'), - 'lighting': False, - 'background': True, - 'color_texture': t('doomShroomBGColor'), - })) + 'terrain', + attrs={ + 'mesh': m('doomShroomBG'), + 'lighting': False, + 'background': True, + 'color_texture': t('doomShroomBGColor'), + })) elif map_type == "Lake Frigid": self.main = bs.NodeActor(bs.newnode( - 'terrain', - delegate=self, - attrs={ - 'mesh': m('lakeFrigid'), - 'color_texture': t('lakeFrigid'), - })) + 'terrain', + delegate=self, + attrs={ + 'mesh': m('lakeFrigid'), + 'color_texture': t('lakeFrigid'), + })) self.top = bs.NodeActor(bs.newnode( - 'terrain', - attrs={ - 'mesh': m('lakeFrigidTop'), - 'lighting': False, - 'color_texture': t('lakeFrigid'), - })) + 'terrain', + attrs={ + 'mesh': m('lakeFrigidTop'), + 'lighting': False, + 'color_texture': t('lakeFrigid'), + })) self.reflections = bs.NodeActor(bs.newnode( - 'terrain', - attrs={ - 'mesh': m('lakeFrigidReflections'), - 'lighting': False, - 'overlay': True, - 'opacity': 0.15, - 'color_texture': t('lakeFrigidReflections'), - })) + 'terrain', + attrs={ + 'mesh': m('lakeFrigidReflections'), + 'lighting': False, + 'overlay': True, + 'opacity': 0.15, + 'color_texture': t('lakeFrigidReflections'), + })) elif map_type == "Tip Top": self.main = bs.NodeActor(bs.newnode( - 'terrain', - delegate=self, - attrs={ - 'mesh': m('tipTopLevel'), - 'color': (0.7, 0.7, 0.7), - 'color_texture': t('tipTopLevelColor'), - })) + 'terrain', + delegate=self, + attrs={ + 'mesh': m('tipTopLevel'), + 'color': (0.7, 0.7, 0.7), + 'color_texture': t('tipTopLevelColor'), + })) self.bottom = bs.NodeActor(bs.newnode( - 'terrain', - attrs={ - 'mesh': m('tipTopLevelBottom'), - 'lighting': False, - 'color': (0.7, 0.7, 0.7), - 'color_texture': t('tipTopLevelColor'), - })) + 'terrain', + attrs={ + 'mesh': m('tipTopLevelBottom'), + 'lighting': False, + 'color': (0.7, 0.7, 0.7), + 'color_texture': t('tipTopLevelColor'), + })) self.background = bs.NodeActor(bs.newnode( - 'terrain', - attrs={ - 'mesh': m('tipTopBG'), - 'lighting': False, - 'color': (0.4, 0.4, 0.4), - 'background': True, - 'color_texture': t('tipTopBGColor'), - })) + 'terrain', + attrs={ + 'mesh': m('tipTopBG'), + 'lighting': False, + 'color': (0.4, 0.4, 0.4), + 'background': True, + 'color_texture': t('tipTopBGColor'), + })) elif map_type == "Crag Castle": self.main = bs.NodeActor(bs.newnode( - 'terrain', - delegate=self, - attrs={ - 'mesh': m('cragCastleLevel'), - 'color_texture': t('cragCastleLevelColor'), - })) + 'terrain', + delegate=self, + attrs={ + 'mesh': m('cragCastleLevel'), + 'color_texture': t('cragCastleLevelColor'), + })) self.bottom = bs.NodeActor(bs.newnode( - 'terrain', - attrs={ - 'mesh': m('cragCastleLevelBottom'), - 'lighting': False, - 'color_texture': t('cragCastleLevelColor'), - })) + 'terrain', + attrs={ + 'mesh': m('cragCastleLevelBottom'), + 'lighting': False, + 'color_texture': t('cragCastleLevelColor'), + })) self.background = bs.NodeActor(bs.newnode( - 'terrain', - attrs={ - 'mesh': m('thePadBG'), - 'lighting': False, - 'background': True, - 'color_texture': t('menuBG'), - })) + 'terrain', + attrs={ + 'mesh': m('thePadBG'), + 'lighting': False, + 'background': True, + 'color_texture': t('menuBG'), + })) elif map_type == "Tower D": self.main = bs.NodeActor(bs.newnode( - 'terrain', - delegate=self, - attrs={ - 'mesh': m('towerDLevel'), - 'color_texture': t('towerDLevelColor'), - })) + 'terrain', + delegate=self, + attrs={ + 'mesh': m('towerDLevel'), + 'color_texture': t('towerDLevelColor'), + })) self.bottom = bs.NodeActor(bs.newnode( - 'terrain', - attrs={ - 'mesh': m('towerDLevelBottom'), - 'lighting': False, - 'color_texture': t('towerDLevelColor'), - })) + 'terrain', + attrs={ + 'mesh': m('towerDLevelBottom'), + 'lighting': False, + 'color_texture': t('towerDLevelColor'), + })) self.background = bs.NodeActor(bs.newnode( - 'terrain', - attrs={ - 'mesh': m('thePadBG'), - 'lighting': False, - 'background': True, - 'color_texture': t('menuBG'), - })) + 'terrain', + attrs={ + 'mesh': m('thePadBG'), + 'lighting': False, + 'background': True, + 'color_texture': t('menuBG'), + })) elif map_type == "Happy Thoughts": self.main = bs.NodeActor(bs.newnode( - 'terrain', - delegate=self, - attrs={ - 'mesh': m('alwaysLandLevel'), - 'color_texture': t('alwaysLandLevelColor'), - })) + 'terrain', + delegate=self, + attrs={ + 'mesh': m('alwaysLandLevel'), + 'color_texture': t('alwaysLandLevelColor'), + })) self.bottom = bs.NodeActor(bs.newnode( - 'terrain', - attrs={ - 'mesh': m('alwaysLandLevelBottom'), - 'lighting': False, - 'color_texture': t('alwaysLandLevelColor'), - })) + 'terrain', + attrs={ + 'mesh': m('alwaysLandLevelBottom'), + 'lighting': False, + 'color_texture': t('alwaysLandLevelColor'), + })) self.background = bs.NodeActor(bs.newnode( - 'terrain', - attrs={ - 'mesh': m('alwaysLandBG'), - 'lighting': False, - 'background': True, - 'color_texture': t('alwaysLandBGColor'), - })) + 'terrain', + attrs={ + 'mesh': m('alwaysLandBG'), + 'lighting': False, + 'background': True, + 'color_texture': t('alwaysLandBGColor'), + })) elif map_type == "Step Right Up": self.main = bs.NodeActor(bs.newnode( - 'terrain', - delegate=self, - attrs={ - 'mesh': m('stepRightUpLevel'), - 'color_texture': t('stepRightUpLevelColor'), - })) + 'terrain', + delegate=self, + attrs={ + 'mesh': m('stepRightUpLevel'), + 'color_texture': t('stepRightUpLevelColor'), + })) self.bottom = bs.NodeActor(bs.newnode( - 'terrain', - attrs={ - 'mesh': m('stepRightUpLevelBottom'), - 'lighting': False, - 'color_texture': t('stepRightUpLevelColor'), - })) + 'terrain', + attrs={ + 'mesh': m('stepRightUpLevelBottom'), + 'lighting': False, + 'color_texture': t('stepRightUpLevelColor'), + })) self.background = bs.NodeActor(bs.newnode( - 'terrain', - attrs={ - 'mesh': m('thePadBG'), - 'lighting': False, - 'background': True, - 'color_texture': t('menuBG'), - })) + 'terrain', + attrs={ + 'mesh': m('thePadBG'), + 'lighting': False, + 'background': True, + 'color_texture': t('menuBG'), + })) elif map_type == "Courtyard": self.main = bs.NodeActor(bs.newnode( - 'terrain', - delegate=self, - attrs={ - 'mesh': m('courtyardLevel'), - 'color_texture': t('courtyardLevelColor'), - })) + 'terrain', + delegate=self, + attrs={ + 'mesh': m('courtyardLevel'), + 'color_texture': t('courtyardLevelColor'), + })) self.bottom = bs.NodeActor(bs.newnode( - 'terrain', - attrs={ - 'mesh': m('courtyardLevelBottom'), - 'lighting': False, - 'color_texture': t('courtyardLevelColor'), - })) + 'terrain', + attrs={ + 'mesh': m('courtyardLevelBottom'), + 'lighting': False, + 'color_texture': t('courtyardLevelColor'), + })) self.background = bs.NodeActor(bs.newnode( - 'terrain', - attrs={ - 'mesh': m('thePadBG'), - 'lighting': False, - 'background': True, - 'color_texture': t('menuBG'), - })) + 'terrain', + attrs={ + 'mesh': m('thePadBG'), + 'lighting': False, + 'background': True, + 'color_texture': t('menuBG'), + })) elif map_type == "Rampage": self.main = bs.NodeActor(bs.newnode( - 'terrain', - delegate=self, - attrs={ - 'mesh': m('rampageLevel'), - 'color_texture': t('rampageLevelColor'), - })) + 'terrain', + delegate=self, + attrs={ + 'mesh': m('rampageLevel'), + 'color_texture': t('rampageLevelColor'), + })) self.bottom = bs.NodeActor(bs.newnode( - 'terrain', - attrs={ - 'mesh': m('rampageLevelBottom'), - 'lighting': False, - 'color_texture': t('rampageLevelColor'), - })) + 'terrain', + attrs={ + 'mesh': m('rampageLevelBottom'), + 'lighting': False, + 'color_texture': t('rampageLevelColor'), + })) self.background = bs.NodeActor(bs.newnode( - 'terrain', - attrs={ - 'mesh': m('rampageBG'), - 'lighting': False, - 'background': True, - 'color_texture': t('rampageBGColor'), - })) + 'terrain', + attrs={ + 'mesh': m('rampageBG'), + 'lighting': False, + 'background': True, + 'color_texture': t('rampageBGColor'), + })) self.background_2 = bs.NodeActor(bs.newnode( - 'terrain', - attrs={ - 'mesh': m('rampageBG2'), - 'lighting': False, - 'background': True, - 'color_texture': t('rampageBGColor2'), - })) + 'terrain', + attrs={ + 'mesh': m('rampageBG2'), + 'lighting': False, + 'background': True, + 'color_texture': t('rampageBGColor2'), + })) def menu_theme(self): this_class = self - MenuThemeWindow(accounts_window = this_class) + MenuThemeWindow(accounts_window=this_class) + def handle_config(keys: List[str], adding: bool = False): our_config = { @@ -1883,7 +1899,7 @@ def handle_config(keys: List[str], adding: bool = False): } config_keys = list(our_config.keys()) p = 0 - + for cf in config_keys: if cf not in bs.app.config and adding: config[cf] = keys[p] @@ -1930,7 +1946,7 @@ def new_back(self, save_state: bool = True): assert bui.app.classic is not None if save_state: self._save_state() - + bui.containerwidget(edit=self._root_widget, transition=self._transition_out) main_menu_window = MainMenuWindow(transition='in_left').get_root_widget() @@ -1971,6 +1987,5 @@ def on_app_running(self): (0.45, 0.55, 0.54), (0.99, 0.98, 0.98), "Menu", (1.0, 1.0, 1.0), 0.3, 'None', 'rotate', True, True, True, True, True, True, True, True, True - ],True + ], True ) - \ No newline at end of file From b88c52e9b9d75924a7df0f95550f99061a5c7a4c Mon Sep 17 00:00:00 2001 From: heLlow-step-sis Date: Sat, 26 Aug 2023 02:01:11 +0000 Subject: [PATCH 0708/1464] [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 511c8d6c..f9fbe0b1 100644 --- a/plugins/utilities.json +++ b/plugins/utilities.json @@ -847,7 +847,12 @@ } ], "versions": { - "1.0.0": null + "1.0.0": { + "api_version": 8, + "commit_sha": "f829aca", + "released_on": "26-08-2023", + "md5sum": "4cca8e04efadf39b2be51b5b95c4e5a4" + } } }, "discord_richpresence": { @@ -894,4 +899,4 @@ } } } -} +} \ No newline at end of file From 41cc38af1ffa172496beeb0fb79caa0a7f884df4 Mon Sep 17 00:00:00 2001 From: Loup Date: Sun, 1 Oct 2023 17:48:20 +0530 Subject: [PATCH 0709/1464] Removed deprecated methods --- index.json | 3 ++- plugin_manager.py | 4 ++-- plugins/utilities.json | 3 ++- plugins/utilities/practice_tools.py | 2 +- 4 files changed, 7 insertions(+), 5 deletions(-) diff --git a/index.json b/index.json index 3369fcba..871e4f60 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": { + "1.0.2": null, "1.0.1": { "api_version": 8, "commit_sha": "7dba50e", @@ -116,4 +117,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 e883fba7..a894ba1a 100644 --- a/plugin_manager.py +++ b/plugin_manager.py @@ -799,7 +799,7 @@ def latest_version(self): def latest_compatible_version(self): if self._latest_compatible_version is None: for number, info in self.info["versions"].items(): - if info["api_version"] == babase.app.api_version: + if info["api_version"] == babase.app.env.api_version: self._latest_compatible_version = PluginVersion( self, (number, info), @@ -1233,7 +1233,7 @@ def unset_index_global_cache(self): async def get_update_details(self): index = await self.get_index() for version, info in index["versions"].items(): - if info["api_version"] != babase.app.api_version: + if info["api_version"] != babase.app.env.api_version: # No point checking a version of the API game doesn't support. continue if version == PLUGIN_MANAGER_VERSION: diff --git a/plugins/utilities.json b/plugins/utilities.json index f9fbe0b1..341f9bc5 100644 --- a/plugins/utilities.json +++ b/plugins/utilities.json @@ -722,6 +722,7 @@ } ], "versions": { + "2.0.1": null, "2.0.0": { "api_version": 8, "commit_sha": "9340deb", @@ -899,4 +900,4 @@ } } } -} \ No newline at end of file +} diff --git a/plugins/utilities/practice_tools.py b/plugins/utilities/practice_tools.py index 1c7fe086..88dcc800 100644 --- a/plugins/utilities/practice_tools.py +++ b/plugins/utilities/practice_tools.py @@ -185,7 +185,7 @@ class Practice(Plugin): def on_app_running(self) -> None: """Plugin start point.""" - if app.build_number < 20427: + if app.env.build_number < 20427: bui.screenmessage( 'ok', color=(.8, .1, .1)) From 292d5cc1fc6f19f09b027ccc01b711a725183654 Mon Sep 17 00:00:00 2001 From: Loup-Garou911XD Date: Sun, 1 Oct 2023 12:20:03 +0000 Subject: [PATCH 0710/1464] [ci] apply-version-metadata --- index.json | 9 +++++++-- plugins/utilities.json | 9 +++++++-- 2 files changed, 14 insertions(+), 4 deletions(-) diff --git a/index.json b/index.json index 871e4f60..f8038a6e 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": { - "1.0.2": null, + "1.0.2": { + "api_version": 8, + "commit_sha": "41cc38a", + "released_on": "01-10-2023", + "md5sum": "908dc850e1e33cba0deea94309fcfb86" + }, "1.0.1": { "api_version": 8, "commit_sha": "7dba50e", @@ -117,4 +122,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/plugins/utilities.json b/plugins/utilities.json index 341f9bc5..4246bcc0 100644 --- a/plugins/utilities.json +++ b/plugins/utilities.json @@ -722,7 +722,12 @@ } ], "versions": { - "2.0.1": null, + "2.0.1": { + "api_version": 8, + "commit_sha": "41cc38a", + "released_on": "01-10-2023", + "md5sum": "9ed00b2c86bd62168aa1cab6ea5fdfe4" + }, "2.0.0": { "api_version": 8, "commit_sha": "9340deb", @@ -900,4 +905,4 @@ } } } -} +} \ No newline at end of file From 818ec655be9664c45ef68ddf0fd874da6ebacb1a Mon Sep 17 00:00:00 2001 From: Rikko Date: Sun, 1 Oct 2023 18:43:25 +0530 Subject: [PATCH 0711/1464] Bump plugin manager source version --- index.json | 9 ++------- plugin_manager.py | 2 +- 2 files changed, 3 insertions(+), 8 deletions(-) diff --git a/index.json b/index.json index f8038a6e..871e4f60 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": { - "1.0.2": { - "api_version": 8, - "commit_sha": "41cc38a", - "released_on": "01-10-2023", - "md5sum": "908dc850e1e33cba0deea94309fcfb86" - }, + "1.0.2": null, "1.0.1": { "api_version": 8, "commit_sha": "7dba50e", @@ -122,4 +117,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 a894ba1a..ea65c03d 100644 --- a/plugin_manager.py +++ b/plugin_manager.py @@ -32,7 +32,7 @@ _uiscale = bui.app.ui_v1.uiscale -PLUGIN_MANAGER_VERSION = "1.0.1" +PLUGIN_MANAGER_VERSION = "1.0.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 8233d3290ef188d75450e4d2c2409c68b1f1c4cb Mon Sep 17 00:00:00 2001 From: rikkolovescats Date: Sun, 1 Oct 2023 13:16:21 +0000 Subject: [PATCH 0712/1464] [ci] apply-version-metadata --- index.json | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/index.json b/index.json index 871e4f60..f913ecd7 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": { - "1.0.2": null, + "1.0.2": { + "api_version": 8, + "commit_sha": "818ec65", + "released_on": "01-10-2023", + "md5sum": "9cd1facb888e63ba08b0607a8561991a" + }, "1.0.1": { "api_version": 8, "commit_sha": "7dba50e", @@ -117,4 +122,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 c92737eb8c828d75236392ad3c5ace6c233b9dab Mon Sep 17 00:00:00 2001 From: brostos <67740566+brostosjoined@users.noreply.github.com> Date: Tue, 3 Oct 2023 01:18:42 +0300 Subject: [PATCH 0713/1464] Loop and backward compability fix --- plugin_manager.py | 54 +++++++++++++++++++++++++++++++---------------- 1 file changed, 36 insertions(+), 18 deletions(-) diff --git a/plugin_manager.py b/plugin_manager.py index ea65c03d..923bf889 100644 --- a/plugin_manager.py +++ b/plugin_manager.py @@ -1,5 +1,6 @@ # ba_meta require api 8 from babase._meta import EXPORT_CLASS_NAME_SHORTCUTS +from baenv import TARGET_BALLISTICA_BUILD as build_number import babase import _babase import bauiv1 as bui @@ -32,7 +33,7 @@ _uiscale = bui.app.ui_v1.uiscale -PLUGIN_MANAGER_VERSION = "1.0.2" +PLUGIN_MANAGER_VERSION = "1.0.3" 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. @@ -43,7 +44,24 @@ } PLUGIN_DIRECTORY = _env["python_directory_user"] - +def get_event_loop(): + # loop = asyncio.ProactorEventLoop() if sys.platform == 'win32' else asyncio.new_event_loop() + return ba._asyncio._asyncio_event_loop + # try: + # running = asyncio.get_running_loop() + # except RuntimeError: + # return loop + # if running.is_closed(): + # return loop + # else: + # if sys.platform in ('linux', 'darwin'): + # return running + # if sys.platform == 'win32': + # if isinstance(running, asyncio.ProactorEventLoop): + # return running + # else: + # return loop + def _regexp_friendly_class_name_shortcut(string): return string.replace(".", "\\.") @@ -100,7 +118,7 @@ def send_network_request(request): async def async_send_network_request(request): - loop = asyncio.get_event_loop() + loop = get_event_loop() response = await loop.run_in_executor(None, send_network_request, request) return response @@ -129,7 +147,7 @@ def stream_network_response_to_file(request, file, md5sum=None, retries=3): async def async_stream_network_response_to_file(request, file, md5sum=None, retries=3): - loop = asyncio.get_event_loop() + loop = get_event_loop() content = await loop.run_in_executor( None, stream_network_response_to_file, @@ -537,7 +555,7 @@ async def get_content(self): if self._content is None: if not self.is_installed: raise PluginNotInstalled("Plugin is not available locally.") - loop = asyncio.get_event_loop() + loop = get_event_loop() self._content = await loop.run_in_executor(None, self._get_content) return self._content @@ -669,7 +687,7 @@ def set_version(self, version): async def set_content(self, content): if not self._content: - loop = asyncio.get_event_loop() + loop = get_event_loop() await loop.run_in_executor(None, self._set_content, content) self._content = content return self @@ -799,7 +817,7 @@ def latest_version(self): def latest_compatible_version(self): if self._latest_compatible_version is None: for number, info in self.info["versions"].items(): - if info["api_version"] == babase.app.env.api_version: + if info["api_version"] == babase.app.api_version if build_number < 21282 else babase.app.env.api_version: self._latest_compatible_version = PluginVersion( self, (number, info), @@ -855,7 +873,7 @@ def __init__(self, plugin, origin_widget, button_callback=lambda: None): self.plugin = plugin self.button_callback = button_callback self.scale_origin = origin_widget.get_screen_space_center() - loop = asyncio.get_event_loop() + loop = get_event_loop() loop.create_task(self.draw_ui()) def get_description(self, minimum_character_offset=40): @@ -1107,7 +1125,7 @@ async def asyncio_handler(fn, self, *args, **kwargs): def wrapper(self, *args, **kwargs): self._ok() - loop = asyncio.get_event_loop() + loop = get_event_loop() if asyncio.iscoroutinefunction(fn): loop.create_task(asyncio_handler(fn, self, *args, **kwargs)) else: @@ -1233,7 +1251,7 @@ def unset_index_global_cache(self): async def get_update_details(self): index = await self.get_index() for version, info in index["versions"].items(): - if info["api_version"] != babase.app.env.api_version: + if info["api_version"] != babase.app.api_version if build_number < 21282 else babase.app.env.api_version: # No point checking a version of the API game doesn't support. continue if version == PLUGIN_MANAGER_VERSION: @@ -1369,7 +1387,7 @@ def __init__(self, origin_widget): # autoselect=True, description="Add Source") - loop = asyncio.get_event_loop() + loop = get_event_loop() bui.buttonwidget(parent=self._root_widget, position=(330, 28), @@ -1475,7 +1493,7 @@ def _update_custom_sources_widget(self): on_activate_call=self.show_sources_window) def popup_menu_selected_choice(self, window, choice): - loop = asyncio.get_event_loop() + loop = get_event_loop() loop.create_task(self._asyncio_callback(choice)) def popup_menu_closing(self, window): @@ -1497,7 +1515,7 @@ def __init__(self, transition: str = "in_right", origin_widget: bui.Widget = Non self.selected_category = None self.plugins_in_current_view = {} - loop = asyncio.get_event_loop() + loop = get_event_loop() loop.create_task(self.draw_index()) self._width = (700 if _uiscale is babase.UIScale.SMALL @@ -1692,7 +1710,7 @@ def draw_search_bar(self): description=filter_txt) self._last_filter_text = None self._last_filter_plugins = [] - loop = asyncio.get_event_loop() + loop = get_event_loop() loop.create_task(self.process_search_term()) async def process_search_term(self): @@ -1751,7 +1769,7 @@ def draw_refresh_icon(self): 500 if _uiscale is babase.UIScale.MEDIUM else 510) refresh_pos_y = (180 if _uiscale is babase.UIScale.SMALL else 108 if _uiscale is babase.UIScale.MEDIUM else 120) - loop = asyncio.get_event_loop() + loop = get_event_loop() controller_button = bui.buttonwidget(parent=self._root_widget, # autoselect=True, position=(refresh_pos_x, refresh_pos_y), @@ -1908,7 +1926,7 @@ def __init__(self, plugin_manager, origin_widget): self._plugin_manager = plugin_manager self.scale_origin = origin_widget.get_screen_space_center() self.settings = babase.app.config["Community Plugin Manager"]["Settings"].copy() - loop = asyncio.get_event_loop() + loop = get_event_loop() loop.create_task(self.draw_ui()) async def draw_ui(self): @@ -2028,7 +2046,7 @@ async def draw_ui(self): plugin_manager_update_available = False if plugin_manager_update_available: text_color = (0.75, 0.2, 0.2) - loop = asyncio.get_event_loop() + loop = get_event_loop() button_size = (95 * s, 32 * s) update_button_label = f'Update to v{plugin_manager_update_available[0]}' self._update_button = bui.buttonwidget(parent=self._root_widget, @@ -2483,5 +2501,5 @@ def on_app_running(self) -> None: DNSBlockWorkaround.apply() asyncio.set_event_loop(babase._asyncio._asyncio_event_loop) startup_tasks = StartupTasks() - loop = asyncio.get_event_loop() + loop = get_event_loop() loop.create_task(startup_tasks.execute()) From 6c9064e0a7e49768edcf58fc552e23761205c5a0 Mon Sep 17 00:00:00 2001 From: brostos <67740566+brostosjoined@users.noreply.github.com> Date: Tue, 3 Oct 2023 01:23:30 +0300 Subject: [PATCH 0714/1464] Update index.json --- index.json | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/index.json b/index.json index f913ecd7..528b34a3 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": { + "1.0.3": null, "1.0.2": { "api_version": 8, "commit_sha": "818ec65", @@ -122,4 +123,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 f3d874d3ecfdb0d03d5d5647b1d98526088778c0 Mon Sep 17 00:00:00 2001 From: brostosjoined Date: Mon, 2 Oct 2023 22:28:17 +0000 Subject: [PATCH 0715/1464] [ci] auto-format --- plugin_manager.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/plugin_manager.py b/plugin_manager.py index 923bf889..d0e08b12 100644 --- a/plugin_manager.py +++ b/plugin_manager.py @@ -44,6 +44,7 @@ } PLUGIN_DIRECTORY = _env["python_directory_user"] + def get_event_loop(): # loop = asyncio.ProactorEventLoop() if sys.platform == 'win32' else asyncio.new_event_loop() return ba._asyncio._asyncio_event_loop @@ -61,7 +62,8 @@ def get_event_loop(): # return running # else: # return loop - + + def _regexp_friendly_class_name_shortcut(string): return string.replace(".", "\\.") From b83bc9c05cdbeb5d2c4b6d4f1c5516876144e3cb Mon Sep 17 00:00:00 2001 From: brostosjoined Date: Mon, 2 Oct 2023 22:28:18 +0000 Subject: [PATCH 0716/1464] [ci] apply-version-metadata --- index.json | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/index.json b/index.json index 528b34a3..cc72565b 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": { - "1.0.3": null, + "1.0.3": { + "api_version": 8, + "commit_sha": "f3d874d", + "released_on": "02-10-2023", + "md5sum": "ab408d977dc7b88530d721d8cc19658d" + }, "1.0.2": { "api_version": 8, "commit_sha": "818ec65", @@ -123,4 +128,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 c90face51e72b82e231e2ae178dd007147000b96 Mon Sep 17 00:00:00 2001 From: brostos <67740566+brostosjoined@users.noreply.github.com> Date: Tue, 3 Oct 2023 10:50:14 +0300 Subject: [PATCH 0717/1464] Update --- plugin_manager.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugin_manager.py b/plugin_manager.py index d0e08b12..7e4a53a1 100644 --- a/plugin_manager.py +++ b/plugin_manager.py @@ -47,7 +47,7 @@ def get_event_loop(): # loop = asyncio.ProactorEventLoop() if sys.platform == 'win32' else asyncio.new_event_loop() - return ba._asyncio._asyncio_event_loop + return babase._asyncio._asyncio_event_loop # try: # running = asyncio.get_running_loop() # except RuntimeError: From 5c8606422316fa0c6174aae0560738f31f513e73 Mon Sep 17 00:00:00 2001 From: brostos <67740566+brostosjoined@users.noreply.github.com> Date: Tue, 3 Oct 2023 11:19:36 +0300 Subject: [PATCH 0718/1464] Update plugin_manager.py --- plugin_manager.py | 49 +++++++++++++++-------------------------------- 1 file changed, 15 insertions(+), 34 deletions(-) diff --git a/plugin_manager.py b/plugin_manager.py index 7e4a53a1..e614112a 100644 --- a/plugin_manager.py +++ b/plugin_manager.py @@ -43,26 +43,7 @@ "User-Agent": _env["legacy_user_agent_string"], } PLUGIN_DIRECTORY = _env["python_directory_user"] - - -def get_event_loop(): - # loop = asyncio.ProactorEventLoop() if sys.platform == 'win32' else asyncio.new_event_loop() - return babase._asyncio._asyncio_event_loop - # try: - # running = asyncio.get_running_loop() - # except RuntimeError: - # return loop - # if running.is_closed(): - # return loop - # else: - # if sys.platform in ('linux', 'darwin'): - # return running - # if sys.platform == 'win32': - # if isinstance(running, asyncio.ProactorEventLoop): - # return running - # else: - # return loop - +loop = babase._asyncio._asyncio_event_loop def _regexp_friendly_class_name_shortcut(string): return string.replace(".", "\\.") @@ -120,7 +101,7 @@ def send_network_request(request): async def async_send_network_request(request): - loop = get_event_loop() + response = await loop.run_in_executor(None, send_network_request, request) return response @@ -149,7 +130,7 @@ def stream_network_response_to_file(request, file, md5sum=None, retries=3): async def async_stream_network_response_to_file(request, file, md5sum=None, retries=3): - loop = get_event_loop() + content = await loop.run_in_executor( None, stream_network_response_to_file, @@ -557,7 +538,7 @@ async def get_content(self): if self._content is None: if not self.is_installed: raise PluginNotInstalled("Plugin is not available locally.") - loop = get_event_loop() + self._content = await loop.run_in_executor(None, self._get_content) return self._content @@ -689,7 +670,7 @@ def set_version(self, version): async def set_content(self, content): if not self._content: - loop = get_event_loop() + await loop.run_in_executor(None, self._set_content, content) self._content = content return self @@ -875,7 +856,7 @@ def __init__(self, plugin, origin_widget, button_callback=lambda: None): self.plugin = plugin self.button_callback = button_callback self.scale_origin = origin_widget.get_screen_space_center() - loop = get_event_loop() + loop.create_task(self.draw_ui()) def get_description(self, minimum_character_offset=40): @@ -1127,7 +1108,7 @@ async def asyncio_handler(fn, self, *args, **kwargs): def wrapper(self, *args, **kwargs): self._ok() - loop = get_event_loop() + if asyncio.iscoroutinefunction(fn): loop.create_task(asyncio_handler(fn, self, *args, **kwargs)) else: @@ -1389,7 +1370,7 @@ def __init__(self, origin_widget): # autoselect=True, description="Add Source") - loop = get_event_loop() + bui.buttonwidget(parent=self._root_widget, position=(330, 28), @@ -1495,7 +1476,7 @@ def _update_custom_sources_widget(self): on_activate_call=self.show_sources_window) def popup_menu_selected_choice(self, window, choice): - loop = get_event_loop() + loop.create_task(self._asyncio_callback(choice)) def popup_menu_closing(self, window): @@ -1517,7 +1498,7 @@ def __init__(self, transition: str = "in_right", origin_widget: bui.Widget = Non self.selected_category = None self.plugins_in_current_view = {} - loop = get_event_loop() + loop.create_task(self.draw_index()) self._width = (700 if _uiscale is babase.UIScale.SMALL @@ -1712,7 +1693,7 @@ def draw_search_bar(self): description=filter_txt) self._last_filter_text = None self._last_filter_plugins = [] - loop = get_event_loop() + loop.create_task(self.process_search_term()) async def process_search_term(self): @@ -1771,7 +1752,7 @@ def draw_refresh_icon(self): 500 if _uiscale is babase.UIScale.MEDIUM else 510) refresh_pos_y = (180 if _uiscale is babase.UIScale.SMALL else 108 if _uiscale is babase.UIScale.MEDIUM else 120) - loop = get_event_loop() + controller_button = bui.buttonwidget(parent=self._root_widget, # autoselect=True, position=(refresh_pos_x, refresh_pos_y), @@ -1928,7 +1909,7 @@ def __init__(self, plugin_manager, origin_widget): self._plugin_manager = plugin_manager self.scale_origin = origin_widget.get_screen_space_center() self.settings = babase.app.config["Community Plugin Manager"]["Settings"].copy() - loop = get_event_loop() + loop.create_task(self.draw_ui()) async def draw_ui(self): @@ -2048,7 +2029,7 @@ async def draw_ui(self): plugin_manager_update_available = False if plugin_manager_update_available: text_color = (0.75, 0.2, 0.2) - loop = get_event_loop() + button_size = (95 * s, 32 * s) update_button_label = f'Update to v{plugin_manager_update_available[0]}' self._update_button = bui.buttonwidget(parent=self._root_widget, @@ -2503,5 +2484,5 @@ def on_app_running(self) -> None: DNSBlockWorkaround.apply() asyncio.set_event_loop(babase._asyncio._asyncio_event_loop) startup_tasks = StartupTasks() - loop = get_event_loop() + loop.create_task(startup_tasks.execute()) From e57c5417624a2f9a6750bc569c0430a0a90e88e1 Mon Sep 17 00:00:00 2001 From: brostosjoined Date: Tue, 3 Oct 2023 08:20:09 +0000 Subject: [PATCH 0719/1464] [ci] auto-format --- plugin_manager.py | 28 +++++++++++++--------------- 1 file changed, 13 insertions(+), 15 deletions(-) diff --git a/plugin_manager.py b/plugin_manager.py index e614112a..b28dde05 100644 --- a/plugin_manager.py +++ b/plugin_manager.py @@ -45,6 +45,7 @@ PLUGIN_DIRECTORY = _env["python_directory_user"] loop = babase._asyncio._asyncio_event_loop + def _regexp_friendly_class_name_shortcut(string): return string.replace(".", "\\.") @@ -101,7 +102,7 @@ def send_network_request(request): async def async_send_network_request(request): - + response = await loop.run_in_executor(None, send_network_request, request) return response @@ -130,7 +131,7 @@ def stream_network_response_to_file(request, file, md5sum=None, retries=3): async def async_stream_network_response_to_file(request, file, md5sum=None, retries=3): - + content = await loop.run_in_executor( None, stream_network_response_to_file, @@ -538,7 +539,7 @@ async def get_content(self): if self._content is None: if not self.is_installed: raise PluginNotInstalled("Plugin is not available locally.") - + self._content = await loop.run_in_executor(None, self._get_content) return self._content @@ -670,7 +671,7 @@ def set_version(self, version): async def set_content(self, content): if not self._content: - + await loop.run_in_executor(None, self._set_content, content) self._content = content return self @@ -856,7 +857,7 @@ def __init__(self, plugin, origin_widget, button_callback=lambda: None): self.plugin = plugin self.button_callback = button_callback self.scale_origin = origin_widget.get_screen_space_center() - + loop.create_task(self.draw_ui()) def get_description(self, minimum_character_offset=40): @@ -1108,7 +1109,7 @@ async def asyncio_handler(fn, self, *args, **kwargs): def wrapper(self, *args, **kwargs): self._ok() - + if asyncio.iscoroutinefunction(fn): loop.create_task(asyncio_handler(fn, self, *args, **kwargs)) else: @@ -1370,8 +1371,6 @@ def __init__(self, origin_widget): # autoselect=True, description="Add Source") - - bui.buttonwidget(parent=self._root_widget, position=(330, 28), size=(37, 37), @@ -1476,7 +1475,7 @@ def _update_custom_sources_widget(self): on_activate_call=self.show_sources_window) def popup_menu_selected_choice(self, window, choice): - + loop.create_task(self._asyncio_callback(choice)) def popup_menu_closing(self, window): @@ -1498,7 +1497,6 @@ def __init__(self, transition: str = "in_right", origin_widget: bui.Widget = Non self.selected_category = None self.plugins_in_current_view = {} - loop.create_task(self.draw_index()) self._width = (700 if _uiscale is babase.UIScale.SMALL @@ -1693,7 +1691,7 @@ def draw_search_bar(self): description=filter_txt) self._last_filter_text = None self._last_filter_plugins = [] - + loop.create_task(self.process_search_term()) async def process_search_term(self): @@ -1752,7 +1750,7 @@ def draw_refresh_icon(self): 500 if _uiscale is babase.UIScale.MEDIUM else 510) refresh_pos_y = (180 if _uiscale is babase.UIScale.SMALL else 108 if _uiscale is babase.UIScale.MEDIUM else 120) - + controller_button = bui.buttonwidget(parent=self._root_widget, # autoselect=True, position=(refresh_pos_x, refresh_pos_y), @@ -1909,7 +1907,7 @@ def __init__(self, plugin_manager, origin_widget): self._plugin_manager = plugin_manager self.scale_origin = origin_widget.get_screen_space_center() self.settings = babase.app.config["Community Plugin Manager"]["Settings"].copy() - + loop.create_task(self.draw_ui()) async def draw_ui(self): @@ -2029,7 +2027,7 @@ async def draw_ui(self): plugin_manager_update_available = False if plugin_manager_update_available: text_color = (0.75, 0.2, 0.2) - + button_size = (95 * s, 32 * s) update_button_label = f'Update to v{plugin_manager_update_available[0]}' self._update_button = bui.buttonwidget(parent=self._root_widget, @@ -2484,5 +2482,5 @@ def on_app_running(self) -> None: DNSBlockWorkaround.apply() asyncio.set_event_loop(babase._asyncio._asyncio_event_loop) startup_tasks = StartupTasks() - + loop.create_task(startup_tasks.execute()) From 68360e77143b91608df5ec3f0286529a969ba35e Mon Sep 17 00:00:00 2001 From: brostos <67740566+brostosjoined@users.noreply.github.com> Date: Tue, 3 Oct 2023 12:08:21 +0300 Subject: [PATCH 0720/1464] Update plugin_manager.py --- plugin_manager.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/plugin_manager.py b/plugin_manager.py index b28dde05..840cd481 100644 --- a/plugin_manager.py +++ b/plugin_manager.py @@ -810,7 +810,7 @@ def latest_compatible_version(self): break if self._latest_compatible_version is None: raise NoCompatibleVersion( - f"{self.name} has no version compatible with API {babase.app.api_version}." + f"{self.name} has no version compatible with API {babase.app.api_version if build_number < 21282 else babase.app.env.api_version}." ) return self._latest_compatible_version @@ -2072,7 +2072,7 @@ async def draw_ui(self): size=(0, 0), h_align='center', v_align='center', - text=f'API Version: {babase.app.api_version}', + text=f'API Version: {babase.app.api_version if build_number < 21282 else babase.app.env.api_version}', scale=text_scale * 0.7, color=(0.4, 0.8, 1), maxwidth=width * 0.95) From dcf4545171eaf8af97cec43212c10b79814ba3a2 Mon Sep 17 00:00:00 2001 From: Rikko Date: Fri, 6 Oct 2023 18:51:49 +0530 Subject: [PATCH 0721/1464] Add 1.0.2 changelog entry --- CHANGELOG.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 7b9fd57c..fe2ca3c0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,9 @@ ## Plugin Manager (dd-mm-yyyy) +### 1.0.2 (01-10-2023) + +- Rename deprecated `babase.app.api_version` -> `babase.app.env.api_version`. + ### 1.0.1 (30-06-2023) - Allow specifying branch names in custom sources. From ce526371cb80830de391a724d44f6af60029ff1e Mon Sep 17 00:00:00 2001 From: Rikko Date: Fri, 6 Oct 2023 19:04:16 +0530 Subject: [PATCH 0722/1464] Add a test for plugin manager changelog entries --- CHANGELOG.md | 4 ++++ test/test_checks.py | 9 +++++++++ 2 files changed, 13 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index fe2ca3c0..3f0fa416 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -78,3 +78,7 @@ ### 0.1.5 (08-09-2022) - Plugin files that export classes besides plugin or game, now work. + +### 0.1.4 (05-09-2022) + +- First public release of plugin manager. 🎉 diff --git a/test/test_checks.py b/test/test_checks.py index 72225bca..2e0798e4 100644 --- a/test/test_checks.py +++ b/test/test_checks.py @@ -21,6 +21,7 @@ def setUp(self): self.plugin_manager_version_regexp = re.compile(b"(?<=PLUGIN_MANAGER_VERSION = )(.*)") self.current_path = pathlib.Path() + self.changelog = self.current_path / "CHANGELOG.md" self.repository = git.Repo() def test_keys(self): @@ -68,6 +69,14 @@ def test_latest_version(self): self.assertEqual(int(api_version.decode("utf-8")), latest_version_metadata["api_version"]) self.assertEqual(plugin_manager_version.decode("utf-8"), f'"{latest_version_name}"') + def test_changelog_entries(self): + versions = tuple(self.content["versions"].keys()) + with open(self.changelog, "r") as fin: + changelog = fin.read() + for version in versions: + changelog_version_header = f"## {version}" + if changelog_version_header not in changelog: + self.fail(f"Changelog entry for plugin manager {version} is missing.") class TestPluginMetadata(unittest.TestCase): def setUp(self): From 3464799b96dfb65c96a7e89bd5991257dc088c55 Mon Sep 17 00:00:00 2001 From: rikkolovescats Date: Fri, 6 Oct 2023 13:35:18 +0000 Subject: [PATCH 0723/1464] [ci] auto-format --- test/test_checks.py | 1 + 1 file changed, 1 insertion(+) diff --git a/test/test_checks.py b/test/test_checks.py index 2e0798e4..734a76fb 100644 --- a/test/test_checks.py +++ b/test/test_checks.py @@ -78,6 +78,7 @@ def test_changelog_entries(self): if changelog_version_header not in changelog: self.fail(f"Changelog entry for plugin manager {version} is missing.") + class TestPluginMetadata(unittest.TestCase): def setUp(self): self.category_directories = tuple( From b93d1ff2701217054f0172fdd9641b476baa1b2a Mon Sep 17 00:00:00 2001 From: Rikko Date: Fri, 6 Oct 2023 20:48:34 +0530 Subject: [PATCH 0724/1464] Improve error messages on common test failures --- test/test_checks.py | 41 +++++++++++++++++++++++++++++++++-------- 1 file changed, 33 insertions(+), 8 deletions(-) diff --git a/test/test_checks.py b/test/test_checks.py index 734a76fb..69a6a4ee 100644 --- a/test/test_checks.py +++ b/test/test_checks.py @@ -50,7 +50,12 @@ def test_versions(self): api_version = self.api_version_regexp.search(content).group() plugin_manager_version = self.plugin_manager_version_regexp.search(content).group() - self.assertEqual(md5sum, version_metadata["md5sum"]) + if md5sum != version_metadata["md5sum"]: + self.fail( + "Plugin manager MD5 checksum changed;\n" + f"{version_metadata['md5sum']} (mentioned in index.json) ->\n" + f"{md5sum} (actual)" + ) self.assertEqual(int(api_version.decode("utf-8")), version_metadata["api_version"]) self.assertEqual(plugin_manager_version.decode("utf-8"), f'"{version_name}"') @@ -65,7 +70,12 @@ def test_latest_version(self): api_version = self.api_version_regexp.search(content).group() plugin_manager_version = self.plugin_manager_version_regexp.search(content).group() - self.assertEqual(md5sum, latest_version_metadata["md5sum"]) + if md5sum != latest_version_metadata["md5sum"]: + self.fail( + "Plugin manager MD5 checksum changed;\n" + f"{latest_version_metadata['md5sum']} (mentioned in index.json) ->\n" + f"{md5sum} (actual)" + ) self.assertEqual(int(api_version.decode("utf-8")), latest_version_metadata["api_version"]) self.assertEqual(plugin_manager_version.decode("utf-8"), f'"{latest_version_name}"') @@ -137,14 +147,20 @@ def test_versions(self): for plugin_name, plugin_metadata in self.content["plugins"].items(): for version_name, version_metadata in plugin_metadata["versions"].items(): commit = self.repository.commit(version_metadata["commit_sha"]) - plugin = commit.tree / self.category / f"{plugin_name}.py" - with io.BytesIO(plugin.data_stream.read()) as fin: + plugin = os.path.join(self.category, f"{plugin_name}.py") + plugin_commit_sha = commit.tree / plugin + with io.BytesIO(plugin_commit_sha.data_stream.read()) as fin: content = fin.read() md5sum = hashlib.md5(content).hexdigest() api_version = self.api_version_regexp.search(content).group() - self.assertEqual(md5sum, version_metadata["md5sum"]) + if md5sum != version_metadata["md5sum"]: + self.fail( + f"{plugin} checksum changed;\n" + f"{version_metadata['md5sum']} (mentioned in {self.category_metadata_file}) ->\n" + f"{md5sum} (actual)" + ) self.assertEqual(int(api_version.decode("utf-8")), version_metadata["api_version"]) @@ -159,6 +175,12 @@ def test_latest_version(self): md5sum = hashlib.md5(content).hexdigest() api_version = self.api_version_regexp.search(content).group() + if md5sum != latest_version_metadata["md5sum"]: + self.fail( + f"{plugin} checksum changed;\n" + f"{latest_version_metadata['md5sum']} (mentioned in {self.category_metadata_file}) ->\n" + f"{md5sum} (actual)" + ) self.assertEqual(md5sum, latest_version_metadata["md5sum"]) self.assertEqual(int(api_version.decode("utf-8")), latest_version_metadata["api_version"]) @@ -169,7 +191,8 @@ def setUp(self): super().setUp() self.name = "Utilities" self.category = os.path.join("plugins", "utilities") - with open(f"{self.category}.json", "rb") as fin: + self.category_metadata_file = f"{self.category}.json" + with open(self.category_metadata_file, "rb") as fin: self.content = json.load(fin) @@ -178,7 +201,8 @@ def setUp(self): super().setUp() self.name = "Maps" self.category = os.path.join("plugins", "maps") - with open(f"{self.category}.json", "rb") as fin: + self.category_metadata_file = f"{self.category}.json" + with open(self.category_metadata_file, "rb") as fin: self.content = json.load(fin) @@ -187,5 +211,6 @@ def setUp(self): super().setUp() self.name = "Minigames" self.category = os.path.join("plugins", "minigames") - with open(f"{self.category}.json", "rb") as fin: + self.category_metadata_file = f"{self.category}.json" + with open(self.category_metadata_file, "rb") as fin: self.content = json.load(fin) From 2a5ce50834b81a1b0c3d68fa027e19676530b644 Mon Sep 17 00:00:00 2001 From: Rikko Date: Fri, 6 Oct 2023 22:16:07 +0530 Subject: [PATCH 0725/1464] Add a compatibility layer for older builds --- index.json | 9 ++------ plugin_manager.py | 52 +++++++++++++++++++++++++++++++++++++++-------- 2 files changed, 45 insertions(+), 16 deletions(-) diff --git a/index.json b/index.json index cc72565b..528b34a3 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": { - "1.0.3": { - "api_version": 8, - "commit_sha": "f3d874d", - "released_on": "02-10-2023", - "md5sum": "ab408d977dc7b88530d721d8cc19658d" - }, + "1.0.3": null, "1.0.2": { "api_version": 8, "commit_sha": "818ec65", @@ -128,4 +123,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 840cd481..a75b9fe2 100644 --- a/plugin_manager.py +++ b/plugin_manager.py @@ -1,6 +1,6 @@ # ba_meta require api 8 from babase._meta import EXPORT_CLASS_NAME_SHORTCUTS -from baenv import TARGET_BALLISTICA_BUILD as build_number +from baenv import TARGET_BALLISTICA_BUILD import babase import _babase import bauiv1 as bui @@ -29,15 +29,46 @@ from threading import Thread import logging -_env = _babase.env() -_uiscale = bui.app.ui_v1.uiscale - PLUGIN_MANAGER_VERSION = "1.0.3" 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" + + +if TARGET_BALLISTICA_BUILD < 21282: + # These attributes have been deprecated as of 1.7.27. For more info see: + # https://github.com/efroemling/ballistica/blob/master/CHANGELOG.md#1727-build-21282-api-8-2023-08-30 + # Adding a compatibility layer here so older builds still work fine. + class Dummy: + pass + + babase.app.env = Dummy() + + babase.app.env.build_number = babase.app.build_number + babase.app.env.device_name = babase.app.device_name + babase.app.env.config_file_path = babase.app.config_file_path + babase.app.env.version = babase.app.version + babase.app.env.debug_build = babase.app.debug_build + babase.app.env.test_build = babase.app.test_build + babase.app.env.data_directory = babase.app.data_directory + babase.app.env.python_directory_user = babase.app.python_directory_user + babase.app.env.python_directory_app = babase.app.python_directory_app + babase.app.env.python_directory_app_site = babase.app.python_directory_app_site + babase.app.env.api_version = babase.app.api_version + babase.app.env.on_tv = babase.app.on_tv + babase.app.env.vr_mode = babase.app.vr_mode + babase.app.env.toolbar_test = babase.app.toolbar_test + babase.app.env.arcade_mode = babase.app.arcade_mode + babase.app.env.headless_mode = babase.app.arcade_mode + babase.app.env.demo_mode = babase.app.demo_mode + babase.app.env.protocl_version = babase.app.protocol_version + + +_env = _babase.env() +_uiscale = bui.app.ui_v1.uiscale + INDEX_META = "{repository_url}/{content_type}/{tag}/index.json" HEADERS = { "User-Agent": _env["legacy_user_agent_string"], @@ -70,6 +101,7 @@ def _regexp_friendly_class_name_shortcut(string): return string.replace(".", "\\ } DISCORD_URL = "https://ballistica.net/discord" + _CACHE = {} @@ -102,7 +134,6 @@ def send_network_request(request): async def async_send_network_request(request): - response = await loop.run_in_executor(None, send_network_request, request) return response @@ -158,6 +189,9 @@ class DNSBlockWorkaround: Such as Jio, a pretty popular ISP in India has a DNS block on raw.githubusercontent.com (sigh..). + References: + * https://github.com/orgs/community/discussions/42655 + Usage: ----- >>> import urllib.request @@ -801,7 +835,7 @@ def latest_version(self): def latest_compatible_version(self): if self._latest_compatible_version is None: for number, info in self.info["versions"].items(): - if info["api_version"] == babase.app.api_version if build_number < 21282 else babase.app.env.api_version: + if info["api_version"] == babase.app.env.api_version: self._latest_compatible_version = PluginVersion( self, (number, info), @@ -810,7 +844,7 @@ def latest_compatible_version(self): break if self._latest_compatible_version is None: raise NoCompatibleVersion( - f"{self.name} has no version compatible with API {babase.app.api_version if build_number < 21282 else babase.app.env.api_version}." + f"{self.name} has no version compatible with API {babase.app.env.api_version}." ) return self._latest_compatible_version @@ -1235,7 +1269,7 @@ def unset_index_global_cache(self): async def get_update_details(self): index = await self.get_index() for version, info in index["versions"].items(): - if info["api_version"] != babase.app.api_version if build_number < 21282 else babase.app.env.api_version: + if info["api_version"] != babase.app.env.api_version: # No point checking a version of the API game doesn't support. continue if version == PLUGIN_MANAGER_VERSION: @@ -2072,7 +2106,7 @@ async def draw_ui(self): size=(0, 0), h_align='center', v_align='center', - text=f'API Version: {babase.app.api_version if build_number < 21282 else babase.app.env.api_version}', + text=f'API Version: {babase.app.env.api_version}', scale=text_scale * 0.7, color=(0.4, 0.8, 1), maxwidth=width * 0.95) From c50e986d413d8545a87a76b8d58b3fbc77065491 Mon Sep 17 00:00:00 2001 From: rikkolovescats Date: Fri, 6 Oct 2023 16:46:57 +0000 Subject: [PATCH 0726/1464] [ci] apply-version-metadata --- index.json | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/index.json b/index.json index 528b34a3..96d4945a 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": { - "1.0.3": null, + "1.0.3": { + "api_version": 8, + "commit_sha": "2a5ce50", + "released_on": "06-10-2023", + "md5sum": "d8e6267b2eae6fc21efd77bbb47c0a07" + }, "1.0.2": { "api_version": 8, "commit_sha": "818ec65", @@ -123,4 +128,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 1d629cdd40ae8d97185ac454d7029298dafbdfc5 Mon Sep 17 00:00:00 2001 From: Rikko Date: Fri, 6 Oct 2023 22:20:40 +0530 Subject: [PATCH 0727/1464] Add 1.0.3 changelog entry --- CHANGELOG.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 3f0fa416..771981de 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,9 @@ ## Plugin Manager (dd-mm-yyyy) +### 1.0.3 (06-10-2023) + +- Add a compatibility layer for older builds for API deprecation changes that occured in https://github.com/efroemling/ballistica/blob/master/CHANGELOG.md#1727-build-21282-api-8-2023-08-30 + ### 1.0.2 (01-10-2023) - Rename deprecated `babase.app.api_version` -> `babase.app.env.api_version`. From 5f2e315000fa45b7550052d3a780553cd9a817a2 Mon Sep 17 00:00:00 2001 From: brostos <67740566+brostosjoined@users.noreply.github.com> Date: Mon, 9 Oct 2023 08:52:29 +0300 Subject: [PATCH 0728/1464] Update supersmash.py --- plugins/minigames/supersmash.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/minigames/supersmash.py b/plugins/minigames/supersmash.py index 37363606..35838d65 100644 --- a/plugins/minigames/supersmash.py +++ b/plugins/minigames/supersmash.py @@ -78,7 +78,7 @@ def pow(self) -> None: self.explode() def handlemessage(self, m: Any) -> Any: - if isinstance(m, babase.PickedUpMessage): + if isinstance(m, bs.PickedUpMessage): self._heldBy = m.node elif isinstance(m, bs.DroppedMessage): bs.timer(0.6, self.pow) From 22db1a5fc9912b1fc78e463d47d50543efcd4b27 Mon Sep 17 00:00:00 2001 From: brostos <67740566+brostosjoined@users.noreply.github.com> Date: Mon, 9 Oct 2023 09:03:18 +0300 Subject: [PATCH 0729/1464] Update minigames.json --- plugins/minigames.json | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/plugins/minigames.json b/plugins/minigames.json index 1f982212..cc149a46 100644 --- a/plugins/minigames.json +++ b/plugins/minigames.json @@ -846,6 +846,7 @@ } ], "versions": { + "1.1.0: null "1.0.0": { "api_version": 8, "commit_sha": "68e77f2", @@ -855,4 +856,4 @@ } } } -} \ No newline at end of file +} From deb3848285645f8debbbf822d2b9c27494f745f5 Mon Sep 17 00:00:00 2001 From: brostos <67740566+brostosjoined@users.noreply.github.com> Date: Thu, 12 Oct 2023 17:06:57 +0300 Subject: [PATCH 0730/1464] Update minigames.json --- plugins/minigames.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/minigames.json b/plugins/minigames.json index cc149a46..a0b73f4f 100644 --- a/plugins/minigames.json +++ b/plugins/minigames.json @@ -846,7 +846,7 @@ } ], "versions": { - "1.1.0: null + "1.1.0": null "1.0.0": { "api_version": 8, "commit_sha": "68e77f2", From 6a668265057611cac4180763990edf37ba1fda98 Mon Sep 17 00:00:00 2001 From: brostos <67740566+brostosjoined@users.noreply.github.com> Date: Thu, 12 Oct 2023 17:10:10 +0300 Subject: [PATCH 0731/1464] Update minigames.json --- plugins/minigames.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/minigames.json b/plugins/minigames.json index a0b73f4f..23ddf38d 100644 --- a/plugins/minigames.json +++ b/plugins/minigames.json @@ -846,7 +846,7 @@ } ], "versions": { - "1.1.0": null + "1.1.0": null, "1.0.0": { "api_version": 8, "commit_sha": "68e77f2", From aa55c7a33622dcb73dab9e70c93db47822c04f7c Mon Sep 17 00:00:00 2001 From: brostosjoined Date: Thu, 12 Oct 2023 14:10:41 +0000 Subject: [PATCH 0732/1464] [ci] apply-version-metadata --- plugins/minigames.json | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/plugins/minigames.json b/plugins/minigames.json index 23ddf38d..e803bce3 100644 --- a/plugins/minigames.json +++ b/plugins/minigames.json @@ -846,7 +846,12 @@ } ], "versions": { - "1.1.0": null, + "1.1.0": { + "api_version": 8, + "commit_sha": "6a66826", + "released_on": "12-10-2023", + "md5sum": "f71b146868554b61b7b1fe3d393a5859" + }, "1.0.0": { "api_version": 8, "commit_sha": "68e77f2", @@ -856,4 +861,4 @@ } } } -} +} \ No newline at end of file From bc4780d46173c427b2e4299062a1e4f29171d7ff Mon Sep 17 00:00:00 2001 From: Ayush Saini <36878972+imayushsaini@users.noreply.github.com> Date: Sun, 12 Nov 2023 17:30:32 +0530 Subject: [PATCH 0733/1464] update apw --- plugins/utilities.json | 1 + plugins/utilities/advanced_party_window.py | 68 ++++++++++++---------- 2 files changed, 38 insertions(+), 31 deletions(-) diff --git a/plugins/utilities.json b/plugins/utilities.json index 4246bcc0..1bd77de6 100644 --- a/plugins/utilities.json +++ b/plugins/utilities.json @@ -415,6 +415,7 @@ } ], "versions": { + "2.0.2": null, "2.0.1": { "api_version": 8, "commit_sha": "d511c15", diff --git a/plugins/utilities/advanced_party_window.py b/plugins/utilities/advanced_party_window.py index f9db1b80..ab4009aa 100644 --- a/plugins/utilities/advanced_party_window.py +++ b/plugins/utilities/advanced_party_window.py @@ -76,8 +76,11 @@ def newconnect_to_party(address, port=43210, print_progress=False): global ip_add global p_port - + bs.chatmessage(" Joined IP "+ip_add+" PORT "+str(p_port)) dd = bs.get_connection_to_host_info() + if dd.get('name', '') != '': + title = dd['name'] + bs.chatmessage(title) if (dd != {}): bs.disconnect_from_host() @@ -356,7 +359,8 @@ def _getTransText(text, isBaLstr=False, same_fb=False): "unmutethisguy": "unmute this guy", "mutethisguy": "mute this guy", "muteall": "Mute all", - "unmuteall": "Unmute all" + "unmuteall": "Unmute all", + "copymsg":"copy" } } @@ -493,6 +497,7 @@ def __init__(self, origin: Sequence[float] = (0, 0)): color=(0.4, 0.6, 0.3)) self._columnwidget = bui.columnwidget(parent=self._scrollwidget, border=2, + left_border=-200, margin=0) bui.widget(edit=self._menu_button, down_widget=self._columnwidget) @@ -651,38 +656,49 @@ def on_chat_message(self, msg: str) -> None: if True: self._add_msg(msg) - def _on_chat_press(self, msg, widget): - global unmuted_names - if msg.split(":")[0] in unmuted_names: + def _copy_msg(self, msg: str) -> None: + if bui.clipboard_is_supported(): + bui.clipboard_set_text(msg) + bui.screenmessage( + bui.Lstr(resource='copyConfirmText'), + color=(0, 1, 0) + ) - choices = ['mute'] - choices_display = [_getTransText("mutethisguy", isBaLstr=True)] - else: - choices = ['unmute'] - choices_display = [_getTransText("unmutethisguy", isBaLstr=True)] + def _on_chat_press(self, msg, widget, showMute): + global unmuted_names + choices = ['copy'] + choices_display = [_getTransText("copymsg", isBaLstr=True)] + if showMute: + if msg.split(":")[0].encode('utf-8') in unmuted_names: + choices.append('mute') + choices_display.append(_getTransText("mutethisguy", isBaLstr=True)) + else: + choices.append('unmute') + choices_display.append(_getTransText("unmutethisguy", isBaLstr=True)) PopupMenuWindow(position=widget.get_screen_space_center(), scale=_get_popup_window_scale(), choices=choices, choices_display=choices_display, current_choice="@ this guy", delegate=self) - self.msg_user_selected = msg.split(":")[0] + self.msg_user_selected = msg self._popup_type = "chatmessagepress" # bs.chatmessage("pressed") def _add_msg(self, msg: str) -> None: try: - if babase.app.config.resolve('Chat Muted'): - + showMute = babase.app.config.resolve('Chat Muted') + if True: txt = bui.textwidget(parent=self._columnwidget, text=msg, h_align='left', v_align='center', - size=(130, 13), + size=(900, 13), scale=0.55, position=(-0.6, 0), selectable=True, + autoselect=True, click_activate=True, maxwidth=self._scroll_width * 0.94, shadow=0.3, @@ -690,20 +706,8 @@ def _add_msg(self, msg: str) -> None: bui.textwidget(edit=txt, on_activate_call=babase.Call( self._on_chat_press, - msg, txt)) - else: - txt = bui.textwidget(parent=self._columnwidget, - text=msg, - h_align='left', - v_align='center', - size=(0, 13), - scale=0.55, - - - - maxwidth=self._scroll_width * 0.94, - shadow=0.3, - flatness=1.0) + msg, txt, showMute)) + # btn = bui.buttonwidget(parent=self._columnwidget, # scale=0.7, @@ -720,6 +724,7 @@ def _add_msg(self, msg: str) -> None: except Exception: pass + def _add_msg_when_muted(self, msg: str) -> None: txt = bui.textwidget(parent=self._columnwidget, @@ -1421,10 +1426,11 @@ def popup_menu_selected_choice(self, popup_window: PopupMenuWindow, elif self._popup_type == "chatmessagepress": if choice == "mute": - - unmuted_names.remove(self.msg_user_selected) + unmuted_names.remove(self.msg_user_selected.split(":")[0].encode('utf-8')) if choice == "unmute": - unmuted_names.append(self.msg_user_selected) + unmuted_names.append(self.msg_user_selected.split(":")[0].encode('utf-8')) + if choice == "copy": + self._copy_msg(self.msg_user_selected) elif self._popup_type == "partyMemberPress": if choice == "kick": From 32e0f4505ebeed07e0f8f721b258397a398d4907 Mon Sep 17 00:00:00 2001 From: imayushsaini Date: Sun, 12 Nov 2023 12:01:30 +0000 Subject: [PATCH 0734/1464] [ci] auto-format --- plugins/utilities/advanced_party_window.py | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/plugins/utilities/advanced_party_window.py b/plugins/utilities/advanced_party_window.py index ab4009aa..a38d78a8 100644 --- a/plugins/utilities/advanced_party_window.py +++ b/plugins/utilities/advanced_party_window.py @@ -360,7 +360,7 @@ def _getTransText(text, isBaLstr=False, same_fb=False): "mutethisguy": "mute this guy", "muteall": "Mute all", "unmuteall": "Unmute all", - "copymsg":"copy" + "copymsg": "copy" } } @@ -707,7 +707,6 @@ def _add_msg(self, msg: str) -> None: on_activate_call=babase.Call( self._on_chat_press, msg, txt, showMute)) - # btn = bui.buttonwidget(parent=self._columnwidget, # scale=0.7, @@ -724,7 +723,6 @@ def _add_msg(self, msg: str) -> None: except Exception: pass - def _add_msg_when_muted(self, msg: str) -> None: txt = bui.textwidget(parent=self._columnwidget, From 913d0125cff25aca5ab784233ce013d404fd9d3f Mon Sep 17 00:00:00 2001 From: imayushsaini Date: Sun, 12 Nov 2023 12:01:31 +0000 Subject: [PATCH 0735/1464] [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 1bd77de6..c6d3501e 100644 --- a/plugins/utilities.json +++ b/plugins/utilities.json @@ -415,7 +415,12 @@ } ], "versions": { - "2.0.2": null, + "2.0.2": { + "api_version": 8, + "commit_sha": "32e0f45", + "released_on": "12-11-2023", + "md5sum": "a3c20dd470939ea7831df3e4e007f303" + }, "2.0.1": { "api_version": 8, "commit_sha": "d511c15", From 0b19b2b7dc27ef5ed3edb9c798225dbd5d1fb38b Mon Sep 17 00:00:00 2001 From: ! Freaku <92618708+Freaku17@users.noreply.github.com> Date: Fri, 8 Dec 2023 17:04:54 +0530 Subject: [PATCH 0736/1464] Fix file_share.py --- plugins/utilities/file_share.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/utilities/file_share.py b/plugins/utilities/file_share.py index 69200377..a7986ac8 100644 --- a/plugins/utilities/file_share.py +++ b/plugins/utilities/file_share.py @@ -33,7 +33,7 @@ app = _babase.app -MODS_DIR = app.python_directory_user +MODS_DIR = app.env.python_directory_user REPLAYS_DIR = bui.get_replays_dir() HEADERS = { 'accept': 'application/json', From af2ff1a431778f745e19a2719c89c192d73b0690 Mon Sep 17 00:00:00 2001 From: ! Freaku <92618708+Freaku17@users.noreply.github.com> Date: Fri, 8 Dec 2023 17:06:27 +0530 Subject: [PATCH 0737/1464] Update JSON file --- plugins/utilities.json | 1 + 1 file changed, 1 insertion(+) diff --git a/plugins/utilities.json b/plugins/utilities.json index c6d3501e..c7f5f53c 100644 --- a/plugins/utilities.json +++ b/plugins/utilities.json @@ -477,6 +477,7 @@ } ], "versions": { + "1.0.1": null, "1.0.0": { "api_version": 8, "commit_sha": "dbd41c4", From 9770913e8262ff023f40c35d4dd4a34fdbea34ca Mon Sep 17 00:00:00 2001 From: Freaku17 Date: Fri, 8 Dec 2023 11:38:44 +0000 Subject: [PATCH 0738/1464] [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 c7f5f53c..4783507c 100644 --- a/plugins/utilities.json +++ b/plugins/utilities.json @@ -477,7 +477,12 @@ } ], "versions": { - "1.0.1": null, + "1.0.1": { + "api_version": 8, + "commit_sha": "af2ff1a", + "released_on": "08-12-2023", + "md5sum": "b9188c0cbc9d6f8e0716a4f1cc408589" + }, "1.0.0": { "api_version": 8, "commit_sha": "dbd41c4", From 6ca93193d6ebcaac57058b2260de76161553f3ea Mon Sep 17 00:00:00 2001 From: Rikko Date: Fri, 8 Dec 2023 21:22:42 +0530 Subject: [PATCH 0739/1464] Fix a bug to set party icon to always visible in floater.py This change seems necessary to always show party icon on game launch as of 1.7.30. --- plugins/utilities.json | 3 ++- plugins/utilities/floater.py | 14 +++++++++----- 2 files changed, 11 insertions(+), 6 deletions(-) diff --git a/plugins/utilities.json b/plugins/utilities.json index c6d3501e..0f6a5546 100644 --- a/plugins/utilities.json +++ b/plugins/utilities.json @@ -347,6 +347,7 @@ } ], "versions": { + "2.0.1": null, "2.0.0": { "api_version": 8, "commit_sha": "48f9302", @@ -911,4 +912,4 @@ } } } -} \ No newline at end of file +} diff --git a/plugins/utilities/floater.py b/plugins/utilities/floater.py index 28e943ec..2f53b601 100644 --- a/plugins/utilities/floater.py +++ b/plugins/utilities/floater.py @@ -21,6 +21,7 @@ from bascenev1lib.actor.bomb import Bomb from bascenev1lib.actor.popuptext import PopupText from bauiv1lib.party import PartyWindow +import bauiv1lib.mainmenu if TYPE_CHECKING: from typing import Optional @@ -258,9 +259,6 @@ def dis(i, floater): i.assigninput(babase.InputType.LEFT_RIGHT, floater.leftright) -# Display chat icon, but if user open/close gather it may disappear -bui.set_party_icon_always_visible(True) - old_piv = bui.set_party_icon_always_visible @@ -287,8 +285,14 @@ def new_chat_message(*args, **kwargs): bs.chatmessage = new_chat_message -# ba_meta export plugin +class NewMainMenuWindow(bauiv1lib.mainmenu.MainMenuWindow): + def __init__(self, *args, **kwargs): + super().__init__(*args, **kwargs) + # Display chat icon, but if user open/close gather it may disappear + bui.set_party_icon_always_visible(True) +# ba_meta export plugin class byFreaku(babase.Plugin): - def __init__(self): pass + def on_app_running(self): + bauiv1lib.mainmenu.MainMenuWindow = NewMainMenuWindow From 1d45e69d0ef90722b76c0e5ec3bada2358fccb88 Mon Sep 17 00:00:00 2001 From: rikkolovescats Date: Fri, 8 Dec 2023 15:55:18 +0000 Subject: [PATCH 0740/1464] [ci] auto-format --- plugins/utilities/floater.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/utilities/floater.py b/plugins/utilities/floater.py index 2f53b601..0f0ec640 100644 --- a/plugins/utilities/floater.py +++ b/plugins/utilities/floater.py @@ -259,7 +259,6 @@ def dis(i, floater): i.assigninput(babase.InputType.LEFT_RIGHT, floater.leftright) - old_piv = bui.set_party_icon_always_visible @@ -285,6 +284,7 @@ def new_chat_message(*args, **kwargs): bs.chatmessage = new_chat_message + class NewMainMenuWindow(bauiv1lib.mainmenu.MainMenuWindow): def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) From 8cbf923c05deeec7ddca57cad7de0c45d0c99c0f Mon Sep 17 00:00:00 2001 From: rikkolovescats Date: Fri, 8 Dec 2023 15:55:20 +0000 Subject: [PATCH 0741/1464] [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 0f6a5546..53a3657a 100644 --- a/plugins/utilities.json +++ b/plugins/utilities.json @@ -347,7 +347,12 @@ } ], "versions": { - "2.0.1": null, + "2.0.1": { + "api_version": 8, + "commit_sha": "1d45e69", + "released_on": "08-12-2023", + "md5sum": "e5ca160fd0c847697fbf61d53462a7cd" + }, "2.0.0": { "api_version": 8, "commit_sha": "48f9302", @@ -912,4 +917,4 @@ } } } -} +} \ No newline at end of file From 08e9cee2d05e8ed3547f82ab5da252f83dc697dd Mon Sep 17 00:00:00 2001 From: ! Freaku <92618708+Freaku17@users.noreply.github.com> Date: Fri, 8 Dec 2023 21:28:33 +0530 Subject: [PATCH 0742/1464] Update file_share.py --- plugins/utilities/file_share.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/plugins/utilities/file_share.py b/plugins/utilities/file_share.py index a7986ac8..55f1f5e0 100644 --- a/plugins/utilities/file_share.py +++ b/plugins/utilities/file_share.py @@ -28,12 +28,14 @@ import logging from babase._general import Call from typing import TYPE_CHECKING +from baenv import TARGET_BALLISTICA_BUILD if TYPE_CHECKING: from typing import Any, Callable, Sequence app = _babase.app -MODS_DIR = app.env.python_directory_user + +MODS_DIR = app.python_directory_user if TARGET_BALLISTICA_BUILD < 21282 else app.env.python_directory_user REPLAYS_DIR = bui.get_replays_dir() HEADERS = { 'accept': 'application/json', From b08929395af2020b2aef963eb4eeb3aadc0ee830 Mon Sep 17 00:00:00 2001 From: ! Freaku <92618708+Freaku17@users.noreply.github.com> Date: Fri, 8 Dec 2023 21:30:02 +0530 Subject: [PATCH 0743/1464] Update utilities.json --- plugins/utilities.json | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/plugins/utilities.json b/plugins/utilities.json index 4783507c..0836af67 100644 --- a/plugins/utilities.json +++ b/plugins/utilities.json @@ -477,12 +477,7 @@ } ], "versions": { - "1.0.1": { - "api_version": 8, - "commit_sha": "af2ff1a", - "released_on": "08-12-2023", - "md5sum": "b9188c0cbc9d6f8e0716a4f1cc408589" - }, + "1.0.1": null, "1.0.0": { "api_version": 8, "commit_sha": "dbd41c4", @@ -917,4 +912,4 @@ } } } -} \ No newline at end of file +} From db99c82c0684772d7b84708f145e01dbf9033cdd Mon Sep 17 00:00:00 2001 From: Freaku17 Date: Fri, 8 Dec 2023 16:00:27 +0000 Subject: [PATCH 0744/1464] [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 0836af67..79829512 100644 --- a/plugins/utilities.json +++ b/plugins/utilities.json @@ -477,7 +477,12 @@ } ], "versions": { - "1.0.1": null, + "1.0.1": { + "api_version": 8, + "commit_sha": "b089293", + "released_on": "08-12-2023", + "md5sum": "d89537f6737829f3527b8ed32a1b12bf" + }, "1.0.0": { "api_version": 8, "commit_sha": "dbd41c4", @@ -912,4 +917,4 @@ } } } -} +} \ No newline at end of file From 1a764046c102c940228c55b050b23d4f3aa4622f Mon Sep 17 00:00:00 2001 From: ! Freaku <92618708+Freaku17@users.noreply.github.com> Date: Fri, 8 Dec 2023 21:46:14 +0530 Subject: [PATCH 0745/1464] Update plugin_manager Fixes warning in 1.7.30: `set_main_menu_window() should be passed a 'from_window' value to help ensure proper UI behavior` --- plugin_manager.py | 27 ++++++++++++++------------- 1 file changed, 14 insertions(+), 13 deletions(-) diff --git a/plugin_manager.py b/plugin_manager.py index a75b9fe2..080bae1b 100644 --- a/plugin_manager.py +++ b/plugin_manager.py @@ -1607,7 +1607,8 @@ def _back(self) -> None: bui.containerwidget(edit=self._root_widget, transition=self._transition_out) bui.app.ui_v1.set_main_menu_window( - AllSettingsWindow(transition='in_left').get_root_widget()) + AllSettingsWindow(transition='in_left').get_root_widget(), + from_window=self._root_widget,) @contextlib.contextmanager def exception_handler(self): @@ -2392,8 +2393,8 @@ def _do_back(self) -> None: ) assert bui.app.classic is not None bui.app.ui_v1.set_main_menu_window( - MainMenuWindow(transition='in_left').get_root_widget() - ) + MainMenuWindow(transition='in_left').get_root_widget(), + from_window=self._root_widget,) def _do_controllers(self) -> None: # pylint: disable=cyclic-import @@ -2405,8 +2406,8 @@ def _do_controllers(self) -> None: bui.app.ui_v1.set_main_menu_window( ControlsSettingsWindow( origin_widget=self._controllers_button - ).get_root_widget() - ) + ).get_root_widget(), + from_window=self._root_widget,) def _do_graphics(self) -> None: # pylint: disable=cyclic-import @@ -2418,8 +2419,8 @@ def _do_graphics(self) -> None: bui.app.ui_v1.set_main_menu_window( GraphicsSettingsWindow( origin_widget=self._graphics_button - ).get_root_widget() - ) + ).get_root_widget(), + from_window=self._root_widget,) def _do_audio(self) -> None: # pylint: disable=cyclic-import @@ -2431,8 +2432,8 @@ def _do_audio(self) -> None: bui.app.ui_v1.set_main_menu_window( AudioSettingsWindow( origin_widget=self._audio_button - ).get_root_widget() - ) + ).get_root_widget(), + from_window=self._root_widget,) def _do_advanced(self) -> None: # pylint: disable=cyclic-import @@ -2444,8 +2445,8 @@ def _do_advanced(self) -> None: bui.app.ui_v1.set_main_menu_window( AdvancedSettingsWindow( origin_widget=self._advanced_button - ).get_root_widget() - ) + ).get_root_widget(), + from_window=self._root_widget,) def _do_modmanager(self) -> None: self._save_state() @@ -2453,8 +2454,8 @@ def _do_modmanager(self) -> None: bui.app.ui_v1.set_main_menu_window( PluginManagerWindow( origin_widget=self._modmgr_button - ).get_root_widget() - ) + ).get_root_widget(), + from_window=self._root_widget,) def _save_state(self) -> None: try: From 8ce09ea0a339b8b4003460a74eb2999280b6af13 Mon Sep 17 00:00:00 2001 From: Rikko Date: Fri, 8 Dec 2023 22:26:29 +0530 Subject: [PATCH 0746/1464] Make sure filter widget exists when looking for filter text --- plugin_manager.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/plugin_manager.py b/plugin_manager.py index 080bae1b..3567f00c 100644 --- a/plugin_manager.py +++ b/plugin_manager.py @@ -1732,9 +1732,9 @@ def draw_search_bar(self): async def process_search_term(self): while True: await asyncio.sleep(0.2) - try: - filter_text = bui.textwidget(query=self._filter_widget) - except RuntimeError: + if self._filter_widget: + filter_text = bui.textwidget(parent=self._root_widget, query=self._filter_widget) + else: # Search filter widget got destroyed. No point checking for filter text anymore. return if self.selected_category is None: From 94abe80e3adbccfc47abc91d7d0b631852902722 Mon Sep 17 00:00:00 2001 From: Rikko Date: Fri, 8 Dec 2023 23:44:14 +0530 Subject: [PATCH 0747/1464] Fix a memory leak --- CHANGELOG.md | 5 +++++ index.json | 3 ++- plugin_manager.py | 18 ++++++++++-------- 3 files changed, 17 insertions(+), 9 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 771981de..4b2423f1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,10 @@ ## Plugin Manager (dd-mm-yyyy) +### 1.0.4 (08-12-2023) + +- Fix a few UI warnings related to 1.7.30. +- Fix a memory leak. + ### 1.0.3 (06-10-2023) - Add a compatibility layer for older builds for API deprecation changes that occured in https://github.com/efroemling/ballistica/blob/master/CHANGELOG.md#1727-build-21282-api-8-2023-08-30 diff --git a/index.json b/index.json index 96d4945a..b7b3b171 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": { + "1.0.4": null, "1.0.3": { "api_version": 8, "commit_sha": "2a5ce50", @@ -128,4 +129,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 3567f00c..119d01da 100644 --- a/plugin_manager.py +++ b/plugin_manager.py @@ -30,7 +30,7 @@ import logging -PLUGIN_MANAGER_VERSION = "1.0.3" +PLUGIN_MANAGER_VERSION = "1.0.4" 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. @@ -1604,6 +1604,7 @@ def __init__(self, transition: str = "in_right", origin_widget: bui.Widget = Non def _back(self) -> None: from bauiv1lib.settings.allsettings import AllSettingsWindow + del self._last_filter_plugins bui.containerwidget(edit=self._root_widget, transition=self._transition_out) bui.app.ui_v1.set_main_menu_window( @@ -1724,7 +1725,7 @@ def draw_search_bar(self): autoselect=True, maxwidth=search_bar_maxwidth, description=filter_txt) - self._last_filter_text = None + self._last_filter_text = "" self._last_filter_plugins = [] loop.create_task(self.process_search_term()) @@ -1732,11 +1733,10 @@ def draw_search_bar(self): async def process_search_term(self): while True: await asyncio.sleep(0.2) - if self._filter_widget: - filter_text = bui.textwidget(parent=self._root_widget, query=self._filter_widget) - else: + if not self._filter_widget: # Search filter widget got destroyed. No point checking for filter text anymore. return + filter_text = bui.textwidget(parent=self._root_widget, query=self._filter_widget) if self.selected_category is None: continue try: @@ -1835,8 +1835,10 @@ async def draw_plugin_names(self, category, search_term=""): raise CategoryDoesNotExist(f"{category} does not exist.") if search_term: - def search_term_filterer(plugin): return self.search_term_filterer(plugin, search_term) - plugins = filter(search_term_filterer, category_plugins) + plugins = filter( + lambda plugin: self.search_term_filterer(plugin, search_term), + category_plugins, + ) else: plugins = category_plugins @@ -1918,7 +1920,7 @@ def cleanup(self): for plugin in self._columnwidget.get_children(): plugin.delete() self.plugins_in_current_view.clear() - self._last_filter_text = None + self._last_filter_text = "" self._last_filter_plugins = [] async def refresh(self): From 1aa6484bbd820f5b99119f9073014cbadf986415 Mon Sep 17 00:00:00 2001 From: rikkolovescats Date: Fri, 8 Dec 2023 18:14:44 +0000 Subject: [PATCH 0748/1464] [ci] apply-version-metadata --- index.json | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/index.json b/index.json index b7b3b171..df80cfe4 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": { - "1.0.4": null, + "1.0.4": { + "api_version": 8, + "commit_sha": "94abe80", + "released_on": "08-12-2023", + "md5sum": "eae81ded9f9acee862c529ca6202cc72" + }, "1.0.3": { "api_version": 8, "commit_sha": "2a5ce50", @@ -129,4 +134,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 c0fadb1213c0ab790dfe7ed07e941936b5171334 Mon Sep 17 00:00:00 2001 From: ! Freaku <92618708+Freaku17@users.noreply.github.com> Date: Sat, 9 Dec 2023 00:54:50 +0530 Subject: [PATCH 0749/1464] Fix `character_maker` For 1.7.30+ --- plugins/utilities/character_maker.py | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/plugins/utilities/character_maker.py b/plugins/utilities/character_maker.py index 7a3e7ecd..d4679081 100644 --- a/plugins/utilities/character_maker.py +++ b/plugins/utilities/character_maker.py @@ -49,6 +49,7 @@ from bascenev1lib.actor.spazappearance import * from bascenev1lib.actor.text import Text from bascenev1lib.actor.image import Image +import bauiv1lib.mainmenu import os import copy @@ -747,12 +748,25 @@ def get_player(msg, activity): if client_id == player_client_id: return player + +old_piv = bui.set_party_icon_always_visible + +def new_piv(*args, **kwargs): + old_piv(True) + +bui.set_party_icon_always_visible = new_piv + +class NewMainMenuWindow(bauiv1lib.mainmenu.MainMenuWindow): + def __init__(self, *args, **kwargs): + super().__init__(*args, **kwargs) + bui.set_party_icon_always_visible(True) + # ba_meta export plugin class bySmoothy(babase.Plugin): def __init__(self): - bui.set_party_icon_always_visible(True) + bauiv1lib.mainmenu.MainMenuWindow = NewMainMenuWindow _babase.import_character = import_character _babase.export_character = export_character _babase.spaz_to_json = spaz_to_json From 430f279d71bebd8685efbed2513912799d448a6c Mon Sep 17 00:00:00 2001 From: ! Freaku <92618708+Freaku17@users.noreply.github.com> Date: Sat, 9 Dec 2023 00:55:10 +0530 Subject: [PATCH 0750/1464] Update JSON file --- plugins/utilities.json | 1 + 1 file changed, 1 insertion(+) diff --git a/plugins/utilities.json b/plugins/utilities.json index 15934f24..adb940c8 100644 --- a/plugins/utilities.json +++ b/plugins/utilities.json @@ -564,6 +564,7 @@ } ], "versions": { + "2.0.1": null, "2.0.0": { "api_version": 8, "commit_sha": "f7ae806", From f336f582164808247e37738fd1857bc954c98628 Mon Sep 17 00:00:00 2001 From: Freaku17 Date: Fri, 8 Dec 2023 19:26:26 +0000 Subject: [PATCH 0751/1464] [ci] auto-format --- plugins/utilities/character_maker.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/plugins/utilities/character_maker.py b/plugins/utilities/character_maker.py index d4679081..09f2a5e8 100644 --- a/plugins/utilities/character_maker.py +++ b/plugins/utilities/character_maker.py @@ -751,11 +751,14 @@ def get_player(msg, activity): old_piv = bui.set_party_icon_always_visible + def new_piv(*args, **kwargs): old_piv(True) + bui.set_party_icon_always_visible = new_piv + class NewMainMenuWindow(bauiv1lib.mainmenu.MainMenuWindow): def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) From 27a3dea518beef74a8264322653e986ad42bc0e4 Mon Sep 17 00:00:00 2001 From: Freaku17 Date: Fri, 8 Dec 2023 19:26:27 +0000 Subject: [PATCH 0752/1464] [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 adb940c8..aabdf17a 100644 --- a/plugins/utilities.json +++ b/plugins/utilities.json @@ -564,7 +564,12 @@ } ], "versions": { - "2.0.1": null, + "2.0.1": { + "api_version": 8, + "commit_sha": "f336f58", + "released_on": "08-12-2023", + "md5sum": "d449c87e4657d2bddcc9b25586d60368" + }, "2.0.0": { "api_version": 8, "commit_sha": "f7ae806", From 3820106ed7db7cd1cde679b1dccc34b04cab1a07 Mon Sep 17 00:00:00 2001 From: ! Freaku <92618708+Freaku17@users.noreply.github.com> Date: Sat, 9 Dec 2023 00:58:22 +0530 Subject: [PATCH 0753/1464] Fix oops --- plugins/utilities/character_maker.py | 4 ---- 1 file changed, 4 deletions(-) diff --git a/plugins/utilities/character_maker.py b/plugins/utilities/character_maker.py index 09f2a5e8..72d72771 100644 --- a/plugins/utilities/character_maker.py +++ b/plugins/utilities/character_maker.py @@ -159,7 +159,6 @@ def __init__(self, settings): super().__init__(settings) self.initialize_meshs() - bui.set_party_icon_always_visible(True) self._score_to_win = None self._dingsound = bs.getsound('dingSmall') self._epic_mode = bool(settings['Epic Mode']) @@ -751,14 +750,11 @@ def get_player(msg, activity): old_piv = bui.set_party_icon_always_visible - def new_piv(*args, **kwargs): old_piv(True) - bui.set_party_icon_always_visible = new_piv - class NewMainMenuWindow(bauiv1lib.mainmenu.MainMenuWindow): def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) From 2dfb7da81364a72b49fc9da3936a8dbab00b1d12 Mon Sep 17 00:00:00 2001 From: Freaku17 Date: Fri, 8 Dec 2023 19:28:45 +0000 Subject: [PATCH 0754/1464] [ci] auto-format --- plugins/utilities/character_maker.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/plugins/utilities/character_maker.py b/plugins/utilities/character_maker.py index 72d72771..d417a5b0 100644 --- a/plugins/utilities/character_maker.py +++ b/plugins/utilities/character_maker.py @@ -750,11 +750,14 @@ def get_player(msg, activity): old_piv = bui.set_party_icon_always_visible + def new_piv(*args, **kwargs): old_piv(True) + bui.set_party_icon_always_visible = new_piv + class NewMainMenuWindow(bauiv1lib.mainmenu.MainMenuWindow): def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) From a3a48c2ad1181cf0bcf42109f22a220201822398 Mon Sep 17 00:00:00 2001 From: ! Freaku <92618708+Freaku17@users.noreply.github.com> Date: Sat, 9 Dec 2023 00:58:51 +0530 Subject: [PATCH 0755/1464] Update JSON --- plugins/utilities.json | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/plugins/utilities.json b/plugins/utilities.json index aabdf17a..adb940c8 100644 --- a/plugins/utilities.json +++ b/plugins/utilities.json @@ -564,12 +564,7 @@ } ], "versions": { - "2.0.1": { - "api_version": 8, - "commit_sha": "f336f58", - "released_on": "08-12-2023", - "md5sum": "d449c87e4657d2bddcc9b25586d60368" - }, + "2.0.1": null, "2.0.0": { "api_version": 8, "commit_sha": "f7ae806", From 99ef984ef267feafb4d36a6a4070550b94cc4175 Mon Sep 17 00:00:00 2001 From: Freaku17 Date: Fri, 8 Dec 2023 19:29:11 +0000 Subject: [PATCH 0756/1464] [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 adb940c8..717c6605 100644 --- a/plugins/utilities.json +++ b/plugins/utilities.json @@ -564,7 +564,12 @@ } ], "versions": { - "2.0.1": null, + "2.0.1": { + "api_version": 8, + "commit_sha": "a3a48c2", + "released_on": "08-12-2023", + "md5sum": "0adc53345b1616a3356a9032cdfeb82f" + }, "2.0.0": { "api_version": 8, "commit_sha": "f7ae806", From d0d5d9fc8cad2bc4da70610a5880098295a12ecf Mon Sep 17 00:00:00 2001 From: ! Freaku <92618708+Freaku17@users.noreply.github.com> Date: Sat, 9 Dec 2023 01:44:39 +0530 Subject: [PATCH 0757/1464] Fix discord_rp --- plugins/utilities/discord_richpresence.py | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/plugins/utilities/discord_richpresence.py b/plugins/utilities/discord_richpresence.py index 5f3d378a..494e4308 100644 --- a/plugins/utilities/discord_richpresence.py +++ b/plugins/utilities/discord_richpresence.py @@ -27,6 +27,7 @@ import bascenev1 as bs import bascenev1lib import bauiv1 as bui +from baenv import TARGET_BALLISTICA_BUILD from typing import TYPE_CHECKING @@ -35,7 +36,8 @@ ANDROID = babase.app.classic.platform == "android" -DIRPATH = Path(f"{_babase.app.python_directory_user}/image_id.json") +DIRPATH = Path(f"{_babase.app.python_directory_user if TARGET_BALLISTICA_BUILD < 21282 else _babase.app.env.python_directory_user}/image_id.json") +APP_VERSION = _babase.app.version if TARGET_BALLISTICA_BUILD < 21282 else _babase.app.env.version if ANDROID: # !can add ios in future @@ -92,7 +94,7 @@ def __init__(self): self.large_image_text: str | None = "BombSquad Icon" self.small_image_key: str | None = None self.small_image_text: str | None = ( - f"{_babase.app.classic.platform.capitalize()}({_babase.app.version})") + f"{_babase.app.classic.platform.capitalize()}({APP_VERSION})") self.media_proxy = "mp:/app-assets/963434684669382696/{}.png" self.identify: bool = False self.party_id: str = str(uuid.uuid4()) @@ -872,7 +874,7 @@ def update_status(self) -> None: self.rpc_thread.large_image_text = "BombSquad" self.rpc_thread.small_image_key = _babase.app.classic.platform self.rpc_thread.small_image_text = ( - f"{_babase.app.classic.platform.capitalize()}({_babase.app.version})" + f"{_babase.app.classic.platform.capitalize()}({APP_VERSION})" ) connection_info = bs.get_connection_to_host_info() if not ANDROID: From d5d56ff15624ead9264b8ae27508901ec719a9ea Mon Sep 17 00:00:00 2001 From: ! Freaku <92618708+Freaku17@users.noreply.github.com> Date: Sat, 9 Dec 2023 01:46:21 +0530 Subject: [PATCH 0758/1464] Update utilities.json --- plugins/utilities.json | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/plugins/utilities.json b/plugins/utilities.json index 717c6605..f93efd9e 100644 --- a/plugins/utilities.json +++ b/plugins/utilities.json @@ -896,6 +896,7 @@ } ], "versions": { + "1.4.1": null, "1.4.0": { "api_version": 8, "commit_sha": "6947777", @@ -929,4 +930,4 @@ } } } -} \ No newline at end of file +} From 48c8abb555b1b4e5d651c8cc2a79c51bb9162a0f Mon Sep 17 00:00:00 2001 From: Freaku17 Date: Fri, 8 Dec 2023 20:18:09 +0000 Subject: [PATCH 0759/1464] [ci] auto-format --- plugins/utilities/discord_richpresence.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/plugins/utilities/discord_richpresence.py b/plugins/utilities/discord_richpresence.py index 494e4308..6e8bdb27 100644 --- a/plugins/utilities/discord_richpresence.py +++ b/plugins/utilities/discord_richpresence.py @@ -36,7 +36,8 @@ ANDROID = babase.app.classic.platform == "android" -DIRPATH = Path(f"{_babase.app.python_directory_user if TARGET_BALLISTICA_BUILD < 21282 else _babase.app.env.python_directory_user}/image_id.json") +DIRPATH = Path( + f"{_babase.app.python_directory_user if TARGET_BALLISTICA_BUILD < 21282 else _babase.app.env.python_directory_user}/image_id.json") APP_VERSION = _babase.app.version if TARGET_BALLISTICA_BUILD < 21282 else _babase.app.env.version if ANDROID: # !can add ios in future From b1114bdfa86cc730873ed5cb8b4d8b544e5ef8c9 Mon Sep 17 00:00:00 2001 From: Freaku17 Date: Fri, 8 Dec 2023 20:18:10 +0000 Subject: [PATCH 0760/1464] [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 f93efd9e..4d1acd4a 100644 --- a/plugins/utilities.json +++ b/plugins/utilities.json @@ -896,7 +896,12 @@ } ], "versions": { - "1.4.1": null, + "1.4.1": { + "api_version": 8, + "commit_sha": "48c8abb", + "released_on": "08-12-2023", + "md5sum": "087728c68fb9505b06beccc9ceb8acbf" + }, "1.4.0": { "api_version": 8, "commit_sha": "6947777", @@ -930,4 +935,4 @@ } } } -} +} \ No newline at end of file From 8d83d2e6508f5d049cb9cc62ffafcb796a679cd1 Mon Sep 17 00:00:00 2001 From: Cross Joy <87638792+CrossJoy@users.noreply.github.com> Date: Sat, 9 Dec 2023 23:22:43 +0800 Subject: [PATCH 0761/1464] Update and Fix practice_tools.py - Fix the bug where the ui is stuck if opened on the server side. - Fix a bug to set the party icon to always be visible for the newer bombsquad version. --- plugins/utilities/practice_tools.py | 33 ++++++++++++++++++++--------- 1 file changed, 23 insertions(+), 10 deletions(-) diff --git a/plugins/utilities/practice_tools.py b/plugins/utilities/practice_tools.py index 88dcc800..61ea61e0 100644 --- a/plugins/utilities/practice_tools.py +++ b/plugins/utilities/practice_tools.py @@ -1,4 +1,4 @@ -"""Practice Tools Mod: V2.0 +"""Practice Tools Mod: V2.1 Made by Cross Joy""" # If anyone who want to help me on giving suggestion/ fix bugs/ creating PR, @@ -12,6 +12,10 @@ # Support link: https://www.buymeacoffee.com/CrossJoy # ---------------------------------------------------------------------------- +# V2.1 update +# - Fix bug where the ui stuck if opened on server side. +# - Fix a bug to set party icon to always visible for newer bombsquad version. + # V2.0 update # - Updated to API 8 (1.7.20+) @@ -66,7 +70,7 @@ import bascenev1 as bs import bascenev1lib import bauiv1 as bui -import bauiv1lib as buil +from bauiv1lib import mainmenu from babase import app, Plugin from bascenev1lib.actor.powerupbox import PowerupBox from bascenev1lib.actor.spaz import Spaz @@ -90,7 +94,7 @@ if TYPE_CHECKING: from typing import Any, Sequence, Callable, Optional -version = '2.0' +version = '2.1' try: if babase.app.config.get("bombCountdown") is None: @@ -132,8 +136,6 @@ except: babase.app.config["invincible"] = False -bui.set_party_icon_always_visible(True) - class PartyWindow(bui.Window): _redefine_methods = ['__init__'] @@ -176,11 +178,16 @@ def main(plugin: Plugin) -> None: app.practice_tool = plugin redefine_class(OriginalPartyWindow, PartyWindow) +class NewMainMenuWindow(mainmenu.MainMenuWindow): + def __init__(self, *args, **kwargs): + super().__init__(*args, **kwargs) + # Display chat icon, but if user open/close gather it may disappear + bui.set_party_icon_always_visible(True) # ba_meta require api 8 # ba_meta export plugin class Practice(Plugin): - __version__ = '2.0' + __version__ = version def on_app_running(self) -> None: """Plugin start point.""" @@ -191,7 +198,7 @@ def on_app_running(self) -> None: color=(.8, .1, .1)) raise RuntimeError( 'sad') - + mainmenu.MainMenuWindow = NewMainMenuWindow return main(self) def new_bomb_init(func): @@ -527,8 +534,13 @@ def doTestButton(self): bui.screenmessage('Join any map to start using it.', color=(.8, .8, .1)) return - bui.containerwidget(edit=self._root_widget, transition='out_left') - bs.Call(PracticeWindow()) + activity = bs.get_foreground_host_activity() + if activity is not None: + bui.containerwidget(edit=self._root_widget, transition='out_left') + bs.Call(PracticeWindow()) + else: + bs.screenmessage('Only works on local games.', color=(.8, .8, .1)) + # --------------------------------------------------------------- @@ -550,7 +562,6 @@ def start_moving(self) -> None: ) def _update(self) -> None: - # Update one of our bot lists each time through. # First off, remove no-longer-existing bots from the list. try: @@ -588,6 +599,7 @@ def _update(self) -> None: bot.set_player_points(player_pts) bot.update_ai() + def clear(self) -> None: """Immediately clear out any bots in the set.""" # Don't do this if the activity is shutting down or dead. @@ -2334,3 +2346,4 @@ def _transition_out(self) -> None: def on_popup_cancel(self) -> None: bui.getsound('swish').play() self._transition_out() + From 836e91d6a37f4f8c9d41366e4df6082867173039 Mon Sep 17 00:00:00 2001 From: Cross Joy <87638792+CrossJoy@users.noreply.github.com> Date: Sat, 9 Dec 2023 23:29:18 +0800 Subject: [PATCH 0762/1464] Update utilities.json Update practice tools ver --- plugins/utilities.json | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/plugins/utilities.json b/plugins/utilities.json index 4d1acd4a..26524bce 100644 --- a/plugins/utilities.json +++ b/plugins/utilities.json @@ -248,6 +248,7 @@ } ], "versions": { + "2.1.0": null, "2.0.0": { "api_version": 8, "commit_sha": "0b55bc2", @@ -935,4 +936,4 @@ } } } -} \ No newline at end of file +} From 464eb7c645e4ad36c16c402d3f7802349f1876c2 Mon Sep 17 00:00:00 2001 From: CrossJoy Date: Sat, 9 Dec 2023 15:36:37 +0000 Subject: [PATCH 0763/1464] [ci] auto-format --- plugins/utilities/practice_tools.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/plugins/utilities/practice_tools.py b/plugins/utilities/practice_tools.py index 61ea61e0..e4e928b0 100644 --- a/plugins/utilities/practice_tools.py +++ b/plugins/utilities/practice_tools.py @@ -178,6 +178,7 @@ def main(plugin: Plugin) -> None: app.practice_tool = plugin redefine_class(OriginalPartyWindow, PartyWindow) + class NewMainMenuWindow(mainmenu.MainMenuWindow): def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) @@ -186,6 +187,8 @@ def __init__(self, *args, **kwargs): # ba_meta require api 8 # ba_meta export plugin + + class Practice(Plugin): __version__ = version @@ -542,7 +545,6 @@ def doTestButton(self): bs.screenmessage('Only works on local games.', color=(.8, .8, .1)) - # --------------------------------------------------------------- @@ -599,7 +601,6 @@ def _update(self) -> None: bot.set_player_points(player_pts) bot.update_ai() - def clear(self) -> None: """Immediately clear out any bots in the set.""" # Don't do this if the activity is shutting down or dead. @@ -2346,4 +2347,3 @@ def _transition_out(self) -> None: def on_popup_cancel(self) -> None: bui.getsound('swish').play() self._transition_out() - From 1412285dc9c3b3debe4d3d909254bad6c77230a9 Mon Sep 17 00:00:00 2001 From: CrossJoy Date: Sat, 9 Dec 2023 15:36:38 +0000 Subject: [PATCH 0764/1464] [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 26524bce..48ca8701 100644 --- a/plugins/utilities.json +++ b/plugins/utilities.json @@ -248,7 +248,12 @@ } ], "versions": { - "2.1.0": null, + "2.1.0": { + "api_version": 8, + "commit_sha": "464eb7c", + "released_on": "09-12-2023", + "md5sum": "517fec3938f31627c1cfd2126f1ee9da" + }, "2.0.0": { "api_version": 8, "commit_sha": "0b55bc2", @@ -936,4 +941,4 @@ } } } -} +} \ No newline at end of file From dcfe582ccf07cdffd4f2e50aed41c371d3215ae9 Mon Sep 17 00:00:00 2001 From: Cross Joy <87638792+CrossJoy@users.noreply.github.com> Date: Sun, 10 Dec 2023 01:21:38 +0800 Subject: [PATCH 0765/1464] Update utilities.json --- plugins/utilities.json | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/plugins/utilities.json b/plugins/utilities.json index 48ca8701..443de451 100644 --- a/plugins/utilities.json +++ b/plugins/utilities.json @@ -743,7 +743,7 @@ }, "practice_tools": { "description": "Powerful and comprehensive tools for practice purpose. Practice tabs can be access through party window.", - "external_url": "", + "external_url": "https://www.youtube.com/watch?v=7BeCcIYSXd0&t=113s&ab_channel=BOMBsquadlife", "authors": [ { "name": "Cross Joy", @@ -752,6 +752,7 @@ } ], "versions": { + "2.1.0": null, "2.0.1": { "api_version": 8, "commit_sha": "41cc38a", @@ -941,4 +942,4 @@ } } } -} \ No newline at end of file +} From 7da26018bcc51396eae61bc6a4a6f64381968272 Mon Sep 17 00:00:00 2001 From: CrossJoy Date: Sat, 9 Dec 2023 17:22:47 +0000 Subject: [PATCH 0766/1464] [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 443de451..2539aefd 100644 --- a/plugins/utilities.json +++ b/plugins/utilities.json @@ -752,7 +752,12 @@ } ], "versions": { - "2.1.0": null, + "2.1.0": { + "api_version": 8, + "commit_sha": "dcfe582", + "released_on": "09-12-2023", + "md5sum": "f2b5e4ff71c3952f57957ca3ab0c2e00" + }, "2.0.1": { "api_version": 8, "commit_sha": "41cc38a", @@ -942,4 +947,4 @@ } } } -} +} \ No newline at end of file From e417f4130c5b2ef8778ed41e2f0474cb65467506 Mon Sep 17 00:00:00 2001 From: ! Freaku <92618708+Freaku17@users.noreply.github.com> Date: Mon, 11 Dec 2023 21:17:22 +0530 Subject: [PATCH 0767/1464] Fix a unnoticed typo --- CHANGELOG.md | 4 ++++ index.json | 1 + plugin_manager.py | 2 +- 3 files changed, 6 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 4b2423f1..2ca4b872 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,9 @@ ## Plugin Manager (dd-mm-yyyy) +### 1.0.5 (11-12-2023) + +- Fix a typo. + ### 1.0.4 (08-12-2023) - Fix a few UI warnings related to 1.7.30. diff --git a/index.json b/index.json index df80cfe4..16e91308 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": { + "1.0.5": null, "1.0.4": { "api_version": 8, "commit_sha": "94abe80", diff --git a/plugin_manager.py b/plugin_manager.py index 119d01da..6478c32c 100644 --- a/plugin_manager.py +++ b/plugin_manager.py @@ -63,7 +63,7 @@ class Dummy: babase.app.env.arcade_mode = babase.app.arcade_mode babase.app.env.headless_mode = babase.app.arcade_mode babase.app.env.demo_mode = babase.app.demo_mode - babase.app.env.protocl_version = babase.app.protocol_version + babase.app.env.protocol_version = babase.app.protocol_version _env = _babase.env() From 30061db28dd104eb88ea942af4edf1a970f86816 Mon Sep 17 00:00:00 2001 From: Freaku17 Date: Mon, 11 Dec 2023 15:48:43 +0000 Subject: [PATCH 0768/1464] [ci] apply-version-metadata --- index.json | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/index.json b/index.json index 16e91308..a43348ce 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": { - "1.0.5": null, + "1.0.5": { + "api_version": 8, + "commit_sha": "e417f41", + "released_on": "11-12-2023", + "md5sum": "3a27fb8fd11bc59ae6f2f2655bb151f3" + }, "1.0.4": { "api_version": 8, "commit_sha": "94abe80", From cd1c858bbd82847dfef3f3eb758c60e04b3afb86 Mon Sep 17 00:00:00 2001 From: ! Freaku <92618708+Freaku17@users.noreply.github.com> Date: Mon, 11 Dec 2023 22:20:07 +0530 Subject: [PATCH 0769/1464] Fix oops --- index.json | 7 +------ plugin_manager.py | 2 +- 2 files changed, 2 insertions(+), 7 deletions(-) diff --git a/index.json b/index.json index a43348ce..16e91308 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": { - "1.0.5": { - "api_version": 8, - "commit_sha": "e417f41", - "released_on": "11-12-2023", - "md5sum": "3a27fb8fd11bc59ae6f2f2655bb151f3" - }, + "1.0.5": null, "1.0.4": { "api_version": 8, "commit_sha": "94abe80", diff --git a/plugin_manager.py b/plugin_manager.py index 6478c32c..92566a2b 100644 --- a/plugin_manager.py +++ b/plugin_manager.py @@ -30,7 +30,7 @@ import logging -PLUGIN_MANAGER_VERSION = "1.0.4" +PLUGIN_MANAGER_VERSION = "1.0.5" 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 3a37d10b50864fae3514c721f3dabf4aab5b3a9f Mon Sep 17 00:00:00 2001 From: Freaku17 Date: Mon, 11 Dec 2023 16:50:48 +0000 Subject: [PATCH 0770/1464] [ci] apply-version-metadata --- index.json | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/index.json b/index.json index 16e91308..ec93ec09 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": { - "1.0.5": null, + "1.0.5": { + "api_version": 8, + "commit_sha": "cd1c858", + "released_on": "11-12-2023", + "md5sum": "bbd7b03d0e16b088c0df842271dbf9cc" + }, "1.0.4": { "api_version": 8, "commit_sha": "94abe80", From 0577f22736be9f6146a1319dbbe7cdf94ad66a14 Mon Sep 17 00:00:00 2001 From: ! Freaku <92618708+Freaku17@users.noreply.github.com> Date: Sat, 16 Dec 2023 12:16:07 +0530 Subject: [PATCH 0771/1464] Update icons_keyboard.py MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit • Added ALL icons • Will automatically add new icons introduced in-game in future • Fixed errors; no characters present in `num` & `pages` list --- plugins/utilities/icons_keyboard.py | 57 +++++++++-------------------- 1 file changed, 18 insertions(+), 39 deletions(-) diff --git a/plugins/utilities/icons_keyboard.py b/plugins/utilities/icons_keyboard.py index 74476602..480d028d 100644 --- a/plugins/utilities/icons_keyboard.py +++ b/plugins/utilities/icons_keyboard.py @@ -4,54 +4,33 @@ # Make your chats look even more cooler! # Make sure "Always Use Internal Keyboard" is ON # Double tap the space to change between keyboards... +# Tap bottom-left bomb button to cycle through different icons -# ba_meta require api 8 -from __future__ import annotations -from typing import TYPE_CHECKING +# ba_meta require api 8 import babase -import bascenev1 as bs -from babase import charstr as uwu +from babase import charstr + +list_of_icons = [i for i in babase.SpecialChar] +list_of_icons = [charstr(i) for i in list_of_icons] +list_of_icons.reverse() -if TYPE_CHECKING: - from typing import Any, Optional, Dict, List, Tuple, Type, Iterable +for i in range(26 - (len(list_of_icons) % 26)): + list_of_icons.append('‎') # ba_meta export keyboard -class IconKeyboard_byFreaku(babase.Keyboard): +class IconKeyboard(babase.Keyboard): """Keyboard go brrrrrrr""" name = 'Icons by \ue048Freaku' - chars = [(uwu(babase.SpecialChar.TICKET), - uwu(babase.SpecialChar.CROWN), - uwu(babase.SpecialChar.DRAGON), - uwu(babase.SpecialChar.SKULL), - uwu(babase.SpecialChar.HEART), - uwu(babase.SpecialChar.FEDORA), - uwu(babase.SpecialChar.HAL), - uwu(babase.SpecialChar.YIN_YANG), - uwu(babase.SpecialChar.EYE_BALL), - uwu(babase.SpecialChar.HELMET), - uwu(babase.SpecialChar.OUYA_BUTTON_U)), - (uwu(babase.SpecialChar.MUSHROOM), - uwu(babase.SpecialChar.NINJA_STAR), - uwu(babase.SpecialChar.VIKING_HELMET), - uwu(babase.SpecialChar.MOON), - uwu(babase.SpecialChar.SPIDER), - uwu(babase.SpecialChar.FIREBALL), - uwu(babase.SpecialChar.MIKIROG), - uwu(babase.SpecialChar.OUYA_BUTTON_O), - uwu(babase.SpecialChar.LOCAL_ACCOUNT), - uwu(babase.SpecialChar.LOGO)), - (uwu(babase.SpecialChar.TICKET), - uwu(babase.SpecialChar.FLAG_INDIA), - uwu(babase.SpecialChar.OCULUS_LOGO), - uwu(babase.SpecialChar.STEAM_LOGO), - uwu(babase.SpecialChar.NVIDIA_LOGO), - uwu(babase.SpecialChar.GAME_CENTER_LOGO), - uwu(babase.SpecialChar.GOOGLE_PLAY_GAMES_LOGO), - uwu(babase.SpecialChar.EXPLODINARY_LOGO))] - nums = [] - pages: Dict[str, Tuple[str, ...]] = {} + chars = [(list_of_icons[0:10]), + (list_of_icons[10:19]), + (list_of_icons[19:26])] + nums = ['‎' for i in range(26)] + pages = { + f'icon{i//26+1}': tuple(list_of_icons[i:i+26]) + for i in range(26, len(list_of_icons), 26) + } \ No newline at end of file From e3927b265179502d9eeb17d3ad97ed81b5027e0e Mon Sep 17 00:00:00 2001 From: ! Freaku <92618708+Freaku17@users.noreply.github.com> Date: Sat, 16 Dec 2023 12:16:31 +0530 Subject: [PATCH 0772/1464] Update JSON file --- plugins/utilities.json | 1 + 1 file changed, 1 insertion(+) diff --git a/plugins/utilities.json b/plugins/utilities.json index 2539aefd..43930beb 100644 --- a/plugins/utilities.json +++ b/plugins/utilities.json @@ -607,6 +607,7 @@ } ], "versions": { + "3.0.0": null, "2.0.0": { "api_version": 8, "commit_sha": "48f9302", From 02da437aa47835f344f50eff456a6fbfc2f08876 Mon Sep 17 00:00:00 2001 From: Freaku17 Date: Sat, 16 Dec 2023 06:48:26 +0000 Subject: [PATCH 0773/1464] [ci] auto-format --- plugins/utilities/icons_keyboard.py | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/plugins/utilities/icons_keyboard.py b/plugins/utilities/icons_keyboard.py index 480d028d..1b697112 100644 --- a/plugins/utilities/icons_keyboard.py +++ b/plugins/utilities/icons_keyboard.py @@ -7,8 +7,6 @@ # Tap bottom-left bomb button to cycle through different icons - - # ba_meta require api 8 import babase @@ -27,10 +25,10 @@ class IconKeyboard(babase.Keyboard): """Keyboard go brrrrrrr""" name = 'Icons by \ue048Freaku' chars = [(list_of_icons[0:10]), - (list_of_icons[10:19]), - (list_of_icons[19:26])] + (list_of_icons[10:19]), + (list_of_icons[19:26])] nums = ['‎' for i in range(26)] pages = { f'icon{i//26+1}': tuple(list_of_icons[i:i+26]) for i in range(26, len(list_of_icons), 26) - } \ No newline at end of file + } From e083e8de85ba9fae76673a2624523860fabcb10b Mon Sep 17 00:00:00 2001 From: Freaku17 Date: Sat, 16 Dec 2023 06:48:28 +0000 Subject: [PATCH 0774/1464] [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 43930beb..323ebbb5 100644 --- a/plugins/utilities.json +++ b/plugins/utilities.json @@ -607,7 +607,12 @@ } ], "versions": { - "3.0.0": null, + "3.0.0": { + "api_version": 8, + "commit_sha": "02da437", + "released_on": "16-12-2023", + "md5sum": "ae221a7c2b938eccf63db493c247991e" + }, "2.0.0": { "api_version": 8, "commit_sha": "48f9302", From d938b0730d061f966b0097738d204cbb61e79e1c Mon Sep 17 00:00:00 2001 From: Loup-Garou911XD Date: Mon, 25 Dec 2023 19:30:43 +0530 Subject: [PATCH 0775/1464] Fixed menu theme --- plugins/utilities.json | 3 +- plugins/utilities/menu_theme.py | 68 +++++++++++++++++++++++++-------- 2 files changed, 54 insertions(+), 17 deletions(-) diff --git a/plugins/utilities.json b/plugins/utilities.json index 323ebbb5..e04925b0 100644 --- a/plugins/utilities.json +++ b/plugins/utilities.json @@ -895,6 +895,7 @@ } ], "versions": { + "1.0.1": null, "1.0.0": { "api_version": 8, "commit_sha": "f829aca", @@ -953,4 +954,4 @@ } } } -} \ No newline at end of file +} diff --git a/plugins/utilities/menu_theme.py b/plugins/utilities/menu_theme.py index 4a1163ea..67d53e04 100644 --- a/plugins/utilities/menu_theme.py +++ b/plugins/utilities/menu_theme.py @@ -23,6 +23,7 @@ from typing import List, Sequence, Callable, Any, cast +from baenv import TARGET_BALLISTICA_BUILD from bascenev1lib.mainmenu import MainMenuActivity, NewsDisplay, _preload1 from bauiv1lib.mainmenu import MainMenuWindow from bauiv1lib.account.settings import AccountSettingsWindow @@ -30,7 +31,10 @@ from bauiv1lib.fileselector import FileSelectorWindow from bauiv1lib.popup import PopupMenuWindow +import _bauiv1 as _bui +import _bascenev1 as _bs import _babase as _ba + import babase as ba import bascenev1 as bs import bauiv1 as bui @@ -44,7 +48,38 @@ # defined version and author __author__ = "Yann" -__version__ = "1.0.9" +__version__ = "1.0.10" + +if TARGET_BALLISTICA_BUILD < 21282: + # These attributes have been deprecated as of 1.7.27. For more info see: + # https://github.com/efroemling/ballistica/blob/master/CHANGELOG.md#1727-build-21282-api-8-2023-08-30 + # Adding a compatibility layer here so older builds still work fine. + class Dummy: + pass + babase = ba + babase.app.env = Dummy() + + babase.app.env.build_number = babase.app.build_number + babase.app.env.device_name = babase.app.device_name + babase.app.env.config_file_path = babase.app.config_file_path + babase.app.env.version = babase.app.version + babase.app.env.debug = babase.app.debug_build + babase.app.env.test = babase.app.test_build + babase.app.env.data_directory = babase.app.data_directory + babase.app.env.python_directory_user = babase.app.python_directory_user + babase.app.env.python_directory_app = babase.app.python_directory_app + babase.app.env.python_directory_app_site = babase.app.python_directory_app_site + babase.app.env.api_version = babase.app.api_version + babase.app.env.tv = babase.app.on_tv + babase.app.env.vr = babase.app.vr_mode + babase.app.env.arcade = babase.app.arcade_mode + babase.app.env.headless = babase.app.arcade_mode + babase.app.env.demo = babase.app.demo_mode + protocol_version = babase.app.protocol_version + toolbar_test = babase.app.toolbar_test +else: + protocol_version = _bs.protocol_version + toolbar_test = _bui.toolbar_test() # frequently used variables references config = bs.app.config @@ -1158,14 +1193,15 @@ def on_transition_in(self): bs.Activity.on_transition_in(self) random.seed(123) app = bs.app + env = ba.app.env assert app.classic is not None plus = bui.app.plus assert plus is not None - vr_mode = bs.app.vr_mode + vr_mode = env.vr - if not bs.app.toolbar_test: + if not toolbar_test: color = (1.0, 1.0, 1.0, 1.0) if vr_mode else (0.5, 0.6, 0.5, 0.6) scale = ( @@ -1213,19 +1249,19 @@ def on_transition_in(self): assert self.my_name.node bs.animate(self.my_name.node, 'opacity', {2.3: 0, 3.0: 1.0}) - vr_mode = app.vr_mode - uiscale = app.ui_v1.uiscale + vr_mode = env.vr + uiscale = bui.UIV1Subsystem.uiscale force_show_build_number = False - if not bs.app.toolbar_test: - if app.debug_build or app.test_build or force_show_build_number: - if app.debug_build: + if not toolbar_test: + if env.debug or env.test or force_show_build_number: + if env.debug: text = bs.Lstr( value='${V} (${B}) (${D})', subs=[ - ('${V}', app.version), - ('${B}', str(app.build_number)), + ('${V}', env.version), + ('${B}', str(env.build_number)), ('${D}', bs.Lstr(resource='debugText')), ], ) @@ -1233,12 +1269,12 @@ def on_transition_in(self): text = bs.Lstr( value='${V} (${B})', subs=[ - ('${V}', app.version), - ('${B}', str(app.build_number)), + ('${V}', env.version), + ('${B}', str(env.build_number)), ], ) else: - text = bs.Lstr(value='${V}', subs=[('${V}', app.version)]) + text = bs.Lstr(value='${V}', subs=[('${V}', env.version)]) scale = 0.9 if (uiscale is bs.UIScale.SMALL or vr_mode) else 0.7 color = (1, 1, 1, 1) if vr_mode else (0.5, 0.6, 0.5, 0.7) self.version = bs.NodeActor( @@ -1263,7 +1299,7 @@ def on_transition_in(self): bs.animate(self.version.node, 'opacity', {2.3: 0, 3.0: 1.0}) self.beta_info = self.beta_info_2 = None - if app.test_build and not (app.demo_mode or app.arcade_mode) and config['Menu Logo Text']: + if env.test and not (env.demo or env.arcade) and config['Menu Logo Text']: pos = (230, 35) self.beta_info = bs.NodeActor( bs.newnode( @@ -1316,7 +1352,7 @@ def on_transition_in(self): random.seed() - if not (app.demo_mode or app.arcade_mode) and not app.toolbar_test: + if not (env.demo or env.arcade) and not toolbar_test: self._news = NewsDisplay(self) with bs.ContextRef.empty(): @@ -1332,7 +1368,7 @@ def on_transition_in(self): # When coming back from a kiosk-mode game, jump to # the kiosk start screen. - if bs.app.demo_mode or bs.app.arcade_mode: + if env.demo or env.arcade: # pylint: disable=cyclic-import from bauiv1lib.kiosk import KioskWindow From c5e924f9e9b9ea4f3ac358f50780db2312318d89 Mon Sep 17 00:00:00 2001 From: Loup-Garou911XD Date: Mon, 25 Dec 2023 14:30:59 +0000 Subject: [PATCH 0776/1464] [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 e04925b0..64520ef4 100644 --- a/plugins/utilities.json +++ b/plugins/utilities.json @@ -895,7 +895,12 @@ } ], "versions": { - "1.0.1": null, + "1.0.1": { + "api_version": 8, + "commit_sha": "d938b07", + "released_on": "25-12-2023", + "md5sum": "26401c0480745cb0ebd5be7dfcf6fd2e" + }, "1.0.0": { "api_version": 8, "commit_sha": "f829aca", @@ -954,4 +959,4 @@ } } } -} +} \ No newline at end of file From 66bd5675d0df10f30d8d495d057adc4252b34472 Mon Sep 17 00:00:00 2001 From: Loup-Garou911XD Date: Mon, 25 Dec 2023 21:54:23 +0530 Subject: [PATCH 0777/1464] Fixed plugman throwing errors on older builds --- index.json | 3 +- plugin_manager.py | 150 +++++++++++++++++++++++++++++++++------------- 2 files changed, 109 insertions(+), 44 deletions(-) diff --git a/index.json b/index.json index ec93ec09..c7748c4d 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": { + "1.0.6": null, "1.0.5": { "api_version": 8, "commit_sha": "cd1c858", @@ -140,4 +141,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 92566a2b..81b836ce 100644 --- a/plugin_manager.py +++ b/plugin_manager.py @@ -4,6 +4,8 @@ import babase import _babase import bauiv1 as bui +import _bauiv1 as _bui +import _bascenev1 as _bs from bauiv1lib import popup, confirm import urllib.request @@ -30,7 +32,7 @@ import logging -PLUGIN_MANAGER_VERSION = "1.0.5" +PLUGIN_MANAGER_VERSION = "1.0.6" 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. @@ -50,20 +52,23 @@ class Dummy: babase.app.env.device_name = babase.app.device_name babase.app.env.config_file_path = babase.app.config_file_path babase.app.env.version = babase.app.version - babase.app.env.debug_build = babase.app.debug_build - babase.app.env.test_build = babase.app.test_build + babase.app.env.debug = babase.app.debug_build + babase.app.env.test = babase.app.test_build babase.app.env.data_directory = babase.app.data_directory babase.app.env.python_directory_user = babase.app.python_directory_user babase.app.env.python_directory_app = babase.app.python_directory_app babase.app.env.python_directory_app_site = babase.app.python_directory_app_site babase.app.env.api_version = babase.app.api_version - babase.app.env.on_tv = babase.app.on_tv - babase.app.env.vr_mode = babase.app.vr_mode - babase.app.env.toolbar_test = babase.app.toolbar_test - babase.app.env.arcade_mode = babase.app.arcade_mode - babase.app.env.headless_mode = babase.app.arcade_mode - babase.app.env.demo_mode = babase.app.demo_mode - babase.app.env.protocol_version = babase.app.protocol_version + babase.app.env.tv = babase.app.on_tv + babase.app.env.vr = babase.app.vr_mode + babase.app.env.arcade = babase.app.arcade_mode + babase.app.env.headless = babase.app.arcade_mode + babase.app.env.demo = babase.app.demo_mode + protocol_version = babase.app.protocol_version + toolbar_test = babase.app.toolbar_test +else: + protocol_version = _bs.protocol_version() + toolbar_test = _bui.toolbar_test() _env = _babase.env() @@ -1607,10 +1612,17 @@ def _back(self) -> None: del self._last_filter_plugins bui.containerwidget(edit=self._root_widget, transition=self._transition_out) - bui.app.ui_v1.set_main_menu_window( - AllSettingsWindow(transition='in_left').get_root_widget(), - from_window=self._root_widget,) - + if TARGET_BALLISTICA_BUILD < 21697: + # from_window parameter was added in 1.7.30, see changelogs below + # https://github.com/efroemling/ballistica/blob/master/CHANGELOG.md#1730-build-21697-api-8-2023-12-08 + # Adding a check here so older builds still work fine. + bui.app.ui_v1.set_main_menu_window( + AllSettingsWindow(transition='in_left').get_root_widget()) + else: + bui.app.ui_v1.set_main_menu_window( + AllSettingsWindow(transition='in_left').get_root_widget(), + from_window=self._root_widget,) + @contextlib.contextmanager def exception_handler(self): try: @@ -2394,9 +2406,16 @@ def _do_back(self) -> None: edit=self._root_widget, transition=self._transition_out ) assert bui.app.classic is not None - bui.app.ui_v1.set_main_menu_window( - MainMenuWindow(transition='in_left').get_root_widget(), - from_window=self._root_widget,) + if TARGET_BALLISTICA_BUILD < 21697: + # from_window parameter was added in 1.7.30, see changelogs below + # https://github.com/efroemling/ballistica/blob/master/CHANGELOG.md#1730-build-21697-api-8-2023-12-08 + # Adding a check here so older builds still work fine. + bui.app.ui_v1.set_main_menu_window( + MainMenuWindow(transition='in_left').get_root_widget(),) + else: + bui.app.ui_v1.set_main_menu_window( + MainMenuWindow(transition='in_left').get_root_widget(), + from_window=self._root_widget,) def _do_controllers(self) -> None: # pylint: disable=cyclic-import @@ -2405,12 +2424,21 @@ def _do_controllers(self) -> None: self._save_state() bui.containerwidget(edit=self._root_widget, transition='out_left') assert bui.app.classic is not None - bui.app.ui_v1.set_main_menu_window( - ControlsSettingsWindow( - origin_widget=self._controllers_button - ).get_root_widget(), - from_window=self._root_widget,) - + if TARGET_BALLISTICA_BUILD < 21697: + # from_window parameter was added in 1.7.30, see changelogs below + # https://github.com/efroemling/ballistica/blob/master/CHANGELOG.md#1730-build-21697-api-8-2023-12-08 + # Adding a check here so older builds still work fine. + bui.app.ui_v1.set_main_menu_window( + ControlsSettingsWindow( + origin_widget=self._controllers_button + ).get_root_widget(),) + else: + bui.app.ui_v1.set_main_menu_window( + ControlsSettingsWindow( + origin_widget=self._controllers_button + ).get_root_widget(), + from_window=self._root_widget,) + def _do_graphics(self) -> None: # pylint: disable=cyclic-import from bauiv1lib.settings.graphics import GraphicsSettingsWindow @@ -2418,11 +2446,20 @@ def _do_graphics(self) -> None: self._save_state() bui.containerwidget(edit=self._root_widget, transition='out_left') assert bui.app.classic is not None - bui.app.ui_v1.set_main_menu_window( - GraphicsSettingsWindow( - origin_widget=self._graphics_button - ).get_root_widget(), - from_window=self._root_widget,) + if TARGET_BALLISTICA_BUILD < 21697: + # from_window parameter was added in 1.7.30, see changelogs below + # https://github.com/efroemling/ballistica/blob/master/CHANGELOG.md#1730-build-21697-api-8-2023-12-08 + # Adding a check here so older builds still work fine. + bui.app.ui_v1.set_main_menu_window( + GraphicsSettingsWindow( + origin_widget=self._graphics_button + ).get_root_widget(),) + else: + bui.app.ui_v1.set_main_menu_window( + GraphicsSettingsWindow( + origin_widget=self._graphics_button + ).get_root_widget(), + from_window=self._root_widget,) def _do_audio(self) -> None: # pylint: disable=cyclic-import @@ -2431,11 +2468,20 @@ def _do_audio(self) -> None: self._save_state() bui.containerwidget(edit=self._root_widget, transition='out_left') assert bui.app.classic is not None - bui.app.ui_v1.set_main_menu_window( - AudioSettingsWindow( - origin_widget=self._audio_button - ).get_root_widget(), - from_window=self._root_widget,) + if TARGET_BALLISTICA_BUILD < 21697: + # from_window parameter was added in 1.7.30, see changelogs below + # https://github.com/efroemling/ballistica/blob/master/CHANGELOG.md#1730-build-21697-api-8-2023-12-08 + # Adding a check here so older builds still work fine. + bui.app.ui_v1.set_main_menu_window( + AudioSettingsWindow( + origin_widget=self._audio_button + ).get_root_widget(),) + else: + bui.app.ui_v1.set_main_menu_window( + AudioSettingsWindow( + origin_widget=self._audio_button + ).get_root_widget(), + from_window=self._root_widget,) def _do_advanced(self) -> None: # pylint: disable=cyclic-import @@ -2444,20 +2490,38 @@ def _do_advanced(self) -> None: self._save_state() bui.containerwidget(edit=self._root_widget, transition='out_left') assert bui.app.classic is not None - bui.app.ui_v1.set_main_menu_window( - AdvancedSettingsWindow( - origin_widget=self._advanced_button - ).get_root_widget(), - from_window=self._root_widget,) + if TARGET_BALLISTICA_BUILD < 21697: + # from_window parameter was added in 1.7.30, see changelogs below + # https://github.com/efroemling/ballistica/blob/master/CHANGELOG.md#1730-build-21697-api-8-2023-12-08 + # Adding a check here so older builds still work fine. + bui.app.ui_v1.set_main_menu_window( + AdvancedSettingsWindow( + origin_widget=self._advanced_button + ).get_root_widget()) + else: + bui.app.ui_v1.set_main_menu_window( + AdvancedSettingsWindow( + origin_widget=self._advanced_button + ).get_root_widget(), + from_window=self._root_widget,) def _do_modmanager(self) -> None: self._save_state() bui.containerwidget(edit=self._root_widget, transition="out_left") - bui.app.ui_v1.set_main_menu_window( - PluginManagerWindow( - origin_widget=self._modmgr_button - ).get_root_widget(), - from_window=self._root_widget,) + if TARGET_BALLISTICA_BUILD < 21697: + # from_window parameter was added in 1.7.30, see changelogs below + # https://github.com/efroemling/ballistica/blob/master/CHANGELOG.md#1730-build-21697-api-8-2023-12-08 + # Adding a check here so older builds still work fine. + bui.app.ui_v1.set_main_menu_window( + PluginManagerWindow( + origin_widget=self._modmgr_button + ).get_root_widget(),) + else: + bui.app.ui_v1.set_main_menu_window( + PluginManagerWindow( + origin_widget=self._modmgr_button + ).get_root_widget(), + from_window=self._root_widget,) def _save_state(self) -> None: try: From e5a0e9069d321e6647058eb5f73a3123c0f40d9c Mon Sep 17 00:00:00 2001 From: Loup-Garou911XD Date: Tue, 26 Dec 2023 09:33:21 +0000 Subject: [PATCH 0778/1464] [ci] auto-format --- plugin_manager.py | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/plugin_manager.py b/plugin_manager.py index 81b836ce..491304c1 100644 --- a/plugin_manager.py +++ b/plugin_manager.py @@ -1612,7 +1612,7 @@ def _back(self) -> None: del self._last_filter_plugins bui.containerwidget(edit=self._root_widget, transition=self._transition_out) - if TARGET_BALLISTICA_BUILD < 21697: + if TARGET_BALLISTICA_BUILD < 21697: # from_window parameter was added in 1.7.30, see changelogs below # https://github.com/efroemling/ballistica/blob/master/CHANGELOG.md#1730-build-21697-api-8-2023-12-08 # Adding a check here so older builds still work fine. @@ -1622,7 +1622,7 @@ def _back(self) -> None: bui.app.ui_v1.set_main_menu_window( AllSettingsWindow(transition='in_left').get_root_widget(), from_window=self._root_widget,) - + @contextlib.contextmanager def exception_handler(self): try: @@ -2406,7 +2406,7 @@ def _do_back(self) -> None: edit=self._root_widget, transition=self._transition_out ) assert bui.app.classic is not None - if TARGET_BALLISTICA_BUILD < 21697: + if TARGET_BALLISTICA_BUILD < 21697: # from_window parameter was added in 1.7.30, see changelogs below # https://github.com/efroemling/ballistica/blob/master/CHANGELOG.md#1730-build-21697-api-8-2023-12-08 # Adding a check here so older builds still work fine. @@ -2424,7 +2424,7 @@ def _do_controllers(self) -> None: self._save_state() bui.containerwidget(edit=self._root_widget, transition='out_left') assert bui.app.classic is not None - if TARGET_BALLISTICA_BUILD < 21697: + if TARGET_BALLISTICA_BUILD < 21697: # from_window parameter was added in 1.7.30, see changelogs below # https://github.com/efroemling/ballistica/blob/master/CHANGELOG.md#1730-build-21697-api-8-2023-12-08 # Adding a check here so older builds still work fine. @@ -2438,7 +2438,7 @@ def _do_controllers(self) -> None: origin_widget=self._controllers_button ).get_root_widget(), from_window=self._root_widget,) - + def _do_graphics(self) -> None: # pylint: disable=cyclic-import from bauiv1lib.settings.graphics import GraphicsSettingsWindow @@ -2446,7 +2446,7 @@ def _do_graphics(self) -> None: self._save_state() bui.containerwidget(edit=self._root_widget, transition='out_left') assert bui.app.classic is not None - if TARGET_BALLISTICA_BUILD < 21697: + if TARGET_BALLISTICA_BUILD < 21697: # from_window parameter was added in 1.7.30, see changelogs below # https://github.com/efroemling/ballistica/blob/master/CHANGELOG.md#1730-build-21697-api-8-2023-12-08 # Adding a check here so older builds still work fine. @@ -2468,7 +2468,7 @@ def _do_audio(self) -> None: self._save_state() bui.containerwidget(edit=self._root_widget, transition='out_left') assert bui.app.classic is not None - if TARGET_BALLISTICA_BUILD < 21697: + if TARGET_BALLISTICA_BUILD < 21697: # from_window parameter was added in 1.7.30, see changelogs below # https://github.com/efroemling/ballistica/blob/master/CHANGELOG.md#1730-build-21697-api-8-2023-12-08 # Adding a check here so older builds still work fine. @@ -2490,7 +2490,7 @@ def _do_advanced(self) -> None: self._save_state() bui.containerwidget(edit=self._root_widget, transition='out_left') assert bui.app.classic is not None - if TARGET_BALLISTICA_BUILD < 21697: + if TARGET_BALLISTICA_BUILD < 21697: # from_window parameter was added in 1.7.30, see changelogs below # https://github.com/efroemling/ballistica/blob/master/CHANGELOG.md#1730-build-21697-api-8-2023-12-08 # Adding a check here so older builds still work fine. @@ -2508,7 +2508,7 @@ def _do_advanced(self) -> None: def _do_modmanager(self) -> None: self._save_state() bui.containerwidget(edit=self._root_widget, transition="out_left") - if TARGET_BALLISTICA_BUILD < 21697: + if TARGET_BALLISTICA_BUILD < 21697: # from_window parameter was added in 1.7.30, see changelogs below # https://github.com/efroemling/ballistica/blob/master/CHANGELOG.md#1730-build-21697-api-8-2023-12-08 # Adding a check here so older builds still work fine. From 4abb455640634d62759706e2a434173b5f62c433 Mon Sep 17 00:00:00 2001 From: Loup-Garou911XD Date: Tue, 26 Dec 2023 09:33:23 +0000 Subject: [PATCH 0779/1464] [ci] apply-version-metadata --- index.json | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/index.json b/index.json index c7748c4d..656078ce 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": { - "1.0.6": null, + "1.0.6": { + "api_version": 8, + "commit_sha": "e5a0e90", + "released_on": "26-12-2023", + "md5sum": "39b379e6243d921313065fcf1f45e908" + }, "1.0.5": { "api_version": 8, "commit_sha": "cd1c858", @@ -141,4 +146,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 b412893a55fc6aacf98669adf53b2cb167b511be Mon Sep 17 00:00:00 2001 From: ! Freaku <92618708+Freaku17@users.noreply.github.com> Date: Tue, 26 Dec 2023 18:44:09 +0530 Subject: [PATCH 0780/1464] Help Loup --- plugins/utilities/menu_theme.py | 82 ++++++++++++++++++++++++++------- 1 file changed, 65 insertions(+), 17 deletions(-) diff --git a/plugins/utilities/menu_theme.py b/plugins/utilities/menu_theme.py index 67d53e04..d0a55aeb 100644 --- a/plugins/utilities/menu_theme.py +++ b/plugins/utilities/menu_theme.py @@ -1372,8 +1372,13 @@ def on_transition_in(self): # pylint: disable=cyclic-import from bauiv1lib.kiosk import KioskWindow - bs.app.ui_v1.set_main_menu_window( - KioskWindow().get_root_widget() + if TARGET_BALLISTICA_BUILD < 21697: + bs.app.ui_v1.set_main_menu_window( + KioskWindow().get_root_widget(), + ) + else: + bs.app.ui_v1.set_main_menu_window( + KioskWindow().get_root_widget(), from_window = self._root_widget ) # ..or in normal cases go back to the main menu else: @@ -1381,15 +1386,25 @@ def on_transition_in(self): # pylint: disable=cyclic-import from bauiv1lib.gather import GatherWindow - bs.app.ui_v1.set_main_menu_window( - GatherWindow(transition=None).get_root_widget() + if TARGET_BALLISTICA_BUILD < 21697: + bs.app.ui_v1.set_main_menu_window( + GatherWindow(transition=None).get_root_widget(), + ) + else: + bs.app.ui_v1.set_main_menu_window( + GatherWindow(transition=None).get_root_widget(), from_window=self._root_widget ) elif main_menu_location == 'Watch': # pylint: disable=cyclic-import from bauiv1lib.watch import WatchWindow - bs.app.ui_v1.set_main_menu_window( - WatchWindow(transition=None).get_root_widget() + if TARGET_BALLISTICA_BUILD < 21697: + bs.app.ui_v1.set_main_menu_window( + WatchWindow(transition=None).get_root_widget(), + ) + else: + bs.app.ui_v1.set_main_menu_window( + WatchWindow(transition=None).get_root_widget(), from_window=self._root_widget ) elif main_menu_location == 'Team Game Select': # pylint: disable=cyclic-import @@ -1397,10 +1412,17 @@ def on_transition_in(self): PlaylistBrowserWindow, ) - bs.app.ui_v1.set_main_menu_window( + if TARGET_BALLISTICA_BUILD < 21697: + bs.app.ui_v1.set_main_menu_window( + PlaylistBrowserWindow( + sessiontype=bs.DualTeamSession, transition=None + ).get_root_widget(), + ) + else: + bs.app.ui_v1.set_main_menu_window( PlaylistBrowserWindow( sessiontype=bs.DualTeamSession, transition=None - ).get_root_widget() + ).get_root_widget(), from_window=self._root_widget ) elif main_menu_location == 'Free-for-All Game Select': # pylint: disable=cyclic-import @@ -1408,32 +1430,55 @@ def on_transition_in(self): PlaylistBrowserWindow, ) - bs.app.ui_v1.set_main_menu_window( + if TARGET_BALLISTICA_BUILD < 21697: + bs.app.ui_v1.set_main_menu_window( + PlaylistBrowserWindow( + sessiontype=bs.FreeForAllSession, + transition=None, + ).get_root_widget(), + ) + else: + bs.app.ui_v1.set_main_menu_window( PlaylistBrowserWindow( sessiontype=bs.FreeForAllSession, transition=None, - ).get_root_widget() + ).get_root_widget(), from_window=self._root_widget ) elif main_menu_location == 'Coop Select': # pylint: disable=cyclic-import from bauiv1lib.coop.browser import CoopBrowserWindow - bs.app.ui_v1.set_main_menu_window( - CoopBrowserWindow(transition=None).get_root_widget() + if TARGET_BALLISTICA_BUILD < 21697: + bs.app.ui_v1.set_main_menu_window( + CoopBrowserWindow(transition=None).get_root_widget(), + ) + else: + bs.app.ui_v1.set_main_menu_window( + CoopBrowserWindow(transition=None).get_root_widget(), from_window=self._root_widget ) elif main_menu_location == 'Benchmarks & Stress Tests': # pylint: disable=cyclic-import from bauiv1lib.debug import DebugWindow - bs.app.ui_v1.set_main_menu_window( - DebugWindow(transition=None).get_root_widget() + if TARGET_BALLISTICA_BUILD < 21697: + bs.app.ui_v1.set_main_menu_window( + DebugWindow(transition=None).get_root_widget(), + ) + else: + bs.app.ui_v1.set_main_menu_window( + DebugWindow(transition=None).get_root_widget(), from_window=self._root_widget ) else: # pylint: disable=cyclic-import from bauiv1lib.mainmenu import MainMenuWindow - bs.app.ui_v1.set_main_menu_window( - MainMenuWindow(transition=None).get_root_widget() + if TARGET_BALLISTICA_BUILD < 21697: + bs.app.ui_v1.set_main_menu_window( + MainMenuWindow(transition=None).get_root_widget(), + ) + else: + bs.app.ui_v1.set_main_menu_window( + MainMenuWindow(transition=None).get_root_widget(), from_window=self._root_widget ) if not specialoffer.show_offer(): @@ -1986,7 +2031,10 @@ def new_back(self, save_state: bool = True): bui.containerwidget(edit=self._root_widget, transition=self._transition_out) main_menu_window = MainMenuWindow(transition='in_left').get_root_widget() - bui.app.ui_v1.set_main_menu_window(main_menu_window) + if TARGET_BALLISTICA_BUILD < 21697: + bui.app.ui_v1.set_main_menu_window(main_menu_window,) + else: + bui.app.ui_v1.set_main_menu_window(main_menu_window, from_window=self._root_widget) current_config = { "Menu Map": config["Menu Map"], From 6fe37cc90be29aa1b6bfb850aba212dff6c57e7c Mon Sep 17 00:00:00 2001 From: Freaku17 Date: Tue, 26 Dec 2023 13:14:31 +0000 Subject: [PATCH 0781/1464] [ci] auto-format --- plugins/utilities/menu_theme.py | 82 ++++++++++++++++----------------- 1 file changed, 41 insertions(+), 41 deletions(-) diff --git a/plugins/utilities/menu_theme.py b/plugins/utilities/menu_theme.py index d0a55aeb..2aa49a79 100644 --- a/plugins/utilities/menu_theme.py +++ b/plugins/utilities/menu_theme.py @@ -1375,11 +1375,11 @@ def on_transition_in(self): if TARGET_BALLISTICA_BUILD < 21697: bs.app.ui_v1.set_main_menu_window( KioskWindow().get_root_widget(), - ) + ) else: bs.app.ui_v1.set_main_menu_window( - KioskWindow().get_root_widget(), from_window = self._root_widget - ) + KioskWindow().get_root_widget(), from_window=self._root_widget + ) # ..or in normal cases go back to the main menu else: if main_menu_location == 'Gather': @@ -1388,24 +1388,24 @@ def on_transition_in(self): if TARGET_BALLISTICA_BUILD < 21697: bs.app.ui_v1.set_main_menu_window( - GatherWindow(transition=None).get_root_widget(), - ) + GatherWindow(transition=None).get_root_widget(), + ) else: bs.app.ui_v1.set_main_menu_window( - GatherWindow(transition=None).get_root_widget(), from_window=self._root_widget - ) + GatherWindow(transition=None).get_root_widget(), from_window=self._root_widget + ) elif main_menu_location == 'Watch': # pylint: disable=cyclic-import from bauiv1lib.watch import WatchWindow if TARGET_BALLISTICA_BUILD < 21697: bs.app.ui_v1.set_main_menu_window( - WatchWindow(transition=None).get_root_widget(), - ) + WatchWindow(transition=None).get_root_widget(), + ) else: bs.app.ui_v1.set_main_menu_window( - WatchWindow(transition=None).get_root_widget(), from_window=self._root_widget - ) + WatchWindow(transition=None).get_root_widget(), from_window=self._root_widget + ) elif main_menu_location == 'Team Game Select': # pylint: disable=cyclic-import from bauiv1lib.playlist.browser import ( @@ -1414,16 +1414,16 @@ def on_transition_in(self): if TARGET_BALLISTICA_BUILD < 21697: bs.app.ui_v1.set_main_menu_window( - PlaylistBrowserWindow( - sessiontype=bs.DualTeamSession, transition=None - ).get_root_widget(), - ) + PlaylistBrowserWindow( + sessiontype=bs.DualTeamSession, transition=None + ).get_root_widget(), + ) else: bs.app.ui_v1.set_main_menu_window( - PlaylistBrowserWindow( - sessiontype=bs.DualTeamSession, transition=None - ).get_root_widget(), from_window=self._root_widget - ) + PlaylistBrowserWindow( + sessiontype=bs.DualTeamSession, transition=None + ).get_root_widget(), from_window=self._root_widget + ) elif main_menu_location == 'Free-for-All Game Select': # pylint: disable=cyclic-import from bauiv1lib.playlist.browser import ( @@ -1432,54 +1432,54 @@ def on_transition_in(self): if TARGET_BALLISTICA_BUILD < 21697: bs.app.ui_v1.set_main_menu_window( - PlaylistBrowserWindow( - sessiontype=bs.FreeForAllSession, - transition=None, - ).get_root_widget(), - ) + PlaylistBrowserWindow( + sessiontype=bs.FreeForAllSession, + transition=None, + ).get_root_widget(), + ) else: bs.app.ui_v1.set_main_menu_window( - PlaylistBrowserWindow( - sessiontype=bs.FreeForAllSession, - transition=None, - ).get_root_widget(), from_window=self._root_widget - ) + PlaylistBrowserWindow( + sessiontype=bs.FreeForAllSession, + transition=None, + ).get_root_widget(), from_window=self._root_widget + ) elif main_menu_location == 'Coop Select': # pylint: disable=cyclic-import from bauiv1lib.coop.browser import CoopBrowserWindow if TARGET_BALLISTICA_BUILD < 21697: bs.app.ui_v1.set_main_menu_window( - CoopBrowserWindow(transition=None).get_root_widget(), - ) + CoopBrowserWindow(transition=None).get_root_widget(), + ) else: bs.app.ui_v1.set_main_menu_window( - CoopBrowserWindow(transition=None).get_root_widget(), from_window=self._root_widget - ) + CoopBrowserWindow(transition=None).get_root_widget(), from_window=self._root_widget + ) elif main_menu_location == 'Benchmarks & Stress Tests': # pylint: disable=cyclic-import from bauiv1lib.debug import DebugWindow if TARGET_BALLISTICA_BUILD < 21697: bs.app.ui_v1.set_main_menu_window( - DebugWindow(transition=None).get_root_widget(), - ) + DebugWindow(transition=None).get_root_widget(), + ) else: bs.app.ui_v1.set_main_menu_window( - DebugWindow(transition=None).get_root_widget(), from_window=self._root_widget - ) + DebugWindow(transition=None).get_root_widget(), from_window=self._root_widget + ) else: # pylint: disable=cyclic-import from bauiv1lib.mainmenu import MainMenuWindow if TARGET_BALLISTICA_BUILD < 21697: bs.app.ui_v1.set_main_menu_window( - MainMenuWindow(transition=None).get_root_widget(), - ) + MainMenuWindow(transition=None).get_root_widget(), + ) else: bs.app.ui_v1.set_main_menu_window( - MainMenuWindow(transition=None).get_root_widget(), from_window=self._root_widget - ) + MainMenuWindow(transition=None).get_root_widget(), from_window=self._root_widget + ) if not specialoffer.show_offer(): From d5ff78ca2aafcc7a0fc925e4a635bd577b6b4c34 Mon Sep 17 00:00:00 2001 From: ! Freaku <92618708+Freaku17@users.noreply.github.com> Date: Wed, 27 Dec 2023 23:08:40 +0530 Subject: [PATCH 0782/1464] Update icons_keyboard.py MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit • Add compatibility for new/old versions --- plugins/utilities/icons_keyboard.py | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/plugins/utilities/icons_keyboard.py b/plugins/utilities/icons_keyboard.py index 1b697112..cd27eaf0 100644 --- a/plugins/utilities/icons_keyboard.py +++ b/plugins/utilities/icons_keyboard.py @@ -9,6 +9,7 @@ # ba_meta require api 8 +import bauiv1 import babase from babase import charstr @@ -20,8 +21,7 @@ list_of_icons.append('‎') -# ba_meta export keyboard -class IconKeyboard(babase.Keyboard): +class IconKeyboard(babase.Keyboard if hasattr(babase, 'Keyboard') else bauiv1.Keyboard): """Keyboard go brrrrrrr""" name = 'Icons by \ue048Freaku' chars = [(list_of_icons[0:10]), @@ -32,3 +32,9 @@ class IconKeyboard(babase.Keyboard): f'icon{i//26+1}': tuple(list_of_icons[i:i+26]) for i in range(26, len(list_of_icons), 26) } + + +# ba_meta export plugin +class byFreaku(babase.Plugin): + def __init__(self): + babase.app.meta.scanresults.exports['babase.Keyboard' if hasattr(babase, 'Keyboard') else 'bauiv1.Keyboard'].append(__name__+'.IconKeyboard') From a43a79c7377e11a5c14c24ddf7b0b0941778a031 Mon Sep 17 00:00:00 2001 From: ! Freaku <92618708+Freaku17@users.noreply.github.com> Date: Wed, 27 Dec 2023 23:08:56 +0530 Subject: [PATCH 0783/1464] Update JSON --- plugins/utilities.json | 1 + 1 file changed, 1 insertion(+) diff --git a/plugins/utilities.json b/plugins/utilities.json index 323ebbb5..76fe5bb5 100644 --- a/plugins/utilities.json +++ b/plugins/utilities.json @@ -607,6 +607,7 @@ } ], "versions": { + "3.0.1": null, "3.0.0": { "api_version": 8, "commit_sha": "02da437", From 78f3c44d16df9cb92cdf5740225b899b3fa97300 Mon Sep 17 00:00:00 2001 From: Freaku17 Date: Wed, 27 Dec 2023 17:40:26 +0000 Subject: [PATCH 0784/1464] [ci] auto-format --- plugins/utilities/icons_keyboard.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/plugins/utilities/icons_keyboard.py b/plugins/utilities/icons_keyboard.py index cd27eaf0..ff29a503 100644 --- a/plugins/utilities/icons_keyboard.py +++ b/plugins/utilities/icons_keyboard.py @@ -37,4 +37,5 @@ class IconKeyboard(babase.Keyboard if hasattr(babase, 'Keyboard') else bauiv1.Ke # ba_meta export plugin class byFreaku(babase.Plugin): def __init__(self): - babase.app.meta.scanresults.exports['babase.Keyboard' if hasattr(babase, 'Keyboard') else 'bauiv1.Keyboard'].append(__name__+'.IconKeyboard') + babase.app.meta.scanresults.exports['babase.Keyboard' if hasattr( + babase, 'Keyboard') else 'bauiv1.Keyboard'].append(__name__+'.IconKeyboard') From d31222db3441b98c7cb7fa19698bec28594f70fc Mon Sep 17 00:00:00 2001 From: Freaku17 Date: Wed, 27 Dec 2023 17:40:28 +0000 Subject: [PATCH 0785/1464] [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 76fe5bb5..8ca8c3d7 100644 --- a/plugins/utilities.json +++ b/plugins/utilities.json @@ -607,7 +607,12 @@ } ], "versions": { - "3.0.1": null, + "3.0.1": { + "api_version": 8, + "commit_sha": "78f3c44", + "released_on": "27-12-2023", + "md5sum": "b7756605a4bc382329c078c4e399b96b" + }, "3.0.0": { "api_version": 8, "commit_sha": "02da437", From 0eaa5e9305a8ff61d067c79045c9336d2fd17772 Mon Sep 17 00:00:00 2001 From: ! Freaku <92618708+Freaku17@users.noreply.github.com> Date: Wed, 27 Dec 2023 23:17:15 +0530 Subject: [PATCH 0786/1464] Add missing CHANGELOG --- CHANGELOG.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 2ca4b872..10b52cce 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,9 @@ ## Plugin Manager (dd-mm-yyyy) +### 1.0.6 (26-12-2023) + +- Fixed plugin manager throwing errors on older builds + ### 1.0.5 (11-12-2023) - Fix a typo. From 72e3c714e1c0342176b895c51b299cf2d2ec7ac9 Mon Sep 17 00:00:00 2001 From: ! Freaku <92618708+Freaku17@users.noreply.github.com> Date: Fri, 29 Dec 2023 17:04:31 +0530 Subject: [PATCH 0787/1464] Fix warnings in menu_theme --- plugins/utilities/menu_theme.py | 2060 +++++++++++++++++++++++++++++++ 1 file changed, 2060 insertions(+) diff --git a/plugins/utilities/menu_theme.py b/plugins/utilities/menu_theme.py index 2aa49a79..747d3105 100644 --- a/plugins/utilities/menu_theme.py +++ b/plugins/utilities/menu_theme.py @@ -2056,6 +2056,2065 @@ def new_back(self, save_state: bool = True): break +# ba_meta export plugin +# ba_meta require api 8 +""" +Working for v1.7.20+ only +——————————————————————————————————————— +• Menu Theme v1.0.9 +• discord: riyukiiyan + +I appreciate any kind of modification. So feel free to share, edit and change credit string... no problem +Credits are unnecessary but are a much-appreciated gesture to show support to others :D + +[CHANGELOG]: +~ Support for BombSquad v1.7.26 +~ Fixed "Show Logo Text" checkmark not updating on imports and reset +~ Music changes: + >> Turn off music by selecting 'None' + >> Removed dupes, renamed some and added 2 new musics + +Special thanks to: +snowee, rikko, & unknown +——————————————————————————————————————— +""" +from __future__ import annotations + +from typing import List, Sequence, Callable, Any, cast + +from baenv import TARGET_BALLISTICA_BUILD +from bascenev1lib.mainmenu import MainMenuActivity, NewsDisplay, _preload1 +from bauiv1lib.mainmenu import MainMenuWindow +from bauiv1lib.account.settings import AccountSettingsWindow +from bauiv1lib.colorpicker import ColorPicker, ColorPickerExact +from bauiv1lib.fileselector import FileSelectorWindow +from bauiv1lib.popup import PopupMenuWindow + +import _bauiv1 as _bui +import _bascenev1 as _bs +import _babase as _ba + +import babase as ba +import bascenev1 as bs +import bauiv1 as bui +import bascenev1lib.mainmenu as menu +import json +import os +import shutil +import random +import weakref + + +# defined version and author +__author__ = "Yann" +__version__ = "1.0.10" + +if TARGET_BALLISTICA_BUILD < 21282: + # These attributes have been deprecated as of 1.7.27. For more info see: + # https://github.com/efroemling/ballistica/blob/master/CHANGELOG.md#1727-build-21282-api-8-2023-08-30 + # Adding a compatibility layer here so older builds still work fine. + class Dummy: + pass + babase = ba + babase.app.env = Dummy() + + babase.app.env.build_number = babase.app.build_number + babase.app.env.device_name = babase.app.device_name + babase.app.env.config_file_path = babase.app.config_file_path + babase.app.env.version = babase.app.version + babase.app.env.debug = babase.app.debug_build + babase.app.env.test = babase.app.test_build + babase.app.env.data_directory = babase.app.data_directory + babase.app.env.python_directory_user = babase.app.python_directory_user + babase.app.env.python_directory_app = babase.app.python_directory_app + babase.app.env.python_directory_app_site = babase.app.python_directory_app_site + babase.app.env.api_version = babase.app.api_version + babase.app.env.tv = babase.app.on_tv + babase.app.env.vr = babase.app.vr_mode + babase.app.env.arcade = babase.app.arcade_mode + babase.app.env.headless = babase.app.arcade_mode + babase.app.env.demo = babase.app.demo_mode + protocol_version = babase.app.protocol_version + toolbar_test = babase.app.toolbar_test +else: + protocol_version = _bs.protocol_version + toolbar_test = _bui.toolbar_test() + +# frequently used variables references +config = bs.app.config +ui_type = bs.app.ui_v1.uiscale +ui_small = bs.UIScale.SMALL +ui_medium = bs.UIScale.MEDIUM +ui_large = bs.UIScale.LARGE + +# method references +original_unlocked_pro = bs.app.classic.accounts.have_pro +original_account_init = AccountSettingsWindow.__init__ + +# define globals +GLOBALS_REFLECTION = { + 'Powerup': 'powerup', + 'Character': 'char', + 'Soft': 'soft', + 'None': 'none' +} +GLOBALS_MUSIC = { + 'Menu': bs.MusicType.MENU, + 'Epic': bs.MusicType.EPIC, + 'Flag Catcher': bs.MusicType.FLAG_CATCHER, + 'Flying': bs.MusicType.FLYING, + 'Grand Romp': bs.MusicType.GRAND_ROMP, + 'Lobby': bs.MusicType.CHAR_SELECT, + 'Lobby Epic': bs.MusicType.SCORES, + 'Marching Forward': bs.MusicType.FORWARD_MARCH, + 'Marching Home': bs.MusicType.MARCHING, + 'Run Away': bs.MusicType.RUN_AWAY, + 'Scary': bs.MusicType.SCARY, + 'Sports': bs.MusicType.SPORTS, + 'Survival': bs.MusicType.SURVIVAL, + 'To The Death': bs.MusicType.TO_THE_DEATH, + 'None': None, +} +GLOBALS_MAPDATA = { + "The Pad (with trees)": { + "Camera Bounds": (0.3544110667, 4.493562578, -2.518391331, 16.64754831, 8.06138989, 18.5029888), + "Map Color": (1.0, 1.0, 1.0), + "Map Reflection Scale": 0.3, + "Ambient": (1.14, 1.1, 1.0), + "Tint": (1.06, 1.04, 1.03), + "Vignette Outer": (0.45, 0.55, 0.54), + "Vignette Inner": (0.99, 0.98, 0.98) + }, + "The Pad": { + "Camera Bounds": (0.3544110667, 4.493562578, -2.518391331, 16.64754831, 8.06138989, 18.5029888), + "Map Color": (1.0, 1.0, 1.0), + "Map Reflection Scale": 0.3, + "Ambient": (1.1, 1.1, 1.0), + "Tint": (1.1, 1.1, 1.0), + "Vignette Outer": (0.7, 0.65, 0.75), + "Vignette Inner": (0.95, 0.95, 0.93) + }, + "Big G": { + "Camera Bounds": (-0.4011866709, 2.331310176, -0.5426286416, 19.11746262, 10.19675564, 23.50119277), + "Map Color": (0.7, 0.7, 0.7), + "Map Reflection Scale": 0.0, + "Ambient": (1.1, 1.2, 1.3), + "Tint": (1.1, 1.2, 1.3), + "Vignette Outer": (0.65, 0.6, 0.55), + "Vignette Inner": (0.9, 0.9, 0.93) + }, + "Bridgit": { + "Camera Bounds": (-0.2457963347, 3.828181068, -1.528362695, 19.14849937, 7.312788846, 8.436232726), + "Map Color": (1.0, 1.0, 1.0), + "Map Reflection Scale": 0.0, + "Ambient": (1.1, 1.2, 1.3), + "Tint": (1.1, 1.2, 1.3), + "Vignette Outer": (0.65, 0.6, 0.55), + "Vignette Inner": (0.9, 0.9, 0.93) + }, + "Courtyard": { + "Camera Bounds": (0.3544110667, 3.958431362, -2.175025358, 16.37702017, 7.755670126, 13.38680645), + "Map Color": (1.0, 1.0, 1.0), + "Map Reflection Scale": 0.0, + "Ambient": (1.2, 1.17, 1.1), + "Tint": (1.2, 1.17, 1.1), + "Vignette Outer": (0.6, 0.6, 0.64), + "Vignette Inner": (0.95, 0.95, 0.93) + }, + "Crag Castle": { + "Camera Bounds": (0.7033834902, 6.55869393, -3.153439808, 16.73648528, 14.94789935, 11.60063102), + "Map Color": (1.0, 1.0, 1.0), + "Map Reflection Scale": 0.0, + "Ambient": (1.15, 1.05, 0.75), + "Tint": (1.15, 1.05, 0.75), + "Vignette Outer": (0.6, 0.65, 0.6), + "Vignette Inner": (0.95, 0.95, 0.95) + }, + "Doom Shroom": { + "Camera Bounds": (0.4687647786, 2.320345088, -3.219423694, 21.34898078, 10.25529817, 14.67298352), + "Map Color": (1.0, 1.0, 1.0), + "Map Reflection Scale": 0.0, + "Ambient": (0.9, 1.3, 1.1), + "Tint": (0.82, 1.10, 1.15), + "Vignette Outer": (0.76, 0.76, 0.76), + "Vignette Inner": (0.95, 0.95, 0.99) + }, + "Happy Thoughts": { + "Camera Bounds": (-1.045859963, 12.67722855, -5.401537075, 34.46156851, 20.94044653, 0.6931564611), + "Map Color": (1.0, 1.0, 1.0), + "Map Reflection Scale": 0.0, + "Ambient": (1.3, 1.23, 1.0), + "Tint": (1.3, 1.23, 1.0), + "Vignette Outer": (0.64, 0.59, 0.69), + "Vignette Inner": (0.95, 0.95, 0.93) + }, + "Football Stadium": { + "Camera Bounds": (0.0, 1.185751251, 0.4326226188, 29.8180273, 11.57249038, 18.89134176), + "Map Color": (1.0, 1.0, 1.0), + "Map Reflection Scale": 0.0, + "Ambient": (1.3, 1.2, 1.0), + "Tint": (1.3, 1.2, 1.0), + "Vignette Outer": (0.57, 0.57, 0.57), + "Vignette Inner": (0.9, 0.9, 0.9) + }, + "Hockey Stadium": { + "Camera Bounds": (0.0, 0.7956858119, 0.0, 30.80223883, 0.5961646365, 13.88431707), + "Map Color": (1.0, 1.0, 1.0), + "Map Reflection Scale": 0.3, + "Ambient": (1.15, 1.25, 1.6), + "Tint": (1.2, 1.3, 1.33), + "Vignette Outer": (0.66, 0.67, 0.73), + "Vignette Inner": (0.93, 0.93, 0.95) + }, + "Lake Frigid": { + "Camera Bounds": (0.622753268, 3.958431362, -2.48708008, 20.62310543, 7.755670126, 12.33155049), + "Map Color": (1.0, 1.0, 1.0), + "Map Reflection Scale": 0.0, + "Ambient": (1, 1, 1), + "Tint": (1, 1, 1), + "Vignette Outer": (0.86, 0.86, 0.86), + "Vignette Inner": (0.95, 0.95, 0.99) + }, + "Monkey Face": { + "Camera Bounds": (-1.657177611, 4.132574186, -1.580485661, 17.36258946, 10.49020453, 12.31460338), + "Map Color": (1.0, 1.0, 1.0), + "Map Reflection Scale": 0.0, + "Ambient": (1.1, 1.2, 1.2), + "Tint": (1.1, 1.2, 1.2), + "Vignette Outer": (0.60, 0.62, 0.66), + "Vignette Inner": (0.97, 0.95, 0.93) + }, + "Rampage": { + "Camera Bounds": (0.3544110667, 5.616383286, -4.066055072, 19.90053969, 10.34051135, 8.16221072), + "Map Color": (1.0, 1.0, 1.0), + "Map Reflection Scale": 0.0, + "Ambient": (1.3, 1.2, 1.03), + "Tint": (1.2, 1.1, 0.97), + "Vignette Outer": (0.62, 0.64, 0.69), + "Vignette Inner": (0.97, 0.95, 0.93) + }, + "Roundabout": { + "Camera Bounds": (-1.552280404, 3.189001207, -2.40908495, 11.96255385, 8.857531648, 9.531689995), + "Map Color": (0.7, 0.7, 0.7), + "Map Reflection Scale": 0.0, + "Ambient": (1.0, 1.05, 1.1), + "Tint": (1.0, 1.05, 1.1), + "Vignette Outer": (0.63, 0.65, 0.7), + "Vignette Inner": (0.97, 0.95, 0.93) + }, + "Step Right Up": { + "Camera Bounds": (0.3544110667, 6.07676405, -2.271833016, 22.55121262, 10.14644532, 14.66087273), + "Map Color": (1.0, 1.0, 1.0), + "Map Reflection Scale": 0.0, + "Ambient": (1.2, 1.1, 1.0), + "Tint": (1.2, 1.1, 1.0), + "Vignette Outer": (1.2, 1.1, 1.0), + "Vignette Inner": (0.95, 0.95, 0.93) + }, + "Tower D": { + "Camera Bounds": (-0.4714933293, 2.887077774, -1.505479919, 17.90145968, 6.188484831, 15.96149117), + "Map Color": (1.0, 1.0, 1.0), + "Map Reflection Scale": 0.0, + "Ambient": (1.2, 1.1, 1.0), + "Tint": (1.15, 1.11, 1.03), + "Vignette Outer": (1.2, 1.1, 1.0), + "Vignette Inner": (0.95, 0.95, 0.95) + }, + "Tip Top": { + "Camera Bounds": (0.004375512593, 7.141135803, -0.01745294675, 21.12506141, 4.959977313, 16.6885592), + "Map Color": (0.7, 0.7, 0.7), + "Map Reflection Scale": 0.0, + "Ambient": (0.8, 0.9, 1.3), + "Tint": (0.8, 0.9, 1.3), + "Vignette Outer": (0.79, 0.79, 0.69), + "Vignette Inner": (0.97, 0.97, 0.99) + }, + "Zig Zag": { + "Camera Bounds": (-1.807378035, 3.943412768, -1.61304303, 23.01413538, 13.27980464, 10.0098376), + "Map Color": (1.0, 1.0, 1.0), + "Map Reflection Scale": 0.0, + "Ambient": (1.0, 1.15, 1.15), + "Tint": (1.0, 1.15, 1.15), + "Vignette Outer": (0.57, 0.59, 0.63), + "Vignette Inner": (0.97, 0.95, 0.93) + } +} + + +class CustomColorPicker(ColorPicker): + + def _select_other(self): + from bauiv1lib import purchase + + CustomColorPickerExact(parent=self._parent, + position=self._position, + initial_color=self._initial_color, + delegate=self._delegate, + scale=self._scale, + offset=self._offset, + tag=self._tag) + self._delegate = None + self._transition_out() + + +class CustomColorPickerExact(ColorPickerExact): + + def _color_change_press(self, color_name: str, increasing: bool): + current_time = bui.apptime() + since_last = current_time - self._last_press_time + if ( + since_last < 0.2 + and self._last_press_color_name == color_name + and self._last_press_increasing == increasing + ): + self._change_speed += 0.25 + else: + self._change_speed = 1.0 + self._last_press_time = current_time + self._last_press_color_name = color_name + self._last_press_increasing = increasing + + color_index = ('r', 'g', 'b').index(color_name) + offs = int(self._change_speed) * (0.01 if increasing else -0.01) + self._color[color_index] = max( + -1.0, min(2.55, self._color[color_index] + offs) + ) + self._update_for_color() + + +class ConfigCheckBox: + widget: bui.Widget + + def __init__( + self, + parent: bui.Widget, + configkey: str, + position: tuple[float, float], + size: tuple[float, float], + displayname: str | bs.Lstr | None = None, + scale: float | None = None, + maxwidth: float | None = None, + autoselect: bool = True, + value_change_call: Callable[[Any], Any] | None = None): + + if displayname is None: + displayname = configkey + self._value_change_call = value_change_call + self._configkey = configkey + self.widget = bui.checkboxwidget( + parent=parent, + autoselect=autoselect, + position=position, + size=size, + text=displayname, + textcolor=(0.8, 0.8, 0.8), + value=bs.app.config[configkey], + on_value_change_call=self._value_changed, + scale=scale, + maxwidth=maxwidth, + ) + # complain if we outlive our checkbox + bui.uicleanupcheck(self, self.widget) + + def _value_changed(self, val: bool): + cfg = bs.app.config + cfg[self._configkey] = val + if self._value_change_call is not None: + self._value_change_call(val) + cfg.apply_and_commit() + + +class FreeEditWindow(bui.Window): + + def _do_enter(self): + + def _error() -> None: + bui.getsound('error').play(volume=2.0) + bui.screenmessage('error ' + u'😑😑', color=(1.0, 0.0, 0.0)) + + try: + if self.name_only: + value = bui.textwidget(query=self._text_field) + if not value.strip(): + return _error() + + self.delegate._export(self, txt=value) + else: + value = round(float(bui.textwidget(query=self._text_field)), 4) + self.delegate.free_edit_enter(self, c=self.config_name, txt=value) + + except ValueError: + return _error() + bui.containerwidget(edit=self._root_widget, transition=self._transition_out) + + def _activate_enter_button(self): + self._enter_button.activate() + + def _do_back(self): + bui.containerwidget(edit=self._root_widget, transition=self._transition_out) + + def __init__(self, delegate: Any = None, config_name: str = 'Menu Map', whitelist: List = [], name_only: bool = False, origin_widget: bui.widget = None): + self._transition_out = 'out_scale' if origin_widget else 'out_right' + scale_origin = origin_widget.get_screen_space_center() if origin_widget else None + transition = 'in_scale' if origin_widget else 'in_right' + width, height = 450, 230 + uiscale = bs.app.ui_v1.uiscale + + super().__init__(root_widget=bui.containerwidget( + size=(width, height), + transition=transition, + toolbar_visibility='menu_minimal_no_back', + scale_origin_stack_offset=scale_origin, + scale=(2.0 if uiscale is bs.UIScale.SMALL else + 1.5 if uiscale is bs.UIScale.MEDIUM else 1.0))) + + btn = bui.buttonwidget(parent=self._root_widget, + scale=0.5, + position=(40, height - 40), + size=(60, 60), + label='', + on_activate_call=self._do_back, + autoselect=True, + color=(0.55, 0.5, 0.6), + icon=bui.gettexture('crossOut'), + iconscale=1.2) + + self.config_name, self.delegate, self.name_only = config_name, delegate, name_only + + self._text_field = bui.textwidget( + parent=self._root_widget, + position=(125, height - 121), + size=(280, 46), + text='', + h_align='left', + v_align='center', + color=(0.9, 0.9, 0.9, 1.0), + description='', + editable=True, + padding=4, + max_chars=20 if name_only else 5, + on_return_press_call=self._activate_enter_button) + + bui.textwidget(parent=self._root_widget, + text='Current: ' + str(config[config_name]) if not name_only else 'Save as', + position=(220, height - 44), + color=(0.5, 0.5, 0.5, 1.0), + size=(90, 30), + h_align='right') + + bui.widget(edit=btn, down_widget=self._text_field) + + b_width = 200 + self._enter_button = btn2 = bui.buttonwidget( + parent=self._root_widget, + position=(width * 0.5 - b_width * 0.5, height - 200), + size=(b_width, 60), + scale=1.0, + label='Enter', + on_activate_call=self._do_enter) + bui.containerwidget(edit=self._root_widget, + cancel_button=btn, + start_button=btn2, + selected_child=self._text_field) + + +class MenuThemeWindow: + def __init__(self, origin_widget: bui.widget = None, accounts_window=None): + if origin_widget is not None: + self._transition_out = 'out_scale' + scale_origin = origin_widget.get_screen_space_center() + transition = 'in_scale' + else: + self._transition_out = 'out_right' + scale_origin = None + transition = 'in_right' + + self._choice_page: str = None + self._accounts_window = accounts_window + height = 500 if ui_type is ui_small else 772 + + self._root_widget = bui.containerwidget( + size=(445, 365) if ui_type is ui_small else (799, 576), + transition=transition, + toolbar_visibility='menu_minimal', + scale_origin_stack_offset=scale_origin, + scale=2.23 if ui_type is ui_small else 1.0, + stack_offset=(0, -35) if ui_type is ui_small else (0, 0) + ) + + self._scroll_border_parent = bui.scrollwidget( + parent=self._root_widget, + position=(39, 58) if ui_type is ui_small else (86, 39), + size=(375, 240) if ui_type is ui_small else (645, 463), + color=(0.52, 0.48, 0.63) + ) + + self._scroll_parent = bui.containerwidget( + parent=self._scroll_border_parent, + size=(450, height), + background=False, + claims_left_right=False, + claims_tab=False + ) + + self._back_button = bui.buttonwidget( + parent=self._root_widget, + position=(23, 310) if ui_type is ui_small else (80, 511), + size=(35, 35) if ui_type is ui_small else (55, 55), + color=(0.76, 0.42, 0.38), + button_type="backSmall", + textcolor=(1, 1, 1), + text_scale=0.8 if ui_type is ui_small else 1.0, + label="", + autoselect=True, + on_activate_call=bs.Call(self.close) + ) + + self._home_button = bui.buttonwidget( + parent=self._root_widget, + position=(383, 308) if ui_type is ui_small else (688, 511), + size=(60, 60) if ui_type is ui_small else (55, 55), + color=(0.76, 0.42, 0.38), + icon=bui.gettexture('crossOut'), + iconscale=1.2, + scale=0.59 if ui_type is ui_small else 0.92, + label="", + autoselect=True, + on_activate_call=bs.Call(self.close_all) + ) + + # menutheme title + bui.textwidget( + parent=self._root_widget, + position=(225, 327) if ui_type is ui_small else (415, 547), + size=(0, 0), + text="Menu Theme", + color=(0.8, 0.8, 0.8, 0.76), + maxwidth=290, + scale=0.95 if ui_type is ui_small else 1.25, + h_align='center', + v_align='center' + ) + + bui.textwidget( + parent=self._root_widget, + position=(225, 309) if ui_type is ui_small else (415, 517), + size=(0, 0), + text=f"version: {__version__}", + color=(0.6, 0.6, 0.6, 0.8), + maxwidth=290, + scale=0.454 if ui_type is ui_small else 0.653, + h_align='center', + v_align='center' + ) + + # settings txt + bui.textwidget( + parent=self._scroll_parent, + position=(10, height - 27) if ui_type is ui_small else (30, height - 47), + size=(0, 0), + text="Map Type:", + color=(1, 1, 1, 0.8), + maxwidth=290, + scale=0.7 if ui_type is ui_small else 1.3, + h_align='left', + v_align='center' + ) + + bui.textwidget( + parent=self._scroll_parent, + position=(10, height - 65) if ui_type is ui_small else (30, height - 104), + size=(0, 0), + text="Music:", + color=(1, 1, 1, 0.8), + maxwidth=290, + scale=0.7 if ui_type is ui_small else 1.3, + h_align='left', + v_align='center' + ) + + bui.textwidget( + parent=self._scroll_parent, + position=(25, height - 147) if ui_type is ui_small else (45, height - 239), + size=(0, 0), + text="tint", + color=(1, 1, 1, 0.8), + maxwidth=290, + scale=0.5 if ui_type is ui_small else 1.0, + h_align='left', + v_align='center' + ) + + bui.textwidget( + parent=self._scroll_parent, + position=(81, height - 147) if ui_type is ui_small else (140, height - 239), + size=(0, 0), + text="ambient", + color=(1, 1, 1, 0.8), + maxwidth=290, + scale=0.5 if ui_type is ui_small else 1.0, + h_align='left', + v_align='center' + ) + + bui.textwidget( + parent=self._scroll_parent, + position=(147, height - 156) if ui_type is ui_small else (262, height - 258), + size=(0, 0), + text="vignette\n outer", + color=(1, 1, 1, 0.8), + maxwidth=290, + scale=0.5 if ui_type is ui_small else 1.0, + h_align='left', + v_align='center' + ) + + bui.textwidget( + parent=self._scroll_parent, + position=(213, height - 156) if ui_type is ui_small else (382, height - 258), + size=(0, 0), + text="vignette\n inner", + color=(1, 1, 1, 0.8), + maxwidth=290, + scale=0.5 if ui_type is ui_small else 1.0, + h_align='left', + v_align='center' + ) + + bui.textwidget( + parent=self._scroll_parent, + position=(279, height - 156) if ui_type is ui_small else (500, height - 258), + size=(0, 0), + text="reflection\n color", + color=(1, 1, 1, 0.8), + maxwidth=290, + scale=0.5 if ui_type is ui_small else 1.0, + h_align='left', + v_align='center' + ) + + bui.textwidget( + parent=self._scroll_parent, + position=(10, height - 193) if ui_type is ui_small else (30, height - 320), + size=(0, 0), + text="Reflection Type:", + color=(1, 1, 1, 0.8), + maxwidth=290, + scale=0.7 if ui_type is ui_small else 1.3, + h_align='left', + v_align='center' + ) + + bui.textwidget( + parent=self._scroll_parent, + position=(10, height - 227) if ui_type is ui_small else (30, height - 373), + size=(0, 0), + text="Reflection Scale:", + color=(1, 1, 1, 0.8), + maxwidth=290, + scale=0.7 if ui_type is ui_small else 1.3, + h_align='left', + v_align='center' + ) + + bui.textwidget( + parent=self._scroll_parent, + position=(10, height - 260) if ui_type is ui_small else (30, height - 423), + size=(0, 0), + text="Camera Mode:", + color=(1, 1, 1, 0.8), + maxwidth=290, + scale=0.7 if ui_type is ui_small else 1.3, + h_align='left', + v_align='center' + ) + + bui.textwidget( + parent=self._scroll_parent, + position=(10, height - 294) if ui_type is ui_small else (30, height - 480), + size=(0, 0), + text="Show Logo Text:", + color=(1, 1, 1, 0.8), + maxwidth=290, + scale=0.7 if ui_type is ui_small else 1.3, + h_align='left', + v_align='center' + ) + + # prioritize this first for: + # >> handling config-errors + # >> debugging + self._menu_configreset_button = bui.buttonwidget( + parent=self._scroll_parent, + position=(5, height - 486) if ui_type is ui_small else (12, height - 765), + size=(329, 50) if ui_type is ui_small else (600, 80), + color=(0.0, 0.67, 0.85), + textcolor=(0.8, 0.8, 0.8), + button_type="regular", + label="Reset to Default Settings", + text_scale=0.7 if ui_type is ui_small else 1.0, + on_activate_call=bs.Call(self.reset_config) + ) + + # settings buttons + self._menu_map_button = bui.buttonwidget( + parent=self._scroll_parent, + position=(112, height - 38) if ui_type is ui_small else (206, height - 67), + size=(87, 24) if ui_type is ui_small else (149, 40), + button_type="regular", + label=config["Menu Map"], + on_activate_call=bs.Call(self.choice_window, 'Map') + ) + + self._menu_music_button = bui.buttonwidget( + parent=self._scroll_parent, + position=(85, height - 75) if ui_type is ui_small else (149, height - 123), + size=(87, 24) if ui_type is ui_small else (149, 40), + button_type="regular", + label=config["Menu Music"], + text_scale=0.6 if ui_type is ui_small else 1.0, + on_activate_call=bs.Call(self.choice_window, 'Music') + ) + + self._menu_tint_button = bui.buttonwidget( + parent=self._scroll_parent, + color=config["Menu Tint"], + position=(15, height - 136) if ui_type is ui_small else (30, height - 220), + size=(40, 40) if ui_type is ui_small else (70, 70), + button_type="square", + label="", + on_activate_call=bs.WeakCall(self.color_picker_popup, "Menu Tint") + ) + + self._menu_ambient_button = bui.buttonwidget( + parent=self._scroll_parent, + color=config["Menu Ambient"], + position=(81, height - 136) if ui_type is ui_small else (150, height - 220), + size=(40, 40) if ui_type is ui_small else (70, 70), + button_type="square", + label="", + on_activate_call=bs.WeakCall(self.color_picker_popup, "Menu Ambient") + ) + + self._menu_vignetteO_button = bui.buttonwidget( + parent=self._scroll_parent, + color=config["Menu Vignette Outer"], + position=(147, height - 136) if ui_type is ui_small else (270, height - 220), + size=(40, 40) if ui_type is ui_small else (70, 70), + button_type="square", + label="", + on_activate_call=bs.WeakCall(self.color_picker_popup, "Menu Vignette Outer") + ) + + self._menu_vignetteI_button = bui.buttonwidget( + parent=self._scroll_parent, + color=config["Menu Vignette Inner"], + position=(213, height - 136) if ui_type is ui_small else (390, height - 220), + size=(40, 40) if ui_type is ui_small else (70, 70), + button_type="square", + label="", + on_activate_call=bs.WeakCall(self.color_picker_popup, "Menu Vignette Inner") + ) + + self._menu_rcolor_button = bui.buttonwidget( + parent=self._scroll_parent, + color=config["Menu Map Color"], + position=(279, height - 136) if ui_type is ui_small else (510, height - 220), + size=(40, 40) if ui_type is ui_small else (70, 70), + button_type="square", + label="", + on_activate_call=bs.WeakCall(self.color_picker_popup, "Menu Map Color") + ) + + self._menu_reflectiont_button = bui.buttonwidget( + parent=self._scroll_parent, + position=(148, height - 204) if ui_type is ui_small else (287, height - 339), + size=(87, 24) if ui_type is ui_small else (149, 40), + button_type="regular", + label=config["Menu Reflection Type"], + text_scale=0.6 if ui_type is ui_small else 1.0, + on_activate_call=bs.Call(self.choice_window, 'Reflection Type') + ) + + self._menu_reflections_button = bui.buttonwidget( + parent=self._scroll_parent, + position=(153, height - 237) if ui_type is ui_small else (289, height - 392), + size=(87, 24) if ui_type is ui_small else (149, 40), + button_type="regular", + label=str(config["Menu Reflection Scale"]), + text_scale=0.6 if ui_type is ui_small else 1.0, + on_activate_call=lambda: FreeEditWindow( + delegate=self, whitelist=['num'], config_name='Menu Reflection Scale') + ) + + self._menu_cameramode_button = bui.buttonwidget( + parent=self._scroll_parent, + position=(138, height - 272) if ui_type is ui_small else (265, height - 444), + size=(87, 24) if ui_type is ui_small else (149, 40), + button_type="regular", + label=str(config["Menu Camera Mode"]), + text_scale=0.6 if ui_type is ui_small else 1.0, + on_activate_call=bs.Call(self.choice_window, 'Camera Mode') + ) + + self._menu_logotext_button = ConfigCheckBox( + parent=self._scroll_parent, + configkey="Menu Logo Text", + position=(151, height - 308) if ui_type is ui_small else (287, height - 520), + size=(40, 40) if ui_type is ui_small else (56, 56), + scale=0.62 if ui_type is ui_small else 1.4, + displayname="" + ) + + self._menu_load_button = bui.buttonwidget( + parent=self._scroll_parent, + position=(11, height - 365) if ui_type is ui_small else (22, height - 590), + size=(155, 45) if ui_type is ui_small else (280, 75), + textcolor=(0.8, 0.8, 0.8), + button_type="regular", + label="Load Theme", + text_scale=0.7 if ui_type is ui_small else 1.0, + on_activate_call=bs.Call(self.popup_fileselector) + ) + + self._menu_save_button = bui.buttonwidget( + parent=self._scroll_parent, + position=(178, height - 365) if ui_type is ui_small else (312, height - 590), + size=(155, 45) if ui_type is ui_small else (280, 75), + textcolor=(0.8, 0.8, 0.8), + button_type="regular", + label="Save Theme", + text_scale=0.7 if ui_type is ui_small else 1.0, + on_activate_call=lambda: FreeEditWindow(delegate=self, name_only=True) + ) + + self._menu_mapdata_button = bui.buttonwidget( + parent=self._scroll_parent, + position=(5, height - 425) if ui_type is ui_small else (12, height - 677), + size=(329, 50) if ui_type is ui_small else (600, 80), + color=(0.23, 0.27, 0.55), + textcolor=(0.8, 0.8, 0.8), + button_type="regular", + label="Map Data Overrides", + text_scale=0.7 if ui_type is ui_small else 1.0, + on_activate_call=bs.Call(self.checkbox_window) + ) + + def checkbox_window(self): + self._root_widget_checkbox = bui.containerwidget( + size=(800, 740), + transition='in_scale', + toolbar_visibility='menu_minimal', + scale_origin_stack_offset=(0, 0), + scale=0.6 if ui_type is ui_large else 0.88 if ui_type is ui_small else 0.76, + color=(0.17, 0.2, 0.25), + on_outside_click_call=bs.Call(self.checkbox_window_out), + claim_outside_clicks=True, + stack_offset=(0, -35) if ui_type is ui_small else (0, 0) + ) + self._button_tint = ConfigCheckBox( + parent=self._root_widget_checkbox, + configkey="tint", + position=(88, 600), + size=(380, 40), + scale=1.9, + displayname='Tint' + ) + self._button_ambient = ConfigCheckBox( + parent=self._root_widget_checkbox, + configkey="ambient_color", + position=(88, 510), + size=(380, 40), + scale=1.9, + displayname='Ambient Color' + ) + self._button_vignette_outer = ConfigCheckBox( + parent=self._root_widget_checkbox, + configkey="vignette_outer", + position=(88, 420), + size=(380, 40), + scale=1.9, + displayname='Vignette Outer' + ) + self._button_vignette_inner = ConfigCheckBox( + parent=self._root_widget_checkbox, + configkey="vignette_inner", + position=(88, 330), + size=(380, 40), + scale=1.9, + displayname='Vignette Inner' + ) + self._button_map_color = ConfigCheckBox( + parent=self._root_widget_checkbox, + configkey="map_color", + position=(88, 240), + size=(380, 40), + scale=1.9, + displayname='Map Color' + ) + self._button_map_reflection_scale = ConfigCheckBox( + parent=self._root_widget_checkbox, + configkey="map_reflection_scale", + position=(88, 150), + size=(380, 40), + scale=1.9, + displayname='Map Reflection Scale' + ) + self._button_map_reflection_type = ConfigCheckBox( + parent=self._root_widget_checkbox, + configkey="map_reflection_type", + position=(88, 60), + size=(380, 40), + scale=1.9, + displayname='Map Reflection Type' + ) + + def checkbox_window_out(self): + # Memory-leak prevention + bui.containerwidget(edit=self._root_widget_checkbox, transition='out_scale') + del self._button_tint + del self._button_ambient + del self._button_vignette_outer + del self._button_vignette_inner + del self._button_map_color + del self._button_map_reflection_scale + del self._button_map_reflection_type + + def choice_window(self, category: str): + choices_map = { + 'Map': [ + 'Big G', + 'Bridgit', + 'Courtyard', + 'Crag Castle', + 'Doom Shroom', + 'Football Stadium', + 'Happy Thoughts', + 'Hockey Stadium', + 'Lake Frigid', + 'Monkey Face', + 'Rampage', + 'Roundabout', + 'Step Right Up', + 'The Pad', + 'The Pad (with trees)', + 'Tower D', + 'Tip Top', + 'Zig Zag' + ], + 'Camera Mode': [ + 'rotate', + 'static' + ], + 'Reflection Type': [ + 'Soft', + 'None', + 'Powerup', + 'Character' + ], + 'Music': [ + 'Menu', + 'Epic', + 'Flag Catcher', + 'Flying', + 'Grand Romp', + 'Lobby', + 'Lobby Epic', + 'Marching Forward', + 'Marching Home', + 'Run Away', + 'Scary', + 'Sports', + 'Survival', + 'To The Death', + 'None' + ] + } + + if category in choices_map: + PopupMenuWindow( + position=(0, 0), + scale=2.0 if ui_type is ui_small else 1.0, + delegate=self, + current_choice=bs.app.config[f"Menu {category}"], + choices=choices_map[category] + ) + self._choice_page = category + + def popup_menu_selected_choice(self, window: PopupMenuWindow, choice: str): + if self._choice_page == 'Map': + bs.app.config['Menu Map'] = choice + if config["tint"]: + bs.app.config["Menu Tint"] = GLOBALS_MAPDATA.get(config["Menu Map"]).get("Tint") + if config["ambient_color"]: + bs.app.config["Menu Ambient"] = GLOBALS_MAPDATA.get( + config["Menu Map"]).get("Ambient") + if config["vignette_outer"]: + bs.app.config["Menu Vignette Outer"] = GLOBALS_MAPDATA.get( + config["Menu Map"]).get("Vignette Outer") + if config["vignette_inner"]: + bs.app.config["Menu Vignette Inner"] = GLOBALS_MAPDATA.get( + config["Menu Map"]).get("Vignette Inner") + if config["map_color"]: + bs.app.config["Menu Map Color"] = GLOBALS_MAPDATA.get( + config["Menu Map"]).get("Map Color") + if config["map_reflection_scale"]: + bs.app.config["Menu Reflection Scale"] = GLOBALS_MAPDATA.get( + config["Menu Map"]).get("Map Reflection Scale") + if config["map_reflection_type"]: + bs.app.config["Menu Reflection Type"] = 'Soft' + + elif self._choice_page == 'Music': + bs.app.config['Menu Music'] = choice + + elif self._choice_page == 'Reflection Type': + bs.app.config['Menu Reflection Type'] = choice + + elif self._choice_page == 'Camera Mode': + bs.app.config['Menu Camera Mode'] = choice + bs.app.config.apply_and_commit() + self.update_buttons() + + def popup_menu_closing(self, window: PopupMenuWindow): + self._choice_page = None + self.update_buttons() + + def popup_fileselector(self): + self._file_selector = FileSelectorWindow( + path=str(_ba.env()['python_directory_user']), + callback=self._import, + show_base_path=True, + valid_file_extensions=['json'], + allow_folders=False + ) + + def _import(self, path: str = None): + try: + self.path = path + '/' + self.path = self.path[:-1] + with open(self.path, 'r') as imported: + selected = json.load(imported) + handle_config([ + selected["Menu Map"], + selected["Menu Tint"], + selected["Menu Ambient"], + selected["Menu Vignette Outer"], + selected["Menu Vignette Inner"], + selected["Menu Music"], + selected["Menu Map Color"], + selected["Menu Reflection Scale"], + selected["Menu Reflection Type"], + selected["Menu Camera Mode"], + selected["Menu Logo Text"], + selected["vignette_outer"], + selected["vignette_inner"], + selected["ambient_color"], + selected["tint"], + selected["map_reflection_scale"], + selected["map_reflection_type"], + selected["map_color"]], + False + ) + self.update_buttons() + bui.screenmessage( + f"Loaded {os.path.splitext(os.path.basename(self.path))[0]}!", color=(0.2, 0.4, 1.0)) + except: + pass + del self._file_selector + + def _export(self, window: FreeEditWindow, txt: Any): + path = _ba.env()['python_directory_user'] + "/_menutheme/" + try: + a = _ba.env()['python_directory_user'] + "/_menutheme" + os.makedirs(a, exist_ok=False) + except: + pass + + with open(path + txt + '.json', 'w') as file: + my_config = { + "Menu Map": config["Menu Map"], + "Menu Tint": config["Menu Tint"], + "Menu Ambient": config["Menu Ambient"], + "Menu Vignette Outer": config["Menu Vignette Outer"], + "Menu Vignette Inner": config["Menu Vignette Inner"], + "Menu Music": config["Menu Music"], + "Menu Map Color": config["Menu Map Color"], + "Menu Reflection Scale": config["Menu Reflection Scale"], + "Menu Reflection Type": config["Menu Reflection Type"], + "Menu Camera Mode": config["Menu Camera Mode"], + "Menu Logo Text": config["Menu Logo Text"], + "vignette_outer": config["vignette_outer"], + "vignette_inner": config["vignette_inner"], + "ambient_color": config["ambient_color"], + "tint": config["tint"], + "map_color": config["map_color"], + "map_reflection_scale": config["map_reflection_scale"], + "map_reflection_type": config["map_reflection_type"] + } + json.dump(my_config, file, indent=4) + bui.screenmessage( + f"Saved {os.path.splitext(os.path.basename(path+txt+'.json'))[0]}!", color=(0.2, 0.4, 1.0)) + bui.getsound('gunCocking').play() + + def color_picker_popup(self, tag: str): + bs.app.classic.accounts.have_pro = lambda: True + CustomColorPicker(parent=self._root_widget, + position=(0, 0), + initial_color=config[tag], + delegate=self, + tag=tag) + + def color_picker_selected_color(self, picker: CustomColorPicker, color: Sequence[float, float, float]): + if not self._root_widget: + return + self.update_color(tag=picker.get_tag(), color=color) + self.update_buttons() + + def color_picker_closing(self, picker: ColorPicker): + bs.app.classic.accounts.have_pro = original_unlocked_pro + + def free_edit_enter(self, window: FreeEditWindow, c: Any, txt: Any): + bs.app.config[c] = float(txt) + bs.app.config.apply_and_commit() + self.update_buttons() + + def update_buttons(self): + # menu labels + bui.buttonwidget(edit=self._menu_map_button, label=config['Menu Map']) + bui.buttonwidget(edit=self._menu_music_button, label=config['Menu Music']) + bui.buttonwidget(edit=self._menu_reflectiont_button, label=config['Menu Reflection Type']) + + # menu colors + bui.buttonwidget(edit=self._menu_tint_button, color=config['Menu Tint']) + bui.buttonwidget(edit=self._menu_ambient_button, color=config['Menu Ambient']) + bui.buttonwidget(edit=self._menu_vignetteO_button, color=config['Menu Vignette Outer']) + bui.buttonwidget(edit=self._menu_vignetteI_button, color=config['Menu Vignette Inner']) + bui.buttonwidget(edit=self._menu_rcolor_button, color=config['Menu Map Color']) + + # menu values + bui.buttonwidget(edit=self._menu_reflections_button, + label=str(config['Menu Reflection Scale'])) + bui.buttonwidget(edit=self._menu_cameramode_button, label=str(config['Menu Camera Mode'])) + bui.checkboxwidget(edit=self._menu_logotext_button.widget, value=config['Menu Logo Text']) + + def update_color(self, tag: str, color: tuple[float, float, float]): + bs.app.config[tag] = color + bs.app.config.apply_and_commit() + + def reset_config(self): + handle_config([ + "The Pad (with trees)", + (1.14, 1.1, 1.0), (1.06, 1.04, 1.03), + (0.45, 0.55, 0.54), (0.99, 0.98, 0.98), "Menu", + (1.0, 1.0, 1.0), 0.3, 'None', 'rotate', + True, True, True, True, True, True, True, True, True + ], False + ) + self.update_buttons() + bui.screenmessage('Reset Settings', color=(0, 1, 0)) + + def close(self): + self._accounts_window = None + bui.containerwidget(edit=self._root_widget, transition='out_scale') + + def close_all(self): + accounts_window = self._accounts_window + bui.containerwidget(edit=self._root_widget, transition='out_scale') + accounts_window._back(False) + + +class MainMenuTheme(MainMenuActivity): + + def _start_preloads(self): + if self.expired: + return + with self.context: + _preload1() + + bui.apptimer(0.5, self._start_menu_music) + + def _start_menu_music(self): + music = GLOBALS_MUSIC.get(config['Menu Music']) + if music is not None: + bs.setmusic(music) + + def _make_word(self, *args, **kwargs) -> None: + if not config['Menu Logo Text']: + return + super()._make_word(*args, **kwargs) + + def _make_logo(self, *args, **kwargs) -> None: + if not config['Menu Logo Text']: + return + super()._make_logo(*args, **kwargs) + + def on_transition_in(self): + bs.Activity.on_transition_in(self) + random.seed(123) + app = bs.app + env = ba.app.env + assert app.classic is not None + + plus = bui.app.plus + assert plus is not None + + vr_mode = env.vr + + if not toolbar_test: + color = (1.0, 1.0, 1.0, 1.0) if vr_mode else (0.5, 0.6, 0.5, 0.6) + + scale = ( + 0.9 + if (app.ui_v1.uiscale is bs.UIScale.SMALL or vr_mode) + else 0.7 + ) + self.my_name = bs.NodeActor( + bs.newnode( + 'text', + attrs={ + 'v_attach': 'bottom', + 'h_align': 'center', + 'color': color, + 'flatness': 1.0, + 'shadow': 1.0 if vr_mode else 0.5, + 'scale': scale, + 'position': (0, 10), + 'vr_depth': -10, + 'text': '\xa9 2011-2023 Eric Froemling', + }, + ) + ) + + tval = bs.Lstr( + resource='hostIsNavigatingMenusText', + subs=[('${HOST}', plus.get_v1_account_display_string())], + ) + self._host_is_navigating_text = bs.NodeActor( + bs.newnode( + 'text', + attrs={ + 'text': tval, + 'client_only': True, + 'position': (0, -200), + 'flatness': 1.0, + 'h_align': 'center', + }, + ) + ) + if not app.classic.main_menu_did_initial_transition and hasattr( + self, 'my_name' + ): + assert self.my_name is not None + assert self.my_name.node + bs.animate(self.my_name.node, 'opacity', {2.3: 0, 3.0: 1.0}) + + vr_mode = env.vr + uiscale = bui.UIV1Subsystem.uiscale + + force_show_build_number = False + + if not toolbar_test: + if env.debug or env.test or force_show_build_number: + if env.debug: + text = bs.Lstr( + value='${V} (${B}) (${D})', + subs=[ + ('${V}', env.version), + ('${B}', str(env.build_number)), + ('${D}', bs.Lstr(resource='debugText')), + ], + ) + else: + text = bs.Lstr( + value='${V} (${B})', + subs=[ + ('${V}', env.version), + ('${B}', str(env.build_number)), + ], + ) + else: + text = bs.Lstr(value='${V}', subs=[('${V}', env.version)]) + scale = 0.9 if (uiscale is bs.UIScale.SMALL or vr_mode) else 0.7 + color = (1, 1, 1, 1) if vr_mode else (0.5, 0.6, 0.5, 0.7) + self.version = bs.NodeActor( + bs.newnode( + 'text', + attrs={ + 'v_attach': 'bottom', + 'h_attach': 'right', + 'h_align': 'right', + 'flatness': 1.0, + 'vr_depth': -10, + 'shadow': 1.0 if vr_mode else 0.5, + 'color': color, + 'scale': scale, + 'position': (-260, 10) if vr_mode else (-10, 10), + 'text': text, + }, + ) + ) + if not app.classic.main_menu_did_initial_transition: + assert self.version.node + bs.animate(self.version.node, 'opacity', {2.3: 0, 3.0: 1.0}) + + self.beta_info = self.beta_info_2 = None + if env.test and not (env.demo or env.arcade) and config['Menu Logo Text']: + pos = (230, 35) + self.beta_info = bs.NodeActor( + bs.newnode( + 'text', + attrs={ + 'v_attach': 'center', + 'h_align': 'center', + 'color': (1, 1, 1, 1), + 'shadow': 0.5, + 'flatness': 0.5, + 'scale': 1, + 'vr_depth': -60, + 'position': pos, + 'text': bs.Lstr(resource='testBuildText'), + }, + ) + ) + if not app.classic.main_menu_did_initial_transition: + assert self.beta_info.node + bs.animate(self.beta_info.node, 'opacity', {1.3: 0, 1.8: 1.0}) + + b = GLOBALS_MAPDATA.get(config["Menu Map"]).get("Camera Bounds") + b = ( + b[0] - b[3] / 2.0, + b[1] - b[4] / 2.0, + b[2] - b[5] / 2.0, + b[0] + b[3] / 2.0, + b[1] + b[4] / 2.0, + b[2] + b[5] / 2.0 + ) + + gnode = self.globalsnode + gnode.camera_mode = 'follow' if config["Menu Camera Mode"] == 'static' else 'rotate' + + self.load_map_stuff() + gnode.tint = config["Menu Tint"] + gnode.ambient_color = config["Menu Ambient"] + gnode.vignette_outer = config["Menu Vignette Outer"] + gnode.vignette_inner = config["Menu Vignette Inner"] + gnode.area_of_interest_bounds = b + + self.main.node.color = config["Menu Map Color"] + self.main.node.reflection = GLOBALS_REFLECTION[config["Menu Reflection Type"]] + self.main.node.reflection_scale = [float(config["Menu Reflection Scale"])] + + self._update_timer = bs.Timer(1.0, self._update, repeat=True) + self._update() + + bui.add_clean_frame_callback(bs.WeakCall(self._start_preloads)) + + random.seed() + + if not (env.demo or env.arcade) and not toolbar_test: + self._news = NewsDisplay(self) + + with bs.ContextRef.empty(): + from bauiv1lib import specialoffer + + assert bs.app.classic is not None + if bool(False): + uicontroller = bs.app.ui_v1.controller + assert uicontroller is not None + uicontroller.show_main_menu() + else: + main_menu_location = bs.app.ui_v1.get_main_menu_location() + + # When coming back from a kiosk-mode game, jump to + # the kiosk start screen. + if env.demo or env.arcade: + # pylint: disable=cyclic-import + from bauiv1lib.kiosk import KioskWindow + + if TARGET_BALLISTICA_BUILD < 21697: + bs.app.ui_v1.set_main_menu_window( + KioskWindow().get_root_widget(), + ) + else: + bs.app.ui_v1.set_main_menu_window( + KioskWindow().get_root_widget(), from_window = False + ) + # ..or in normal cases go back to the main menu + else: + if main_menu_location == 'Gather': + # pylint: disable=cyclic-import + from bauiv1lib.gather import GatherWindow + + if TARGET_BALLISTICA_BUILD < 21697: + bs.app.ui_v1.set_main_menu_window( + GatherWindow(transition=None).get_root_widget(), + ) + else: + bs.app.ui_v1.set_main_menu_window( + GatherWindow(transition=None).get_root_widget(), from_window = False + ) + elif main_menu_location == 'Watch': + # pylint: disable=cyclic-import + from bauiv1lib.watch import WatchWindow + + if TARGET_BALLISTICA_BUILD < 21697: + bs.app.ui_v1.set_main_menu_window( + WatchWindow(transition=None).get_root_widget(), + ) + else: + bs.app.ui_v1.set_main_menu_window( + WatchWindow(transition=None).get_root_widget(), from_window = False + ) + elif main_menu_location == 'Team Game Select': + # pylint: disable=cyclic-import + from bauiv1lib.playlist.browser import ( + PlaylistBrowserWindow, + ) + + if TARGET_BALLISTICA_BUILD < 21697: + bs.app.ui_v1.set_main_menu_window( + PlaylistBrowserWindow( + sessiontype=bs.DualTeamSession, transition=None + ).get_root_widget(), + ) + else: + bs.app.ui_v1.set_main_menu_window( + PlaylistBrowserWindow( + sessiontype=bs.DualTeamSession, transition=None + ).get_root_widget(), from_window = False + ) + elif main_menu_location == 'Free-for-All Game Select': + # pylint: disable=cyclic-import + from bauiv1lib.playlist.browser import ( + PlaylistBrowserWindow, + ) + + if TARGET_BALLISTICA_BUILD < 21697: + bs.app.ui_v1.set_main_menu_window( + PlaylistBrowserWindow( + sessiontype=bs.FreeForAllSession, + transition=None, + ).get_root_widget(), + ) + else: + bs.app.ui_v1.set_main_menu_window( + PlaylistBrowserWindow( + sessiontype=bs.FreeForAllSession, + transition=None, + ).get_root_widget(), from_window = False + ) + elif main_menu_location == 'Coop Select': + # pylint: disable=cyclic-import + from bauiv1lib.coop.browser import CoopBrowserWindow + + if TARGET_BALLISTICA_BUILD < 21697: + bs.app.ui_v1.set_main_menu_window( + CoopBrowserWindow(transition=None).get_root_widget(), + ) + else: + bs.app.ui_v1.set_main_menu_window( + CoopBrowserWindow(transition=None).get_root_widget(), from_window = False + ) + elif main_menu_location == 'Benchmarks & Stress Tests': + # pylint: disable=cyclic-import + from bauiv1lib.debug import DebugWindow + + if TARGET_BALLISTICA_BUILD < 21697: + bs.app.ui_v1.set_main_menu_window( + DebugWindow(transition=None).get_root_widget(), + ) + else: + bs.app.ui_v1.set_main_menu_window( + DebugWindow(transition=None).get_root_widget(), from_window = False + ) + else: + # pylint: disable=cyclic-import + from bauiv1lib.mainmenu import MainMenuWindow + + if TARGET_BALLISTICA_BUILD < 21697: + bs.app.ui_v1.set_main_menu_window( + MainMenuWindow(transition=None).get_root_widget(), + ) + else: + bs.app.ui_v1.set_main_menu_window( + MainMenuWindow(transition=None).get_root_widget(), from_window = False + ) + + if not specialoffer.show_offer(): + + def try_again(): + if not specialoffer.show_offer(): + bui.apptimer(2.0, specialoffer.show_offer) + + bui.apptimer(2.0, try_again) + app.classic.main_menu_did_initial_transition = True + + def load_map_stuff(self): + m = bs.getmesh + t = bs.gettexture + map_type = config["Menu Map"] + if map_type == "The Pad (with trees)": + self.main = bs.NodeActor(bs.newnode( + 'terrain', + delegate=self, + attrs={ + 'mesh': m('thePadLevel'), + 'color_texture': t('thePadLevelColor'), + 'reflection': 'soft', + 'reflection_scale': [0.3] + })) + self.trees = bs.NodeActor(bs.newnode( + 'terrain', + attrs={ + 'mesh': m('trees'), + 'lighting': False, + 'reflection': 'char', + 'reflection_scale': [0.1], + 'color_texture': t('treesColor') + })) + self.bgterrain = bs.NodeActor(bs.newnode( + 'terrain', + attrs={ + 'mesh': m('thePadBG'), + 'color': (0.92, 0.91, 0.9), + 'lighting': False, + 'background': True, + 'color_texture': t('menuBG'), + })) + self.bottom = bs.NodeActor(bs.newnode( + 'terrain', + attrs={ + 'mesh': m('thePadLevelBottom'), + 'lighting': False, + 'reflection': 'soft', + 'reflection_scale': [0.45], + 'color_texture': t('thePadLevelColor') + })) + elif map_type == "The Pad": + self.main = bs.NodeActor(bs.newnode( + 'terrain', + delegate=self, + attrs={ + 'mesh': m('thePadLevel'), + 'color_texture': t('thePadLevelColor'), + 'reflection': 'soft', + 'reflection_scale': [0.3] + })) + self.bgterrain = bs.NodeActor(bs.newnode( + 'terrain', + attrs={ + 'mesh': m('thePadBG'), + 'color': (0.92, 0.91, 0.9), + 'lighting': False, + 'background': True, + 'color_texture': t("menuBG") + })) + self.bottom = bs.NodeActor(bs.newnode( + 'terrain', + attrs={ + 'mesh': m('thePadLevelBottom'), + 'lighting': False, + 'reflection': 'soft', + 'reflection_scale': [0.45], + 'color_texture': t('thePadLevelColor') + })) + elif map_type == "Hockey Stadium": + self.main = bs.NodeActor(bs.newnode( + 'terrain', + delegate=self, + attrs={ + 'mesh': m('hockeyStadiumOuter'), + 'color_texture': t('hockeyStadium'), + 'reflection': 'soft', + 'reflection_scale': [0.3] + })) + self.inner = bs.NodeActor(bs.newnode( + 'terrain', + attrs={ + 'mesh': m('hockeyStadiumInner'), + 'opacity': 0.92, + 'opacity_in_low_or_ui_medium_quality': 1.0, + 'color_texture': t('hockeyStadium') + })) + self.stands = bs.NodeActor(bs.newnode( + 'terrain', + attrs={ + 'mesh': m('hockeyStadiumStands'), + 'visible_in_reflections': False, + 'color_texture': t('footballStadium') + })) + elif map_type == "Football Stadium": + self.main = bs.NodeActor(bs.newnode( + 'terrain', + delegate=self, + attrs={ + 'mesh': m('footballStadium'), + 'color_texture': t('footballStadium'), + })) + elif map_type == "Bridgit": + self.main = bs.NodeActor(bs.newnode( + 'terrain', + delegate=self, + attrs={ + 'mesh': m('bridgitLevelTop'), + 'color_texture': t('bridgitLevelColor'), + })) + self.bottom = bs.NodeActor(bs.newnode( + 'terrain', + attrs={ + 'mesh': m('bridgitLevelBottom'), + 'lighting': False, + 'color_texture': t('bridgitLevelColor'), + })) + self.background = bs.NodeActor(bs.newnode( + 'terrain', + attrs={ + 'mesh': m('natureBackground'), + 'lighting': False, + 'background': True, + 'color_texture': t('natureBackgroundColor'), + })) + elif map_type == "Big G": + self.main = bs.NodeActor(bs.newnode( + 'terrain', + delegate=self, + attrs={ + 'mesh': m('bigG'), + 'color': (0.7, 0.7, 0.7), + 'color_texture': t('bigG'), + })) + self.bottom = bs.NodeActor(bs.newnode( + 'terrain', + attrs={ + 'mesh': m('bigGBottom'), + 'lighting': False, + 'color': (0.7, 0.7, 0.7), + 'color_texture': t('bigG'), + })) + self.background = bs.NodeActor(bs.newnode( + 'terrain', + attrs={ + 'mesh': m('natureBackground'), + 'lighting': False, + 'background': True, + 'color_texture': t('natureBackgroundColor'), + })) + elif map_type == "Roundabout": + self.main = bs.NodeActor(bs.newnode( + 'terrain', + delegate=self, + attrs={ + 'mesh': m('roundaboutLevel'), + 'color': (0.7, 0.7, 0.7), + 'color_texture': t('roundaboutLevelColor'), + })) + self.bottom = bs.NodeActor(bs.newnode( + 'terrain', + attrs={ + 'mesh': m('roundaboutLevelBottom'), + 'lighting': False, + 'color': (0.7, 0.7, 0.7), + 'color_texture': t('roundaboutLevelColor'), + })) + self.background = bs.NodeActor(bs.newnode( + 'terrain', + attrs={ + 'mesh': m('natureBackground'), + 'lighting': False, + 'background': True, + 'color_texture': t('natureBackgroundColor'), + })) + elif map_type == "Monkey Face": + self.main = bs.NodeActor(bs.newnode( + 'terrain', + delegate=self, + attrs={ + 'mesh': m('monkeyFaceLevel'), + 'color_texture': t('monkeyFaceLevelColor'), + })) + self.bottom = bs.NodeActor(bs.newnode( + 'terrain', + attrs={ + 'mesh': m('monkeyFaceLevelBottom'), + 'lighting': False, + 'color_texture': t('monkeyFaceLevelColor'), + })) + self.background = bs.NodeActor(bs.newnode( + 'terrain', + attrs={ + 'mesh': m('natureBackground'), + 'lighting': False, + 'color_texture': t('natureBackgroundColor'), + })) + elif map_type == "Monkey Face": + self.main = bs.NodeActor(bs.newnode( + 'terrain', + delegate=self, + attrs={ + 'mesh': m('monkeyFaceLevel'), + 'color_texture': t('monkeyFaceLevelColor'), + })) + self.bottom = bs.NodeActor(bs.newnode( + 'terrain', + attrs={ + 'mesh': m('monkeyFaceLevelBottom'), + 'lighting': False, + 'color_texture': t('monkeyFaceLevelColor'), + })) + self.background = bs.NodeActor(bs.newnode( + 'terrain', + attrs={ + 'mesh': m('natureBackground'), + 'lighting': False, + 'color_texture': t('natureBackgroundColor'), + })) + elif map_type == "Zig Zag": + self.main = bs.NodeActor(bs.newnode( + 'terrain', + delegate=self, + attrs={ + 'mesh': m('zigZagLevel'), + 'color_texture': t('zigZagLevelColor'), + })) + self.bottom = bs.NodeActor(bs.newnode( + 'terrain', + attrs={ + 'mesh': m('zigZagLevelBottom'), + 'lighting': False, + 'color_texture': t('zigZagLevelColor'), + })) + self.background = bs.NodeActor(bs.newnode( + 'terrain', + attrs={ + 'mesh': m('natureBackground'), + 'lighting': False, + 'color_texture': t('natureBackgroundColor'), + })) + elif map_type == "Doom Shroom": + self.main = bs.NodeActor(bs.newnode( + 'terrain', + delegate=self, + attrs={ + 'mesh': m('doomShroomLevel'), + 'color_texture': t('doomShroomLevelColor'), + })) + self.stem = bs.NodeActor(bs.newnode( + 'terrain', + attrs={ + 'mesh': m('doomShroomStem'), + 'lighting': False, + 'color_texture': t('doomShroomLevelColor'), + })) + self.background = bs.NodeActor(bs.newnode( + 'terrain', + attrs={ + 'mesh': m('doomShroomBG'), + 'lighting': False, + 'background': True, + 'color_texture': t('doomShroomBGColor'), + })) + elif map_type == "Lake Frigid": + self.main = bs.NodeActor(bs.newnode( + 'terrain', + delegate=self, + attrs={ + 'mesh': m('lakeFrigid'), + 'color_texture': t('lakeFrigid'), + })) + self.top = bs.NodeActor(bs.newnode( + 'terrain', + attrs={ + 'mesh': m('lakeFrigidTop'), + 'lighting': False, + 'color_texture': t('lakeFrigid'), + })) + self.reflections = bs.NodeActor(bs.newnode( + 'terrain', + attrs={ + 'mesh': m('lakeFrigidReflections'), + 'lighting': False, + 'overlay': True, + 'opacity': 0.15, + 'color_texture': t('lakeFrigidReflections'), + })) + elif map_type == "Tip Top": + self.main = bs.NodeActor(bs.newnode( + 'terrain', + delegate=self, + attrs={ + 'mesh': m('tipTopLevel'), + 'color': (0.7, 0.7, 0.7), + 'color_texture': t('tipTopLevelColor'), + })) + self.bottom = bs.NodeActor(bs.newnode( + 'terrain', + attrs={ + 'mesh': m('tipTopLevelBottom'), + 'lighting': False, + 'color': (0.7, 0.7, 0.7), + 'color_texture': t('tipTopLevelColor'), + })) + self.background = bs.NodeActor(bs.newnode( + 'terrain', + attrs={ + 'mesh': m('tipTopBG'), + 'lighting': False, + 'color': (0.4, 0.4, 0.4), + 'background': True, + 'color_texture': t('tipTopBGColor'), + })) + elif map_type == "Crag Castle": + self.main = bs.NodeActor(bs.newnode( + 'terrain', + delegate=self, + attrs={ + 'mesh': m('cragCastleLevel'), + 'color_texture': t('cragCastleLevelColor'), + })) + self.bottom = bs.NodeActor(bs.newnode( + 'terrain', + attrs={ + 'mesh': m('cragCastleLevelBottom'), + 'lighting': False, + 'color_texture': t('cragCastleLevelColor'), + })) + self.background = bs.NodeActor(bs.newnode( + 'terrain', + attrs={ + 'mesh': m('thePadBG'), + 'lighting': False, + 'background': True, + 'color_texture': t('menuBG'), + })) + elif map_type == "Tower D": + self.main = bs.NodeActor(bs.newnode( + 'terrain', + delegate=self, + attrs={ + 'mesh': m('towerDLevel'), + 'color_texture': t('towerDLevelColor'), + })) + self.bottom = bs.NodeActor(bs.newnode( + 'terrain', + attrs={ + 'mesh': m('towerDLevelBottom'), + 'lighting': False, + 'color_texture': t('towerDLevelColor'), + })) + self.background = bs.NodeActor(bs.newnode( + 'terrain', + attrs={ + 'mesh': m('thePadBG'), + 'lighting': False, + 'background': True, + 'color_texture': t('menuBG'), + })) + elif map_type == "Happy Thoughts": + self.main = bs.NodeActor(bs.newnode( + 'terrain', + delegate=self, + attrs={ + 'mesh': m('alwaysLandLevel'), + 'color_texture': t('alwaysLandLevelColor'), + })) + self.bottom = bs.NodeActor(bs.newnode( + 'terrain', + attrs={ + 'mesh': m('alwaysLandLevelBottom'), + 'lighting': False, + 'color_texture': t('alwaysLandLevelColor'), + })) + self.background = bs.NodeActor(bs.newnode( + 'terrain', + attrs={ + 'mesh': m('alwaysLandBG'), + 'lighting': False, + 'background': True, + 'color_texture': t('alwaysLandBGColor'), + })) + elif map_type == "Step Right Up": + self.main = bs.NodeActor(bs.newnode( + 'terrain', + delegate=self, + attrs={ + 'mesh': m('stepRightUpLevel'), + 'color_texture': t('stepRightUpLevelColor'), + })) + self.bottom = bs.NodeActor(bs.newnode( + 'terrain', + attrs={ + 'mesh': m('stepRightUpLevelBottom'), + 'lighting': False, + 'color_texture': t('stepRightUpLevelColor'), + })) + self.background = bs.NodeActor(bs.newnode( + 'terrain', + attrs={ + 'mesh': m('thePadBG'), + 'lighting': False, + 'background': True, + 'color_texture': t('menuBG'), + })) + elif map_type == "Courtyard": + self.main = bs.NodeActor(bs.newnode( + 'terrain', + delegate=self, + attrs={ + 'mesh': m('courtyardLevel'), + 'color_texture': t('courtyardLevelColor'), + })) + self.bottom = bs.NodeActor(bs.newnode( + 'terrain', + attrs={ + 'mesh': m('courtyardLevelBottom'), + 'lighting': False, + 'color_texture': t('courtyardLevelColor'), + })) + self.background = bs.NodeActor(bs.newnode( + 'terrain', + attrs={ + 'mesh': m('thePadBG'), + 'lighting': False, + 'background': True, + 'color_texture': t('menuBG'), + })) + elif map_type == "Rampage": + self.main = bs.NodeActor(bs.newnode( + 'terrain', + delegate=self, + attrs={ + 'mesh': m('rampageLevel'), + 'color_texture': t('rampageLevelColor'), + })) + self.bottom = bs.NodeActor(bs.newnode( + 'terrain', + attrs={ + 'mesh': m('rampageLevelBottom'), + 'lighting': False, + 'color_texture': t('rampageLevelColor'), + })) + self.background = bs.NodeActor(bs.newnode( + 'terrain', + attrs={ + 'mesh': m('rampageBG'), + 'lighting': False, + 'background': True, + 'color_texture': t('rampageBGColor'), + })) + self.background_2 = bs.NodeActor(bs.newnode( + 'terrain', + attrs={ + 'mesh': m('rampageBG2'), + 'lighting': False, + 'background': True, + 'color_texture': t('rampageBGColor2'), + })) + + +def menu_theme(self): + this_class = self + MenuThemeWindow(accounts_window=this_class) + + +def handle_config(keys: List[str], adding: bool = False): + our_config = { + "Menu Map": keys[0], + "Menu Tint": keys[1], + "Menu Ambient": keys[2], + "Menu Vignette Outer": keys[3], + "Menu Vignette Inner": keys[4], + "Menu Music": keys[5], + "Menu Map Color": keys[6], + "Menu Reflection Scale": keys[7], + "Menu Reflection Type": keys[8], + "Menu Camera Mode": keys[9], + "Menu Logo Text": keys[10], + "vignette_outer": keys[11], + "vignette_inner": keys[12], + "ambient_color": keys[13], + "tint": keys[14], + "map_color": keys[15], + "map_reflection_scale": keys[16], + "map_reflection_type": keys[17] + } + config_keys = list(our_config.keys()) + p = 0 + + for cf in config_keys: + if cf not in bs.app.config and adding: + config[cf] = keys[p] + elif our_config[cf] is not None and not adding: + config[cf] = keys[p] + p += 1 + bs.app.config.apply_and_commit() + + +def new_init(self, *args, **kwargs): + original_account_init(self, *args, **kwargs) + + self._menu_theme = bui.buttonwidget( + parent=self._root_widget, + position=((470, 330) if ui_type is ui_small else + (420, 434) if ui_type is ui_large else (445, 374)), + scale=(1.2 if ui_type is ui_small else + 1.3 if ui_type is ui_large else 1.0), + size=(160, 30) if ui_type is ui_small else (167, 30), + color=(0.55, 0.7, 0.63), + text_scale=(0.7 if ui_type is ui_medium else + 0.65 if ui_type is ui_large else 0.5), + autoselect=False, + button_type="regular", + label="Menu Theme", + on_activate_call=self.menu_theme + ) + self.previous_config = { + "Menu Map": config["Menu Map"], + "Menu Tint": config["Menu Tint"], + "Menu Ambient": config["Menu Ambient"], + "Menu Vignette Outer": config["Menu Vignette Outer"], + "Menu Vignette Inner": config["Menu Vignette Inner"], + "Menu Music": config["Menu Music"], + "Menu Map Color": config["Menu Map Color"], + "Menu Reflection Scale": config["Menu Reflection Scale"], + "Menu Reflection Type": config["Menu Reflection Type"], + "Menu Camera Mode": config["Menu Camera Mode"], + "Menu Logo Text": config["Menu Logo Text"] + } + + +def new_back(self, save_state: bool = True): + assert bui.app.classic is not None + if save_state: + self._save_state() + + bui.containerwidget(edit=self._root_widget, transition=self._transition_out) + + main_menu_window = MainMenuWindow(transition='in_left').get_root_widget() + if TARGET_BALLISTICA_BUILD < 21697: + bui.app.ui_v1.set_main_menu_window(main_menu_window,) + else: + bui.app.ui_v1.set_main_menu_window(main_menu_window, from_window = False) + + current_config = { + "Menu Map": config["Menu Map"], + "Menu Tint": config["Menu Tint"], + "Menu Ambient": config["Menu Ambient"], + "Menu Vignette Outer": config["Menu Vignette Outer"], + "Menu Vignette Inner": config["Menu Vignette Inner"], + "Menu Music": config["Menu Music"], + "Menu Map Color": config["Menu Map Color"], + "Menu Reflection Scale": config["Menu Reflection Scale"], + "Menu Reflection Type": config["Menu Reflection Type"], + "Menu Camera Mode": config["Menu Camera Mode"], + "Menu Logo Text": config["Menu Logo Text"] + } + + for x in self.previous_config: + if current_config[x] != self.previous_config[x]: + bs.pushcall(lambda: bs.new_host_session(menu.MainMenuSession)) + break + + # ba_meta export plugin class Plugin(ba.Plugin): def on_app_running(self): @@ -2073,3 +4132,4 @@ def on_app_running(self): True, True, True, True, True, True, True, True, True ], True ) + From b6d7c56070fd6a937fbed3fb2c170ef218b6c97c Mon Sep 17 00:00:00 2001 From: Freaku17 Date: Fri, 29 Dec 2023 11:34:53 +0000 Subject: [PATCH 0788/1464] [ci] auto-format --- plugins/utilities/menu_theme.py | 110 ++++++++++++-------------------- 1 file changed, 42 insertions(+), 68 deletions(-) diff --git a/plugins/utilities/menu_theme.py b/plugins/utilities/menu_theme.py index 747d3105..f3f19cac 100644 --- a/plugins/utilities/menu_theme.py +++ b/plugins/utilities/menu_theme.py @@ -2078,31 +2078,6 @@ def new_back(self, save_state: bool = True): snowee, rikko, & unknown ——————————————————————————————————————— """ -from __future__ import annotations - -from typing import List, Sequence, Callable, Any, cast - -from baenv import TARGET_BALLISTICA_BUILD -from bascenev1lib.mainmenu import MainMenuActivity, NewsDisplay, _preload1 -from bauiv1lib.mainmenu import MainMenuWindow -from bauiv1lib.account.settings import AccountSettingsWindow -from bauiv1lib.colorpicker import ColorPicker, ColorPickerExact -from bauiv1lib.fileselector import FileSelectorWindow -from bauiv1lib.popup import PopupMenuWindow - -import _bauiv1 as _bui -import _bascenev1 as _bs -import _babase as _ba - -import babase as ba -import bascenev1 as bs -import bauiv1 as bui -import bascenev1lib.mainmenu as menu -import json -import os -import shutil -import random -import weakref # defined version and author @@ -3434,11 +3409,11 @@ def on_transition_in(self): if TARGET_BALLISTICA_BUILD < 21697: bs.app.ui_v1.set_main_menu_window( KioskWindow().get_root_widget(), - ) + ) else: bs.app.ui_v1.set_main_menu_window( - KioskWindow().get_root_widget(), from_window = False - ) + KioskWindow().get_root_widget(), from_window=False + ) # ..or in normal cases go back to the main menu else: if main_menu_location == 'Gather': @@ -3447,24 +3422,24 @@ def on_transition_in(self): if TARGET_BALLISTICA_BUILD < 21697: bs.app.ui_v1.set_main_menu_window( - GatherWindow(transition=None).get_root_widget(), - ) + GatherWindow(transition=None).get_root_widget(), + ) else: bs.app.ui_v1.set_main_menu_window( - GatherWindow(transition=None).get_root_widget(), from_window = False - ) + GatherWindow(transition=None).get_root_widget(), from_window=False + ) elif main_menu_location == 'Watch': # pylint: disable=cyclic-import from bauiv1lib.watch import WatchWindow if TARGET_BALLISTICA_BUILD < 21697: bs.app.ui_v1.set_main_menu_window( - WatchWindow(transition=None).get_root_widget(), - ) + WatchWindow(transition=None).get_root_widget(), + ) else: bs.app.ui_v1.set_main_menu_window( - WatchWindow(transition=None).get_root_widget(), from_window = False - ) + WatchWindow(transition=None).get_root_widget(), from_window=False + ) elif main_menu_location == 'Team Game Select': # pylint: disable=cyclic-import from bauiv1lib.playlist.browser import ( @@ -3473,16 +3448,16 @@ def on_transition_in(self): if TARGET_BALLISTICA_BUILD < 21697: bs.app.ui_v1.set_main_menu_window( - PlaylistBrowserWindow( - sessiontype=bs.DualTeamSession, transition=None - ).get_root_widget(), - ) + PlaylistBrowserWindow( + sessiontype=bs.DualTeamSession, transition=None + ).get_root_widget(), + ) else: bs.app.ui_v1.set_main_menu_window( - PlaylistBrowserWindow( - sessiontype=bs.DualTeamSession, transition=None - ).get_root_widget(), from_window = False - ) + PlaylistBrowserWindow( + sessiontype=bs.DualTeamSession, transition=None + ).get_root_widget(), from_window=False + ) elif main_menu_location == 'Free-for-All Game Select': # pylint: disable=cyclic-import from bauiv1lib.playlist.browser import ( @@ -3491,54 +3466,54 @@ def on_transition_in(self): if TARGET_BALLISTICA_BUILD < 21697: bs.app.ui_v1.set_main_menu_window( - PlaylistBrowserWindow( - sessiontype=bs.FreeForAllSession, - transition=None, - ).get_root_widget(), - ) + PlaylistBrowserWindow( + sessiontype=bs.FreeForAllSession, + transition=None, + ).get_root_widget(), + ) else: bs.app.ui_v1.set_main_menu_window( - PlaylistBrowserWindow( - sessiontype=bs.FreeForAllSession, - transition=None, - ).get_root_widget(), from_window = False - ) + PlaylistBrowserWindow( + sessiontype=bs.FreeForAllSession, + transition=None, + ).get_root_widget(), from_window=False + ) elif main_menu_location == 'Coop Select': # pylint: disable=cyclic-import from bauiv1lib.coop.browser import CoopBrowserWindow if TARGET_BALLISTICA_BUILD < 21697: bs.app.ui_v1.set_main_menu_window( - CoopBrowserWindow(transition=None).get_root_widget(), - ) + CoopBrowserWindow(transition=None).get_root_widget(), + ) else: bs.app.ui_v1.set_main_menu_window( - CoopBrowserWindow(transition=None).get_root_widget(), from_window = False - ) + CoopBrowserWindow(transition=None).get_root_widget(), from_window=False + ) elif main_menu_location == 'Benchmarks & Stress Tests': # pylint: disable=cyclic-import from bauiv1lib.debug import DebugWindow if TARGET_BALLISTICA_BUILD < 21697: bs.app.ui_v1.set_main_menu_window( - DebugWindow(transition=None).get_root_widget(), - ) + DebugWindow(transition=None).get_root_widget(), + ) else: bs.app.ui_v1.set_main_menu_window( - DebugWindow(transition=None).get_root_widget(), from_window = False - ) + DebugWindow(transition=None).get_root_widget(), from_window=False + ) else: # pylint: disable=cyclic-import from bauiv1lib.mainmenu import MainMenuWindow if TARGET_BALLISTICA_BUILD < 21697: bs.app.ui_v1.set_main_menu_window( - MainMenuWindow(transition=None).get_root_widget(), - ) + MainMenuWindow(transition=None).get_root_widget(), + ) else: bs.app.ui_v1.set_main_menu_window( - MainMenuWindow(transition=None).get_root_widget(), from_window = False - ) + MainMenuWindow(transition=None).get_root_widget(), from_window=False + ) if not specialoffer.show_offer(): @@ -4093,7 +4068,7 @@ def new_back(self, save_state: bool = True): if TARGET_BALLISTICA_BUILD < 21697: bui.app.ui_v1.set_main_menu_window(main_menu_window,) else: - bui.app.ui_v1.set_main_menu_window(main_menu_window, from_window = False) + bui.app.ui_v1.set_main_menu_window(main_menu_window, from_window=False) current_config = { "Menu Map": config["Menu Map"], @@ -4132,4 +4107,3 @@ def on_app_running(self): True, True, True, True, True, True, True, True, True ], True ) - From 3796c78b57900936e4236eac618235150c71a21a Mon Sep 17 00:00:00 2001 From: ! Freaku <92618708+Freaku17@users.noreply.github.com> Date: Fri, 29 Dec 2023 17:06:05 +0530 Subject: [PATCH 0789/1464] Update utilities.json --- plugins/utilities.json | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/plugins/utilities.json b/plugins/utilities.json index 64520ef4..e04925b0 100644 --- a/plugins/utilities.json +++ b/plugins/utilities.json @@ -895,12 +895,7 @@ } ], "versions": { - "1.0.1": { - "api_version": 8, - "commit_sha": "d938b07", - "released_on": "25-12-2023", - "md5sum": "26401c0480745cb0ebd5be7dfcf6fd2e" - }, + "1.0.1": null, "1.0.0": { "api_version": 8, "commit_sha": "f829aca", @@ -959,4 +954,4 @@ } } } -} \ No newline at end of file +} From 3850dba5b8e89587a641d040f1103c731b21416b Mon Sep 17 00:00:00 2001 From: Freaku17 Date: Fri, 29 Dec 2023 11:36:26 +0000 Subject: [PATCH 0790/1464] [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 e04925b0..4fa90d67 100644 --- a/plugins/utilities.json +++ b/plugins/utilities.json @@ -895,7 +895,12 @@ } ], "versions": { - "1.0.1": null, + "1.0.1": { + "api_version": 8, + "commit_sha": "3796c78", + "released_on": "29-12-2023", + "md5sum": "de3e44d05e20a7e03441db4078057c10" + }, "1.0.0": { "api_version": 8, "commit_sha": "f829aca", @@ -954,4 +959,4 @@ } } } -} +} \ No newline at end of file From b864bc24e68ea8213c306d7cfc103251006ffff5 Mon Sep 17 00:00:00 2001 From: ! Freaku <92618708+Freaku17@users.noreply.github.com> Date: Fri, 29 Dec 2023 17:08:24 +0530 Subject: [PATCH 0791/1464] Fix oops --- plugins/utilities/menu_theme.py | 2118 +------------------------------ 1 file changed, 42 insertions(+), 2076 deletions(-) diff --git a/plugins/utilities/menu_theme.py b/plugins/utilities/menu_theme.py index f3f19cac..98d1371e 100644 --- a/plugins/utilities/menu_theme.py +++ b/plugins/utilities/menu_theme.py @@ -2,7 +2,7 @@ """ Working for v1.7.20+ only ——————————————————————————————————————— -• Menu Theme v1.0.9 +• Menu Theme v1.0.10 • discord: riyukiiyan I appreciate any kind of modification. So feel free to share, edit and change credit string... no problem @@ -1375,2045 +1375,11 @@ def on_transition_in(self): if TARGET_BALLISTICA_BUILD < 21697: bs.app.ui_v1.set_main_menu_window( KioskWindow().get_root_widget(), - ) - else: - bs.app.ui_v1.set_main_menu_window( - KioskWindow().get_root_widget(), from_window=self._root_widget - ) - # ..or in normal cases go back to the main menu - else: - if main_menu_location == 'Gather': - # pylint: disable=cyclic-import - from bauiv1lib.gather import GatherWindow - - if TARGET_BALLISTICA_BUILD < 21697: - bs.app.ui_v1.set_main_menu_window( - GatherWindow(transition=None).get_root_widget(), - ) - else: - bs.app.ui_v1.set_main_menu_window( - GatherWindow(transition=None).get_root_widget(), from_window=self._root_widget - ) - elif main_menu_location == 'Watch': - # pylint: disable=cyclic-import - from bauiv1lib.watch import WatchWindow - - if TARGET_BALLISTICA_BUILD < 21697: - bs.app.ui_v1.set_main_menu_window( - WatchWindow(transition=None).get_root_widget(), - ) - else: - bs.app.ui_v1.set_main_menu_window( - WatchWindow(transition=None).get_root_widget(), from_window=self._root_widget - ) - elif main_menu_location == 'Team Game Select': - # pylint: disable=cyclic-import - from bauiv1lib.playlist.browser import ( - PlaylistBrowserWindow, - ) - - if TARGET_BALLISTICA_BUILD < 21697: - bs.app.ui_v1.set_main_menu_window( - PlaylistBrowserWindow( - sessiontype=bs.DualTeamSession, transition=None - ).get_root_widget(), - ) - else: - bs.app.ui_v1.set_main_menu_window( - PlaylistBrowserWindow( - sessiontype=bs.DualTeamSession, transition=None - ).get_root_widget(), from_window=self._root_widget - ) - elif main_menu_location == 'Free-for-All Game Select': - # pylint: disable=cyclic-import - from bauiv1lib.playlist.browser import ( - PlaylistBrowserWindow, - ) - - if TARGET_BALLISTICA_BUILD < 21697: - bs.app.ui_v1.set_main_menu_window( - PlaylistBrowserWindow( - sessiontype=bs.FreeForAllSession, - transition=None, - ).get_root_widget(), - ) - else: - bs.app.ui_v1.set_main_menu_window( - PlaylistBrowserWindow( - sessiontype=bs.FreeForAllSession, - transition=None, - ).get_root_widget(), from_window=self._root_widget - ) - elif main_menu_location == 'Coop Select': - # pylint: disable=cyclic-import - from bauiv1lib.coop.browser import CoopBrowserWindow - - if TARGET_BALLISTICA_BUILD < 21697: - bs.app.ui_v1.set_main_menu_window( - CoopBrowserWindow(transition=None).get_root_widget(), - ) - else: - bs.app.ui_v1.set_main_menu_window( - CoopBrowserWindow(transition=None).get_root_widget(), from_window=self._root_widget - ) - elif main_menu_location == 'Benchmarks & Stress Tests': - # pylint: disable=cyclic-import - from bauiv1lib.debug import DebugWindow - - if TARGET_BALLISTICA_BUILD < 21697: - bs.app.ui_v1.set_main_menu_window( - DebugWindow(transition=None).get_root_widget(), - ) - else: - bs.app.ui_v1.set_main_menu_window( - DebugWindow(transition=None).get_root_widget(), from_window=self._root_widget - ) - else: - # pylint: disable=cyclic-import - from bauiv1lib.mainmenu import MainMenuWindow - - if TARGET_BALLISTICA_BUILD < 21697: - bs.app.ui_v1.set_main_menu_window( - MainMenuWindow(transition=None).get_root_widget(), - ) - else: - bs.app.ui_v1.set_main_menu_window( - MainMenuWindow(transition=None).get_root_widget(), from_window=self._root_widget - ) - - if not specialoffer.show_offer(): - - def try_again(): - if not specialoffer.show_offer(): - bui.apptimer(2.0, specialoffer.show_offer) - - bui.apptimer(2.0, try_again) - app.classic.main_menu_did_initial_transition = True - - def load_map_stuff(self): - m = bs.getmesh - t = bs.gettexture - map_type = config["Menu Map"] - if map_type == "The Pad (with trees)": - self.main = bs.NodeActor(bs.newnode( - 'terrain', - delegate=self, - attrs={ - 'mesh': m('thePadLevel'), - 'color_texture': t('thePadLevelColor'), - 'reflection': 'soft', - 'reflection_scale': [0.3] - })) - self.trees = bs.NodeActor(bs.newnode( - 'terrain', - attrs={ - 'mesh': m('trees'), - 'lighting': False, - 'reflection': 'char', - 'reflection_scale': [0.1], - 'color_texture': t('treesColor') - })) - self.bgterrain = bs.NodeActor(bs.newnode( - 'terrain', - attrs={ - 'mesh': m('thePadBG'), - 'color': (0.92, 0.91, 0.9), - 'lighting': False, - 'background': True, - 'color_texture': t('menuBG'), - })) - self.bottom = bs.NodeActor(bs.newnode( - 'terrain', - attrs={ - 'mesh': m('thePadLevelBottom'), - 'lighting': False, - 'reflection': 'soft', - 'reflection_scale': [0.45], - 'color_texture': t('thePadLevelColor') - })) - elif map_type == "The Pad": - self.main = bs.NodeActor(bs.newnode( - 'terrain', - delegate=self, - attrs={ - 'mesh': m('thePadLevel'), - 'color_texture': t('thePadLevelColor'), - 'reflection': 'soft', - 'reflection_scale': [0.3] - })) - self.bgterrain = bs.NodeActor(bs.newnode( - 'terrain', - attrs={ - 'mesh': m('thePadBG'), - 'color': (0.92, 0.91, 0.9), - 'lighting': False, - 'background': True, - 'color_texture': t("menuBG") - })) - self.bottom = bs.NodeActor(bs.newnode( - 'terrain', - attrs={ - 'mesh': m('thePadLevelBottom'), - 'lighting': False, - 'reflection': 'soft', - 'reflection_scale': [0.45], - 'color_texture': t('thePadLevelColor') - })) - elif map_type == "Hockey Stadium": - self.main = bs.NodeActor(bs.newnode( - 'terrain', - delegate=self, - attrs={ - 'mesh': m('hockeyStadiumOuter'), - 'color_texture': t('hockeyStadium'), - 'reflection': 'soft', - 'reflection_scale': [0.3] - })) - self.inner = bs.NodeActor(bs.newnode( - 'terrain', - attrs={ - 'mesh': m('hockeyStadiumInner'), - 'opacity': 0.92, - 'opacity_in_low_or_ui_medium_quality': 1.0, - 'color_texture': t('hockeyStadium') - })) - self.stands = bs.NodeActor(bs.newnode( - 'terrain', - attrs={ - 'mesh': m('hockeyStadiumStands'), - 'visible_in_reflections': False, - 'color_texture': t('footballStadium') - })) - elif map_type == "Football Stadium": - self.main = bs.NodeActor(bs.newnode( - 'terrain', - delegate=self, - attrs={ - 'mesh': m('footballStadium'), - 'color_texture': t('footballStadium'), - })) - elif map_type == "Bridgit": - self.main = bs.NodeActor(bs.newnode( - 'terrain', - delegate=self, - attrs={ - 'mesh': m('bridgitLevelTop'), - 'color_texture': t('bridgitLevelColor'), - })) - self.bottom = bs.NodeActor(bs.newnode( - 'terrain', - attrs={ - 'mesh': m('bridgitLevelBottom'), - 'lighting': False, - 'color_texture': t('bridgitLevelColor'), - })) - self.background = bs.NodeActor(bs.newnode( - 'terrain', - attrs={ - 'mesh': m('natureBackground'), - 'lighting': False, - 'background': True, - 'color_texture': t('natureBackgroundColor'), - })) - elif map_type == "Big G": - self.main = bs.NodeActor(bs.newnode( - 'terrain', - delegate=self, - attrs={ - 'mesh': m('bigG'), - 'color': (0.7, 0.7, 0.7), - 'color_texture': t('bigG'), - })) - self.bottom = bs.NodeActor(bs.newnode( - 'terrain', - attrs={ - 'mesh': m('bigGBottom'), - 'lighting': False, - 'color': (0.7, 0.7, 0.7), - 'color_texture': t('bigG'), - })) - self.background = bs.NodeActor(bs.newnode( - 'terrain', - attrs={ - 'mesh': m('natureBackground'), - 'lighting': False, - 'background': True, - 'color_texture': t('natureBackgroundColor'), - })) - elif map_type == "Roundabout": - self.main = bs.NodeActor(bs.newnode( - 'terrain', - delegate=self, - attrs={ - 'mesh': m('roundaboutLevel'), - 'color': (0.7, 0.7, 0.7), - 'color_texture': t('roundaboutLevelColor'), - })) - self.bottom = bs.NodeActor(bs.newnode( - 'terrain', - attrs={ - 'mesh': m('roundaboutLevelBottom'), - 'lighting': False, - 'color': (0.7, 0.7, 0.7), - 'color_texture': t('roundaboutLevelColor'), - })) - self.background = bs.NodeActor(bs.newnode( - 'terrain', - attrs={ - 'mesh': m('natureBackground'), - 'lighting': False, - 'background': True, - 'color_texture': t('natureBackgroundColor'), - })) - elif map_type == "Monkey Face": - self.main = bs.NodeActor(bs.newnode( - 'terrain', - delegate=self, - attrs={ - 'mesh': m('monkeyFaceLevel'), - 'color_texture': t('monkeyFaceLevelColor'), - })) - self.bottom = bs.NodeActor(bs.newnode( - 'terrain', - attrs={ - 'mesh': m('monkeyFaceLevelBottom'), - 'lighting': False, - 'color_texture': t('monkeyFaceLevelColor'), - })) - self.background = bs.NodeActor(bs.newnode( - 'terrain', - attrs={ - 'mesh': m('natureBackground'), - 'lighting': False, - 'color_texture': t('natureBackgroundColor'), - })) - elif map_type == "Monkey Face": - self.main = bs.NodeActor(bs.newnode( - 'terrain', - delegate=self, - attrs={ - 'mesh': m('monkeyFaceLevel'), - 'color_texture': t('monkeyFaceLevelColor'), - })) - self.bottom = bs.NodeActor(bs.newnode( - 'terrain', - attrs={ - 'mesh': m('monkeyFaceLevelBottom'), - 'lighting': False, - 'color_texture': t('monkeyFaceLevelColor'), - })) - self.background = bs.NodeActor(bs.newnode( - 'terrain', - attrs={ - 'mesh': m('natureBackground'), - 'lighting': False, - 'color_texture': t('natureBackgroundColor'), - })) - elif map_type == "Zig Zag": - self.main = bs.NodeActor(bs.newnode( - 'terrain', - delegate=self, - attrs={ - 'mesh': m('zigZagLevel'), - 'color_texture': t('zigZagLevelColor'), - })) - self.bottom = bs.NodeActor(bs.newnode( - 'terrain', - attrs={ - 'mesh': m('zigZagLevelBottom'), - 'lighting': False, - 'color_texture': t('zigZagLevelColor'), - })) - self.background = bs.NodeActor(bs.newnode( - 'terrain', - attrs={ - 'mesh': m('natureBackground'), - 'lighting': False, - 'color_texture': t('natureBackgroundColor'), - })) - elif map_type == "Doom Shroom": - self.main = bs.NodeActor(bs.newnode( - 'terrain', - delegate=self, - attrs={ - 'mesh': m('doomShroomLevel'), - 'color_texture': t('doomShroomLevelColor'), - })) - self.stem = bs.NodeActor(bs.newnode( - 'terrain', - attrs={ - 'mesh': m('doomShroomStem'), - 'lighting': False, - 'color_texture': t('doomShroomLevelColor'), - })) - self.background = bs.NodeActor(bs.newnode( - 'terrain', - attrs={ - 'mesh': m('doomShroomBG'), - 'lighting': False, - 'background': True, - 'color_texture': t('doomShroomBGColor'), - })) - elif map_type == "Lake Frigid": - self.main = bs.NodeActor(bs.newnode( - 'terrain', - delegate=self, - attrs={ - 'mesh': m('lakeFrigid'), - 'color_texture': t('lakeFrigid'), - })) - self.top = bs.NodeActor(bs.newnode( - 'terrain', - attrs={ - 'mesh': m('lakeFrigidTop'), - 'lighting': False, - 'color_texture': t('lakeFrigid'), - })) - self.reflections = bs.NodeActor(bs.newnode( - 'terrain', - attrs={ - 'mesh': m('lakeFrigidReflections'), - 'lighting': False, - 'overlay': True, - 'opacity': 0.15, - 'color_texture': t('lakeFrigidReflections'), - })) - elif map_type == "Tip Top": - self.main = bs.NodeActor(bs.newnode( - 'terrain', - delegate=self, - attrs={ - 'mesh': m('tipTopLevel'), - 'color': (0.7, 0.7, 0.7), - 'color_texture': t('tipTopLevelColor'), - })) - self.bottom = bs.NodeActor(bs.newnode( - 'terrain', - attrs={ - 'mesh': m('tipTopLevelBottom'), - 'lighting': False, - 'color': (0.7, 0.7, 0.7), - 'color_texture': t('tipTopLevelColor'), - })) - self.background = bs.NodeActor(bs.newnode( - 'terrain', - attrs={ - 'mesh': m('tipTopBG'), - 'lighting': False, - 'color': (0.4, 0.4, 0.4), - 'background': True, - 'color_texture': t('tipTopBGColor'), - })) - elif map_type == "Crag Castle": - self.main = bs.NodeActor(bs.newnode( - 'terrain', - delegate=self, - attrs={ - 'mesh': m('cragCastleLevel'), - 'color_texture': t('cragCastleLevelColor'), - })) - self.bottom = bs.NodeActor(bs.newnode( - 'terrain', - attrs={ - 'mesh': m('cragCastleLevelBottom'), - 'lighting': False, - 'color_texture': t('cragCastleLevelColor'), - })) - self.background = bs.NodeActor(bs.newnode( - 'terrain', - attrs={ - 'mesh': m('thePadBG'), - 'lighting': False, - 'background': True, - 'color_texture': t('menuBG'), - })) - elif map_type == "Tower D": - self.main = bs.NodeActor(bs.newnode( - 'terrain', - delegate=self, - attrs={ - 'mesh': m('towerDLevel'), - 'color_texture': t('towerDLevelColor'), - })) - self.bottom = bs.NodeActor(bs.newnode( - 'terrain', - attrs={ - 'mesh': m('towerDLevelBottom'), - 'lighting': False, - 'color_texture': t('towerDLevelColor'), - })) - self.background = bs.NodeActor(bs.newnode( - 'terrain', - attrs={ - 'mesh': m('thePadBG'), - 'lighting': False, - 'background': True, - 'color_texture': t('menuBG'), - })) - elif map_type == "Happy Thoughts": - self.main = bs.NodeActor(bs.newnode( - 'terrain', - delegate=self, - attrs={ - 'mesh': m('alwaysLandLevel'), - 'color_texture': t('alwaysLandLevelColor'), - })) - self.bottom = bs.NodeActor(bs.newnode( - 'terrain', - attrs={ - 'mesh': m('alwaysLandLevelBottom'), - 'lighting': False, - 'color_texture': t('alwaysLandLevelColor'), - })) - self.background = bs.NodeActor(bs.newnode( - 'terrain', - attrs={ - 'mesh': m('alwaysLandBG'), - 'lighting': False, - 'background': True, - 'color_texture': t('alwaysLandBGColor'), - })) - elif map_type == "Step Right Up": - self.main = bs.NodeActor(bs.newnode( - 'terrain', - delegate=self, - attrs={ - 'mesh': m('stepRightUpLevel'), - 'color_texture': t('stepRightUpLevelColor'), - })) - self.bottom = bs.NodeActor(bs.newnode( - 'terrain', - attrs={ - 'mesh': m('stepRightUpLevelBottom'), - 'lighting': False, - 'color_texture': t('stepRightUpLevelColor'), - })) - self.background = bs.NodeActor(bs.newnode( - 'terrain', - attrs={ - 'mesh': m('thePadBG'), - 'lighting': False, - 'background': True, - 'color_texture': t('menuBG'), - })) - elif map_type == "Courtyard": - self.main = bs.NodeActor(bs.newnode( - 'terrain', - delegate=self, - attrs={ - 'mesh': m('courtyardLevel'), - 'color_texture': t('courtyardLevelColor'), - })) - self.bottom = bs.NodeActor(bs.newnode( - 'terrain', - attrs={ - 'mesh': m('courtyardLevelBottom'), - 'lighting': False, - 'color_texture': t('courtyardLevelColor'), - })) - self.background = bs.NodeActor(bs.newnode( - 'terrain', - attrs={ - 'mesh': m('thePadBG'), - 'lighting': False, - 'background': True, - 'color_texture': t('menuBG'), - })) - elif map_type == "Rampage": - self.main = bs.NodeActor(bs.newnode( - 'terrain', - delegate=self, - attrs={ - 'mesh': m('rampageLevel'), - 'color_texture': t('rampageLevelColor'), - })) - self.bottom = bs.NodeActor(bs.newnode( - 'terrain', - attrs={ - 'mesh': m('rampageLevelBottom'), - 'lighting': False, - 'color_texture': t('rampageLevelColor'), - })) - self.background = bs.NodeActor(bs.newnode( - 'terrain', - attrs={ - 'mesh': m('rampageBG'), - 'lighting': False, - 'background': True, - 'color_texture': t('rampageBGColor'), - })) - self.background_2 = bs.NodeActor(bs.newnode( - 'terrain', - attrs={ - 'mesh': m('rampageBG2'), - 'lighting': False, - 'background': True, - 'color_texture': t('rampageBGColor2'), - })) - - -def menu_theme(self): - this_class = self - MenuThemeWindow(accounts_window=this_class) - - -def handle_config(keys: List[str], adding: bool = False): - our_config = { - "Menu Map": keys[0], - "Menu Tint": keys[1], - "Menu Ambient": keys[2], - "Menu Vignette Outer": keys[3], - "Menu Vignette Inner": keys[4], - "Menu Music": keys[5], - "Menu Map Color": keys[6], - "Menu Reflection Scale": keys[7], - "Menu Reflection Type": keys[8], - "Menu Camera Mode": keys[9], - "Menu Logo Text": keys[10], - "vignette_outer": keys[11], - "vignette_inner": keys[12], - "ambient_color": keys[13], - "tint": keys[14], - "map_color": keys[15], - "map_reflection_scale": keys[16], - "map_reflection_type": keys[17] - } - config_keys = list(our_config.keys()) - p = 0 - - for cf in config_keys: - if cf not in bs.app.config and adding: - config[cf] = keys[p] - elif our_config[cf] is not None and not adding: - config[cf] = keys[p] - p += 1 - bs.app.config.apply_and_commit() - - -def new_init(self, *args, **kwargs): - original_account_init(self, *args, **kwargs) - - self._menu_theme = bui.buttonwidget( - parent=self._root_widget, - position=((470, 330) if ui_type is ui_small else - (420, 434) if ui_type is ui_large else (445, 374)), - scale=(1.2 if ui_type is ui_small else - 1.3 if ui_type is ui_large else 1.0), - size=(160, 30) if ui_type is ui_small else (167, 30), - color=(0.55, 0.7, 0.63), - text_scale=(0.7 if ui_type is ui_medium else - 0.65 if ui_type is ui_large else 0.5), - autoselect=False, - button_type="regular", - label="Menu Theme", - on_activate_call=self.menu_theme - ) - self.previous_config = { - "Menu Map": config["Menu Map"], - "Menu Tint": config["Menu Tint"], - "Menu Ambient": config["Menu Ambient"], - "Menu Vignette Outer": config["Menu Vignette Outer"], - "Menu Vignette Inner": config["Menu Vignette Inner"], - "Menu Music": config["Menu Music"], - "Menu Map Color": config["Menu Map Color"], - "Menu Reflection Scale": config["Menu Reflection Scale"], - "Menu Reflection Type": config["Menu Reflection Type"], - "Menu Camera Mode": config["Menu Camera Mode"], - "Menu Logo Text": config["Menu Logo Text"] - } - - -def new_back(self, save_state: bool = True): - assert bui.app.classic is not None - if save_state: - self._save_state() - - bui.containerwidget(edit=self._root_widget, transition=self._transition_out) - - main_menu_window = MainMenuWindow(transition='in_left').get_root_widget() - if TARGET_BALLISTICA_BUILD < 21697: - bui.app.ui_v1.set_main_menu_window(main_menu_window,) - else: - bui.app.ui_v1.set_main_menu_window(main_menu_window, from_window=self._root_widget) - - current_config = { - "Menu Map": config["Menu Map"], - "Menu Tint": config["Menu Tint"], - "Menu Ambient": config["Menu Ambient"], - "Menu Vignette Outer": config["Menu Vignette Outer"], - "Menu Vignette Inner": config["Menu Vignette Inner"], - "Menu Music": config["Menu Music"], - "Menu Map Color": config["Menu Map Color"], - "Menu Reflection Scale": config["Menu Reflection Scale"], - "Menu Reflection Type": config["Menu Reflection Type"], - "Menu Camera Mode": config["Menu Camera Mode"], - "Menu Logo Text": config["Menu Logo Text"] - } - - for x in self.previous_config: - if current_config[x] != self.previous_config[x]: - bs.pushcall(lambda: bs.new_host_session(menu.MainMenuSession)) - break - - -# ba_meta export plugin -# ba_meta require api 8 -""" -Working for v1.7.20+ only -——————————————————————————————————————— -• Menu Theme v1.0.9 -• discord: riyukiiyan - -I appreciate any kind of modification. So feel free to share, edit and change credit string... no problem -Credits are unnecessary but are a much-appreciated gesture to show support to others :D - -[CHANGELOG]: -~ Support for BombSquad v1.7.26 -~ Fixed "Show Logo Text" checkmark not updating on imports and reset -~ Music changes: - >> Turn off music by selecting 'None' - >> Removed dupes, renamed some and added 2 new musics - -Special thanks to: -snowee, rikko, & unknown -——————————————————————————————————————— -""" - - -# defined version and author -__author__ = "Yann" -__version__ = "1.0.10" - -if TARGET_BALLISTICA_BUILD < 21282: - # These attributes have been deprecated as of 1.7.27. For more info see: - # https://github.com/efroemling/ballistica/blob/master/CHANGELOG.md#1727-build-21282-api-8-2023-08-30 - # Adding a compatibility layer here so older builds still work fine. - class Dummy: - pass - babase = ba - babase.app.env = Dummy() - - babase.app.env.build_number = babase.app.build_number - babase.app.env.device_name = babase.app.device_name - babase.app.env.config_file_path = babase.app.config_file_path - babase.app.env.version = babase.app.version - babase.app.env.debug = babase.app.debug_build - babase.app.env.test = babase.app.test_build - babase.app.env.data_directory = babase.app.data_directory - babase.app.env.python_directory_user = babase.app.python_directory_user - babase.app.env.python_directory_app = babase.app.python_directory_app - babase.app.env.python_directory_app_site = babase.app.python_directory_app_site - babase.app.env.api_version = babase.app.api_version - babase.app.env.tv = babase.app.on_tv - babase.app.env.vr = babase.app.vr_mode - babase.app.env.arcade = babase.app.arcade_mode - babase.app.env.headless = babase.app.arcade_mode - babase.app.env.demo = babase.app.demo_mode - protocol_version = babase.app.protocol_version - toolbar_test = babase.app.toolbar_test -else: - protocol_version = _bs.protocol_version - toolbar_test = _bui.toolbar_test() - -# frequently used variables references -config = bs.app.config -ui_type = bs.app.ui_v1.uiscale -ui_small = bs.UIScale.SMALL -ui_medium = bs.UIScale.MEDIUM -ui_large = bs.UIScale.LARGE - -# method references -original_unlocked_pro = bs.app.classic.accounts.have_pro -original_account_init = AccountSettingsWindow.__init__ - -# define globals -GLOBALS_REFLECTION = { - 'Powerup': 'powerup', - 'Character': 'char', - 'Soft': 'soft', - 'None': 'none' -} -GLOBALS_MUSIC = { - 'Menu': bs.MusicType.MENU, - 'Epic': bs.MusicType.EPIC, - 'Flag Catcher': bs.MusicType.FLAG_CATCHER, - 'Flying': bs.MusicType.FLYING, - 'Grand Romp': bs.MusicType.GRAND_ROMP, - 'Lobby': bs.MusicType.CHAR_SELECT, - 'Lobby Epic': bs.MusicType.SCORES, - 'Marching Forward': bs.MusicType.FORWARD_MARCH, - 'Marching Home': bs.MusicType.MARCHING, - 'Run Away': bs.MusicType.RUN_AWAY, - 'Scary': bs.MusicType.SCARY, - 'Sports': bs.MusicType.SPORTS, - 'Survival': bs.MusicType.SURVIVAL, - 'To The Death': bs.MusicType.TO_THE_DEATH, - 'None': None, -} -GLOBALS_MAPDATA = { - "The Pad (with trees)": { - "Camera Bounds": (0.3544110667, 4.493562578, -2.518391331, 16.64754831, 8.06138989, 18.5029888), - "Map Color": (1.0, 1.0, 1.0), - "Map Reflection Scale": 0.3, - "Ambient": (1.14, 1.1, 1.0), - "Tint": (1.06, 1.04, 1.03), - "Vignette Outer": (0.45, 0.55, 0.54), - "Vignette Inner": (0.99, 0.98, 0.98) - }, - "The Pad": { - "Camera Bounds": (0.3544110667, 4.493562578, -2.518391331, 16.64754831, 8.06138989, 18.5029888), - "Map Color": (1.0, 1.0, 1.0), - "Map Reflection Scale": 0.3, - "Ambient": (1.1, 1.1, 1.0), - "Tint": (1.1, 1.1, 1.0), - "Vignette Outer": (0.7, 0.65, 0.75), - "Vignette Inner": (0.95, 0.95, 0.93) - }, - "Big G": { - "Camera Bounds": (-0.4011866709, 2.331310176, -0.5426286416, 19.11746262, 10.19675564, 23.50119277), - "Map Color": (0.7, 0.7, 0.7), - "Map Reflection Scale": 0.0, - "Ambient": (1.1, 1.2, 1.3), - "Tint": (1.1, 1.2, 1.3), - "Vignette Outer": (0.65, 0.6, 0.55), - "Vignette Inner": (0.9, 0.9, 0.93) - }, - "Bridgit": { - "Camera Bounds": (-0.2457963347, 3.828181068, -1.528362695, 19.14849937, 7.312788846, 8.436232726), - "Map Color": (1.0, 1.0, 1.0), - "Map Reflection Scale": 0.0, - "Ambient": (1.1, 1.2, 1.3), - "Tint": (1.1, 1.2, 1.3), - "Vignette Outer": (0.65, 0.6, 0.55), - "Vignette Inner": (0.9, 0.9, 0.93) - }, - "Courtyard": { - "Camera Bounds": (0.3544110667, 3.958431362, -2.175025358, 16.37702017, 7.755670126, 13.38680645), - "Map Color": (1.0, 1.0, 1.0), - "Map Reflection Scale": 0.0, - "Ambient": (1.2, 1.17, 1.1), - "Tint": (1.2, 1.17, 1.1), - "Vignette Outer": (0.6, 0.6, 0.64), - "Vignette Inner": (0.95, 0.95, 0.93) - }, - "Crag Castle": { - "Camera Bounds": (0.7033834902, 6.55869393, -3.153439808, 16.73648528, 14.94789935, 11.60063102), - "Map Color": (1.0, 1.0, 1.0), - "Map Reflection Scale": 0.0, - "Ambient": (1.15, 1.05, 0.75), - "Tint": (1.15, 1.05, 0.75), - "Vignette Outer": (0.6, 0.65, 0.6), - "Vignette Inner": (0.95, 0.95, 0.95) - }, - "Doom Shroom": { - "Camera Bounds": (0.4687647786, 2.320345088, -3.219423694, 21.34898078, 10.25529817, 14.67298352), - "Map Color": (1.0, 1.0, 1.0), - "Map Reflection Scale": 0.0, - "Ambient": (0.9, 1.3, 1.1), - "Tint": (0.82, 1.10, 1.15), - "Vignette Outer": (0.76, 0.76, 0.76), - "Vignette Inner": (0.95, 0.95, 0.99) - }, - "Happy Thoughts": { - "Camera Bounds": (-1.045859963, 12.67722855, -5.401537075, 34.46156851, 20.94044653, 0.6931564611), - "Map Color": (1.0, 1.0, 1.0), - "Map Reflection Scale": 0.0, - "Ambient": (1.3, 1.23, 1.0), - "Tint": (1.3, 1.23, 1.0), - "Vignette Outer": (0.64, 0.59, 0.69), - "Vignette Inner": (0.95, 0.95, 0.93) - }, - "Football Stadium": { - "Camera Bounds": (0.0, 1.185751251, 0.4326226188, 29.8180273, 11.57249038, 18.89134176), - "Map Color": (1.0, 1.0, 1.0), - "Map Reflection Scale": 0.0, - "Ambient": (1.3, 1.2, 1.0), - "Tint": (1.3, 1.2, 1.0), - "Vignette Outer": (0.57, 0.57, 0.57), - "Vignette Inner": (0.9, 0.9, 0.9) - }, - "Hockey Stadium": { - "Camera Bounds": (0.0, 0.7956858119, 0.0, 30.80223883, 0.5961646365, 13.88431707), - "Map Color": (1.0, 1.0, 1.0), - "Map Reflection Scale": 0.3, - "Ambient": (1.15, 1.25, 1.6), - "Tint": (1.2, 1.3, 1.33), - "Vignette Outer": (0.66, 0.67, 0.73), - "Vignette Inner": (0.93, 0.93, 0.95) - }, - "Lake Frigid": { - "Camera Bounds": (0.622753268, 3.958431362, -2.48708008, 20.62310543, 7.755670126, 12.33155049), - "Map Color": (1.0, 1.0, 1.0), - "Map Reflection Scale": 0.0, - "Ambient": (1, 1, 1), - "Tint": (1, 1, 1), - "Vignette Outer": (0.86, 0.86, 0.86), - "Vignette Inner": (0.95, 0.95, 0.99) - }, - "Monkey Face": { - "Camera Bounds": (-1.657177611, 4.132574186, -1.580485661, 17.36258946, 10.49020453, 12.31460338), - "Map Color": (1.0, 1.0, 1.0), - "Map Reflection Scale": 0.0, - "Ambient": (1.1, 1.2, 1.2), - "Tint": (1.1, 1.2, 1.2), - "Vignette Outer": (0.60, 0.62, 0.66), - "Vignette Inner": (0.97, 0.95, 0.93) - }, - "Rampage": { - "Camera Bounds": (0.3544110667, 5.616383286, -4.066055072, 19.90053969, 10.34051135, 8.16221072), - "Map Color": (1.0, 1.0, 1.0), - "Map Reflection Scale": 0.0, - "Ambient": (1.3, 1.2, 1.03), - "Tint": (1.2, 1.1, 0.97), - "Vignette Outer": (0.62, 0.64, 0.69), - "Vignette Inner": (0.97, 0.95, 0.93) - }, - "Roundabout": { - "Camera Bounds": (-1.552280404, 3.189001207, -2.40908495, 11.96255385, 8.857531648, 9.531689995), - "Map Color": (0.7, 0.7, 0.7), - "Map Reflection Scale": 0.0, - "Ambient": (1.0, 1.05, 1.1), - "Tint": (1.0, 1.05, 1.1), - "Vignette Outer": (0.63, 0.65, 0.7), - "Vignette Inner": (0.97, 0.95, 0.93) - }, - "Step Right Up": { - "Camera Bounds": (0.3544110667, 6.07676405, -2.271833016, 22.55121262, 10.14644532, 14.66087273), - "Map Color": (1.0, 1.0, 1.0), - "Map Reflection Scale": 0.0, - "Ambient": (1.2, 1.1, 1.0), - "Tint": (1.2, 1.1, 1.0), - "Vignette Outer": (1.2, 1.1, 1.0), - "Vignette Inner": (0.95, 0.95, 0.93) - }, - "Tower D": { - "Camera Bounds": (-0.4714933293, 2.887077774, -1.505479919, 17.90145968, 6.188484831, 15.96149117), - "Map Color": (1.0, 1.0, 1.0), - "Map Reflection Scale": 0.0, - "Ambient": (1.2, 1.1, 1.0), - "Tint": (1.15, 1.11, 1.03), - "Vignette Outer": (1.2, 1.1, 1.0), - "Vignette Inner": (0.95, 0.95, 0.95) - }, - "Tip Top": { - "Camera Bounds": (0.004375512593, 7.141135803, -0.01745294675, 21.12506141, 4.959977313, 16.6885592), - "Map Color": (0.7, 0.7, 0.7), - "Map Reflection Scale": 0.0, - "Ambient": (0.8, 0.9, 1.3), - "Tint": (0.8, 0.9, 1.3), - "Vignette Outer": (0.79, 0.79, 0.69), - "Vignette Inner": (0.97, 0.97, 0.99) - }, - "Zig Zag": { - "Camera Bounds": (-1.807378035, 3.943412768, -1.61304303, 23.01413538, 13.27980464, 10.0098376), - "Map Color": (1.0, 1.0, 1.0), - "Map Reflection Scale": 0.0, - "Ambient": (1.0, 1.15, 1.15), - "Tint": (1.0, 1.15, 1.15), - "Vignette Outer": (0.57, 0.59, 0.63), - "Vignette Inner": (0.97, 0.95, 0.93) - } -} - - -class CustomColorPicker(ColorPicker): - - def _select_other(self): - from bauiv1lib import purchase - - CustomColorPickerExact(parent=self._parent, - position=self._position, - initial_color=self._initial_color, - delegate=self._delegate, - scale=self._scale, - offset=self._offset, - tag=self._tag) - self._delegate = None - self._transition_out() - - -class CustomColorPickerExact(ColorPickerExact): - - def _color_change_press(self, color_name: str, increasing: bool): - current_time = bui.apptime() - since_last = current_time - self._last_press_time - if ( - since_last < 0.2 - and self._last_press_color_name == color_name - and self._last_press_increasing == increasing - ): - self._change_speed += 0.25 - else: - self._change_speed = 1.0 - self._last_press_time = current_time - self._last_press_color_name = color_name - self._last_press_increasing = increasing - - color_index = ('r', 'g', 'b').index(color_name) - offs = int(self._change_speed) * (0.01 if increasing else -0.01) - self._color[color_index] = max( - -1.0, min(2.55, self._color[color_index] + offs) - ) - self._update_for_color() - - -class ConfigCheckBox: - widget: bui.Widget - - def __init__( - self, - parent: bui.Widget, - configkey: str, - position: tuple[float, float], - size: tuple[float, float], - displayname: str | bs.Lstr | None = None, - scale: float | None = None, - maxwidth: float | None = None, - autoselect: bool = True, - value_change_call: Callable[[Any], Any] | None = None): - - if displayname is None: - displayname = configkey - self._value_change_call = value_change_call - self._configkey = configkey - self.widget = bui.checkboxwidget( - parent=parent, - autoselect=autoselect, - position=position, - size=size, - text=displayname, - textcolor=(0.8, 0.8, 0.8), - value=bs.app.config[configkey], - on_value_change_call=self._value_changed, - scale=scale, - maxwidth=maxwidth, - ) - # complain if we outlive our checkbox - bui.uicleanupcheck(self, self.widget) - - def _value_changed(self, val: bool): - cfg = bs.app.config - cfg[self._configkey] = val - if self._value_change_call is not None: - self._value_change_call(val) - cfg.apply_and_commit() - - -class FreeEditWindow(bui.Window): - - def _do_enter(self): - - def _error() -> None: - bui.getsound('error').play(volume=2.0) - bui.screenmessage('error ' + u'😑😑', color=(1.0, 0.0, 0.0)) - - try: - if self.name_only: - value = bui.textwidget(query=self._text_field) - if not value.strip(): - return _error() - - self.delegate._export(self, txt=value) - else: - value = round(float(bui.textwidget(query=self._text_field)), 4) - self.delegate.free_edit_enter(self, c=self.config_name, txt=value) - - except ValueError: - return _error() - bui.containerwidget(edit=self._root_widget, transition=self._transition_out) - - def _activate_enter_button(self): - self._enter_button.activate() - - def _do_back(self): - bui.containerwidget(edit=self._root_widget, transition=self._transition_out) - - def __init__(self, delegate: Any = None, config_name: str = 'Menu Map', whitelist: List = [], name_only: bool = False, origin_widget: bui.widget = None): - self._transition_out = 'out_scale' if origin_widget else 'out_right' - scale_origin = origin_widget.get_screen_space_center() if origin_widget else None - transition = 'in_scale' if origin_widget else 'in_right' - width, height = 450, 230 - uiscale = bs.app.ui_v1.uiscale - - super().__init__(root_widget=bui.containerwidget( - size=(width, height), - transition=transition, - toolbar_visibility='menu_minimal_no_back', - scale_origin_stack_offset=scale_origin, - scale=(2.0 if uiscale is bs.UIScale.SMALL else - 1.5 if uiscale is bs.UIScale.MEDIUM else 1.0))) - - btn = bui.buttonwidget(parent=self._root_widget, - scale=0.5, - position=(40, height - 40), - size=(60, 60), - label='', - on_activate_call=self._do_back, - autoselect=True, - color=(0.55, 0.5, 0.6), - icon=bui.gettexture('crossOut'), - iconscale=1.2) - - self.config_name, self.delegate, self.name_only = config_name, delegate, name_only - - self._text_field = bui.textwidget( - parent=self._root_widget, - position=(125, height - 121), - size=(280, 46), - text='', - h_align='left', - v_align='center', - color=(0.9, 0.9, 0.9, 1.0), - description='', - editable=True, - padding=4, - max_chars=20 if name_only else 5, - on_return_press_call=self._activate_enter_button) - - bui.textwidget(parent=self._root_widget, - text='Current: ' + str(config[config_name]) if not name_only else 'Save as', - position=(220, height - 44), - color=(0.5, 0.5, 0.5, 1.0), - size=(90, 30), - h_align='right') - - bui.widget(edit=btn, down_widget=self._text_field) - - b_width = 200 - self._enter_button = btn2 = bui.buttonwidget( - parent=self._root_widget, - position=(width * 0.5 - b_width * 0.5, height - 200), - size=(b_width, 60), - scale=1.0, - label='Enter', - on_activate_call=self._do_enter) - bui.containerwidget(edit=self._root_widget, - cancel_button=btn, - start_button=btn2, - selected_child=self._text_field) - - -class MenuThemeWindow: - def __init__(self, origin_widget: bui.widget = None, accounts_window=None): - if origin_widget is not None: - self._transition_out = 'out_scale' - scale_origin = origin_widget.get_screen_space_center() - transition = 'in_scale' - else: - self._transition_out = 'out_right' - scale_origin = None - transition = 'in_right' - - self._choice_page: str = None - self._accounts_window = accounts_window - height = 500 if ui_type is ui_small else 772 - - self._root_widget = bui.containerwidget( - size=(445, 365) if ui_type is ui_small else (799, 576), - transition=transition, - toolbar_visibility='menu_minimal', - scale_origin_stack_offset=scale_origin, - scale=2.23 if ui_type is ui_small else 1.0, - stack_offset=(0, -35) if ui_type is ui_small else (0, 0) - ) - - self._scroll_border_parent = bui.scrollwidget( - parent=self._root_widget, - position=(39, 58) if ui_type is ui_small else (86, 39), - size=(375, 240) if ui_type is ui_small else (645, 463), - color=(0.52, 0.48, 0.63) - ) - - self._scroll_parent = bui.containerwidget( - parent=self._scroll_border_parent, - size=(450, height), - background=False, - claims_left_right=False, - claims_tab=False - ) - - self._back_button = bui.buttonwidget( - parent=self._root_widget, - position=(23, 310) if ui_type is ui_small else (80, 511), - size=(35, 35) if ui_type is ui_small else (55, 55), - color=(0.76, 0.42, 0.38), - button_type="backSmall", - textcolor=(1, 1, 1), - text_scale=0.8 if ui_type is ui_small else 1.0, - label="", - autoselect=True, - on_activate_call=bs.Call(self.close) - ) - - self._home_button = bui.buttonwidget( - parent=self._root_widget, - position=(383, 308) if ui_type is ui_small else (688, 511), - size=(60, 60) if ui_type is ui_small else (55, 55), - color=(0.76, 0.42, 0.38), - icon=bui.gettexture('crossOut'), - iconscale=1.2, - scale=0.59 if ui_type is ui_small else 0.92, - label="", - autoselect=True, - on_activate_call=bs.Call(self.close_all) - ) - - # menutheme title - bui.textwidget( - parent=self._root_widget, - position=(225, 327) if ui_type is ui_small else (415, 547), - size=(0, 0), - text="Menu Theme", - color=(0.8, 0.8, 0.8, 0.76), - maxwidth=290, - scale=0.95 if ui_type is ui_small else 1.25, - h_align='center', - v_align='center' - ) - - bui.textwidget( - parent=self._root_widget, - position=(225, 309) if ui_type is ui_small else (415, 517), - size=(0, 0), - text=f"version: {__version__}", - color=(0.6, 0.6, 0.6, 0.8), - maxwidth=290, - scale=0.454 if ui_type is ui_small else 0.653, - h_align='center', - v_align='center' - ) - - # settings txt - bui.textwidget( - parent=self._scroll_parent, - position=(10, height - 27) if ui_type is ui_small else (30, height - 47), - size=(0, 0), - text="Map Type:", - color=(1, 1, 1, 0.8), - maxwidth=290, - scale=0.7 if ui_type is ui_small else 1.3, - h_align='left', - v_align='center' - ) - - bui.textwidget( - parent=self._scroll_parent, - position=(10, height - 65) if ui_type is ui_small else (30, height - 104), - size=(0, 0), - text="Music:", - color=(1, 1, 1, 0.8), - maxwidth=290, - scale=0.7 if ui_type is ui_small else 1.3, - h_align='left', - v_align='center' - ) - - bui.textwidget( - parent=self._scroll_parent, - position=(25, height - 147) if ui_type is ui_small else (45, height - 239), - size=(0, 0), - text="tint", - color=(1, 1, 1, 0.8), - maxwidth=290, - scale=0.5 if ui_type is ui_small else 1.0, - h_align='left', - v_align='center' - ) - - bui.textwidget( - parent=self._scroll_parent, - position=(81, height - 147) if ui_type is ui_small else (140, height - 239), - size=(0, 0), - text="ambient", - color=(1, 1, 1, 0.8), - maxwidth=290, - scale=0.5 if ui_type is ui_small else 1.0, - h_align='left', - v_align='center' - ) - - bui.textwidget( - parent=self._scroll_parent, - position=(147, height - 156) if ui_type is ui_small else (262, height - 258), - size=(0, 0), - text="vignette\n outer", - color=(1, 1, 1, 0.8), - maxwidth=290, - scale=0.5 if ui_type is ui_small else 1.0, - h_align='left', - v_align='center' - ) - - bui.textwidget( - parent=self._scroll_parent, - position=(213, height - 156) if ui_type is ui_small else (382, height - 258), - size=(0, 0), - text="vignette\n inner", - color=(1, 1, 1, 0.8), - maxwidth=290, - scale=0.5 if ui_type is ui_small else 1.0, - h_align='left', - v_align='center' - ) - - bui.textwidget( - parent=self._scroll_parent, - position=(279, height - 156) if ui_type is ui_small else (500, height - 258), - size=(0, 0), - text="reflection\n color", - color=(1, 1, 1, 0.8), - maxwidth=290, - scale=0.5 if ui_type is ui_small else 1.0, - h_align='left', - v_align='center' - ) - - bui.textwidget( - parent=self._scroll_parent, - position=(10, height - 193) if ui_type is ui_small else (30, height - 320), - size=(0, 0), - text="Reflection Type:", - color=(1, 1, 1, 0.8), - maxwidth=290, - scale=0.7 if ui_type is ui_small else 1.3, - h_align='left', - v_align='center' - ) - - bui.textwidget( - parent=self._scroll_parent, - position=(10, height - 227) if ui_type is ui_small else (30, height - 373), - size=(0, 0), - text="Reflection Scale:", - color=(1, 1, 1, 0.8), - maxwidth=290, - scale=0.7 if ui_type is ui_small else 1.3, - h_align='left', - v_align='center' - ) - - bui.textwidget( - parent=self._scroll_parent, - position=(10, height - 260) if ui_type is ui_small else (30, height - 423), - size=(0, 0), - text="Camera Mode:", - color=(1, 1, 1, 0.8), - maxwidth=290, - scale=0.7 if ui_type is ui_small else 1.3, - h_align='left', - v_align='center' - ) - - bui.textwidget( - parent=self._scroll_parent, - position=(10, height - 294) if ui_type is ui_small else (30, height - 480), - size=(0, 0), - text="Show Logo Text:", - color=(1, 1, 1, 0.8), - maxwidth=290, - scale=0.7 if ui_type is ui_small else 1.3, - h_align='left', - v_align='center' - ) - - # prioritize this first for: - # >> handling config-errors - # >> debugging - self._menu_configreset_button = bui.buttonwidget( - parent=self._scroll_parent, - position=(5, height - 486) if ui_type is ui_small else (12, height - 765), - size=(329, 50) if ui_type is ui_small else (600, 80), - color=(0.0, 0.67, 0.85), - textcolor=(0.8, 0.8, 0.8), - button_type="regular", - label="Reset to Default Settings", - text_scale=0.7 if ui_type is ui_small else 1.0, - on_activate_call=bs.Call(self.reset_config) - ) - - # settings buttons - self._menu_map_button = bui.buttonwidget( - parent=self._scroll_parent, - position=(112, height - 38) if ui_type is ui_small else (206, height - 67), - size=(87, 24) if ui_type is ui_small else (149, 40), - button_type="regular", - label=config["Menu Map"], - on_activate_call=bs.Call(self.choice_window, 'Map') - ) - - self._menu_music_button = bui.buttonwidget( - parent=self._scroll_parent, - position=(85, height - 75) if ui_type is ui_small else (149, height - 123), - size=(87, 24) if ui_type is ui_small else (149, 40), - button_type="regular", - label=config["Menu Music"], - text_scale=0.6 if ui_type is ui_small else 1.0, - on_activate_call=bs.Call(self.choice_window, 'Music') - ) - - self._menu_tint_button = bui.buttonwidget( - parent=self._scroll_parent, - color=config["Menu Tint"], - position=(15, height - 136) if ui_type is ui_small else (30, height - 220), - size=(40, 40) if ui_type is ui_small else (70, 70), - button_type="square", - label="", - on_activate_call=bs.WeakCall(self.color_picker_popup, "Menu Tint") - ) - - self._menu_ambient_button = bui.buttonwidget( - parent=self._scroll_parent, - color=config["Menu Ambient"], - position=(81, height - 136) if ui_type is ui_small else (150, height - 220), - size=(40, 40) if ui_type is ui_small else (70, 70), - button_type="square", - label="", - on_activate_call=bs.WeakCall(self.color_picker_popup, "Menu Ambient") - ) - - self._menu_vignetteO_button = bui.buttonwidget( - parent=self._scroll_parent, - color=config["Menu Vignette Outer"], - position=(147, height - 136) if ui_type is ui_small else (270, height - 220), - size=(40, 40) if ui_type is ui_small else (70, 70), - button_type="square", - label="", - on_activate_call=bs.WeakCall(self.color_picker_popup, "Menu Vignette Outer") - ) - - self._menu_vignetteI_button = bui.buttonwidget( - parent=self._scroll_parent, - color=config["Menu Vignette Inner"], - position=(213, height - 136) if ui_type is ui_small else (390, height - 220), - size=(40, 40) if ui_type is ui_small else (70, 70), - button_type="square", - label="", - on_activate_call=bs.WeakCall(self.color_picker_popup, "Menu Vignette Inner") - ) - - self._menu_rcolor_button = bui.buttonwidget( - parent=self._scroll_parent, - color=config["Menu Map Color"], - position=(279, height - 136) if ui_type is ui_small else (510, height - 220), - size=(40, 40) if ui_type is ui_small else (70, 70), - button_type="square", - label="", - on_activate_call=bs.WeakCall(self.color_picker_popup, "Menu Map Color") - ) - - self._menu_reflectiont_button = bui.buttonwidget( - parent=self._scroll_parent, - position=(148, height - 204) if ui_type is ui_small else (287, height - 339), - size=(87, 24) if ui_type is ui_small else (149, 40), - button_type="regular", - label=config["Menu Reflection Type"], - text_scale=0.6 if ui_type is ui_small else 1.0, - on_activate_call=bs.Call(self.choice_window, 'Reflection Type') - ) - - self._menu_reflections_button = bui.buttonwidget( - parent=self._scroll_parent, - position=(153, height - 237) if ui_type is ui_small else (289, height - 392), - size=(87, 24) if ui_type is ui_small else (149, 40), - button_type="regular", - label=str(config["Menu Reflection Scale"]), - text_scale=0.6 if ui_type is ui_small else 1.0, - on_activate_call=lambda: FreeEditWindow( - delegate=self, whitelist=['num'], config_name='Menu Reflection Scale') - ) - - self._menu_cameramode_button = bui.buttonwidget( - parent=self._scroll_parent, - position=(138, height - 272) if ui_type is ui_small else (265, height - 444), - size=(87, 24) if ui_type is ui_small else (149, 40), - button_type="regular", - label=str(config["Menu Camera Mode"]), - text_scale=0.6 if ui_type is ui_small else 1.0, - on_activate_call=bs.Call(self.choice_window, 'Camera Mode') - ) - - self._menu_logotext_button = ConfigCheckBox( - parent=self._scroll_parent, - configkey="Menu Logo Text", - position=(151, height - 308) if ui_type is ui_small else (287, height - 520), - size=(40, 40) if ui_type is ui_small else (56, 56), - scale=0.62 if ui_type is ui_small else 1.4, - displayname="" - ) - - self._menu_load_button = bui.buttonwidget( - parent=self._scroll_parent, - position=(11, height - 365) if ui_type is ui_small else (22, height - 590), - size=(155, 45) if ui_type is ui_small else (280, 75), - textcolor=(0.8, 0.8, 0.8), - button_type="regular", - label="Load Theme", - text_scale=0.7 if ui_type is ui_small else 1.0, - on_activate_call=bs.Call(self.popup_fileselector) - ) - - self._menu_save_button = bui.buttonwidget( - parent=self._scroll_parent, - position=(178, height - 365) if ui_type is ui_small else (312, height - 590), - size=(155, 45) if ui_type is ui_small else (280, 75), - textcolor=(0.8, 0.8, 0.8), - button_type="regular", - label="Save Theme", - text_scale=0.7 if ui_type is ui_small else 1.0, - on_activate_call=lambda: FreeEditWindow(delegate=self, name_only=True) - ) - - self._menu_mapdata_button = bui.buttonwidget( - parent=self._scroll_parent, - position=(5, height - 425) if ui_type is ui_small else (12, height - 677), - size=(329, 50) if ui_type is ui_small else (600, 80), - color=(0.23, 0.27, 0.55), - textcolor=(0.8, 0.8, 0.8), - button_type="regular", - label="Map Data Overrides", - text_scale=0.7 if ui_type is ui_small else 1.0, - on_activate_call=bs.Call(self.checkbox_window) - ) - - def checkbox_window(self): - self._root_widget_checkbox = bui.containerwidget( - size=(800, 740), - transition='in_scale', - toolbar_visibility='menu_minimal', - scale_origin_stack_offset=(0, 0), - scale=0.6 if ui_type is ui_large else 0.88 if ui_type is ui_small else 0.76, - color=(0.17, 0.2, 0.25), - on_outside_click_call=bs.Call(self.checkbox_window_out), - claim_outside_clicks=True, - stack_offset=(0, -35) if ui_type is ui_small else (0, 0) - ) - self._button_tint = ConfigCheckBox( - parent=self._root_widget_checkbox, - configkey="tint", - position=(88, 600), - size=(380, 40), - scale=1.9, - displayname='Tint' - ) - self._button_ambient = ConfigCheckBox( - parent=self._root_widget_checkbox, - configkey="ambient_color", - position=(88, 510), - size=(380, 40), - scale=1.9, - displayname='Ambient Color' - ) - self._button_vignette_outer = ConfigCheckBox( - parent=self._root_widget_checkbox, - configkey="vignette_outer", - position=(88, 420), - size=(380, 40), - scale=1.9, - displayname='Vignette Outer' - ) - self._button_vignette_inner = ConfigCheckBox( - parent=self._root_widget_checkbox, - configkey="vignette_inner", - position=(88, 330), - size=(380, 40), - scale=1.9, - displayname='Vignette Inner' - ) - self._button_map_color = ConfigCheckBox( - parent=self._root_widget_checkbox, - configkey="map_color", - position=(88, 240), - size=(380, 40), - scale=1.9, - displayname='Map Color' - ) - self._button_map_reflection_scale = ConfigCheckBox( - parent=self._root_widget_checkbox, - configkey="map_reflection_scale", - position=(88, 150), - size=(380, 40), - scale=1.9, - displayname='Map Reflection Scale' - ) - self._button_map_reflection_type = ConfigCheckBox( - parent=self._root_widget_checkbox, - configkey="map_reflection_type", - position=(88, 60), - size=(380, 40), - scale=1.9, - displayname='Map Reflection Type' - ) - - def checkbox_window_out(self): - # Memory-leak prevention - bui.containerwidget(edit=self._root_widget_checkbox, transition='out_scale') - del self._button_tint - del self._button_ambient - del self._button_vignette_outer - del self._button_vignette_inner - del self._button_map_color - del self._button_map_reflection_scale - del self._button_map_reflection_type - - def choice_window(self, category: str): - choices_map = { - 'Map': [ - 'Big G', - 'Bridgit', - 'Courtyard', - 'Crag Castle', - 'Doom Shroom', - 'Football Stadium', - 'Happy Thoughts', - 'Hockey Stadium', - 'Lake Frigid', - 'Monkey Face', - 'Rampage', - 'Roundabout', - 'Step Right Up', - 'The Pad', - 'The Pad (with trees)', - 'Tower D', - 'Tip Top', - 'Zig Zag' - ], - 'Camera Mode': [ - 'rotate', - 'static' - ], - 'Reflection Type': [ - 'Soft', - 'None', - 'Powerup', - 'Character' - ], - 'Music': [ - 'Menu', - 'Epic', - 'Flag Catcher', - 'Flying', - 'Grand Romp', - 'Lobby', - 'Lobby Epic', - 'Marching Forward', - 'Marching Home', - 'Run Away', - 'Scary', - 'Sports', - 'Survival', - 'To The Death', - 'None' - ] - } - - if category in choices_map: - PopupMenuWindow( - position=(0, 0), - scale=2.0 if ui_type is ui_small else 1.0, - delegate=self, - current_choice=bs.app.config[f"Menu {category}"], - choices=choices_map[category] - ) - self._choice_page = category - - def popup_menu_selected_choice(self, window: PopupMenuWindow, choice: str): - if self._choice_page == 'Map': - bs.app.config['Menu Map'] = choice - if config["tint"]: - bs.app.config["Menu Tint"] = GLOBALS_MAPDATA.get(config["Menu Map"]).get("Tint") - if config["ambient_color"]: - bs.app.config["Menu Ambient"] = GLOBALS_MAPDATA.get( - config["Menu Map"]).get("Ambient") - if config["vignette_outer"]: - bs.app.config["Menu Vignette Outer"] = GLOBALS_MAPDATA.get( - config["Menu Map"]).get("Vignette Outer") - if config["vignette_inner"]: - bs.app.config["Menu Vignette Inner"] = GLOBALS_MAPDATA.get( - config["Menu Map"]).get("Vignette Inner") - if config["map_color"]: - bs.app.config["Menu Map Color"] = GLOBALS_MAPDATA.get( - config["Menu Map"]).get("Map Color") - if config["map_reflection_scale"]: - bs.app.config["Menu Reflection Scale"] = GLOBALS_MAPDATA.get( - config["Menu Map"]).get("Map Reflection Scale") - if config["map_reflection_type"]: - bs.app.config["Menu Reflection Type"] = 'Soft' - - elif self._choice_page == 'Music': - bs.app.config['Menu Music'] = choice - - elif self._choice_page == 'Reflection Type': - bs.app.config['Menu Reflection Type'] = choice - - elif self._choice_page == 'Camera Mode': - bs.app.config['Menu Camera Mode'] = choice - bs.app.config.apply_and_commit() - self.update_buttons() - - def popup_menu_closing(self, window: PopupMenuWindow): - self._choice_page = None - self.update_buttons() - - def popup_fileselector(self): - self._file_selector = FileSelectorWindow( - path=str(_ba.env()['python_directory_user']), - callback=self._import, - show_base_path=True, - valid_file_extensions=['json'], - allow_folders=False - ) - - def _import(self, path: str = None): - try: - self.path = path + '/' - self.path = self.path[:-1] - with open(self.path, 'r') as imported: - selected = json.load(imported) - handle_config([ - selected["Menu Map"], - selected["Menu Tint"], - selected["Menu Ambient"], - selected["Menu Vignette Outer"], - selected["Menu Vignette Inner"], - selected["Menu Music"], - selected["Menu Map Color"], - selected["Menu Reflection Scale"], - selected["Menu Reflection Type"], - selected["Menu Camera Mode"], - selected["Menu Logo Text"], - selected["vignette_outer"], - selected["vignette_inner"], - selected["ambient_color"], - selected["tint"], - selected["map_reflection_scale"], - selected["map_reflection_type"], - selected["map_color"]], - False - ) - self.update_buttons() - bui.screenmessage( - f"Loaded {os.path.splitext(os.path.basename(self.path))[0]}!", color=(0.2, 0.4, 1.0)) - except: - pass - del self._file_selector - - def _export(self, window: FreeEditWindow, txt: Any): - path = _ba.env()['python_directory_user'] + "/_menutheme/" - try: - a = _ba.env()['python_directory_user'] + "/_menutheme" - os.makedirs(a, exist_ok=False) - except: - pass - - with open(path + txt + '.json', 'w') as file: - my_config = { - "Menu Map": config["Menu Map"], - "Menu Tint": config["Menu Tint"], - "Menu Ambient": config["Menu Ambient"], - "Menu Vignette Outer": config["Menu Vignette Outer"], - "Menu Vignette Inner": config["Menu Vignette Inner"], - "Menu Music": config["Menu Music"], - "Menu Map Color": config["Menu Map Color"], - "Menu Reflection Scale": config["Menu Reflection Scale"], - "Menu Reflection Type": config["Menu Reflection Type"], - "Menu Camera Mode": config["Menu Camera Mode"], - "Menu Logo Text": config["Menu Logo Text"], - "vignette_outer": config["vignette_outer"], - "vignette_inner": config["vignette_inner"], - "ambient_color": config["ambient_color"], - "tint": config["tint"], - "map_color": config["map_color"], - "map_reflection_scale": config["map_reflection_scale"], - "map_reflection_type": config["map_reflection_type"] - } - json.dump(my_config, file, indent=4) - bui.screenmessage( - f"Saved {os.path.splitext(os.path.basename(path+txt+'.json'))[0]}!", color=(0.2, 0.4, 1.0)) - bui.getsound('gunCocking').play() - - def color_picker_popup(self, tag: str): - bs.app.classic.accounts.have_pro = lambda: True - CustomColorPicker(parent=self._root_widget, - position=(0, 0), - initial_color=config[tag], - delegate=self, - tag=tag) - - def color_picker_selected_color(self, picker: CustomColorPicker, color: Sequence[float, float, float]): - if not self._root_widget: - return - self.update_color(tag=picker.get_tag(), color=color) - self.update_buttons() - - def color_picker_closing(self, picker: ColorPicker): - bs.app.classic.accounts.have_pro = original_unlocked_pro - - def free_edit_enter(self, window: FreeEditWindow, c: Any, txt: Any): - bs.app.config[c] = float(txt) - bs.app.config.apply_and_commit() - self.update_buttons() - - def update_buttons(self): - # menu labels - bui.buttonwidget(edit=self._menu_map_button, label=config['Menu Map']) - bui.buttonwidget(edit=self._menu_music_button, label=config['Menu Music']) - bui.buttonwidget(edit=self._menu_reflectiont_button, label=config['Menu Reflection Type']) - - # menu colors - bui.buttonwidget(edit=self._menu_tint_button, color=config['Menu Tint']) - bui.buttonwidget(edit=self._menu_ambient_button, color=config['Menu Ambient']) - bui.buttonwidget(edit=self._menu_vignetteO_button, color=config['Menu Vignette Outer']) - bui.buttonwidget(edit=self._menu_vignetteI_button, color=config['Menu Vignette Inner']) - bui.buttonwidget(edit=self._menu_rcolor_button, color=config['Menu Map Color']) - - # menu values - bui.buttonwidget(edit=self._menu_reflections_button, - label=str(config['Menu Reflection Scale'])) - bui.buttonwidget(edit=self._menu_cameramode_button, label=str(config['Menu Camera Mode'])) - bui.checkboxwidget(edit=self._menu_logotext_button.widget, value=config['Menu Logo Text']) - - def update_color(self, tag: str, color: tuple[float, float, float]): - bs.app.config[tag] = color - bs.app.config.apply_and_commit() - - def reset_config(self): - handle_config([ - "The Pad (with trees)", - (1.14, 1.1, 1.0), (1.06, 1.04, 1.03), - (0.45, 0.55, 0.54), (0.99, 0.98, 0.98), "Menu", - (1.0, 1.0, 1.0), 0.3, 'None', 'rotate', - True, True, True, True, True, True, True, True, True - ], False - ) - self.update_buttons() - bui.screenmessage('Reset Settings', color=(0, 1, 0)) - - def close(self): - self._accounts_window = None - bui.containerwidget(edit=self._root_widget, transition='out_scale') - - def close_all(self): - accounts_window = self._accounts_window - bui.containerwidget(edit=self._root_widget, transition='out_scale') - accounts_window._back(False) - - -class MainMenuTheme(MainMenuActivity): - - def _start_preloads(self): - if self.expired: - return - with self.context: - _preload1() - - bui.apptimer(0.5, self._start_menu_music) - - def _start_menu_music(self): - music = GLOBALS_MUSIC.get(config['Menu Music']) - if music is not None: - bs.setmusic(music) - - def _make_word(self, *args, **kwargs) -> None: - if not config['Menu Logo Text']: - return - super()._make_word(*args, **kwargs) - - def _make_logo(self, *args, **kwargs) -> None: - if not config['Menu Logo Text']: - return - super()._make_logo(*args, **kwargs) - - def on_transition_in(self): - bs.Activity.on_transition_in(self) - random.seed(123) - app = bs.app - env = ba.app.env - assert app.classic is not None - - plus = bui.app.plus - assert plus is not None - - vr_mode = env.vr - - if not toolbar_test: - color = (1.0, 1.0, 1.0, 1.0) if vr_mode else (0.5, 0.6, 0.5, 0.6) - - scale = ( - 0.9 - if (app.ui_v1.uiscale is bs.UIScale.SMALL or vr_mode) - else 0.7 - ) - self.my_name = bs.NodeActor( - bs.newnode( - 'text', - attrs={ - 'v_attach': 'bottom', - 'h_align': 'center', - 'color': color, - 'flatness': 1.0, - 'shadow': 1.0 if vr_mode else 0.5, - 'scale': scale, - 'position': (0, 10), - 'vr_depth': -10, - 'text': '\xa9 2011-2023 Eric Froemling', - }, - ) - ) - - tval = bs.Lstr( - resource='hostIsNavigatingMenusText', - subs=[('${HOST}', plus.get_v1_account_display_string())], - ) - self._host_is_navigating_text = bs.NodeActor( - bs.newnode( - 'text', - attrs={ - 'text': tval, - 'client_only': True, - 'position': (0, -200), - 'flatness': 1.0, - 'h_align': 'center', - }, - ) - ) - if not app.classic.main_menu_did_initial_transition and hasattr( - self, 'my_name' - ): - assert self.my_name is not None - assert self.my_name.node - bs.animate(self.my_name.node, 'opacity', {2.3: 0, 3.0: 1.0}) - - vr_mode = env.vr - uiscale = bui.UIV1Subsystem.uiscale - - force_show_build_number = False - - if not toolbar_test: - if env.debug or env.test or force_show_build_number: - if env.debug: - text = bs.Lstr( - value='${V} (${B}) (${D})', - subs=[ - ('${V}', env.version), - ('${B}', str(env.build_number)), - ('${D}', bs.Lstr(resource='debugText')), - ], - ) - else: - text = bs.Lstr( - value='${V} (${B})', - subs=[ - ('${V}', env.version), - ('${B}', str(env.build_number)), - ], ) - else: - text = bs.Lstr(value='${V}', subs=[('${V}', env.version)]) - scale = 0.9 if (uiscale is bs.UIScale.SMALL or vr_mode) else 0.7 - color = (1, 1, 1, 1) if vr_mode else (0.5, 0.6, 0.5, 0.7) - self.version = bs.NodeActor( - bs.newnode( - 'text', - attrs={ - 'v_attach': 'bottom', - 'h_attach': 'right', - 'h_align': 'right', - 'flatness': 1.0, - 'vr_depth': -10, - 'shadow': 1.0 if vr_mode else 0.5, - 'color': color, - 'scale': scale, - 'position': (-260, 10) if vr_mode else (-10, 10), - 'text': text, - }, - ) - ) - if not app.classic.main_menu_did_initial_transition: - assert self.version.node - bs.animate(self.version.node, 'opacity', {2.3: 0, 3.0: 1.0}) - - self.beta_info = self.beta_info_2 = None - if env.test and not (env.demo or env.arcade) and config['Menu Logo Text']: - pos = (230, 35) - self.beta_info = bs.NodeActor( - bs.newnode( - 'text', - attrs={ - 'v_attach': 'center', - 'h_align': 'center', - 'color': (1, 1, 1, 1), - 'shadow': 0.5, - 'flatness': 0.5, - 'scale': 1, - 'vr_depth': -60, - 'position': pos, - 'text': bs.Lstr(resource='testBuildText'), - }, - ) - ) - if not app.classic.main_menu_did_initial_transition: - assert self.beta_info.node - bs.animate(self.beta_info.node, 'opacity', {1.3: 0, 1.8: 1.0}) - - b = GLOBALS_MAPDATA.get(config["Menu Map"]).get("Camera Bounds") - b = ( - b[0] - b[3] / 2.0, - b[1] - b[4] / 2.0, - b[2] - b[5] / 2.0, - b[0] + b[3] / 2.0, - b[1] + b[4] / 2.0, - b[2] + b[5] / 2.0 - ) - - gnode = self.globalsnode - gnode.camera_mode = 'follow' if config["Menu Camera Mode"] == 'static' else 'rotate' - - self.load_map_stuff() - gnode.tint = config["Menu Tint"] - gnode.ambient_color = config["Menu Ambient"] - gnode.vignette_outer = config["Menu Vignette Outer"] - gnode.vignette_inner = config["Menu Vignette Inner"] - gnode.area_of_interest_bounds = b - - self.main.node.color = config["Menu Map Color"] - self.main.node.reflection = GLOBALS_REFLECTION[config["Menu Reflection Type"]] - self.main.node.reflection_scale = [float(config["Menu Reflection Scale"])] - - self._update_timer = bs.Timer(1.0, self._update, repeat=True) - self._update() - - bui.add_clean_frame_callback(bs.WeakCall(self._start_preloads)) - - random.seed() - - if not (env.demo or env.arcade) and not toolbar_test: - self._news = NewsDisplay(self) - - with bs.ContextRef.empty(): - from bauiv1lib import specialoffer - - assert bs.app.classic is not None - if bool(False): - uicontroller = bs.app.ui_v1.controller - assert uicontroller is not None - uicontroller.show_main_menu() - else: - main_menu_location = bs.app.ui_v1.get_main_menu_location() - - # When coming back from a kiosk-mode game, jump to - # the kiosk start screen. - if env.demo or env.arcade: - # pylint: disable=cyclic-import - from bauiv1lib.kiosk import KioskWindow - - if TARGET_BALLISTICA_BUILD < 21697: - bs.app.ui_v1.set_main_menu_window( - KioskWindow().get_root_widget(), - ) else: bs.app.ui_v1.set_main_menu_window( - KioskWindow().get_root_widget(), from_window=False - ) + KioskWindow().get_root_widget(), from_window = False + ) # ..or in normal cases go back to the main menu else: if main_menu_location == 'Gather': @@ -3422,24 +1388,24 @@ def on_transition_in(self): if TARGET_BALLISTICA_BUILD < 21697: bs.app.ui_v1.set_main_menu_window( - GatherWindow(transition=None).get_root_widget(), - ) + GatherWindow(transition=None).get_root_widget(), + ) else: bs.app.ui_v1.set_main_menu_window( - GatherWindow(transition=None).get_root_widget(), from_window=False - ) + GatherWindow(transition=None).get_root_widget(), from_window = False + ) elif main_menu_location == 'Watch': # pylint: disable=cyclic-import from bauiv1lib.watch import WatchWindow if TARGET_BALLISTICA_BUILD < 21697: bs.app.ui_v1.set_main_menu_window( - WatchWindow(transition=None).get_root_widget(), - ) + WatchWindow(transition=None).get_root_widget(), + ) else: bs.app.ui_v1.set_main_menu_window( - WatchWindow(transition=None).get_root_widget(), from_window=False - ) + WatchWindow(transition=None).get_root_widget(), from_window = False + ) elif main_menu_location == 'Team Game Select': # pylint: disable=cyclic-import from bauiv1lib.playlist.browser import ( @@ -3448,16 +1414,16 @@ def on_transition_in(self): if TARGET_BALLISTICA_BUILD < 21697: bs.app.ui_v1.set_main_menu_window( - PlaylistBrowserWindow( - sessiontype=bs.DualTeamSession, transition=None - ).get_root_widget(), - ) + PlaylistBrowserWindow( + sessiontype=bs.DualTeamSession, transition=None + ).get_root_widget(), + ) else: bs.app.ui_v1.set_main_menu_window( - PlaylistBrowserWindow( - sessiontype=bs.DualTeamSession, transition=None - ).get_root_widget(), from_window=False - ) + PlaylistBrowserWindow( + sessiontype=bs.DualTeamSession, transition=None + ).get_root_widget(), from_window = False + ) elif main_menu_location == 'Free-for-All Game Select': # pylint: disable=cyclic-import from bauiv1lib.playlist.browser import ( @@ -3466,54 +1432,54 @@ def on_transition_in(self): if TARGET_BALLISTICA_BUILD < 21697: bs.app.ui_v1.set_main_menu_window( - PlaylistBrowserWindow( - sessiontype=bs.FreeForAllSession, - transition=None, - ).get_root_widget(), - ) + PlaylistBrowserWindow( + sessiontype=bs.FreeForAllSession, + transition=None, + ).get_root_widget(), + ) else: bs.app.ui_v1.set_main_menu_window( - PlaylistBrowserWindow( - sessiontype=bs.FreeForAllSession, - transition=None, - ).get_root_widget(), from_window=False - ) + PlaylistBrowserWindow( + sessiontype=bs.FreeForAllSession, + transition=None, + ).get_root_widget(), from_window = False + ) elif main_menu_location == 'Coop Select': # pylint: disable=cyclic-import from bauiv1lib.coop.browser import CoopBrowserWindow if TARGET_BALLISTICA_BUILD < 21697: bs.app.ui_v1.set_main_menu_window( - CoopBrowserWindow(transition=None).get_root_widget(), - ) + CoopBrowserWindow(transition=None).get_root_widget(), + ) else: bs.app.ui_v1.set_main_menu_window( - CoopBrowserWindow(transition=None).get_root_widget(), from_window=False - ) + CoopBrowserWindow(transition=None).get_root_widget(), from_window = False + ) elif main_menu_location == 'Benchmarks & Stress Tests': # pylint: disable=cyclic-import from bauiv1lib.debug import DebugWindow if TARGET_BALLISTICA_BUILD < 21697: bs.app.ui_v1.set_main_menu_window( - DebugWindow(transition=None).get_root_widget(), - ) + DebugWindow(transition=None).get_root_widget(), + ) else: bs.app.ui_v1.set_main_menu_window( - DebugWindow(transition=None).get_root_widget(), from_window=False - ) + DebugWindow(transition=None).get_root_widget(), from_window = False + ) else: # pylint: disable=cyclic-import from bauiv1lib.mainmenu import MainMenuWindow if TARGET_BALLISTICA_BUILD < 21697: bs.app.ui_v1.set_main_menu_window( - MainMenuWindow(transition=None).get_root_widget(), - ) + MainMenuWindow(transition=None).get_root_widget(), + ) else: bs.app.ui_v1.set_main_menu_window( - MainMenuWindow(transition=None).get_root_widget(), from_window=False - ) + MainMenuWindow(transition=None).get_root_widget(), from_window = False + ) if not specialoffer.show_offer(): @@ -4068,7 +2034,7 @@ def new_back(self, save_state: bool = True): if TARGET_BALLISTICA_BUILD < 21697: bui.app.ui_v1.set_main_menu_window(main_menu_window,) else: - bui.app.ui_v1.set_main_menu_window(main_menu_window, from_window=False) + bui.app.ui_v1.set_main_menu_window(main_menu_window, from_window = False) current_config = { "Menu Map": config["Menu Map"], From 610f110a162f777d279baeac82ccf85dce6b6fd0 Mon Sep 17 00:00:00 2001 From: Freaku17 Date: Fri, 29 Dec 2023 11:38:44 +0000 Subject: [PATCH 0792/1464] [ci] auto-format --- plugins/utilities/menu_theme.py | 84 ++++++++++++++++----------------- 1 file changed, 42 insertions(+), 42 deletions(-) diff --git a/plugins/utilities/menu_theme.py b/plugins/utilities/menu_theme.py index 98d1371e..6ee35c86 100644 --- a/plugins/utilities/menu_theme.py +++ b/plugins/utilities/menu_theme.py @@ -1375,11 +1375,11 @@ def on_transition_in(self): if TARGET_BALLISTICA_BUILD < 21697: bs.app.ui_v1.set_main_menu_window( KioskWindow().get_root_widget(), - ) + ) else: bs.app.ui_v1.set_main_menu_window( - KioskWindow().get_root_widget(), from_window = False - ) + KioskWindow().get_root_widget(), from_window=False + ) # ..or in normal cases go back to the main menu else: if main_menu_location == 'Gather': @@ -1388,24 +1388,24 @@ def on_transition_in(self): if TARGET_BALLISTICA_BUILD < 21697: bs.app.ui_v1.set_main_menu_window( - GatherWindow(transition=None).get_root_widget(), - ) + GatherWindow(transition=None).get_root_widget(), + ) else: bs.app.ui_v1.set_main_menu_window( - GatherWindow(transition=None).get_root_widget(), from_window = False - ) + GatherWindow(transition=None).get_root_widget(), from_window=False + ) elif main_menu_location == 'Watch': # pylint: disable=cyclic-import from bauiv1lib.watch import WatchWindow if TARGET_BALLISTICA_BUILD < 21697: bs.app.ui_v1.set_main_menu_window( - WatchWindow(transition=None).get_root_widget(), - ) + WatchWindow(transition=None).get_root_widget(), + ) else: bs.app.ui_v1.set_main_menu_window( - WatchWindow(transition=None).get_root_widget(), from_window = False - ) + WatchWindow(transition=None).get_root_widget(), from_window=False + ) elif main_menu_location == 'Team Game Select': # pylint: disable=cyclic-import from bauiv1lib.playlist.browser import ( @@ -1414,16 +1414,16 @@ def on_transition_in(self): if TARGET_BALLISTICA_BUILD < 21697: bs.app.ui_v1.set_main_menu_window( - PlaylistBrowserWindow( - sessiontype=bs.DualTeamSession, transition=None - ).get_root_widget(), - ) + PlaylistBrowserWindow( + sessiontype=bs.DualTeamSession, transition=None + ).get_root_widget(), + ) else: bs.app.ui_v1.set_main_menu_window( - PlaylistBrowserWindow( - sessiontype=bs.DualTeamSession, transition=None - ).get_root_widget(), from_window = False - ) + PlaylistBrowserWindow( + sessiontype=bs.DualTeamSession, transition=None + ).get_root_widget(), from_window=False + ) elif main_menu_location == 'Free-for-All Game Select': # pylint: disable=cyclic-import from bauiv1lib.playlist.browser import ( @@ -1432,54 +1432,54 @@ def on_transition_in(self): if TARGET_BALLISTICA_BUILD < 21697: bs.app.ui_v1.set_main_menu_window( - PlaylistBrowserWindow( - sessiontype=bs.FreeForAllSession, - transition=None, - ).get_root_widget(), - ) + PlaylistBrowserWindow( + sessiontype=bs.FreeForAllSession, + transition=None, + ).get_root_widget(), + ) else: bs.app.ui_v1.set_main_menu_window( - PlaylistBrowserWindow( - sessiontype=bs.FreeForAllSession, - transition=None, - ).get_root_widget(), from_window = False - ) + PlaylistBrowserWindow( + sessiontype=bs.FreeForAllSession, + transition=None, + ).get_root_widget(), from_window=False + ) elif main_menu_location == 'Coop Select': # pylint: disable=cyclic-import from bauiv1lib.coop.browser import CoopBrowserWindow if TARGET_BALLISTICA_BUILD < 21697: bs.app.ui_v1.set_main_menu_window( - CoopBrowserWindow(transition=None).get_root_widget(), - ) + CoopBrowserWindow(transition=None).get_root_widget(), + ) else: bs.app.ui_v1.set_main_menu_window( - CoopBrowserWindow(transition=None).get_root_widget(), from_window = False - ) + CoopBrowserWindow(transition=None).get_root_widget(), from_window=False + ) elif main_menu_location == 'Benchmarks & Stress Tests': # pylint: disable=cyclic-import from bauiv1lib.debug import DebugWindow if TARGET_BALLISTICA_BUILD < 21697: bs.app.ui_v1.set_main_menu_window( - DebugWindow(transition=None).get_root_widget(), - ) + DebugWindow(transition=None).get_root_widget(), + ) else: bs.app.ui_v1.set_main_menu_window( - DebugWindow(transition=None).get_root_widget(), from_window = False - ) + DebugWindow(transition=None).get_root_widget(), from_window=False + ) else: # pylint: disable=cyclic-import from bauiv1lib.mainmenu import MainMenuWindow if TARGET_BALLISTICA_BUILD < 21697: bs.app.ui_v1.set_main_menu_window( - MainMenuWindow(transition=None).get_root_widget(), - ) + MainMenuWindow(transition=None).get_root_widget(), + ) else: bs.app.ui_v1.set_main_menu_window( - MainMenuWindow(transition=None).get_root_widget(), from_window = False - ) + MainMenuWindow(transition=None).get_root_widget(), from_window=False + ) if not specialoffer.show_offer(): @@ -2034,7 +2034,7 @@ def new_back(self, save_state: bool = True): if TARGET_BALLISTICA_BUILD < 21697: bui.app.ui_v1.set_main_menu_window(main_menu_window,) else: - bui.app.ui_v1.set_main_menu_window(main_menu_window, from_window = False) + bui.app.ui_v1.set_main_menu_window(main_menu_window, from_window=False) current_config = { "Menu Map": config["Menu Map"], From 53ce44adc0236c5f5a498b5a07cd676ffc5481a7 Mon Sep 17 00:00:00 2001 From: ! Freaku <92618708+Freaku17@users.noreply.github.com> Date: Fri, 29 Dec 2023 17:09:02 +0530 Subject: [PATCH 0793/1464] Update utilities.json --- plugins/utilities.json | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/plugins/utilities.json b/plugins/utilities.json index 4fa90d67..e04925b0 100644 --- a/plugins/utilities.json +++ b/plugins/utilities.json @@ -895,12 +895,7 @@ } ], "versions": { - "1.0.1": { - "api_version": 8, - "commit_sha": "3796c78", - "released_on": "29-12-2023", - "md5sum": "de3e44d05e20a7e03441db4078057c10" - }, + "1.0.1": null, "1.0.0": { "api_version": 8, "commit_sha": "f829aca", @@ -959,4 +954,4 @@ } } } -} \ No newline at end of file +} From f161be4806d7bb1c1a0e3d6aad2bb0e50f789e84 Mon Sep 17 00:00:00 2001 From: Freaku17 Date: Fri, 29 Dec 2023 11:39:23 +0000 Subject: [PATCH 0794/1464] [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 e04925b0..2e5a879b 100644 --- a/plugins/utilities.json +++ b/plugins/utilities.json @@ -895,7 +895,12 @@ } ], "versions": { - "1.0.1": null, + "1.0.1": { + "api_version": 8, + "commit_sha": "53ce44a", + "released_on": "29-12-2023", + "md5sum": "41e324d84bc79bf1283b643014802069" + }, "1.0.0": { "api_version": 8, "commit_sha": "f829aca", @@ -954,4 +959,4 @@ } } } -} +} \ No newline at end of file From 43d42d4ef38b60ef1e3a811ac1e8065ae242813a Mon Sep 17 00:00:00 2001 From: brostosjoined Date: Thu, 11 Jan 2024 11:53:21 +0300 Subject: [PATCH 0795/1464] Removed depracated methods and some untested android fixes --- plugins/utilities/discord_richpresence.py | 36 +++++++++++++---------- 1 file changed, 21 insertions(+), 15 deletions(-) diff --git a/plugins/utilities/discord_richpresence.py b/plugins/utilities/discord_richpresence.py index 6e8bdb27..89462f3a 100644 --- a/plugins/utilities/discord_richpresence.py +++ b/plugins/utilities/discord_richpresence.py @@ -188,7 +188,7 @@ def heartbeats(): def identify(): """Identifying to the gateway and enable by using user token and the intents we will be using e.g 256->For Presence""" - with open(f"{getcwd()}/token.txt", 'r') as f: + with open(Path(f"{_babase.app.env.python_directory_user}/token.txt", 'r')) as f: token = bytes.fromhex(f.read()).decode('utf-8') identify_payload = { "op": 2, @@ -220,8 +220,11 @@ def identify(): threading.Thread(target=heartbeats, daemon=True, name="heartbeat").start() def start(self): - if Path(f"{getcwd()}/token.txt").exists(): - threading.Thread(target=self.ws.run_forever, daemon=True, name="websocket").start() + if Path(f"{_babase.app.env.python_directory_user}/token.txt").exists(): + try: + threading.Thread(target=self.ws.run_forever, daemon=True, name="websocket").start() + except: + pass def close(self): self.stop_heartbeat_thread.set() @@ -370,7 +373,7 @@ def is_discord_running(): def _generate_join_secret(self): # resp = requests.get('https://legacy.ballistica.net/bsAccessCheck').text - connection_info = bs.get_connection_to_host_info() + connection_info = bs.get_connection_to_host_info_2() if connection_info: addr = _last_server_addr port = _last_server_port @@ -535,7 +538,7 @@ def __init__(self): s = 1.25 if _uiscale is babase.UIScale.SMALL else 1.27 if _uiscale is babase.UIScale.MEDIUM else 1.3 self._width = 380 * s self._height = 150 + 150 * s - self.path = Path(f"{getcwd()}/token.txt") + self.path = Path(f"{_babase.app.env.python_directory_user}/token.txt") bg_color = (0.5, 0.4, 0.6) log_btn_colour = (0.10, 0.95, 0.10) if not self.path.exists() else (1.00, 0.15, 0.15) log_txt = "LOG IN" if not self.path.exists() else "LOG OUT" @@ -794,15 +797,19 @@ def __init__(self) -> None: def on_app_running(self) -> None: if not ANDROID: self.rpc_thread.start() + self.update_timer = bs.AppTimer( 1, bs.WeakCall(self.update_status), repeat=True ) if ANDROID: self.rpc_thread.start() - self.update_timer = bs.AppTimer( - 4, bs.WeakCall(self.update_status), repeat=True - ) - + try: + self.update_timer = bs.AppTimer( + 4, bs.WeakCall(self.update_status), repeat=True + ) + except: + pass + def has_settings_ui(self): return True @@ -869,7 +876,7 @@ def _get_current_map_name(self) -> Tuple[str | None, str | None]: def update_status(self) -> None: roster = bs.get_game_roster() - connection_info = bs.get_connection_to_host_info() + connection_info = bs.get_connection_to_host_info_2() self.rpc_thread.large_image_key = "bombsquadicon" self.rpc_thread.large_image_text = "BombSquad" @@ -877,15 +884,14 @@ def update_status(self) -> None: self.rpc_thread.small_image_text = ( f"{_babase.app.classic.platform.capitalize()}({APP_VERSION})" ) - connection_info = bs.get_connection_to_host_info() if not ANDROID: svinfo = str(connection_info) if self._last_server_info != svinfo: self._last_server_info = svinfo self.rpc_thread.party_id = str(uuid.uuid4()) self.rpc_thread._update_secret() - if connection_info != {}: - servername = connection_info["name"] + if connection_info: + servername = connection_info.name self.rpc_thread.details = "Online" self.rpc_thread.party_size = max( 1, sum(len(client["players"]) for client in roster) @@ -910,7 +916,7 @@ def update_status(self) -> None: else: self.rpc_thread.state = servername[slice(19)] - if connection_info == {}: + if not connection_info: self.rpc_thread.details = "Local" # ! replace with something like ballistica github cause self.rpc_thread.state = self._get_current_activity_name() self.rpc_thread.party_size = max(1, len(roster)) @@ -995,5 +1001,5 @@ def update_status(self) -> None: self.rpc_thread.large_image_key = ( "https://media.tenor.com/uAqNn6fv7x4AAAAM/bombsquad-spaz.gif" ) - if ANDROID and Path(f"{getcwd()}/token.txt").exists(): + if ANDROID and Path(f"{_babase.app.env.python_directory_user}/token.txt").exists(): self.rpc_thread.presence() From 39845e7b610fd2d4d56ea205572530f675e203cf Mon Sep 17 00:00:00 2001 From: brostosjoined Date: Sun, 14 Jan 2024 10:58:32 +0300 Subject: [PATCH 0796/1464] Android presence now works after an update no need relogin --- plugins/utilities.json | 1 + plugins/utilities/discord_richpresence.py | 22 ++++++++-------------- 2 files changed, 9 insertions(+), 14 deletions(-) diff --git a/plugins/utilities.json b/plugins/utilities.json index 39e9062b..866a6593 100644 --- a/plugins/utilities.json +++ b/plugins/utilities.json @@ -926,6 +926,7 @@ } ], "versions": { + "1.4.2": null, "1.4.1": { "api_version": 8, "commit_sha": "48c8abb", diff --git a/plugins/utilities/discord_richpresence.py b/plugins/utilities/discord_richpresence.py index 89462f3a..70a1ee34 100644 --- a/plugins/utilities/discord_richpresence.py +++ b/plugins/utilities/discord_richpresence.py @@ -188,7 +188,7 @@ def heartbeats(): def identify(): """Identifying to the gateway and enable by using user token and the intents we will be using e.g 256->For Presence""" - with open(Path(f"{_babase.app.env.python_directory_user}/token.txt", 'r')) as f: + with open(f"{_babase.app.env.python_directory_user}/__pycache__/token.txt", 'r') as f: token = bytes.fromhex(f.read()).decode('utf-8') identify_payload = { "op": 2, @@ -220,11 +220,8 @@ def identify(): threading.Thread(target=heartbeats, daemon=True, name="heartbeat").start() def start(self): - if Path(f"{_babase.app.env.python_directory_user}/token.txt").exists(): - try: - threading.Thread(target=self.ws.run_forever, daemon=True, name="websocket").start() - except: - pass + if Path(f"{_babase.app.env.python_directory_user}/__pycache__/token.txt").exists(): + threading.Thread(target=self.ws.run_forever, daemon=True, name="websocket").start() def close(self): self.stop_heartbeat_thread.set() @@ -538,7 +535,7 @@ def __init__(self): s = 1.25 if _uiscale is babase.UIScale.SMALL else 1.27 if _uiscale is babase.UIScale.MEDIUM else 1.3 self._width = 380 * s self._height = 150 + 150 * s - self.path = Path(f"{_babase.app.env.python_directory_user}/token.txt") + self.path = Path(f"{_babase.app.env.python_directory_user}/__pycache__/token.txt") bg_color = (0.5, 0.4, 0.6) log_btn_colour = (0.10, 0.95, 0.10) if not self.path.exists() else (1.00, 0.15, 0.15) log_txt = "LOG IN" if not self.path.exists() else "LOG OUT" @@ -803,12 +800,9 @@ def on_app_running(self) -> None: ) if ANDROID: self.rpc_thread.start() - try: - self.update_timer = bs.AppTimer( - 4, bs.WeakCall(self.update_status), repeat=True - ) - except: - pass + self.update_timer = bs.AppTimer( + 4, bs.WeakCall(self.update_status), repeat=True + ) def has_settings_ui(self): return True @@ -1001,5 +995,5 @@ def update_status(self) -> None: self.rpc_thread.large_image_key = ( "https://media.tenor.com/uAqNn6fv7x4AAAAM/bombsquad-spaz.gif" ) - if ANDROID and Path(f"{_babase.app.env.python_directory_user}/token.txt").exists(): + if ANDROID and Path(f"{_babase.app.env.python_directory_user}/__pycache__/token.txt").exists(): self.rpc_thread.presence() From 77d16e63c70b37abb93dc05e0cff4233385fe8dd Mon Sep 17 00:00:00 2001 From: brostosjoined Date: Tue, 16 Jan 2024 15:06:45 +0300 Subject: [PATCH 0797/1464] Done with utilities. Need some testing on ultraparty and few fix on auto stunt and quick customgame --- plugins/maps/forest.py | 41 +- plugins/utilities.json | 35 +- plugins/utilities/allow_invisible_models.py | 18 +- plugins/utilities/auto_stunt.py | 141 +-- plugins/utilities/autorun.py | 58 +- plugins/utilities/bomb_radius_visualizer.py | 23 +- plugins/utilities/chat_cmd.py | 164 +-- .../colored_bomb_explosion_patches.py | 21 +- plugins/utilities/custom_death.py | 34 +- plugins/utilities/disco_light.py | 78 +- plugins/utilities/discord_richpresence.py | 6 +- plugins/utilities/max_players.py | 128 +- plugins/utilities/mood_light.py | 161 +-- plugins/utilities/quick_custom_game.py | 174 +-- plugins/utilities/quickturn.py | 29 +- plugins/utilities/ragdoll_b_gone.py | 31 +- plugins/utilities/random_join.py | 112 +- plugins/utilities/tnt_respawn_text.py | 27 +- plugins/utilities/ultra_party_window.py | 1033 +++++++++-------- 19 files changed, 1221 insertions(+), 1093 deletions(-) diff --git a/plugins/maps/forest.py b/plugins/maps/forest.py index d5c4d1d5..c9f04be6 100644 --- a/plugins/maps/forest.py +++ b/plugins/maps/forest.py @@ -1,12 +1,15 @@ +# Porting to api 8 made easier by baport.(https://github.com/bombsquad-community/baport) -# ba_meta require api 7 +# ba_meta require api 8 from __future__ import annotations from typing import TYPE_CHECKING -import ba -from ba import _map -from bastd.gameutils import SharedObjects -from bastd.maps import * +import babase +import bauiv1 as bui +import bascenev1 as bs +from bascenev1 import _map +from bascenev1lib.gameutils import SharedObjects +from bascenev1lib.maps import * if TYPE_CHECKING: pass @@ -48,7 +51,7 @@ class ForestMapData(): points['spawn2'] = (5.0, -2.0, -2.0) + (0.5, 1.0, 3.2) -class ForestMap(ba.Map): +class ForestMap(bs.Map): defs = ForestMapData() name = 'Forest' @@ -64,11 +67,11 @@ def get_preview_texture_name(cls) -> list[str]: @classmethod def on_preload(cls) -> any: data: dict[str, any] = { - 'model': ba.getmodel('natureBackground'), - 'tex': ba.gettexture('natureBackgroundColor'), - 'collide_model': ba.getcollidemodel('natureBackgroundCollide'), - 'bgmodel': ba.getmodel('thePadBG'), - 'bgtex': ba.gettexture('menuBG') + 'mesh': bs.getmesh('natureBackground'), + 'tex': bui.gettexture('natureBackgroundColor'), + 'collision_mesh': bs.getcollisionmesh('natureBackgroundCollide'), + 'bgmesh': bs.getmesh('thePadBG'), + 'bgtex': bui.gettexture('menuBG') } return data @@ -76,27 +79,27 @@ def __init__(self) -> None: super().__init__() shared = SharedObjects.get() - self.node = ba.newnode( + self.node = bs.newnode( 'terrain', delegate=self, attrs={ - 'model': self.preloaddata['model'], + 'mesh': self.preloaddata['mesh'], 'color_texture': self.preloaddata['tex'], - 'collide_model': self.preloaddata['collide_model'], + 'collide_mesh': self.preloaddata['collide_mesh'], 'materials': [shared.footing_material] } ) - self.background = ba.newnode( + self.background = bs.newnode( 'terrain', attrs={ - 'model': self.preloaddata['bgmodel'], + 'mesh': self.preloaddata['bgmesh'], 'lighting': False, 'shadow': True, 'color_texture': self.preloaddata['bgtex'] } ) - gnode = ba.getactivity().globalsnode + gnode = bs.getactivity().globalsnode gnode.tint = (1.0, 1.10, 1.15) gnode.ambient_color = (0.9, 1.3, 1.1) gnode.shadow_ortho = False @@ -104,7 +107,7 @@ def __init__(self) -> None: gnode.vignette_inner = (0.95, 0.95, 0.99) def is_point_near_edge(self, - point: ba.Vec3, + point: babase.Vec3, running: bool = False) -> bool: xpos = point.x zpos = point.z @@ -117,5 +120,5 @@ def is_point_near_edge(self, # ba_meta export plugin -class EnableMe(ba.Plugin): +class EnableMe(babase.Plugin): _map.register_map(ForestMap) diff --git a/plugins/utilities.json b/plugins/utilities.json index 866a6593..433adf4d 100644 --- a/plugins/utilities.json +++ b/plugins/utilities.json @@ -19,6 +19,7 @@ } ], "versions": { + "1.0.1": null, "1.0.0": { "api_version": 7, "commit_sha": "2454845", @@ -106,6 +107,7 @@ } ], "versions": { + "1.0.1": null, "1.0.0": { "api_version": 7, "commit_sha": "2fda676", @@ -125,6 +127,7 @@ } ], "versions": { + "1.0.1": null, "1.0.0": { "api_version": 7, "commit_sha": "2fda676", @@ -163,6 +166,7 @@ } ], "versions": { + "1.0.1": null, "1.0.0": { "api_version": 7, "commit_sha": "fed7c24", @@ -187,6 +191,7 @@ } ], "versions": { + "1.0.1": null, "1.0.0": { "api_version": 7, "commit_sha": "2fda676", @@ -206,6 +211,7 @@ } ], "versions": { + "1.2.3": null, "1.2.2": { "api_version": 7, "commit_sha": "7753b87", @@ -239,7 +245,7 @@ { "name": "Rikko", "email": "rikkolovescats@proton.me", - "discord": "Rikko#7383" + "discord": "rikkolovescats" }, { "name": "Vishal", @@ -299,7 +305,7 @@ { "name": "Rikko", "email": "rikkolovescats@proton.me", - "discord": "Rikko#7383" + "discord": "rikkolovescats" } ], "versions": { @@ -470,6 +476,7 @@ } ], "versions": { + "1.0.1": null, "1.0.0": { "api_version": 7, "commit_sha": "6acdea8", @@ -669,6 +676,7 @@ } ], "versions": { + "4.0.1": null, "4.0.0": { "api_version": 7, "commit_sha": "a23e8cd", @@ -684,10 +692,11 @@ { "name": "TheMikirog", "email": "", - "discord": "TheMikirog#1984" + "discord": "themikirog" } ], "versions": { + "3.0.1": null, "3.0.0": { "api_version": 7, "commit_sha": "0841b9e", @@ -703,10 +712,11 @@ { "name": "TheMikirog", "email": "", - "discord": "TheMikirog#1984" + "discord": "themikirog" } ], "versions": { + "1.0.1": null, "1.0.0": { "api_version": 7, "commit_sha": "0841b9e", @@ -722,10 +732,11 @@ { "name": "TheMikirog", "email": "", - "discord": "TheMikirog#1984" + "discord": "themikirog" } ], "versions": { + "1.0.1": null, "1.0.0": { "api_version": 7, "commit_sha": "0841b9e", @@ -741,10 +752,11 @@ { "name": "Cross Joy", "email": "cross.joy.official@gmail.com", - "discord": "Cross Joy#0721" + "discord": "crossjoy" } ], "versions": { + "1.0.1": null, "1.0.0": { "api_version": 7, "commit_sha": "800125c", @@ -760,7 +772,7 @@ { "name": "Cross Joy", "email": "cross.joy.official@gmail.com", - "discord": "Cross Joy#0721" + "discord": "crossjoy" } ], "versions": { @@ -809,10 +821,11 @@ { "name": "TheMikirog", "email": "", - "discord": "TheMikirog#1984" + "discord": "themikirog" } ], "versions": { + "1.0.1": null, "1.0.0": { "api_version": 7, "commit_sha": "cb2d952", @@ -828,10 +841,11 @@ { "name": "TheMikirog", "email": "", - "discord": "TheMikirog#1984" + "discord": "themikirog" } ], "versions": { + "1.0.1": null, "1.0.0": { "api_version": 7, "commit_sha": "05ffa9f", @@ -847,10 +861,11 @@ { "name": "Rikko", "email": "rikkolovescats@proton.me", - "discord": "Rikko#7383" + "discord": "rikkolovescats" } ], "versions": { + "1.0.1": null, "1.0.0": { "api_version": 7, "commit_sha": "3221b3a", diff --git a/plugins/utilities/allow_invisible_models.py b/plugins/utilities/allow_invisible_models.py index b2d1403a..4f337615 100644 --- a/plugins/utilities/allow_invisible_models.py +++ b/plugins/utilities/allow_invisible_models.py @@ -1,15 +1,17 @@ -# ba_meta require api 7 -import ba +# Porting to api 8 made easier by baport.(https://github.com/bombsquad-community/baport) +# ba_meta require api 8 +import babase +import bascenev1 as bs -original_getmodel = ba.getmodel +original_getmesh = bs.getmesh -def get_model_gracefully(model): - if model is not None: - return original_getmodel(model) +def get_mesh_gracefully(mesh): + if mesh is not None: + return original_getmesh(mesh) # ba_meta export plugin -class Main(ba.Plugin): +class Main(babase.Plugin): def on_app_running(self): - ba.getmodel = get_model_gracefully + bs.getmesh = get_mesh_gracefully diff --git a/plugins/utilities/auto_stunt.py b/plugins/utilities/auto_stunt.py index 0b4ca11c..85668212 100644 --- a/plugins/utilities/auto_stunt.py +++ b/plugins/utilities/auto_stunt.py @@ -1,22 +1,25 @@ -# ba_meta require api 7 +# Porting to api 8 made easier by baport.(https://github.com/bombsquad-community/baport) +# ba_meta require api 8 # AutoStunt mod by - Mr.Smoothy x Rikko # https://discord.gg/ucyaesh -# https://bombsquad.ga +# https://bombsquad-community.web.app/home # Dont modify redistribute this plugin , if want to use features of this plugin in your mod write logic in seprate file # and import this as module. # If want to contribute in this original module, raise PR on github https://github.com/bombsquad-community/plugin-manager -import ba -import _ba -import bastd -from bastd.actor.text import Text -from bastd.actor.image import Image -from bastd.actor import spaz -from bastd.actor import playerspaz -from bastd.gameutils import SharedObjects -from bastd.actor.powerupbox import PowerupBoxFactory -from bastd.actor.spazfactory import SpazFactory -from bastd.game.elimination import EliminationGame +import babase +import bauiv1 as bui +import bascenev1 as bs +import _babase +import bascenev1lib +from bascenev1lib.actor.text import Text +from bascenev1lib.actor.image import Image +from bascenev1lib.actor import spaz +from bascenev1lib.actor import playerspaz +from bascenev1lib.gameutils import SharedObjects +from bascenev1lib.actor.powerupbox import PowerupBoxFactory +from bascenev1lib.actor.spazfactory import SpazFactory +from bascenev1lib.game.elimination import EliminationGame import math import json import os @@ -26,12 +29,12 @@ CONTROLS_CENTER = (0, 0) CONTROLS_SCALE = 1 -BASE_STUNTS_DIRECTORY = os.path.join(_ba.env()["python_directory_user"], "CustomStunts") +BASE_STUNTS_DIRECTORY = os.path.join(_babase.env()["python_directory_user"], "CustomStunts") PLAYERS_STUNT_INFO = {} STUNT_CACHE = {} -original_on_begin = ba._activity.Activity.on_begin -original_chatmessage = _ba.chatmessage +original_on_begin = bs._activity.Activity.on_begin +original_chatmessage = bs.chatmessage class ControlsUI: @@ -105,7 +108,7 @@ def hide(activity): } -class NewSpaz(bastd.actor.spaz.Spaz): +class NewSpaz(bascenev1lib.actor.spaz.Spaz): def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) self.move_map = { @@ -125,7 +128,7 @@ def __init__(self, *args, **kwargs): } -class NewPlayerSpaz(bastd.actor.playerspaz.PlayerSpaz): +class NewPlayerSpaz(bascenev1lib.actor.playerspaz.PlayerSpaz): def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) self.move_map = { @@ -150,7 +153,7 @@ def __init__(self, *args, **kwargs): def _handle_action(self, action, value: Optional[float] = None) -> None: if self.source_player.sessionplayer in PLAYERS_STUNT_INFO: PLAYERS_STUNT_INFO[self.source_player.sessionplayer].append({ - "time": ba.time() - self.source_player.recording_start_time, + "time": bs.time() - self.source_player.recording_start_time, "move": { "action": action, "value": value, @@ -230,11 +233,11 @@ def handle_player_replay_end(player): def get_player_from_client_id(client_id, activity=None): - activity = activity or _ba.get_foreground_host_activity() + activity = activity or bs.get_foreground_host_activity() for player in activity.players: if player.sessionplayer.inputdevice.client_id == client_id: return player - raise ba.SessionPlayerNotFound() + raise bs.SessionPlayerNotFound() def mirror(clieid): @@ -243,8 +246,8 @@ def mirror(clieid): def capture(player): - with ba.Context(player.actor._activity()): - player.recording_start_time = ba.time() + with babase.ContextRef(player.actor._activity()): + player.recording_start_time = bs.time() PLAYERS_STUNT_INFO[player.sessionplayer] = [] @@ -266,33 +269,33 @@ def replay(player, stunt_name): stunt = json.load(fin) STUNT_CACHE[stunt_name] = stunt except: - ba.screenmessage(f"{stunt_name} doesn't exists") + bui.screenmessage(f"{stunt_name} doesn't exists") return player.in_replay = True - with ba.Context(player.actor._activity()): + with babase.ContextRef(player.actor._activity()): ControlsUI.display(player.actor._activity()) for move in stunt: value = move["move"]["value"] if value is None: - ba.timer( + bs.timer( move["time"], - ba.Call(player.actor.move_map[move["move"]["action"]]) + babase.Call(player.actor.move_map[move["move"]["action"]]) ) else: - ba.timer( + bs.timer( move["time"], - ba.Call(player.actor.move_map[move["move"]["action"]], move["move"]["value"]) + babase.Call(player.actor.move_map[move["move"]["action"]], move["move"]["value"]) ) last_move_time = move["time"] time_to_hide_controls = last_move_time + 1 - ba.timer(time_to_hide_controls, ba.Call(handle_player_replay_end, player)) + bs.timer(time_to_hide_controls, babase.Call(handle_player_replay_end, player)) def spawn_mirror_spaz(player): player.mirror_mode = True - with ba.Context(player.actor._activity()): + with babase.ContextRef(player.actor._activity()): bot = spaz.Spaz(player.color, player.highlight, character=player.character).autoretain() - bot.handlemessage(ba.StandMessage( + bot.handlemessage(bs.StandMessage( (player.actor.node.position[0], player.actor.node.position[1], player.actor.node.position[2]+1), 93)) bot.node.name = player.actor.node.name bot.node.name_color = player.actor.node.name_color @@ -309,51 +312,51 @@ def ghost(player, stunt_name): stunt = json.load(fin) STUNT_CACHE[stunt_name] = stunt except: - ba.screenmessage(f"{stunt_name} doesn't exists") + bui.screenmessage(f"{stunt_name} doesn't exists") return player.in_replay = True - with ba.Context(player.actor._activity()): + with babase.ContextRef(player.actor._activity()): bot = spaz.Spaz((1, 0, 0), character="Spaz").autoretain() - bot.handlemessage(ba.StandMessage(player.actor.node.position, 93)) + bot.handlemessage(bs.StandMessage(player.actor.node.position, 93)) give_ghost_power(bot) ControlsUI.display(player.actor._activity()) for move in stunt: value = move["move"]["value"] if value is None: - ba.timer( + bs.timer( move["time"], - ba.Call(bot.move_map[move["move"]["action"]]) + babase.Call(bot.move_map[move["move"]["action"]]) ) ui_activation = CONTROLS_UI_MAP.get(move["move"]["action"]) if ui_activation: - ba.timer( + bs.timer( move["time"], - ba.Call(ui_activation, player.actor._activity()) + babase.Call(ui_activation, player.actor._activity()) ) else: - ba.timer( + bs.timer( move["time"], - ba.Call(bot.move_map[move["move"]["action"]], move["move"]["value"]) + babase.Call(bot.move_map[move["move"]["action"]], move["move"]["value"]) ) ui_activation = CONTROLS_UI_MAP.get(move["move"]["action"]) if ui_activation: - ba.timer( + bs.timer( move["time"], - ba.Call(ui_activation, player.actor._activity(), move["move"]["value"]) + babase.Call(ui_activation, player.actor._activity(), move["move"]["value"]) ) last_move_time = move["time"] time_to_hide_controls = last_move_time + 1 - ba.timer(time_to_hide_controls, ba.Call(handle_player_replay_end, player)) - ba.timer(time_to_hide_controls, ba.Call(bot.node.delete)) + bs.timer(time_to_hide_controls, babase.Call(handle_player_replay_end, player)) + bs.timer(time_to_hide_controls, babase.Call(bot.node.delete)) def give_ghost_power(spaz): spaz.node.invincible = True shared = SharedObjects.get() factory = SpazFactory.get() - ghost = ba.Material() + ghost = bs.Material() # smoothy hecks ghost.add_actions( conditions=(('they_have_material', factory.spaz_material), 'or', @@ -397,7 +400,7 @@ def new_chatmessage(msg): if command == "start": capture(player) - _ba.chatmessage("Recording started for {}.".format( + bs.chatmessage("Recording started for {}.".format( player.getname(), )) return original_chatmessage(msg) @@ -406,28 +409,28 @@ def new_chatmessage(msg): if command == "save": if len(msg_splits) < 2: - ba.screenmessage("Enter name of stunt eg : *save bombjump") + bui.screenmessage("Enter name of stunt eg : *save bombjump") return original_chatmessage(msg) save(player, stunt_name) - _ba.chatmessage('Recording "{}" by {} saved.'.format( + bs.chatmessage('Recording "{}" by {} saved.'.format( stunt_name, player.getname(), )) elif command == "stunt": if len(msg_splits) < 2: - ba.screenmessage("Enter name of stunt eg : *stunt bombjump") + bui.screenmessage("Enter name of stunt eg : *stunt bombjump") return original_chatmessage(msg) replay(player, stunt_name) - _ba.chatmessage('Replaying "{}" on {}.'.format( + bs.chatmessage('Replaying "{}" on {}.'.format( stunt_name, player.getname(), )) elif command == "learn": if len(msg_splits) < 2: - ba.screenmessage("Enter name of stunt eg : *learn bombjump") + bui.screenmessage("Enter name of stunt eg : *learn bombjump") return original_chatmessage(msg) ghost(player, stunt_name) - _ba.chatmessage('Replaying "{}" on {}.'.format( + bs.chatmessage('Replaying "{}" on {}.'.format( stunt_name, player.getname(), )) @@ -473,25 +476,25 @@ def set_stick_image_position(self, x: float, y: float) -> None: def on_begin(self, *args, **kwargs) -> None: self._jump_image = Image( - ba.gettexture('buttonJump'), + bui.gettexture('buttonJump'), position=(385, 160), scale=(50, 50), color=[0.1, 0.45, 0.1, 0] ) self._pickup_image = Image( - ba.gettexture('buttonPickUp'), + bui.gettexture('buttonPickUp'), position=(385, 240), scale=(50, 50), color=[0, 0.35, 0, 0] ) self._punch_image = Image( - ba.gettexture('buttonPunch'), + bui.gettexture('buttonPunch'), position=(345, 200), scale=(50, 50), color=[0.45, 0.45, 0, 0] ) self._bomb_image = Image( - ba.gettexture('buttonBomb'), + bui.gettexture('buttonBomb'), position=(425, 200), scale=(50, 50), color=[0.45, 0.1, 0.1, 0] @@ -499,10 +502,10 @@ def on_begin(self, *args, **kwargs) -> None: self.stick_image_position_x = self.stick_image_position_y = 0.0 self._stick_base_position = p = (-328, 200) self._stick_base_image_color = c2 = (0.25, 0.25, 0.25, 1.0) - self._stick_base_image = ba.newnode( + self._stick_base_image = bs.newnode( 'image', attrs={ - 'texture': ba.gettexture('nub'), + 'texture': bui.gettexture('nub'), 'absolute_scale': True, 'vr_depth': -40, 'position': p, @@ -511,9 +514,9 @@ def on_begin(self, *args, **kwargs) -> None: }) self._stick_nub_position = p = (-328, 200) self._stick_nub_image_color = c3 = (0.4, 0.4, 0.4, 1.0) - self._stick_nub_image = ba.newnode('image', + self._stick_nub_image = bs.newnode('image', attrs={ - 'texture': ba.gettexture('nub'), + 'texture': bui.gettexture('nub'), 'absolute_scale': True, 'position': p, 'scale': (110*0.6, 110*0.66), @@ -526,22 +529,22 @@ def on_begin(self, *args, **kwargs) -> None: # ba_meta export plugin -class byHeySmoothy(ba.Plugin): +class byHeySmoothy(babase.Plugin): def on_app_running(self): - _ba.set_party_icon_always_visible(True) - ba._activity.Activity.on_begin = on_begin - _ba.chatmessage = new_chatmessage - bastd.actor.playerspaz.PlayerSpaz = NewPlayerSpaz - bastd.actor.spaz.Spaz = NewSpaz + bui.set_party_icon_always_visible(True) + bs._activity.Activity.on_begin = on_begin + bs.chatmessage = new_chatmessage + bascenev1lib.actor.playerspaz.PlayerSpaz = NewPlayerSpaz + bascenev1lib.actor.spaz.Spaz = NewSpaz # lets define a sample elimination game that can use super power of this plugin -# ba_meta export game +# ba_meta export bascenev1.GameActivity class BroEliminaition(EliminationGame): name = 'BroElimination' description = 'Elimination Game with dual character control' - def spawn_player(self, player) -> ba.Actor: + def spawn_player(self, player) -> bs.Actor: super().spawn_player(player) spawn_mirror_spaz(player) diff --git a/plugins/utilities/autorun.py b/plugins/utilities/autorun.py index 263b1b43..f72b1435 100644 --- a/plugins/utilities/autorun.py +++ b/plugins/utilities/autorun.py @@ -1,4 +1,5 @@ -# ba_meta require api 7 +# Porting to api 8 made easier by baport.(https://github.com/bombsquad-community/baport) +# ba_meta require api 8 """ AutoRun by TheMikirog @@ -18,11 +19,13 @@ from typing import TYPE_CHECKING # Let's import everything we need and nothing more. -import ba -import bastd +import babase +import bauiv1 as bui +import bascenev1 as bs +import bascenev1lib import math -from ba._generated.enums import TimeType -from bastd.actor.spaz import Spaz +from babase._mgen.enums import TimeType +from bascenev1lib.actor.spaz import Spaz if TYPE_CHECKING: pass @@ -72,8 +75,7 @@ # ba_meta export plugin -class AutoRun(ba.Plugin): - +class AutoRun(babase.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. @@ -109,14 +111,13 @@ def normalize(vector): # 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_timer: bs.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. @@ -140,12 +141,14 @@ def spaz_autorun_update(): # 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 = bs.Timer(0.1, spaz_autorun_update, 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__) + bascenev1lib.actor.spaz.Spaz.__init__ = new_init( + bascenev1lib.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. @@ -170,8 +173,10 @@ def run_update(self) -> None: 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]) + 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) @@ -216,9 +221,11 @@ def wrapper(*args, **kwargs): 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) + bascenev1lib.actor.spaz.Spaz.on_run = new_onrun(bascenev1lib.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. @@ -229,9 +236,13 @@ def wrapper(*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) + bascenev1lib.actor.spaz.Spaz.on_move_up_down = new_updown( + bascenev1lib.actor.spaz.Spaz.on_move_up_down + ) # Let's do the same for our horizontal axis. # Second verse same as the first. @@ -240,9 +251,12 @@ 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) + + bascenev1lib.actor.spaz.Spaz.on_move_left_right = new_leftright( + bascenev1lib.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. @@ -250,10 +264,14 @@ def wrapper(*args, **kwargs): def new_handlemessage(func): def wrapper(*args, **kwargs): # Only react to the death message. - if isinstance(args[1], ba.DieMessage): + if isinstance(args[1], bs.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) + + bascenev1lib.actor.spaz.Spaz.handlemessage = new_handlemessage( + bascenev1lib.actor.spaz.Spaz.handlemessage + ) diff --git a/plugins/utilities/bomb_radius_visualizer.py b/plugins/utilities/bomb_radius_visualizer.py index 994ccef4..88229617 100644 --- a/plugins/utilities/bomb_radius_visualizer.py +++ b/plugins/utilities/bomb_radius_visualizer.py @@ -1,4 +1,5 @@ -# ba_meta require api 7 +# Porting to api 8 made easier by baport.(https://github.com/bombsquad-community/baport) +# ba_meta require api 8 """ Bomb Radius Visualizer by TheMikirog @@ -16,9 +17,11 @@ from typing import TYPE_CHECKING # Let's import everything we need and nothing more. -import ba -import bastd -from bastd.actor.bomb import Bomb +import babase +import bauiv1 as bui +import bascenev1 as bs +import bascenev1lib +from bascenev1lib.actor.bomb import Bomb if TYPE_CHECKING: pass @@ -26,7 +29,7 @@ # ba_meta export plugin -class BombRadiusVisualizer(ba.Plugin): +class BombRadiusVisualizer(babase.Plugin): # We use a decorator to add extra code to existing code, increasing mod compatibility. # Here I'm defining a new bomb init function that'll be replaced. @@ -44,7 +47,7 @@ def wrapper(*args, **kwargs): # Let's make a new node that's just a circle. It's the some one used in the Target Practice minigame. # This is going to make a slightly opaque red circle, signifying damaging area. # We aren't defining the size, because we're gonna animate it shortly after. - args[0].radius_visualizer = ba.newnode('locator', + args[0].radius_visualizer = bs.newnode('locator', # Remove itself when the bomb node dies. owner=args[0].node, attrs={ @@ -59,14 +62,14 @@ def wrapper(*args, **kwargs): # Let's do a fancy animation of that red circle growing into shape like a cartoon. # We're gonna read our bomb's blast radius and use it to decide the size of our circle. - ba.animate_array(args[0].radius_visualizer, 'size', 1, { + bs.animate_array(args[0].radius_visualizer, 'size', 1, { 0.0: [0.0], 0.2: [args[0].blast_radius * 2.2], 0.25: [args[0].blast_radius * 2.0] }) # Let's do a second circle, this time just the outline to where the damaging area ends. - args[0].radius_visualizer_circle = ba.newnode('locator', + args[0].radius_visualizer_circle = bs.newnode('locator', # Remove itself when the bomb node dies. owner=args[0].node, attrs={ @@ -81,7 +84,7 @@ def wrapper(*args, **kwargs): args[0].node.connectattr('position', args[0].radius_visualizer_circle, 'position') # Let's animate that circle too, but this time let's do the opacity. - ba.animate( + bs.animate( args[0].radius_visualizer_circle, 'opacity', { 0: 0.0, 0.4: 0.1 @@ -90,4 +93,4 @@ def wrapper(*args, **kwargs): # Finally we """travel through the game files""" to replace the function we want with our own version. # We transplant the old function's arguments into our version. - bastd.actor.bomb.Bomb.__init__ = new_bomb_init(bastd.actor.bomb.Bomb.__init__) + bascenev1lib.actor.bomb.Bomb.__init__ = new_bomb_init(bascenev1lib.actor.bomb.Bomb.__init__) diff --git a/plugins/utilities/chat_cmd.py b/plugins/utilities/chat_cmd.py index 5bb3da4f..071073b6 100644 --- a/plugins/utilities/chat_cmd.py +++ b/plugins/utilities/chat_cmd.py @@ -1,12 +1,22 @@ +# Ported by brostos to api 8 +# Tool used to make porting easier.(https://github.com/bombsquad-community/baport) """python 3.9 | chatcmd for a beutiful game - BombSquad OwO""" # modded by IM_NOT_PRANAV#7874 # biggggggg thankssssssssssssss to FireFighter1037 for helping everything # -*- coding: utf-8 -*- -# ba_meta require api 7 -from _ba import env, get_foreground_host_activity, get_foreground_host_session, get_game_roster, get_chat_messages, set_party_icon_always_visible, chatmessage as cmsg, screenmessage as smsg -import ba +# Ported by brostos to api 8 +# ba_meta require api 8 + +import threading +import time +from bascenev1 import get_foreground_host_activity, get_foreground_host_session, get_game_roster, get_chat_messages, chatmessage as cmsg +from bauiv1 import set_party_icon_always_visible, screenmessage as smsg +import babase +import bauiv1 as bui +import bascenev1 as bs +from bauiv1lib import mainmenu # our prefix that what we starts cmds with px = '/' @@ -17,17 +27,20 @@ class _cmds: def _process_cmd(): - set_party_icon_always_visible(True) - messages = get_chat_messages() - if len(messages) > 1: - lastmsg = messages[len(messages)-1] - - m = lastmsg.split(' ')[1] - if m.startswith(px): - return _cmds._handle() - else: - pass + try: + messages = get_chat_messages() + if len(messages) > 1: + lastmsg = messages[len(messages)-1] + + m = lastmsg.split(' ')[1] + if m.startswith(px): + return _cmds._handle() + else: + pass + except: + pass + def _handle(): messages = get_chat_messages() if len(messages) > 1: @@ -137,17 +150,17 @@ def _handle(): cmsg('could not found player') elif m in [px+'quit', px+'restart']: - ba.quit() + babase.quit() elif m in [px+'mute', px+'mutechat']: - cfg = ba.app.config + cfg = babase.app.config cfg['Chat Muted'] = True cfg.apply_and_commit() cmsg('muted') smsg(f'chat muted use {px}unmute and click on send to unmute') elif m in [px+'unmute', px+'unmutechat']: - cfg = ba.app.config + cfg = babase.app.config cfg['Chat Muted'] = False cfg.apply_and_commit() cmsg('un_muted') @@ -222,16 +235,16 @@ def _handle(): elif n[0] == 'all': for i in activity_players: body = i.actor.node - if not body.torso_model == None: - body.head_model = None - body.torso_model = None - body.upper_arm_model = None - body.forearm_model = None - body.pelvis_model = None - body.hand_model = None - body.toes_model = None - body.upper_leg_model = None - body.lower_leg_model = None + if not body.torso_mesh == None: + body.head_mesh = None + body.torso_mesh = None + body.upper_arm_mesh = None + body.forearm_mesh = None + body.pelvis_mesh = None + body.hand_mesh = None + body.toes_mesh = None + body.upper_leg_mesh = None + body.lower_leg_mesh = None body.style = 'cyborg' cmsg('All invisible now Dont get cought') else: @@ -239,16 +252,16 @@ def _handle(): else: body = activity_players[int(n[0])].actor.node is_name = session_players[int(n[0])].getname() - if not body.torso_model == None: - body.head_model = None - body.torso_model = None - body.upper_arm_model = None - body.forearm_model = None - body.pelvis_model = None - body.hand_model = None - body.toes_model = None - body.upper_leg_model = None - body.lower_leg_model = None + if not body.torso_mesh == None: + body.head_mesh = None + body.torso_mesh = None + body.upper_arm_mesh = None + body.forearm_mesh = None + body.pelvis_mesh = None + body.hand_mesh = None + body.toes_mesh = None + body.upper_leg_mesh = None + body.lower_leg_mesh = None body.style = 'cyborg' cmsg(is_name+' using invisiblelity ') else: @@ -260,8 +273,8 @@ def _handle(): elif n[0] == 'all': for i in activity_players: body = i.actor.node - if not body.head_model == None: - body.head_model = None + if not body.head_mesh == None: + body.head_mesh = None body.style = 'cyborg' cmsg('headless ? xD') else: @@ -269,8 +282,8 @@ def _handle(): else: body = activity_players[int(n[0])].actor.node is_name = session_players[int(n[0])].getname() - if not body.head_model == None: - body.head_model = None + if not body.head_mesh == None: + body.head_mesh = None body.style = 'cyborg' cmsg(is_name+'is headless now xD') else: @@ -282,16 +295,16 @@ def _handle(): elif n[0] == 'all': for i in activity_players: body = i.actor.node - body.head_model = None - body.handlemessage(ba.PowerupMessage(poweruptype='punch')) - body.handlemessage(ba.PowerupMessage(poweruptype='shield')) + body.head_mesh = None + body.handlemessage(bs.PowerupMessage(poweruptype='punch')) + body.handlemessage(bs.PowerupMessage(poweruptype='shield')) cmsg('dont creep out childs all will be scared') else: try: body = activity_players[int(n[0])].actor.node - body.head_model = None - body.handlemessage(ba.PowerupMessage(poweruptype='punch')) - body.handlemessage(ba.PowerupMessage(poweruptype='shield')) + body.head_mesh = None + body.handlemessage(bs.PowerupMessage(poweruptype='punch')) + body.handlemessage(bs.PowerupMessage(poweruptype='shield')) cmsg('dont creep out childs all will be scared') except: cmsg('could not found player to make') @@ -301,11 +314,11 @@ def _handle(): cmsg(f'Use : {px}kill all or {px}kill number of list') elif n[0] == 'all': for i in activity_players: - i.actor.node.handlemessage(ba.DieMessage()) + i.actor.node.handlemessage(bs.DieMessage()) cmsg('Killed all') else: is_name = session_players[int(n[0])].getname() - activity_players[int(n[0])].actor.node.handlemessage(ba.DieMessage()) + activity_players[int(n[0])].actor.node.handlemessage(bs.DieMessage()) cmsg('Killed '+is_name) elif m in [px+'heal', px+'heath']: @@ -313,12 +326,12 @@ def _handle(): cmsg(f'Use: {px}heal all or {px}heal number of list') elif n[0] == 'all': for i in activity_players: - i.actor.node.handlemessage(ba.PowerupMessage(poweruptype='health')) + i.actor.node.handlemessage(bs.PowerupMessage(poweruptype='health')) cmsg('Heald all') else: is_name = session_players[int(n[0])].getname() activity_players[int(n[0])].actor.node.handlemessage( - ba.PowerupMessage(poweruptype='health')) + bs.PowerupMessage(poweruptype='health')) cmsg('Heald '+is_name) elif m in [px+'curse', px+'cur']: @@ -326,12 +339,12 @@ def _handle(): cmsg(f'Use: {px}curse all or {px}curse number of list') elif n[0] == 'all': for i in activity_players: - i.actor.node.handlemessage(ba.PowerupMessage(poweruptype='curse')) + i.actor.node.handlemessage(bs.PowerupMessage(poweruptype='curse')) cmsg('Cursed all') else: is_name = session_players[int(n[0])].getname() activity_players[int(n[0])].actor.node.handlemessage( - ba.PowerupMessage(poweruptype='curse')) + bs.PowerupMessage(poweruptype='curse')) cmsg('Cursed '+is_name) elif m in [px+'sleep']: @@ -378,12 +391,12 @@ def _handle(): cmsg(f'Use: {px}gloves all or {px}gloves number of list') elif n[0] == 'all': for i in activity_players: - i.actor.node.handlemessage(ba.PowerupMessage(poweruptype='punch')) + i.actor.node.handlemessage(bs.PowerupMessage(poweruptype='punch')) cmsg('Free Gloves enjoy all') else: is_name = session_players[int(n[0])].getname() activity_players[int(n[0])].actor.node.handlemessage( - ba.PowerupMessage(poweruptype='punch')) + bs.PowerupMessage(poweruptype='punch')) cmsg(is_name+' using gloves') elif m in [px+'shield', px+'protect']: @@ -391,12 +404,12 @@ def _handle(): cmsg(f'Use: {px}shield all or {px}shield number of list') elif n[0] == 'all': for i in activity_players: - i.actor.node.handlemessage(ba.PowerupMessage(poweruptype='shield')) + i.actor.node.handlemessage(bs.PowerupMessage(poweruptype='shield')) cmsg('Everyone enjoy free shield :)') else: is_name = session_players[int(n[0])].getname() activity_players[int(n[0])].actor.node.handlemessage( - ba.PowerupMessage(poweruptype='shield')) + bs.PowerupMessage(poweruptype='shield')) cmsg(is_name+' using shield') elif m in [px+'freeze', px+'ice']: @@ -404,11 +417,11 @@ def _handle(): cmsg(f'Use: {px}freeze all or {px}freeze number of list') elif n[0] == 'all': for i in activity_players: - i.actor.node.handlemessage(ba.FreezeMessage()) + i.actor.node.handlemessage(bs.FreezeMessage()) cmsg('Freezed all') else: is_name = session_players[int(n[0])].getname() - activity_players[int(n[0])].actor.node.handlemessage(ba.FreezeMessage()) + activity_players[int(n[0])].actor.node.handlemessage(bs.FreezeMessage()) cmsg('Un freezed '+is_name) elif m in [px+'unfreeze', px+'thaw']: @@ -416,11 +429,11 @@ def _handle(): cmsg(f'Use: {px}unfreeze/thaw all or {px}unfreeze/thaw number of list') elif n[0] == 'all': for i in activity_players: - i.actor.node.handlemessage(ba.ThawMessage()) + i.actor.node.handlemessage(bs.ThawMessage()) cmsg('Un freezed all ') else: is_name = session_players[int(n[0])].getname() - activity_players[int(n[0])].actor.node.handlemessage(ba.ThawMessage()) + activity_players[int(n[0])].actor.node.handlemessage(bs.ThawMessage()) cmsg('Un freezed '+is_name) elif m in [px+'fall']: @@ -428,11 +441,11 @@ def _handle(): cmsg(f'Use: {px}fall all or {px}fall number of list') elif n[0] == 'all': for i in activity_players: - i.actor.node.handlemessage(ba.StandMessage()) + i.actor.node.handlemessage(bs.StandMessage()) cmsg('Felt everyone') else: is_name = session_players[int(n[0])].getname() - activity_players[int(n[0])].actor.node.handlemessage(ba.StandMessage()) + activity_players[int(n[0])].actor.node.handlemessage(bs.StandMessage()) cmsg(is_name+' got felt') elif m in [px+'celebrate', px+'celeb']: @@ -440,11 +453,11 @@ def _handle(): cmsg(f'Use: {px}celebrate all or {px}celebrate number of list') elif n[0] == 'all': for i in activity_players: - i.actor.node.handlemessage(ba.CelebrateMessage()) + i.actor.node.handlemessage(bs.CelebrateMessage()) cmsg('Celebrate all :)') else: is_name = session_players[int(n[0])].getname() - activity_players[int(n[0])].actor.node.handlemessage(ba.CelebrateMessage()) + activity_players[int(n[0])].actor.node.handlemessage(bs.CelebrateMessage()) cmsg(is_name+' is celebrating bt why?') elif m in [px+'fly']: @@ -531,13 +544,24 @@ def _handle(): cmsg(u'\U0001F95A Nazz are past/present/future \U0001F95A') cmsg(u'\U0001F95A everything is Nazz \U0001F95A') - -# ba.timer(0.05, _update, repeat=True) +class NewMainMenuWindow(mainmenu.MainMenuWindow): + def __init__(self, *args, **kwargs): + super().__init__(*args, **kwargs) + # Display chat icon, but if user open/close gather it may disappear + bui.set_party_icon_always_visible(True) + +# bs.timer(0.05, _update, repeat=True) def same(): - ba.timer(0.5, _cmds._process_cmd, True) + # bs.timer(0.5, _cmds._process_cmd, True) + _cmds._process_cmd() +# ba_meta export babase.Plugin -# ba_meta export plugin +class _enableee(babase.Plugin): + timer = bs.AppTimer(0.5, same,repeat=True) + + def on_app_running(self): + mainmenu.MainMenuWindow = NewMainMenuWindow -class _enableee(ba.Plugin): - same() + + \ No newline at end of file diff --git a/plugins/utilities/colored_bomb_explosion_patches.py b/plugins/utilities/colored_bomb_explosion_patches.py index 3ea0ba6e..813989e7 100644 --- a/plugins/utilities/colored_bomb_explosion_patches.py +++ b/plugins/utilities/colored_bomb_explosion_patches.py @@ -1,13 +1,16 @@ -# ba_meta require api 7 +# Porting to api 8 made easier by baport.(https://github.com/bombsquad-community/baport) +# ba_meta require api 8 # (see https://ballistica.net/wiki/meta-tag-system) from __future__ import annotations from typing import TYPE_CHECKING -import ba +import babase +import bauiv1 as bui +import bascenev1 as bs import random -from bastd.actor import bomb +from bascenev1lib.actor import bomb if TYPE_CHECKING: from typing import Sequence @@ -20,7 +23,7 @@ def __init__( velocity: Sequence[float] = (0.0, 0.0, 0.0), blast_radius: float = 2.0, blast_type: str = 'normal', - source_player: ba.Player | None = None, + source_player: bs.Player | None = None, hit_type: str = 'explosion', hit_subtype: str = 'normal', ): @@ -29,7 +32,7 @@ def __init__( scorch_radius = light_radius = self.radius if self.blast_type == 'tnt': scorch_radius *= 1.15 - scorch = ba.newnode( + scorch = bs.newnode( 'scorch', attrs={ 'position': position, @@ -38,11 +41,11 @@ def __init__( }, ) random_color = (random.random(), random.random(), random.random()) - scorch.color = ba.safecolor(random_color) - ba.animate(scorch, 'presence', {3.000: 1, 13.000: 0}) - ba.timer(13.0, scorch.delete) + scorch.color = babase.safecolor(random_color) + bs.animate(scorch, 'presence', {3.000: 1, 13.000: 0}) + bs.timer(13.0, scorch.delete) # ba_meta export plugin -class RandomColorsPlugin(ba.Plugin): +class RandomColorsPlugin(babase.Plugin): bomb.Blast = NewBlast diff --git a/plugins/utilities/custom_death.py b/plugins/utilities/custom_death.py index b3730e12..bc8a66b6 100644 --- a/plugins/utilities/custom_death.py +++ b/plugins/utilities/custom_death.py @@ -1,12 +1,14 @@ -# ba_meta require api 7 +# Porting to api 8 made easier by baport.(https://github.com/bombsquad-community/baport) +# ba_meta require api 8 # (see https://ballistica.net/wiki/meta-tag-system) from __future__ import annotations from typing import TYPE_CHECKING -import ba -from bastd.actor.spaz import Spaz +import babase +import bascenev1 as bs +from bascenev1lib.actor.spaz import Spaz if TYPE_CHECKING: from typing import Any @@ -16,19 +18,19 @@ def handlemessage(self, msg: Any) -> Any: - if isinstance(msg, ba.DieMessage): + if isinstance(msg, bs.DieMessage): if self.node: - self.node.color_texture = ba.gettexture('bonesColor') - self.node.color_mask_texture = ba.gettexture('bonesColorMask') - self.node.head_model = ba.getmodel('bonesHead') - self.node.torso_model = ba.getmodel('bonesTorso') - self.node.pelvis_model = ba.getmodel('bonesPelvis') - self.node.upper_arm_model = ba.getmodel('bonesUpperArm') - self.node.forearm_model = ba.getmodel('bonesForeArm') - self.node.hand_model = ba.getmodel('bonesHand') - self.node.upper_leg_model = ba.getmodel('bonesUpperLeg') - self.node.lower_leg_model = ba.getmodel('bonesLowerLeg') - self.node.toes_model = ba.getmodel('bonesToes') + self.node.color_texture = bs.gettexture('bonesColor') + self.node.color_mask_texture = bs.gettexture('bonesColorMask') + self.node.head_mesh = bs.getmesh('bonesHead') + self.node.torso_mesh = bs.getmesh('bonesTorso') + self.node.pelvis_mesh = bs.getmesh('bonesPelvis') + self.node.upper_arm_mesh = bs.getmesh('bonesUpperArm') + self.node.forearm_mesh = bs.getmesh('bonesForeArm') + self.node.hand_mesh = bs.getmesh('bonesHand') + self.node.upper_leg_mesh = bs.getmesh('bonesUpperLeg') + self.node.lower_leg_mesh = bs.getmesh('bonesLowerLeg') + self.node.toes_mesh = bs.getmesh('bonesToes') self.node.style = 'bones' self.oldhandlemessage(msg) else: @@ -36,5 +38,5 @@ def handlemessage(self, msg: Any) -> Any: # ba_meta export plugin -class CustomDeath(ba.Plugin): +class CustomDeath(babase.Plugin): Spaz.handlemessage = handlemessage diff --git a/plugins/utilities/disco_light.py b/plugins/utilities/disco_light.py index b87553b5..572baa04 100644 --- a/plugins/utilities/disco_light.py +++ b/plugins/utilities/disco_light.py @@ -1,3 +1,4 @@ +# Porting to api 8 made easier by baport.(https://github.com/bombsquad-community/baport) """Disco Light Mod: V1.0 Made by Cross Joy""" @@ -5,7 +6,7 @@ # Can visit my github https://github.com/CrossJoy/Bombsquad-Modding # You can contact me through discord: -# My Discord Id: Cross Joy#0721 +# My Discord Id: crossjoy # My BS Discord Server: https://discord.gg/JyBY6haARJ @@ -25,19 +26,22 @@ # Other clients/players can't use the commands. # ---------------------------------------------------------------------------- -# ba_meta require api 7 +# ba_meta require api 8 from __future__ import annotations from typing import TYPE_CHECKING -import ba -import _ba -from ba import _gameutils +from baenv import TARGET_BALLISTICA_BUILD as build_number +from bauiv1lib import mainmenu +import babase +import bauiv1 as bui +import bascenev1 as bs +import _babase +from bascenev1 import _gameutils, animate import random -from ba import animate if TYPE_CHECKING: from typing import Sequence, Union @@ -51,38 +55,38 @@ def is_game_version_lower_than(version): version is lower than the passed version. Useful for addressing any breaking changes within game versions. """ - game_version = tuple(map(int, ba.app.version.split("."))) + game_version = tuple(map(int, babase.app.version if build_number < 21282 else babase.app.env.split("."))) version = tuple(map(int, version.split("."))) return game_version < version -if is_game_version_lower_than("1.7.7"): - ba_internal = _ba -else: - ba_internal = ba.internal +# if is_game_version_lower_than("1.7.7"): +# ba_internal = _ba +# else: +# ba_internal = babase.internal # Activate disco light. def start(): - activity = _ba.get_foreground_host_activity() + activity = bs.get_foreground_host_activity() - with ba.Context(activity): + with activity.context: partyLight(True) rainbow(activity) # Deactivate disco light. def stop(): - activity = _ba.get_foreground_host_activity() + activity = bs.get_foreground_host_activity() - with ba.Context(activity): + with activity.context: partyLight(False) stop_rainbow(activity) # Create and animate colorful spotlight. def partyLight(switch=True): - from ba._nodeactor import NodeActor + from bascenev1._nodeactor import NodeActor x_spread = 10 y_spread = 5 positions = [[-x_spread, -y_spread], [0, -y_spread], [0, y_spread], @@ -91,14 +95,14 @@ def partyLight(switch=True): times = [0, 2700, 1000, 1800, 500, 1400] # Store this on the current activity, so we only have one at a time. - activity = _ba.getactivity() + activity = bs.getactivity() activity.camera_flash_data = [] # type: ignore for i in range(6): r = random.choice([0.5, 1]) g = random.choice([0.5, 1]) b = random.choice([0.5, 1]) light = NodeActor( - _ba.newnode('light', + bs.newnode('light', attrs={ 'position': (positions[i][0], 0, positions[i][1]), 'radius': 1.0, @@ -108,7 +112,7 @@ def partyLight(switch=True): })) sval = 1.87 iscale = 1.3 - tcombine = _ba.newnode('combine', + tcombine = bs.newnode('combine', owner=light.node, attrs={ 'size': 3, @@ -149,7 +153,7 @@ def partyLight(switch=True): loop=True, offset=times[i]) if not switch: - _ba.timer(0.1, + bs.timer(0.1, light.node.delete) activity.camera_flash_data.append(light) # type: ignore @@ -158,7 +162,7 @@ def partyLight(switch=True): def rainbow(self) -> None: """Create RGB tint.""" c_existing = self.globalsnode.tint - cnode = _ba.newnode('combine', + cnode = bs.newnode('combine', attrs={ 'input0': c_existing[0], 'input1': c_existing[1], @@ -187,11 +191,14 @@ def rainbow(self) -> None: # Revert to the original map tint. def stop_rainbow(self): """Revert to the original map tint.""" - c_existing = self.globalsnode.tint - map_name = self.map.getname() - tint = check_map_tint(map_name) + try: + c_existing = self.globalsnode.tint + map_name = self.map.getname() + tint = check_map_tint(map_name) + except: + tint = (1, 1, 1) - cnode = _ba.newnode('combine', + cnode = bs.newnode('combine', attrs={ 'input0': c_existing[0], 'input1': c_existing[1], @@ -249,11 +256,11 @@ def check_map_tint(map_name): # Get the original game codes. -old_fcm = ba_internal.chatmessage +old_fcm = bs.chatmessage # New chat func to add some commands to activate/deactivate the disco light. -def new_chat_message(msg: Union[str, ba.Lstr], clients: Sequence[int] = None, +def new_chat_message(msg: Union[str, babase.Lstr], clients: Sequence[int] = None, sender_override: str = None): old_fcm(msg, clients, sender_override) if msg == '/disco': @@ -261,13 +268,18 @@ def new_chat_message(msg: Union[str, ba.Lstr], clients: Sequence[int] = None, if msg == '/disco off': stop() - +class NewMainMenuWindow(mainmenu.MainMenuWindow): + def __init__(self, *args, **kwargs): + super().__init__(*args, **kwargs) + # Display chat icon, but if user open/close gather it may disappear + bui.set_party_icon_always_visible(True) + # Replace new chat func to the original game codes. -ba_internal.chatmessage = new_chat_message -if not ba_internal.is_party_icon_visible(): - ba_internal.set_party_icon_always_visible(True) +bs.chatmessage = new_chat_message # ba_meta export plugin -class ByCrossJoy(ba.Plugin): - def __init__(self): pass +class ByCrossJoy(babase.Plugin): + def on_app_running(self): + mainmenu.MainMenuWindow = NewMainMenuWindow + \ No newline at end of file diff --git a/plugins/utilities/discord_richpresence.py b/plugins/utilities/discord_richpresence.py index 70a1ee34..3028e649 100644 --- a/plugins/utilities/discord_richpresence.py +++ b/plugins/utilities/discord_richpresence.py @@ -370,7 +370,7 @@ def is_discord_running(): def _generate_join_secret(self): # resp = requests.get('https://legacy.ballistica.net/bsAccessCheck').text - connection_info = bs.get_connection_to_host_info_2() + connection_info = bs.get_connection_to_host_info() if build_number < 21697 else bs.get_connection_to_host_info_2() if connection_info: addr = _last_server_addr port = _last_server_port @@ -870,7 +870,7 @@ def _get_current_map_name(self) -> Tuple[str | None, str | None]: def update_status(self) -> None: roster = bs.get_game_roster() - connection_info = bs.get_connection_to_host_info_2() + connection_info = bs.get_connection_to_host_info() if build_number < 21697 else bs.get_connection_to_host_info_2() self.rpc_thread.large_image_key = "bombsquadicon" self.rpc_thread.large_image_text = "BombSquad" @@ -963,7 +963,7 @@ def update_status(self) -> None: points = act._score self.rpc_thread.details += f" ({points} points)" elif isinstance(act, MeteorShowerGame): - with bs.ContextRef(act): + with act.context: sec = bs.time() - act._timer.getstarttime() secfmt = "" if sec < 60: diff --git a/plugins/utilities/max_players.py b/plugins/utilities/max_players.py index 6d6257a4..f18265f5 100644 --- a/plugins/utilities/max_players.py +++ b/plugins/utilities/max_players.py @@ -1,29 +1,32 @@ +# Porting to api 8 made easier by baport.(https://github.com/bombsquad-community/baport) """===========MAX_PLAYERS===========""" -# ba_meta require api 7 +# ba_meta require api 8 # (see https://ballistica.net/wiki/meta-tag-system) from __future__ import annotations from typing import TYPE_CHECKING -import ba -import _ba -from ba._session import Session -from ba._coopsession import CoopSession, TEAM_COLORS, TEAM_NAMES -from ba._multiteamsession import MultiTeamSession -from bastd.ui.gather import GatherWindow -from bastd.ui.popup import PopupWindow +import babase +import bauiv1 as bui +import bascenev1 as bs +import _babase +from bascenev1._session import Session +from bascenev1._coopsession import CoopSession, TEAM_COLORS, TEAM_NAMES +from bascenev1._multiteamsession import MultiTeamSession +from bauiv1lib.gather import GatherWindow +from bauiv1lib.popup import PopupWindow if TYPE_CHECKING: from typing import List, Any, Optional, Sequence -cfg = ba.app.config +cfg = babase.app.config cmp = {'coop_max_players': 4, 'teams_max_players': 8, 'ffa_max_players': 8} -lang = ba.app.lang.language +lang = bs.app.lang.language if lang == 'Spanish': title_text = 'Máximo de Jugadores' title_short_text = 'Jugadores' @@ -41,7 +44,7 @@ class ConfigNumberEdit: def __init__(self, - parent: ba.Widget, + parent: bui.Widget, position: Tuple[float, float], value: int, config: str, @@ -53,7 +56,7 @@ def __init__(self, self._config = config textscale = 1.0 - self.nametext = ba.textwidget( + self.nametext = bui.textwidget( parent=parent, position=(position[0], position[1]), size=(100, 30), @@ -63,7 +66,7 @@ def __init__(self, h_align='left', v_align='center', scale=textscale) - self.valuetext = ba.textwidget( + self.valuetext = bui.textwidget( parent=parent, position=(position[0]+150, position[1]), size=(60, 28), @@ -73,21 +76,21 @@ def __init__(self, v_align='center', text=str(value), padding=2) - self.minusbutton = ba.buttonwidget( + self.minusbutton = bui.buttonwidget( parent=parent, position=(position[0]+240, position[1]), size=(28, 28), label='-', autoselect=True, - on_activate_call=ba.Call(self._down), + on_activate_call=babase.Call(self._down), repeat=True) - self.plusbutton = ba.buttonwidget( + self.plusbutton = bui.buttonwidget( parent=parent, position=(position[0]+290, position[1]), size=(28, 28), label='+', autoselect=True, - on_activate_call=ba.Call(self._up), + on_activate_call=babase.Call(self._up), repeat=True) def _up(self) -> None: @@ -99,7 +102,7 @@ def _down(self) -> None: self._update_display() def _update_display(self) -> None: - ba.textwidget(edit=self.valuetext, text=str(self._value)) + bui.textwidget(edit=self.valuetext, text=str(self._value)) cfg['Config Max Players'][self._config] = self._value cfg.apply_and_commit() @@ -108,7 +111,7 @@ class SettingsMaxPlayers(PopupWindow): def __init__(self): # pylint: disable=too-many-locals - uiscale = ba.app.ui.uiscale + uiscale = bui.app.ui_v1.uiscale self._transitioning_out = False self._width = 400 self._height = 220 @@ -121,7 +124,7 @@ def __init__(self): scale=1.2, bg_color=bg_color) - self._cancel_button = ba.buttonwidget( + self._cancel_button = bui.buttonwidget( parent=self.root_widget, position=(25, self._height - 40), size=(50, 50), @@ -130,12 +133,12 @@ def __init__(self): color=bg_color, on_activate_call=self._on_cancel_press, autoselect=True, - icon=ba.gettexture('crossOut'), + icon=bui.gettexture('crossOut'), iconscale=1.2) - ba.containerwidget(edit=self.root_widget, + bui.containerwidget(edit=self.root_widget, cancel_button=self._cancel_button) - ba.textwidget( + bui.textwidget( parent=self.root_widget, position=(self._width * 0.5, self._height - 30), size=(0, 0), @@ -144,7 +147,7 @@ def __init__(self): scale=0.8, text=title_text, maxwidth=200, - color=ba.app.ui.title_color) + color=bui.app.ui_v1.title_color) posx = 33 posy = self._height @@ -176,37 +179,38 @@ def _on_cancel_press(self) -> None: def _transition_out(self) -> None: if not self._transitioning_out: self._transitioning_out = True - ba.containerwidget(edit=self.root_widget, transition='out_scale') + bui.containerwidget(edit=self.root_widget, transition='out_scale') def on_popup_cancel(self) -> None: - ba.playsound(ba.getsound('swish')) + bui.getsound('swish').play() self._transition_out() def __init__(self) -> None: """Instantiate a co-op mode session.""" # pylint: disable=cyclic-import - from ba._campaign import getcampaign - from bastd.activity.coopjoin import CoopJoinActivity + getcampaign = bui.app.classic.getcampaign + from bascenev1lib.activity.coopjoin import CoopJoinActivity - _ba.increment_analytics_count('Co-op session start') - app = _ba.app + _babase.increment_analytics_count('Co-op session start') + app = babase.app + classic = app.classic # If they passed in explicit min/max, honor that. # Otherwise defer to user overrides or defaults. - if 'min_players' in app.coop_session_args: - min_players = app.coop_session_args['min_players'] + if 'min_players' in classic.coop_session_args: + min_players = classic.coop_session_args['min_players'] else: min_players = 1 - if 'max_players' in app.coop_session_args: - max_players = app.coop_session_args['max_players'] + if 'max_players' in classic.coop_session_args: + max_players = classic.coop_session_args['max_players'] else: max_players = app.config.get( 'Coop Game Max Players', cfg['Config Max Players']['coop_max_players']) # print('FIXME: COOP SESSION WOULD CALC DEPS.') - depsets: Sequence[ba.DependencySet] = [] + depsets: Sequence[babase.DependencySet] = [] Session.__init__(self, depsets, @@ -217,30 +221,30 @@ def __init__(self) -> None: # Tournament-ID if we correspond to a co-op tournament (otherwise None) self.tournament_id: Optional[str] = ( - app.coop_session_args.get('tournament_id')) + classic.coop_session_args.get('tournament_id')) - self.campaign = getcampaign(app.coop_session_args['campaign']) - self.campaign_level_name: str = app.coop_session_args['level'] + self.campaign = getcampaign(classic.coop_session_args['campaign']) + self.campaign_level_name: str = classic.coop_session_args['level'] self._ran_tutorial_activity = False - self._tutorial_activity: Optional[ba.Activity] = None + self._tutorial_activity: Optional[babase.Activity] = None self._custom_menu_ui: List[Dict[str, Any]] = [] # Start our joining screen. - self.setactivity(_ba.newactivity(CoopJoinActivity)) + self.setactivity(bs.newactivity(CoopJoinActivity)) - self._next_game_instance: Optional[ba.GameActivity] = None + self._next_game_instance: Optional[bs.GameActivity] = None self._next_game_level_name: Optional[str] = None self._update_on_deck_game_instances() def get_max_players(self) -> int: - """Return max number of ba.Players allowed to join the game at once.""" + """Return max number of bs.Players allowed to join the game at once.""" if self.use_teams: - return _ba.app.config.get( + return _babase.app.config.get( 'Team Game Max Players', cfg['Config Max Players']['teams_max_players']) - return _ba.app.config.get( + return _babase.app.config.get( 'Free-for-All Max Players', cfg['Config Max Players']['ffa_max_players']) @@ -250,18 +254,18 @@ def get_max_players(self) -> int: def __gather_init__(self, transition: Optional[str] = 'in_right', - origin_widget: ba.Widget = None): + origin_widget: bui.Widget = None): self.__old_init__(transition, origin_widget) def _do_max_players(): SettingsMaxPlayers() - self._max_players_button = ba.buttonwidget( + self._max_players_button = bui.buttonwidget( parent=self._root_widget, position=(self._width*0.72, self._height*0.91), size=(220, 60), scale=1.0, color=(0.6, 0.0, 0.9), - icon=ba.gettexture('usersButton'), + icon=bui.gettexture('usersButton'), iconscale=1.5, autoselect=True, label=title_short_text, @@ -290,11 +294,11 @@ def _save_state(self) -> None: sel_name = 'TabContainer' else: raise ValueError(f'unrecognized selection: \'{sel}\'') - ba.app.ui.window_states[type(self)] = { + bui.app.ui_v1.window_states[type(self)] = { 'sel_name': sel_name, } except Exception: - ba.print_exception(f'Error saving state for {self}.') + babase.print_exception(f'Error saving state for {self}.') def _restore_state(self) -> None: @@ -303,12 +307,12 @@ def _restore_state(self) -> None: for tab in self._tabs.values(): tab.restore_state() - sel: Optional[ba.Widget] - winstate = ba.app.ui.window_states.get(type(self), {}) + sel: Optional[bui.Widget] + winstate = bui.app.ui_v1.window_states.get(type(self), {}) sel_name = winstate.get('sel_name', None) assert isinstance(sel_name, (str, type(None))) current_tab = self.TabID.ABOUT - gather_tab_val = ba.app.config.get('Gather Tab') + gather_tab_val = babase.app.config.get('Gather Tab') try: stored_tab = enum_by_value(self.TabID, gather_tab_val) if stored_tab in self._tab_row.tabs: @@ -331,35 +335,35 @@ def _restore_state(self) -> None: sel = self._tab_row.tabs[sel_tab_id].button else: sel = self._tab_row.tabs[current_tab].button - ba.containerwidget(edit=self._root_widget, selected_child=sel) + bui.containerwidget(edit=self._root_widget, selected_child=sel) except Exception: - ba.print_exception('Error restoring gather-win state.') + babase.print_exception('Error restoring gather-win state.') # ba_meta export plugin -class MaxPlayersPlugin(ba.Plugin): +class MaxPlayersPlugin(babase.Plugin): def has_settings_ui(self) -> bool: return True - def show_settings_ui(self, source_widget: ba.Widget | None) -> None: + def show_settings_ui(self, source_widget: bui.Widget | None) -> None: SettingsMaxPlayers() - if 'Config Max Players' in ba.app.config: - old_config = ba.app.config['Config Max Players'] + if 'Config Max Players' in babase.app.config: + old_config = babase.app.config['Config Max Players'] for setting in cmp: if setting not in old_config: - ba.app.config['Config Max Players'].update({setting: cmp[setting]}) + babase.app.config['Config Max Players'].update({setting: cmp[setting]}) remove_list = [] for setting in old_config: if setting not in cmp: remove_list.append(setting) for element in remove_list: - ba.app.config['Config Max Players'].pop(element) + babase.app.config['Config Max Players'].pop(element) else: - ba.app.config['Config Max Players'] = cmp - ba.app.config.apply_and_commit() + babase.app.config['Config Max Players'] = cmp + babase.app.config.apply_and_commit() CoopSession.__init__ = __init__ MultiTeamSession.get_max_players = get_max_players diff --git a/plugins/utilities/mood_light.py b/plugins/utilities/mood_light.py index cb94021f..ec822dd4 100644 --- a/plugins/utilities/mood_light.py +++ b/plugins/utilities/mood_light.py @@ -1,16 +1,20 @@ -# ba_meta require api 7 +# Porting to api 8 made easier by baport.(https://github.com/bombsquad-community/baport) +# ba_meta require api 8 from __future__ import annotations from typing import TYPE_CHECKING, cast if TYPE_CHECKING: from typing import Any, Sequence, Callable, List, Dict, Tuple, Optional, Union import random -import ba -import _ba -from ba._map import Map -from bastd import mainmenu -from bastd.ui.party import PartyWindow -from bastd.gameutils import SharedObjects +import babase +import bauiv1 as bui +import bascenev1 as bs +import _babase +from bascenev1._map import Map +from bascenev1lib import mainmenu +from bauiv1lib.mainmenu import MainMenuWindow +from bauiv1lib.party import PartyWindow +from bascenev1lib.gameutils import SharedObjects """mood light plugin by ʟօʊքɢǟʀօʊ type ml in chat or use plugin manager to open settings""" @@ -21,7 +25,7 @@ def Print(*args): for arg in args: a = str(arg) out += a - ba.screenmessage(out) + bui.screenmessage(out) def cprint(*args): @@ -29,26 +33,26 @@ def cprint(*args): for arg in args: a = str(arg) out += a - _ba.chatmessage(out) + bs.chatmessage(out) try: - Ldefault, Udefault = ba.app.config.get("moodlightingSettings") + Ldefault, Udefault = babase.app.config.get("moodlightingSettings") except: - ba.app.config["moodlightingSettings"] = (15, 20) - Ldefault, Udefault = ba.app.config.get("moodlightingSettings") + babase.app.config["moodlightingSettings"] = (15, 20) + Ldefault, Udefault = babase.app.config.get("moodlightingSettings") Print("settings up moodlight") Print("Type ml in chat or use plugin manager to access settings") try: - loop = ba.app.config.get("moodlightEnabled") + loop = babase.app.config.get("moodlightEnabled") except: - ba.app.config["moodlightEnabled"] = True - ba.app.config.commit() + babase.app.config["moodlightEnabled"] = True + babase.app.config.commit() loop = True -class SettingWindow(ba.Window): +class SettingWindow(bui.Window): def __init__(self): self.draw_ui() @@ -56,57 +60,57 @@ def increase_limit(self): global Ldefault, Udefault try: if Udefault >= 29 and self.selected == "upper": - ba.textwidget(edit=self.warn_text, + bui.textwidget(edit=self.warn_text, text="Careful!You risk get blind beyond this point") elif self.selected == "lower" and Ldefault >= -20 or self.selected == "upper" and Udefault <= 30: - ba.textwidget(edit=self.warn_text, text="") + bui.textwidget(edit=self.warn_text, text="") if self.selected == "lower": Ldefault += 1 - ba.textwidget(edit=self.lower_text, text=str(Ldefault)) + bui.textwidget(edit=self.lower_text, text=str(Ldefault)) elif self.selected == "upper": Udefault += 1 - ba.textwidget(edit=self.upper_text, text=str(Udefault)) + bui.textwidget(edit=self.upper_text, text=str(Udefault)) except AttributeError: - ba.textwidget(edit=self.warn_text, text="Click on number to select it") + bui.textwidget(edit=self.warn_text, text="Click on number to select it") def decrease_limit(self): global Ldefault, Udefault try: if Ldefault <= -19 and self.selected == "lower": - ba.textwidget(edit=self.warn_text, + bui.textwidget(edit=self.warn_text, text="DON'T BE AFRAID OF DARK,IT'S A PLACE WHERE YOU CAN HIDE") elif (self.selected == "upper" and Udefault <= 30) or (self.selected == "lower" and Ldefault >= -20): - ba.textwidget(edit=self.warn_text, text="") + bui.textwidget(edit=self.warn_text, text="") if self.selected == "lower": Ldefault -= 1 - ba.textwidget(edit=self.lower_text, text=str(Ldefault)) + bui.textwidget(edit=self.lower_text, text=str(Ldefault)) elif self.selected == "upper": Udefault -= 1 - ba.textwidget(edit=self.upper_text, text=str(Udefault)) + bui.textwidget(edit=self.upper_text, text=str(Udefault)) except AttributeError: - ba.textwidget(edit=self.warn_text, text="Click on number to select it") + bui.textwidget(edit=self.warn_text, text="Click on number to select it") def on_text_click(self, selected): self.selected = selected if selected == "upper": - ba.textwidget(edit=self.upper_text, color=(0, 0, 1)) - ba.textwidget(edit=self.lower_text, color=(1, 1, 1)) + bui.textwidget(edit=self.upper_text, color=(0, 0, 1)) + bui.textwidget(edit=self.lower_text, color=(1, 1, 1)) elif selected == "lower": - ba.textwidget(edit=self.lower_text, color=(0, 0, 1)) - ba.textwidget(edit=self.upper_text, color=(1, 1, 1)) + bui.textwidget(edit=self.lower_text, color=(0, 0, 1)) + bui.textwidget(edit=self.upper_text, color=(1, 1, 1)) else: Print("this should't happen from on_text_click") def draw_ui(self): - self.uiscale = ba.app.ui.uiscale + self.uiscale = bui.app.ui_v1.uiscale super().__init__( - root_widget=ba.containerwidget( + root_widget=bui.containerwidget( size=(670, 670), on_outside_click_call=self.close, transition="in_right",)) - moodlight_label = ba.textwidget( + moodlight_label = bui.textwidget( parent=self._root_widget, size=(200, 100), position=(150, 550), @@ -117,7 +121,7 @@ def draw_ui(self): text="Mood light settings", color=(0, 1, 0)) - self.enable_button = ba.buttonwidget( + self.enable_button = bui.buttonwidget( parent=self._root_widget, position=(100, 470), size=(90, 70), @@ -126,7 +130,7 @@ def draw_ui(self): label="DISABLE" if loop else "ENABLE", on_activate_call=self.on_enableButton_press) - save_button = ba.buttonwidget( + save_button = bui.buttonwidget( parent=self._root_widget, position=(520, 470), size=(90, 70), @@ -134,18 +138,18 @@ def draw_ui(self): label="SAVE", on_activate_call=self.save_settings) - self.close_button = ba.buttonwidget( + self.close_button = bui.buttonwidget( parent=self._root_widget, position=(550, 590), size=(35, 35), - icon=ba.gettexture("crossOut"), + icon=bui.gettexture("crossOut"), icon_color=(1, 0.2, 0.2), scale=2, color=(1, 0.2, 0.2), extra_touch_border_scale=5, on_activate_call=self.close) - self.lower_text = ba.textwidget( + self.lower_text = bui.textwidget( parent=self._root_widget, size=(200, 100), scale=2, @@ -157,7 +161,7 @@ def draw_ui(self): click_activate=True, selectable=True) - lower_text_label = ba.textwidget( + lower_text_label = bui.textwidget( parent=self._root_widget, size=(200, 100), position=(100, 150), @@ -165,7 +169,7 @@ def draw_ui(self): v_align="center", text="Limit darkness") - self.upper_text = ba.textwidget( + self.upper_text = bui.textwidget( parent=self._root_widget, size=(200, 100), scale=2, @@ -177,7 +181,7 @@ def draw_ui(self): click_activate=True, selectable=True) - upper_text_label = ba.textwidget( + upper_text_label = bui.textwidget( parent=self._root_widget, size=(200, 100), position=(400, 150), @@ -185,25 +189,25 @@ def draw_ui(self): v_align="center", text="Limit brightness") - decrease_button = ba.buttonwidget( + decrease_button = bui.buttonwidget( parent=self._root_widget, position=(100, 100), size=(5, 1), scale=3.5, extra_touch_border_scale=2.5, - icon=ba.gettexture("downButton"), + icon=bui.gettexture("downButton"), on_activate_call=self.decrease_limit) - increase_button = ba.buttonwidget( + increase_button = bui.buttonwidget( parent=self._root_widget, position=(600, 100), size=(5, 1), scale=3.5, extra_touch_border_scale=2.5, - icon=ba.gettexture("upButton"), + icon=bui.gettexture("upButton"), on_activate_call=self.increase_limit) - self.warn_text = ba.textwidget( + self.warn_text = bui.textwidget( parent=self._root_widget, text="", size=(400, 200), @@ -213,28 +217,28 @@ def draw_ui(self): maxwidth=600) # ++++++++++++++++for keyboard navigation++++++++++++++++ - ba.widget(edit=self.enable_button, up_widget=decrease_button, + bui.widget(edit=self.enable_button, up_widget=decrease_button, down_widget=self.lower_text, left_widget=save_button, right_widget=save_button) - ba.widget(edit=save_button, up_widget=self.close_button, down_widget=self.upper_text, + bui.widget(edit=save_button, up_widget=self.close_button, down_widget=self.upper_text, left_widget=self.enable_button, right_widget=self.enable_button) - ba.widget(edit=self.close_button, up_widget=increase_button, down_widget=save_button, + bui.widget(edit=self.close_button, up_widget=increase_button, down_widget=save_button, left_widget=self.enable_button, right_widget=save_button) - ba.widget(edit=self.lower_text, up_widget=self.enable_button, down_widget=decrease_button, + bui.widget(edit=self.lower_text, up_widget=self.enable_button, down_widget=decrease_button, left_widget=self.upper_text, right_widget=self.upper_text) - ba.widget(edit=self.upper_text, up_widget=save_button, down_widget=increase_button, + bui.widget(edit=self.upper_text, up_widget=save_button, down_widget=increase_button, left_widget=self.lower_text, right_widget=self.lower_text) - ba.widget(edit=decrease_button, up_widget=self.lower_text, down_widget=self.enable_button, + bui.widget(edit=decrease_button, up_widget=self.lower_text, down_widget=self.enable_button, left_widget=increase_button, right_widget=increase_button) - ba.widget(edit=increase_button, up_widget=self.upper_text, down_widget=self.close_button, + bui.widget(edit=increase_button, up_widget=self.upper_text, down_widget=self.close_button, left_widget=decrease_button, right_widget=decrease_button) # -------------------------------------------------------------------------------------------------- - ba.textwidget(edit=self.upper_text, on_activate_call=ba.Call(self.on_text_click, "upper")) - ba.textwidget(edit=self.lower_text, on_activate_call=ba.Call(self.on_text_click, "lower")) + bui.textwidget(edit=self.upper_text, on_activate_call=babase.Call(self.on_text_click, "upper")) + bui.textwidget(edit=self.lower_text, on_activate_call=babase.Call(self.on_text_click, "lower")) def on_enableButton_press(self): global loop - loop = ba.app.config.get("moodlightEnabled") + loop = babase.app.config.get("moodlightEnabled") if loop: loop = False label = "ENABLE" @@ -243,49 +247,54 @@ def on_enableButton_press(self): loop = True label = "DISABLE" color = (1, 0, 0) - in_game = not isinstance(_ba.get_foreground_host_session(), mainmenu.MainMenuSession) + in_game = not isinstance(bs.get_foreground_host_session(), mainmenu.MainMenuSession) if in_game: Print("Restart level to apply") - ba.app.config["moodlightEnabled"] = loop - ba.app.config.commit() - ba.buttonwidget(edit=self.enable_button, label=label, color=color) + babase.app.config["moodlightEnabled"] = loop + babase.app.config.commit() + bui.buttonwidget(edit=self.enable_button, label=label, color=color) def save_settings(self): - ba.app.config["moodlightingSettings"] = (Ldefault, Udefault) - ba.app.config.commit() + babase.app.config["moodlightingSettings"] = (Ldefault, Udefault) + babase.app.config.commit() Print("settings saved") self.close() def close(self): - ba.containerwidget(edit=self._root_widget, transition="out_right",) + bui.containerwidget(edit=self._root_widget, transition="out_right",) -def new_chat_message(msg: Union[str, ba.Lstr], clients: Sequence[int] = None, sender_override: str = None): +def new_chat_message(msg: Union[str, babase.Lstr], clients: Sequence[int] = None, sender_override: str = None): old_fcm(msg, clients, sender_override) if msg == 'ml': try: global Ldefault, Udefault - Ldefault, Udefault = ba.app.config.get("moodlightingSettings") + Ldefault, Udefault = babase.app.config.get("moodlightingSettings") SettingWindow() cprint("Mood light settings opened") except Exception as err: Print(err, "-from new_chat_message") - -old_fcm = _ba.chatmessage -_ba.chatmessage = new_chat_message -_ba.set_party_icon_always_visible(True) +class NewMainMenuWindow(MainMenuWindow): + def __init__(self, *args, **kwargs): + super().__init__(*args, **kwargs) + # Display chat icon, but if user open/close gather it may disappear + bui.set_party_icon_always_visible(True) + +old_fcm = bs.chatmessage +bs.chatmessage = new_chat_message Map._old_init = Map.__init__ # ba_meta export plugin -class moodlight(ba.Plugin): +class moodlight(babase.Plugin): def __init__(self): pass def on_app_running(self): - _ba.show_progress_bar() + _babase.show_progress_bar() + MainMenuWindow = NewMainMenuWindow def show_settings_ui(self, source_widget): SettingWindow() @@ -298,11 +307,11 @@ def show_settings_ui(self, button): def _new_init(self, vr_overlay_offset: Optional[Sequence[float]] = None) -> None: self._old_init(vr_overlay_offset) - in_game = not isinstance(_ba.get_foreground_host_session(), mainmenu.MainMenuSession) + in_game = not isinstance(bs.get_foreground_host_session(), mainmenu.MainMenuSession) if not in_game: return - gnode = _ba.getactivity().globalsnode + gnode = bs.getactivity().globalsnode default_tint = (1.100000023841858, 1.0, 0.8999999761581421) transition_duration = 1.0 # for future improvements @@ -310,16 +319,16 @@ def changetint(): if loop: Range = (random.randrange(Ldefault, Udefault)/10, random.randrange(Ldefault, Udefault)/10, random.randrange(Ldefault, Udefault)/10) - ba.animate_array(gnode, 'tint', 3, { + bs.animate_array(gnode, 'tint', 3, { 0.0: gnode.tint, transition_duration: Range }) else: global timer timer = None - ba.animate_array(gnode, "tint", 3, {0.0: gnode.tint, 0.4: default_tint}) + bs.animate_array(gnode, "tint", 3, {0.0: gnode.tint, 0.4: default_tint}) global timer - timer = ba.Timer(0.3, changetint, repeat=True) + timer = bs.Timer(0.3, changetint, repeat=True) Map.__init__ = _new_init diff --git a/plugins/utilities/quick_custom_game.py b/plugins/utilities/quick_custom_game.py index 259dff2b..08575142 100644 --- a/plugins/utilities/quick_custom_game.py +++ b/plugins/utilities/quick_custom_game.py @@ -1,22 +1,25 @@ -# ba_meta require api 7 +# Porting to api 8 made easier by baport.(https://github.com/bombsquad-community/baport) +# ba_meta require api 8 # (see https://ballistica.net/wiki/meta-tag-system) from __future__ import annotations from typing import TYPE_CHECKING -import ba -import _ba -from bastd.ui.play import PlayWindow -from bastd.ui.playlist.addgame import PlaylistAddGameWindow -from ba._freeforallsession import FreeForAllSession -from bastd.activity.multiteamjoin import MultiTeamJoinActivity +import babase +import bauiv1 as bui +import bascenev1 as bs +import _babase +from bauiv1lib.play import PlayWindow +from bauiv1lib.playlist.addgame import PlaylistAddGameWindow +from bascenev1._freeforallsession import FreeForAllSession +from bascenev1lib.activity.multiteamjoin import MultiTeamJoinActivity if TYPE_CHECKING: pass -lang = ba.app.lang.language +lang = bs.app.lang.language if lang == 'Spanish': custom_txt = 'personalizar...' @@ -24,30 +27,30 @@ custom_txt = 'custom...' -if 'quick_game_button' in ba.app.config: - config = ba.app.config['quick_game_button'] +if 'quick_game_button' in babase.app.config: + config = babase.app.config['quick_game_button'] else: config = {'selected': None, 'config': None} - ba.app.config['quick_game_button'] = config - ba.app.config.commit() + babase.app.config['quick_game_button'] = config + babase.app.config.commit() -def start_game(session: ba.Session, fadeout: bool = True): +def start_game(session: bs.Session, fadeout: bool = True): def callback(): if fadeout: - _ba.unlock_all_input() + _babase.unlock_all_input() try: - _ba.new_host_session(session) + bs.new_host_session(session) except Exception: - from bastd import mainmenu - ba.print_exception('exception running session', session) + from bascenev1lib import mainmenu + babase.print_exception('exception running session', session) # Drop back into a main menu session. - _ba.new_host_session(mainmenu.MainMenuSession) + bs.new_host_session(mainmenu.MainMenuSession) if fadeout: - _ba.fade_screen(False, time=0.25, endcall=callback) - _ba.lock_all_input() + _babase.fade_screen(False, time=0.25, endcall=callback) + _babase.lock_all_input() else: callback() @@ -56,7 +59,7 @@ class SimplePlaylist: def __init__(self, settings: dict, - gametype: type[ba.GameActivity]): + gametype: type[bs.GameActivity]): self.settings = settings self.gametype = gametype @@ -75,7 +78,7 @@ def __init__(self, *args, **kwargs): # pylint: disable=cyclic-import self.use_teams = False self._tutorial_activity_instance = None - ba.Session.__init__(self, depsets=[], + bs.Session.__init__(self, depsets=[], team_names=None, team_colors=None, min_players=1, @@ -89,12 +92,12 @@ def __init__(self, *args, **kwargs): self._playlist = SimplePlaylist(self._config, self._gametype) config['selected'] = self._gametype.__name__ config['config'] = self._config - ba.app.config.commit() + babase.app.config.commit() # Get a game on deck ready to go. self._current_game_spec: Optional[Dict[str, Any]] = None self._next_game_spec: Dict[str, Any] = self._playlist.pull_next() - self._next_game: Type[ba.GameActivity] = ( + self._next_game: Type[bs.GameActivity] = ( self._next_game_spec['resolved_type']) # Go ahead and instantiate the next game we'll @@ -102,71 +105,71 @@ def __init__(self, *args, **kwargs): self._instantiate_next_game() # Start in our custom join screen. - self.setactivity(_ba.newactivity(MultiTeamJoinActivity)) + self.setactivity(bs.newactivity(MultiTeamJoinActivity)) class SelectGameWindow(PlaylistAddGameWindow): def __init__(self, transition: str = 'in_right'): class EditController: - _sessiontype = ba.FreeForAllSession + _sessiontype = bs.FreeForAllSession - def get_session_type(self) -> Type[ba.Session]: + def get_session_type(self) -> Type[bs.Session]: return self._sessiontype self._editcontroller = EditController() self._r = 'addGameWindow' - uiscale = ba.app.ui.uiscale - self._width = 750 if uiscale is ba.UIScale.SMALL else 650 - x_inset = 50 if uiscale is ba.UIScale.SMALL else 0 - self._height = (346 if uiscale is ba.UIScale.SMALL else - 380 if uiscale is ba.UIScale.MEDIUM else 440) - top_extra = 30 if uiscale is ba.UIScale.SMALL else 20 + uiscale = bui.app.ui_v1.uiscale + self._width = 750 if uiscale is babase.UIScale.SMALL else 650 + x_inset = 50 if uiscale is babase.UIScale.SMALL else 0 + self._height = (346 if uiscale is babase.UIScale.SMALL else + 380 if uiscale is babase.UIScale.MEDIUM else 440) + top_extra = 30 if uiscale is babase.UIScale.SMALL else 20 self._scroll_width = 210 - self._root_widget = ba.containerwidget( + self._root_widget = bui.containerwidget( size=(self._width, self._height + top_extra), transition=transition, - scale=(2.17 if uiscale is ba.UIScale.SMALL else - 1.5 if uiscale is ba.UIScale.MEDIUM else 1.0), - stack_offset=(0, 1) if uiscale is ba.UIScale.SMALL else (0, 0)) + scale=(2.17 if uiscale is babase.UIScale.SMALL else + 1.5 if uiscale is babase.UIScale.MEDIUM else 1.0), + stack_offset=(0, 1) if uiscale is babase.UIScale.SMALL else (0, 0)) - self._back_button = ba.buttonwidget(parent=self._root_widget, + self._back_button = bui.buttonwidget(parent=self._root_widget, position=(58 + x_inset, self._height - 53), size=(165, 70), scale=0.75, text_scale=1.2, - label=ba.Lstr(resource='backText'), + label=babase.Lstr(resource='backText'), autoselect=True, button_type='back', on_activate_call=self._back) - self._select_button = select_button = ba.buttonwidget( + self._select_button = select_button = bui.buttonwidget( parent=self._root_widget, position=(self._width - (172 + x_inset), self._height - 50), autoselect=True, size=(160, 60), scale=0.75, text_scale=1.2, - label=ba.Lstr(resource='selectText'), + label=babase.Lstr(resource='selectText'), on_activate_call=self._add) - if ba.app.ui.use_toolbars: - ba.widget(edit=select_button, - right_widget=_ba.get_special_widget('party_button')) + if bui.app.ui_v1.use_toolbars: + bui.widget(edit=select_button, + right_widget=bui.get_special_widget('party_button')) - ba.textwidget(parent=self._root_widget, + bui.textwidget(parent=self._root_widget, position=(self._width * 0.5, self._height - 28), size=(0, 0), scale=1.0, - text=ba.Lstr(resource=self._r + '.titleText'), + text=babase.Lstr(resource=self._r + '.titleText'), h_align='center', - color=ba.app.ui.title_color, + color=bui.app.ui_v1.title_color, maxwidth=250, v_align='center') v = self._height - 64 - self._selected_title_text = ba.textwidget( + self._selected_title_text = bui.textwidget( parent=self._root_widget, position=(x_inset + self._scroll_width + 50 + 30, v - 15), size=(0, 0), @@ -177,7 +180,7 @@ def get_session_type(self) -> Type[ba.Session]: v_align='center') v -= 30 - self._selected_description_text = ba.textwidget( + self._selected_description_text = bui.textwidget( parent=self._root_widget, position=(x_inset + self._scroll_width + 50 + 30, v), size=(0, 0), @@ -190,31 +193,31 @@ def get_session_type(self) -> Type[ba.Session]: v = self._height - 60 - self._scrollwidget = ba.scrollwidget(parent=self._root_widget, + self._scrollwidget = bui.scrollwidget(parent=self._root_widget, position=(x_inset + 61, v - scroll_height), size=(self._scroll_width, scroll_height), highlight=False) - ba.widget(edit=self._scrollwidget, + bui.widget(edit=self._scrollwidget, up_widget=self._back_button, left_widget=self._back_button, right_widget=select_button) - self._column: Optional[ba.Widget] = None + self._column: Optional[bui.Widget] = None v -= 35 - ba.containerwidget(edit=self._root_widget, + bui.containerwidget(edit=self._root_widget, cancel_button=self._back_button, start_button=select_button) - self._selected_game_type: Optional[Type[ba.GameActivity]] = None + self._selected_game_type: Optional[Type[bs.GameActivity]] = None - ba.containerwidget(edit=self._root_widget, + bui.containerwidget(edit=self._root_widget, selected_child=self._scrollwidget) - self._game_types: list[type[ba.GameActivity]] = [] + self._game_types: list[type[bs.GameActivity]] = [] # Get actual games loading in the bg. - ba.app.meta.load_exported_classes(ba.GameActivity, + babase.app.meta.load_exported_classes(bs.GameActivity, self._on_game_types_loaded, completion_cb_in_bg_thread=True) @@ -231,12 +234,12 @@ def get_session_type(self) -> Type[ba.Session]: def _refresh(self, select_get_more_games_button: bool = False, selected: bool = None) -> None: - # from ba.internal import get_game_types + # from babase.internal import get_game_types if self._column is not None: self._column.delete() - self._column = ba.columnwidget(parent=self._scrollwidget, + self._column = bui.columnwidget(parent=self._scrollwidget, border=2, margin=0) @@ -244,11 +247,10 @@ def _refresh(self, def _doit() -> None: if self._select_button: - ba.timer(0.1, - self._select_button.activate, - timetype=ba.TimeType.REAL) + bs.apptimer(0.1, + self._select_button.activate) - txt = ba.textwidget(parent=self._column, + txt = bui.textwidget(parent=self._column, position=(0, 0), size=(self._width - 88, 24), text=gametype.get_display_string(), @@ -256,30 +258,30 @@ def _doit() -> None: v_align='center', color=(0.8, 0.8, 0.8, 1.0), maxwidth=self._scroll_width * 0.8, - on_select_call=ba.Call( + on_select_call=babase.Call( self._set_selected_game_type, gametype), always_highlight=True, selectable=True, on_activate_call=_doit) if i == 0: - ba.widget(edit=txt, up_widget=self._back_button) + bui.widget(edit=txt, up_widget=self._back_button) - self._get_more_games_button = ba.buttonwidget( + self._get_more_games_button = bui.buttonwidget( parent=self._column, autoselect=True, - label=ba.Lstr(resource=self._r + '.getMoreGamesText'), + label=babase.Lstr(resource=self._r + '.getMoreGamesText'), color=(0.54, 0.52, 0.67), textcolor=(0.7, 0.65, 0.7), on_activate_call=self._on_get_more_games_press, size=(178, 50)) if select_get_more_games_button: - ba.containerwidget(edit=self._column, + bui.containerwidget(edit=self._column, selected_child=self._get_more_games_button, visible_child=self._get_more_games_button) def _add(self) -> None: - _ba.lock_all_input() # Make sure no more commands happen. - ba.timer(0.1, _ba.unlock_all_input, timetype=ba.TimeType.REAL) + _babase.lock_all_input() # Make sure no more commands happen. + bs.apptimer(0.1, _babase.unlock_all_input) gameconfig = {} if config['selected'] == self._selected_game_type.__name__: if config['config']: @@ -297,13 +299,13 @@ def _edit_game_done(self, config: Optional[Dict[str, Any]]) -> None: CustomSession._gametype = self._selected_game_type start_game(CustomSession) else: - ba.app.ui.clear_main_menu_window(transition='out_right') - ba.app.ui.set_main_menu_window( + bui.app.ui_v1.clear_main_menu_window(transition='out_right') + bui.app.ui_v1.set_main_menu_window( SelectGameWindow(transition='in_left').get_root_widget()) def _back(self) -> None: - ba.containerwidget(edit=self._root_widget, transition='out_right') - ba.app.ui.set_main_menu_window( + bui.containerwidget(edit=self._root_widget, transition='out_right') + bui.app.ui_v1.set_main_menu_window( PlayWindow(transition='in_left').get_root_widget()) @@ -318,11 +320,11 @@ def __init__(self, *args, **kwargs): def do_quick_game() -> None: self._save_state() - ba.containerwidget(edit=self._root_widget, transition='out_left') - ba.app.ui.set_main_menu_window( + bui.containerwidget(edit=self._root_widget, transition='out_left') + bui.app.ui_v1.set_main_menu_window( SelectGameWindow().get_root_widget()) - self._quick_game_button = ba.buttonwidget( + self._quick_game_button = bui.buttonwidget( parent=self._root_widget, position=(width - 55 - 120, height - 132), autoselect=True, @@ -350,32 +352,32 @@ def states(self) -> None: def _save_state(self) -> None: swapped = {v: k for k, v in states(self).items()} if self._root_widget.get_selected_child() in swapped: - ba.app.ui.window_states[ + bui.app.ui_v1.window_states[ self.__class__.__name__] = swapped[ self._root_widget.get_selected_child()] else: - ba.print_exception(f'Error saving state for {self}.') + babase.print_exception(f'Error saving state for {self}.') def _restore_state(self) -> None: if not hasattr(self, '_quick_game_button'): return # ensure that our monkey patched init ran - if self.__class__.__name__ not in ba.app.ui.window_states: - ba.containerwidget(edit=self._root_widget, + if self.__class__.__name__ not in bui.app.ui_v1.window_states: + bui.containerwidget(edit=self._root_widget, selected_child=self._coop_button) return sel = states(self).get( - ba.app.ui.window_states[self.__class__.__name__], None) + bui.app.ui_v1.window_states[self.__class__.__name__], None) if sel: - ba.containerwidget(edit=self._root_widget, selected_child=sel) + bui.containerwidget(edit=self._root_widget, selected_child=sel) else: - ba.containerwidget(edit=self._root_widget, + bui.containerwidget(edit=self._root_widget, selected_child=self._coop_button) - ba.print_exception(f'Error restoring state for {self}.') + babase.print_exception(f'Error restoring state for {self}.') # ba_meta export plugin -class QuickGamePlugin(ba.Plugin): +class QuickGamePlugin(babase.Plugin): PlayWindow.__init__ = __init__ PlayWindow._save_state = _save_state PlayWindow._restore_state = _restore_state diff --git a/plugins/utilities/quickturn.py b/plugins/utilities/quickturn.py index 976c905f..a175a3f4 100644 --- a/plugins/utilities/quickturn.py +++ b/plugins/utilities/quickturn.py @@ -1,3 +1,4 @@ +# Porting to api 8 made easier by baport.(https://github.com/bombsquad-community/baport) """ Quickturn by TheMikirog @@ -9,16 +10,18 @@ No Rights Reserved """ -# ba_meta require api 7 +# ba_meta require api 8 from __future__ import annotations from typing import TYPE_CHECKING -import ba +import babase +import bauiv1 as bui +import bascenev1 as bs import math -import bastd -from bastd.actor.spaz import Spaz +import bascenev1lib +from bascenev1lib.actor.spaz import Spaz if TYPE_CHECKING: pass @@ -26,7 +29,7 @@ # ba_meta export plugin -class Quickturn(ba.Plugin): +class Quickturn(babase.Plugin): class FootConnectMessage: """Spaz started touching the ground""" @@ -46,7 +49,7 @@ def wavedash(self) -> None: if self.node.knockout > 0.0 or self.frozen or self.node.hold_node: return - t_ms = ba.time(timeformat=ba.TimeFormat.MILLISECONDS) + t_ms = bs.time() * 1000 assert isinstance(t_ms, int) if t_ms - self.last_wavedash_time_ms >= self._wavedash_cooldown: @@ -77,7 +80,7 @@ def wavedash(self) -> None: self.last_wavedash_time_ms = t_ms # FX - ba.emitfx(position=self.node.position, + bs.emitfx(position=self.node.position, velocity=(vel[0]*0.5, -1, vel[1]*0.5), chunk_type='spark', count=5, @@ -104,7 +107,7 @@ def wrapper(*args, **kwargs): args[0].grounded = 0 return wrapper - bastd.actor.spaz.Spaz.__init__ = new_spaz_init(bastd.actor.spaz.Spaz.__init__) + bascenev1lib.actor.spaz.Spaz.__init__ = new_spaz_init(bascenev1lib.actor.spaz.Spaz.__init__) def new_factory(func): def wrapper(*args, **kwargs): @@ -112,12 +115,12 @@ def wrapper(*args, **kwargs): args[0].roller_material.add_actions( conditions=('they_have_material', - bastd.gameutils.SharedObjects.get().footing_material), + bascenev1lib.gameutils.SharedObjects.get().footing_material), actions=(('message', 'our_node', 'at_connect', Quickturn.FootConnectMessage), ('message', 'our_node', 'at_disconnect', Quickturn.FootDisconnectMessage))) return wrapper - bastd.actor.spazfactory.SpazFactory.__init__ = new_factory( - bastd.actor.spazfactory.SpazFactory.__init__) + bascenev1lib.actor.spazfactory.SpazFactory.__init__ = new_factory( + bascenev1lib.actor.spazfactory.SpazFactory.__init__) def new_handlemessage(func): def wrapper(*args, **kwargs): @@ -129,7 +132,7 @@ def wrapper(*args, **kwargs): func(*args, **kwargs) return wrapper - bastd.actor.spaz.Spaz.handlemessage = new_handlemessage(bastd.actor.spaz.Spaz.handlemessage) + bascenev1lib.actor.spaz.Spaz.handlemessage = new_handlemessage(bascenev1lib.actor.spaz.Spaz.handlemessage) def new_on_run(func): def wrapper(*args, **kwargs): @@ -137,4 +140,4 @@ def wrapper(*args, **kwargs): Quickturn.wavedash(args[0]) func(*args, **kwargs) return wrapper - bastd.actor.spaz.Spaz.on_run = new_on_run(bastd.actor.spaz.Spaz.on_run) + bascenev1lib.actor.spaz.Spaz.on_run = new_on_run(bascenev1lib.actor.spaz.Spaz.on_run) diff --git a/plugins/utilities/ragdoll_b_gone.py b/plugins/utilities/ragdoll_b_gone.py index 7b8190db..6f229fc6 100644 --- a/plugins/utilities/ragdoll_b_gone.py +++ b/plugins/utilities/ragdoll_b_gone.py @@ -1,4 +1,5 @@ -# ba_meta require api 7 +# Porting to api 8 made easier by baport.(https://github.com/bombsquad-community/baport) +# ba_meta require api 8 """ Ragdoll-B-Gone by TheMikirog @@ -18,11 +19,13 @@ from typing import TYPE_CHECKING # Let's import everything we need and nothing more. -import ba -import bastd +import babase +import bauiv1 as bui +import bascenev1 as bs +import bascenev1lib import random -from bastd.actor.spaz import Spaz -from bastd.actor.spazfactory import SpazFactory +from bascenev1lib.actor.spaz import Spaz +from bascenev1lib.actor.spazfactory import SpazFactory if TYPE_CHECKING: pass @@ -30,7 +33,7 @@ # ba_meta export plugin -class RagdollBGone(ba.Plugin): +class RagdollBGone(babase.Plugin): # We use a decorator to add extra code to existing code, increasing mod compatibility. # Any gameplay altering mod should master the decorator! @@ -42,16 +45,16 @@ def new_handlemessage(func): # We're working kind of blindly here, so it's good to have the original function # open in a second window for argument reference. def wrapper(*args, **kwargs): - if isinstance(args[1], ba.DieMessage): # Replace Spaz death behavior + if isinstance(args[1], bs.DieMessage): # Replace Spaz death behavior # Here we play the gamey death noise in Co-op. if not args[1].immediate: if args[0].play_big_death_sound and not args[0]._dead: - ba.playsound(SpazFactory.get().single_player_death_sound) + SpazFactory.get().single_player_death_sound.play() # If our Spaz dies by falling out of the map, we want to keep the ragdoll. # Ragdolls don't impact gameplay if Spaz dies this way, so it's fine if we leave the behavior as is. - if args[1].how == ba.DeathType.FALL: + if args[1].how == bs.DeathType.FALL: # The next two properties are all built-in, so their behavior can't be edited directly without touching the C++ layer. # We can change their values though! # "hurt" property is basically the health bar above the player and the blinking when low on health. @@ -61,7 +64,7 @@ def wrapper(*args, **kwargs): # Again, this behavior is built in. We can only trigger it by setting "dead" to True. args[0].node.dead = True # After the death animation ends (which is around 2 seconds) let's remove the Spaz our of existence. - ba.timer(2.0, args[0].node.delete) + bs.timer(2.0, args[0].node.delete) else: # Here's our new behavior! # The idea is to remove the Spaz node and make some sparks for extra flair. @@ -80,7 +83,7 @@ def wrapper(*args, **kwargs): args[0].node.position[2]) # This function allows us to spawn particles like sparks and bomb shrapnel. # We're gonna use sparks here. - ba.emitfx(position=pos, # Here we place our edited position. + bs.emitfx(position=pos, # Here we place our edited position. velocity=args[0].node.velocity, # Random amount of sparks between 2 and 5 count=random.randrange(2, 5), @@ -95,10 +98,10 @@ def wrapper(*args, **kwargs): # Pick a random death noise sound = death_sounds[random.randrange(len(death_sounds))] # Play the sound where our Spaz is - ba.playsound(sound, position=args[0].node.position) + sound.play(position=args[0].node.position) # Delete our Spaz node immediately. # Removing stuff is weird and prone to errors, so we're gonna delay it. - ba.timer(0.001, args[0].node.delete) + bs.timer(0.001, args[0].node.delete) # Let's mark our Spaz as dead, so he can't die again. # Notice how we're targeting the Spaz and not it's node. @@ -116,4 +119,4 @@ def wrapper(*args, **kwargs): # Finally we """travel through the game files""" to replace the function we want with our own version. # We transplant the old function's arguments into our version. - bastd.actor.spaz.Spaz.handlemessage = new_handlemessage(bastd.actor.spaz.Spaz.handlemessage) + bascenev1lib.actor.spaz.Spaz.handlemessage = new_handlemessage(bascenev1lib.actor.spaz.Spaz.handlemessage) diff --git a/plugins/utilities/random_join.py b/plugins/utilities/random_join.py index 955b1a2c..e29a5992 100644 --- a/plugins/utilities/random_join.py +++ b/plugins/utilities/random_join.py @@ -1,17 +1,19 @@ +# Porting to api 8 made easier by baport.(https://github.com/bombsquad-community/baport) from __future__ import annotations from typing import TYPE_CHECKING, TypeVar -import _ba -import ba -import ba.internal +import _babase +import babase +import bauiv1 as bui +import bascenev1 as bs import random -from bastd.ui.gather.publictab import PublicGatherTab, PartyEntry, PingThread +from bauiv1lib.gather.publictab import PublicGatherTab, PartyEntry, PingThread if TYPE_CHECKING: from typing import Callable ClassType = TypeVar('ClassType') -MethodType = TypeVar('Methodtype') +MethodType = TypeVar('MethodType') def override(cls: ClassType) -> Callable[[MethodType], MethodType]: @@ -50,26 +52,26 @@ def _build_join_tab(self, region_width: float, v = c_height - 35 v -= 60 - self._random_join_button = ba.buttonwidget( + self._random_join_button = bui.buttonwidget( parent=self._container, label='random', size=(90, 45), position=(710, v + 10), - on_activate_call=ba.WeakCall(self._join_random_server), + on_activate_call=bs.WeakCall(self._join_random_server), ) - ba.widget(edit=self._random_join_button, up_widget=self._host_text, + bui.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( + self._random_join_settings_button = bui.buttonwidget( parent=self._container, - icon=ba.gettexture('settingsIcon'), + icon=bui.gettexture('settingsIcon'), size=(40, 40), position=(820, v + 13), - on_activate_call=ba.WeakCall(self._show_random_join_settings), + on_activate_call=bs.WeakCall(self._show_random_join_settings), ) @override(PublicGatherTab) @@ -97,9 +99,9 @@ def _join_random_server(self) -> None: and p.ping <= randomjoin.maximum_ping)))] if not parties: - ba.screenmessage('No suitable servers found; wait', + bui.screenmessage('No suitable servers found; wait', color=(1, 0, 0)) - ba.playsound(ba.getsound('error')) + bui.getsound('error').play() return for party in parties: @@ -110,33 +112,33 @@ def _join_random_server(self) -> None: party = random.choice( [p for p in parties if p.name[:6] in name_prefixes]) - ba.internal.connect_to_party(party.address, party.port) + bs.connect_to_party(party.address, party.port) -class RandomJoinSettingsPopup(ba.Window): - def __init__(self, origin_widget: ba.Widget) -> None: +class RandomJoinSettingsPopup(bui.Window): + def __init__(self, origin_widget: bui.Widget) -> None: c_width = 600 c_height = 400 - uiscale = ba.app.ui.uiscale - super().__init__(root_widget=ba.containerwidget( + uiscale = bui.app.ui_v1.uiscale + super().__init__(root_widget=bui.containerwidget( scale=( 1.8 - if uiscale is ba.UIScale.SMALL + if uiscale is babase.UIScale.SMALL else 1.55 - if uiscale is ba.UIScale.MEDIUM + if uiscale is babase.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 + if uiscale is babase.UIScale.SMALL else (0, 15) - if uiscale is ba.UIScale.MEDIUM + if uiscale is babase.UIScale.MEDIUM else (0, 0), size=(c_width, c_height), transition='in_scale', )) - ba.textwidget( + bui.textwidget( parent=self._root_widget, size=(0, 0), h_align='center', @@ -149,7 +151,7 @@ def __init__(self, origin_widget: ba.Widget) -> None: ) v = c_height - 120 - ba.textwidget( + bui.textwidget( parent=self._root_widget, size=(0, 0), h_align='right', @@ -158,7 +160,7 @@ def __init__(self, origin_widget: ba.Widget) -> None: maxwidth=c_width * 0.3, position=(c_width * 0.4, v), ) - self._maximum_ping_edit = ba.textwidget( + self._maximum_ping_edit = bui.textwidget( parent=self._root_widget, size=(c_width * 0.3, 40), h_align='left', @@ -171,7 +173,7 @@ def __init__(self, origin_widget: ba.Widget) -> None: max_chars=4, ) v -= 60 - ba.textwidget( + bui.textwidget( parent=self._root_widget, size=(0, 0), h_align='right', @@ -180,7 +182,7 @@ def __init__(self, origin_widget: ba.Widget) -> None: maxwidth=c_width * 0.3, position=(c_width * 0.4, v), ) - self._minimum_players_edit = ba.textwidget( + self._minimum_players_edit = bui.textwidget( parent=self._root_widget, size=(c_width * 0.3, 40), h_align='left', @@ -195,27 +197,27 @@ def __init__(self, origin_widget: ba.Widget) -> None: v -= 60 # Cancel button. - self.cancel_button = btn = ba.buttonwidget( + self.cancel_button = btn = bui.buttonwidget( parent=self._root_widget, - label=ba.Lstr(resource='cancelText'), + label=babase.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) + bui.containerwidget(edit=self._root_widget, cancel_button=btn) # Save button. - self.savebtn = btn = ba.buttonwidget( + self.savebtn = btn = bui.buttonwidget( parent=self._root_widget, - label=ba.Lstr(resource='saveText'), + label=babase.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) + bui.containerwidget(edit=self._root_widget, start_button=btn) def _save(self) -> None: errored = False @@ -223,19 +225,19 @@ def _save(self) -> None: maximum_ping: int | None = None try: minimum_players = int( - ba.textwidget(query=self._minimum_players_edit)) + bui.textwidget(query=self._minimum_players_edit)) except ValueError: - ba.screenmessage('"Minimum players" should be integer', + bui.screenmessage('"Minimum players" should be integer', color=(1, 0, 0)) - ba.playsound(ba.getsound('error')) + bui.getsound('error').play() errored = True try: maximum_ping = int( - ba.textwidget(query=self._maximum_ping_edit)) + bui.textwidget(query=self._maximum_ping_edit)) except ValueError: - ba.screenmessage('"Maximum ping" should be integer', + bui.screenmessage('"Maximum ping" should be integer', color=(1, 0, 0)) - ba.playsound(ba.getsound('error')) + bui.getsound('error').play() errored = True if errored: return @@ -244,16 +246,16 @@ def _save(self) -> None: assert maximum_ping is not None if minimum_players < 0: - ba.screenmessage('"Minimum players" should be at least 0', + bui.screenmessage('"Minimum players" should be at least 0', color=(1, 0, 0)) - ba.playsound(ba.getsound('error')) + bui.getsound('error').play() errored = True if maximum_ping <= 0: - ba.screenmessage('"Maximum ping" should be greater than 0', + bui.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)', + bui.getsound('error').play() + bui.screenmessage('(use 9999 as dont-care value)', color=(1, 0, 0)) errored = True @@ -264,15 +266,15 @@ def _save(self) -> None: randomjoin.minimum_players = minimum_players randomjoin.commit_config() - ba.playsound(ba.getsound('shieldUp')) + bui.getsound('shieldUp').play() self._transition_out() def _cancel(self) -> None: - ba.playsound(ba.getsound('shieldDown')) + bui.getsound('shieldDown').play() self._transition_out() def _transition_out(self) -> None: - ba.containerwidget(edit=self._root_widget, transition='out_scale') + bui.containerwidget(edit=self._root_widget, transition='out_scale') class RandomJoin: @@ -283,7 +285,7 @@ def __init__(self) -> None: self.load_config() def load_config(self) -> None: - cfg = ba.app.config.get('Random Join', { + cfg = babase.app.config.get('Random Join', { 'maximum_ping': self.maximum_ping, 'minimum_players': self.minimum_players, }) @@ -291,25 +293,25 @@ def load_config(self) -> None: self.maximum_ping = cfg['maximum_ping'] self.minimum_players = cfg['minimum_players'] except KeyError: - ba.screenmessage('Error: RandomJoin config is broken, resetting..', + bui.screenmessage('Error: RandomJoin config is broken, resetting..', color=(1, 0, 0), log=True) - ba.playsound(ba.getsound('error')) + bui.getsound('error').play() self.commit_config() def commit_config(self) -> None: - ba.app.config['Random Join'] = { + babase.app.config['Random Join'] = { 'maximum_ping': self.maximum_ping, 'minimum_players': self.minimum_players, } - ba.app.config.commit() + babase.app.config.commit() randomjoin = RandomJoin() -# ba_meta require api 7 -# ba_meta export ba.Plugin -class RandomJoinPlugin(ba.Plugin): +# ba_meta require api 8 +# ba_meta export babase.Plugin +class RandomJoinPlugin(babase.Plugin): def on_app_running(self) -> None: # I feel bad that all patching logic happens not here. pass diff --git a/plugins/utilities/tnt_respawn_text.py b/plugins/utilities/tnt_respawn_text.py index 50051093..52b7f729 100644 --- a/plugins/utilities/tnt_respawn_text.py +++ b/plugins/utilities/tnt_respawn_text.py @@ -1,4 +1,5 @@ -# ba_meta require api 7 +# Porting to api 8 made easier by baport.(https://github.com/bombsquad-community/baport) +# ba_meta require api 8 """ TNT Respawn Text by TheMikirog @@ -16,11 +17,13 @@ from typing import TYPE_CHECKING # Let's import everything we need and nothing more. -import ba -import bastd +import babase +import bauiv1 as bui +import bascenev1 as bs +import bascenev1lib import math import random -from bastd.actor.bomb import Bomb +from bascenev1lib.actor.bomb import Bomb if TYPE_CHECKING: pass @@ -40,7 +43,7 @@ # ba_meta export plugin -class TNTRespawnText(ba.Plugin): +class TNTRespawnText(babase.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. @@ -54,7 +57,7 @@ def clamp(num, min_value, max_value): def on_tnt_exploded(self): self.tnt_has_callback = False self._respawn_text.color = (1.0, 1.0, 1.0) - ba.animate( + bs.animate( self._respawn_text, 'opacity', { @@ -92,7 +95,7 @@ def wrapper(*args, **kwargs): respawn_text_position = (args[0]._position[0], args[0]._position[1] - 0.4, args[0]._position[2]) - args[0]._respawn_text = ba.newnode( + args[0]._respawn_text = bs.newnode( 'text', attrs={ 'text': "", # we'll set the text later @@ -126,7 +129,7 @@ def tnt_callback(): 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__) + bascenev1lib.actor.bomb.TNTSpawner.__init__ = new_init(bascenev1lib.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. @@ -165,7 +168,7 @@ def wrapper(*args, **kwargs): # 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( + bs.animate( args[0]._respawn_text, 'scale', { @@ -176,7 +179,7 @@ def wrapper(*args, **kwargs): }, ) # Fade the text away - ba.animate( + bs.animate( args[0]._respawn_text, 'opacity', { @@ -191,7 +194,7 @@ def wrapper(*args, **kwargs): args[0]._respawn_text.color = (1.0, 0.75, 0.5) # Make some sparks to draw the eye. - ba.emitfx( + bs.emitfx( position=args[0]._position, count=int(5.0 + random.random() * 10), scale=0.8, @@ -212,4 +215,4 @@ def 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) + bascenev1lib.actor.bomb.TNTSpawner._update = new_update(bascenev1lib.actor.bomb.TNTSpawner._update) diff --git a/plugins/utilities/ultra_party_window.py b/plugins/utilities/ultra_party_window.py index 2d39444b..712b7be2 100644 --- a/plugins/utilities/ultra_party_window.py +++ b/plugins/utilities/ultra_party_window.py @@ -1,7 +1,8 @@ +# Porting to api 8 made easier by baport.(https://github.com/bombsquad-community/baport) __author__ = 'Droopy' __version__ = 4.0 -# ba_meta require api 7 +# ba_meta require api 8 import datetime import json import math @@ -15,13 +16,17 @@ from typing import List, Tuple, Sequence, Optional, Dict, Any, cast from hashlib import md5 -import _ba -import ba -import bastd.ui.party -from bastd.ui.colorpicker import ColorPickerExact -from bastd.ui.confirm import ConfirmWindow -from bastd.ui.mainmenu import MainMenuWindow -from bastd.ui.popup import PopupMenuWindow, PopupWindow, PopupMenu +import _babase +import babase +import bauiv1 as bui +import bascenev1 as bs +import bauiv1lib.party +from bauiv1lib.colorpicker import ColorPickerExact +from bauiv1lib import mainmenu +from bauiv1lib.confirm import ConfirmWindow +from bauiv1lib.mainmenu import MainMenuWindow +from bauiv1lib.popup import PopupMenuWindow, PopupWindow, PopupMenu +from baenv import TARGET_BALLISTICA_BUILD as build_number _ip = '127.0.0.1' _port = 43210 @@ -29,7 +34,7 @@ url = 'http://bombsquadprivatechat.ml' last_msg = None -my_directory = _ba.env()['python_directory_user'] + '/UltraPartyWindowFiles/' +my_directory = _babase.env()['python_directory_user'] + '/UltraPartyWindowFiles/' quick_msg_file = my_directory + 'QuickMessages.txt' cookies_file = my_directory + 'cookies.txt' saved_ids_file = my_directory + 'saved_ids.json' @@ -51,7 +56,7 @@ def initialize(): 'Translate Destination Language': 'en', 'Pronunciation': True } - config = ba.app.config + config = babase.app.config for key in config_defaults: if key not in config: config[key] = config_defaults[key] @@ -69,17 +74,17 @@ def initialize(): def display_error(msg=None): if msg: - ba.screenmessage(msg, (1, 0, 0)) + bui.screenmessage(msg, (1, 0, 0)) else: - ba.screenmessage('Failed!', (1, 0, 0)) - ba.playsound(ba.getsound('error')) + bui.screenmessage('Failed!', (1, 0, 0)) + bui.getsound('error').play() def display_success(msg=None): if msg: - ba.screenmessage(msg, (0, 1, 0)) + bui.screenmessage(msg, (0, 1, 0)) else: - ba.screenmessage('Successful!', (0, 1, 0)) + bui.screenmessage('Successful!', (0, 1, 0)) class Translate(Thread): @@ -89,10 +94,10 @@ def __init__(self, data, callback): self._callback = callback def run(self): - _ba.pushcall(ba.Call(ba.screenmessage, 'Translating...'), from_other_thread=True) + _babase.pushcall(babase.Call(bui.screenmessage, 'Translating...'), from_other_thread=True) response = messenger._send_request(f'{url}/translate', self.data) if response: - _ba.pushcall(ba.Call(self._callback, response), from_other_thread=True) + _babase.pushcall(babase.Call(self._callback, response), from_other_thread=True) class ColorTracker: @@ -103,7 +108,7 @@ def _get_safe_color(self, sender): while True: color = (random.random(), random.random(), random.random()) s = 0 - background = ba.app.config.get('PartyWindow Main Color', (0.5, 0.5, 0.5)) + background = babase.app.config.get('PartyWindow Main Color', (0.5, 0.5, 0.5)) for i, j in zip(color, background): s += (i - j) ** 2 if s > 0.1: @@ -184,7 +189,7 @@ def _save_cookie(self): pickle.dump(cookies, f) def _cookie_login(self): - self.myid = ba.internal.get_v1_account_misc_read_val_2('resolvedAccountID', '') + self.myid = bui.app.plus.get_v1_account_misc_read_val_2('resolvedAccountID', '') try: with open(cookies_file, 'rb') as f: cookies = pickle.load(f) @@ -202,7 +207,7 @@ def _cookie_login(self): return True def _login(self, registration_key): - self.myid = ba.internal.get_v1_account_misc_read_val_2('resolvedAccountID', '') + self.myid = bui.app.plus.get_v1_account_misc_read_val_2('resolvedAccountID', '') data = dict(pb_id=self.myid, registration_key=registration_key) response = self._send_request(url=f'{url}/login', data=data) if response == 'successful': @@ -260,8 +265,8 @@ def _save_id(self, account_id, nickname='', verify=True): def _remove_id(self, account_id): removed = self.saved_ids.pop(account_id) self._dump_ids() - ba.screenmessage(f'Removed successfully: {removed}({account_id})', (0, 1, 0)) - ba.playsound(ba.getsound('shieldDown')) + bui.screenmessage(f'Removed successfully: {removed}({account_id})', (0, 1, 0)) + bui.getsound('shieldDown').play() def _format_message(self, msg): filter = msg['filter'] @@ -284,7 +289,7 @@ def _get_status(self, id, type='status'): else: last_seen = info["last_seen"] last_seen = _get_local_time(last_seen) - ba.screenmessage(f'Last seen on: {last_seen}') + bui.screenmessage(f'Last seen on: {last_seen}') def _get_local_time(utctime): @@ -296,8 +301,8 @@ def _get_local_time(utctime): def update_status(): if messenger.logged_in: - if ba.app.config['Self Status'] == 'online': - host = _ba.get_connection_to_host_info().get('name', '') + if babase.app.config['Self Status'] == 'online': + host = bs.get_connection_to_host_info().get('name', '') if build_number < 21697 else bs.get_connection_to_host_info_2().get('name', '') if host: my_status = f'Playing in {host}' else: @@ -357,45 +362,45 @@ def check_new_message(): def display_message(msg, msg_type, filter=None, sent=None): flag = None - notification = ba.app.config['Message Notification'] - if _ba.app.ui.party_window: - if _ba.app.ui.party_window(): - if _ba.app.ui.party_window()._private_chat: + notification = babase.app.config['Message Notification'] + if bui.app.ui_v1.party_window: + if bui.app.ui_v1.party_window(): + if bui.app.ui_v1.party_window()._private_chat: flag = 1 if msg_type == 'private': if messenger.filter == filter or messenger.filter == 'all': - _ba.app.ui.party_window().on_chat_message(msg, sent) + bui.app.ui_v1.party_window().on_chat_message(msg, sent) else: if notification == 'top': - ba.screenmessage(msg, (1, 1, 0), True, ba.gettexture('coin')) + bui.screenmessage(msg, (1, 1, 0), True, bui.gettexture('coin')) else: - ba.screenmessage(msg, (1, 1, 0), False) + bui.screenmessage(msg, (1, 1, 0), False) else: - ba.screenmessage(msg, (0.2, 1.0, 1.0), True, ba.gettexture('circleShadow')) + bui.screenmessage(msg, (0.2, 1.0, 1.0), True, bui.gettexture('circleShadow')) else: flag = 1 if msg_type == 'private': if notification == 'top': - ba.screenmessage(msg, (1, 1, 0), True, ba.gettexture('coin')) + bui.screenmessage(msg, (1, 1, 0), True, bui.gettexture('coin')) else: - ba.screenmessage(msg, (1, 1, 0), False) + bui.screenmessage(msg, (1, 1, 0), False) if not flag: if msg_type == 'private': if notification == 'top': - ba.screenmessage(msg, (1, 1, 0), True, ba.gettexture('coin')) + bui.screenmessage(msg, (1, 1, 0), True, bui.gettexture('coin')) else: - ba.screenmessage(msg, (1, 1, 0), False) + bui.screenmessage(msg, (1, 1, 0), False) else: - ba.screenmessage(msg, (0.2, 1.0, 1.0), True, ba.gettexture('circleShadow')) + bui.screenmessage(msg, (0.2, 1.0, 1.0), True, bui.gettexture('circleShadow')) def msg_displayer(): for msg in messenger.pending_messages: display_message(msg[0], 'private', msg[1], msg[2]) messenger.pending_messages.remove(msg) - if ba.app.config['Chat Muted'] and not ba.app.config['Party Chat Muted']: + if babase.app.config['Chat Muted'] and not babase.app.config['Party Chat Muted']: global last_msg - last = _ba.get_chat_messages() + last = bs.get_chat_messages() lm = last[-1] if last else None if lm != last_msg: last_msg = lm @@ -404,45 +409,45 @@ def msg_displayer(): class SortQuickMessages: def __init__(self): - uiscale = ba.app.ui.uiscale - bg_color = ba.app.config.get('PartyWindow Main Color', (0.5, 0.5, 0.5)) - self._width = 750 if uiscale is ba.UIScale.SMALL else 600 - self._height = (300 if uiscale is ba.UIScale.SMALL else - 325 if uiscale is ba.UIScale.MEDIUM else 350) - self._root_widget = ba.containerwidget( + uiscale = bui.app.ui_v1.uiscale + bg_color = babase.app.config.get('PartyWindow Main Color', (0.5, 0.5, 0.5)) + self._width = 750 if uiscale is babase.UIScale.SMALL else 600 + self._height = (300 if uiscale is babase.UIScale.SMALL else + 325 if uiscale is babase.UIScale.MEDIUM else 350) + self._root_widget = bui.containerwidget( size=(self._width, self._height), transition='in_right', on_outside_click_call=self._save, color=bg_color, - parent=_ba.get_special_widget('overlay_stack'), - scale=(2.0 if uiscale is ba.UIScale.SMALL else - 1.3 if uiscale is ba.UIScale.MEDIUM else 1.0), - stack_offset=(0, -16) if uiscale is ba.UIScale.SMALL else (0, 0)) - ba.textwidget(parent=self._root_widget, + parent=bui.get_special_widget('overlay_stack'), + scale=(2.0 if uiscale is babase.UIScale.SMALL else + 1.3 if uiscale is babase.UIScale.MEDIUM else 1.0), + stack_offset=(0, -16) if uiscale is babase.UIScale.SMALL else (0, 0)) + bui.textwidget(parent=self._root_widget, position=(-10, self._height - 50), size=(self._width, 25), text='Sort Quick Messages', - color=ba.app.ui.title_color, + color=bui.app.ui_v1.title_color, scale=1.05, h_align='center', v_align='center', maxwidth=270) b_textcolor = (0.4, 0.75, 0.5) - up_button = ba.buttonwidget(parent=self._root_widget, + up_button = bui.buttonwidget(parent=self._root_widget, position=(10, 170), size=(75, 75), on_activate_call=self._move_up, - label=ba.charstr(ba.SpecialChar.UP_ARROW), + label=babase.charstr(babase.SpecialChar.UP_ARROW), button_type='square', color=bg_color, textcolor=b_textcolor, autoselect=True, repeat=True) - down_button = ba.buttonwidget(parent=self._root_widget, + down_button = bui.buttonwidget(parent=self._root_widget, position=(10, 75), size=(75, 75), on_activate_call=self._move_down, - label=ba.charstr(ba.SpecialChar.DOWN_ARROW), + label=babase.charstr(babase.SpecialChar.DOWN_ARROW), button_type='square', color=bg_color, textcolor=b_textcolor, @@ -450,12 +455,12 @@ def __init__(self): repeat=True) self._scroll_width = self._width - 150 self._scroll_height = self._height - 110 - self._scrollwidget = ba.scrollwidget( + self._scrollwidget = bui.scrollwidget( parent=self._root_widget, size=(self._scroll_width, self._scroll_height), color=bg_color, position=(100, 40)) - self._columnwidget = ba.columnwidget( + self._columnwidget = bui.columnwidget( parent=self._scrollwidget, border=2, margin=0) @@ -463,25 +468,25 @@ def __init__(self): self.msgs = f.read().split('\n') self._msg_selected = None self._refresh() - ba.containerwidget(edit=self._root_widget, + bui.containerwidget(edit=self._root_widget, on_cancel_call=self._save) def _refresh(self): for child in self._columnwidget.get_children(): child.delete() for msg in enumerate(self.msgs): - txt = ba.textwidget( + txt = bui.textwidget( parent=self._columnwidget, size=(self._scroll_width - 10, 30), selectable=True, always_highlight=True, - on_select_call=ba.Call(self._on_msg_select, msg), + on_select_call=babase.Call(self._on_msg_select, msg), text=msg[1], h_align='left', v_align='center', maxwidth=self._scroll_width) if msg == self._msg_selected: - ba.columnwidget(edit=self._columnwidget, + bui.columnwidget(edit=self._columnwidget, selected_child=txt, visible_child=txt) @@ -509,20 +514,20 @@ def _save(self) -> None: with open(quick_msg_file, 'w') as f: f.write('\n'.join(self.msgs)) except: - ba.print_exception() - ba.screenmessage('Error!', (1, 0, 0)) - ba.containerwidget( + babase.print_exception() + bui.screenmessage('Error!', (1, 0, 0)) + bui.containerwidget( edit=self._root_widget, transition='out_right') class TranslationSettings: def __init__(self): - uiscale = ba.app.ui.uiscale - height = (300 if uiscale is ba.UIScale.SMALL else - 350 if uiscale is ba.UIScale.MEDIUM else 400) - width = (500 if uiscale is ba.UIScale.SMALL else - 600 if uiscale is ba.UIScale.MEDIUM else 650) + uiscale = bui.app.ui_v1.uiscale + height = (300 if uiscale is babase.UIScale.SMALL else + 350 if uiscale is babase.UIScale.MEDIUM else 400) + width = (500 if uiscale is babase.UIScale.SMALL else + 600 if uiscale is babase.UIScale.MEDIUM else 650) self._transition_out: Optional[str] scale_origin: Optional[Tuple[float, float]] self._transition_out = 'out_scale' @@ -530,7 +535,7 @@ def __init__(self): transition = 'in_scale' scale_origin = None cancel_is_selected = False - cfg = ba.app.config + cfg = babase.app.config bg_color = cfg.get('PartyWindow Main Color', (0.5, 0.5, 0.5)) LANGUAGES = { @@ -643,17 +648,17 @@ def __init__(self): 'yo': 'yoruba', 'zu': 'zulu'} - self.root_widget = ba.containerwidget( + self.root_widget = bui.containerwidget( size=(width, height), color=bg_color, transition=transition, toolbar_visibility='menu_minimal_no_back', - parent=_ba.get_special_widget('overlay_stack'), + parent=bui.get_special_widget('overlay_stack'), on_outside_click_call=self._cancel, - scale=(2.1 if uiscale is ba.UIScale.SMALL else - 1.5 if uiscale is ba.UIScale.MEDIUM else 1.0), + scale=(2.1 if uiscale is babase.UIScale.SMALL else + 1.5 if uiscale is babase.UIScale.MEDIUM else 1.0), scale_origin_stack_offset=scale_origin) - ba.textwidget(parent=self.root_widget, + bui.textwidget(parent=self.root_widget, position=(width * 0.5, height - 45), size=(20, 20), h_align='center', @@ -661,15 +666,15 @@ def __init__(self): text="Text Translation", scale=0.9, color=(5, 5, 5)) - cbtn = btn = ba.buttonwidget(parent=self.root_widget, + cbtn = btn = bui.buttonwidget(parent=self.root_widget, autoselect=True, position=(30, height - 60), size=(30, 30), - label=ba.charstr(ba.SpecialChar.BACK), + label=babase.charstr(babase.SpecialChar.BACK), button_type='backSmall', on_activate_call=self._cancel) - source_lang_text = ba.textwidget(parent=self.root_widget, + source_lang_text = bui.textwidget(parent=self.root_widget, position=(40, height - 110), size=(20, 20), h_align='left', @@ -680,17 +685,17 @@ def __init__(self): source_lang_menu = PopupMenu( parent=self.root_widget, - position=(330 if uiscale is ba.UIScale.SMALL else 400, height - 115), + position=(330 if uiscale is babase.UIScale.SMALL else 400, height - 115), width=200, - scale=(2.8 if uiscale is ba.UIScale.SMALL else - 1.8 if uiscale is ba.UIScale.MEDIUM else 1.2), + scale=(2.8 if uiscale is babase.UIScale.SMALL else + 1.8 if uiscale is babase.UIScale.MEDIUM else 1.2), current_choice=cfg['Translate Source Language'], choices=LANGUAGES.keys(), - choices_display=(ba.Lstr(value=i) for i in LANGUAGES.values()), + choices_display=(babase.Lstr(value=i) for i in LANGUAGES.values()), button_size=(130, 35), on_value_change_call=self._change_source) - destination_lang_text = ba.textwidget(parent=self.root_widget, + destination_lang_text = bui.textwidget(parent=self.root_widget, position=(40, height - 165), size=(20, 20), h_align='left', @@ -701,19 +706,19 @@ def __init__(self): destination_lang_menu = PopupMenu( parent=self.root_widget, - position=(330 if uiscale is ba.UIScale.SMALL else 400, height - 170), + position=(330 if uiscale is babase.UIScale.SMALL else 400, height - 170), width=200, - scale=(2.8 if uiscale is ba.UIScale.SMALL else - 1.8 if uiscale is ba.UIScale.MEDIUM else 1.2), + scale=(2.8 if uiscale is babase.UIScale.SMALL else + 1.8 if uiscale is babase.UIScale.MEDIUM else 1.2), current_choice=cfg['Translate Destination Language'], choices=list(LANGUAGES.keys())[1:], - choices_display=list(ba.Lstr(value=i) for i in LANGUAGES.values())[1:], + choices_display=list(babase.Lstr(value=i) for i in LANGUAGES.values())[1:], button_size=(130, 35), on_value_change_call=self._change_destination) try: - translation_mode_text = ba.textwidget(parent=self.root_widget, + translation_mode_text = bui.textwidget(parent=self.root_widget, position=(40, height - 215), size=(20, 20), h_align='left', @@ -721,7 +726,7 @@ def __init__(self): text="Translate Mode", scale=0.9, color=(1, 1, 1)) - decoration = ba.textwidget(parent=self.root_widget, + decoration = bui.textwidget(parent=self.root_widget, position=(40, height - 225), size=(20, 20), h_align='left', @@ -730,7 +735,7 @@ def __init__(self): scale=0.9, color=(1, 1, 1)) - language_char_text = ba.textwidget(parent=self.root_widget, + language_char_text = bui.textwidget(parent=self.root_widget, position=(85, height - 273), size=(20, 20), h_align='left', @@ -739,7 +744,7 @@ def __init__(self): scale=0.6, color=(1, 1, 1)) - pronunciation_text = ba.textwidget(parent=self.root_widget, + pronunciation_text = bui.textwidget(parent=self.root_widget, position=(295, height - 273), size=(20, 20), h_align='left', @@ -748,9 +753,9 @@ def __init__(self): scale=0.6, color=(1, 1, 1)) - from bastd.ui.radiogroup import make_radio_group - cur_val = ba.app.config.get('Pronunciation', True) - cb1 = ba.checkboxwidget( + from bauiv1lib.radiogroup import make_radio_group + cur_val = babase.app.config.get('Pronunciation', True) + cb1 = bui.checkboxwidget( parent=self.root_widget, position=(250, height - 275), size=(20, 20), @@ -758,7 +763,7 @@ def __init__(self): scale=1, autoselect=True, text="") - cb2 = ba.checkboxwidget( + cb2 = bui.checkboxwidget( parent=self.root_widget, position=(40, height - 275), size=(20, 20), @@ -772,40 +777,40 @@ def __init__(self): print(e) pass - ba.containerwidget(edit=self.root_widget, cancel_button=btn) + bui.containerwidget(edit=self.root_widget, cancel_button=btn) def _change_source(self, choice): - cfg = ba.app.config + cfg = babase.app.config cfg['Translate Source Language'] = choice cfg.apply_and_commit() def _change_destination(self, choice): - cfg = ba.app.config + cfg = babase.app.config cfg['Translate Destination Language'] = choice cfg.apply_and_commit() def _actions_changed(self, v: str) -> None: - cfg = ba.app.config + cfg = babase.app.config cfg['Pronunciation'] = v cfg.apply_and_commit() def _cancel(self) -> None: - ba.containerwidget(edit=self.root_widget, transition='out_scale') + bui.containerwidget(edit=self.root_widget, transition='out_scale') SettingsWindow() class SettingsWindow: def __init__(self): - uiscale = ba.app.ui.uiscale - height = (300 if uiscale is ba.UIScale.SMALL else - 350 if uiscale is ba.UIScale.MEDIUM else 400) - width = (500 if uiscale is ba.UIScale.SMALL else - 600 if uiscale is ba.UIScale.MEDIUM else 650) - scroll_h = (200 if uiscale is ba.UIScale.SMALL else - 250 if uiscale is ba.UIScale.MEDIUM else 270) - scroll_w = (450 if uiscale is ba.UIScale.SMALL else - 550 if uiscale is ba.UIScale.MEDIUM else 600) + uiscale = bui.app.ui_v1.uiscale + height = (300 if uiscale is babase.UIScale.SMALL else + 350 if uiscale is babase.UIScale.MEDIUM else 400) + width = (500 if uiscale is babase.UIScale.SMALL else + 600 if uiscale is babase.UIScale.MEDIUM else 650) + scroll_h = (200 if uiscale is babase.UIScale.SMALL else + 250 if uiscale is babase.UIScale.MEDIUM else 270) + scroll_w = (450 if uiscale is babase.UIScale.SMALL else + 550 if uiscale is babase.UIScale.MEDIUM else 600) self._transition_out: Optional[str] scale_origin: Optional[Tuple[float, float]] self._transition_out = 'out_scale' @@ -813,20 +818,20 @@ def __init__(self): transition = 'in_scale' scale_origin = None cancel_is_selected = False - cfg = ba.app.config + cfg = babase.app.config bg_color = cfg.get('PartyWindow Main Color', (0.5, 0.5, 0.5)) - self.root_widget = ba.containerwidget( + self.root_widget = bui.containerwidget( size=(width, height), color=bg_color, transition=transition, toolbar_visibility='menu_minimal_no_back', - parent=_ba.get_special_widget('overlay_stack'), + parent=bui.get_special_widget('overlay_stack'), on_outside_click_call=self._cancel, - scale=(2.1 if uiscale is ba.UIScale.SMALL else - 1.5 if uiscale is ba.UIScale.MEDIUM else 1.0), + scale=(2.1 if uiscale is babase.UIScale.SMALL else + 1.5 if uiscale is babase.UIScale.MEDIUM else 1.0), scale_origin_stack_offset=scale_origin) - ba.textwidget(parent=self.root_widget, + bui.textwidget(parent=self.root_widget, position=(width * 0.5, height - 45), size=(20, 20), h_align='center', @@ -834,25 +839,25 @@ def __init__(self): text="Custom Settings", scale=0.9, color=(5, 5, 5)) - cbtn = btn = ba.buttonwidget(parent=self.root_widget, + cbtn = btn = bui.buttonwidget(parent=self.root_widget, autoselect=True, position=(30, height - 60), size=(30, 30), - label=ba.charstr(ba.SpecialChar.BACK), + label=babase.charstr(babase.SpecialChar.BACK), button_type='backSmall', on_activate_call=self._cancel) - scroll_position = (30 if uiscale is ba.UIScale.SMALL else - 40 if uiscale is ba.UIScale.MEDIUM else 50) - self._scrollwidget = ba.scrollwidget(parent=self.root_widget, + scroll_position = (30 if uiscale is babase.UIScale.SMALL else + 40 if uiscale is babase.UIScale.MEDIUM else 50) + self._scrollwidget = bui.scrollwidget(parent=self.root_widget, position=(30, scroll_position), simple_culling_v=20.0, highlight=False, size=(scroll_w, scroll_h), selection_loops_to_parent=True) - ba.widget(edit=self._scrollwidget, right_widget=self._scrollwidget) - self._subcontainer = ba.columnwidget(parent=self._scrollwidget, + bui.widget(edit=self._scrollwidget, right_widget=self._scrollwidget) + self._subcontainer = bui.columnwidget(parent=self._scrollwidget, selection_loops_to_parent=True) - ip_button = ba.checkboxwidget( + ip_button = bui.checkboxwidget( parent=self._subcontainer, size=(300, 30), maxwidth=300, @@ -862,7 +867,7 @@ def __init__(self): autoselect=True, text="IP Button", on_value_change_call=self.ip_button) - ping_button = ba.checkboxwidget( + ping_button = bui.checkboxwidget( parent=self._subcontainer, size=(300, 30), maxwidth=300, @@ -872,7 +877,7 @@ def __init__(self): autoselect=True, text="Ping Button", on_value_change_call=self.ping_button) - copy_button = ba.checkboxwidget( + copy_button = bui.checkboxwidget( parent=self._subcontainer, size=(300, 30), maxwidth=300, @@ -882,7 +887,7 @@ def __init__(self): autoselect=True, text="Copy Text Button", on_value_change_call=self.copy_button) - direct_send = ba.checkboxwidget( + direct_send = bui.checkboxwidget( parent=self._subcontainer, size=(300, 30), maxwidth=300, @@ -892,7 +897,7 @@ def __init__(self): autoselect=True, text="Directly Send Custom Commands", on_value_change_call=self.direct_send) - colorfulchat = ba.checkboxwidget( + colorfulchat = bui.checkboxwidget( parent=self._subcontainer, size=(300, 30), maxwidth=300, @@ -902,7 +907,7 @@ def __init__(self): autoselect=True, text="Colorful Chat", on_value_change_call=self.colorful_chat) - msg_notification_text = ba.textwidget(parent=self._subcontainer, + msg_notification_text = bui.textwidget(parent=self._subcontainer, scale=0.8, color=(1, 1, 1), text='Message Notifcation:', @@ -913,13 +918,13 @@ def __init__(self): parent=self._subcontainer, position=(100, height - 1200), width=200, - scale=(2.8 if uiscale is ba.UIScale.SMALL else - 1.8 if uiscale is ba.UIScale.MEDIUM else 1.2), + scale=(2.8 if uiscale is babase.UIScale.SMALL else + 1.8 if uiscale is babase.UIScale.MEDIUM else 1.2), choices=['top', 'bottom'], - current_choice=ba.app.config['Message Notification'], + current_choice=babase.app.config['Message Notification'], button_size=(80, 25), on_value_change_call=self._change_notification) - self_status_text = ba.textwidget(parent=self._subcontainer, + self_status_text = bui.textwidget(parent=self._subcontainer, scale=0.8, color=(1, 1, 1), text='Self Status:', @@ -930,19 +935,19 @@ def __init__(self): parent=self._subcontainer, position=(50, height - 1000), width=200, - scale=(2.8 if uiscale is ba.UIScale.SMALL else - 1.8 if uiscale is ba.UIScale.MEDIUM else 1.2), + scale=(2.8 if uiscale is babase.UIScale.SMALL else + 1.8 if uiscale is babase.UIScale.MEDIUM else 1.2), choices=['online', 'offline'], - current_choice=ba.app.config['Self Status'], + current_choice=babase.app.config['Self Status'], button_size=(80, 25), on_value_change_call=self._change_status) - ba.containerwidget(edit=self.root_widget, cancel_button=btn) - ba.containerwidget(edit=self.root_widget, + bui.containerwidget(edit=self.root_widget, cancel_button=btn) + bui.containerwidget(edit=self.root_widget, selected_child=(cbtn if cbtn is not None and cancel_is_selected else None), start_button=None) - self._translation_btn = ba.buttonwidget(parent=self._subcontainer, + self._translation_btn = bui.buttonwidget(parent=self._subcontainer, scale=1.2, position=(100, 1200), size=(150, 50), @@ -951,99 +956,99 @@ def __init__(self): autoselect=True) def ip_button(self, value: bool): - cfg = ba.app.config + cfg = babase.app.config cfg['IP button'] = value cfg.apply_and_commit() if cfg['IP button']: - ba.screenmessage("IP Button is now enabled", color=(0, 1, 0)) + bui.screenmessage("IP Button is now enabled", color=(0, 1, 0)) else: - ba.screenmessage("IP Button is now disabled", color=(1, 0.7, 0)) + bui.screenmessage("IP Button is now disabled", color=(1, 0.7, 0)) def ping_button(self, value: bool): - cfg = ba.app.config + cfg = babase.app.config cfg['ping button'] = value cfg.apply_and_commit() if cfg['ping button']: - ba.screenmessage("Ping Button is now enabled", color=(0, 1, 0)) + bui.screenmessage("Ping Button is now enabled", color=(0, 1, 0)) else: - ba.screenmessage("Ping Button is now disabled", color=(1, 0.7, 0)) + bui.screenmessage("Ping Button is now disabled", color=(1, 0.7, 0)) def copy_button(self, value: bool): - cfg = ba.app.config + cfg = babase.app.config cfg['copy button'] = value cfg.apply_and_commit() if cfg['copy button']: - ba.screenmessage("Copy Text Button is now enabled", color=(0, 1, 0)) + bui.screenmessage("Copy Text Button is now enabled", color=(0, 1, 0)) else: - ba.screenmessage("Copy Text Button is now disabled", color=(1, 0.7, 0)) + bui.screenmessage("Copy Text Button is now disabled", color=(1, 0.7, 0)) def direct_send(self, value: bool): - cfg = ba.app.config + cfg = babase.app.config cfg['Direct Send'] = value cfg.apply_and_commit() def colorful_chat(self, value: bool): - cfg = ba.app.config + cfg = babase.app.config cfg['Colorful Chat'] = value cfg.apply_and_commit() def _change_notification(self, choice): - cfg = ba.app.config + cfg = babase.app.config cfg['Message Notification'] = choice cfg.apply_and_commit() def _change_status(self, choice): - cfg = ba.app.config + cfg = babase.app.config cfg['Self Status'] = choice cfg.apply_and_commit() def _translaton_btn(self): try: - ba.containerwidget(edit=self.root_widget, transition='out_scale') + bui.containerwidget(edit=self.root_widget, transition='out_scale') TranslationSettings() except Exception as e: print(e) pass def _cancel(self) -> None: - ba.containerwidget(edit=self.root_widget, transition='out_scale') + bui.containerwidget(edit=self.root_widget, transition='out_scale') -class PartyWindow(ba.Window): +class PartyWindow(bui.Window): """Party list/chat window.""" def __del__(self) -> None: - _ba.set_party_window_open(False) + bui.set_party_window_open(False) def __init__(self, origin: Sequence[float] = (0, 0)): self._private_chat = False self._firstcall = True self.ping_server() - _ba.set_party_window_open(True) + bui.set_party_window_open(True) self._r = 'partyWindow' self._popup_type: Optional[str] = None self._popup_party_member_client_id: Optional[int] = None self._popup_party_member_is_host: Optional[bool] = None self._width = 500 - uiscale = ba.app.ui.uiscale - self._height = (365 if uiscale is ba.UIScale.SMALL else - 480 if uiscale is ba.UIScale.MEDIUM else 600) - self.bg_color = ba.app.config.get('PartyWindow Main Color', (0.5, 0.5, 0.5)) - self.ping_timer = ba.Timer(5, ba.WeakCall(self.ping_server), repeat=True) + uiscale = bui.app.ui_v1.uiscale + self._height = (365 if uiscale is babase.UIScale.SMALL else + 480 if uiscale is babase.UIScale.MEDIUM else 600) + self.bg_color = babase.app.config.get('PartyWindow Main Color', (0.5, 0.5, 0.5)) + self.ping_timer = bs.apptimer(5, bs.WeakCall(self.ping_server)) - ba.Window.__init__(self, root_widget=ba.containerwidget( + bui.Window.__init__(self, root_widget=bui.containerwidget( size=(self._width, self._height), transition='in_scale', color=self.bg_color, - parent=_ba.get_special_widget('overlay_stack'), + parent=bui.get_special_widget('overlay_stack'), on_outside_click_call=self.close_with_sound, scale_origin_stack_offset=origin, - scale=(2.0 if uiscale is ba.UIScale.SMALL else - 1.35 if uiscale is ba.UIScale.MEDIUM else 1.0), - stack_offset=(0, -10) if uiscale is ba.UIScale.SMALL else ( - 240, 0) if uiscale is ba.UIScale.MEDIUM else (330, 20))) + scale=(2.0 if uiscale is babase.UIScale.SMALL else + 1.35 if uiscale is babase.UIScale.MEDIUM else 1.0), + stack_offset=(0, -10) if uiscale is babase.UIScale.SMALL else ( + 240, 0) if uiscale is babase.UIScale.MEDIUM else (330, 20))) - self._cancel_button = ba.buttonwidget(parent=self._root_widget, + self._cancel_button = bui.buttonwidget(parent=self._root_widget, scale=0.7, position=(30, self._height - 47), size=(50, 50), @@ -1051,12 +1056,12 @@ def __init__(self, origin: Sequence[float] = (0, 0)): on_activate_call=self.close, autoselect=True, color=self.bg_color, - icon=ba.gettexture('crossOut'), + icon=bui.gettexture('crossOut'), iconscale=1.2) - ba.containerwidget(edit=self._root_widget, + bui.containerwidget(edit=self._root_widget, cancel_button=self._cancel_button) - self._menu_button = ba.buttonwidget( + self._menu_button = bui.buttonwidget( parent=self._root_widget, scale=0.7, position=(self._width - 80, self._height - 47), @@ -1064,17 +1069,17 @@ def __init__(self, origin: Sequence[float] = (0, 0)): label='...', autoselect=True, button_type='square', - on_activate_call=ba.WeakCall(self._on_menu_button_press), + on_activate_call=bs.WeakCall(self._on_menu_button_press), color=self.bg_color, iconscale=1.2) - - info = _ba.get_connection_to_host_info() - if info.get('name', '') != '': - self.title = ba.Lstr(value=info['name']) - else: - self.title = ba.Lstr(resource=self._r + '.titleText') - - self._title_text = ba.textwidget(parent=self._root_widget, + try: + info = bs.get_connection_to_host_info().get('name', '') if build_number < 21697 else bs.get_connection_to_host_info_2().name + if info != '': + self.title = babase.Lstr(value=info['name']) if build_number < 21697 else babase.Lstr(value=info) + except AttributeError: + self.title = babase.Lstr(resource=self._r + '.titleText') + + self._title_text = bui.textwidget(parent=self._root_widget, scale=0.9, color=(0.5, 0.7, 0.5), text=self.title, @@ -1084,7 +1089,7 @@ def __init__(self, origin: Sequence[float] = (0, 0)): maxwidth=self._width * 0.6, h_align='center', v_align='center') - self._empty_str = ba.textwidget(parent=self._root_widget, + self._empty_str = bui.textwidget(parent=self._root_widget, scale=0.75, size=(0, 0), position=(self._width * 0.5, @@ -1094,25 +1099,25 @@ def __init__(self, origin: Sequence[float] = (0, 0)): v_align='center') self._scroll_width = self._width - 50 - self._scrollwidget = ba.scrollwidget(parent=self._root_widget, + self._scrollwidget = bui.scrollwidget(parent=self._root_widget, size=(self._scroll_width, self._height - 200), position=(30, 80), color=self.bg_color) - self._columnwidget = ba.columnwidget(parent=self._scrollwidget, + self._columnwidget = bui.columnwidget(parent=self._scrollwidget, border=2, margin=0) - ba.widget(edit=self._menu_button, down_widget=self._columnwidget) + bui.widget(edit=self._menu_button, down_widget=self._columnwidget) - self._muted_text = ba.textwidget( + self._muted_text = bui.textwidget( parent=self._root_widget, position=(self._width * 0.5, self._height * 0.5), size=(0, 0), h_align='center', v_align='center', - text=ba.Lstr(resource='chatMutedText')) + text=babase.Lstr(resource='chatMutedText')) - self._text_field = txt = ba.textwidget( + self._text_field = txt = bui.textwidget( parent=self._root_widget, editable=True, size=(500, 40), @@ -1121,49 +1126,49 @@ def __init__(self, origin: Sequence[float] = (0, 0)): maxwidth=494, shadow=0.3, flatness=1.0, - description=ba.Lstr(resource=self._r + '.chatMessageText'), + description=babase.Lstr(resource=self._r + '.chatMessageText'), autoselect=True, v_align='center', corner_scale=0.7) - ba.widget(edit=self._scrollwidget, + bui.widget(edit=self._scrollwidget, autoselect=True, left_widget=self._cancel_button, up_widget=self._cancel_button, down_widget=self._text_field) - ba.widget(edit=self._columnwidget, + bui.widget(edit=self._columnwidget, autoselect=True, up_widget=self._cancel_button, down_widget=self._text_field) - ba.containerwidget(edit=self._root_widget, selected_child=txt) - self._send_button = btn = ba.buttonwidget(parent=self._root_widget, + bui.containerwidget(edit=self._root_widget, selected_child=txt) + self._send_button = btn = bui.buttonwidget(parent=self._root_widget, size=(50, 35), - label=ba.Lstr(resource=self._r + '.sendText'), + label=babase.Lstr(resource=self._r + '.sendText'), button_type='square', autoselect=True, color=self.bg_color, position=(self._width - 90, 35), on_activate_call=self._send_chat_message) - ba.textwidget(edit=txt, on_return_press_call=btn.activate) - self._previous_button = ba.buttonwidget(parent=self._root_widget, + bui.textwidget(edit=txt, on_return_press_call=btn.activate) + self._previous_button = bui.buttonwidget(parent=self._root_widget, size=(30, 30), - label=ba.charstr(ba.SpecialChar.UP_ARROW), + label=babase.charstr(babase.SpecialChar.UP_ARROW), button_type='square', autoselect=True, position=(15, 57), color=self.bg_color, scale=0.75, on_activate_call=self._previous_message) - self._next_button = ba.buttonwidget(parent=self._root_widget, + self._next_button = bui.buttonwidget(parent=self._root_widget, size=(30, 30), - label=ba.charstr(ba.SpecialChar.DOWN_ARROW), + label=babase.charstr(babase.SpecialChar.DOWN_ARROW), button_type='square', autoselect=True, color=self.bg_color, scale=0.75, position=(15, 28), on_activate_call=self._next_message) - self._translate_button = ba.buttonwidget(parent=self._root_widget, + self._translate_button = bui.buttonwidget(parent=self._root_widget, size=(55, 47), label="Trans", button_type='square', @@ -1172,8 +1177,8 @@ def __init__(self, origin: Sequence[float] = (0, 0)): scale=0.75, position=(self._width - 28, 35), on_activate_call=self._translate) - if ba.app.config['copy button']: - self._copy_button = ba.buttonwidget(parent=self._root_widget, + if babase.app.config['copy button']: + self._copy_button = bui.buttonwidget(parent=self._root_widget, size=(15, 15), label='©', button_type='backSmall', @@ -1182,31 +1187,35 @@ def __init__(self, origin: Sequence[float] = (0, 0)): position=(self._width - 40, 80), on_activate_call=self._copy_to_clipboard) self._ping_button = None - if info.get('name', '') != '': - if ba.app.config['ping button']: - self._ping_button = ba.buttonwidget( - parent=self._root_widget, - scale=0.7, - position=(self._width - 538, self._height - 57), - size=(75, 75), - autoselect=True, - button_type='square', - label=f'{_ping}', - on_activate_call=self._send_ping, - color=self.bg_color, - text_scale=2.3, - iconscale=1.2) - if ba.app.config['IP button']: - self._ip_port_button = ba.buttonwidget(parent=self._root_widget, - size=(30, 30), - label='IP', - button_type='square', - autoselect=True, - color=self.bg_color, - position=(self._width - 530, - self._height - 100), - on_activate_call=self._ip_port_msg) - self._settings_button = ba.buttonwidget(parent=self._root_widget, + try: + info = bs.get_connection_to_host_info().get('name', '') if build_number < 21697 else bs.get_connection_to_host_info_2().name + if info != '': + if babase.app.config['ping button']: + self._ping_button = bui.buttonwidget( + parent=self._root_widget, + scale=0.7, + position=(self._width - 538, self._height - 57), + size=(75, 75), + autoselect=True, + button_type='square', + label=f'{_ping}', + on_activate_call=self._send_ping, + color=self.bg_color, + text_scale=2.3, + iconscale=1.2) + if babase.app.config['IP button']: + self._ip_port_button = bui.buttonwidget(parent=self._root_widget, + size=(30, 30), + label='IP', + button_type='square', + autoselect=True, + color=self.bg_color, + position=(self._width - 530, + self._height - 100), + on_activate_call=self._ip_port_msg) + except AttributeError: + pass + self._settings_button = bui.buttonwidget(parent=self._root_widget, size=(50, 50), scale=0.5, button_type='square', @@ -1214,9 +1223,9 @@ def __init__(self, origin: Sequence[float] = (0, 0)): color=self.bg_color, position=(self._width - 40, self._height - 47), on_activate_call=self._on_setting_button_press, - icon=ba.gettexture('settingsIcon'), + icon=bui.gettexture('settingsIcon'), iconscale=1.2) - self._privatechat_button = ba.buttonwidget(parent=self._root_widget, + self._privatechat_button = bui.buttonwidget(parent=self._root_widget, size=(50, 50), scale=0.5, button_type='square', @@ -1224,19 +1233,17 @@ def __init__(self, origin: Sequence[float] = (0, 0)): color=self.bg_color, position=(self._width - 40, self._height - 80), on_activate_call=self._on_privatechat_button_press, - icon=ba.gettexture('ouyaOButton'), + icon=bui.gettexture('ouyaOButton'), iconscale=1.2) - self._name_widgets: List[ba.Widget] = [] + self._name_widgets: List[bui.Widget] = [] self._roster: Optional[List[Dict[str, Any]]] = None - self._update_timer = ba.Timer(1.0, - ba.WeakCall(self._update), - repeat=True, - timetype=ba.TimeType.REAL) + self._update_timer = bs.apptimer(1.0, + bs.WeakCall(self._update)) self._update() def on_chat_message(self, msg: str, sent=None) -> None: """Called when a new chat message comes through.""" - if ba.app.config['Party Chat Muted'] and not _ba.app.ui.party_window()._private_chat: + if babase.app.config['Party Chat Muted'] and not bui.app.ui_v1.party_window()._private_chat: return if sent: self._add_msg(msg, sent) @@ -1244,13 +1251,13 @@ def on_chat_message(self, msg: str, sent=None) -> None: self._add_msg(msg) def _add_msg(self, msg: str, sent=None) -> None: - if ba.app.config['Colorful Chat']: + if babase.app.config['Colorful Chat']: sender = msg.split(': ')[0] color = color_tracker._get_sender_color(sender) if sender else (1, 1, 1) else: color = (1, 1, 1) maxwidth = self._scroll_width * 0.94 - txt = ba.textwidget(parent=self._columnwidget, + txt = bui.textwidget(parent=self._columnwidget, text=msg, h_align='left', v_align='center', @@ -1261,33 +1268,33 @@ def _add_msg(self, msg: str, sent=None) -> None: shadow=0.3, flatness=1.0) if sent: - ba.textwidget(edit=txt, size=(100, 15), + bui.textwidget(edit=txt, size=(100, 15), selectable=True, click_activate=True, - on_activate_call=ba.Call(ba.screenmessage, f'Message sent: {_get_local_time(sent)}')) + on_activate_call=babase.Call(bui.screenmessage, f'Message sent: {_get_local_time(sent)}')) self._chat_texts.append(txt) if len(self._chat_texts) > 40: first = self._chat_texts.pop(0) first.delete() - ba.containerwidget(edit=self._columnwidget, visible_child=txt) + bui.containerwidget(edit=self._columnwidget, visible_child=txt) def _on_menu_button_press(self) -> None: - is_muted = ba.app.config['Party Chat Muted'] - uiscale = ba.app.ui.uiscale + is_muted = babase.app.config['Party Chat Muted'] + uiscale = bui.app.ui_v1.uiscale choices = ['muteOption', 'modifyColor', 'addQuickReply', 'removeQuickReply', 'credits'] choices_display = ['Mute Option', 'Modify Main Color', 'Add as Quick Reply', 'Remove a Quick Reply', 'Credits'] - if hasattr(_ba.get_foreground_host_activity(), '_map'): + if hasattr(bs.get_foreground_host_activity(), '_map'): choices.append('manualCamera') choices_display.append('Manual Camera') PopupMenuWindow( position=self._menu_button.get_screen_space_center(), color=self.bg_color, - scale=(2.3 if uiscale is ba.UIScale.SMALL else - 1.65 if uiscale is ba.UIScale.MEDIUM else 1.23), + scale=(2.3 if uiscale is babase.UIScale.SMALL else + 1.65 if uiscale is babase.UIScale.MEDIUM else 1.23), choices=choices, choices_display=self._create_baLstr_list(choices_display), current_choice='muteOption', @@ -1296,35 +1303,35 @@ def _on_menu_button_press(self) -> None: def _update(self) -> None: if not self._private_chat: - _ba.set_party_window_open(True) - ba.textwidget(edit=self._title_text, text=self.title) + bui.set_party_window_open(True) + bui.textwidget(edit=self._title_text, text=self.title) if self._firstcall: if hasattr(self, '_status_text'): self._status_text.delete() self._roster = [] self._firstcall = False - self._chat_texts: List[ba.Widget] = [] - if not ba.app.config['Party Chat Muted']: - msgs = _ba.get_chat_messages() + self._chat_texts: List[bui.Widget] = [] + if not babase.app.config['Party Chat Muted']: + msgs = bs.get_chat_messages() for msg in msgs: self._add_msg(msg) # update muted state - if ba.app.config['Party Chat Muted']: - ba.textwidget(edit=self._muted_text, color=(1, 1, 1, 0.3)) + if babase.app.config['Party Chat Muted']: + bui.textwidget(edit=self._muted_text, color=(1, 1, 1, 0.3)) # clear any chat texts we're showing if self._chat_texts: while self._chat_texts: first = self._chat_texts.pop() first.delete() else: - ba.textwidget(edit=self._muted_text, color=(1, 1, 1, 0.0)) + bui.textwidget(edit=self._muted_text, color=(1, 1, 1, 0.0)) if self._ping_button: - ba.buttonwidget(edit=self._ping_button, + bui.buttonwidget(edit=self._ping_button, label=f'{_ping}', textcolor=self._get_ping_color()) # update roster section - roster = _ba.get_game_roster() + roster = bs.get_game_roster() if roster != self._roster or self._firstcall: self._roster = roster @@ -1335,9 +1342,9 @@ def _update(self) -> None: self._name_widgets = [] if not self._roster: top_section_height = 60 - ba.textwidget(edit=self._empty_str, - text=ba.Lstr(resource=self._r + '.emptyText')) - ba.scrollwidget(edit=self._scrollwidget, + bui.textwidget(edit=self._empty_str, + text=babase.Lstr(resource=self._r + '.emptyText')) + bui.scrollwidget(edit=self._scrollwidget, size=(self._width - 50, self._height - top_section_height - 110), position=(30, 80)) @@ -1380,10 +1387,10 @@ def _update(self) -> None: p_str = self._roster[index][ 'display_string'] except Exception: - ba.print_exception( + babase.print_exception( 'Error calcing client name str.') p_str = '???' - widget = ba.textwidget(parent=self._root_widget, + widget = bui.textwidget(parent=self._root_widget, position=(pos[0], pos[1]), scale=t_scale, size=(c_width * 0.85, 30), @@ -1394,7 +1401,7 @@ def _update(self) -> None: selectable=True, autoselect=True, click_activate=True, - text=ba.Lstr(value=p_str), + text=babase.Lstr(value=p_str), h_align='left', v_align='center') self._name_widgets.append(widget) @@ -1412,8 +1419,8 @@ def _update(self) -> None: # FIXME: Should pass client_id to these sort of # calls; not spec-string (perhaps should wait till # client_id is more readily available though). - ba.textwidget(edit=widget, - on_activate_call=ba.Call( + bui.textwidget(edit=widget, + on_activate_call=babase.Call( self._on_party_member_press, self._roster[index]['client_id'], is_host, widget)) @@ -1427,11 +1434,11 @@ def _update(self) -> None: if is_host: twd = min( c_width * 0.85, - _ba.get_string_width( + _babase.get_string_width( p_str, suppress_warning=True) * t_scale) self._name_widgets.append( - ba.textwidget( + bui.textwidget( parent=self._root_widget, position=(pos[0] + twd + 1, pos[1] - 0.5), @@ -1440,24 +1447,24 @@ def _update(self) -> None: v_align='center', maxwidth=c_width * 0.96 - twd, color=(0.1, 1, 0.1, 0.5), - text=ba.Lstr(resource=self._r + + text=babase.Lstr(resource=self._r + '.hostText'), scale=0.4, shadow=0.1, flatness=1.0)) - ba.textwidget(edit=self._empty_str, text='') - ba.scrollwidget(edit=self._scrollwidget, + bui.textwidget(edit=self._empty_str, text='') + bui.scrollwidget(edit=self._scrollwidget, size=(self._width - 50, max(100, self._height - 139 - c_height_total)), position=(30, 80)) else: - _ba.set_party_window_open(False) + bui.set_party_window_open(False) for widget in self._name_widgets: widget.delete() self._name_widgets = [] - ba.textwidget(edit=self._title_text, text='Private Chat') - ba.textwidget(edit=self._empty_str, text='') + bui.textwidget(edit=self._title_text, text='Private Chat') + bui.textwidget(edit=self._empty_str, text='') if self._firstcall: self._firstcall = False if hasattr(self, '_status_text'): @@ -1470,15 +1477,15 @@ def _update(self) -> None: while self._chat_texts: first = self._chat_texts.pop() first.delete() - uiscale = ba.app.ui.uiscale - scroll_height = (165 if uiscale is ba.UIScale.SMALL else - 280 if uiscale is ba.UIScale.MEDIUM else 400) - ba.scrollwidget(edit=self._scrollwidget, + uiscale = bui.app.ui_v1.uiscale + scroll_height = (165 if uiscale is babase.UIScale.SMALL else + 280 if uiscale is babase.UIScale.MEDIUM else 400) + bui.scrollwidget(edit=self._scrollwidget, size=(self._width - 50, scroll_height)) for msg in msgs: message = messenger._format_message(msg) self._add_msg(message, msg['sent']) - self._filter_text = ba.textwidget(parent=self._root_widget, + self._filter_text = bui.textwidget(parent=self._root_widget, scale=0.6, color=(0.9, 1.0, 0.9), text='Filter: ', @@ -1488,17 +1495,17 @@ def _update(self) -> None: h_align='center', v_align='center') choices = [i for i in messenger.saved_ids] - choices_display = [ba.Lstr(value=messenger.saved_ids[i]) + choices_display = [babase.Lstr(value=messenger.saved_ids[i]) for i in messenger.saved_ids] choices.append('add') - choices_display.append(ba.Lstr(value='***Add New***')) + choices_display.append(babase.Lstr(value='***Add New***')) filter_widget = PopupMenu( parent=self._root_widget, position=(self._width * 0.4, self._height - 80), width=200, - scale=(2.8 if uiscale is ba.UIScale.SMALL else - 1.8 if uiscale is ba.UIScale.MEDIUM else 1.2), + scale=(2.8 if uiscale is babase.UIScale.SMALL else + 1.8 if uiscale is babase.UIScale.MEDIUM else 1.2), choices=choices, choices_display=choices_display, current_choice=messenger.filter, @@ -1513,7 +1520,7 @@ def _update(self) -> None: color = (0, 1, 0) else: color = (0.9, 1.0, 0.9) - self._status_text = ba.textwidget(parent=self._root_widget, + self._status_text = bui.textwidget(parent=self._root_widget, scale=0.5, color=color, text=f'Status:\t{user_status}', @@ -1525,8 +1532,8 @@ def _update(self) -> None: autoselect=True, selectable=True, click_activate=True) - ba.textwidget(edit=self._status_text, - on_activate_call=ba.Call(messenger._get_status, messenger.filter, 'last_seen')) + bui.textwidget(edit=self._status_text, + on_activate_call=babase.Call(messenger._get_status, messenger.filter, 'last_seen')) def _change_filter(self, choice): if choice == 'add': @@ -1596,17 +1603,17 @@ def popup_menu_selected_choice(self, popup_window: PopupMenuWindow, name = playerinfo['players'][0]['name_full'] except: name = account - for i in ba.app.config.get('Custom Commands'): + for i in babase.app.config.get('Custom Commands'): i = i.replace('$c', str(self._popup_party_member_client_id)) i = i.replace('$a', str(account)) i = i.replace('$n', str(name)) - if ba.app.config['Direct Send']: - choices.append(f'_ba.chatmessage("{i}")') + if babase.app.config['Direct Send']: + choices.append(f'bs.chatmessage("{i}")') else: choices.append(f'self._edit_text_msg_box("{i}")') - choices_display.append(ba.Lstr(value=i)) + choices_display.append(babase.Lstr(value=i)) choices.append('AddNewChoiceWindow()') - choices_display.append(ba.Lstr(value='***Add New***')) + choices_display.append(babase.Lstr(value='***Add New***')) PopupMenuWindow(position=popup_window.root_widget.get_screen_space_center(), color=self.bg_color, scale=self._get_popup_window_scale(), @@ -1640,14 +1647,14 @@ def popup_menu_selected_choice(self, popup_window: PopupMenuWindow, delegate=self, tag='') elif choice == 'addQuickReply': try: - newReply = ba.textwidget(query=self._text_field) + newReply = bui.textwidget(query=self._text_field) oldReplies = self._get_quick_responds() oldReplies.append(newReply) self._write_quick_responds(oldReplies) - ba.screenmessage(f'"{newReply}" is added.', (0, 1, 0)) - ba.playsound(ba.getsound('dingSmallHigh')) + bui.screenmessage(f'"{newReply}" is added.', (0, 1, 0)) + bui.getsound('dingSmallHigh').play() except: - ba.print_exception() + babase.print_exception() elif choice == 'removeQuickReply': quick_reply = self._get_quick_responds() PopupMenuWindow(position=self._send_button.get_screen_space_center(), @@ -1669,7 +1676,7 @@ def popup_menu_selected_choice(self, popup_window: PopupMenuWindow, ok_text="Join Discord", origin_widget=self.get_root_widget()) elif choice == 'manualCamera': - ba.containerwidget(edit=self._root_widget, transition='out_scale') + bui.containerwidget(edit=self._root_widget, transition='out_scale') Manual_camera_window() elif self._popup_type == 'muteType': @@ -1688,8 +1695,8 @@ def popup_menu_selected_choice(self, popup_window: PopupMenuWindow, data = self._get_quick_responds() data.remove(choice) self._write_quick_responds(data) - ba.screenmessage(f'"{choice}" is removed.', (1, 0, 0)) - ba.playsound(ba.getsound('shieldDown')) + bui.screenmessage(f'"{choice}" is removed.', (1, 0, 0)) + bui.getsound('shieldDown').play() else: print(f'unhandled popup type: {self._popup_type}') @@ -1697,34 +1704,34 @@ def popup_menu_selected_choice(self, popup_window: PopupMenuWindow, def _vote_kick_player(self): if self._popup_party_member_is_host: - ba.playsound(ba.getsound('error')) - ba.screenmessage( - ba.Lstr(resource='internal.cantKickHostError'), + bui.getsound('error').play() + bui.screenmessage( + babase.Lstr(resource='internal.cantKickHostError'), color=(1, 0, 0)) else: assert self._popup_party_member_client_id is not None # Ban for 5 minutes. - result = _ba.disconnect_client( + result = bs.disconnect_client( self._popup_party_member_client_id, ban_time=5 * 60) if not result: - ba.playsound(ba.getsound('error')) - ba.screenmessage( - ba.Lstr(resource='getTicketsWindow.unavailableText'), + bui.getsound('error').play() + bui.screenmessage( + babase.Lstr(resource='getTicketsWindow.unavailableText'), color=(1, 0, 0)) def _send_admin_kick_command(self): - _ba.chatmessage('/kick ' + str(self._popup_party_member_client_id)) + bs.chatmessage('/kick ' + str(self._popup_party_member_client_id)) def _translate(self): def _apply_translation(translated): if self._text_field.exists(): - ba.textwidget(edit=self._text_field, text=translated) - msg = ba.textwidget(query=self._text_field) - cfg = ba.app.config + bui.textwidget(edit=self._text_field, text=translated) + msg = bui.textwidget(query=self._text_field) + cfg = babase.app.config if msg == '': - ba.screenmessage('Nothing to translate.', (1, 0, 0)) - ba.playsound(ba.getsound('error')) + bui.screenmessage('Nothing to translate.', (1, 0, 0)) + bui.getsound('error').play() else: data = dict(message=msg) if cfg['Translate Source Language']: @@ -1736,17 +1743,17 @@ def _apply_translation(translated): Translate(data, _apply_translation).start() def _copy_to_clipboard(self): - msg = ba.textwidget(query=self._text_field) + msg = bui.textwidget(query=self._text_field) if msg == '': - ba.screenmessage('Nothing to copy.', (1, 0, 0)) - ba.playsound(ba.getsound('error')) + bui.screenmessage('Nothing to copy.', (1, 0, 0)) + bui.getsound('error').play() else: - ba.clipboard_set_text(msg) - ba.screenmessage(f'"{msg}" is copied to clipboard.', (0, 1, 0)) - ba.playsound(ba.getsound('dingSmallHigh')) + babase.clipboard_set_text(msg) + bui.screenmessage(f'"{msg}" is copied to clipboard.', (0, 1, 0)) + bui.getsound('dingSmallHigh').play() def _get_current_mute_type(self): - cfg = ba.app.config + cfg = babase.app.config if cfg['Chat Muted'] == True: if cfg['Party Chat Muted'] == True: return 'muteAll' @@ -1759,7 +1766,7 @@ def _get_current_mute_type(self): return 'unmuteAll' def _change_mute_type(self, choice): - cfg = ba.app.config + cfg = babase.app.config if choice == 'muteInGameOnly': cfg['Chat Muted'] = True cfg['Party Chat Muted'] = False @@ -1779,27 +1786,26 @@ def popup_menu_closing(self, popup_window: PopupWindow) -> None: """Called when the popup is closing.""" def _on_party_member_press(self, client_id: int, is_host: bool, - widget: ba.Widget) -> None: + widget: bui.Widget) -> None: # if we're the host, pop up 'kick' options for all non-host members - if _ba.get_foreground_host_session() is not None: - kick_str = ba.Lstr(resource='kickText') + if bs.get_foreground_host_session() is not None: + kick_str = babase.Lstr(resource='kickText') else: # kick-votes appeared in build 14248 - if (_ba.get_connection_to_host_info().get('build_number', 0) < - 14248): + if build_number <14248: return - kick_str = ba.Lstr(resource='kickVoteText') - uiscale = ba.app.ui.uiscale + kick_str = babase.Lstr(resource='kickVoteText') + uiscale = bui.app.ui_v1.uiscale choices = ['kick', 'mention', 'adminkick'] choices_display = [kick_str] + \ list(self._create_baLstr_list(['Mention this guy', f'Kick ID: {client_id}'])) choices.append('customCommands') - choices_display.append(ba.Lstr(value='Custom Commands')) + choices_display.append(babase.Lstr(value='Custom Commands')) PopupMenuWindow( position=widget.get_screen_space_center(), color=self.bg_color, - scale=(2.3 if uiscale is ba.UIScale.SMALL else - 1.65 if uiscale is ba.UIScale.MEDIUM else 1.23), + scale=(2.3 if uiscale is babase.UIScale.SMALL else + 1.65 if uiscale is babase.UIScale.MEDIUM else 1.23), choices=choices, choices_display=choices_display, current_choice='mention', @@ -1809,8 +1815,8 @@ def _on_party_member_press(self, client_id: int, is_host: bool, self._popup_party_member_is_host = is_host def _send_chat_message(self) -> None: - msg = ba.textwidget(query=self._text_field) - ba.textwidget(edit=self._text_field, text='') + msg = bui.textwidget(query=self._text_field) + bui.textwidget(edit=self._text_field, text='') if '\\' in msg: msg = msg.replace('\\d', ('\ue048')) msg = msg.replace('\\c', ('\ue043')) @@ -1842,35 +1848,38 @@ def _send_chat_message(self) -> None: elif msg.startswith('/info '): account = msg.replace('/info ', '') if account: - from bastd.ui.account import viewer + from bauiv1lib.account import viewer viewer.AccountViewerWindow( account_id=account) - ba.textwidget(edit=self._text_field, text='') + bui.textwidget(edit=self._text_field, text='') return if not self._private_chat: if msg == '/id': - myid = ba.internal.get_v1_account_misc_read_val_2('resolvedAccountID', '') - _ba.chatmessage(f"My Unique ID : {myid}") + myid = bui.app.plus.get_v1_account_misc_read_val_2('resolvedAccountID', '') + bs.chatmessage(f"My Unique ID : {myid}") elif msg == '/save': - info = _ba.get_connection_to_host_info() - config = ba.app.config - if info.get('name', '') != '': - title = info['name'] - if not isinstance(config.get('Saved Servers'), dict): - config['Saved Servers'] = {} - config['Saved Servers'][f'{_ip}@{_port}'] = { - 'addr': _ip, - 'port': _port, - 'name': title - } - config.commit() - ba.screenmessage("Server Added To Manual", color=(0, 1, 0), transient=True) - ba.playsound(ba.getsound('gunCocking')) + try: + info = bs.get_connection_to_host_info().get('name', '') if build_number < 21697 else bs.get_connection_to_host_info_2().name + config = babase.app.config + if info != '': + title = info['name'] + if not isinstance(config.get('Saved Servers'), dict): + config['Saved Servers'] = {} + config['Saved Servers'][f'{_ip}@{_port}'] = { + 'addr': _ip, + 'port': _port, + 'name': title + } + config.commit() + bui.screenmessage("Server Added To Manual", color=(0, 1, 0), transient=True) + bui.getsound('gunCocking').play() + except AttributeError: + pass elif msg != '': - _ba.chatmessage(cast(str, msg)) + bs.chatmessage(cast(str, msg)) else: receiver = messenger.filter - name = ba.internal.get_v1_account_display_string() + name = bui.app.plus.get_v1_account_display_string() if not receiver: display_error('Choose a valid receiver id') return @@ -1886,22 +1895,22 @@ def _send_chat_message(self) -> None: self._change_filter('all') else: display_error('Cant delete this') - ba.textwidget(edit=self._text_field, text='') + bui.textwidget(edit=self._text_field, text='') return - ba.Call(messenger._send_request, url, data) - ba.Call(check_new_message) + babase.Call(messenger._send_request, url, data) + babase.Call(check_new_message) Thread(target=messenger._send_request, args=(url, data)).start() Thread(target=check_new_message).start() - ba.textwidget(edit=self._text_field, text='') + bui.textwidget(edit=self._text_field, text='') def _write_quick_responds(self, data): try: with open(quick_msg_file, 'w') as f: f.write('\n'.join(data)) except: - ba.print_exception() - ba.screenmessage('Error!', (1, 0, 0)) - ba.playsound(ba.getsound('error')) + babase.print_exception() + bui.screenmessage('Error!', (1, 0, 0)) + bui.getsound('error').play() def _get_quick_responds(self): if os.path.exists(quick_msg_file): @@ -1913,13 +1922,13 @@ def _get_quick_responds(self): return default_replies def color_picker_selected_color(self, picker, color) -> None: - ba.containerwidget(edit=self._root_widget, color=color) + bui.containerwidget(edit=self._root_widget, color=color) color = tuple(round(i, 2) for i in color) self.bg_color = color - ba.app.config['PartyWindow Main Color'] = color + babase.app.config['PartyWindow Main Color'] = color def color_picker_closing(self, picker) -> None: - ba.app.config.apply_and_commit() + babase.app.config.apply_and_commit() def _remove_sender_from_message(self, msg=''): msg_start = msg.find(": ") + 2 @@ -1936,7 +1945,7 @@ def _previous_message(self): del self.msg_index try: msg_widget = msgs[self.msg_index] - msg = ba.textwidget(query=msg_widget) + msg = bui.textwidget(query=msg_widget) msg = self._remove_sender_from_message(msg) if msg in ('', ' '): self._previous_message() @@ -1956,7 +1965,7 @@ def _next_message(self): del self.msg_index try: msg_widget = msgs[self.msg_index] - msg = ba.textwidget(query=msg_widget) + msg = bui.textwidget(query=msg_widget) msg = self._remove_sender_from_message(msg) if msg in ('', ' '): self._next_message() @@ -1973,10 +1982,13 @@ def _ip_port_msg(self): self._edit_text_msg_box(msg, 'replace') def ping_server(self): - info = _ba.get_connection_to_host_info() - if info.get('name', '') != '': - self.pingThread = PingThread(_ip, _port) - self.pingThread.start() + try: + info = bs.get_connection_to_host_info().get('name', '') if build_number < 21697 else bs.get_connection_to_host_info_2().name + if info != '': + self.pingThread = PingThread(_ip, _port) + self.pingThread.start() + except AttributeError: + pass def _get_ping_color(self): try: @@ -1991,28 +2003,28 @@ def _get_ping_color(self): def _send_ping(self): if isinstance(_ping, int): - _ba.chatmessage(f'My ping = {_ping}ms') + bs.chatmessage(f'My ping = {_ping}ms') def close(self) -> None: """Close the window.""" - ba.containerwidget(edit=self._root_widget, transition='out_scale') + bui.containerwidget(edit=self._root_widget, transition='out_scale') def close_with_sound(self) -> None: """Close the window and make a lovely sound.""" - ba.playsound(ba.getsound('swish')) + bui.getsound('swish').play() self.close() def _get_popup_window_scale(self) -> float: - uiscale = ba.app.ui.uiscale - return (2.4 if uiscale is ba.UIScale.SMALL else - 1.5 if uiscale is ba.UIScale.MEDIUM else 1.0) + uiscale = bui.app.ui_v1.uiscale + return (2.4 if uiscale is babase.UIScale.SMALL else + 1.5 if uiscale is babase.UIScale.MEDIUM else 1.0) def _create_baLstr_list(self, list1): - return (ba.Lstr(value=i) for i in list1) + return (babase.Lstr(value=i) for i in list1) def _get_player_info(self, clientID): info = {} - for i in _ba.get_game_roster(): + for i in bs.get_game_roster(): if i['client_id'] == clientID: info['ds'] = i['display_string'] info['players'] = i['players'] @@ -2023,16 +2035,16 @@ def _get_player_info(self, clientID): def _edit_text_msg_box(self, text, action='add'): if isinstance(text, str): if action == 'add': - ba.textwidget(edit=self._text_field, text=ba.textwidget( + bui.textwidget(edit=self._text_field, text=bui.textwidget( query=self._text_field) + text) elif action == 'replace': - ba.textwidget(edit=self._text_field, text=text) + bui.textwidget(edit=self._text_field, text=text) def _on_setting_button_press(self): try: SettingsWindow() except Exception as e: - ba.print_exception() + babase.print_exception() pass def _on_privatechat_button_press(self): @@ -2060,11 +2072,11 @@ def _on_privatechat_button_press(self): else: display_error(messenger.error) except Exception as e: - ba.print_exception() + babase.print_exception() pass def join_discord(self): - ba.open_url("https://discord.gg/KvYgpEg2JR") + bui.open_url("https://discord.gg/KvYgpEg2JR") class LoginWindow: @@ -2076,19 +2088,19 @@ def __init__(self, wtype): else: title = 'Login Window' label = 'Log In' - uiscale = ba.app.ui.uiscale - bg_color = ba.app.config.get('PartyWindow Main Color', (0.5, 0.5, 0.5)) - self._root_widget = ba.containerwidget(size=(500, 250), + uiscale = bui.app.ui_v1.uiscale + bg_color = babase.app.config.get('PartyWindow Main Color', (0.5, 0.5, 0.5)) + self._root_widget = bui.containerwidget(size=(500, 250), transition='in_scale', color=bg_color, toolbar_visibility='menu_minimal_no_back', - parent=_ba.get_special_widget('overlay_stack'), + parent=bui.get_special_widget('overlay_stack'), on_outside_click_call=self._close, - scale=(2.1 if uiscale is ba.UIScale.SMALL else - 1.5 if uiscale is ba.UIScale.MEDIUM else 1.0), - stack_offset=(0, -10) if uiscale is ba.UIScale.SMALL else ( - 240, 0) if uiscale is ba.UIScale.MEDIUM else (330, 20)) - self._title_text = ba.textwidget(parent=self._root_widget, + scale=(2.1 if uiscale is babase.UIScale.SMALL else + 1.5 if uiscale is babase.UIScale.MEDIUM else 1.0), + stack_offset=(0, -10) if uiscale is babase.UIScale.SMALL else ( + 240, 0) if uiscale is babase.UIScale.MEDIUM else (330, 20)) + self._title_text = bui.textwidget(parent=self._root_widget, scale=0.8, color=(1, 1, 1), text=title, @@ -2096,17 +2108,17 @@ def __init__(self, wtype): position=(250, 200), h_align='center', v_align='center') - self._id = ba.textwidget(parent=self._root_widget, + self._id = bui.textwidget(parent=self._root_widget, scale=0.5, color=(1, 1, 1), text=f'Account: ' + - ba.internal.get_v1_account_misc_read_val_2( + bui.app.plus.get_v1_account_misc_read_val_2( 'resolvedAccountID', ''), size=(0, 0), position=(220, 170), h_align='center', v_align='center') - self._registrationkey_text = ba.textwidget(parent=self._root_widget, + self._registrationkey_text = bui.textwidget(parent=self._root_widget, scale=0.5, color=(1, 1, 1), text=f'Registration Key:', @@ -2114,7 +2126,7 @@ def __init__(self, wtype): position=(100, 140), h_align='center', v_align='center') - self._text_field = ba.textwidget( + self._text_field = bui.textwidget( parent=self._root_widget, editable=True, size=(200, 40), @@ -2125,7 +2137,7 @@ def __init__(self, wtype): autoselect=True, v_align='center', corner_scale=0.7) - self._connect_button = ba.buttonwidget(parent=self._root_widget, + self._connect_button = bui.buttonwidget(parent=self._root_widget, size=(150, 30), color=(0, 1, 0), label='Get Registration Key', @@ -2133,17 +2145,17 @@ def __init__(self, wtype): autoselect=True, position=(150, 80), on_activate_call=self._connect) - self._confirm_button = ba.buttonwidget(parent=self._root_widget, + self._confirm_button = bui.buttonwidget(parent=self._root_widget, size=(50, 30), label=label, button_type='square', autoselect=True, position=(200, 40), on_activate_call=self._confirmcall) - ba.textwidget(edit=self._text_field, on_return_press_call=self._confirm_button.activate) + bui.textwidget(edit=self._text_field, on_return_press_call=self._confirm_button.activate) def _close(self): - ba.containerwidget(edit=self._root_widget, + bui.containerwidget(edit=self._root_widget, transition=('out_scale')) def _connect(self): @@ -2151,35 +2163,35 @@ def _connect(self): host = url.split('http://')[1].split(':')[0] import socket address = socket.gethostbyname(host) - _ba.disconnect_from_host() - _ba.connect_to_party(address, port=11111) + bs.disconnect_from_host() + bs.connect_to_party(address, port=11111) except Exception: display_error('Cant get ip from hostname') def _confirmcall(self): if self.wtype == 'signup': - key = ba.textwidget(query=self._text_field) + key = bui.textwidget(query=self._text_field) answer = messenger._signup(registration_key=key) if key else None if answer: self._close() else: - if messenger._login(registration_key=ba.textwidget(query=self._text_field)): + if messenger._login(registration_key=bui.textwidget(query=self._text_field)): self._close() class AddNewIdWindow: def __init__(self): - uiscale = ba.app.ui.uiscale - bg_color = ba.app.config.get('PartyWindow Main Color', (0.5, 0.5, 0.5)) - self._root_widget = ba.containerwidget(size=(500, 250), + uiscale = bui.app.ui_v1.uiscale + bg_color = babase.app.config.get('PartyWindow Main Color', (0.5, 0.5, 0.5)) + self._root_widget = bui.containerwidget(size=(500, 250), transition='in_scale', color=bg_color, toolbar_visibility='menu_minimal_no_back', - parent=_ba.get_special_widget('overlay_stack'), + parent=bui.get_special_widget('overlay_stack'), on_outside_click_call=self._close, - scale=(2.1 if uiscale is ba.UIScale.SMALL else - 1.5 if uiscale is ba.UIScale.MEDIUM else 1.0)) - self._title_text = ba.textwidget(parent=self._root_widget, + scale=(2.1 if uiscale is babase.UIScale.SMALL else + 1.5 if uiscale is babase.UIScale.MEDIUM else 1.0)) + self._title_text = bui.textwidget(parent=self._root_widget, scale=0.8, color=(1, 1, 1), text='Add New ID', @@ -2187,7 +2199,7 @@ def __init__(self): position=(250, 200), h_align='center', v_align='center') - self._accountid_text = ba.textwidget(parent=self._root_widget, + self._accountid_text = bui.textwidget(parent=self._root_widget, scale=0.6, color=(1, 1, 1), text='pb-id: ', @@ -2195,7 +2207,7 @@ def __init__(self): position=(50, 155), h_align='center', v_align='center') - self._accountid_field = ba.textwidget( + self._accountid_field = bui.textwidget( parent=self._root_widget, editable=True, size=(250, 40), @@ -2206,7 +2218,7 @@ def __init__(self): autoselect=True, v_align='center', corner_scale=0.7) - self._nickname_text = ba.textwidget(parent=self._root_widget, + self._nickname_text = bui.textwidget(parent=self._root_widget, scale=0.5, color=(1, 1, 1), text='Nickname: ', @@ -2214,7 +2226,7 @@ def __init__(self): position=(50, 115), h_align='center', v_align='center') - self._nickname_field = ba.textwidget( + self._nickname_field = bui.textwidget( parent=self._root_widget, editable=True, size=(250, 40), @@ -2225,7 +2237,7 @@ def __init__(self): autoselect=True, v_align='center', corner_scale=0.7) - self._help_text = ba.textwidget(parent=self._root_widget, + self._help_text = bui.textwidget(parent=self._root_widget, scale=0.4, color=(0.1, 0.9, 0.9), text='Help:\nEnter pb-id of account you\n want to chat to\nEnter nickname of id to\n recognize id easily\nLeave nickname \n to use their default name', @@ -2233,27 +2245,27 @@ def __init__(self): position=(325, 120), h_align='left', v_align='center') - self._add = ba.buttonwidget(parent=self._root_widget, + self._add = bui.buttonwidget(parent=self._root_widget, size=(50, 30), label='Add', button_type='square', autoselect=True, position=(100, 50), - on_activate_call=ba.Call(self._relay_function)) - ba.textwidget(edit=self._accountid_field, on_return_press_call=self._add.activate) - self._remove = ba.buttonwidget(parent=self._root_widget, + on_activate_call=babase.Call(self._relay_function)) + bui.textwidget(edit=self._accountid_field, on_return_press_call=self._add.activate) + self._remove = bui.buttonwidget(parent=self._root_widget, size=(75, 30), label='Remove', button_type='square', autoselect=True, position=(170, 50), on_activate_call=self._remove_id) - ba.containerwidget(edit=self._root_widget, + bui.containerwidget(edit=self._root_widget, on_cancel_call=self._close) def _relay_function(self): - account_id = ba.textwidget(query=self._accountid_field) - nickname = ba.textwidget(query=self._nickname_field) + account_id = bui.textwidget(query=self._accountid_field) + nickname = bui.textwidget(query=self._nickname_field) try: if messenger._save_id(account_id, nickname): self._close() @@ -2261,15 +2273,15 @@ def _relay_function(self): display_error('Enter valid pb-id') def _remove_id(self): - uiscale = ba.app.ui.uiscale + uiscale = bui.app.ui_v1.uiscale if len(messenger.saved_ids) > 1: choices = [i for i in messenger.saved_ids] choices.remove('all') - choices_display = [ba.Lstr(value=messenger.saved_ids[i]) for i in choices] + choices_display = [babase.Lstr(value=messenger.saved_ids[i]) for i in choices] PopupMenuWindow(position=self._remove.get_screen_space_center(), - color=ba.app.config.get('PartyWindow Main Color', (0.5, 0.5, 0.5)), - scale=(2.4 if uiscale is ba.UIScale.SMALL else - 1.5 if uiscale is ba.UIScale.MEDIUM else 1.0), + color=babase.app.config.get('PartyWindow Main Color', (0.5, 0.5, 0.5)), + scale=(2.4 if uiscale is babase.UIScale.SMALL else + 1.5 if uiscale is babase.UIScale.MEDIUM else 1.0), choices=choices, choices_display=choices_display, current_choice=choices[0], @@ -2287,25 +2299,25 @@ def popup_menu_closing(self, popup_window: PopupWindow) -> None: """Called when the popup is closing.""" def _close(self): - ba.containerwidget(edit=self._root_widget, + bui.containerwidget(edit=self._root_widget, transition=('out_scale')) class AddNewChoiceWindow: def __init__(self): - uiscale = ba.app.ui.uiscale - bg_color = ba.app.config.get('PartyWindow Main Color', (0.5, 0.5, 0.5)) - self._root_widget = ba.containerwidget(size=(500, 250), + uiscale = bui.app.ui_v1.uiscale + bg_color = babase.app.config.get('PartyWindow Main Color', (0.5, 0.5, 0.5)) + self._root_widget = bui.containerwidget(size=(500, 250), transition='in_scale', color=bg_color, toolbar_visibility='menu_minimal_no_back', - parent=_ba.get_special_widget('overlay_stack'), + parent=bui.get_special_widget('overlay_stack'), on_outside_click_call=self._close, - scale=(2.1 if uiscale is ba.UIScale.SMALL else - 1.5 if uiscale is ba.UIScale.MEDIUM else 1.0), - stack_offset=(0, -10) if uiscale is ba.UIScale.SMALL else ( - 240, 0) if uiscale is ba.UIScale.MEDIUM else (330, 20)) - self._title_text = ba.textwidget(parent=self._root_widget, + scale=(2.1 if uiscale is babase.UIScale.SMALL else + 1.5 if uiscale is babase.UIScale.MEDIUM else 1.0), + stack_offset=(0, -10) if uiscale is babase.UIScale.SMALL else ( + 240, 0) if uiscale is babase.UIScale.MEDIUM else (330, 20)) + self._title_text = bui.textwidget(parent=self._root_widget, scale=0.8, color=(1, 1, 1), text='Add Custom Command', @@ -2313,7 +2325,7 @@ def __init__(self): position=(250, 200), h_align='center', v_align='center') - self._text_field = ba.textwidget( + self._text_field = bui.textwidget( parent=self._root_widget, editable=True, size=(500, 40), @@ -2324,7 +2336,7 @@ def __init__(self): autoselect=True, v_align='center', corner_scale=0.7) - self._help_text = ba.textwidget(parent=self._root_widget, + self._help_text = bui.textwidget(parent=self._root_widget, scale=0.4, color=(0.2, 0.2, 0.2), text='Use\n$c = client id\n$a = account id\n$n = name', @@ -2332,44 +2344,44 @@ def __init__(self): position=(70, 75), h_align='left', v_align='center') - self._add = ba.buttonwidget(parent=self._root_widget, + self._add = bui.buttonwidget(parent=self._root_widget, size=(50, 30), label='Add', button_type='square', autoselect=True, position=(150, 50), on_activate_call=self._add_choice) - ba.textwidget(edit=self._text_field, on_return_press_call=self._add.activate) - self._remove = ba.buttonwidget(parent=self._root_widget, + bui.textwidget(edit=self._text_field, on_return_press_call=self._add.activate) + self._remove = bui.buttonwidget(parent=self._root_widget, size=(50, 30), label='Remove', button_type='square', autoselect=True, position=(350, 50), on_activate_call=self._remove_custom_command) - ba.containerwidget(edit=self._root_widget, + bui.containerwidget(edit=self._root_widget, on_cancel_call=self._close) def _add_choice(self): - newCommand = ba.textwidget(query=self._text_field) - cfg = ba.app.config + newCommand = bui.textwidget(query=self._text_field) + cfg = babase.app.config if any(i in newCommand for i in ('$c', '$a', '$n')): cfg['Custom Commands'].append(newCommand) cfg.apply_and_commit() - ba.screenmessage('Added successfully', (0, 1, 0)) - ba.playsound(ba.getsound('dingSmallHigh')) + bui.screenmessage('Added successfully', (0, 1, 0)) + bui.getsound('dingSmallHigh').play() self._close() else: - ba.screenmessage('Use at least of these ($c, $a, $n)', (1, 0, 0)) - ba.playsound(ba.getsound('error')) + bui.screenmessage('Use at least of these ($c, $a, $n)', (1, 0, 0)) + bui.getsound('error').play() def _remove_custom_command(self): - uiscale = ba.app.ui.uiscale - commands = ba.app.config['Custom Commands'] + uiscale = bui.app.ui_v1.uiscale + commands = babase.app.config['Custom Commands'] PopupMenuWindow(position=self._remove.get_screen_space_center(), - color=ba.app.config.get('PartyWindow Main Color', (0.5, 0.5, 0.5)), - scale=(2.4 if uiscale is ba.UIScale.SMALL else - 1.5 if uiscale is ba.UIScale.MEDIUM else 1.0), + color=babase.app.config.get('PartyWindow Main Color', (0.5, 0.5, 0.5)), + scale=(2.4 if uiscale is babase.UIScale.SMALL else + 1.5 if uiscale is babase.UIScale.MEDIUM else 1.0), choices=commands, current_choice=commands[0], delegate=self) @@ -2379,27 +2391,27 @@ def popup_menu_selected_choice(self, popup_window: PopupMenuWindow, choice: str) -> None: """Called when a choice is selected in the popup.""" if self._popup_type == 'removeCustomCommandSelect': - config = ba.app.config + config = babase.app.config config['Custom Commands'].remove(choice) config.apply_and_commit() - ba.screenmessage('Removed successfully', (0, 1, 0)) - ba.playsound(ba.getsound('shieldDown')) + bui.screenmessage('Removed successfully', (0, 1, 0)) + bui.getsound('shieldDown').play() def popup_menu_closing(self, popup_window: PopupWindow) -> None: """Called when the popup is closing.""" def _close(self): - ba.containerwidget(edit=self._root_widget, + bui.containerwidget(edit=self._root_widget, transition=('out_scale')) class Manual_camera_window: def __init__(self): - self._root_widget = ba.containerwidget( + self._root_widget = bui.containerwidget( on_outside_click_call=None, size=(0, 0)) button_size = (30, 30) - self._title_text = ba.textwidget(parent=self._root_widget, + self._title_text = bui.textwidget(parent=self._root_widget, scale=0.9, color=(1, 1, 1), text='Manual Camera Setup', @@ -2407,49 +2419,49 @@ def __init__(self): position=(130, 153), h_align='center', v_align='center') - self._xminus = ba.buttonwidget(parent=self._root_widget, + self._xminus = bui.buttonwidget(parent=self._root_widget, size=button_size, - label=ba.charstr(ba.SpecialChar.LEFT_ARROW), + label=babase.charstr(babase.SpecialChar.LEFT_ARROW), button_type='square', autoselect=True, position=(1, 60), - on_activate_call=ba.Call(self._change_camera_position, 'x-')) - self._xplus = ba.buttonwidget(parent=self._root_widget, + on_activate_call=babase.Call(self._change_camera_position, 'x-')) + self._xplus = bui.buttonwidget(parent=self._root_widget, size=button_size, - label=ba.charstr(ba.SpecialChar.RIGHT_ARROW), + label=babase.charstr(babase.SpecialChar.RIGHT_ARROW), button_type='square', autoselect=True, position=(60, 60), - on_activate_call=ba.Call(self._change_camera_position, 'x')) - self._yplus = ba.buttonwidget(parent=self._root_widget, + on_activate_call=babase.Call(self._change_camera_position, 'x')) + self._yplus = bui.buttonwidget(parent=self._root_widget, size=button_size, - label=ba.charstr(ba.SpecialChar.UP_ARROW), + label=babase.charstr(babase.SpecialChar.UP_ARROW), button_type='square', autoselect=True, position=(30, 100), - on_activate_call=ba.Call(self._change_camera_position, 'y')) - self._yminus = ba.buttonwidget(parent=self._root_widget, + on_activate_call=babase.Call(self._change_camera_position, 'y')) + self._yminus = bui.buttonwidget(parent=self._root_widget, size=button_size, - label=ba.charstr(ba.SpecialChar.DOWN_ARROW), + label=babase.charstr(babase.SpecialChar.DOWN_ARROW), button_type='square', autoselect=True, position=(30, 20), - on_activate_call=ba.Call(self._change_camera_position, 'y-')) - self.inwards = ba.buttonwidget(parent=self._root_widget, + on_activate_call=babase.Call(self._change_camera_position, 'y-')) + self.inwards = bui.buttonwidget(parent=self._root_widget, size=(100, 30), label='INWARDS', button_type='square', autoselect=True, position=(120, 90), - on_activate_call=ba.Call(self._change_camera_position, 'z-')) - self._outwards = ba.buttonwidget(parent=self._root_widget, + on_activate_call=babase.Call(self._change_camera_position, 'z-')) + self._outwards = bui.buttonwidget(parent=self._root_widget, size=(100, 30), label='OUTWARDS', button_type='square', autoselect=True, position=(120, 50), - on_activate_call=ba.Call(self._change_camera_position, 'z')) - self._step_text = ba.textwidget(parent=self._root_widget, + on_activate_call=babase.Call(self._change_camera_position, 'z')) + self._step_text = bui.textwidget(parent=self._root_widget, scale=0.5, color=(1, 1, 1), text='Step:', @@ -2457,7 +2469,7 @@ def __init__(self): position=(1, -20), h_align='center', v_align='center') - self._text_field = ba.textwidget( + self._text_field = bui.textwidget( parent=self._root_widget, editable=True, size=(100, 40), @@ -2468,29 +2480,29 @@ def __init__(self): autoselect=True, v_align='center', corner_scale=0.7) - self._reset = ba.buttonwidget(parent=self._root_widget, + self._reset = bui.buttonwidget(parent=self._root_widget, size=(50, 30), label='Reset', button_type='square', autoselect=True, position=(120, -35), - on_activate_call=ba.Call(self._change_camera_position, 'reset')) - self._done = ba.buttonwidget(parent=self._root_widget, + on_activate_call=babase.Call(self._change_camera_position, 'reset')) + self._done = bui.buttonwidget(parent=self._root_widget, size=(50, 30), label='Done', button_type='square', autoselect=True, position=(180, -35), on_activate_call=self._close) - ba.containerwidget(edit=self._root_widget, + bui.containerwidget(edit=self._root_widget, cancel_button=self._done) def _close(self): - ba.containerwidget(edit=self._root_widget, + bui.containerwidget(edit=self._root_widget, transition=('out_scale')) def _change_camera_position(self, direction): - activity = _ba.get_foreground_host_activity() + activity = bs.get_foreground_host_activity() node = activity.globalsnode aoi = list(node.area_of_interest_bounds) center = [(aoi[0] + aoi[3]) / 2, @@ -2501,9 +2513,9 @@ def _change_camera_position(self, direction): aoi[5] - aoi[2]) try: - increment = float(ba.textwidget(query=self._text_field)) + increment = float(bui.textwidget(query=self._text_field)) except: - # ba.print_exception() + # babase.print_exception() increment = 1 if direction == 'x': @@ -2542,7 +2554,7 @@ def __popup_menu_window_init__(self, scale: float = 1.0, color: Tuple[float, float, float] = (0.35, 0.55, 0.15), choices_disabled: Sequence[str] = None, - choices_display: Sequence[ba.Lstr] = None): + choices_display: Sequence[babase.Lstr] = None): # FIXME: Clean up a bit. # pylint: disable=too-many-branches # pylint: disable=too-many-locals @@ -2591,14 +2603,14 @@ def __popup_menu_window_init__(self, self._width, min( maxwidth, - _ba.get_string_width(choice_display_name, + _babase.get_string_width(choice_display_name, suppress_warning=True)) + 75) else: self._width = max( self._width, min( maxwidth, - _ba.get_string_width(choice_display_name, + _babase.get_string_width(choice_display_name, suppress_warning=True)) + 60) # init parent class - this will rescale and reposition things as @@ -2610,22 +2622,22 @@ def __popup_menu_window_init__(self, scale=self._scale) if self._use_scroll: - self._scrollwidget = ba.scrollwidget(parent=self.root_widget, + self._scrollwidget = bui.scrollwidget(parent=self.root_widget, position=(20, 20), highlight=False, color=(0.35, 0.55, 0.15), size=(self._width - 40, self._height - 40)) - self._columnwidget = ba.columnwidget(parent=self._scrollwidget, + self._columnwidget = bui.columnwidget(parent=self._scrollwidget, border=2, margin=0) else: - self._offset_widget = ba.containerwidget(parent=self.root_widget, + self._offset_widget = bui.containerwidget(parent=self.root_widget, position=(30, 15), size=(self._width - 40, self._height), background=False) - self._columnwidget = ba.columnwidget(parent=self._offset_widget, + self._columnwidget = bui.columnwidget(parent=self._offset_widget, border=2, margin=0) for index, choice in enumerate(choices): @@ -2634,9 +2646,9 @@ def __popup_menu_window_init__(self, else: choice_display_name = choice inactive = (choice in self._choices_disabled) - wdg = ba.textwidget(parent=self._columnwidget, + wdg = bui.textwidget(parent=self._columnwidget, size=(self._width - 40, 28), - on_select_call=ba.Call(self._select, index), + on_select_call=babase.Call(self._select, index), click_activate=True, color=(0.5, 0.5, 0.5, 0.5) if inactive else ((0.5, 1, 0.5, @@ -2649,7 +2661,7 @@ def __popup_menu_window_init__(self, v_align='center', selectable=(not inactive)) if choice == self._current_choice: - ba.containerwidget(edit=self._columnwidget, + bui.containerwidget(edit=self._columnwidget, selected_child=wdg, visible_child=wdg) @@ -2658,8 +2670,8 @@ def __popup_menu_window_init__(self, self._done_building = True -original_connect_to_party = _ba.connect_to_party -original_sign_in = ba.internal.sign_in_v1 +original_connect_to_party = bs.connect_to_party +original_sign_in = babase.app.plus.sign_in_v1 def modify_connect_to_party(address: str, port: int = 43210, print_progress: bool = True) -> None: @@ -2677,7 +2689,7 @@ def modify_sign_in(account_type: str) -> None: if messenger.server_online: messenger.logged_in = False global temptimer - temptimer = ba.Timer(2, messenger._cookie_login) + temptimer = bs.Timer(2, messenger._cookie_login) class PingThread(Thread): @@ -2692,7 +2704,7 @@ def run(self) -> None: sock: Optional[socket.socket] = None try: import socket - from ba.internal import get_ip_address_type + from babase._net import get_ip_address_type socket_type = get_ip_address_type(self._address) sock = socket.socket(socket_type, socket.SOCK_DGRAM) sock.connect((self._address, self._port)) @@ -2718,38 +2730,43 @@ def run(self) -> None: global _ping _ping = int((time.time() - starttime) * 1000.0) except Exception: - ba.print_exception('Error on gather ping', once=True) + babase.print_exception('Error on gather ping', once=True) finally: try: if sock is not None: sock.close() except Exception: - ba.print_exception('Error on gather ping cleanup', once=True) + babase.print_exception('Error on gather ping cleanup', once=True) def _get_store_char_tex(self) -> str: - _ba.set_party_icon_always_visible(True) - return ('storeCharacterXmas' if ba.internal.get_v1_account_misc_read_val( + return ('storeCharacterXmas' if bui.app.plus.get_v1_account_misc_read_val( 'xmas', False) else - 'storeCharacterEaster' if ba.internal.get_v1_account_misc_read_val( + 'storeCharacterEaster' if bui.app.plus.get_v1_account_misc_read_val( 'easter', False) else 'storeCharacter') +class NewMainMenuWindow(mainmenu.MainMenuWindow): + def __init__(self, *args, **kwargs): + super().__init__(*args, **kwargs) + # Display chat icon, but if user open/close gather it may disappear + bui.set_party_icon_always_visible(True) # ba_meta export plugin -class InitalRun(ba.Plugin): +class InitalRun(babase.Plugin): def __init__(self): - if _ba.env().get("build_number", 0) >= 20124: + if build_number >= 21140: global messenger, listener, displayer, color_tracker initialize() messenger = PrivateChatHandler() listener = Thread(target=messenger_thread) listener.start() - displayer = ba.Timer(0.4, msg_displayer, True) + displayer = bs.AppTimer(0.4, msg_displayer, repeat=True) color_tracker = ColorTracker() - bastd.ui.party.PartyWindow = PartyWindow + bauiv1lib.party.PartyWindow = PartyWindow + mainmenu.MainMenuWindow = NewMainMenuWindow PopupMenuWindow.__init__ = __popup_menu_window_init__ - _ba.connect_to_party = modify_connect_to_party - ba.internal.sign_in_v1 = modify_sign_in + bs.connect_to_party = modify_connect_to_party + babase.app.plus.sign_in_v1 = modify_sign_in MainMenuWindow._get_store_char_tex = _get_store_char_tex else: - display_error("This Party Window only runs with BombSquad version higer than 1.6.0.") + display_error("This Party Window only runs with BombSquad version higer than 1.7.19.") From 1bce1d7d76018f971215988a7b217ad7865b6d23 Mon Sep 17 00:00:00 2001 From: brostosjoined Date: Tue, 16 Jan 2024 15:16:56 +0300 Subject: [PATCH 0798/1464] Update discord names --- plugins/utilities.json | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/plugins/utilities.json b/plugins/utilities.json index 433adf4d..cccabfad 100644 --- a/plugins/utilities.json +++ b/plugins/utilities.json @@ -15,7 +15,7 @@ { "name": "LoupGarou", "email": "LoupGarou5418@outlook.com", - "discord": "ʟօʊքɢǟʀօʊ#3063" + "discord": "loupgarou_" } ], "versions": { @@ -35,7 +35,7 @@ { "name": "Droopy", "email": "", - "discord": "Droopy#3730" + "discord": "droopy25" } ], "versions": { @@ -54,7 +54,7 @@ { "name": "LoupGarou", "email": "LoupGarou5418@outlook.com", - "discord": "ʟօʊքɢǟʀօʊ#3063" + "discord": "loupgarou_" } ], "versions": { @@ -103,7 +103,7 @@ { "name": "JoseAng3l", "email": "", - "discord": "! JoseANG3L#0268" + "discord": "joseang3l" } ], "versions": { @@ -123,7 +123,7 @@ { "name": "JoseAng3l", "email": "", - "discord": "! JoseANG3L#0268" + "discord": "joseang3l" } ], "versions": { @@ -143,7 +143,7 @@ { "name": "JoseAng3l", "email": "", - "discord": "! JoseANG3L#0268" + "discord": "joseang3l" } ], "versions": { @@ -162,7 +162,7 @@ { "name": "JoseAng3l", "email": "", - "discord": "! JoseANG3L#0268" + "discord": "joseang3l" } ], "versions": { @@ -207,7 +207,7 @@ { "name": "LoupGarou", "email": "LoupGarou5418@outlook.com", - "discord": "ʟօʊքɢǟʀօʊ#3063" + "discord": "loupgarou_" } ], "versions": { @@ -250,7 +250,7 @@ { "name": "Vishal", "email": "vishal.u338@gmail.com", - "discord": "𝑽𝑰𝑺𝑯𝑼𝑼𝑼#2921" + "discord": "vishal3308" } ], "versions": { @@ -672,7 +672,7 @@ { "name": "Droopy", "email": "", - "discord": "Droopy#3730" + "discord": "droopy25" } ], "versions": { From 4719c3e7180cdf6db7e2fef01a89f9cb4ac7d7c3 Mon Sep 17 00:00:00 2001 From: brostosjoined Date: Wed, 17 Jan 2024 23:09:18 +0300 Subject: [PATCH 0799/1464] Needs some testing --- plugins/maps/forest.py | 6 +- plugins/minigames.json | 50 ++- plugins/minigames/air_soccer.py | 213 +++++----- plugins/minigames/basket_bomb.py | 231 +++++------ plugins/minigames/castel_queen.py | 133 +++---- plugins/minigames/drone_war.py | 139 +++---- plugins/minigames/hot_potato.py | 222 +++++------ plugins/minigames/invisible_one.py | 133 +++---- plugins/minigames/last_punch_stand.py | 73 ++-- plugins/minigames/meteor_shower.py | 111 +++--- plugins/minigames/port_7_to_8.py | 441 +++++++++++++++++++++ plugins/minigames/quake.py | 221 +++++------ plugins/minigames/shimla.py | 146 +++---- plugins/minigames/simon_says.py | 110 +++--- plugins/minigames/sleep_race.py | 247 ++++++------ plugins/minigames/snake.py | 91 ++--- plugins/minigames/squid_race.py | 309 +++++++-------- plugins/minigames/the_spaz_game.py | 47 +-- plugins/minigames/ufo_fight.py | 453 +++++++++++----------- plugins/minigames/ultimate_last_stand.py | 139 +++---- plugins/minigames/zombie_horde.py | 229 +++++------ plugins/utilities/discord_richpresence.py | 6 +- plugins/utilities/ragdoll_b_gone.py | 2 +- 23 files changed, 2125 insertions(+), 1627 deletions(-) create mode 100644 plugins/minigames/port_7_to_8.py diff --git a/plugins/maps/forest.py b/plugins/maps/forest.py index c9f04be6..4ccf2b62 100644 --- a/plugins/maps/forest.py +++ b/plugins/maps/forest.py @@ -68,10 +68,10 @@ def get_preview_texture_name(cls) -> list[str]: def on_preload(cls) -> any: data: dict[str, any] = { 'mesh': bs.getmesh('natureBackground'), - 'tex': bui.gettexture('natureBackgroundColor'), + 'tex': bs.gettexture('natureBackgroundColor'), 'collision_mesh': bs.getcollisionmesh('natureBackgroundCollide'), 'bgmesh': bs.getmesh('thePadBG'), - 'bgtex': bui.gettexture('menuBG') + 'bgtex': bs.gettexture('menuBG') } return data @@ -85,7 +85,7 @@ def __init__(self) -> None: attrs={ 'mesh': self.preloaddata['mesh'], 'color_texture': self.preloaddata['tex'], - 'collide_mesh': self.preloaddata['collide_mesh'], + 'collision_mesh': self.preloaddata['collision_mesh'], 'materials': [shared.footing_material] } ) diff --git a/plugins/minigames.json b/plugins/minigames.json index e803bce3..e3ad0927 100644 --- a/plugins/minigames.json +++ b/plugins/minigames.json @@ -77,6 +77,7 @@ } ], "versions": { + "1.0.1": null, "1.0.0": { "api_version": 7, "commit_sha": "2fda676", @@ -92,10 +93,11 @@ { "name": "JoseAng3l", "email": "", - "discord": "! JoseANG3L#0268" + "discord": "joseang3l" } ], "versions": { + "1.0.1": null, "1.0.0": { "api_version": 7, "commit_sha": "2fda676", @@ -111,10 +113,11 @@ { "name": "JoseAng3l", "email": "", - "discord": "! JoseANG3L#0268" + "discord": "joseang3l" } ], "versions": { + "1.0.1": null, "1.0.0": { "api_version": 7, "commit_sha": "2fda676", @@ -130,10 +133,11 @@ { "name": "JoseAng3l", "email": "", - "discord": "! JoseANG3L#0268" + "discord": "joseang3l" } ], "versions": { + "1.0.1": null, "1.0.0": { "api_version": 7, "commit_sha": "2fda676", @@ -149,7 +153,7 @@ { "name": "JoseAng3l", "email": "", - "discord": "! JoseANG3L#0268" + "discord": "joseang3l" } ], "versions": { @@ -178,6 +182,7 @@ } ], "versions": { + "1.1.0": null, "1.0.1": { "api_version": 7, "commit_sha": "d511c15", @@ -199,10 +204,11 @@ { "name": "Cross Joy", "email": "cross.joy.official@gmail.com", - "discord": "Cross Joy#0721" + "discord": "crossjoy" } ], "versions": { + "1.0.0": null, "2.0.0": { "api_version": 7, "commit_sha": "8b257b3", @@ -328,6 +334,7 @@ } ], "versions": { + "1.0.1": null, "1.0.0": { "api_version": 7, "commit_sha": "0841b9e", @@ -343,7 +350,7 @@ { "name": "SEBASTIAN2059", "email": "", - "discord": "SEBASTIAN2059#5751" + "discord": "sebastian2059" }, { "name": "zPanxo", @@ -373,10 +380,11 @@ { "name": "Mr.Smoothy", "email": "smoothy@bombsquad.ga", - "discord": "mr.smoothy#5824" + "discord": "mr.smoothy" } ], "versions": { + "1.0.1": null, "1.0.0": { "api_version": 7, "commit_sha": "52094fc", @@ -392,7 +400,7 @@ { "name": "Mr.Smoothy", "email": "smoothy@bombsquad.ga", - "discord": "mr.smoothy#5824" + "discord": "mr.smoothy" } ], "versions": { @@ -417,10 +425,11 @@ { "name": "Mr.Smoothy", "email": "smoothy@bombsquad.ga", - "discord": "mr.smoothy#5824" + "discord": "mr.smoothy" } ], "versions": { + "1.0.1": null, "1.0.0": { "api_version": 7, "commit_sha": "2aa1e50", @@ -436,7 +445,7 @@ { "name": "Mr.Smoothy", "email": "smoothy@bombsquad.ga", - "discord": "mr.smoothy#5824" + "discord": "mr.smoothy" } ], "versions": { @@ -455,10 +464,11 @@ { "name": "Mr.Smoothy", "email": "smoothy@bombsquad.ga", - "discord": "mr.smoothy#5824" + "discord": "mr.smoothy" } ], "versions": { + "1.0.1": null, "1.0.0": { "api_version": 7, "commit_sha": "2aa1e50", @@ -474,10 +484,11 @@ { "name": "Mr.Smoothy", "email": "smoothy@bombsquad.ga", - "discord": "mr.smoothy#5824" + "discord": "mr.smoothy" } ], "versions": { + "1.0.1": null, "1.0.0": { "api_version": 7, "commit_sha": "52094fc", @@ -534,7 +545,7 @@ { "name": "JoseAng3l", "email": "", - "discord": "! JoseANG3L#0268" + "discord": "joseang3l" } ], "versions": { @@ -588,6 +599,7 @@ } ], "versions": { + "1.0.1": null, "1.0.0": { "api_version": 7, "commit_sha": "7219487", @@ -603,10 +615,11 @@ { "name": "ThePersonMan", "email": "", - "discord": "ThePersonMan#0276" + "discord": "the.personman" } ], "versions": { + "1.0.1": null, "1.0.0": { "api_version": 7, "commit_sha": "7219487", @@ -622,10 +635,11 @@ { "name": "Dliwk", "email": "", - "discord": "Dliwk#7961" + "discord": "dliwk" } ], "versions": { + "1.0.1": null, "1.0.0": { "api_version": 7, "commit_sha": "7219487", @@ -645,6 +659,7 @@ } ], "versions": { + "1.0.1": null, "1.0.0": { "api_version": 7, "commit_sha": "7219487", @@ -660,10 +675,11 @@ { "name": "SEBASTIAN2059", "email": "", - "discord": "SEBASTIAN2059#5751" + "discord": "sebastian2059" } ], "versions": { + "1.0.1": null, "1.0.0": { "api_version": 7, "commit_sha": "7219487", @@ -698,7 +714,7 @@ { "name": "Cross Joy", "email": "cross.joy.official@gmail.com", - "discord": "Cross Joy#0721" + "discord": "crossjoy" } ], "versions": { diff --git a/plugins/minigames/air_soccer.py b/plugins/minigames/air_soccer.py index a089d952..75e9ba46 100644 --- a/plugins/minigames/air_soccer.py +++ b/plugins/minigames/air_soccer.py @@ -1,20 +1,21 @@ +# Porting to api 8 made easier by baport.(https://github.com/bombsquad-community/baport) # Released under the MIT License. See LICENSE for details. # BY Stary_Agent """Hockey game and support classes.""" -# ba_meta require api 7 +# ba_meta require api 8 # (see https://ballistica.net/wiki/meta-tag-system) from __future__ import annotations from typing import TYPE_CHECKING -import ba -import _ba -from bastd.actor.playerspaz import PlayerSpaz -from bastd.actor.scoreboard import Scoreboard -from bastd.actor.powerupbox import PowerupBoxFactory -from bastd.gameutils import SharedObjects +import babase +import bascenev1 as bs +from bascenev1lib.actor.playerspaz import PlayerSpaz +from bascenev1lib.actor.scoreboard import Scoreboard +from bascenev1lib.actor.powerupbox import PowerupBoxFactory +from bascenev1lib.gameutils import SharedObjects if TYPE_CHECKING: from typing import Any, Sequence, Dict, Type, List, Optional, Union @@ -32,13 +33,13 @@ def create_slope(self): x = 5 y = 12 for i in range(0, 10): - ba.newnode('region', attrs={'position': (x, y, -5.52), 'scale': (0.2, 0.1, 6), + bs.newnode('region', attrs={'position': (x, y, -5.52), 'scale': (0.2, 0.1, 6), 'type': 'box', 'materials': [shared.footing_material, self._real_wall_material]}) x = x+0.3 y = y+0.1 -class Puck(ba.Actor): +class Puck(bs.Actor): """A lovely giant hockey puck.""" def __init__(self, position: Sequence[float] = (0.0, 13.0, 0.0)): @@ -53,10 +54,10 @@ def __init__(self, position: Sequence[float] = (0.0, 13.0, 0.0)): assert activity is not None assert isinstance(activity, HockeyGame) pmats = [shared.object_material, activity.puck_material] - self.node = ba.newnode('prop', + self.node = bs.newnode('prop', delegate=self, attrs={ - 'model': activity.puck_model, + 'mesh': activity.puck_mesh, 'color_texture': activity.puck_tex, 'body': 'sphere', 'reflection': 'soft', @@ -67,10 +68,10 @@ def __init__(self, position: Sequence[float] = (0.0, 13.0, 0.0)): 'position': self._spawn_pos, 'materials': pmats }) - ba.animate(self.node, 'model_scale', {0: 0, 0.2: 1.3, 0.26: 1}) + bs.animate(self.node, 'mesh_scale', {0: 0, 0.2: 1.3, 0.26: 1}) def handlemessage(self, msg: Any) -> Any: - if isinstance(msg, ba.DieMessage): + if isinstance(msg, bs.DieMessage): assert self.node self.node.delete() activity = self._activity() @@ -78,11 +79,11 @@ def handlemessage(self, msg: Any) -> Any: activity.handlemessage(PuckDiedMessage(self)) # If we go out of bounds, move back to where we started. - elif isinstance(msg, ba.OutOfBoundsMessage): + elif isinstance(msg, bs.OutOfBoundsMessage): assert self.node self.node.position = self._spawn_pos - elif isinstance(msg, ba.HitMessage): + elif isinstance(msg, bs.HitMessage): assert self.node assert msg.force_direction is not None self.node.handlemessage( @@ -103,31 +104,31 @@ def handlemessage(self, msg: Any) -> Any: super().handlemessage(msg) -class Player(ba.Player['Team']): +class Player(bs.Player['Team']): """Our player type for this game.""" -class Team(ba.Team[Player]): +class Team(bs.Team[Player]): """Our team type for this game.""" def __init__(self) -> None: self.score = 0 -# ba_meta export game -class AirSoccerGame(ba.TeamGameActivity[Player, Team]): +# ba_meta export bascenev1.GameActivity +class AirSoccerGame(bs.TeamGameActivity[Player, Team]): """Ice hockey game.""" name = 'Epic Air Soccer' description = 'Score some goals.' available_settings = [ - ba.IntSetting( + bs.IntSetting( 'Score to Win', min_value=1, default=1, increment=1, ), - ba.IntChoiceSetting( + bs.IntChoiceSetting( 'Time Limit', choices=[ ('None', 0), @@ -139,7 +140,7 @@ class AirSoccerGame(ba.TeamGameActivity[Player, Team]): ], default=0, ), - ba.FloatChoiceSetting( + bs.FloatChoiceSetting( 'Respawn Times', choices=[ ('Shorter', 0.1), @@ -151,14 +152,14 @@ class AirSoccerGame(ba.TeamGameActivity[Player, Team]): default=1.0, ), ] - default_music = ba.MusicType.HOCKEY + default_music = bs.MusicType.HOCKEY @classmethod - def supports_session_type(cls, sessiontype: Type[ba.Session]) -> bool: - return issubclass(sessiontype, ba.DualTeamSession) + def supports_session_type(cls, sessiontype: Type[bs.Session]) -> bool: + return issubclass(sessiontype, bs.DualTeamSession) @classmethod - def get_supported_maps(cls, sessiontype: Type[ba.Session]) -> List[str]: + def get_supported_maps(cls, sessiontype: Type[bs.Session]) -> List[str]: return ['Creative Thoughts'] def __init__(self, settings: dict): @@ -166,16 +167,16 @@ def __init__(self, settings: dict): shared = SharedObjects.get() self.slow_motion = True 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.puck_model = ba.getmodel('bomb') - self.puck_tex = ba.gettexture('landMine') - self.puck_scored_tex = ba.gettexture('landMineLit') - self._puck_sound = ba.getsound('metalHit') - self.puck_material = ba.Material() + self._cheer_sound = bs.getsound('cheer') + self._chant_sound = bs.getsound('crowdChant') + self._foghorn_sound = bs.getsound('foghorn') + self._swipsound = bs.getsound('swip') + self._whistle_sound = bs.getsound('refWhistle') + self.puck_mesh = bs.getmesh('bomb') + self.puck_tex = bs.gettexture('landMine') + self.puck_scored_tex = bs.gettexture('landMineLit') + self._puck_sound = bs.getsound('metalHit') + self.puck_material = bs.Material() self.puck_material.add_actions(actions=(('modify_part_collision', 'friction', 0.5))) self.puck_material.add_actions(conditions=('they_have_material', @@ -194,7 +195,7 @@ def __init__(self, settings: dict): shared.footing_material), actions=('impact_sound', self._puck_sound, 0.2, 5)) - self._real_wall_material = ba.Material() + self._real_wall_material = bs.Material() self._real_wall_material.add_actions( actions=( @@ -210,7 +211,7 @@ def __init__(self, settings: dict): ('modify_part_collision', 'physical', True) )) - self._goal_post_material = ba.Material() + self._goal_post_material = bs.Material() self._goal_post_material.add_actions( actions=( @@ -237,15 +238,15 @@ def __init__(self, settings: dict): 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() + ('message', 'their_node', 'at_connect', bs.DieMessage()))) + self._score_region_material = bs.Material() self._score_region_material.add_actions( conditions=('they_have_material', self.puck_material), actions=(('modify_part_collision', 'collide', True), ('modify_part_collision', 'physical', False), ('call', 'at_connect', self._handle_score))) self._puck_spawn_pos: Optional[Sequence[float]] = None - self._score_regions: Optional[List[ba.NodeActor]] = None + self._score_regions: Optional[List[bs.NodeActor]] = None self._puck: Optional[Puck] = None self._score_to_win = int(settings['Score to Win']) self._time_limit = float(settings['Time Limit']) @@ -273,8 +274,8 @@ def on_begin(self) -> None: defs = self.map.defs self._score_regions = [] self._score_regions.append( - ba.NodeActor( - ba.newnode('region', + bs.NodeActor( + bs.newnode('region', attrs={ 'position': (17, 14.5, -5.52), 'scale': (1, 3, 1), @@ -282,8 +283,8 @@ def on_begin(self) -> None: 'materials': [self._score_region_material] }))) self._score_regions.append( - ba.NodeActor( - ba.newnode('region', + bs.NodeActor( + bs.newnode('region', attrs={ 'position': (-17, 14.5, -5.52), 'scale': (1, 3, 1), @@ -291,36 +292,36 @@ def on_begin(self) -> None: 'materials': [self._score_region_material] }))) self._update_scoreboard() - ba.playsound(self._chant_sound) + self._chant_sound.play() def on_team_join(self, team: Team) -> None: self._update_scoreboard() def _handle_puck_player_collide(self) -> None: - collision = ba.getcollision() + collision = bs.getcollision() try: puck = collision.sourcenode.getdelegate(Puck, True) player = collision.opposingnode.getdelegate(PlayerSpaz, True).getplayer( Player, True) - except ba.NotFoundError: + except bs.NotFoundError: return puck.last_players_to_touch[player.team.id] = player def make_map(self): shared = SharedObjects.get() - _ba.get_foreground_host_activity()._map.leftwall.materials = [ + bs.get_foreground_host_activity()._map.leftwall.materials = [ shared.footing_material, self._real_wall_material] - _ba.get_foreground_host_activity()._map.rightwall.materials = [ + bs.get_foreground_host_activity()._map.rightwall.materials = [ shared.footing_material, self._real_wall_material] - _ba.get_foreground_host_activity()._map.topwall.materials = [ + bs.get_foreground_host_activity()._map.topwall.materials = [ shared.footing_material, self._real_wall_material] - self.floorwall = ba.newnode('region', attrs={'position': (0, 5, -5.52), 'scale': ( + self.floorwall = bs.newnode('region', attrs={'position': (0, 5, -5.52), 'scale': ( 35.4, 0.2, 2), 'type': 'box', 'materials': [shared.footing_material, self._real_wall_material]}) - ba.newnode('locator', attrs={'shape': 'box', 'position': ( + bs.newnode('locator', attrs={'shape': 'box', 'position': ( 0, 5, -5.52), 'color': (0, 0, 0), 'opacity': 1, 'draw_beauty': True, 'additive': False, 'size': (35.4, 0.2, 2)}) self.create_goal_post(-16.65, 12.69) @@ -343,9 +344,9 @@ def create_static_step(self, x, y): floor += "_ " shared = SharedObjects.get() step = {} - step["r"] = ba.newnode('region', attrs={'position': (x, y, -5.52), 'scale': ( + step["r"] = bs.newnode('region', attrs={'position': (x, y, -5.52), 'scale': ( 3, 0.1, 6), 'type': 'box', 'materials': [shared.footing_material, self._real_wall_material]}) - ba.newnode('locator', attrs={'shape': 'box', 'position': ( + bs.newnode('locator', attrs={'shape': 'box', 'position': ( x, y, -5.52), 'color': (1, 1, 0), 'opacity': 1, 'draw_beauty': True, 'additive': False, 'size': (3, 0.1, 2)}) return step @@ -359,10 +360,10 @@ def create_goal_post(self, x, y): floor = "" for i in range(0, 4): floor += "_ " - ba.newnode('region', attrs={'position': (x-0.2, y, -5.52), 'scale': (1.8, 0.1, 6), + bs.newnode('region', attrs={'position': (x-0.2, y, -5.52), 'scale': (1.8, 0.1, 6), 'type': 'box', 'materials': [shared.footing_material, self._goal_post_material]}) - ba.newnode('locator', attrs={'shape': 'box', 'position': ( + bs.newnode('locator', attrs={'shape': 'box', 'position': ( x-0.2, y, -5.52), 'color': color, 'opacity': 1, 'draw_beauty': True, 'additive': False, 'size': (1.8, 0.1, 2)}) def create_vertical(self, x, y): @@ -370,9 +371,9 @@ def create_vertical(self, x, y): floor = "" for i in range(0, 4): floor += "|\n" - ba.newnode('region', attrs={'position': (x, y, -5.52), 'scale': (0.1, 2.8, 1), + bs.newnode('region', attrs={'position': (x, y, -5.52), 'scale': (0.1, 2.8, 1), 'type': 'box', 'materials': [shared.footing_material, self._real_wall_material]}) - ba.newnode('locator', attrs={'shape': 'box', 'position': ( + bs.newnode('locator', attrs={'shape': 'box', 'position': ( x, y, -5.52), 'color': (1, 1, 0), 'opacity': 1, 'draw_beauty': True, 'additive': False, 'size': (0.1, 2.8, 2)}) def spawn_player_spaz(self, @@ -402,7 +403,7 @@ def _handle_score(self) -> None: if self._puck.scored: return - region = ba.getcollision().sourcenode + region = bs.getcollision().sourcenode index = 0 for index in range(len(self._score_regions)): if region == self._score_regions[index].node: @@ -416,7 +417,7 @@ def _handle_score(self) -> None: # Tell all players to celebrate. for player in team.players: if player.actor: - player.actor.handlemessage(ba.CelebrateMessage(2.0)) + player.actor.handlemessage(bs.CelebrateMessage(2.0)) # If we've got the player from the scoring team that last # touched us, give them points. @@ -431,30 +432,30 @@ def _handle_score(self) -> None: if team.score >= self._score_to_win: self.end_game() - ba.playsound(self._foghorn_sound) - ba.playsound(self._cheer_sound) + self._foghorn_sound.play() + self._cheer_sound.play() self._puck.scored = True # Change puck texture to something cool self._puck.node.color_texture = self.puck_scored_tex # Kill the puck (it'll respawn itself shortly). - ba.timer(1.0, self._kill_puck) + bs.timer(1.0, self._kill_puck) - light = ba.newnode('light', + light = bs.newnode('light', attrs={ - 'position': ba.getcollision().position, + 'position': bs.getcollision().position, 'height_attenuated': False, 'color': (1, 0, 0) }) - ba.animate(light, 'intensity', {0: 0, 0.5: 1, 1.0: 0}, loop=True) - ba.timer(1.0, light.delete) + bs.animate(light, 'intensity', {0: 0, 0.5: 1, 1.0: 0}, loop=True) + bs.timer(1.0, light.delete) - ba.cameraflash(duration=10.0) + bs.cameraflash(duration=10.0) self._update_scoreboard() def end_game(self) -> None: - results = ba.GameResults() + results = bs.GameResults() for team in self.teams: results.set_team_score(team, team.score) self.end(results=results) @@ -467,7 +468,7 @@ def _update_scoreboard(self) -> None: def handlemessage(self, msg: Any) -> Any: # Respawn dead players if they're still in the game. - if isinstance(msg, ba.PlayerDiedMessage): + if isinstance(msg, bs.PlayerDiedMessage): # Augment standard behavior... super().handlemessage(msg) self.respawn_player(msg.getplayer(Player)) @@ -475,23 +476,23 @@ def handlemessage(self, msg: Any) -> Any: # Respawn dead pucks. elif isinstance(msg, PuckDiedMessage): if not self.has_ended(): - ba.timer(3.0, self._spawn_puck) + bs.timer(3.0, self._spawn_puck) else: super().handlemessage(msg) def _flash_puck_spawn(self) -> None: - light = ba.newnode('light', + light = bs.newnode('light', attrs={ 'position': self._puck_spawn_pos, 'height_attenuated': False, 'color': (1, 0, 0) }) - ba.animate(light, 'intensity', {0.0: 0, 0.25: 1, 0.5: 0}, loop=True) - ba.timer(1.0, light.delete) + bs.animate(light, 'intensity', {0.0: 0, 0.25: 1, 0.5: 0}, loop=True) + bs.timer(1.0, light.delete) def _spawn_puck(self) -> None: - ba.playsound(self._swipsound) - ba.playsound(self._whistle_sound) + self._swipsound.play() + self._whistle_sound.play() self._flash_puck_spawn() assert self._puck_spawn_pos is not None self._puck = Puck(position=self._puck_spawn_pos) @@ -541,7 +542,7 @@ class mapdefs: 0.5245740665, 0.5245740665, 0.01941146064) -class CreativeThoughts(ba.Map): +class CreativeThoughts(bs.Map): """Freaking map by smoothy.""" defs = mapdefs @@ -562,26 +563,26 @@ def get_preview_texture_name(cls) -> str: @classmethod def on_preload(cls) -> Any: data: Dict[str, Any] = { - 'model': ba.getmodel('alwaysLandLevel'), - 'bottom_model': ba.getmodel('alwaysLandLevelBottom'), - 'bgmodel': ba.getmodel('alwaysLandBG'), - 'collide_model': ba.getcollidemodel('alwaysLandLevelCollide'), - 'tex': ba.gettexture('alwaysLandLevelColor'), - 'bgtex': ba.gettexture('alwaysLandBGColor'), - 'vr_fill_mound_model': ba.getmodel('alwaysLandVRFillMound'), - 'vr_fill_mound_tex': ba.gettexture('vrFillMound') + 'mesh': bs.getmesh('alwaysLandLevel'), + 'bottom_mesh': bs.getmesh('alwaysLandLevelBottom'), + 'bgmesh': bs.getmesh('alwaysLandBG'), + 'collision_mesh': bs.getcollisionmesh('alwaysLandLevelCollide'), + 'tex': bs.gettexture('alwaysLandLevelColor'), + 'bgtex': bs.gettexture('alwaysLandBGColor'), + 'vr_fill_mound_mesh': bs.getmesh('alwaysLandVRFillMound'), + 'vr_fill_mound_tex': bs.gettexture('vrFillMound') } return data @classmethod - def get_music_type(cls) -> ba.MusicType: - return ba.MusicType.FLYING + def get_music_type(cls) -> bs.MusicType: + return bs.MusicType.FLYING def __init__(self) -> None: super().__init__(vr_overlay_offset=(0, -3.7, 2.5)) shared = SharedObjects.get() - self._fake_wall_material = ba.Material() - self._real_wall_material = ba.Material() + self._fake_wall_material = bs.Material() + self._real_wall_material = bs.Material() self._fake_wall_material.add_actions( conditions=(('they_are_younger_than', 9000), 'and', ('they_have_material', shared.player_material)), @@ -597,29 +598,29 @@ def __init__(self) -> None: ('modify_part_collision', 'physical', True) )) - self.background = ba.newnode( + self.background = bs.newnode( 'terrain', attrs={ - 'model': self.preloaddata['bgmodel'], + 'mesh': self.preloaddata['bgmesh'], 'lighting': False, 'background': True, - 'color_texture': ba.gettexture("rampageBGColor") + 'color_texture': bs.gettexture("rampageBGColor") }) - self.leftwall = ba.newnode('region', attrs={'position': (-17.75152479, 13, -5.52), 'scale': ( + self.leftwall = bs.newnode('region', attrs={'position': (-17.75152479, 13, -5.52), 'scale': ( 0.1, 15.5, 2), 'type': 'box', 'materials': [shared.footing_material, self._real_wall_material]}) - self.rightwall = ba.newnode('region', attrs={'position': (17.75, 13, -5.52), 'scale': ( + self.rightwall = bs.newnode('region', attrs={'position': (17.75, 13, -5.52), 'scale': ( 0.1, 15.5, 2), 'type': 'box', 'materials': [shared.footing_material, self._real_wall_material]}) - self.topwall = ba.newnode('region', attrs={'position': (0, 21.0, -5.52), 'scale': ( + self.topwall = bs.newnode('region', attrs={'position': (0, 21.0, -5.52), 'scale': ( 35.4, 0.2, 2), 'type': 'box', 'materials': [shared.footing_material, self._real_wall_material]}) - ba.newnode('locator', attrs={'shape': 'box', 'position': (-17.75152479, 13, -5.52), 'color': ( + bs.newnode('locator', attrs={'shape': 'box', 'position': (-17.75152479, 13, -5.52), 'color': ( 0, 0, 0), 'opacity': 1, 'draw_beauty': True, 'additive': False, 'size': (0.1, 15.5, 2)}) - ba.newnode('locator', attrs={'shape': 'box', 'position': (17.75, 13, -5.52), 'color': ( + bs.newnode('locator', attrs={'shape': 'box', 'position': (17.75, 13, -5.52), 'color': ( 0, 0, 0), 'opacity': 1, 'draw_beauty': True, 'additive': False, 'size': (0.1, 15.5, 2)}) - ba.newnode('locator', attrs={'shape': 'box', 'position': (0, 21.0, -5.52), 'color': ( + bs.newnode('locator', attrs={'shape': 'box', 'position': (0, 21.0, -5.52), 'color': ( 0, 0, 0), 'opacity': 1, 'draw_beauty': True, 'additive': False, 'size': (35.4, 0.2, 2)}) - gnode = ba.getactivity().globalsnode + gnode = bs.getactivity().globalsnode gnode.happy_thoughts_mode = True gnode.shadow_offset = (0.0, 8.0, 5.0) gnode.tint = (1.3, 1.23, 1.0) @@ -630,9 +631,9 @@ def __init__(self) -> None: self.is_flying = True # throw out some tips on flying - txt = ba.newnode('text', + txt = bs.newnode('text', attrs={ - 'text': ba.Lstr(resource='pressJumpToFlyText'), + 'text': babase.Lstr(resource='pressJumpToFlyText'), 'scale': 1.2, 'maxwidth': 800, 'position': (0, 200), @@ -641,7 +642,7 @@ def __init__(self) -> None: 'h_align': 'center', 'v_attach': 'bottom' }) - cmb = ba.newnode('combine', + cmb = bs.newnode('combine', owner=txt, attrs={ 'size': 4, @@ -649,12 +650,12 @@ def __init__(self) -> None: 'input1': 0.9, 'input2': 0.0 }) - ba.animate(cmb, 'input3', {3.0: 0, 4.0: 1, 9.0: 1, 10.0: 0}) + bs.animate(cmb, 'input3', {3.0: 0, 4.0: 1, 9.0: 1, 10.0: 0}) cmb.connectattr('output', txt, 'color') - ba.timer(10.0, txt.delete) + bs.timer(10.0, txt.delete) try: - ba._map.register_map(CreativeThoughts) + bs._map.register_map(CreativeThoughts) except: pass diff --git a/plugins/minigames/basket_bomb.py b/plugins/minigames/basket_bomb.py index 4da374d1..8c33edbf 100644 --- a/plugins/minigames/basket_bomb.py +++ b/plugins/minigames/basket_bomb.py @@ -1,19 +1,22 @@ +# Porting to api 8 made easier by baport.(https://github.com/bombsquad-community/baport) # Released under the MIT License. See LICENSE for details. -# ba_meta require api 7 +# ba_meta require api 8 # (see https://ballistica.net/wiki/meta-tag-system) from __future__ import annotations from typing import TYPE_CHECKING -import ba -import _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 bastd.actor import playerspaz as ps -from bastd import maps +import babase +import bauiv1 as bui +import bascenev1 as bs +import _babase +from bascenev1lib.actor.playerspaz import PlayerSpaz +from bascenev1lib.actor.scoreboard import Scoreboard +from bascenev1lib.actor.powerupbox import PowerupBoxFactory +from bascenev1lib.gameutils import SharedObjects +from bascenev1lib.actor import playerspaz as ps +from bascenev1lib import maps if TYPE_CHECKING: from typing import Any, Sequence, Dict, Type, List, Optional, Union @@ -22,7 +25,7 @@ def getlanguage(text, sub: str = ''): - lang = _ba.app.lang.language + lang = bs.app.lang.language translate = { "Name": {"Spanish": "Baloncesto", @@ -60,7 +63,7 @@ def __init__(self, ball: Ball): self.ball = ball -class Ball(ba.Actor): +class Ball(bs.Actor): def __init__(self, position: Sequence[float] = (0.0, 1.0, 0.0)): super().__init__() shared = SharedObjects.get() @@ -76,10 +79,10 @@ def __init__(self, position: Sequence[float] = (0.0, 1.0, 0.0)): assert isinstance(activity, BasketGame) pmats = [shared.object_material, activity.ball_material] - self.node = ba.newnode('prop', + self.node = bs.newnode('prop', delegate=self, attrs={ - 'model': activity.ball_model, + 'mesh': activity.ball_mesh, 'color_texture': activity.ball_tex, 'body': 'sphere', 'reflection': 'soft', @@ -92,22 +95,22 @@ def __init__(self, position: Sequence[float] = (0.0, 1.0, 0.0)): 'velocity': velocty, 'materials': pmats}) self.scale = scale = 0.25 * _scale - ba.animate(self.node, 'model_scale', {0: 0, 0.2: scale*1.3, 0.26: scale}) + bs.animate(self.node, 'mesh_scale', {0: 0, 0.2: scale*1.3, 0.26: scale}) def handlemessage(self, msg: Any) -> Any: - if isinstance(msg, ba.DieMessage): + if isinstance(msg, bs.DieMessage): assert self.node self.node.delete() activity = self._activity() if activity and not msg.immediate: activity.handlemessage(BallDiedMessage(self)) - elif isinstance(msg, ba.OutOfBoundsMessage): + elif isinstance(msg, bs.OutOfBoundsMessage): assert self.node self.node.position = self._spawn_pos self.node.velocity = (0.0, 0.0, 0.0) - elif isinstance(msg, ba.HitMessage): + elif isinstance(msg, bs.HitMessage): assert self.node assert msg.force_direction is not None self.node.handlemessage( @@ -127,11 +130,11 @@ def handlemessage(self, msg: Any) -> Any: super().handlemessage(msg) -class Player(ba.Player['Team']): +class Player(bs.Player['Team']): """Our player type for this game.""" -class Team(ba.Team[Player]): +class Team(bs.Team[Player]): """Our team type for this game.""" def __init__(self) -> None: @@ -144,21 +147,21 @@ class Points: postes['pal_0'] = (10.64702320098877, 0.0000000000000000, 0.0000000000000000) postes['pal_1'] = (-10.64702320098877, 0.0000000000000000, 0.0000000000000000) -# ba_meta export game +# ba_meta export bascenev1.GameActivity -class BasketGame(ba.TeamGameActivity[Player, Team]): +class BasketGame(bs.TeamGameActivity[Player, Team]): name = getlanguage('Name') description = getlanguage('Info') available_settings = [ - ba.IntSetting( + bs.IntSetting( 'Score to Win', min_value=1, default=1, increment=1, ), - ba.IntChoiceSetting( + bs.IntChoiceSetting( 'Time Limit', choices=[ ('None', 0), @@ -170,7 +173,7 @@ class BasketGame(ba.TeamGameActivity[Player, Team]): ], default=0, ), - ba.FloatChoiceSetting( + bs.FloatChoiceSetting( 'Respawn Times', choices=[ ('Shorter', 0.25), @@ -181,38 +184,38 @@ class BasketGame(ba.TeamGameActivity[Player, Team]): ], default=1.0, ), - ba.BoolSetting(getlanguage('S: Powerups'), default=True), - ba.BoolSetting(getlanguage('S: Velocity'), default=False), - ba.BoolSetting('Epic Mode', default=False), + bs.BoolSetting(getlanguage('S: Powerups'), default=True), + bs.BoolSetting(getlanguage('S: Velocity'), default=False), + bs.BoolSetting('Epic Mode', default=False), ] - default_music = ba.MusicType.HOCKEY + default_music = bs.MusicType.HOCKEY @classmethod - def supports_session_type(cls, sessiontype: Type[ba.Session]) -> bool: - return issubclass(sessiontype, ba.DualTeamSession) + def supports_session_type(cls, sessiontype: Type[bs.Session]) -> bool: + return issubclass(sessiontype, bs.DualTeamSession) @classmethod - def get_supported_maps(cls, sessiontype: Type[ba.Session]) -> List[str]: + def get_supported_maps(cls, sessiontype: Type[bs.Session]) -> List[str]: return ['BasketBall Stadium', 'BasketBall Stadium V2'] def __init__(self, settings: dict): super().__init__(settings) 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('shield') - self.ball_tex = ba.gettexture('fontExtras3') - self._ball_sound = ba.getsound('bunnyJump') + self._cheer_sound = bs.getsound('cheer') + self._chant_sound = bs.getsound('crowdChant') + self._foghorn_sound = bs.getsound('foghorn') + self._swipsound = bs.getsound('swip') + self._whistle_sound = bs.getsound('refWhistle') + self.ball_mesh = bs.getmesh('shield') + self.ball_tex = bs.gettexture('fontExtras3') + self._ball_sound = bs.getsound('bunnyJump') self._powerups = bool(settings[getlanguage('S: Powerups')]) self._speed = bool(settings[getlanguage('S: Velocity')]) self._epic_mode = bool(settings['Epic Mode']) self.slow_motion = self._epic_mode - self.ball_material = ba.Material() + self.ball_material = bs.Material() self.ball_material.add_actions(actions=(('modify_part_collision', 'friction', 0.5))) self.ball_material.add_actions(conditions=('they_have_material', @@ -238,14 +241,14 @@ def __init__(self, settings: dict): actions=(('call', 'at_connect', self._handle_ball_player_collide), )) - self._score_region_material = ba.Material() + self._score_region_material = bs.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._ball_spawn_pos: Optional[Sequence[float]] = None - self._score_regions: Optional[List[ba.NodeActor]] = None + self._score_regions: Optional[List[bs.NodeActor]] = None self._ball: Optional[Ball] = None self._score_to_win = int(settings['Score to Win']) self._time_limit = float(settings['Time Limit']) @@ -270,8 +273,8 @@ def on_begin(self) -> None: defs = self.map.defs self._score_regions = [] self._score_regions.append( - ba.NodeActor( - ba.newnode('region', + bs.NodeActor( + bs.newnode('region', attrs={ 'position': defs.boxes['goal1'][0:3], 'scale': defs.boxes['goal1'][6:9], @@ -279,8 +282,8 @@ def on_begin(self) -> None: 'materials': [] }))) self._score_regions.append( - ba.NodeActor( - ba.newnode('region', + bs.NodeActor( + bs.newnode('region', attrs={ 'position': defs.boxes['goal2'][0:3], 'scale': defs.boxes['goal2'][6:9], @@ -288,7 +291,7 @@ def on_begin(self) -> None: 'materials': [] }))) self._update_scoreboard() - ba.playsound(self._chant_sound) + self._chant_sound.play() for id, team in enumerate(self.teams): self.postes(id) @@ -297,13 +300,13 @@ def on_team_join(self, team: Team) -> None: self._update_scoreboard() def _handle_ball_player_collide(self) -> None: - collision = ba.getcollision() + collision = bs.getcollision() try: ball = collision.sourcenode.getdelegate(Ball, True) player = collision.opposingnode.getdelegate(PlayerSpaz, True).getplayer( Player, True) - except ba.NotFoundError: + except bs.NotFoundError: return ball.last_players_to_touch[player.team.id] = player @@ -318,7 +321,7 @@ def _handle_score(self, team_index: int = None) -> None: if self._ball.scored: return - region = ba.getcollision().sourcenode + region = bs.getcollision().sourcenode index = 0 for index in range(len(self._score_regions)): if region == self._score_regions[index].node: @@ -334,7 +337,7 @@ def _handle_score(self, team_index: int = None) -> None: for player in team.players: if player.actor: - player.actor.handlemessage(ba.CelebrateMessage(2.0)) + player.actor.handlemessage(bs.CelebrateMessage(2.0)) if (scoring_team.id in self._ball.last_players_to_touch and self._ball.last_players_to_touch[scoring_team.id]): @@ -345,28 +348,28 @@ def _handle_score(self, team_index: int = None) -> None: if team.score >= self._score_to_win: self.end_game() - # ba.playsound(self._foghorn_sound) - ba.playsound(self._cheer_sound) + # self._foghorn_sound.play() + self._cheer_sound.play() self._ball.scored = True # Kill the ball (it'll respawn itself shortly). - ba.timer(1.0, self._kill_ball) + bs.timer(1.0, self._kill_ball) - light = ba.newnode('light', + light = bs.newnode('light', attrs={ - 'position': ba.getcollision().position, + 'position': bs.getcollision().position, 'height_attenuated': False, 'color': (1, 0, 0) }) - ba.animate(light, 'intensity', {0: 0, 0.5: 1, 1.0: 0}, loop=True) - ba.timer(1.0, light.delete) + bs.animate(light, 'intensity', {0: 0, 0.5: 1, 1.0: 0}, loop=True) + bs.timer(1.0, light.delete) - ba.cameraflash(duration=10.0) + bs.cameraflash(duration=10.0) self._update_scoreboard() def end_game(self) -> None: - results = ba.GameResults() + results = bs.GameResults() for team in self.teams: results.set_team_score(team, team.score) self.end(results=results) @@ -377,7 +380,7 @@ def _update_scoreboard(self) -> None: self._scoreboard.set_team_value(team, team.score, winscore) # self.postes(id) - def spawn_player(self, player: Player) -> ba.Actor: + def spawn_player(self, player: Player) -> bs.Actor: if bsuSpaz is None: spaz = self.spawn_player_spaz(player) else: @@ -390,12 +393,12 @@ def spawn_player(self, player: Player) -> ba.Actor: return spaz def handlemessage(self, msg: Any) -> Any: - if isinstance(msg, ba.PlayerDiedMessage): + if isinstance(msg, bs.PlayerDiedMessage): super().handlemessage(msg) self.respawn_player(msg.getplayer(Player)) elif isinstance(msg, BallDiedMessage): if not self.has_ended(): - ba.timer(3.0, self._spawn_ball) + bs.timer(3.0, self._spawn_ball) else: super().handlemessage(msg) @@ -407,24 +410,24 @@ def postes(self, team_id: int): str(team_id)]).autoretain()) def _flash_ball_spawn(self) -> None: - light = ba.newnode('light', + light = bs.newnode('light', attrs={ 'position': self._ball_spawn_pos, 'height_attenuated': False, 'color': (1, 0, 0) }) - ba.animate(light, 'intensity', {0.0: 0, 0.25: 1, 0.5: 0}, loop=True) - ba.timer(1.0, light.delete) + bs.animate(light, 'intensity', {0.0: 0, 0.25: 1, 0.5: 0}, loop=True) + bs.timer(1.0, light.delete) def _spawn_ball(self) -> None: - ba.playsound(self._swipsound) - ba.playsound(self._whistle_sound) + self._swipsound.play() + self._whistle_sound.play() self._flash_ball_spawn() assert self._ball_spawn_pos is not None self._ball = Ball(position=self._ball_spawn_pos) -class Aro(ba.Actor): +class Aro(bs.Actor): def __init__(self, team: int = 0, position: Sequence[float] = (0.0, 1.0, 0.0)): super().__init__() @@ -434,16 +437,16 @@ def __init__(self, team: int = 0, setattr(self, 'locs', []) # Material Para; Traspasar Objetos - self.no_collision = ba.Material() + self.no_collision = bs.Material() self.no_collision.add_actions( actions=(('modify_part_collision', 'collide', False))) - self.collision = ba.Material() + self.collision = bs.Material() self.collision.add_actions( actions=(('modify_part_collision', 'collide', True))) # Score - self._score_region_material = ba.Material() + self._score_region_material = bs.Material() self._score_region_material.add_actions( conditions=('they_have_material', act.ball_material), actions=(('modify_part_collision', 'collide', @@ -454,14 +457,14 @@ def __init__(self, team: int = 0, self._materials_region0 = [self.collision, shared.footing_material] - model = None - tex = ba.gettexture('null') + mesh = None + tex = bs.gettexture('null') pmats = [self.no_collision] - self.node = ba.newnode('prop', + self.node = bs.newnode('prop', delegate=self, attrs={ - 'model': model, + 'mesh': mesh, 'color_texture': tex, 'body': 'box', 'reflection': 'soft', @@ -471,17 +474,17 @@ def __init__(self, team: int = 0, 'materials': pmats}) self.scale = scale = 1.4 - ba.animate(self.node, 'model_scale', {0: 0}) + bs.animate(self.node, 'mesh_scale', {0: 0}) pos = (position[0], position[1]+0.6, position[2]) - self.regions: List[ba.Node] = [ - ba.newnode('region', + self.regions: List[bs.Node] = [ + bs.newnode('region', attrs={'position': position, 'scale': (0.6, 0.05, 0.6), 'type': 'box', 'materials': self._materials_region0}), - ba.newnode('region', + bs.newnode('region', attrs={'position': pos, 'scale': (0.5, 0.3, 0.9), 'type': 'box', @@ -502,7 +505,7 @@ def __init__(self, team: int = 0, while locs_count > 1: scale = (1.5 * 0.1 * locs_count) + 0.8 - self.locs.append(ba.newnode('locator', + self.locs.append(bs.newnode('locator', owner=self.node, attrs={'shape': 'circleOutline', 'position': pos, @@ -528,14 +531,14 @@ def _annotation(self): act._handle_score(self.team) def handlemessage(self, msg: Any) -> Any: - if isinstance(msg, ba.DieMessage): + if isinstance(msg, bs.DieMessage): if self.node.exists(): self.node.delete() else: super().handlemessage(msg) -class Cuadro(ba.Actor): +class Cuadro(bs.Actor): def __init__(self, team: int = 0, position: Sequence[float] = (0.0, 1.0, 0.0)): super().__init__() @@ -543,19 +546,19 @@ def __init__(self, team: int = 0, shared = SharedObjects.get() setattr(self, 'locs', []) - self.collision = ba.Material() + self.collision = bs.Material() self.collision.add_actions( actions=(('modify_part_collision', 'collide', True))) pos = (position[0], position[1]+0.9, position[2]+1.5) - self.region: ba.Node = ba.newnode('region', + self.region: bs.Node = bs.newnode('region', attrs={'position': pos, 'scale': (0.5, 2.7, 2.5), 'type': 'box', 'materials': [self.collision, shared.footing_material]}) - # self.shield = ba.newnode('shield', attrs={'radius': 1.0, 'color': (0,10,0)}) + # self.shield = bs.newnode('shield', attrs={'radius': 1.0, 'color': (0,10,0)}) # self.region.connectattr('position', self.shield, 'position') position = (position[0], position[1], position[2]+0.09) @@ -578,7 +581,7 @@ def __init__(self, team: int = 0, pos[2] += 0.19 self.locs.append( - ba.newnode('locator', + bs.newnode('locator', owner=self.region, attrs={'shape': 'circle', 'position': pos, @@ -595,14 +598,14 @@ def __init__(self, team: int = 0, count_y -= 1 def handlemessage(self, msg: Any) -> Any: - if isinstance(msg, ba.DieMessage): + if isinstance(msg, bs.DieMessage): if self.node.exists(): self.node.delete() else: super().handlemessage(msg) -class Palos(ba.Actor): +class Palos(bs.Actor): def __init__(self, team: int = 0, position: Sequence[float] = (0.0, 1.0, 0.0)): super().__init__() @@ -613,26 +616,26 @@ def __init__(self, team: int = 0, self.cua = None # Material Para; Traspasar Objetos - self.no_collision = ba.Material() + self.no_collision = bs.Material() self.no_collision.add_actions( actions=(('modify_part_collision', 'collide', False))) # - self.collision = ba.Material() + self.collision = bs.Material() self.collision.add_actions( actions=(('modify_part_collision', 'collide', True))) # Spawn just above the provided point. self._spawn_pos = (position[0], position[2]+2.5, position[2]) - model = ba.getmodel('flagPole') - tex = ba.gettexture('flagPoleColor') + mesh = bs.getmesh('flagPole') + tex = bs.gettexture('flagPoleColor') pmats = [self.no_collision] - self.node = ba.newnode('prop', + self.node = bs.newnode('prop', delegate=self, attrs={ - 'model': model, + 'mesh': mesh, 'color_texture': tex, 'body': 'puck', 'reflection': 'soft', @@ -643,9 +646,9 @@ def __init__(self, team: int = 0, 'materials': pmats }) self.scale = scale = 4.0 - ba.animate(self.node, 'model_scale', {0: scale}) + bs.animate(self.node, 'mesh_scale', {0: scale}) - self.loc = ba.newnode('locator', + self.loc = bs.newnode('locator', owner=self.node, attrs={'shape': 'circle', 'position': position, @@ -657,7 +660,7 @@ def __init__(self, team: int = 0, self._y = _y = 0.30 _x = -0.25 if team == 1 else 0.25 _pos = (position[0]+_x, position[1]-1.5 + _y, position[2]) - self.region = ba.newnode('region', + self.region = bs.newnode('region', attrs={ 'position': _pos, 'scale': (0.4, 8, 0.4), @@ -680,7 +683,7 @@ def __init__(self, team: int = 0, self.cua = Cuadro(team, pos).autoretain() def handlemessage(self, msg: Any) -> Any: - if isinstance(msg, ba.DieMessage): + if isinstance(msg, bs.DieMessage): if self.node.exists(): self.node.delete() else: @@ -698,7 +701,7 @@ def get_play_types(cls) -> List[str]: def __init__(self) -> None: super().__init__() - gnode = ba.getactivity().globalsnode + gnode = bs.getactivity().globalsnode gnode.tint = [(0.806, 0.8, 1.0476), (1.3, 1.2, 1.0)][0] gnode.ambient_color = (1.3, 1.2, 1.0) gnode.vignette_outer = (0.57, 0.57, 0.57) @@ -715,21 +718,21 @@ def __init__(self) -> None: shared = SharedObjects.get() self.node.materials = [shared.footing_material] - self.node.collide_model = ba.getcollidemodel('footballStadiumCollide') - self.node.model = None - self.stands.model = None + self.node.collision_mesh = bs.getcollisionmesh('footballStadiumCollide') + self.node.mesh = None + self.stands.mesh = None self.floor.reflection = 'soft' self.floor.reflection_scale = [1.6] self.floor.color = (1.1, 0.05, 0.8) - self.background = ba.newnode('terrain', - attrs={'model': ba.getmodel('thePadBG'), + self.background = bs.newnode('terrain', + attrs={'mesh': bs.getmesh('thePadBG'), 'lighting': False, 'background': True, 'color': (1.0, 0.2, 1.0), - 'color_texture': ba.gettexture('menuBG')}) + 'color_texture': bs.gettexture('menuBG')}) - gnode = ba.getactivity().globalsnode + gnode = bs.getactivity().globalsnode gnode.floor_reflection = True gnode.debris_friction = 0.3 gnode.debris_kill_height = -0.3 @@ -742,24 +745,24 @@ def __init__(self) -> None: self.is_hockey = False ################## - self.collision = ba.Material() + self.collision = bs.Material() self.collision.add_actions( actions=(('modify_part_collision', 'collide', True))) - self.regions: List[ba.Node] = [ - ba.newnode('region', + self.regions: List[bs.Node] = [ + bs.newnode('region', attrs={'position': (12.676897048950195, 0.2997918128967285, 5.583303928375244), 'scale': (1.01, 12, 28), 'type': 'box', 'materials': [self.collision]}), - ba.newnode('region', + bs.newnode('region', attrs={'position': (11.871315956115723, 0.29975247383117676, 5.711406707763672), 'scale': (50, 12, 0.9), 'type': 'box', 'materials': [self.collision]}), - ba.newnode('region', + bs.newnode('region', attrs={'position': (-12.776557922363281, 0.30036890506744385, 4.96237850189209), 'scale': (1.01, 12, 28), 'type': 'box', @@ -767,5 +770,5 @@ def __init__(self) -> None: ] -ba._map.register_map(BasketMap) -ba._map.register_map(BasketMapV2) +bs._map.register_map(BasketMap) +bs._map.register_map(BasketMapV2) diff --git a/plugins/minigames/castel_queen.py b/plugins/minigames/castel_queen.py index df863689..e3d7bc54 100644 --- a/plugins/minigames/castel_queen.py +++ b/plugins/minigames/castel_queen.py @@ -1,3 +1,4 @@ +# Porting to api 8 made easier by baport.(https://github.com/bombsquad-community/baport) # Released under the MIT License. See LICENSE for details. # """ @@ -8,24 +9,24 @@ Website: https://bombsquad-community.web.app Github: https://github.com/bombsquad-community """ -# ba_meta require api 7 +# ba_meta require api 8 # (see https://ballistica.net/wiki/meta-tag-system) from __future__ import annotations from typing import TYPE_CHECKING -import ba -import _ba +import babase +import bascenev1 as bs -from bastd.gameutils import SharedObjects -from bastd.actor.playerspaz import PlayerSpaz -from bastd.game.keepaway import KeepAwayGame, FlagState, Player -from bastd.actor import spaz +from bascenev1lib.gameutils import SharedObjects +from bascenev1lib.actor.playerspaz import PlayerSpaz +from bascenev1lib.game.keepaway import KeepAwayGame, FlagState, Player +from bascenev1lib.actor import spaz if TYPE_CHECKING: from typing import Any, Sequence, Dict, Type, List, Optional, Union -# ba_meta export game +# ba_meta export bascenev1.GameActivity class ChooseQueen(KeepAwayGame): @@ -33,11 +34,11 @@ class ChooseQueen(KeepAwayGame): description = 'Carry the queen for a set length of time' @classmethod - def supports_session_type(cls, sessiontype: Type[ba.Session]) -> bool: - return issubclass(sessiontype, ba.DualTeamSession) + def supports_session_type(cls, sessiontype: Type[bs.Session]) -> bool: + return issubclass(sessiontype, bs.DualTeamSession) @classmethod - def get_supported_maps(cls, sessiontype: Type[ba.Session]) -> List[str]: + def get_supported_maps(cls, sessiontype: Type[bs.Session]) -> List[str]: return ['Creative Thoughts'] def get_instance_description(self) -> str | Sequence: @@ -50,13 +51,13 @@ def __init__(self, settings: dict): super().__init__(settings) shared = SharedObjects.get() self.lifts = {} - self._room_wall_material = ba.Material() + self._room_wall_material = bs.Material() self._room_wall_material.add_actions( actions=( ('modify_part_collision', 'collide', False), ('modify_part_collision', 'physical', False) )) - self._queen_material = ba.Material() + self._queen_material = bs.Material() self._queen_material.add_actions( conditions=('they_have_material', self._room_wall_material), actions=( @@ -74,7 +75,7 @@ def __init__(self, settings: dict): ('modify_part_collision', 'collide', True), ('modify_part_collision', 'physical', True) )) - self._real_wall_material = ba.Material() + self._real_wall_material = bs.Material() self._real_wall_material.add_actions( actions=( ('modify_part_collision', 'collide', True), @@ -90,17 +91,17 @@ def __init__(self, settings: dict): )) def on_begin(self): - ba.getactivity().globalsnode.happy_thoughts_mode = True + bs.getactivity().globalsnode.happy_thoughts_mode = True super().on_begin() self.make_map() def _spawn_flag(self) -> None: - ba.playsound(self._swipsound) + self._swipsound.play() self._flash_flag_spawn() assert self._flag_spawn_pos is not None shared = SharedObjects.get() self._flag = spaz.Spaz((0, 0, 0), character="Pixel").autoretain() - self._flag.handlemessage(ba.StandMessage((0, 14.63, -5.52), 93)) + self._flag.handlemessage(bs.StandMessage((0, 14.63, -5.52), 93)) self._flag.node.hold_position_pressed = True self._flag.node.materials = (self._queen_material, shared.object_material) # self._flag.node.extras_material= tuple(list(self._flag.node.extras_material).append(self._queen_materia)) @@ -108,7 +109,7 @@ def _spawn_flag(self) -> None: self._flag.hitpoints_max = 5000 self._flag_state = FlagState.NEW - self._flag_light = ba.newnode( + self._flag_light = bs.newnode( 'light', owner=self._flag.node, attrs={'intensity': 0.2, 'radius': 0.3, 'color': (0.2, 0.2, 0.2)}, @@ -136,7 +137,7 @@ def _update_flag_state(self) -> None: player.actor.node.hold_node == self._flag.node ) except Exception: - ba.print_exception('Error checking hold flag.') + babase.print_exception('Error checking hold flag.') if holdingflag: self._holding_players.append(player) player.team.holdingflag = True @@ -158,43 +159,43 @@ def _update_flag_state(self) -> None: self._scoring_team = None if self._flag_state != prevstate: - ba.playsound(self._swipsound) + self._swipsound.play() def handlemessage(self, msg: Any) -> Any: - if isinstance(msg, ba.PlayerDiedMessage): + if isinstance(msg, bs.PlayerDiedMessage): # Augment standard behavior. super().handlemessage(msg) self.respawn_player(msg.getplayer(Player)) - elif isinstance(msg, (ba.PickedUpMessage, ba.DroppedMessage)): + elif isinstance(msg, (bs.PickedUpMessage, bs.DroppedMessage)): self._update_flag_state() else: super().handlemessage(msg) def make_map(self): shared = SharedObjects.get() - _ba.get_foreground_host_activity()._map.leftwall.materials = [ + bs.get_foreground_host_activity()._map.leftwall.materials = [ shared.footing_material, self._real_wall_material] - _ba.get_foreground_host_activity()._map.rightwall.materials = [ + bs.get_foreground_host_activity()._map.rightwall.materials = [ shared.footing_material, self._real_wall_material] - _ba.get_foreground_host_activity()._map.topwall.materials = [ + bs.get_foreground_host_activity()._map.topwall.materials = [ shared.footing_material, self._real_wall_material] - self.floorwall1 = ba.newnode('region', attrs={'position': (-10, 5, -5.52), 'scale': + self.floorwall1 = bs.newnode('region', attrs={'position': (-10, 5, -5.52), 'scale': (15, 0.2, 2), 'type': 'box', 'materials': [shared.footing_material, self._real_wall_material]}) - self.floorwall2 = ba.newnode('region', attrs={'position': (10, 5, -5.52), 'scale': ( + self.floorwall2 = bs.newnode('region', attrs={'position': (10, 5, -5.52), 'scale': ( 15, 0.2, 2), 'type': 'box', 'materials': [shared.footing_material, self._real_wall_material]}) - self.wall1 = ba.newnode('region', attrs={'position': (0, 11, -6.90), 'scale': ( + self.wall1 = bs.newnode('region', attrs={'position': (0, 11, -6.90), 'scale': ( 35.4, 20, 1), 'type': 'box', 'materials': [shared.footing_material, self._real_wall_material]}) - self.wall2 = ba.newnode('region', attrs={'position': (0, 11, -4.14), 'scale': ( + self.wall2 = bs.newnode('region', attrs={'position': (0, 11, -4.14), 'scale': ( 35.4, 20, 1), 'type': 'box', 'materials': [shared.footing_material, self._real_wall_material]}) - ba.newnode('locator', attrs={'shape': 'box', 'position': (-10, 5, -5.52), 'color': ( + bs.newnode('locator', attrs={'shape': 'box', 'position': (-10, 5, -5.52), 'color': ( 0, 0, 0), 'opacity': 1, 'draw_beauty': True, 'additive': False, 'size': (15, 0.2, 2)}) - ba.newnode('locator', attrs={'shape': 'box', 'position': (10, 5, -5.52), 'color': ( + bs.newnode('locator', attrs={'shape': 'box', 'position': (10, 5, -5.52), 'color': ( 0, 0, 0), 'opacity': 1, 'draw_beauty': True, 'additive': False, 'size': (15, 0.2, 2)}) self.create_static_step(0, 14.29) @@ -219,25 +220,25 @@ def make_map(self): self.create_static_step(-3, 10) # create queen personal room - self.room_wall_left = ba.newnode('region', attrs={'position': (-3.633, 16.63, -5.52), 'scale': + self.room_wall_left = bs.newnode('region', attrs={'position': (-3.633, 16.63, -5.52), 'scale': (2, 4, 5), 'type': 'box', 'materials': [shared.footing_material, self._room_wall_material]}) - self.room_wall_right = ba.newnode('region', attrs={'position': (3.533, 16.63, -5.52), 'scale': + self.room_wall_right = bs.newnode('region', attrs={'position': (3.533, 16.63, -5.52), 'scale': (2, 4, 5), 'type': 'box', 'materials': [shared.footing_material, self._room_wall_material]}) def create_static_step(self, x, y): shared = SharedObjects.get() - ba.newnode('region', attrs={'position': (x, y, -5.52), 'scale': (5.5, 0.1, 6), + bs.newnode('region', attrs={'position': (x, y, -5.52), 'scale': (5.5, 0.1, 6), 'type': 'box', 'materials': [shared.footing_material, self._real_wall_material]}) - ba.newnode('locator', attrs={'shape': 'box', 'position': (x, y, -5.52), 'color': ( + bs.newnode('locator', attrs={'shape': 'box', 'position': (x, y, -5.52), 'color': ( 1, 1, 0), 'opacity': 1, 'draw_beauty': True, 'additive': False, 'size': (5.5, 0.1, 2)}) def create_slope(self, x, y, backslash): shared = SharedObjects.get() for _ in range(0, 21): - ba.newnode('region', attrs={'position': (x, y, -5.52), 'scale': (0.2, 0.1, 6), + bs.newnode('region', attrs={'position': (x, y, -5.52), 'scale': (0.2, 0.1, 6), 'type': 'box', 'materials': [shared.footing_material, self._real_wall_material]}) - ba.newnode('locator', attrs={'shape': 'box', 'position': (x, y, -5.52), 'color': ( + bs.newnode('locator', attrs={'shape': 'box', 'position': (x, y, -5.52), 'color': ( 1, 1, 0), 'opacity': 1, 'draw_beauty': True, 'additive': False, 'size': (0.2, 0.1, 2)}) if backslash: x = x + 0.1 @@ -291,7 +292,7 @@ class mapdefs: 0.5245740665, 0.5245740665, 0.01941146064) -class CreativeThoughts(ba.Map): +class CreativeThoughts(bs.Map): """Freaking map by smoothy.""" defs = mapdefs @@ -312,26 +313,26 @@ def get_preview_texture_name(cls) -> str: @classmethod def on_preload(cls) -> Any: data: Dict[str, Any] = { - 'model': ba.getmodel('alwaysLandLevel'), - 'bottom_model': ba.getmodel('alwaysLandLevelBottom'), - 'bgmodel': ba.getmodel('alwaysLandBG'), - 'collide_model': ba.getcollidemodel('alwaysLandLevelCollide'), - 'tex': ba.gettexture('alwaysLandLevelColor'), - 'bgtex': ba.gettexture('alwaysLandBGColor'), - 'vr_fill_mound_model': ba.getmodel('alwaysLandVRFillMound'), - 'vr_fill_mound_tex': ba.gettexture('vrFillMound') + 'mesh': bs.getmesh('alwaysLandLevel'), + 'bottom_mesh': bs.getmesh('alwaysLandLevelBottom'), + 'bgmesh': bs.getmesh('alwaysLandBG'), + 'collision_mesh': bs.getcollisionmesh('alwaysLandLevelCollide'), + 'tex': bs.gettexture('alwaysLandLevelColor'), + 'bgtex': bs.gettexture('alwaysLandBGColor'), + 'vr_fill_mound_mesh': bs.getmesh('alwaysLandVRFillMound'), + 'vr_fill_mound_tex': bs.gettexture('vrFillMound') } return data @classmethod - def get_music_type(cls) -> ba.MusicType: - return ba.MusicType.FLYING + def get_music_type(cls) -> bs.MusicType: + return bs.MusicType.FLYING def __init__(self) -> None: super().__init__(vr_overlay_offset=(0, -3.7, 2.5)) shared = SharedObjects.get() - self._fake_wall_material = ba.Material() - self._real_wall_material = ba.Material() + self._fake_wall_material = bs.Material() + self._real_wall_material = bs.Material() self._fake_wall_material.add_actions( conditions=(('they_are_younger_than', 9000), 'and', ('they_have_material', shared.player_material)), @@ -347,29 +348,29 @@ def __init__(self) -> None: ('modify_part_collision', 'physical', True) )) - self.background = ba.newnode( + self.background = bs.newnode( 'terrain', attrs={ - 'model': self.preloaddata['bgmodel'], + 'mesh': self.preloaddata['bgmesh'], 'lighting': False, 'background': True, - 'color_texture': ba.gettexture("rampageBGColor") + 'color_texture': bs.gettexture("rampageBGColor") }) - self.leftwall = ba.newnode('region', attrs={'position': (-17.75152479, 13, -5.52), 'scale': ( + self.leftwall = bs.newnode('region', attrs={'position': (-17.75152479, 13, -5.52), 'scale': ( 0.1, 15.5, 2), 'type': 'box', 'materials': [shared.footing_material, self._real_wall_material]}) - self.rightwall = ba.newnode('region', attrs={'position': (17.75, 13, -5.52), 'scale': ( + self.rightwall = bs.newnode('region', attrs={'position': (17.75, 13, -5.52), 'scale': ( 0.1, 15.5, 2), 'type': 'box', 'materials': [shared.footing_material, self._real_wall_material]}) - self.topwall = ba.newnode('region', attrs={'position': (0, 21.0, -5.52), 'scale': ( + self.topwall = bs.newnode('region', attrs={'position': (0, 21.0, -5.52), 'scale': ( 35.4, 0.2, 2), 'type': 'box', 'materials': [shared.footing_material, self._real_wall_material]}) - ba.newnode('locator', attrs={'shape': 'box', 'position': (-17.75152479, 13, -5.52), 'color': ( + bs.newnode('locator', attrs={'shape': 'box', 'position': (-17.75152479, 13, -5.52), 'color': ( 0, 0, 0), 'opacity': 1, 'draw_beauty': True, 'additive': False, 'size': (0.1, 15.5, 2)}) - ba.newnode('locator', attrs={'shape': 'box', 'position': (17.75, 13, -5.52), 'color': ( + bs.newnode('locator', attrs={'shape': 'box', 'position': (17.75, 13, -5.52), 'color': ( 0, 0, 0), 'opacity': 1, 'draw_beauty': True, 'additive': False, 'size': (0.1, 15.5, 2)}) - ba.newnode('locator', attrs={'shape': 'box', 'position': (0, 21.0, -5.52), 'color': ( + bs.newnode('locator', attrs={'shape': 'box', 'position': (0, 21.0, -5.52), 'color': ( 0, 0, 0), 'opacity': 1, 'draw_beauty': True, 'additive': False, 'size': (35.4, 0.2, 2)}) - gnode = ba.getactivity().globalsnode + gnode = bs.getactivity().globalsnode gnode.happy_thoughts_mode = True gnode.shadow_offset = (0.0, 8.0, 5.0) gnode.tint = (1.3, 1.23, 1.0) @@ -380,9 +381,9 @@ def __init__(self) -> None: self.is_flying = True # throw out some tips on flying - txt = ba.newnode('text', + txt = bs.newnode('text', attrs={ - 'text': ba.Lstr(resource='pressJumpToFlyText'), + 'text': babase.Lstr(resource='pressJumpToFlyText'), 'scale': 1.2, 'maxwidth': 800, 'position': (0, 200), @@ -391,7 +392,7 @@ def __init__(self) -> None: 'h_align': 'center', 'v_attach': 'bottom' }) - cmb = ba.newnode('combine', + cmb = bs.newnode('combine', owner=txt, attrs={ 'size': 4, @@ -399,12 +400,12 @@ def __init__(self) -> None: 'input1': 0.9, 'input2': 0.0 }) - ba.animate(cmb, 'input3', {3.0: 0, 4.0: 1, 9.0: 1, 10.0: 0}) + bs.animate(cmb, 'input3', {3.0: 0, 4.0: 1, 9.0: 1, 10.0: 0}) cmb.connectattr('output', txt, 'color') - ba.timer(10.0, txt.delete) + bs.timer(10.0, txt.delete) try: - ba._map.register_map(CreativeThoughts) + bs._map.register_map(CreativeThoughts) except: pass diff --git a/plugins/minigames/drone_war.py b/plugins/minigames/drone_war.py index 4877afaf..21eafb1a 100644 --- a/plugins/minigames/drone_war.py +++ b/plugins/minigames/drone_war.py @@ -1,3 +1,4 @@ +# Porting to api 8 made easier by baport.(https://github.com/bombsquad-community/baport) # Released under the MIT License. See LICENSE for details. # """ @@ -8,22 +9,22 @@ Website: https://bombsquad-community.web.app Github: https://github.com/bombsquad-community """ -# ba_meta require api 7 +# ba_meta require api 8 # (see https://ballistica.net/wiki/meta-tag-system) from __future__ import annotations from typing import TYPE_CHECKING -import ba -import _ba -from ba._generated.enums import InputType -from bastd.actor.bomb import Blast +import babase +import bascenev1 as bs +from babase._mgen.enums import InputType +from bascenev1lib.actor.bomb import Blast -from bastd.gameutils import SharedObjects -from bastd.actor.playerspaz import PlayerSpaz, PlayerType -from bastd.game.deathmatch import DeathMatchGame, Player -from bastd.actor import spaz +from bascenev1lib.gameutils import SharedObjects +from bascenev1lib.actor.playerspaz import PlayerSpaz, PlayerT +from bascenev1lib.game.deathmatch import DeathMatchGame, Player +from bascenev1lib.actor import spaz if TYPE_CHECKING: from typing import Any, Sequence, Dict, Type, List, Optional, Union @@ -33,11 +34,11 @@ # use drone as long as you want , unlike floater which dies after being idle. -class Drone(ba.Actor): +class Drone(bs.Actor): def __init__(self, spaz): super().__init__() shared = SharedObjects.get() - self._drone_material = ba.Material() + self._drone_material = bs.Material() self.loop_ascend = None self.loop_descend = None self.loop_lr = None @@ -59,45 +60,45 @@ def __init__(self, spaz): ('they_have_material', self._drone_material)), actions=('modify_part_collision', 'physical', False)) - self.node = ba.newnode( + self.node = bs.newnode( 'prop', delegate=self, owner=None, attrs={ 'position': spaz.node.position, - 'model': ba.getmodel('landMine'), - 'light_model': ba.getmodel('landMine'), + 'mesh': bs.getmesh('landMine'), + 'light_mesh': bs.getmesh('landMine'), 'body': 'landMine', 'body_scale': 1, - 'model_scale': 1, + 'mesh_scale': 1, 'shadow_size': 0.25, 'density': 999999, 'gravity_scale': 0.0, - 'color_texture': ba.gettexture('achievementCrossHair'), + 'color_texture': bs.gettexture('achievementCrossHair'), 'reflection': 'soft', 'reflection_scale': [0.25], 'materials': [shared.footing_material, self._drone_material] }) - self.grab_node = ba.newnode( + self.grab_node = bs.newnode( 'prop', owner=self.node, attrs={ 'position': (0, 0, 0), 'body': 'sphere', - 'model': None, + 'mesh': None, 'color_texture': None, 'body_scale': 0.2, 'reflection': 'powerup', 'density': 999999, 'reflection_scale': [1.0], - 'model_scale': 0.2, + 'mesh_scale': 0.2, 'gravity_scale': 0, 'shadow_size': 0.1, 'is_area_of_interest': True, 'materials': [shared.object_material, self._drone_material] }) self.node.connectattr('position', self.grab_node, 'position') - self._rcombine = ba.newnode('combine', + self._rcombine = bs.newnode('combine', owner=self.node, attrs={ 'input0': self.spaz.node.position[0], @@ -119,12 +120,12 @@ def fire(self): def ascend(self): def loop(): if self.node.exists(): - ba.animate(self._rcombine, 'input1', { + bs.animate(self._rcombine, 'input1', { 0: self.node.position[1], 1: self.node.position[1] + 2 }) loop() - self.loop_ascend = ba.Timer(1, loop, repeat=True) + self.loop_ascend = bs.Timer(1, loop, repeat=True) def pause_movement(self): self.loop_ascend = None @@ -132,12 +133,12 @@ def pause_movement(self): def decend(self): def loop(): if self.node.exists(): - ba.animate(self._rcombine, 'input1', { + bs.animate(self._rcombine, 'input1', { 0: self.node.position[1], 1: self.node.position[1] - 2 }) loop() - self.loop_ascend = ba.Timer(1, loop, repeat=True) + self.loop_ascend = bs.Timer(1, loop, repeat=True) def pause_lr(self): self.loop_lr = None @@ -148,7 +149,7 @@ def pause_ud(self): def left_(self, value=-1): def loop(): if self.node.exists(): - ba.animate(self._rcombine, 'input0', { + bs.animate(self._rcombine, 'input0', { 0: self.node.position[0], 1: self.node.position[0] + 2 * value }) @@ -158,12 +159,12 @@ def loop(): self.x_direction = value self.z_direction = 0 loop() - self.loop_lr = ba.Timer(1, loop, repeat=True) + self.loop_lr = bs.Timer(1, loop, repeat=True) def right_(self, value=1): def loop(): if self.node.exists(): - ba.animate(self._rcombine, 'input0', { + bs.animate(self._rcombine, 'input0', { 0: self.node.position[0], 1: self.node.position[0] + 2 * value }) @@ -173,12 +174,12 @@ def loop(): self.x_direction = value self.z_direction = 0 loop() - self.loop_lr = ba.Timer(1, loop, repeat=True) + self.loop_lr = bs.Timer(1, loop, repeat=True) def up_(self, value=1): def loop(): if self.node.exists(): - ba.animate(self._rcombine, 'input2', { + bs.animate(self._rcombine, 'input2', { 0: self.node.position[2], 1: self.node.position[2] - 2 * value }) @@ -188,12 +189,12 @@ def loop(): self.x_direction = 0 self.z_direction = - value loop() - self.loop_ud = ba.Timer(1, loop, repeat=True) + self.loop_ud = bs.Timer(1, loop, repeat=True) def down_(self, value=-1): def loop(): if self.node.exists(): - ba.animate(self._rcombine, 'input2', { + bs.animate(self._rcombine, 'input2', { 0: self.node.position[2], 1: self.node.position[2] - 2 * value }) @@ -203,17 +204,17 @@ def loop(): self.x_direction = 0 self.z_direction = - value loop() - self.loop_ud = ba.Timer(1, loop, repeat=True) + self.loop_ud = bs.Timer(1, loop, repeat=True) def handlemessage(self, msg): - if isinstance(msg, ba.DieMessage): + if isinstance(msg, bs.DieMessage): self.node.delete() self.grab_node.delete() self.loop_ascend = None self.loop_ud = None self.loop_lr = None - elif isinstance(msg, ba.OutOfBoundsMessage): - self.handlemessage(ba.DieMessage()) + elif isinstance(msg, bs.OutOfBoundsMessage): + self.handlemessage(bs.DieMessage()) else: super().handlemessage(msg) @@ -224,7 +225,7 @@ class RocketFactory: """Quake Rocket factory""" def __init__(self) -> None: - self.ball_material = ba.Material() + self.ball_material = bs.Material() self.ball_material.add_actions( conditions=((('we_are_younger_than', 5), 'or', @@ -251,7 +252,7 @@ def __init__(self) -> None: @classmethod def get(cls): """Get factory if exists else create new""" - activity = ba.getactivity() + activity = bs.getactivity() if hasattr(activity, STORAGE_ATTR_NAME): return getattr(activity, STORAGE_ATTR_NAME) factory = cls() @@ -263,30 +264,30 @@ class RocketLauncher: """Very dangerous weapon""" def __init__(self): - self.last_shot = ba.time() + self.last_shot = bs.time() def give(self, spaz: spaz.Spaz) -> None: """Give spaz a rocket launcher""" spaz.punch_callback = self.shot - self.last_shot = ba.time() + self.last_shot = bs.time() # FIXME # noinspection PyUnresolvedReferences def shot(self, spaz, x, z, position) -> None: """Release a rocket""" - time = ba.time() + time = bs.time() if time - self.last_shot > 0.6: self.last_shot = time direction = [x, 0, z] direction[1] = 0.0 - mag = 10.0 / 1 if ba.Vec3(*direction).length() == 0 else ba.Vec3(*direction).length() + mag = 10.0 / 1 if babase.Vec3(*direction).length() == 0 else babase.Vec3(*direction).length() vel = [v * mag for v in direction] Rocket(position=position, velocity=vel, - owner=spaz.getplayer(ba.Player), - source_player=spaz.getplayer(ba.Player), + owner=spaz.getplayer(bs.Player), + source_player=spaz.getplayer(bs.Player), color=spaz.node.color).autoretain() @@ -294,7 +295,7 @@ class ImpactMessage: """Rocket touched something""" -class Rocket(ba.Actor): +class Rocket(bs.Actor): """Epic rocket from rocket launcher""" def __init__(self, @@ -309,16 +310,16 @@ def __init__(self, self._color = color factory = RocketFactory.get() - self.node = ba.newnode('prop', + self.node = bs.newnode('prop', delegate=self, attrs={ 'position': position, 'velocity': velocity, - 'model': ba.getmodel('impactBomb'), + 'mesh': bs.getmesh('impactBomb'), 'body': 'sphere', - 'color_texture': ba.gettexture( + 'color_texture': bs.gettexture( 'bunnyColor'), - 'model_scale': 0.2, + 'mesh_scale': 0.2, 'is_area_of_interest': True, 'body_scale': 0.8, 'materials': [ @@ -328,17 +329,17 @@ def __init__(self, self.node.extra_acceleration = (self.node.velocity[0] * 200, 0, self.node.velocity[2] * 200) - self._life_timer = ba.Timer( - 5, ba.WeakCall(self.handlemessage, ba.DieMessage())) + self._life_timer = bs.Timer( + 5, bs.WeakCall(self.handlemessage, bs.DieMessage())) - self._emit_timer = ba.Timer(0.001, ba.WeakCall(self.emit), repeat=True) + self._emit_timer = bs.Timer(0.001, bs.WeakCall(self.emit), repeat=True) self.base_pos_y = self.node.position[1] - ba.camerashake(5.0) + bs.camerashake(5.0) def emit(self) -> None: """Emit a trace after rocket""" - ba.emitfx(position=self.node.position, + bs.emitfx(position=self.node.position, scale=0.4, spread=0.01, chunk_type='spark') @@ -346,7 +347,7 @@ def emit(self) -> None: return self.node.position = (self.node.position[0], self.base_pos_y, self.node.position[2]) # ignore y - ba.newnode('explosion', + bs.newnode('explosion', owner=self.node, attrs={ 'position': self.node.position, @@ -358,9 +359,9 @@ def handlemessage(self, msg: Any) -> Any: """Message handling for rocket""" super().handlemessage(msg) if isinstance(msg, ImpactMessage): - self.node.handlemessage(ba.DieMessage()) + self.node.handlemessage(bs.DieMessage()) - elif isinstance(msg, ba.DieMessage): + elif isinstance(msg, bs.DieMessage): if self.node: Blast(position=self.node.position, blast_radius=2, @@ -369,25 +370,25 @@ def handlemessage(self, msg: Any) -> Any: self.node.delete() self._emit_timer = None - elif isinstance(msg, ba.OutOfBoundsMessage): - self.handlemessage(ba.DieMessage()) + elif isinstance(msg, bs.OutOfBoundsMessage): + self.handlemessage(bs.DieMessage()) -# ba_meta export game +# ba_meta export bascenev1.GameActivity class ChooseQueen(DeathMatchGame): name = 'Drone War' @classmethod - def supports_session_type(cls, sessiontype: Type[ba.Session]) -> bool: - return issubclass(sessiontype, ba.DualTeamSession) + def supports_session_type(cls, sessiontype: Type[bs.Session]) -> bool: + return issubclass(sessiontype, bs.DualTeamSession) @classmethod - def get_supported_maps(cls, sessiontype: Type[ba.Session]) -> List[str]: + def get_supported_maps(cls, sessiontype: Type[bs.Session]) -> List[str]: return ['Football Stadium'] def spawn_player_spaz( self, - player: PlayerType, + player: PlayerT, position: Sequence[float] | None = None, angle: float | None = None, ) -> PlayerSpaz: @@ -398,29 +399,29 @@ def spawn_player_spaz( def on_begin(self): super().on_begin() shared = SharedObjects.get() - self.ground_material = ba.Material() + self.ground_material = bs.Material() self.ground_material.add_actions( conditions=('they_have_material', shared.player_material), actions=( ('modify_part_collision', 'collide', True), - ('call', 'at_connect', ba.Call(self._handle_player_collide)), + ('call', 'at_connect', babase.Call(self._handle_player_collide)), ), ) pos = (0, 0.1, -5) - self.main_region = ba.newnode('region', attrs={'position': pos, 'scale': ( + self.main_region = bs.newnode('region', attrs={'position': pos, 'scale': ( 30, 0.001, 23), 'type': 'box', 'materials': [shared.footing_material, self.ground_material]}) def _handle_player_collide(self): try: - player = ba.getcollision().opposingnode.getdelegate( + player = bs.getcollision().opposingnode.getdelegate( PlayerSpaz, True) - except ba.NotFoundError: + except bs.NotFoundError: return if player.is_alive(): player.shatter(True) def spawn_drone(self, spaz): - with ba.Context(_ba.get_foreground_host_activity()): + with bs.get_foreground_host_activity().context: drone = Drone(spaz) r_launcher = RocketLauncher() diff --git a/plugins/minigames/hot_potato.py b/plugins/minigames/hot_potato.py index 2eed1dc8..9acc3553 100644 --- a/plugins/minigames/hot_potato.py +++ b/plugins/minigames/hot_potato.py @@ -1,3 +1,4 @@ +# Porting to api 8 made easier by baport.(https://github.com/bombsquad-community/baport) """ Hot Potato by TheMikirog#1984 @@ -13,20 +14,23 @@ """ -# ba_meta require api 7 +# ba_meta require api 8 from __future__ import annotations from typing import TYPE_CHECKING # Define only what we need and nothing more -import ba -from bastd.actor.spaz import SpazFactory -from bastd.actor.spaz import PickupMessage -from bastd.actor.spaz import BombDiedMessage -from bastd.actor.playerspaz import PlayerSpaz -from bastd.actor.bomb import Bomb -from bastd.actor.bomb import Blast +from baenv import TARGET_BALLISTICA_BUILD as build_number +import babase +import bauiv1 as bui +import bascenev1 as bs +from bascenev1lib.actor.spaz import SpazFactory +from bascenev1lib.actor.spaz import PickupMessage +from bascenev1lib.actor.spaz import BombDiedMessage +from bascenev1lib.actor.playerspaz import PlayerSpaz +from bascenev1lib.actor.bomb import Bomb +from bascenev1lib.actor.bomb import Blast from enum import Enum import random @@ -72,7 +76,7 @@ class PlayerState(Enum): # Here's the behavior of each icon. -class Icon(ba.Actor): +class Icon(bs.Actor): """Creates in in-game icon on screen.""" def __init__(self, @@ -88,11 +92,11 @@ def __init__(self, self._player = player self._name_scale = name_scale - self._outline_tex = ba.gettexture('characterIconMask') + self._outline_tex = bui.gettexture('characterIconMask') # Character portrait icon = player.get_icon() - self.node = ba.newnode('image', + self.node = bs.newnode('image', delegate=self, attrs={ 'texture': icon['texture'], @@ -106,12 +110,12 @@ def __init__(self, 'attach': 'bottomCenter' }) # Player name - self._name_text = ba.newnode( + self._name_text = bs.newnode( 'text', owner=self.node, attrs={ - 'text': ba.Lstr(value=player.getname()), - 'color': ba.safecolor(player.team.color), + 'text': babase.Lstr(value=player.getname()), + 'color': babase.safecolor(player.team.color), 'h_align': 'center', 'v_align': 'center', 'vr_depth': 410, @@ -122,7 +126,7 @@ def __init__(self, 'v_attach': 'bottom' }) # Status text (such as Marked!, Stunned! and You're Out!) - self._marked_text = ba.newnode( + self._marked_text = bs.newnode( 'text', owner=self.node, attrs={ @@ -137,11 +141,11 @@ def __init__(self, 'v_attach': 'bottom' }) # Status icon overlaying the character portrait - self._marked_icon = ba.newnode( + self._marked_icon = bs.newnode( 'text', owner=self.node, attrs={ - 'text': ba.charstr(ba.SpecialChar.HAL), + 'text': babase.charstr(babase.SpecialChar.HAL), 'color': (1, 1, 1), 'h_align': 'center', 'v_align': 'center', @@ -169,7 +173,7 @@ def set_marked_icon(self, type: PlayerState) -> None: self.node.color = (1.0, 1.0, 1.0) # Marked players get ALL of the attention - red portrait, red text and icon overlaying the portrait elif type is PlayerState.MARKED: - self._marked_icon.text = ba.charstr(ba.SpecialChar.HAL) + self._marked_icon.text = babase.charstr(babase.SpecialChar.HAL) self._marked_icon.position = (pos[0] - 1, pos[1] - 13) self._marked_icon.opacity = 1.0 self._marked_text.text = 'Marked!' @@ -179,7 +183,7 @@ def set_marked_icon(self, type: PlayerState) -> None: self.node.color = (1.0, 0.2, 0.2) # Stunned players are just as important - yellow portrait, yellow text and moon icon. elif type is PlayerState.STUNNED: - self._marked_icon.text = ba.charstr(ba.SpecialChar.MOON) + self._marked_icon.text = babase.charstr(babase.SpecialChar.MOON) self._marked_icon.position = (pos[0] - 2, pos[1] - 12) self._marked_icon.opacity = 1.0 self._marked_text.text = 'Stunned!' @@ -189,17 +193,17 @@ def set_marked_icon(self, type: PlayerState) -> None: # Eliminated players get special treatment. # We make the portrait semi-transparent, while adding some visual flair with an fading skull icon and text. elif type is PlayerState.ELIMINATED: - self._marked_icon.text = ba.charstr(ba.SpecialChar.SKULL) + self._marked_icon.text = babase.charstr(babase.SpecialChar.SKULL) self._marked_icon.position = (pos[0] - 2, pos[1] - 12) self._marked_text.text = 'You\'re Out!' self._marked_text.color = (0.5, 0.5, 0.5) # Animate text and icon animation_end_time = 1.5 if bool(self.activity.settings['Epic Mode']) else 3.0 - ba.animate(self._marked_icon, 'opacity', { + bs.animate(self._marked_icon, 'opacity', { 0: 1.0, animation_end_time: 0.0}) - ba.animate(self._marked_text, 'opacity', { + bs.animate(self._marked_text, 'opacity', { 0: 1.0, animation_end_time: 0.0}) @@ -235,7 +239,7 @@ def __init__(self, *args, **kwargs): self.dropped_bombs = [] # we use this to track bombs thrown by the player # Define a marked light - self.marked_light = ba.newnode('light', + self.marked_light = bs.newnode('light', owner=self.node, attrs={'position': self.node.position, 'radius': 0.15, @@ -244,7 +248,7 @@ def __init__(self, *args, **kwargs): 'color': (1.0, 0.0, 0.0)}) # Pulsing red light when the player is Marked - ba.animate(self.marked_light, 'radius', { + bs.animate(self.marked_light, 'radius', { 0: 0.1, 0.3: 0.15, 0.6: 0.1}, @@ -252,12 +256,12 @@ def __init__(self, *args, **kwargs): self.node.connectattr('position_center', self.marked_light, 'position') # Marked timer. It should be above our head, so we attach the text to the offset that's attached to the player. - self.marked_timer_offset = ba.newnode('math', owner=self.node, attrs={ + self.marked_timer_offset = bs.newnode('math', owner=self.node, attrs={ 'input1': (0, 1.2, 0), 'operation': 'add'}) self.node.connectattr('torso_position', self.marked_timer_offset, 'input2') - self.marked_timer_text = ba.newnode('text', owner=self.node, attrs={ + self.marked_timer_text = bs.newnode('text', owner=self.node, attrs={ 'text': '', 'in_world': True, 'shadow': 0.4, @@ -278,7 +282,7 @@ def drop_bomb(self) -> stdbomb.Bomb | None: # Add our bomb to the list of our tracked bombs self.dropped_bombs.append(bomb) # Bring a light - bomb.bomb_marked_light = ba.newnode('light', + bomb.bomb_marked_light = bs.newnode('light', owner=bomb.node, attrs={'position': bomb.node.position, 'radius': 0.04, @@ -291,7 +295,7 @@ def drop_bomb(self) -> stdbomb.Bomb | None: self.set_bombs_marked() # When the bomb physics node dies, call a function. bomb.node.add_death_action( - ba.WeakCall(self.bomb_died, bomb)) + bs.WeakCall(self.bomb_died, bomb)) # Here's the function that gets called when one of the player's bombs dies. # We reference the player's dropped_bombs list and remove the bomb that died. @@ -309,7 +313,7 @@ def set_bombs_marked(self): # Since our gamemode relies heavily on players passing the mark to other players # we need to have access to this message. This gets called when the player takes damage for any reason. def handlemessage(self, msg): - if isinstance(msg, ba.HitMessage): + if isinstance(msg, bs.HitMessage): # This is basically the same HitMessage code as in the original Spaz. # The only difference is that there is no health bar and you can't die with punches or bombs. # Also some useless or redundant code was removed. @@ -326,9 +330,7 @@ def handlemessage(self, msg): # If the attacker is healthy and we're stunned, do a flash and play a sound, then ignore the rest of the code. if self.source_player.state == PlayerState.STUNNED and msg._source_player != PlayerState.MARKED: self.node.handlemessage('flash') - ba.playsound(SpazFactory.get().block_sound, - 1.0, - position=self.node.position) + SpazFactory.get().block_sound.play(1.0, position=self.node.position) return True # Here's all the damage and force calculations unchanged from the source. @@ -360,11 +362,11 @@ def handlemessage(self, msg): sound = SpazFactory.get().punch_sound else: sound = SpazFactory.get().punch_sound_weak - ba.playsound(sound, 1.0, position=self.node.position) + sound.play(1.0, position=self.node.position) # Throw up some chunks. assert msg.force_direction is not None - ba.emitfx(position=msg.pos, + bs.emitfx(position=msg.pos, velocity=(msg.force_direction[0] * 0.5, msg.force_direction[1] * 0.5, msg.force_direction[2] * 0.5), @@ -372,7 +374,7 @@ def handlemessage(self, msg): scale=0.3, spread=0.03) - ba.emitfx(position=msg.pos, + bs.emitfx(position=msg.pos, chunk_type='sweat', velocity=(msg.force_direction[0] * 1.3, msg.force_direction[1] * 1.3 + 5.0, @@ -387,7 +389,7 @@ def handlemessage(self, msg): msg.pos[1] + msg.force_direction[1] * 0.02, msg.pos[2] + msg.force_direction[2] * 0.02) flash_color = (1.0, 0.8, 0.4) - light = ba.newnode( + light = bs.newnode( 'light', attrs={ 'position': punchpos, @@ -396,20 +398,20 @@ def handlemessage(self, msg): 'height_attenuated': False, 'color': flash_color }) - ba.timer(0.06, light.delete) + bs.timer(0.06, light.delete) - flash = ba.newnode('flash', + flash = bs.newnode('flash', attrs={ 'position': punchpos, 'size': 0.17 + 0.17 * hurtiness, 'color': flash_color }) - ba.timer(0.06, flash.delete) + bs.timer(0.06, flash.delete) # Physics collision particles. if msg.hit_type == 'impact': assert msg.force_direction is not None - ba.emitfx(position=msg.pos, + bs.emitfx(position=msg.pos, velocity=(msg.force_direction[0] * 2.0, msg.force_direction[1] * 2.0, msg.force_direction[2] * 2.0), @@ -435,9 +437,9 @@ def handlemessage(self, msg): # Let's get all collision data if we can. Otherwise cancel. try: - collision = ba.getcollision() + collision = bs.getcollision() opposingnode = collision.opposingnode - except ba.NotFoundError: + except bs.NotFoundError: return True # Our grabber needs to be a Spaz @@ -447,9 +449,7 @@ def handlemessage(self, msg): # It's the same sound and flashing behavior as hitting a stunned player as a healthy player. if (opposingnode.source_player.state == PlayerState.STUNNED and self.source_player.state != PlayerState.MARKED): opposingnode.handlemessage('flash') - ba.playsound(SpazFactory.get().block_sound, - 1.0, - position=opposingnode.position) + SpazFactory.get().block_sound.play(1.0, position=opposingnode.position) return True # If they're marked and we're healthy or stunned, pass that mark along to us. elif opposingnode.source_player.state in [PlayerState.REGULAR, PlayerState.STUNNED] and self.source_player.state == PlayerState.MARKED: @@ -458,10 +458,10 @@ def handlemessage(self, msg): # Our work is done. Continue with the rest of the grabbing behavior as usual. super().handlemessage(msg) # Dying is important in this gamemode and as such we need to address this behavior. - elif isinstance(msg, ba.DieMessage): + elif isinstance(msg, bs.DieMessage): # If a player left the game, inform our gamemode logic. - if msg.how == ba.DeathType.LEFT_GAME: + if msg.how == bs.DeathType.LEFT_GAME: self.activity.player_left(self.source_player) # If a MARKED or STUNNED player dies, hide the text from the previous spaz. @@ -470,7 +470,7 @@ def handlemessage(self, msg): self.marked_timer_text.color[1], self.marked_timer_text.color[2], 0.0) - ba.animate(self.marked_light, 'intensity', { + bs.animate(self.marked_light, 'intensity', { 0: self.marked_light.intensity, 0.5: 0.0}) @@ -483,7 +483,7 @@ def handlemessage(self, msg): # A concept of a player is very useful to reference if we don't have a player character present (maybe they died). -class Player(ba.Player['Team']): +class Player(bs.Player['Team']): """Our player type for this game.""" def __init__(self) -> None: @@ -535,8 +535,8 @@ def set_state(self, state: PlayerState) -> None: self.stunned_time_remaining = stun_time # Set our stun time remaining # Remove our stun once the time is up - self.stunned_timer = ba.Timer(stun_time + 0.1, ba.Call(self.stun_remove)) - self.stunned_update_timer = ba.Timer(0.1, ba.Call( + self.stunned_timer = bs.Timer(stun_time + 0.1, babase.Call(self.stun_remove)) + self.stunned_update_timer = bs.Timer(0.1, babase.Call( self.stunned_timer_tick), repeat=True) # Call a function every 0.1 seconds self.fall_times += 1 # Increase the amount of times we fell by one # Change the text above the Spaz's head to total stun time @@ -579,8 +579,8 @@ def set_state(self, state: PlayerState) -> None: self.icon.set_marked_icon(state) # Update our icon -# ba_meta export game -class HotPotato(ba.TeamGameActivity[Player, ba.Team]): +# ba_meta export bascenev1.GameActivity +class HotPotato(bs.TeamGameActivity[Player, bs.Team]): # Let's define the basics like the name of the game, description and some tips that should appear at the start of a match. name = 'Hot Potato' @@ -604,8 +604,8 @@ class HotPotato(ba.TeamGameActivity[Player, ba.Team]): # We're gonna distribute end of match session scores based on who dies first and who survives. # First place gets most points, then second, then third. - scoreconfig = ba.ScoreConfig(label='Place', - scoretype=ba.ScoreType.POINTS, + scoreconfig = bs.ScoreConfig(label='Place', + scoretype=bs.ScoreType.POINTS, lower_is_better=True) # These variables are self explanatory too. @@ -614,25 +614,25 @@ class HotPotato(ba.TeamGameActivity[Player, ba.Team]): # Let's define some settings the user can mess around with to fit their needs. available_settings = [ - ba.IntSetting('Elimination Timer', + bs.IntSetting('Elimination Timer', min_value=5, default=15, increment=1, ), - ba.BoolSetting('Marked Players use Impact Bombs', default=False), - ba.BoolSetting('Epic Mode', default=False), + bs.BoolSetting('Marked Players use Impact Bombs', default=False), + bs.BoolSetting('Epic Mode', default=False), ] # Hot Potato is strictly a Free-For-All gamemode, so only picking the gamemode in FFA playlists. @classmethod - def supports_session_type(cls, sessiontype: type[ba.Session]) -> bool: - return issubclass(sessiontype, ba.FreeForAllSession) + def supports_session_type(cls, sessiontype: type[bs.Session]) -> bool: + return issubclass(sessiontype, bs.FreeForAllSession) # Most maps should work in Hot Potato. Generally maps marked as 'melee' are the most versatile map types of them all. # As the name implies, fisticuffs are common forms of engagement. @classmethod - def get_supported_maps(cls, sessiontype: type[ba.Session]) -> list[str]: - return ba.getmaps('melee') + def get_supported_maps(cls, sessiontype: type[bs.Session]) -> list[str]: + return bs.app.classic.getmaps('melee') # Here we define everything the gamemode needs, like sounds and settings. def __init__(self, settings: dict): @@ -640,22 +640,22 @@ def __init__(self, settings: dict): self.settings = settings # Let's define all of the sounds we need. - self._tick_sound = ba.getsound('tick') - self._player_eliminated_sound = ba.getsound('playerDeath') + self._tick_sound = bui.getsound('tick') + self._player_eliminated_sound = bui.getsound('playerDeath') # These next sounds are arrays instead of single sounds. # We'll use that fact later. - self._danger_tick_sounds = [ba.getsound('orchestraHit'), - ba.getsound('orchestraHit2'), - ba.getsound('orchestraHit3')] - self._marked_sounds = [ba.getsound('powerdown01'), - ba.getsound('activateBeep'), - ba.getsound('hiss')] + self._danger_tick_sounds = [bui.getsound('orchestraHit'), + bui.getsound('orchestraHit2'), + bui.getsound('orchestraHit3')] + self._marked_sounds = [bui.getsound('powerdown01'), + bui.getsound('activateBeep'), + bui.getsound('hiss')] # Normally play KOTH music, but switch to Epic music if we're in slow motion. self._epic_mode = bool(settings['Epic Mode']) self.slow_motion = self._epic_mode - self.default_music = (ba.MusicType.EPIC if self._epic_mode else - ba.MusicType.SCARY) + self.default_music = (bs.MusicType.EPIC if self._epic_mode else + bs.MusicType.SCARY) # This description appears below the title card after it comes crashing when the game begins. def get_instance_description(self) -> str | Sequence: @@ -680,7 +680,7 @@ def on_player_join(self, player: Player) -> None: # Returns every single marked player. # This piece of info is used excensively in this gamemode, so it's advantageous to have a function to cut on # work and make the gamemode easier to maintain - def get_marked_players(self) -> Sequence[ba.Player]: + def get_marked_players(self) -> Sequence[bs.Player]: marked_players = [] for p in self.players: if p.state == PlayerState.MARKED: @@ -691,7 +691,7 @@ def get_marked_players(self) -> Sequence[ba.Player]: def mark(self, target: Player) -> None: target.set_state(PlayerState.MARKED) - ba.emitfx(position=target.actor.node.position, + bs.emitfx(position=target.actor.node.position, velocity=target.actor.node.velocity, chunk_type='spark', count=int(20.0+random.random()*20), @@ -738,7 +738,7 @@ def _eliminate_tick(self) -> None: sound_volume = 1.0 / marked_player_amount for target in marked_players: - ba.playsound(self._tick_sound, sound_volume, target.actor.node.position) + self._tick_sound.play(sound_volume, target.actor.node.position) target.actor.marked_timer_text.text = str(self.elimination_timer_display) # When counting down 3, 2, 1 play some dramatic sounds @@ -746,7 +746,7 @@ def _eliminate_tick(self) -> None: # We store our dramatic sounds in an array, so we target a specific element on the array # depending on time remaining. Arrays start at index 0, so we need to decrease # our variable by 1 to get the element index. - ba.playsound(self._danger_tick_sounds[self.elimination_timer_display - 1], 1.5) + self._danger_tick_sounds[self.elimination_timer_display - 1].play(1.5) else: # Elimination timer is up! Let's eliminate all marked players. self.elimination_timer_display -= 1 # Decrease our timer by one second. @@ -763,18 +763,18 @@ def _eliminate_marked_players(self) -> None: velocity=target.actor.node.velocity, blast_radius=3.0, source_player=target).autoretain() - ba.emitfx(position=target.actor.node.position, + bs.emitfx(position=target.actor.node.position, velocity=target.actor.node.velocity, count=int(16.0+random.random()*60), scale=1.5, spread=2, chunk_type='spark') - target.actor.handlemessage(ba.DieMessage(how='marked_elimination')) + target.actor.handlemessage(bs.DieMessage(how='marked_elimination')) target.actor.shatter(extreme=True) self.match_placement.append(target.team) - ba.playsound(self._player_eliminated_sound, 1.0) + self._player_eliminated_sound.play(1.0) # Let the gamemode know a Marked self.marked_players_died() @@ -788,13 +788,13 @@ def marked_players_died(self) -> bool: # Let's add our lone survivor to the match placement list. self.match_placement.append(alive_players[0].team) # Wait a while to let this sink in before we announce our victor. - self._end_game_timer = ba.Timer(1.25, ba.Call(self.end_game)) + self._end_game_timer = bs.Timer(1.25, babase.Call(self.end_game)) else: # There's still players remaining, so let's wait a while before marking a new player. - self.new_mark_timer = ba.Timer(2.0 if self.slow_motion else 4.0, ba.Call(self.new_mark)) + self.new_mark_timer = bs.Timer(2.0 if self.slow_motion else 4.0, babase.Call(self.new_mark)) # Another extensively used function that returns all alive players. - def get_alive_players(self) -> Sequence[ba.Player]: + def get_alive_players(self) -> Sequence[bs.Player]: alive_players = [] for player in self.players: if player.state == PlayerState.ELIMINATED: @@ -829,14 +829,14 @@ def new_mark(self) -> None: # Set time until marked players explode self.elimination_timer_display = self.settings['Elimination Timer'] # Set a timer that calls _eliminate_tick every second - self.marked_tick_timer = ba.Timer(1.0, ba.Call(self._eliminate_tick), repeat=True) + self.marked_tick_timer = bs.Timer(1.0, babase.Call(self._eliminate_tick), repeat=True) # Mark all chosen victims and play a sound for new_victim in all_victims: # _marked_sounds is an array. # To make a nice marked sound effect, I play multiple sounds at once # All of them are contained in the array. for sound in self._marked_sounds: - ba.playsound(sound, 1.0, new_victim.actor.node.position) + sound.play(1.0, new_victim.actor.node.position) self.mark(new_victim) # This function is called when the gamemode first loads. @@ -849,10 +849,10 @@ def on_begin(self) -> None: # End the game if there's only one player if len(self.players) < 2: self.match_placement.append(self.players[0].team) - self._round_end_timer = ba.Timer(0.5, self.end_game) + self._round_end_timer = bs.Timer(0.5, self.end_game) else: # Pick random player(s) to get marked - self.new_mark_timer = ba.Timer(2.0 if self.slow_motion else 5.2, ba.Call(self.new_mark)) + self.new_mark_timer = bs.Timer(2.0 if self.slow_motion else 5.2, babase.Call(self.new_mark)) self._update_icons() # Create player state icons @@ -873,17 +873,17 @@ def _update_icons(self): # I'm gonna modify this function to move the tip text above the icons. def _show_tip(self) -> None: - from ba._gameutils import animate, GameTip - from ba._generated.enums import SpecialChar - from ba._language import Lstr + from bascenev1._gameutils import animate, GameTip + from babase._mgen.enums import SpecialChar + from babase._language import Lstr # If there's any tips left on the list, display one. if self.tips: tip = self.tips.pop(random.randrange(len(self.tips))) tip_title = Lstr(value='${A}:', subs=[('${A}', Lstr(resource='tipText'))]) - icon: ba.Texture | None = None - sound: ba.Sound | None = None + icon: babase.Texture | None = None + sound: babase.Sound | None = None if isinstance(tip, GameTip): icon = tip.icon sound = tip.sound @@ -893,15 +893,15 @@ def _show_tip(self) -> None: # Do a few replacements. tip_lstr = Lstr(translate=('tips', tip), subs=[('${PICKUP}', - ba.charstr(SpecialChar.TOP_BUTTON))]) + babase.charstr(SpecialChar.TOP_BUTTON))]) base_position = (75, 50) tip_scale = 0.8 tip_title_scale = 1.2 - vrmode = ba.app.vr_mode + vrmode = babase.app.vr_mode if build_number < 21282 else babase.app.env.vr t_offs = -350.0 height_offs = 100.0 - tnode = ba.newnode('text', + tnode = bs.newnode('text', attrs={ 'text': tip_lstr, 'scale': tip_scale, @@ -917,7 +917,7 @@ def _show_tip(self) -> None: }) t2pos = (base_position[0] + t_offs - (20 if icon is None else 82), base_position[1] + 2 + height_offs) - t2node = ba.newnode('text', + t2node = bs.newnode('text', owner=tnode, attrs={ 'text': tip_title, @@ -933,7 +933,7 @@ def _show_tip(self) -> None: }) if icon is not None: ipos = (base_position[0] + t_offs - 40, base_position[1] + 1 + height_offs) - img = ba.newnode('image', + img = bs.newnode('image', attrs={ 'texture': icon, 'position': ipos, @@ -945,11 +945,11 @@ def _show_tip(self) -> None: 'attach': 'bottomCenter' }) animate(img, 'opacity', {0: 0, 1.0: 1, 4.0: 1, 5.0: 0}) - ba.timer(5.0, img.delete) + bs.timer(5.0, img.delete) if sound is not None: - ba.playsound(sound) + sound.play() - combine = ba.newnode('combine', + combine = bs.newnode('combine', owner=tnode, attrs={ 'input0': 1.0, @@ -960,7 +960,7 @@ def _show_tip(self) -> None: combine.connectattr('output', tnode, 'color') combine.connectattr('output', t2node, 'color') animate(combine, 'input3', {0: 0, 1.0: 1, 4.0: 1, 5.0: 0}) - ba.timer(5.0, tnode.delete) + bs.timer(5.0, tnode.delete) # This function is called when a player leaves the game. # This is only called when the player already joined with a character. @@ -985,7 +985,7 @@ def player_left(self, player: Player) -> None: player.set_state(PlayerState.ELIMINATED) # This function is called every time a player spawns - def spawn_player(self, player: Player) -> ba.Actor: + def spawn_player(self, player: Player) -> bs.Actor: position = self.map.get_ffa_start_position(self.players) position = (position[0], position[1] - 0.3, # Move the spawn a bit lower @@ -993,8 +993,8 @@ def spawn_player(self, player: Player) -> ba.Actor: name = player.getname() - light_color = ba.normalized_color(player.color) - display_color = ba.safecolor(player.color, target_intensity=0.75) + light_color = babase.normalized_color(player.color) + display_color = babase.safecolor(player.color, target_intensity=0.75) # Here we actually crate the player character spaz = PotatoPlayerSpaz(color=player.color, @@ -1009,20 +1009,20 @@ def spawn_player(self, player: Player) -> ba.Actor: spaz.connect_controls_to_player() # Move to the stand position and add a flash of light - spaz.handlemessage(ba.StandMessage(position, random.uniform(0, 360))) - t = ba.time(ba.TimeType.BASE) - ba.playsound(self._spawn_sound, 1.0, position=spaz.node.position) - light = ba.newnode('light', attrs={'color': light_color}) + spaz.handlemessage(bs.StandMessage(position, random.uniform(0, 360))) + t = bs.time() + self._spawn_sound.play(1.0, position=spaz.node.position) + light = bs.newnode('light', attrs={'color': light_color}) spaz.node.connectattr('position', light, 'position') - ba.animate(light, 'intensity', {0: 0, + bs.animate(light, 'intensity', {0: 0, 0.25: 1, 0.5: 0}) - ba.timer(0.5, light.delete) + bs.timer(0.5, light.delete) # Game reacts to various events def handlemessage(self, msg: Any) -> Any: # This is called if the player dies. - if isinstance(msg, ba.PlayerDiedMessage): + if isinstance(msg, bs.PlayerDiedMessage): super().handlemessage(msg) player = msg.getplayer(Player) @@ -1046,7 +1046,7 @@ def end_game(self) -> None: # Proceed only if the game hasn't ended yet. if self.has_ended(): return - results = ba.GameResults() + results = bs.GameResults() # By this point our match placement list should be filled with all players. # Players that died/left earliest should be the first entries. # We're gonna use array indexes to decide match placements. diff --git a/plugins/minigames/invisible_one.py b/plugins/minigames/invisible_one.py index 3b9bdd82..ad5676ce 100644 --- a/plugins/minigames/invisible_one.py +++ b/plugins/minigames/invisible_one.py @@ -1,3 +1,4 @@ +# Porting to api 8 made easier by baport.(https://github.com/bombsquad-community/baport) # Released under the MIT License. See LICENSE for details. # # By itsre3 @@ -6,39 +7,41 @@ # Besides that, enjoy.......!! """Provides the chosen-one mini-game.""" -# ba_meta require api 7 +# ba_meta require api 8 # (see https://ballistica.net/wiki/meta-tag-system) from __future__ import annotations from typing import TYPE_CHECKING -import ba -from bastd.actor.flag import Flag -from bastd.actor.playerspaz import PlayerSpaz -from bastd.actor.scoreboard import Scoreboard -from bastd.gameutils import SharedObjects +import babase +import bauiv1 as bui +import bascenev1 as bs +from bascenev1lib.actor.flag import Flag +from bascenev1lib.actor.playerspaz import PlayerSpaz +from bascenev1lib.actor.scoreboard import Scoreboard +from bascenev1lib.gameutils import SharedObjects if TYPE_CHECKING: from typing import Any, Type, List, Dict, Optional, Sequence, Union -class Player(ba.Player['Team']): +class Player(bs.Player['Team']): """Our player type for this game.""" def __init__(self) -> None: - self.chosen_light: Optional[ba.NodeActor] = None + self.chosen_light: Optional[bs.NodeActor] = None -class Team(ba.Team[Player]): +class Team(bs.Team[Player]): """Our team type for this game.""" def __init__(self, time_remaining: int) -> None: self.time_remaining = time_remaining -# ba_meta export game -class InvicibleOneGame(ba.TeamGameActivity[Player, Team]): +# ba_meta export bascenev1.GameActivity +class InvicibleOneGame(bs.TeamGameActivity[Player, Team]): """ Game involving trying to remain the one 'invisible one' for a set length of time while everyone else tries to @@ -49,15 +52,15 @@ class InvicibleOneGame(ba.TeamGameActivity[Player, Team]): description = ('Be the invisible one for a length of time to win.\n' 'Kill the invisible one to become it.') available_settings = [ - ba.IntSetting( + bs.IntSetting( 'Invicible One Time', min_value=10, default=30, increment=10, ), - ba.BoolSetting('Invicible one is lazy', default=True), - ba.BoolSetting('Night mode', default=False), - ba.IntChoiceSetting( + bs.BoolSetting('Invicible one is lazy', default=True), + bs.BoolSetting('Night mode', default=False), + bs.IntChoiceSetting( 'Time Limit', choices=[ ('None', 0), @@ -69,7 +72,7 @@ class InvicibleOneGame(ba.TeamGameActivity[Player, Team]): ], default=0, ), - ba.FloatChoiceSetting( + bs.FloatChoiceSetting( 'Respawn Times', choices=[ ('Shorter', 0.25), @@ -80,35 +83,35 @@ class InvicibleOneGame(ba.TeamGameActivity[Player, Team]): ], default=1.0, ), - ba.BoolSetting('Epic Mode', default=False), + bs.BoolSetting('Epic Mode', default=False), ] - scoreconfig = ba.ScoreConfig(label='Time Held') + scoreconfig = bs.ScoreConfig(label='Time Held') @classmethod - def get_supported_maps(cls, sessiontype: Type[ba.Session]) -> List[str]: - return ba.getmaps('keep_away') + def get_supported_maps(cls, sessiontype: Type[bs.Session]) -> List[str]: + return bs.app.classic.getmaps('keep_away') def __init__(self, settings: dict): super().__init__(settings) self._scoreboard = Scoreboard() self._invicible_one_player: Optional[Player] = None - self._swipsound = ba.getsound('swip') - self._countdownsounds: Dict[int, ba.Sound] = { - 10: ba.getsound('announceTen'), - 9: ba.getsound('announceNine'), - 8: ba.getsound('announceEight'), - 7: ba.getsound('announceSeven'), - 6: ba.getsound('announceSix'), - 5: ba.getsound('announceFive'), - 4: ba.getsound('announceFour'), - 3: ba.getsound('announceThree'), - 2: ba.getsound('announceTwo'), - 1: ba.getsound('announceOne') + self._swipsound = bs.getsound('swip') + self._countdownsounds: Dict[int, babase.Sound] = { + 10: bs.getsound('announceTen'), + 9: bs.getsound('announceNine'), + 8: bs.getsound('announceEight'), + 7: bs.getsound('announceSeven'), + 6: bs.getsound('announceSix'), + 5: bs.getsound('announceFive'), + 4: bs.getsound('announceFour'), + 3: bs.getsound('announceThree'), + 2: bs.getsound('announceTwo'), + 1: bs.getsound('announceOne') } self._flag_spawn_pos: Optional[Sequence[float]] = None - self._reset_region_material: Optional[ba.Material] = None + self._reset_region_material: Optional[bs.Material] = None self._flag: Optional[Flag] = None - self._reset_region: Optional[ba.Node] = None + self._reset_region: Optional[bs.Node] = None self._epic_mode = bool(settings['Epic Mode']) self._invicible_one_time = int(settings['Invicible One Time']) self._time_limit = float(settings['Time Limit']) @@ -117,13 +120,13 @@ def __init__(self, settings: dict): # Base class overrides self.slow_motion = self._epic_mode - self.default_music = (ba.MusicType.EPIC - if self._epic_mode else ba.MusicType.CHOSEN_ONE) + self.default_music = (bs.MusicType.EPIC + if self._epic_mode else bs.MusicType.CHOSEN_ONE) def get_instance_description(self) -> Union[str, Sequence]: return 'Show your invisibility powers.' - def create_team(self, sessionteam: ba.SessionTeam) -> Team: + def create_team(self, sessionteam: bs.SessionTeam) -> Team: return Team(time_remaining=self._invicible_one_time) def on_team_join(self, team: Team) -> None: @@ -143,13 +146,13 @@ def on_begin(self) -> None: Flag.project_stand(self._flag_spawn_pos) self._set_invicible_one_player(None) if self._night_mode: - gnode = ba.getactivity().globalsnode + gnode = bs.getactivity().globalsnode gnode.tint = (0.4, 0.4, 0.4) pos = self._flag_spawn_pos - ba.timer(1.0, call=self._tick, repeat=True) + bs.timer(1.0, call=self._tick, repeat=True) - mat = self._reset_region_material = ba.Material() + mat = self._reset_region_material = bs.Material() mat.add_actions( conditions=( 'they_have_material', @@ -159,11 +162,11 @@ def on_begin(self) -> None: ('modify_part_collision', 'collide', True), ('modify_part_collision', 'physical', False), ('call', 'at_connect', - ba.WeakCall(self._handle_reset_collide)), + bs.WeakCall(self._handle_reset_collide)), ), ) - self._reset_region = ba.newnode('region', + self._reset_region = bs.newnode('region', attrs={ 'position': (pos[0], pos[1] + 0.75, pos[2]), @@ -185,24 +188,24 @@ def _handle_reset_collide(self) -> None: # Attempt to get a Player controlling a Spaz that we hit. try: - player = ba.getcollision().opposingnode.getdelegate( + player = bs.getcollision().opposingnode.getdelegate( PlayerSpaz, True).getplayer(Player, True) - except ba.NotFoundError: + except bs.NotFoundError: return if player.is_alive(): self._set_invicible_one_player(player) def _flash_flag_spawn(self) -> None: - light = ba.newnode('light', + light = bs.newnode('light', attrs={ 'position': self._flag_spawn_pos, 'color': (1, 1, 1), 'radius': 0.3, 'height_attenuated': False }) - ba.animate(light, 'intensity', {0: 0, 0.25: 0.5, 0.5: 0}, loop=True) - ba.timer(1.0, light.delete) + bs.animate(light, 'intensity', {0: 0, 0.25: 0.5, 0.5: 0}, loop=True) + bs.timer(1.0, light.delete) def _tick(self) -> None: @@ -212,7 +215,7 @@ def _tick(self) -> None: # This shouldn't happen, but just in case. if not player.is_alive(): - ba.print_error('got dead player as chosen one in _tick') + babase.print_error('got dead player as chosen one in _tick') self._set_invicible_one_player(None) else: scoring_team = player.team @@ -229,9 +232,7 @@ def _tick(self) -> None: # announce numbers we have sounds for if scoring_team.time_remaining in self._countdownsounds: - ba.playsound( - self._countdownsounds[scoring_team.time_remaining]) - + self._countdownsounds[scoring_team.time_remaining].play() # Winner! if scoring_team.time_remaining <= 0: self.end_game() @@ -242,11 +243,11 @@ def _tick(self) -> None: # (Chosen-one player ceasing to exist should # trigger on_player_leave which resets chosen-one) if self._invicible_one_player is not None: - ba.print_error('got nonexistent player as chosen one in _tick') + babase.print_error('got nonexistent player as chosen one in _tick') self._set_invicible_one_player(None) def end_game(self) -> None: - results = ba.GameResults() + results = bs.GameResults() for team in self.teams: results.set_team_score(team, self._invicible_one_time - team.time_remaining) @@ -256,7 +257,7 @@ def _set_invicible_one_player(self, player: Optional[Player]) -> None: existing = self._get_invicible_one_player() if existing: existing.chosen_light = None - ba.playsound(self._swipsound) + self._swipsound.play() if not player: assert self._flag_spawn_pos is not None self._flag = Flag(color=(1, 0.9, 0.2), @@ -266,7 +267,7 @@ def _set_invicible_one_player(self, player: Optional[Player]) -> None: # Create a light to highlight the flag; # this will go away when the flag dies. - ba.newnode('light', + bs.newnode('light', owner=self._flag.node, attrs={ 'position': self._flag_spawn_pos, @@ -287,18 +288,18 @@ def _set_invicible_one_player(self, player: Optional[Player]) -> None: if self._invicible_one_is_lazy: player.actor.connect_controls_to_player( enable_punch=False, enable_pickup=False, enable_bomb=False) - if player.actor.node.torso_model != None: + if player.actor.node.torso_mesh != None: player.actor.node.color_mask_texture = None player.actor.node.color_texture = None - player.actor.node.head_model = None - player.actor.node.torso_model = None - player.actor.node.upper_arm_model = None - player.actor.node.forearm_model = None - player.actor.node.pelvis_model = None - player.actor.node.toes_model = None - player.actor.node.upper_leg_model = None - player.actor.node.lower_leg_model = None - player.actor.node.hand_model = None + player.actor.node.head_mesh = None + player.actor.node.torso_mesh = None + player.actor.node.upper_arm_mesh = None + player.actor.node.forearm_mesh = None + player.actor.node.pelvis_mesh = None + player.actor.node.toes_mesh = None + player.actor.node.upper_leg_mesh = None + player.actor.node.lower_leg_mesh = None + player.actor.node.hand_mesh = None player.actor.node.style = 'cyborg' invi_sound = [] player.actor.node.jump_sounds = invi_sound @@ -311,7 +312,7 @@ def _set_invicible_one_player(self, player: Optional[Player]) -> None: player.actor.node.name = '' def handlemessage(self, msg: Any) -> Any: - if isinstance(msg, ba.PlayerDiedMessage): + if isinstance(msg, bs.PlayerDiedMessage): # Augment standard behavior. super().handlemessage(msg) player = msg.getplayer(Player) diff --git a/plugins/minigames/last_punch_stand.py b/plugins/minigames/last_punch_stand.py index 41fe2810..75d3a402 100644 --- a/plugins/minigames/last_punch_stand.py +++ b/plugins/minigames/last_punch_stand.py @@ -1,17 +1,20 @@ -# ba_meta require api 7 +# Porting to api 8 made easier by baport.(https://github.com/bombsquad-community/baport) +# ba_meta require api 8 from typing import Sequence -import ba -import _ba +import babase +import bauiv1 as bui +import bascenev1 as bs +import _babase import random -from bastd.actor.spaz import Spaz -from bastd.actor.scoreboard import Scoreboard +from bascenev1lib.actor.spaz import Spaz +from bascenev1lib.actor.scoreboard import Scoreboard -class Player(ba.Player['Team']): +class Player(bs.Player['Team']): """Our player type for this game.""" -class Team(ba.Team[Player]): +class Team(bs.Team[Player]): """Our team type for this game.""" def __init__(self) -> None: @@ -39,7 +42,7 @@ def __init__( super().__init__(color, highlight, "Spaz", None, True, True, False, False) self.last_player_attacked_by = None self.stand(pos) - self.loc = ba.newnode( + self.loc = bs.newnode( 'locator', attrs={ 'shape': 'circleOutline', @@ -51,37 +54,37 @@ def __init__( }, ) self.node.connectattr("position", self.loc, "position") - ba.animate_array(self.loc, "size", 1, keys={0: [0.5,], 1: [2,], 1.5: [0.5]}, loop=True) + bs.animate_array(self.loc, "size", 1, keys={0: [0.5,], 1: [2,], 1.5: [0.5]}, loop=True) def handlemessage(self, msg): - if isinstance(msg, ba.FreezeMessage): + if isinstance(msg, bs.FreezeMessage): return - if isinstance(msg, ba.PowerupMessage): + if isinstance(msg, bs.PowerupMessage): if not (msg.poweruptype == "health"): return super().handlemessage(msg) - if isinstance(msg, ba.HitMessage): - self.handlemessage(ba.PowerupMessage("health")) + if isinstance(msg, bs.HitMessage): + self.handlemessage(bs.PowerupMessage("health")) player = msg.get_source_player(Player) if self.is_alive(): self.activity.handlemessage(ChooseingSpazHitMessage(player)) self.last_player_attacked_by = player - elif isinstance(msg, ba.DieMessage): + elif isinstance(msg, bs.DieMessage): player = self.last_player_attacked_by - if msg.how.value != ba.DeathType.GENERIC.value: + if msg.how.value != bs.DeathType.GENERIC.value: self._dead = True self.activity.handlemessage(ChooseingSpazDieMessage(player)) self.loc.delete() def stand(self, pos=(0, 0, 0), angle=0): - self.handlemessage(ba.StandMessage(pos, angle)) + self.handlemessage(bs.StandMessage(pos, angle)) def recolor(self, color, highlight=(1, 1, 1)): self.node.color = color @@ -89,14 +92,14 @@ def recolor(self, color, highlight=(1, 1, 1)): self.loc.color = color -class ChooseBilbord(ba.Actor): +class ChooseBilbord(bs.Actor): def __init__(self, player: Player, delay=0.1) -> None: super().__init__() icon = player.get_icon() self.scale = 100 - self.node = ba.newnode( + self.node = bs.newnode( 'image', delegate=self, attrs={ @@ -111,13 +114,13 @@ def __init__(self, player: Player, delay=0.1) -> None: }, ) - self.name_node = ba.newnode( + self.name_node = bs.newnode( 'text', owner=self.node, attrs={ 'position': (60, -185), - 'text': ba.Lstr(value=player.getname()), - 'color': ba.safecolor(player.team.color), + 'text': babase.Lstr(value=player.getname()), + 'color': babase.safecolor(player.team.color), 'h_align': 'center', 'v_align': 'center', 'vr_depth': 410, @@ -128,26 +131,26 @@ def __init__(self, player: Player, delay=0.1) -> None: }, ) - ba.animate_array(self.node, "scale", keys={ + bs.animate_array(self.node, "scale", keys={ 0 + delay: [0, 0], 0.05 + delay: [self.scale, self.scale]}, size=1) - ba.animate(self.name_node, "scale", {0 + delay: 0, 0.07 + delay: 1}) + bs.animate(self.name_node, "scale", {0 + delay: 0, 0.07 + delay: 1}) def handlemessage(self, msg): super().handlemessage(msg) - if isinstance(msg, ba.DieMessage): - ba.animate_array(self.node, "scale", keys={0: self.node.scale, 0.05: [0, 0]}, size=1) - ba.animate(self.name_node, "scale", {0: self.name_node.scale, 0.07: 0}) + if isinstance(msg, bs.DieMessage): + bs.animate_array(self.node, "scale", keys={0: self.node.scale, 0.05: [0, 0]}, size=1) + bs.animate(self.name_node, "scale", {0: self.name_node.scale, 0.07: 0}) def __delete(): self.node.delete() self.name_node.delete() - ba.timer(0.2, __delete) + bs.timer(0.2, __delete) -# ba_meta export game +# ba_meta export bascenev1.GameActivity -class LastPunchStand(ba.TeamGameActivity[Player, Team]): +class LastPunchStand(bs.TeamGameActivity[Player, Team]): name = "Last Punch Stand" description = "Last one punchs the choosing spaz wins" tips = [ @@ -156,11 +159,11 @@ class LastPunchStand(ba.TeamGameActivity[Player, Team]): "evry time you punch the choosing spaz, you will get one point", ] - default_music = ba.MusicType.TO_THE_DEATH + default_music = bs.MusicType.TO_THE_DEATH available_settings = [ - ba.FloatSetting("min time limit (in seconds)", 50.0, min_value=30.0), - ba.FloatSetting("max time limit (in seconds)", 160.0, 60), + bs.FloatSetting("min time limit (in seconds)", 50.0, min_value=30.0), + bs.FloatSetting("max time limit (in seconds)", 160.0, 60), ] @@ -203,12 +206,12 @@ def on_begin(self) -> None: super().on_begin() time_limit = random.randint(self._min_timelimit, self._max_timelimit) self.spaw_bot() - ba.timer(time_limit, self.times_up) + bs.timer(time_limit, self.times_up) self.setup_standard_powerup_drops(False) def end_game(self) -> None: - results = ba.GameResults() + results = bs.GameResults() for team in self.teams: if self.choosed_player and (team.id == self.choosed_player.team.id): team.score += 100 @@ -261,7 +264,7 @@ def handlemessage(self, msg): self.spaw_bot() self.change_choosed_player(None) - elif isinstance(msg, ba.PlayerDiedMessage): + elif isinstance(msg, bs.PlayerDiedMessage): player = msg.getplayer(Player) if not (self.has_ended() or self.times_uped): self.respawn_player(player, 0) diff --git a/plugins/minigames/meteor_shower.py b/plugins/minigames/meteor_shower.py index 0f87f397..5cb2f8c0 100644 --- a/plugins/minigames/meteor_shower.py +++ b/plugins/minigames/meteor_shower.py @@ -1,4 +1,5 @@ -# ba_meta require api 7 +# Porting to api 8 made easier by baport.(https://github.com/bombsquad-community/baport) +# ba_meta require api 8 # (see https://ballistica.net/wiki/meta-tag-system) from __future__ import annotations @@ -6,15 +7,17 @@ import random from typing import TYPE_CHECKING -import ba -from bastd.actor.bomb import Bomb -from bastd.actor.onscreentimer import OnScreenTimer +import babase +import bauiv1 as bui +import bascenev1 as bs +from bascenev1lib.actor.bomb import Bomb +from bascenev1lib.actor.onscreentimer import OnScreenTimer if TYPE_CHECKING: from typing import Any, Sequence -lang = ba.app.lang.language +lang = bs.app.lang.language if lang == 'Spanish': name = 'Lluvia de Meteoritos v2' @@ -48,7 +51,7 @@ random_rain = 'Random Rain' -class Player(ba.Player['Team']): +class Player(bs.Player['Team']): """Our player type for this game.""" def __init__(self) -> None: @@ -56,18 +59,18 @@ def __init__(self) -> None: self.death_time: float | None = None -class Team(ba.Team[Player]): +class Team(bs.Team[Player]): """Our team type for this game.""" -# ba_meta export game -class MeteorShowerv2Game(ba.TeamGameActivity[Player, Team]): +# ba_meta export bascenev1.GameActivity +class MeteorShowerv2Game(bs.TeamGameActivity[Player, Team]): """Minigame involving dodging falling bombs.""" name = name description = 'Dodge the falling bombs.' - scoreconfig = ba.ScoreConfig( - label='Survived', scoretype=ba.ScoreType.MILLISECONDS, version='B' + scoreconfig = bs.ScoreConfig( + label='Survived', scoretype=bs.ScoreType.MILLISECONDS, version='B' ) # Print messages when players die (since its meaningful in this game). @@ -79,10 +82,10 @@ class MeteorShowerv2Game(ba.TeamGameActivity[Player, Team]): @classmethod def get_available_settings( - cls, sessiontype: type[ba.Session] - ) -> list[ba.Setting]: + cls, sessiontype: type[bs.Session] + ) -> list[babase.Setting]: settings = [ - ba.IntChoiceSetting( + bs.IntChoiceSetting( bomb_type, choices=[ ('normal', 0), @@ -95,22 +98,22 @@ def get_available_settings( ], default=0, ), - ba.BoolSetting('Epic Mode', default=False), + bs.BoolSetting('Epic Mode', default=False), ] return settings # We're currently hard-coded for one map. @classmethod - def get_supported_maps(cls, sessiontype: type[ba.Session]) -> list[str]: + def get_supported_maps(cls, sessiontype: type[bs.Session]) -> list[str]: return ['Rampage'] # We support teams, free-for-all, and co-op sessions. @classmethod - def supports_session_type(cls, sessiontype: type[ba.Session]) -> bool: + def supports_session_type(cls, sessiontype: type[bs.Session]) -> bool: return ( - issubclass(sessiontype, ba.DualTeamSession) - or issubclass(sessiontype, ba.FreeForAllSession) - or issubclass(sessiontype, ba.CoopSession) + issubclass(sessiontype, bs.DualTeamSession) + or issubclass(sessiontype, bs.FreeForAllSession) + or issubclass(sessiontype, bs.CoopSession) ) def __init__(self, settings: dict): @@ -138,7 +141,7 @@ def __init__(self, settings: dict): # Some base class overrides: self.default_music = ( - ba.MusicType.EPIC if self._epic_mode else ba.MusicType.SURVIVAL + bs.MusicType.EPIC if self._epic_mode else bs.MusicType.SURVIVAL ) if self._epic_mode: self.slow_motion = True @@ -152,19 +155,19 @@ def on_begin(self) -> None: delay = 5.0 if len(self.players) > 2 else 2.5 if self._epic_mode: delay *= 0.25 - ba.timer(delay, self._decrement_meteor_time, repeat=True) + bs.timer(delay, self._decrement_meteor_time, repeat=True) # Kick off the first wave in a few seconds. delay = 3.0 if self._epic_mode: delay *= 0.25 - ba.timer(delay, self._set_meteor_timer) + bs.timer(delay, self._set_meteor_timer) self._timer = OnScreenTimer() self._timer.start() # Check for immediate end (if we've only got 1 player, etc). - ba.timer(5.0, self._check_end_game) + bs.timer(5.0, self._check_end_game) def on_player_leave(self, player: Player) -> None: # Augment default behavior. @@ -174,7 +177,7 @@ def on_player_leave(self, player: Player) -> None: self._check_end_game() # overriding the default character spawning.. - def spawn_player(self, player: Player) -> ba.Actor: + def spawn_player(self, player: Player) -> bs.Actor: spaz = self.spawn_player_spaz(player) # Let's reconnect this player's controls to this @@ -189,12 +192,12 @@ def spawn_player(self, player: Player) -> ba.Actor: # Various high-level game events come through this method. def handlemessage(self, msg: Any) -> Any: - if isinstance(msg, ba.PlayerDiedMessage): + if isinstance(msg, bs.PlayerDiedMessage): # Augment standard behavior. super().handlemessage(msg) - curtime = ba.time() + curtime = bs.time() # Record the player's moment of death. # assert isinstance(msg.spaz.player @@ -204,15 +207,15 @@ def handlemessage(self, msg: Any) -> Any: # (more accurate looking). # In teams/ffa, allow a one-second fudge-factor so we can # get more draws if players die basically at the same time. - if isinstance(self.session, ba.CoopSession): + if isinstance(self.session, bs.CoopSession): # Teams will still show up if we check now.. check in # the next cycle. - ba.pushcall(self._check_end_game) + babase.pushcall(self._check_end_game) # Also record this for a final setting of the clock. self._last_player_death_time = curtime else: - ba.timer(1.0, self._check_end_game) + bs.timer(1.0, self._check_end_game) else: # Default handler: @@ -229,7 +232,7 @@ def _check_end_game(self) -> None: # In co-op, we go till everyone is dead.. otherwise we go # until one team remains. - if isinstance(self.session, ba.CoopSession): + if isinstance(self.session, bs.CoopSession): if living_team_count <= 0: self.end_game() else: @@ -237,7 +240,7 @@ def _check_end_game(self) -> None: self.end_game() def _set_meteor_timer(self) -> None: - ba.timer( + bs.timer( (1.0 + 0.2 * random.random()) * self._meteor_time, self._drop_bomb_cluster, ) @@ -248,10 +251,10 @@ def _drop_bomb_cluster(self) -> None: # and debug things. loc_test = False if loc_test: - ba.newnode('locator', attrs={'position': (8, 6, -5.5)}) - ba.newnode('locator', attrs={'position': (8, 6, -2.3)}) - ba.newnode('locator', attrs={'position': (-7.3, 6, -5.5)}) - ba.newnode('locator', attrs={'position': (-7.3, 6, -2.3)}) + bs.newnode('locator', attrs={'position': (8, 6, -5.5)}) + bs.newnode('locator', attrs={'position': (8, 6, -2.3)}) + bs.newnode('locator', attrs={'position': (-7.3, 6, -5.5)}) + bs.newnode('locator', attrs={'position': (-7.3, 6, -2.3)}) # Drop several bombs in series. delay = 0.0 @@ -269,7 +272,7 @@ def _drop_bomb_cluster(self) -> None: random.uniform(-3.066, -4.12), 0, ) - ba.timer(delay, ba.Call(self._drop_bomb, pos, vel)) + bs.timer(delay, babase.Call(self._drop_bomb, pos, vel)) delay += 0.1 self._set_meteor_timer() @@ -294,7 +297,7 @@ def _decrement_meteor_time(self) -> None: self._meteor_time = max(0.01, self._meteor_time * 0.9) def end_game(self) -> None: - cur_time = ba.time() + cur_time = bs.time() assert self._timer is not None start_time = self._timer.getstarttime() @@ -325,7 +328,7 @@ def end_game(self) -> None: # Ok now calc game results: set a score for each team and then tell # the game to end. - results = ba.GameResults() + results = bs.GameResults() # Remember that 'free-for-all' mode is simply a special form # of 'teams' mode where each player gets their own team, so we can @@ -346,58 +349,58 @@ def end_game(self) -> None: # ba_meta export plugin -class MeteorShowerv2Coop(ba.Plugin): +class MeteorShowerv2Coop(babase.Plugin): def on_app_running(self) -> None: - ba.app.add_coop_practice_level( - ba.Level( + babase.app.classic.add_coop_practice_level( + bs._level.Level( normal_rain, gametype=MeteorShowerv2Game, settings={bomb_type: 0}, preview_texture_name='rampagePreview', ) ) - ba.app.add_coop_practice_level( - ba.Level( + babase.app.classic.add_coop_practice_level( + bs._level.Level( frozen_rain, gametype=MeteorShowerv2Game, settings={bomb_type: 1}, preview_texture_name='rampagePreview', ) ) - ba.app.add_coop_practice_level( - ba.Level( + babase.app.classic.add_coop_practice_level( + bs._level.Level( sticky_rain, gametype=MeteorShowerv2Game, settings={bomb_type: 2}, preview_texture_name='rampagePreview', ) ) - ba.app.add_coop_practice_level( - ba.Level( + babase.app.classic.add_coop_practice_level( + bs._level.Level( impact_rain, gametype=MeteorShowerv2Game, settings={bomb_type: 3}, preview_texture_name='rampagePreview', ) ) - ba.app.add_coop_practice_level( - ba.Level( + babase.app.classic.add_coop_practice_level( + bs._level.Level( mine_rain, gametype=MeteorShowerv2Game, settings={bomb_type: 4}, preview_texture_name='rampagePreview', ) ) - ba.app.add_coop_practice_level( - ba.Level( + babase.app.classic.add_coop_practice_level( + bs._level.Level( tnt_rain, gametype=MeteorShowerv2Game, settings={bomb_type: 5}, preview_texture_name='rampagePreview', ) ) - ba.app.add_coop_practice_level( - ba.Level( + babase.app.classic.add_coop_practice_level( + bs._level.Level( random_rain, gametype=MeteorShowerv2Game, settings={bomb_type: 6}, diff --git a/plugins/minigames/port_7_to_8.py b/plugins/minigames/port_7_to_8.py new file mode 100644 index 00000000..1a8c94e4 --- /dev/null +++ b/plugins/minigames/port_7_to_8.py @@ -0,0 +1,441 @@ +# Usage: port_7_to_8.py + +# You'll have to manually update the following: +# with ba.Context(_ba.foreground_host_activity()): +# To: +# with _ba.foreground_host_activity().context: +# +# ba.time(timeformat=ba.TimeFormat.MILLISECONDS) +# To: +# ba.time() * 1000 +# +# ba.Timer((POWERUP_WEAR_OFF_TIME - 2000),ba.WeakCall(self._multi_bomb_wear_off_flash),timeformat=ba.TimeFormat.MILLISECONDS) +# To: +# ba.Timer((POWERUP_WEAR_OFF_TIME - 2000 / 1000),ba.WeakCall(self._multi_bomb_wear_off_flash)) + +import re +import sys +import codecs + +def detect_encoding(filename): + encodings = ['utf-8', 'latin-1', 'ascii', 'cp1252'] + for encoding in encodings: + try: + with open(filename, 'rb') as f: + f.read().decode(encoding) + return encoding + except UnicodeDecodeError: + pass + return None + +filename = sys.argv[2] +encoding = detect_encoding(filename) +if encoding: + with open(filename, 'r', encoding=encoding) as f: + print("Porting "+ sys.argv[2]) + content = f.read() +else: + print('Could not detect encoding') + +content = content.replace("# ba_meta require api 7", "# ba_meta require api 8") +content = content.replace("# ba_meta export game", "# ba_meta export bascenev1.GameActivity") + + +content = content.replace("user_agent_string", "legacy_user_agent_string") +content = re.sub(r'^(import\s+[\w]+(\s*,\s*[\w]+)+)', lambda match: re.sub(r'\s*,\s*', '\nimport ', match.group()), content, flags=re.MULTILINE) +content = content.replace("_ba.", "_babase.") +content = content.replace("_ba.", "_babase.") +content = content.replace("ba.", "babase.") +content = content.replace("import _ba", "import _babase") +content = content.replace("from ba import", "from babase import") +content = content.replace("from _ba import", "from _babase import") +content = re.sub(r'\bimport _ba\b', "import _babase", content) +content = re.sub(r'\bimport ba(\b|\.(\w+))', "import babase\nimport bauiv1\nimport bascenev1", content) +match = re.search(r'^(import\s+[\w]+(\s*,\s*[\w]+)*)', content, flags=re.MULTILINE) +affected_methods = ["build_number", "device_name", "config_file_path", "version", "debug_build", "test_build", "data_directory", "python_directory_user", "python_directory_app", "python_directory_app_site", "api_version", "on_tv", "vr_mode","toolbar_test", "arcade_test", "headless_mode", "demo_mode", "protocol_version", "get_connection_to_host_info"] +for word in affected_methods: + if f".{word}" in content: + first_import_index = match.start() + content = content[:first_import_index] + 'from baenv import TARGET_BALLISTICA_BUILD as build_number\n' + content[first_import_index:] +content = content.replace("babase.app.ui", "bauiv1.app.ui_v1") +content = content.replace("babase.app.accounts_v1", "bauiv1.app.classic.accounts") + +################################################################################### +# Comment out one of these as per your requirements, depending whether to +# stay local or if it'll also be needed to transmitted to the clients. + +## For local: +if sys.argv[1] == "client": + content = content.replace("_babase.screenmessage", "bauiv1.screenmessage") + content = content.replace("babase.screenmessage", "bauiv1.screenmessage") + content = content.replace("babase.getsound", "bauiv1.getsound") + content = content.replace("_babase.gettexture", "bauiv1.gettexture") + content = content.replace("babase.gettexture", "bauiv1.gettexture") + content = content.replace("babase.getmesh", "bauiv1.getmesh") + content = content.replace("babase.getcollisionmesh", "bauiv1.getcollisionmesh") +else: +## For transmission: + content = content.replace("_babase.screenmessage", "bascenev1.broadcastmessage") + content = content.replace("babase.screenmessage", "bascenev1.broadcastmessage") + content = content.replace("babase.getsound", "bascenev1.getsound") + content = content.replace("_babase.gettexture", "bascenev1.gettexture") + content = content.replace("babase.gettexture", "bascenev1.gettexture") + content = content.replace("babase.getmesh", "bascenev1.getmesh") + content = content.replace("babase.getcollisionmesh", "bascenev1.getcollisionmesh") +################################################################################### +content = content.replace("babase.getcollidemesh", "bascenev1.getcollisionmesh") +content = content.replace("collide_mesh", "collision_mesh") +content = content.replace("babase.open_url", "bauiv1.open_url") +content = content.replace("babase.IntSetting", "bascenev1.IntSetting") +content = content.replace("babase.IntChoiceSetting", "bascenev1.IntChoiceSetting") +content = content.replace("babase.FloatChoiceSetting", "bascenev1.FloatChoiceSetting") +content = content.replace("babase.BoolSetting", "bascenev1.BoolSetting") +content = content.replace("babase.Actor", "bascenev1.Actor") +content = content.replace("babase.Player", "bascenev1.Player") +content = content.replace("babase.PlayerDiedMessage", "bascenev1.PlayerDiedMessage") +content = content.replace("babase.time", "bascenev1.time") +content = content.replace("babase.Timer", "bascenev1.Timer") +content = content.replace("babase.newnode", "bascenev1.newnode") +content = content.replace("babase.Node", "bascenev1.Node") +content = content.replace("babase.emitfx", "bascenev1.emitfx") +content = content.replace("babase.animate", "bascenev1.animate") +content = content.replace("babase.FreeForAllSession", "bascenev1.FreeForAllSession") +content = content.replace("babase.DualTeamSession", "bascenev1.DualTeamSession") +content = content.replace("babase.MultiTeamSession", "bascenev1.MultiTeamSession") +content = content.replace("babase.EndSession", "bascenev1.EndSession") +content = content.replace("babase.CoopSession", "bascenev1.CoopSession") +content = content.replace("babase.TeamGameActivity", "bascenev1.TeamGameActivity") +content = content.replace("babase.Team", "bascenev1.Team") +content = content.replace("babase.Session", "bascenev1.Session") +content = content.replace("babase.getsession", "bascenev1.getsession") +content = content.replace("babase.Material", "bascenev1.Material") +content = content.replace("babase.WeakCall", "bascenev1.WeakCall") +content = content.replace("babase.DieMessage", "bascenev1.DieMessage") +content = content.replace("babase.OutOfBoundsMessage", "bascenev1.OutOfBoundsMessage") +content = content.replace("babase.DroppedMessage", "bascenev1.DroppedMessage") +content = content.replace("babase.HitMessage", "bascenev1.HitMessage") +content = content.replace("babase.ThawMessage", "bascenev1.ThawMessage") +content = content.replace("babase.NotFoundError", "bascenev1.NotFoundError") +content = content.replace("babase.getcollision", "bascenev1.getcollision") +content = content.replace("babase.app.lang", "bascenev1.app.lang") +content = content.replace("babase.MusicType", "bascenev1.MusicType") +content = content.replace("babase.getactivity", "bascenev1.getactivity") +content = content.replace("babase.getactivity", "bascenev1.getactivity") +content = content.replace("babase.CelebrateMessage", "bascenev1.CelebrateMessage") +content = content.replace("babase.ScoreConfig", "bascenev1.ScoreConfig") +content = content.replace("babase.ScoreType", "bascenev1.ScoreType") +content = content.replace("babase.GameResults", "bascenev1.GameResults") +content = content.replace("babase.getmaps", "bascenev1.app.classic.getmaps") +content = content.replace("babase.cameraflash", "bascenev1.cameraflash") +content = content.replace("babase.getmodel", "bascenev1.getmesh") +content = content.replace("babase.Map", "bascenev1.Map") +content = content.replace("babase.DeathType", "bascenev1.DeathType") +content = content.replace("babase.GameActivity", "bascenev1.GameActivity") +content = content.replace("_babase.app.stress_test_reset_timer", "_babase.app.classic.stress_test_reset_timer") +content = content.replace("babase.app.stress_test_reset_timer", "_babase.app.classic.stress_test_reset_timer") +content = content.replace("babase._map", "bascenev1._map") +content = content.replace("babase._session.", "bascenev1._session.") +content = content.replace("babase._activity", "bascenev1._activity") +content = content.replace("_babase.get_client_public_device_uuid", "_bascenev1.get_client_public_device_uuid") +content = content.replace("babase.PickedUpMessage", "bascenev1.PickedUpMessage") +content = content.replace("babase.PowerupMessage", "bascenev1.PowerupMessage") +content = content.replace("babase.FreezeMessage", "bascenev1.FreezeMessage") +content = content.replace("with babase.ContextRef(activity):", "with activity.context:") +content = content.replace("babase.Context", "babase.ContextRef") +content = content.replace("babase._dualteamsession", "bascenev1._dualteamsession") +content = content.replace("babase._freeforallsession", "bascenev1._freeforallsession") +content = content.replace("babase._multiteamsession", "bascenev1._multiteamsession") +content = content.replace("babase._gameactivity", "bascenev1._gameactivity") +content = content.replace("babase._powerup", "bascenev1._powerup") +content = content.replace("babase.Chooser", "bascenev1.Chooser") +content = content.replace("babase._lobby", "bascenev1._lobby") +content = content.replace("babase._stats", "bascenev1._stats") +content = content.replace("babase._team", "bascenev1._team") +content = content.replace("PlayerType", "PlayerT") +content = content.replace("babase.app.spaz_appearances", "babase.app.classic.spaz_appearances") +content = content.replace("babase._coopsession", "bascenev1._coopsession") +content = content.replace("babase._servermode", "baclassic._servermode") +content = content.replace("_babase.app.server", "babase.app.classic.server") +content = content.replace("_babase.chatmessage", "bascenev1.chatmessage") +content = content.replace("_babase.disconnect_client", "_bascenev1.disconnect_client") +content = content.replace("_babase.get_game_roster", "bascenev1.get_game_roster") +content = content.replace("_babase.get_public_party_max_size", "bascenev1.get_public_party_max_size") +content = content.replace("_babase.new_host_session", "bascenev1.new_host_session") +content = content.replace("babase._playlist", "bascenev1._playlist") +content = content.replace("model", "mesh") +content = content.replace("TimeType.REAL", "use `bascenev1.apptimer` in `activity.context` instead") +content = content.replace("_babase.app.coop_session_args", "babase.app.classic.coop_session_args") +content = content.replace("_babase.app.campaigns", "babase.app.classic.campaigns") + +content = content.replace("_babase.newactivity", "bascenev1.newactivity") +content = content.replace("babase.Window", "bauiv1.Window") +content = content.replace("babase.Widget", "bauiv1.Widget") +content = content.replace("babase.widget", "bauiv1.widget") +content = content.replace("babase.containerwidget", "bauiv1.containerwidget") +content = content.replace("babase.scrollwidget", "bauiv1.scrollwidget") +content = content.replace("babase.buttonwidget", "bauiv1.buttonwidget") +content = content.replace("babase.textwidget", "bauiv1.textwidget") +content = content.replace("babase.checkboxwidget", "bauiv1.checkboxwidget") +content = content.replace("babase.imagewidget", "bauiv1.imagewidget") +content = content.replace("babase.uicleanupcheck", "bauiv1.uicleanupcheck") +content = content.replace("_babase.set_public_party_max_size", "bascenev1.set_public_party_max_size") +content = content.replace("_bauiv1", "bauiv1") +content = content.replace("babase.show_damage_count", "bascenev1.show_damage_count") +content = content.replace("babase._gameutils", "bascenev1._gameutils") +content = content.replace("babase.StandMessage", "bascenev1.StandMessage") +content = content.replace("babase.PowerupAcceptMessage", "bascenev1.PowerupAcceptMessage") +content = content.replace("babase._gameutils", "bascenev1._gameutils") +content = content.replace("babase.camerashake", "bascenev1.camerashake") +content = content.replace("babase.app.add_coop_practice_level", "babase.app.classic.add_coop_practice_level") +content = content.replace("babase._campaign", "bascenev1._campaign") +content = content.replace("babase.Level", "bascenev1._level.Level") +content = content.replace("babase.app.cloud.send_message_cb", "bauiv1.app.plus.cloud.send_message_cb") +content = content.replace("_babase.get_special_widget", "bauiv1.get_special_widget") + +content = content.replace(".app.platform", ".app.classic.platform") +content = content.replace(".app.subplatform", ".app.classic.subplatform") +content = content.replace(".getlog", ".get_v1_cloud_log") +# Converting `ba.playsound(abc)` to `abc.play()` is tricky. +# Do it manually in case regex substitution fails.# Do it manually in case regex substitution fails. Are you sure!! +#! FIXME May cause syntax warning on 3.12 +content = re.sub( + r'babase\.playsound\(\s*([^,\n]+),\s*([^,\n]+)\)', + r'\1.play(\2)', + content, + flags=re.MULTILINE +) +content = re.sub( + r'babase\.playsound\(\s*([^,\n]+),\s*([^,\n]+),\s*position=([^,\n]+)\)', + r'\1.play(\2, position=\3)', + content, + flags=re.MULTILINE +) +content = re.sub("babase\.playsound\((.+?), (.+?), (.+?)\)", "\\1.play(\\2, \\3)", content) +content = re.sub( + r'babase\.playsound\(([^,\n]+),\s*position=([^,\n]+)\)', + r'\1.play(position=\2)', + content +) +content = re.sub("babase\.playsound\((.*)\)", "\\1.play()", content) + +content = content.replace("babase.internal.add_transaction", "bauiv1.app.plus.add_v1_account_transaction") +content = content.replace("babase.internal.run_transaction", "bauiv1.app.plus.run_v1_account_transaction") +content = content.replace("_babase.add_transaction", "bauiv1.app.plus.add_v1_account_transaction") +content = content.replace("_babase.run_transactions", "bauiv1.app.plus.run_v1_account_transactions") +content = content.replace("babase._store.get_store_layout", "bauiv1.app.classic.store.get_store_layout") +content = content.replace("babase.internal.get_store_layout", "bauiv1.app.classic.store.get_store_layout") +content = content.replace("babase.internal.connect_to_party", "bascenev1.connect_to_party") +content = content.replace("babase.internal.get_default_powerup_distribution", "bascenev1._powerup.get_default_powerup_distribution") +content = content.replace("babase.internal.DEFAULT_REQUEST_TIMEOUT_SECONDS", "babase.DEFAULT_REQUEST_TIMEOUT_SECONDS") +content = content.replace("babase.internal.DEFAULT_TEAM_COLORS", "bascenev1.DEFAULT_TEAM_COLORS") +content = content.replace("babase.internal.DEFAULT_TEAM_NAMES", "bascenev1.DEFAULT_TEAM_NAMES") +content = content.replace("babase.internal.JoinActivity", "bascenev1.JoinActivity") +content = content.replace("babase.internal.LoginAdapter", "babase._login.LoginAdapter") +content = content.replace("babase.internal.PlayerProfilesChangedMessage", "bascenev1._messages.PlayerProfilesChangedMessage") +content = content.replace("babase.internal.ScoreScreenActivity", "bascenev1.ScoreScreenActivity") +content = content.replace("babase.internal.add_clean_frame_callback", "babase.add_clean_frame_callback") +content = content.replace("babase.internal.android_get_external_files_dir", "babase.android_get_external_files_dir") +content = content.replace("babase.internal.appname", "babase.appname") +content = content.replace("babase.internal.appnameupper", "babase.appnameupper") +content = content.replace("babase.internal.capture_gamepad_input", "bascenev1.capture_gamepad_input") +content = content.replace("babase.internal.capture_keyboard_input", "bascenev1.capture_keyboard_input") +content = content.replace("babase.internal.charstr", "babase.charstr") +content = content.replace("babase.internal.chatmessage", "bascenev1.chatmessage") +content = content.replace("babase.internal.commit_app_config", "bauiv1.commit_app_config") +content = content.replace("babase.internal.disconnect_client", "bascenev1.disconnect_client") +content = content.replace("babase.internal.disconnect_from_host", "bascenev1.disconnect_from_host") +content = content.replace("babase.internal.do_play_music", "babase.app.classic.music.do_play_music") +content = content.replace("babase.internal.end_host_scanning", "bascenev1.end_host_scanning") +content = content.replace("babase.internal.fade_screen", "bauiv1.fade_screen") +content = content.replace("babase.internal.filter_playlist", "bascenev1.filter_playlist") +content = content.replace("babase.internal.game_service_has_leaderboard", "_baplus.game_service_has_leaderboard") +content = content.replace("babase.internal.get_available_purchase_count", "bauiv1.app.classic.store.get_available_purchase_count") +content = content.replace("babase.internal.get_available_sale_time", "bauiv1.app.classic.store.get_available_sale_time") +content = content.replace("babase.internal.get_chat_messages", "bascenev1.get_chat_messages") +content = content.replace("babase.internal.get_clean_price", "bauiv1.app.classic.store.get_clean_price") +content = content.replace("babase.internal.get_connection_to_host_info", "bascenev1.get_connection_to_host_info_2") +content = content.replace("babase.internal.get_default_free_for_all_playlist", "bascenev1._playlist.get_default_free_for_all_playlist") +content = content.replace("babase.internal.get_default_teams_playlist", "bascenev1._playlist.get_default_teams_playlist") +content = content.replace("babase.internal.get_display_resolution", "babase.get_display_resolution") +content = content.replace("babase.internal.get_filtered_map_name", "bascenev1._map.get_filtered_map_name") +content = content.replace("babase.internal.get_foreground_host_session", "bascenev1.get_foreground_host_session") +content = content.replace("babase.internal.get_game_port", "bascenev1.get_game_port") +content = content.replace("babase.internal.get_game_roster", "bascenev1.get_game_roster") +content = content.replace("babase.internal.get_input_device_config", "bauiv1.app.classic.get_input_device_config") +content = content.replace("babase.internal.get_ip_address_type", "babase.get_ip_address_type") +content = content.replace("babase.internal.get_local_active_input_devices_count", "bascenev1.get_local_active_input_devices_count") +content = content.replace("babase.internal.get_low_level_config_value", "bauiv1.get_low_level_config_value") +content = content.replace("babase.internal.get_map_class", "bascenev1.get_map_class") +content = content.replace("babase.internal.get_map_display_string", "bascenev1.get_map_display_string") +content = content.replace("babase.internal.get_master_server_address", "bauiv1.app.plus.get_master_server_address") +content = content.replace("babase.internal.get_max_graphics_quality", "babase.get_max_graphics_quality") +content = content.replace("babase.internal.get_news_show", "_babase.app.plus.get_news_show") +content = content.replace("babase.internal.get_next_tip", "bascenev1.app.classic.get_next_tip") +content = content.replace("babase.internal.get_player_colors", "bascenev1.get_player_colors") +content = content.replace("babase.internal.get_player_profile_colors", "bascenev1.get_player_profile_colors") +content = content.replace("babase.internal.get_player_profile_icon", "bascenev1.get_player_profile_icon") +content = content.replace("babase.internal.get_price", "bauiv1.app.plus.get_price") +content = content.replace("babase.internal.get_public_party_enabled", "bascenev1.get_public_party_enabled") +content = content.replace("babase.internal.get_public_party_max_size", "bascenev1.get_public_party_max_size") +content = content.replace("babase.internal.get_purchased", "bauiv1.app.plus.get_purchased") +content = content.replace("babase.internal.get_purchases_state", "_baplus.get_purchases_state") +content = content.replace("babase.internal.get_qrcode_texture", "bauiv1.get_qrcode_texture") +content = content.replace("babase.internal.get_random_names", "bascenev1.get_random_names") +content = content.replace("babase.internal.get_remote_app_name", "bascenev1.get_remote_app_name") +content = content.replace("babase.internal.get_replay_speed_exponent", "bascenev1.get_replay_speed_exponent") +content = content.replace("babase.internal.get_replays_dir", "babase.get_replays_dir") +content = content.replace("babase.internal.get_special_widget", "bauiv1.get_special_widget") +content = content.replace("babase.internal.get_store_item", "babase.app.classic.store.get_store_item") +content = content.replace("babase.internal.get_store_item_display_size", "babase.app.classic.store.get_store_item_display_size") +content = content.replace("babase.internal.get_store_item_name_translated", "babase.app.classic.store.get_store_item_name_translated") +content = content.replace("babase.internal.get_string_height", "babase.get_string_height") +content = content.replace("babase.internal.get_string_width", "babase.get_string_width") +content = content.replace("babase.internal.get_tournament_prize_strings", "bascenev1.app.classic.get_tournament_prize_strings") +content = content.replace("babase.internal.get_trophy_string", "bascenev1.get_trophy_string") +content = content.replace("babase.internal.get_type_name", "babase.get_type_name") +content = content.replace("babase.internal.get_ui_input_device", "bascenev1.get_ui_input_device") +content = content.replace("babase.internal.get_unowned_game_types", "babase.app.classic.store.get_unowned_game_types") +content = content.replace("babase.internal.get_unowned_maps", "babase.app.classic.store.get_unowned_maps") +content = content.replace("babase.internal.get_v1_account_display_string", "bauiv1.app.plus.get_v1_account_display_string") +content = content.replace("babase.internal.get_v1_account_misc_read_val", "bauiv1.app.plus.get_v1_account_misc_read_val") +content = content.replace("babase.internal.get_v1_account_misc_read_val_2", "bauiv1.app.plus.get_v1_account_misc_read_val_2") +content = content.replace("babase.internal.get_v1_account_misc_val", "bauiv1.app.plus.get_v1_account_misc_val") +content = content.replace("babase.internal.get_v1_account_name", "bauiv1.app.plus.get_v1_account_name") +content = content.replace("babase.internal.get_v1_account_state", "bauiv1.app.plus.get_v1_account_state") +content = content.replace("babase.internal.get_v1_account_state_num", "bauiv1.app.plus.get_v1_account_state_num") +content = content.replace("babase.internal.get_v1_account_ticket_count", "bauiv1.app.plus.get_v1_account_ticket_count") +content = content.replace("babase.internal.get_v1_account_type", "bauiv1.app.plus.get_v1_account_type") +content = content.replace("babase.internal.get_v2_fleet", "_baplus.get_v2_fleet") +content = content.replace("babase.internal.getcampaign", "bauiv1.app.classic.getcampaign") +content = content.replace("babase.internal.getclass", "babase.getclass") +content = content.replace("babase.internal.getinputdevice", "bascenev1.getinputdevice") +content = content.replace("babase.internal.has_gamma_control", "babase.has_gamma_control") +content = content.replace("babase.internal.has_video_ads", "bauiv1.has_video_ads") +content = content.replace("babase.internal.have_incentivized_ad", "bauiv1.have_incentivized_ad") +content = content.replace("babase.internal.have_permission", "babase.have_permission") +content = content.replace("babase.internal.have_touchscreen_input", "bascenev1.have_touchscreen_input") +content = content.replace("babase.internal.host_scan_cycle", "bascenev1.host_scan_cycle") +content = content.replace("babase.internal.in_game_purchase", "bui.app.plus.in_game_purchase") +content = content.replace("babase.internal.increment_analytics_count", "babase.increment_analytics_count") +content = content.replace("babase.internal.is_blessed", "bui.app.plus.is_blessed") +content = content.replace("babase.internal.is_browser_likely_available", "bauiv1.is_browser_likely_available") +content = content.replace("babase.internal.is_in_replay", "bascenev1.is_in_replay") +content = content.replace("babase.internal.is_party_icon_visible", "bauiv1.is_party_icon_visible") +content = content.replace("babase.internal.is_running_on_fire_tv", "babase.is_running_on_fire_tv") +content = content.replace("babase.internal.is_xcode_build", "babase.is_xcode_build") +content = content.replace("babase.internal.json_prep", "babase.json_prep") +content = content.replace("babase.internal.lock_all_input", "babase.lock_all_input") +content = content.replace("babase.internal.mark_config_dirty", "_babase.app.plus.mark_config_dirty") +content = content.replace("babase.internal.new_host_session", "bascenev1.new_host_session") +content = content.replace("babase.internal.new_replay_session", "bascenev1.new_replay_session") +content = content.replace("babase.internal.open_file_externally", "bauiv1.open_file_externally") +content = content.replace("babase.internal.power_ranking_query", "_baplus.power_ranking_query") +content = content.replace("babase.internal.preload_map_preview_media", "bauiv1.app.classic.preload_map_preview_media") +content = content.replace("babase.internal.purchase", "_baplus.purchase") +content = content.replace("babase.internal.register_map", "bascenev1.register_map") +content = content.replace("babase.internal.release_gamepad_input", "bascenev1.release_gamepad_input") +content = content.replace("babase.internal.release_keyboard_input", "bascenev1.release_keyboard_input") +content = content.replace("babase.internal.report_achievement", "babase.app.plus.report_achievement") +content = content.replace("babase.internal.request_permission", "babase.request_permission") +content = content.replace("babase.internal.reset_achievements", "_baplus.reset_achievements") +content = content.replace("babase.internal.reset_random_player_names", "bascenev1.reset_random_player_names") +content = content.replace("babase.internal.restore_purchases", "_baplus.restore_purchases") +content = content.replace("babase.internal.run_cpu_benchmark", "baclassic._benchmark.run_cpu_benchmark") +content = content.replace("babase.internal.run_gpu_benchmark", "baclassic._benchmark.run_gpu_benchmark") +content = content.replace("babase.internal.run_media_reload_benchmark", "baclassic._benchmark.run_media_reload_benchmark") +content = content.replace("babase.internal.run_stress_test", "babase.app.classic.run_stress_test") +content = content.replace("babase.internal.set_authenticate_clients", "bascenev1.set_authenticate_clients") +content = content.replace("babase.internal.set_debug_speed_exponent", "bascenev1.set_debug_speed_exponent") +content = content.replace("babase.internal.set_low_level_config_value", "babase.set_low_level_config_value") +content = content.replace("babase.internal.set_party_icon_always_visible", "bauiv1.set_party_icon_always_visible") +content = content.replace("babase.internal.set_party_window_open", "bauiv1.set_party_window_open") +content = content.replace("babase.internal.set_public_party_enabled", "bascenev1.set_public_party_enabled") +content = content.replace("babase.internal.set_public_party_max_size", "bascenev1.set_public_party_max_size") +content = content.replace("babase.internal.set_public_party_name", "bascenev1.set_public_party_name") +content = content.replace("babase.internal.set_public_party_queue_enabled", "bascenev1.set_public_party_queue_enabled") +content = content.replace("babase.internal.set_replay_speed_exponent", "bascenev1.set_replay_speed_exponent") +content = content.replace("babase.internal.set_touchscreen_editing", "bascenev1.set_touchscreen_editing") +content = content.replace("babase.internal.set_ui_input_device", "babase.set_ui_input_device") +content = content.replace("babase.internal.should_submit_debug_info", "babase._apputils.should_submit_debug_info") +content = content.replace("babase.internal.show_online_score_ui", "bauiv1.show_online_score_ui") +content = content.replace("babase.internal.sign_in_v1", "babase.app.plus.sign_in_v1") +content = content.replace("babase.internal.sign_out_v1", "babase.app.plus.sign_out_v1") +content = content.replace("babase.internal.submit_score", "bascenev1.app.plus.submit_score") +content = content.replace("babase.internal.tournament_query", "_baplus.tournament_query") +content = content.replace("babase.internal.unlock_all_input", "babase.unlock_all_input") +content = content.replace("babase.internal.value_test", "bauiv1.app.classic.value_test") +content = content.replace("babase.internal.workspaces_in_use", "babase.workspaces_in_use") +content = content.replace("babase.internal.dump_tracebacks", "babase._apputils.dump_app_state") +content = content.replace("babase.internal.show_app_invite", "_bauiv1.show_app_invite") +content = content.replace("babase._generated", "babase._mgen") +content = content.replace("_babase.disconnect_from_host", "bascenev1.disconnect_from_host") +content = content.replace("babase.disconnect_from_host", "bascenev1.disconnect_from_host") +content = content.replace("_babase.connect_to_party", "bascenev1.connect_to_party") +content = content.replace("babase.connect_to_party", "bascenev1.connect_to_party") +content = content.replace("babase.set_party_window_open", "bauiv1.set_party_window_open") +content = content.replace("babase.set_party_window_open", "bauiv1.set_party_window_open") +content = content.replace("babase.getcollidemesh", "bascenev1.getcollisionmesh") +content = content.replace("collide_mesh", "collision_mesh") +content = content.replace("babase.FloatSetting", "bascenev1.FloatSetting") +# Removed in API 8: +# content = content.replace("babase.internal.set_telnet_access_enabled", "") + +content = content.replace("babase.internal.master_server_get", "babase.app.classic.master_server_v1_get") +content = content.replace("babase.internal.master_server_post", "babase.app.classic.master_server_v1_post") +content = content.replace("babase.internal.log_dumped_tracebacks", "babase._apputils.log_dumped_app_state") +content = content.replace("babase.internal.have_outstanding_transactions", "bauiv1.app.plus.have_outstanding_v1_account_transactions") +content = content.replace("babase.internal.get_public_login_id", "bauiv1.app.plus.get_v1_account_public_login_id") +content = content.replace("babase.internal.get_input_map_hash", "bauiv1.app.classic.get_input_device_map_hash") +content = content.replace("babase.internal.get_device_value", "bauiv1.app.classic.get_input_device_mapped_value") + +# Depracations +content = content.replace("babase.app.build_number", "babase.app.build_number if build_number < 21282 else babase.app.env.build_number") +content = content.replace("babase.app.device_name", "babase.app.device_name if build_number < 21282 else babase.app.env.device_name") +content = content.replace("babase.app.config_file_path", "babase.app.config_file_path if build_number < 21282 else babase.app.env.config_file_path") +content = content.replace("babase.app.version", "babase.app.version if build_number < 21282 else babase.app.env") +content = content.replace("babase.app.debug_build", "babase.app.debug_build if build_number < 21282 else babase.app.env.debug_build") +content = content.replace("babase.app.test_build", "babase.app.test_build if build_number < 21282 else babase.app.env.test_build") +content = content.replace("babase.app.data_directory", "babase.app.data_directory if build_number < 21282 else babase.app.env.data_directory") +content = content.replace("babase.app.python_directory_user", "babase.app.python_directory_user if build_number < 21282 else babase.app.env.python_directory_user") +content = content.replace("babase.app.python_directory_app", "babase.app.env") +content = content.replace("babase.app.python_directory_app_site", "babase.app.python_directory_app_site if build_number < 21282 else babase.app.env.python_directory_app_site") +content = content.replace("babase.app.api_version", "babase.app.api_version if build_number < 21282 else babase.app.env.api_version") +content = content.replace("babase.app.on_tv", "babase.app.on_tv if build_number < 21282 else babase.app.env.on_tv") +content = content.replace("babase.app.vr_mode", "babase.app.vr_mode if build_number < 21282 else babase.app.env.vr") +content = content.replace("babase.app.toolbar_test", "babase.app.toolbar_test if build_number < 21282 else babase.app.env.toolbar_test") +content = content.replace("babase.app.arcade_mode", "babase.app.arcade_mode if build_number < 21282 else babase.app.env.arcade_mode") +content = content.replace("babase.app.headless_mode", "babase.app.headless_mode if build_number < 21282 else babase.app.env.headless_mode") +content = content.replace("babase.app.demo_mode", "babase.app.demo_mode if build_number < 21282 else babase.app.env.demo_mode") +content = content.replace("babase.app.protocol_version", "babase.app.protocol_version if build_number < 21282 else babase.app.env.protocol_version") +content = content.replace("bascenev1.get_connection_to_host_info", "bascenev1.get_connection_to_host_info if build_number < 21697 else bascenev1.get_connection_to_host_info_2") + +content = content.replace("babase._store", "bauiv1.app.classic.store") +# content = content.replace("babase.internal", "") +content = content.replace("bastd.ui", "bauiv1lib") +content = content.replace("bastd", "bascenev1lib") +content = content.replace("timetype=","") +content = content.replace("babase.columnwidget", "bauiv1.columnwidget") +content = content.replace("_babase.get_game_port", "bascenev1.get_game_port") +content = content.replace("_babase.get_chat_messages", "bascenev1.get_chat_messages") +content = content.replace("_babase.get_foreground_host_session", "bascenev1.get_foreground_host_session") +content = content.replace("_babase.get_foreground_host_activity", "bascenev1.get_foreground_host_activity") +content = content.replace("bascenev1.SessionPlayerNotFoundError", "babase.SessionPlayerNotFoundError") +content = content.replace("bascenev1", "bs") +content = content.replace("bauiv1", "bui") +content = content.replace("import bs", "import bascenev1 as bs") +content = content.replace("import bui", "import bauiv1 as bui") +content = content.replace("bslib", "bascenev1lib") +content = content.replace("builib", "bauiv1lib") +content = content.replace("from bs.", "from bascenev1.") +content = content.replace("from bui.", "from bauiv1.") +content = content.replace("import bascenev1 as bascenev1lib", "import bascenev1lib") +content = content.replace("import bauiv1 as bauiv1lib", "import bauiv1lib") +content = content.replace("# ba_meta export bs.GameActivity", "# ba_meta export bascenev1.GameActivity") +content = content.replace("_bs", "bs") + +content = re.sub(r'bs\.Timer\(([^)]*)\bTimeType\.REAL\b([^)]*)\)', r'babase.AppTimer(\1\2)', content) +trademark = "# Porting to api 8 made easier by baport.(https://github.com/bombsquad-community/baport)\n" +with open(sys.argv[2], "w", encoding=encoding) as f: + f.write(trademark + content) + + diff --git a/plugins/minigames/quake.py b/plugins/minigames/quake.py index e0bb33bf..65fcfcbb 100644 --- a/plugins/minigames/quake.py +++ b/plugins/minigames/quake.py @@ -1,24 +1,27 @@ +# Porting to api 8 made easier by baport.(https://github.com/bombsquad-community/baport) """Quake Game Activity""" -# ba_meta require api 7 +# ba_meta require api 8 from __future__ import annotations from typing import TYPE_CHECKING import random import enum -import ba -import _ba +import babase +import bauiv1 as bui +import bascenev1 as bs +import _babase -from bastd.actor.scoreboard import Scoreboard -from bastd.actor.powerupbox import PowerupBox -from bastd.gameutils import SharedObjects +from bascenev1lib.actor.scoreboard import Scoreboard +from bascenev1lib.actor.powerupbox import PowerupBox +from bascenev1lib.gameutils import SharedObjects # from rocket -from bastd.actor.bomb import Blast +from bascenev1lib.actor.bomb import Blast # from railgun -from bastd.actor.playerspaz import PlayerSpaz -from bastd.actor.spaz import Spaz +from bascenev1lib.actor.playerspaz import PlayerSpaz +from bascenev1lib.actor.spaz import Spaz if TYPE_CHECKING: @@ -33,7 +36,7 @@ class RocketFactory: """Quake Rocket factory""" def __init__(self) -> None: - self.ball_material = ba.Material() + self.ball_material = bs.Material() self.ball_material.add_actions( conditions=((('we_are_younger_than', 5), 'or', @@ -60,7 +63,7 @@ def __init__(self) -> None: @classmethod def get(cls): """Get factory if exists else create new""" - activity = ba.getactivity() + activity = bs.getactivity() if hasattr(activity, STORAGE_ATTR_NAME): return getattr(activity, STORAGE_ATTR_NAME) factory = cls() @@ -77,13 +80,13 @@ def __init__(self): def give(self, spaz: Spaz) -> None: """Give spaz a rocket launcher""" spaz.punch_callback = self.shot - self.last_shot = ba.time() + self.last_shot = bs.time() # FIXME # noinspection PyUnresolvedReferences def shot(self, spaz: Spaz) -> None: """Release a rocket""" - time = ba.time() + time = bs.time() if time - self.last_shot > 0.6: self.last_shot = time center = spaz.node.position_center @@ -92,12 +95,12 @@ def shot(self, spaz: Spaz) -> None: center[2] - forward[2]] direction[1] = 0.0 - mag = 10.0 / ba.Vec3(*direction).length() + mag = 10.0 / babase.Vec3(*direction).length() vel = [v * mag for v in direction] Rocket(position=spaz.node.position, velocity=vel, - owner=spaz.getplayer(ba.Player), - source_player=spaz.getplayer(ba.Player), + owner=spaz.getplayer(bs.Player), + source_player=spaz.getplayer(bs.Player), color=spaz.node.color).autoretain() @@ -105,7 +108,7 @@ class ImpactMessage: """Rocket touched something""" -class Rocket(ba.Actor): +class Rocket(bs.Actor): """Epic rocket from rocket launcher""" def __init__(self, @@ -120,16 +123,16 @@ def __init__(self, self._color = color factory = RocketFactory.get() - self.node = ba.newnode('prop', + self.node = bs.newnode('prop', delegate=self, attrs={ 'position': position, 'velocity': velocity, - 'model': ba.getmodel('impactBomb'), + 'mesh': bs.getmesh('impactBomb'), 'body': 'sphere', - 'color_texture': ba.gettexture( + 'color_texture': bs.gettexture( 'bunnyColor'), - 'model_scale': 0.2, + 'mesh_scale': 0.2, 'is_area_of_interest': True, 'body_scale': 0.8, 'materials': [ @@ -139,17 +142,17 @@ def __init__(self, self.node.extra_acceleration = (self.node.velocity[0] * 200, 0, self.node.velocity[2] * 200) - self._life_timer = ba.Timer( - 5, ba.WeakCall(self.handlemessage, ba.DieMessage())) + self._life_timer = bs.Timer( + 5, bs.WeakCall(self.handlemessage, bs.DieMessage())) - self._emit_timer = ba.Timer(0.001, ba.WeakCall(self.emit), repeat=True) + self._emit_timer = bs.Timer(0.001, bs.WeakCall(self.emit), repeat=True) self.base_pos_y = self.node.position[1] - ba.camerashake(5.0) + bs.camerashake(5.0) def emit(self) -> None: """Emit a trace after rocket""" - ba.emitfx(position=self.node.position, + bs.emitfx(position=self.node.position, scale=0.4, spread=0.01, chunk_type='spark') @@ -157,7 +160,7 @@ def emit(self) -> None: return self.node.position = (self.node.position[0], self.base_pos_y, self.node.position[2]) # ignore y - ba.newnode('explosion', + bs.newnode('explosion', owner=self.node, attrs={ 'position': self.node.position, @@ -169,9 +172,9 @@ def handlemessage(self, msg: Any) -> Any: """Message handling for rocket""" super().handlemessage(msg) if isinstance(msg, ImpactMessage): - self.node.handlemessage(ba.DieMessage()) + self.node.handlemessage(bs.DieMessage()) - elif isinstance(msg, ba.DieMessage): + elif isinstance(msg, bs.DieMessage): if self.node: Blast(position=self.node.position, blast_radius=2, @@ -180,8 +183,8 @@ def handlemessage(self, msg: Any) -> Any: self.node.delete() self._emit_timer = None - elif isinstance(msg, ba.OutOfBoundsMessage): - self.handlemessage(ba.DieMessage()) + elif isinstance(msg, bs.OutOfBoundsMessage): + self.handlemessage(bs.DieMessage()) # -------------------Rocket-------------------------- @@ -196,13 +199,13 @@ def __init__(self) -> None: def give(self, spaz: Spaz) -> None: """Give spaz a railgun""" spaz.punch_callback = self.shot - self.last_shot = ba.time() + self.last_shot = bs.time() # FIXME # noinspection PyUnresolvedReferences def shot(self, spaz: Spaz) -> None: """Release a rocket""" - time = ba.time() + time = bs.time() if time - self.last_shot > 0.6: self.last_shot = time center = spaz.node.position_center @@ -215,8 +218,8 @@ def shot(self, spaz: Spaz) -> None: RailBullet(position=spaz.node.position, direction=direction, - owner=spaz.getplayer(ba.Player), - source_player=spaz.getplayer(ba.Player), + owner=spaz.getplayer(bs.Player), + source_player=spaz.getplayer(bs.Player), color=spaz.node.color).autoretain() @@ -227,7 +230,7 @@ def __init__(self, spaz) -> None: self.spaz = spaz -class RailBullet(ba.Actor): +class RailBullet(bs.Actor): """Railgun bullet""" def __init__(self, @@ -239,23 +242,23 @@ def __init__(self, super().__init__() self._color = color - self.node = ba.newnode('light', + self.node = bs.newnode('light', delegate=self, attrs={ 'position': position, 'color': self._color }) - ba.animate(self.node, 'radius', {0: 0, 0.1: 0.5, 0.5: 0}) + bs.animate(self.node, 'radius', {0: 0, 0.1: 0.5, 0.5: 0}) self.source_player = source_player self.owner = owner - self._life_timer = ba.Timer( - 0.5, ba.WeakCall(self.handlemessage, ba.DieMessage())) + self._life_timer = bs.Timer( + 0.5, bs.WeakCall(self.handlemessage, bs.DieMessage())) pos = position - vel = tuple(i / 5 for i in ba.Vec3(direction).normalized()) + vel = tuple(i / 5 for i in babase.Vec3(direction).normalized()) for _ in range(500): # Optimization :( - ba.newnode('explosion', + bs.newnode('explosion', owner=self.node, attrs={ 'position': pos, @@ -264,25 +267,25 @@ def __init__(self, }) pos = (pos[0] + vel[0], pos[1] + vel[1], pos[2] + vel[2]) - for node in _ba.getnodes(): + for node in _babase.getnodes(): if node and node.getnodetype() == 'spaz': # pylint: disable=invalid-name - m3 = ba.Vec3(position) - a = ba.Vec3(direction[2], direction[1], direction[0]) - m1 = ba.Vec3(node.position) + m3 = babase.Vec3(position) + a = babase.Vec3(direction[2], direction[1], direction[0]) + m1 = babase.Vec3(node.position) # pylint: enable=invalid-name # distance between node and line dist = (a * (m1 - m3)).length() / a.length() if dist < 0.3: if node and node != self.owner and node.getdelegate( PlayerSpaz, True).getplayer( - ba.Player, True).team != self.owner.team: - node.handlemessage(ba.FreezeMessage()) + bs.Player, True).team != self.owner.team: + node.handlemessage(bs.FreezeMessage()) pos = self.node.position hit_dir = (0, 10, 0) node.handlemessage( - ba.HitMessage(pos=pos, + bs.HitMessage(pos=pos, magnitude=50, velocity_magnitude=50, radius=0, @@ -292,21 +295,21 @@ def __init__(self, def handlemessage(self, msg: Any) -> Any: super().handlemessage(msg) - if isinstance(msg, ba.DieMessage): + if isinstance(msg, bs.DieMessage): if self.node: self.node.delete() - elif isinstance(msg, ba.OutOfBoundsMessage): - self.handlemessage(ba.DieMessage()) + elif isinstance(msg, bs.OutOfBoundsMessage): + self.handlemessage(bs.DieMessage()) # ------------------Railgun------------------------- -class Player(ba.Player['Team']): +class Player(bs.Player['Team']): """Our player""" -class Team(ba.Team[Player]): +class Team(bs.Team[Player]): """Our team""" def __init__(self) -> None: @@ -326,91 +329,91 @@ class ObstaclesForm(enum.Enum): RANDOM = 2 -# ba_meta export game -class QuakeGame(ba.TeamGameActivity[Player, Team]): +# ba_meta export bascenev1.GameActivity +class QuakeGame(bs.TeamGameActivity[Player, Team]): """Quake Team Game Activity""" name = 'Quake' description = 'Kill a set number of enemies to win.' available_settings = [ - ba.IntSetting( + bs.IntSetting( 'Kills to Win Per Player', default=15, min_value=1, increment=1, ), - ba.IntChoiceSetting( + bs.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( + bs.FloatChoiceSetting( 'Respawn Times', choices=[('At once', 0.0), ('Shorter', 0.25), ('Short', 0.5), ('Normal', 1.0), ('Long', 2.0), ('Longer', 4.0)], default=1.0, ), - ba.BoolSetting( + bs.BoolSetting( 'Speed', default=True, ), - ba.BoolSetting( + bs.BoolSetting( 'Enable Jump', default=True, ), - ba.BoolSetting( + bs.BoolSetting( 'Enable Pickup', default=True, ), - ba.BoolSetting( + bs.BoolSetting( 'Enable Bomb', default=False, ), - ba.BoolSetting( + bs.BoolSetting( 'Obstacles', default=True, ), - ba.IntChoiceSetting( + bs.IntChoiceSetting( 'Obstacles Form', choices=[('Cube', ObstaclesForm.CUBE.value), ('Sphere', ObstaclesForm.SPHERE.value), ('Random', ObstaclesForm.RANDOM.value)], default=0, ), - ba.IntChoiceSetting( + bs.IntChoiceSetting( 'Weapon Type', choices=[('Rocket', WeaponType.ROCKET.value), ('Railgun', WeaponType.RAILGUN.value)], default=WeaponType.ROCKET.value, ), - ba.BoolSetting( + bs.BoolSetting( 'Obstacles Mirror Shots', default=False, ), - ba.IntSetting( + bs.IntSetting( 'Obstacles Count', default=16, min_value=0, increment=2, ), - ba.BoolSetting( + bs.BoolSetting( 'Random Obstacles Color', default=True, ), - ba.BoolSetting( + bs.BoolSetting( 'Epic Mode', default=False, ), ] @classmethod - def supports_session_type(cls, sessiontype: Type[ba.Session]) -> bool: - return issubclass(sessiontype, ba.MultiTeamSession) or issubclass( - sessiontype, ba.FreeForAllSession) + def supports_session_type(cls, sessiontype: Type[bs.Session]) -> bool: + return issubclass(sessiontype, bs.MultiTeamSession) or issubclass( + sessiontype, bs.FreeForAllSession) @classmethod - def get_supported_maps(cls, sessiontype: Type[ba.Session]) -> List[str]: + def get_supported_maps(cls, sessiontype: Type[bs.Session]) -> List[str]: # TODO add more maps return ['Football Stadium', 'Monkey Face', 'Doom Shroom'] @@ -426,15 +429,15 @@ def __init__(self, settings) -> None: self._pickup_enabled = self.settings_raw['Enable Pickup'] self._jump_enabled = self.settings_raw['Enable Jump'] self._weapon_type = WeaponType(self.settings_raw['Weapon Type']) - self.default_music = (ba.MusicType.EPIC - if self._epic_mode else ba.MusicType.GRAND_ROMP) + self.default_music = (bs.MusicType.EPIC + if self._epic_mode else bs.MusicType.GRAND_ROMP) self.slow_motion = self._epic_mode self.announce_player_deaths = True self._scoreboard = Scoreboard() - self._ding_sound = ba.getsound('dingSmall') + self._ding_sound = bs.getsound('dingSmall') - self._shield_dropper: Optional[ba.Timer] = None + self._shield_dropper: Optional[bs.Timer] = None def get_instance_description(self) -> Union[str, Sequence]: return 'Kill ${ARG1} enemies.', self._score_to_win @@ -445,11 +448,11 @@ def on_team_join(self, team: Team) -> None: self._update_scoreboard() def on_begin(self) -> None: - ba.TeamGameActivity.on_begin(self) - ba.getactivity().globalsnode.tint = (0.5, 0.7, 1) + bs.TeamGameActivity.on_begin(self) + bs.getactivity().globalsnode.tint = (0.5, 0.7, 1) self.drop_shield() - self._shield_dropper = ba.Timer(8, - ba.WeakCall(self.drop_shield), + self._shield_dropper = bs.Timer(8, + bs.WeakCall(self.drop_shield), repeat=True) self.setup_standard_time_limit(self._time_limit) if self._obstacles_enabled: @@ -483,9 +486,9 @@ def drop_shield(self) -> None: position=(random.uniform(-10, 10), 6, random.uniform(-5, 5))).autoretain() - ba.playsound(self._ding_sound) + self._ding_sound.play() - p_light = ba.newnode('light', + p_light = bs.newnode('light', owner=shield.node, attrs={ 'position': (0, 0, 0), @@ -497,7 +500,7 @@ def drop_shield(self) -> None: shield.node.connectattr('position', p_light, 'position') - ba.animate(p_light, 'intensity', {0: 2, 8: 0}) + bs.animate(p_light, 'intensity', {0: 2, 8: 0}) def spawn_player(self, player: Player) -> None: spaz = self.spawn_player_spaz(player) @@ -511,7 +514,7 @@ def spawn_player(self, player: Player) -> None: enable_fly=False) spaz.node.hockey = self._speed_enabled - spaz.spaz_light = ba.newnode('light', + spaz.spaz_light = bs.newnode('light', owner=spaz.node, attrs={ 'position': (0, 0, 0), @@ -524,8 +527,8 @@ def spawn_player(self, player: Player) -> None: spaz.node.connectattr('position', spaz.spaz_light, 'position') def handlemessage(self, msg: Any) -> Any: - if isinstance(msg, ba.PlayerDiedMessage): - ba.TeamGameActivity.handlemessage(self, msg) + if isinstance(msg, bs.PlayerDiedMessage): + bs.TeamGameActivity.handlemessage(self, msg) player = msg.getplayer(Player) self.respawn_player(player) killer = msg.getkillerplayer(Player) @@ -535,20 +538,20 @@ def handlemessage(self, msg: Any) -> Any: # handle team-kills if killer.team is player.team: # in free-for-all, killing yourself loses you a point - if isinstance(self.session, ba.FreeForAllSession): + if isinstance(self.session, bs.FreeForAllSession): new_score = player.team.score - 1 new_score = max(0, new_score) player.team.score = new_score # in teams-mode it gives a point to the other team else: - ba.playsound(self._ding_sound) + self._ding_sound.play() for team in self.teams: if team is not killer.team: team.score += 1 # killing someone on another team nets a kill else: killer.team.score += 1 - ba.playsound(self._ding_sound) + self._ding_sound.play() # in FFA show our score since its hard to find on # the scoreboard assert killer.actor is not None @@ -564,10 +567,10 @@ def handlemessage(self, msg: Any) -> Any: # (allows the dust to clear and draws to occur if # deaths are close enough) if any(team.score >= self._score_to_win for team in self.teams): - ba.timer(0.5, self.end_game) + bs.timer(0.5, self.end_game) else: - ba.TeamGameActivity.handlemessage(self, msg) + bs.TeamGameActivity.handlemessage(self, msg) def _update_scoreboard(self) -> None: for team in self.teams: @@ -575,51 +578,51 @@ def _update_scoreboard(self) -> None: self._score_to_win) def end_game(self) -> None: - results = ba.GameResults() + results = bs.GameResults() for team in self.teams: results.set_team_score(team, team.score) self.end(results=results) -class Obstacle(ba.Actor): +class Obstacle(bs.Actor): """Scene object""" def __init__(self, position, form=ObstaclesForm.CUBE, mirror=False) -> None: - ba.Actor.__init__(self) + bs.Actor.__init__(self) if form == ObstaclesForm.CUBE: - model = 'tnt' + mesh = 'tnt' body = 'crate' elif form == ObstaclesForm.SPHERE: - model = 'bomb' + mesh = 'bomb' body = 'sphere' else: # ObstaclesForm.RANDOM: - model = random.choice(['tnt', 'bomb']) - body = 'sphere' if model == 'bomb' else 'crate' + mesh = random.choice(['tnt', 'bomb']) + body = 'sphere' if mesh == 'bomb' else 'crate' - self.node = ba.newnode( + self.node = bs.newnode( 'prop', delegate=self, attrs={ 'position': position, - 'model': - ba.getmodel(model), + 'mesh': + bs.getmesh(mesh), 'body': body, 'body_scale': 1.3, - 'model_scale': + 'mesh_scale': 1.3, 'reflection': 'powerup', 'reflection_scale': [0.7], 'color_texture': - ba.gettexture('bunnyColor'), + bs.gettexture('bunnyColor'), 'materials': [SharedObjects.get().footing_material] if mirror else [ SharedObjects.get().object_material, @@ -628,15 +631,15 @@ def __init__(self, }) def handlemessage(self, msg: Any) -> Any: - if isinstance(msg, ba.DieMessage): + if isinstance(msg, bs.DieMessage): if self.node: self.node.delete() - elif isinstance(msg, ba.OutOfBoundsMessage): + elif isinstance(msg, bs.OutOfBoundsMessage): if self.node: - self.handlemessage(ba.DieMessage()) + self.handlemessage(bs.DieMessage()) - elif isinstance(msg, ba.HitMessage): + elif isinstance(msg, bs.HitMessage): self.node.handlemessage('impulse', msg.pos[0], msg.pos[1], msg.pos[2], msg.velocity[0], msg.velocity[1], msg.velocity[2], diff --git a/plugins/minigames/shimla.py b/plugins/minigames/shimla.py index da963927..23161944 100644 --- a/plugins/minigames/shimla.py +++ b/plugins/minigames/shimla.py @@ -1,43 +1,43 @@ +# Porting to api 8 made easier by baport.(https://github.com/bombsquad-community/baport) # Released under the MIT License. See LICENSE for details. # """DeathMatch game and support classes.""" -# ba_meta require api 7 +# ba_meta require api 8 # (see https://ballistica.net/wiki/meta-tag-system) from __future__ import annotations from typing import TYPE_CHECKING -import ba -import _ba -from bastd.actor.playerspaz import PlayerSpaz -from bastd.actor.scoreboard import Scoreboard -from bastd.gameutils import SharedObjects -from bastd.game.deathmatch import DeathMatchGame, Player, Team -from bastd.gameutils import SharedObjects +import babase +import bascenev1 as bs +from bascenev1lib.actor.playerspaz import PlayerSpaz +from bascenev1lib.gameutils import SharedObjects +from bascenev1lib.game.deathmatch import DeathMatchGame, Player +from bascenev1lib.gameutils import SharedObjects if TYPE_CHECKING: from typing import Any, Sequence, Dict, Type, List, Optional, Union -# ba_meta export game +# ba_meta export bascenev1.GameActivity class ShimlaGame(DeathMatchGame): name = 'Shimla' @classmethod - def supports_session_type(cls, sessiontype: Type[ba.Session]) -> bool: - return issubclass(sessiontype, ba.DualTeamSession) + def supports_session_type(cls, sessiontype: Type[bs.Session]) -> bool: + return issubclass(sessiontype, bs.DualTeamSession) @classmethod - def get_supported_maps(cls, sessiontype: Type[ba.Session]) -> List[str]: + def get_supported_maps(cls, sessiontype: Type[bs.Session]) -> List[str]: return ['Creative Thoughts'] def __init__(self, settings: dict): super().__init__(settings) shared = SharedObjects.get() self.lifts = {} - self._real_wall_material = ba.Material() + self._real_wall_material = bs.Material() self._real_wall_material.add_actions( actions=( @@ -53,7 +53,7 @@ def __init__(self, settings: dict): ('modify_part_collision', 'physical', True) )) - self._lift_material = ba.Material() + self._lift_material = bs.Material() self._lift_material.add_actions( actions=( @@ -71,14 +71,14 @@ def __init__(self, settings: dict): ) def on_begin(self): - ba.getactivity().globalsnode.happy_thoughts_mode = False + bs.getactivity().globalsnode.happy_thoughts_mode = False super().on_begin() self.make_map() - ba.timer(2, self.disable_fly) + bs.timer(2, self.disable_fly) def disable_fly(self): - activity = _ba.get_foreground_host_activity() + activity = bs.get_foreground_host_activity() for players in activity.players: players.actor.node.fly = False @@ -102,29 +102,29 @@ def spawn_player_spaz( def make_map(self): shared = SharedObjects.get() - _ba.get_foreground_host_activity()._map.leftwall.materials = [ + bs.get_foreground_host_activity()._map.leftwall.materials = [ shared.footing_material, self._real_wall_material] - _ba.get_foreground_host_activity()._map.rightwall.materials = [ + bs.get_foreground_host_activity()._map.rightwall.materials = [ shared.footing_material, self._real_wall_material] - _ba.get_foreground_host_activity()._map.topwall.materials = [ + bs.get_foreground_host_activity()._map.topwall.materials = [ shared.footing_material, self._real_wall_material] - self.floorwall1 = ba.newnode('region', attrs={'position': (-10, 5, -5.52), 'scale': + self.floorwall1 = bs.newnode('region', attrs={'position': (-10, 5, -5.52), 'scale': (15, 0.2, 2), 'type': 'box', 'materials': [shared.footing_material, self._real_wall_material]}) - self.floorwall2 = ba.newnode('region', attrs={'position': (10, 5, -5.52), 'scale': ( + self.floorwall2 = bs.newnode('region', attrs={'position': (10, 5, -5.52), 'scale': ( 15, 0.2, 2), 'type': 'box', 'materials': [shared.footing_material, self._real_wall_material]}) - self.wall1 = ba.newnode('region', attrs={'position': (0, 11, -6.90), 'scale': ( + self.wall1 = bs.newnode('region', attrs={'position': (0, 11, -6.90), 'scale': ( 35.4, 20, 1), 'type': 'box', 'materials': [shared.footing_material, self._real_wall_material]}) - self.wall2 = ba.newnode('region', attrs={'position': (0, 11, -4.14), 'scale': ( + self.wall2 = bs.newnode('region', attrs={'position': (0, 11, -4.14), 'scale': ( 35.4, 20, 1), 'type': 'box', 'materials': [shared.footing_material, self._real_wall_material]}) - ba.newnode('locator', attrs={'shape': 'box', 'position': (-10, 5, -5.52), 'color': ( + bs.newnode('locator', attrs={'shape': 'box', 'position': (-10, 5, -5.52), 'color': ( 0, 0, 0), 'opacity': 1, 'draw_beauty': True, 'additive': False, 'size': (15, 0.2, 2)}) - ba.newnode('locator', attrs={'shape': 'box', 'position': (10, 5, -5.52), 'color': ( + bs.newnode('locator', attrs={'shape': 'box', 'position': (10, 5, -5.52), 'color': ( 0, 0, 0), 'opacity': 1, 'draw_beauty': True, 'additive': False, 'size': (15, 0.2, 2)}) self.create_lift(-16.65, 8) @@ -151,32 +151,32 @@ def create_static_step(self, x, y): shared = SharedObjects.get() - ba.newnode('region', attrs={'position': (x, y, -5.52), 'scale': (5.5, 0.1, 6), + bs.newnode('region', attrs={'position': (x, y, -5.52), 'scale': (5.5, 0.1, 6), 'type': 'box', 'materials': [shared.footing_material, self._real_wall_material]}) - ba.newnode('locator', attrs={'shape': 'box', 'position': (x, y, -5.52), 'color': ( + bs.newnode('locator', attrs={'shape': 'box', 'position': (x, y, -5.52), 'color': ( 1, 1, 0), 'opacity': 1, 'draw_beauty': True, 'additive': False, 'size': (5.5, 0.1, 2)}) def create_lift(self, x, y): shared = SharedObjects.get() color = (0.7, 0.6, 0.5) - floor = ba.newnode('region', attrs={'position': (x, y, -5.52), 'scale': ( + floor = bs.newnode('region', attrs={'position': (x, y, -5.52), 'scale': ( 1.8, 0.1, 2), 'type': 'box', 'materials': [shared.footing_material, self._real_wall_material, self._lift_material]}) - cleaner = ba.newnode('region', attrs={'position': (x, y, -5.52), 'scale': ( + cleaner = bs.newnode('region', attrs={'position': (x, y, -5.52), 'scale': ( 2, 0.3, 2), 'type': 'box', 'materials': [shared.footing_material, self._real_wall_material]}) - lift = ba.newnode('locator', attrs={'shape': 'box', 'position': ( + lift = bs.newnode('locator', attrs={'shape': 'box', 'position': ( x, y, -5.52), 'color': color, 'opacity': 1, 'draw_beauty': True, 'additive': False, 'size': (1.8, 3.7, 2)}) - _tcombine = ba.newnode('combine', + _tcombine = bs.newnode('combine', owner=floor, attrs={ 'input0': x, 'input2': -5.5, 'size': 3 }) - mnode = ba.newnode('math', + mnode = bs.newnode('math', owner=lift, attrs={ 'input1': (0, 2, 0), @@ -184,7 +184,7 @@ def create_lift(self, x, y): }) _tcombine.connectattr('output', mnode, 'input2') - _cleaner_combine = ba.newnode('combine', + _cleaner_combine = bs.newnode('combine', owner=cleaner, attrs={ 'input1': 5.6, @@ -192,10 +192,10 @@ def create_lift(self, x, y): 'size': 3 }) _cleaner_combine.connectattr('output', cleaner, 'position') - ba.animate(_tcombine, 'input1', { + bs.animate(_tcombine, 'input1', { 0: 5.1, }) - ba.animate(_cleaner_combine, 'input0', { + bs.animate(_cleaner_combine, 'input0', { 0: -19 if x < 0 else 19, }) @@ -205,29 +205,29 @@ def create_lift(self, x, y): "cleaner": _cleaner_combine, 'leftLift': x < 0} def _handle_lift(self): - region = ba.getcollision().sourcenode + region = bs.getcollision().sourcenode lift = self.lifts[region] def clean(lift): - ba.animate(lift["cleaner"], 'input0', { + bs.animate(lift["cleaner"], 'input0', { 0: -19 if lift["leftLift"] else 19, 2: -16 if lift["leftLift"] else 16, 4.3: -19 if lift["leftLift"] else 19 }) if lift["state"] == "origin": lift["state"] = "transition" - ba.animate(lift["lift"], 'input1', { + bs.animate(lift["lift"], 'input1', { 0: 5.1, 1.3: 5.1, 6: 5+12, 9: 5+12, 15: 5.1 }) - ba.timer(16, ba.Call(lambda lift: lift.update({'state': 'end'}), lift)) - ba.timer(12, ba.Call(clean, lift)) + bs.timer(16, babase.Call(lambda lift: lift.update({'state': 'end'}), lift)) + bs.timer(12, babase.Call(clean, lift)) def _handle_lift_disconnect(self): - region = ba.getcollision().sourcenode + region = bs.getcollision().sourcenode lift = self.lifts[region] if lift["state"] == 'end': lift["state"] = "origin" @@ -236,9 +236,9 @@ def create_slope(self, x, y, backslash): shared = SharedObjects.get() for i in range(0, 21): - ba.newnode('region', attrs={'position': (x, y, -5.52), 'scale': (0.2, 0.1, 6), + bs.newnode('region', attrs={'position': (x, y, -5.52), 'scale': (0.2, 0.1, 6), 'type': 'box', 'materials': [shared.footing_material, self._real_wall_material]}) - ba.newnode('locator', attrs={'shape': 'box', 'position': (x, y, -5.52), 'color': ( + bs.newnode('locator', attrs={'shape': 'box', 'position': (x, y, -5.52), 'color': ( 1, 1, 0), 'opacity': 1, 'draw_beauty': True, 'additive': False, 'size': (0.2, 0.1, 2)}) if backslash: x = x+0.1 @@ -292,7 +292,7 @@ class mapdefs: 0.5245740665, 0.5245740665, 0.01941146064) -class CreativeThoughts(ba.Map): +class CreativeThoughts(bs.Map): """Freaking map by smoothy.""" defs = mapdefs @@ -313,26 +313,26 @@ def get_preview_texture_name(cls) -> str: @classmethod def on_preload(cls) -> Any: data: Dict[str, Any] = { - 'model': ba.getmodel('alwaysLandLevel'), - 'bottom_model': ba.getmodel('alwaysLandLevelBottom'), - 'bgmodel': ba.getmodel('alwaysLandBG'), - 'collide_model': ba.getcollidemodel('alwaysLandLevelCollide'), - 'tex': ba.gettexture('alwaysLandLevelColor'), - 'bgtex': ba.gettexture('alwaysLandBGColor'), - 'vr_fill_mound_model': ba.getmodel('alwaysLandVRFillMound'), - 'vr_fill_mound_tex': ba.gettexture('vrFillMound') + 'mesh': bs.getmesh('alwaysLandLevel'), + 'bottom_mesh': bs.getmesh('alwaysLandLevelBottom'), + 'bgmesh': bs.getmesh('alwaysLandBG'), + 'collision_mesh': bs.getcollisionmesh('alwaysLandLevelCollide'), + 'tex': bs.gettexture('alwaysLandLevelColor'), + 'bgtex': bs.gettexture('alwaysLandBGColor'), + 'vr_fill_mound_mesh': bs.getmesh('alwaysLandVRFillMound'), + 'vr_fill_mound_tex': bs.gettexture('vrFillMound') } return data @classmethod - def get_music_type(cls) -> ba.MusicType: - return ba.MusicType.FLYING + def get_music_type(cls) -> bs.MusicType: + return bs.MusicType.FLYING def __init__(self) -> None: super().__init__(vr_overlay_offset=(0, -3.7, 2.5)) shared = SharedObjects.get() - self._fake_wall_material = ba.Material() - self._real_wall_material = ba.Material() + self._fake_wall_material = bs.Material() + self._real_wall_material = bs.Material() self._fake_wall_material.add_actions( conditions=(('they_are_younger_than', 9000), 'and', ('they_have_material', shared.player_material)), @@ -348,29 +348,29 @@ def __init__(self) -> None: ('modify_part_collision', 'physical', True) )) - self.background = ba.newnode( + self.background = bs.newnode( 'terrain', attrs={ - 'model': self.preloaddata['bgmodel'], + 'mesh': self.preloaddata['bgmesh'], 'lighting': False, 'background': True, - 'color_texture': ba.gettexture("rampageBGColor") + 'color_texture': bs.gettexture("rampageBGColor") }) - self.leftwall = ba.newnode('region', attrs={'position': (-17.75152479, 13, -5.52), 'scale': ( + self.leftwall = bs.newnode('region', attrs={'position': (-17.75152479, 13, -5.52), 'scale': ( 0.1, 15.5, 2), 'type': 'box', 'materials': [shared.footing_material, self._real_wall_material]}) - self.rightwall = ba.newnode('region', attrs={'position': (17.75, 13, -5.52), 'scale': ( + self.rightwall = bs.newnode('region', attrs={'position': (17.75, 13, -5.52), 'scale': ( 0.1, 15.5, 2), 'type': 'box', 'materials': [shared.footing_material, self._real_wall_material]}) - self.topwall = ba.newnode('region', attrs={'position': (0, 21.0, -5.52), 'scale': ( + self.topwall = bs.newnode('region', attrs={'position': (0, 21.0, -5.52), 'scale': ( 35.4, 0.2, 2), 'type': 'box', 'materials': [shared.footing_material, self._real_wall_material]}) - ba.newnode('locator', attrs={'shape': 'box', 'position': (-17.75152479, 13, -5.52), 'color': ( + bs.newnode('locator', attrs={'shape': 'box', 'position': (-17.75152479, 13, -5.52), 'color': ( 0, 0, 0), 'opacity': 1, 'draw_beauty': True, 'additive': False, 'size': (0.1, 15.5, 2)}) - ba.newnode('locator', attrs={'shape': 'box', 'position': (17.75, 13, -5.52), 'color': ( + bs.newnode('locator', attrs={'shape': 'box', 'position': (17.75, 13, -5.52), 'color': ( 0, 0, 0), 'opacity': 1, 'draw_beauty': True, 'additive': False, 'size': (0.1, 15.5, 2)}) - ba.newnode('locator', attrs={'shape': 'box', 'position': (0, 21.0, -5.52), 'color': ( + bs.newnode('locator', attrs={'shape': 'box', 'position': (0, 21.0, -5.52), 'color': ( 0, 0, 0), 'opacity': 1, 'draw_beauty': True, 'additive': False, 'size': (35.4, 0.2, 2)}) - gnode = ba.getactivity().globalsnode + gnode = bs.getactivity().globalsnode gnode.happy_thoughts_mode = True gnode.shadow_offset = (0.0, 8.0, 5.0) gnode.tint = (1.3, 1.23, 1.0) @@ -381,9 +381,9 @@ def __init__(self) -> None: self.is_flying = True # throw out some tips on flying - txt = ba.newnode('text', + txt = bs.newnode('text', attrs={ - 'text': ba.Lstr(resource='pressJumpToFlyText'), + 'text': babase.Lstr(resource='pressJumpToFlyText'), 'scale': 1.2, 'maxwidth': 800, 'position': (0, 200), @@ -392,7 +392,7 @@ def __init__(self) -> None: 'h_align': 'center', 'v_attach': 'bottom' }) - cmb = ba.newnode('combine', + cmb = bs.newnode('combine', owner=txt, attrs={ 'size': 4, @@ -400,12 +400,12 @@ def __init__(self) -> None: 'input1': 0.9, 'input2': 0.0 }) - ba.animate(cmb, 'input3', {3.0: 0, 4.0: 1, 9.0: 1, 10.0: 0}) + bs.animate(cmb, 'input3', {3.0: 0, 4.0: 1, 9.0: 1, 10.0: 0}) cmb.connectattr('output', txt, 'color') - ba.timer(10.0, txt.delete) + bs.timer(10.0, txt.delete) try: - ba._map.register_map(CreativeThoughts) + bs._map.register_map(CreativeThoughts) except: pass diff --git a/plugins/minigames/simon_says.py b/plugins/minigames/simon_says.py index ad3ac276..5640951d 100644 --- a/plugins/minigames/simon_says.py +++ b/plugins/minigames/simon_says.py @@ -1,6 +1,7 @@ +# Porting to api 8 made easier by baport.(https://github.com/bombsquad-community/baport) # SimonSays # you had really better do what Simon says... -# ba_meta require api 7 +# ba_meta require api 8 from __future__ import annotations from typing import TYPE_CHECKING @@ -8,19 +9,21 @@ if TYPE_CHECKING: from typing import Any, Union, Sequence -from ba import _gameutils -import ba +from bascenev1 import _gameutils +import babase +import bauiv1 as bui +import bascenev1 as bs import random -class CustomText(ba.Actor): +class CustomText(bs.Actor): """Text that pops up above a position to denote something special. category: Gameplay Classes """ def __init__(self, - text: Union[str, ba.Lstr], + text: Union[str, babase.Lstr], position: Sequence[float] = (0.0, 0.0, 0.0), color: Sequence[float] = (1.0, 1.0, 1.0, 1.0), random_offset: float = 0.5, @@ -34,7 +37,7 @@ def __init__(self, (0.5 - random.random()), position[1] + offset[0] + random_offset * (0.5 - random.random()), position[2] + offset[0] + random_offset * (0.5 - random.random())) - self.node = ba.newnode('text', + self.node = bs.newnode('text', attrs={ 'text': text, 'in_world': True, @@ -42,27 +45,27 @@ def __init__(self, 'flatness': 1.0, 'h_align': 'center'}, delegate=self) lifespan = duration - ba.animate( + bs.animate( self.node, 'scale', { 0: 0.0, lifespan * 0.11: 0.020 * 0.7 * scale, lifespan * 0.16: 0.013 * 0.7 * scale, lifespan * 0.25: 0.014 * 0.7 * scale }) - self._tcombine = ba.newnode('combine', + self._tcombine = bs.newnode('combine', owner=self.node, attrs={ 'input0': pos[0], 'input2': pos[2], 'size': 3 }) - ba.animate(self._tcombine, 'input1', { + bs.animate(self._tcombine, 'input1', { 0: pos[1] + 1.5, lifespan: pos[1] + 2.0 }) self._tcombine.connectattr('output', self.node, 'position') # fade our opacity in/out - self._combine = ba.newnode('combine', + self._combine = bs.newnode('combine', owner=self.node, attrs={ 'input0': color[0], @@ -71,64 +74,64 @@ def __init__(self, 'size': 4 }) for i in range(4): - ba.animate( + bs.animate( self._combine, 'input' + str(i), { 0.13 * lifespan: color[i], 0.18 * lifespan: 4.0 * color[i], 0.22 * lifespan: color[i]}) - ba.animate(self._combine, 'input3', { + bs.animate(self._combine, 'input3', { 0: 0, 0.1 * lifespan: color[3], 0.7 * lifespan: color[3], lifespan: 0}) self._combine.connectattr('output', self.node, 'color') - self._die_timer = ba.Timer( - lifespan, ba.WeakCall(self.handlemessage, ba.DieMessage())) + self._die_timer = bs.Timer( + lifespan, bs.WeakCall(self.handlemessage, bs.DieMessage())) def handlemessage(self, msg: Any) -> Any: assert not self.expired - if isinstance(msg, ba.DieMessage): + if isinstance(msg, bs.DieMessage): if self.node: self.node.delete() else: super().handlemessage(msg) -class Player(ba.Player['Team']): +class Player(bs.Player['Team']): """Our player type for this game.""" def __init__(self) -> None: self.score = 0 -class Team(ba.Team[Player]): +class Team(bs.Team[Player]): """Our team type for this game.""" def __init__(self) -> None: self.score = 0 -# ba_meta export game +# ba_meta export bascenev1.GameActivity -class SimonSays(ba.TeamGameActivity[Player, Team]): +class SimonSays(bs.TeamGameActivity[Player, Team]): name = "Simon Says" description = "You have to better do what Simon says!" @classmethod - def get_available_settings(cls, sessiontype: Type[ba.Session]) -> List[ba.Setting]: + def get_available_settings(cls, sessiontype: Type[bs.Session]) -> List[babase.Setting]: settings = [ - ba.BoolSetting("Epic Mode", default=False), - ba.BoolSetting("Enable Jumping", default=False), - ba.BoolSetting("Enable Punching", default=False), - ba.BoolSetting("Enable Picking Up", default=False), - ba.IntChoiceSetting("Timer Speed", + bs.BoolSetting("Epic Mode", default=False), + bs.BoolSetting("Enable Jumping", default=False), + bs.BoolSetting("Enable Punching", default=False), + bs.BoolSetting("Enable Picking Up", default=False), + bs.IntChoiceSetting("Timer Speed", choices=[("Snaily", 1200), ("Slow", 900), ("Normal", 655), ("Fast", 544), ("Turbo", 460)], default=655), - ba.FloatChoiceSetting("Text Duration", + bs.FloatChoiceSetting("Text Duration", choices=[("Slow", 2.5), ("Normal", 1.5), ("Mediocre", 1.0), @@ -136,12 +139,12 @@ def get_available_settings(cls, sessiontype: Type[ba.Session]) -> List[ba.Settin return settings @classmethod - def get_supported_maps(cls, sessiontype: Type[ba.Session]) -> List[str]: + def get_supported_maps(cls, sessiontype: Type[bs.Session]) -> List[str]: return ["Courtyard"] @classmethod - def supports_session_type(cls, sessiontype: Type[ba.Session]) -> bool: - return issubclass(sessiontype, ba.FreeForAllSession) + def supports_session_type(cls, sessiontype: Type[bs.Session]) -> bool: + return issubclass(sessiontype, bs.FreeForAllSession) def __init__(self, settings: dict): super().__init__(settings) @@ -157,7 +160,7 @@ def __init__(self, settings: dict): self.counter_loop = None self.time = 5000 self._r1 = 2 - self.ct_text = ba.newnode('text', attrs={ + self.ct_text = bs.newnode('text', attrs={ 'in_world': True, 'text': '......', 'shadow': 1.0, @@ -165,44 +168,44 @@ def __init__(self, settings: dict): 'flatness': 0.5, 'position': (-5.627144702, 3.3275475, -9.572879116), 'scale': 0.05}) - self.n1 = ba.newnode('locator', attrs={'shape': 'circle', 'position': (-4, 0, -6), + self.n1 = bs.newnode('locator', attrs={'shape': 'circle', 'position': (-4, 0, -6), 'color': (1, 0, 0), 'opacity': 0.5, 'draw_beauty': True, 'additive': True}) - self.n2 = ba.newnode('locator', attrs={'shape': 'circle', 'position': (0, 0, -6), + self.n2 = bs.newnode('locator', attrs={'shape': 'circle', 'position': (0, 0, -6), 'color': (0, 1, 0), 'opacity': 0.5, 'draw_beauty': True, 'additive': True}) - self.n3 = ba.newnode('locator', attrs={'shape': 'circle', 'position': (4, 0, -6), + self.n3 = bs.newnode('locator', attrs={'shape': 'circle', 'position': (4, 0, -6), 'color': (0, 0, 1), 'opacity': 0.5, 'draw_beauty': True, 'additive': True}) - self.n4 = ba.newnode('locator', attrs={'shape': 'circle', 'position': (-4, 0, -2), + self.n4 = bs.newnode('locator', attrs={'shape': 'circle', 'position': (-4, 0, -2), 'color': (1, 1, 0), 'opacity': 0.5, 'draw_beauty': True, 'additive': True}) - self.n5 = ba.newnode('locator', attrs={'shape': 'circle', 'position': (0, 0, -2), + self.n5 = bs.newnode('locator', attrs={'shape': 'circle', 'position': (0, 0, -2), 'color': (0, 1, 1), 'opacity': 0.5, 'draw_beauty': True, 'additive': True}) - self.n6 = ba.newnode('locator', attrs={'shape': 'circle', 'position': (4, 0, -2), + self.n6 = bs.newnode('locator', attrs={'shape': 'circle', 'position': (4, 0, -2), 'color': (1, 0, 1), 'opacity': 0.5, 'draw_beauty': True, 'additive': True}) - self.n7 = ba.newnode('locator', attrs={'shape': 'circle', 'position': (-4, 0, 2), + self.n7 = bs.newnode('locator', attrs={'shape': 'circle', 'position': (-4, 0, 2), 'color': (.5, .5, .5), 'opacity': 0.5, 'draw_beauty': True, 'additive': True}) - self.n8 = ba.newnode('locator', attrs={'shape': 'circle', 'position': (0, 0, 2), + self.n8 = bs.newnode('locator', attrs={'shape': 'circle', 'position': (0, 0, 2), 'color': (.5, .325, 0), 'opacity': 0.5, 'draw_beauty': True, 'additive': True}) - self.n9 = ba.newnode('locator', attrs={'shape': 'circle', 'position': (4, 0, 2), + self.n9 = bs.newnode('locator', attrs={'shape': 'circle', 'position': (4, 0, 2), 'color': (1, 1, 1), 'opacity': 0.5, 'draw_beauty': True, 'additive': True}) self.options = ["red", "green", "blue", "yellow", "teal", "purple", "gray", "orange", "white", "top", "bottom", "middle row", "left", "right", "center column", "outside"] - self.default_music = ba.MusicType.FLAG_CATCHER + self.default_music = bs.MusicType.FLAG_CATCHER def get_instance_description(self) -> str: return 'Follow the commands... but only when \"Simon says!"' def on_player_join(self, player: Player) -> None: if self.has_begun(): - ba.screenmessage( - ba.Lstr(resource='playerDelayedJoinText', + bs.broadcastmessage( + babase.Lstr(resource='playerDelayedJoinText', subs=[('${PLAYER}', player.getname(full=True))]), color=(0, 1, 0),) return @@ -227,11 +230,11 @@ def on_begin(self) -> None: player.score = 0 # check for immediate end if theres only 1 player if len(self.players) == 1: - ba.timer(4000, lambda: self.check_end(), timeformat=ba.TimeFormat.MILLISECONDS) + bs.timer(4000/1000, lambda: self.check_end()) else: - ba.timer(6000, self.call_round, timeformat=ba.TimeFormat.MILLISECONDS) + bs.timer(6000/1000, self.call_round) - def spawn_player(self, player: PlayerType) -> ba.Actor: + def spawn_player(self, player: PlayerT) -> bs.Actor: assert player spaz = self.spawn_player_spaz(player, position=( 0 + random.uniform(-3.6, 3.6), 2.9, -2 + random.uniform(-3.6, 3.6))) @@ -291,12 +294,11 @@ def set_counter(): self.string = "0" self.ct_text.text = self.string self.counter_loop = None - ba.timer(1, dummy_check, timeformat=ba.TimeFormat.MILLISECONDS) + bs.timer(1/1000, dummy_check) else: self.ct_text.text = str(self.now) - ba.playsound(ba.getsound('tick')) - self.counter_loop = ba.Timer(self.speed, set_counter, - timeformat=ba.TimeFormat.MILLISECONDS, repeat=True) + bs.getsound('tick').play() + self.counter_loop = bs.Timer(self.speed/1000, set_counter, repeat=True) def check_round(self) -> None: if self.ended: @@ -307,8 +309,8 @@ def check_round(self) -> None: player.actor.node.position_center) else False if ((self.simon and safe == False) or ((not self.simon) and safe == True)): player.team.score = self.round_num - player.actor.handlemessage(ba.DieMessage()) - ba.timer(1633, self.call_round, timeformat=ba.TimeFormat.MILLISECONDS) + player.actor.handlemessage(bs.DieMessage()) + bs.timer(1633/1000, self.call_round) def in_circle(self, pos) -> None: circles = [] @@ -349,14 +351,14 @@ def in_circle(self, pos) -> None: return circles def handlemessage(self, msg) -> None: - if isinstance(msg, ba.PlayerDiedMessage): + if isinstance(msg, bs.PlayerDiedMessage): self.check_end() else: super().handlemessage(msg) def end_game(self) -> None: self.ended = True - results = ba.GameResults() + results = bs.GameResults() for team in self.teams: results.set_team_score(team, team.score) self.end(results=results) @@ -367,4 +369,4 @@ def check_end(self) -> None: if player.is_alive(): i += 1 if i <= 2: - ba.timer(0.6, lambda: self.end_game()) + bs.timer(0.6, lambda: self.end_game()) diff --git a/plugins/minigames/sleep_race.py b/plugins/minigames/sleep_race.py index 104c98ce..3f003122 100644 --- a/plugins/minigames/sleep_race.py +++ b/plugins/minigames/sleep_race.py @@ -1,3 +1,4 @@ +# Porting to api 8 made easier by baport.(https://github.com/bombsquad-community/baport) # Released under the MIT License. See LICENSE for details. # y me (: itsre3 # =>2<= @@ -5,7 +6,7 @@ # """Defines Race mini-game.""" -# ba_meta require api 7 +# ba_meta require api 8 # (see https://ballistica.net/wiki/meta-tag-system) from __future__ import annotations @@ -14,17 +15,17 @@ from typing import TYPE_CHECKING from dataclasses import dataclass -import ba -import _ba -from bastd.actor.bomb import Bomb -from bastd.actor.playerspaz import PlayerSpaz -from bastd.actor.scoreboard import Scoreboard -from bastd.gameutils import SharedObjects +import babase +import bascenev1 as bs +from bascenev1lib.actor.bomb import Bomb +from bascenev1lib.actor.playerspaz import PlayerSpaz +from bascenev1lib.actor.scoreboard import Scoreboard +from bascenev1lib.gameutils import SharedObjects if TYPE_CHECKING: from typing import (Any, Type, Tuple, List, Sequence, Optional, Dict, Union) - from bastd.actor.onscreentimer import OnScreenTimer + from bascenev1lib.actor.onscreentimer import OnScreenTimer @dataclass @@ -34,7 +35,7 @@ class RaceMine: mine: Optional[Bomb] -class RaceRegion(ba.Actor): +class RaceRegion(bs.Actor): """Region used to track progress during a race.""" def __init__(self, pt: Sequence[float], index: int): @@ -43,7 +44,7 @@ def __init__(self, pt: Sequence[float], index: int): assert isinstance(activity, RaceGame) self.pos = pt self.index = index - self.node = ba.newnode( + self.node = bs.newnode( 'region', delegate=self, attrs={ @@ -54,11 +55,11 @@ def __init__(self, pt: Sequence[float], index: int): }) -class Player(ba.Player['Team']): +class Player(bs.Player['Team']): """Our player type for this game.""" def __init__(self) -> None: - self.distance_txt: Optional[ba.Node] = None + self.distance_txt: Optional[bs.Node] = None self.last_region = 0 self.lap = 0 self.distance = 0.0 @@ -66,7 +67,7 @@ def __init__(self) -> None: self.rank: Optional[int] = None -class Team(ba.Team[Player]): +class Team(bs.Team[Player]): """Our team type for this game.""" def __init__(self) -> None: @@ -75,22 +76,22 @@ def __init__(self) -> None: self.finished = False -# ba_meta export game -class SleepRaceGame(ba.TeamGameActivity[Player, Team]): +# ba_meta export bascenev1.GameActivity +class SleepRaceGame(bs.TeamGameActivity[Player, Team]): """Game of racing around a track.""" name = 'Sleep Race' description = 'Can you run while sleeping?' - scoreconfig = ba.ScoreConfig(label='Time', + scoreconfig = bs.ScoreConfig(label='Time', lower_is_better=True, - scoretype=ba.ScoreType.MILLISECONDS) + scoretype=bs.ScoreType.MILLISECONDS) @classmethod def get_available_settings( - cls, sessiontype: Type[ba.Session]) -> List[ba.Setting]: + cls, sessiontype: Type[bs.Session]) -> List[babase.Setting]: settings = [ - ba.IntSetting('Laps', min_value=1, default=2, increment=1), - ba.IntChoiceSetting( + bs.IntSetting('Laps', min_value=1, default=2, increment=1), + bs.IntChoiceSetting( 'Time Limit', default=0, choices=[ @@ -102,7 +103,7 @@ def get_available_settings( ('20 Minutes', 1200), ], ), - ba.IntChoiceSetting( + bs.IntChoiceSetting( 'Mine Spawning', default=4000, choices=[ @@ -112,7 +113,7 @@ def get_available_settings( ('2 Seconds', 2000), ], ), - ba.IntChoiceSetting( + bs.IntChoiceSetting( 'Bomb Spawning', choices=[ ('None', 0), @@ -123,7 +124,7 @@ def get_available_settings( ], default=2000, ), - ba.IntChoiceSetting( + bs.IntChoiceSetting( 'Knockout Time', choices=[ ('8 Seconds', 8000), @@ -131,48 +132,48 @@ def get_available_settings( ], default=5000, ), - ba.BoolSetting('Epic Mode', default=False), - ba.BoolSetting('Credits', default=True), + bs.BoolSetting('Epic Mode', default=False), + bs.BoolSetting('Credits', default=True), ] # We have some specific settings in teams mode. - if issubclass(sessiontype, ba.DualTeamSession): + if issubclass(sessiontype, bs.DualTeamSession): settings.append( - ba.BoolSetting('Entire Team Must Finish', default=False)) + bs.BoolSetting('Entire Team Must Finish', default=False)) return settings @classmethod - def supports_session_type(cls, sessiontype: Type[ba.Session]) -> bool: - return issubclass(sessiontype, ba.MultiTeamSession) + def supports_session_type(cls, sessiontype: Type[bs.Session]) -> bool: + return issubclass(sessiontype, bs.MultiTeamSession) @classmethod - def get_supported_maps(cls, sessiontype: Type[ba.Session]) -> List[str]: - return ba.getmaps('race') + def get_supported_maps(cls, sessiontype: Type[bs.Session]) -> List[str]: + return bs.app.classic.getmaps('race') def __init__(self, settings: dict): self._race_started = False super().__init__(settings) self._scoreboard = Scoreboard() - self._score_sound = ba.getsound('score') - self._swipsound = ba.getsound('swip') + self._score_sound = bs.getsound('score') + self._swipsound = bs.getsound('swip') self._last_team_time: Optional[float] = None self._front_race_region: Optional[int] = None - self._nub_tex = ba.gettexture('nub') - self._beep_1_sound = ba.getsound('raceBeep1') - self._beep_2_sound = ba.getsound('raceBeep2') - self.race_region_material: Optional[ba.Material] = None + self._nub_tex = bs.gettexture('nub') + self._beep_1_sound = bs.getsound('raceBeep1') + self._beep_2_sound = bs.getsound('raceBeep2') + self.race_region_material: Optional[bs.Material] = None self._regions: List[RaceRegion] = [] self._team_finish_pts: Optional[int] = None - self._time_text: Optional[ba.Actor] = None - self._cd_text: Optional[ba.Actor] = None + self._time_text: Optional[bs.Actor] = None + self._cd_text: Optional[bs.Actor] = None self._timer: Optional[OnScreenTimer] = None self._race_mines: Optional[List[RaceMine]] = None - self._race_mine_timer: Optional[ba.Timer] = None - self._scoreboard_timer: Optional[ba.Timer] = None - self._player_order_update_timer: Optional[ba.Timer] = None - self._start_lights: Optional[List[ba.Node]] = None - self._bomb_spawn_timer: Optional[ba.Timer] = None - self._knockout_timer: Optional[ba.Timer] = None + self._race_mine_timer: Optional[bs.Timer] = None + self._scoreboard_timer: Optional[bs.Timer] = None + self._player_order_update_timer: Optional[bs.Timer] = None + self._start_lights: Optional[List[bs.Node]] = None + self._bomb_spawn_timer: Optional[bs.Timer] = None + self._knockout_timer: Optional[bs.Timer] = None self._laps = int(settings['Laps']) self._entire_team_must_finish = bool( settings.get('Entire Team Must Finish', False)) @@ -185,11 +186,11 @@ def __init__(self, settings: dict): # Base class overrides. self.slow_motion = self._epic_mode - self.default_music = (ba.MusicType.EPIC_RACE - if self._epic_mode else ba.MusicType.RACE) + self.default_music = (bs.MusicType.EPIC_RACE + if self._epic_mode else bs.MusicType.RACE) def get_instance_description(self) -> Union[str, Sequence]: - if (isinstance(self.session, ba.DualTeamSession) + if (isinstance(self.session, bs.DualTeamSession) and self._entire_team_must_finish): t_str = ' Your entire team has to finish.' else: @@ -208,7 +209,7 @@ def on_transition_in(self) -> None: super().on_transition_in() shared = SharedObjects.get() pts = self.map.get_def_points('race_point') - mat = self.race_region_material = ba.Material() + mat = self.race_region_material = bs.Material() mat.add_actions(conditions=('they_have_material', shared.player_material), actions=( @@ -224,28 +225,28 @@ def _flash_player(self, player: Player, scale: float) -> None: assert isinstance(player.actor, PlayerSpaz) assert player.actor.node pos = player.actor.node.position - light = ba.newnode('light', + light = bs.newnode('light', attrs={ 'position': pos, 'color': (1, 1, 0), 'height_attenuated': False, 'radius': 0.4 }) - ba.timer(0.5, light.delete) - ba.animate(light, 'intensity', {0: 0, 0.1: 1.0 * scale, 0.5: 0}) + bs.timer(0.5, light.delete) + bs.animate(light, 'intensity', {0: 0, 0.1: 1.0 * scale, 0.5: 0}) def _handle_race_point_collide(self) -> None: # FIXME: Tidy this up. # pylint: disable=too-many-statements # pylint: disable=too-many-branches # pylint: disable=too-many-nested-blocks - collision = ba.getcollision() + collision = bs.getcollision() try: region = collision.sourcenode.getdelegate(RaceRegion, True) player = collision.opposingnode.getdelegate(PlayerSpaz, True).getplayer( Player, True) - except ba.NotFoundError: + except bs.NotFoundError: return last_region = player.last_region @@ -259,8 +260,8 @@ def _handle_race_point_collide(self) -> None: if this_region > last_region + 2: if player.is_alive(): assert player.actor - player.actor.handlemessage(ba.DieMessage()) - ba.screenmessage(ba.Lstr( + player.actor.handlemessage(bs.DieMessage()) + bs.broadcastmessage(babase.Lstr( translate=('statements', 'Killing ${NAME} for' ' skipping part of the track!'), subs=[('${NAME}', player.getname(full=True))]), @@ -279,7 +280,7 @@ def _handle_race_point_collide(self) -> None: # In teams mode with all-must-finish on, the team lap # value is the min of all team players. # Otherwise its the max. - if isinstance(self.session, ba.DualTeamSession + if isinstance(self.session, bs.DualTeamSession ) and self._entire_team_must_finish: team.lap = min([p.lap for p in team.players]) else: @@ -290,7 +291,7 @@ def _handle_race_point_collide(self) -> None: # In teams mode, hand out points based on the order # players come in. - if isinstance(self.session, ba.DualTeamSession): + if isinstance(self.session, bs.DualTeamSession): assert self._team_finish_pts is not None if self._team_finish_pts > 0: self.stats.player_scored(player, @@ -303,7 +304,7 @@ def _handle_race_point_collide(self) -> None: player.finished = True assert player.actor player.actor.handlemessage( - ba.DieMessage(immediate=True)) + bs.DieMessage(immediate=True)) # Makes sure noone behind them passes them in rank # while finishing. @@ -311,26 +312,26 @@ def _handle_race_point_collide(self) -> None: # If the whole team has finished the race. if team.lap == self._laps: - ba.playsound(self._score_sound) + self._score_sound.play() player.team.finished = True assert self._timer is not None - elapsed = ba.time() - self._timer.getstarttime() + elapsed = bs.time() - self._timer.getstarttime() self._last_team_time = player.team.time = elapsed self._check_end_game() # Team has yet to finish. else: - ba.playsound(self._swipsound) + self._swipsound.play() # They've just finished a lap but not the race. else: - ba.playsound(self._swipsound) + self._swipsound.play() self._flash_player(player, 0.3) # Print their lap number over their head. try: assert isinstance(player.actor, PlayerSpaz) - mathnode = ba.newnode('math', + mathnode = bs.newnode('math', owner=player.actor.node, attrs={ 'input1': (0, 1.9, 0), @@ -338,12 +339,12 @@ def _handle_race_point_collide(self) -> None: }) player.actor.node.connectattr( 'torso_position', mathnode, 'input2') - tstr = ba.Lstr(resource='lapNumberText', + tstr = babase.Lstr(resource='lapNumberText', subs=[('${CURRENT}', str(player.lap + 1)), ('${TOTAL}', str(self._laps)) ]) - txtnode = ba.newnode('text', + txtnode = bs.newnode('text', owner=mathnode, attrs={ 'text': tstr, @@ -353,15 +354,15 @@ def _handle_race_point_collide(self) -> None: 'h_align': 'center' }) mathnode.connectattr('output', txtnode, 'position') - ba.animate(txtnode, 'scale', { + bs.animate(txtnode, 'scale', { 0.0: 0, 0.2: 0.019, 2.0: 0.019, 2.2: 0 }) - ba.timer(2.3, mathnode.delete) + bs.timer(2.3, mathnode.delete) except Exception: - ba.print_exception('Error printing lap.') + babase.print_exception('Error printing lap.') def on_team_join(self, team: Team) -> None: self._update_scoreboard() @@ -372,9 +373,9 @@ def on_player_leave(self, player: Player) -> None: # A player leaving disqualifies the team if 'Entire Team Must Finish' # is on (otherwise in teams mode everyone could just leave except the # leading player to win). - if (isinstance(self.session, ba.DualTeamSession) + if (isinstance(self.session, bs.DualTeamSession) and self._entire_team_must_finish): - ba.screenmessage(ba.Lstr( + bs.broadcastmessage(babase.Lstr( translate=('statements', '${TEAM} is disqualified because ${PLAYER} left'), subs=[('${TEAM}', player.team.name), @@ -383,18 +384,18 @@ def on_player_leave(self, player: Player) -> None: player.team.finished = True player.team.time = None player.team.lap = 0 - ba.playsound(ba.getsound('boo')) + bs.getsound('boo').play() for otherplayer in player.team.players: otherplayer.lap = 0 otherplayer.finished = True try: if otherplayer.actor is not None: - otherplayer.actor.handlemessage(ba.DieMessage()) + otherplayer.actor.handlemessage(bs.DieMessage()) except Exception: - ba.print_exception('Error sending DieMessage.') + babase.print_exception('Error sending DieMessage.') # Defer so team/player lists will be updated. - ba.pushcall(self._check_end_game) + babase.pushcall(self._check_end_game) def _update_scoreboard(self) -> None: for team in self.teams: @@ -402,7 +403,7 @@ def _update_scoreboard(self) -> None: if not distances: teams_dist = 0.0 else: - if (isinstance(self.session, ba.DualTeamSession) + if (isinstance(self.session, bs.DualTeamSession) and self._entire_team_must_finish): teams_dist = min(distances) else: @@ -415,14 +416,14 @@ def _update_scoreboard(self) -> None: show_value=False) def on_begin(self) -> None: - from bastd.actor.onscreentimer import OnScreenTimer + from bascenev1lib.actor.onscreentimer import OnScreenTimer super().on_begin() self.setup_standard_time_limit(self._time_limit) self.setup_standard_powerup_drops() self._team_finish_pts = 100 if self._credits: - self._cd_text = ba.NodeActor( - ba.newnode('text', + self._cd_text = bs.NodeActor( + bs.newnode('text', attrs={ 'position': (0, 0), 'h_attach': 'center', @@ -437,8 +438,8 @@ def on_begin(self) -> None: })) # Throw a timer up on-screen. - self._time_text = ba.NodeActor( - ba.newnode('text', + self._time_text = bs.NodeActor( + bs.newnode('text', attrs={ 'v_attach': 'top', 'h_attach': 'center', @@ -458,14 +459,14 @@ def on_begin(self) -> None: for p in self.map.get_def_points('race_mine') ] if self._race_mines: - self._race_mine_timer = ba.Timer(0.001 * self._mine_spawning, + self._race_mine_timer = bs.Timer(0.001 * self._mine_spawning, self._update_race_mine, repeat=True) - self._scoreboard_timer = ba.Timer(0.25, + self._scoreboard_timer = bs.Timer(0.25, self._update_scoreboard, repeat=True) - self._player_order_update_timer = ba.Timer(0.25, + self._player_order_update_timer = bs.Timer(0.25, self._update_player_order, repeat=True) @@ -478,30 +479,30 @@ def on_begin(self) -> None: lstart = 7.1 * t_scale inc = 1.25 * t_scale - ba.timer(lstart, self._do_light_1) - ba.timer(lstart + inc, self._do_light_2) - ba.timer(lstart + 2 * inc, self._do_light_3) - ba.timer(lstart + 3 * inc, self._start_race) + bs.timer(lstart, self._do_light_1) + bs.timer(lstart + inc, self._do_light_2) + bs.timer(lstart + 2 * inc, self._do_light_3) + bs.timer(lstart + 3 * inc, self._start_race) self._start_lights = [] for i in range(4): - lnub = ba.newnode('image', + lnub = bs.newnode('image', attrs={ - 'texture': ba.gettexture('nub'), + 'texture': bs.gettexture('nub'), 'opacity': 1.0, 'absolute_scale': True, 'position': (-75 + i * 50, light_y), 'scale': (50, 50), 'attach': 'center' }) - ba.animate( + bs.animate( lnub, 'opacity', { 4.0 * t_scale: 0, 5.0 * t_scale: 1.0, 12.0 * t_scale: 1.0, 12.5 * t_scale: 0.0 }) - ba.timer(13.0 * t_scale, lnub.delete) + bs.timer(13.0 * t_scale, lnub.delete) self._start_lights.append(lnub) self._start_lights[0].color = (0.2, 0, 0) @@ -512,45 +513,45 @@ def on_begin(self) -> None: def _do_light_1(self) -> None: assert self._start_lights is not None self._start_lights[0].color = (1.0, 0, 0) - ba.playsound(self._beep_1_sound) + self._beep_1_sound.play() def _do_light_2(self) -> None: assert self._start_lights is not None self._start_lights[1].color = (1.0, 0, 0) - ba.playsound(self._beep_1_sound) + self._beep_1_sound.play() def _do_light_3(self) -> None: assert self._start_lights is not None self._start_lights[2].color = (1.0, 0.3, 0) - ba.playsound(self._beep_1_sound) + self._beep_1_sound.play() def _start_race(self) -> None: assert self._start_lights is not None self._start_lights[3].color = (0.0, 1.0, 0) - ba.playsound(self._beep_2_sound) + self._beep_2_sound.play() for player in self.players: if player.actor is not None: try: assert isinstance(player.actor, PlayerSpaz) player.actor.connect_controls_to_player() except Exception: - ba.print_exception('Error in race player connects.') + babase.print_exception('Error in race player connects.') assert self._timer is not None self._timer.start() if self._bomb_spawning != 0: - self._bomb_spawn_timer = ba.Timer(0.001 * self._bomb_spawning, + self._bomb_spawn_timer = bs.Timer(0.001 * self._bomb_spawning, self._spawn_bomb, repeat=True) def knock_players(): - activity = _ba.get_foreground_host_activity() - gnode = ba.getactivity().globalsnode + activity = bs.get_foreground_host_activity() + gnode = bs.getactivity().globalsnode for players in activity.players: gnode.tint = (0.5, 0.5, 0.5) node = players.actor.node node.handlemessage('knockout', 600.0) - self.text_offset = ba.newnode('math', + self.text_offset = bs.newnode('math', owner=node, attrs={'input1': (-0.5, 0.5, 0.25), 'operation': 'add'}) @@ -558,7 +559,7 @@ def knock_players(): 'torso_position', self.text_offset, 'input2') - self.text = ba.newnode('text', + self.text = bs.newnode('text', owner=node, attrs={ 'h_align': 'right', @@ -571,12 +572,12 @@ def knock_players(): 'output', self.text, 'position') - ba.animate(self.text, 'scale', {0: 0.0, 1.0: 0.01}) - ba.timer(2, self.text.delete) + bs.animate(self.text, 'scale', {0: 0.0, 1.0: 0.01}) + bs.timer(2, self.text.delete) if self._knockout_time != 0: knock_time = 0.001 * self._knockout_time - self._knockout_timer = ba.Timer(knock_time, + self._knockout_timer = bs.Timer(knock_time, knock_players, repeat=True) @@ -586,18 +587,18 @@ def _update_player_order(self) -> None: # Calc all player distances. for player in self.players: - pos: Optional[ba.Vec3] + pos: Optional[babase.Vec3] try: pos = player.position - except ba.NotFoundError: + except bs.NotFoundError: pos = None if pos is not None: r_index = player.last_region rg1 = self._regions[r_index] - r1pt = ba.Vec3(rg1.pos[:3]) + r1pt = babase.Vec3(rg1.pos[:3]) rg2 = self._regions[0] if r_index == len( self._regions) - 1 else self._regions[r_index + 1] - r2pt = ba.Vec3(rg2.pos[:3]) + r2pt = babase.Vec3(rg2.pos[:3]) r2dist = (pos - r2pt).length() amt = 1.0 - (r2dist / (r2pt - r1pt).length()) amt = player.lap + (r_index + amt) * (1.0 / len(self._regions)) @@ -628,8 +629,8 @@ def _spawn_bomb(self) -> None: (-region_scale * pos[5], region_scale * pos[5])) pos = (pos[0] + random.uniform(*x_range), pos[1] + 1.0, pos[2] + random.uniform(*z_range)) - ba.timer(random.uniform(0.0, 2.0), - ba.WeakCall(self._spawn_bomb_at_pos, pos)) + bs.timer(random.uniform(0.0, 2.0), + bs.WeakCall(self._spawn_bomb_at_pos, pos)) def _spawn_bomb_at_pos(self, pos: Sequence[float]) -> None: if self.has_ended(): @@ -645,15 +646,15 @@ def _make_mine(self, i: int) -> None: def _flash_mine(self, i: int) -> None: assert self._race_mines is not None rmine = self._race_mines[i] - light = ba.newnode('light', + light = bs.newnode('light', attrs={ 'position': rmine.point[:3], 'color': (1, 0.2, 0.2), 'radius': 0.1, 'height_attenuated': False }) - ba.animate(light, 'intensity', {0.0: 0, 0.1: 1.0, 0.2: 0}, loop=True) - ba.timer(1.0, light.delete) + bs.animate(light, 'intensity', {0.0: 0, 0.1: 1.0, 0.2: 0}, loop=True) + bs.timer(1.0, light.delete) def _update_race_mine(self) -> None: assert self._race_mines is not None @@ -667,9 +668,9 @@ def _update_race_mine(self) -> None: assert rmine is not None if not rmine.mine: self._flash_mine(m_index) - ba.timer(0.95, ba.Call(self._make_mine, m_index)) + bs.timer(0.95, babase.Call(self._make_mine, m_index)) - def spawn_player(self, player: Player) -> ba.Actor: + def spawn_player(self, player: Player) -> bs.Actor: if player.team.finished: # FIXME: This is not type-safe! # This call is expected to always return an Actor! @@ -692,7 +693,7 @@ def spawn_player(self, player: Player) -> ba.Actor: # Prevent controlling of characters before the start of the race. if not self._race_started: spaz.disconnect_controls_from_player() - mathnode = ba.newnode('math', + mathnode = bs.newnode('math', owner=spaz.node, attrs={ 'input1': (0, 1.4, 0), @@ -700,7 +701,7 @@ def spawn_player(self, player: Player) -> ba.Actor: }) spaz.node.connectattr('torso_position', mathnode, 'input2') - distance_txt = ba.newnode('text', + distance_txt = bs.newnode('text', owner=spaz.node, attrs={ 'text': '', @@ -730,14 +731,14 @@ def _check_end_game(self) -> None: # In teams mode its over as soon as any team finishes the race # FIXME: The get_ffa_point_awards code looks dangerous. - if isinstance(session, ba.DualTeamSession): + if isinstance(session, bs.DualTeamSession): self.end_game() else: # In ffa we keep the race going while there's still any points # to be handed out. Find out how many points we have to award # and how many teams have finished, and once that matches # we're done. - assert isinstance(session, ba.FreeForAllSession) + assert isinstance(session, bs.FreeForAllSession) points_to_award = len(session.get_ffa_point_awards()) if teams_completed >= points_to_award - teams_completed: self.end_game() @@ -754,7 +755,7 @@ def end_game(self) -> None: endtime=None if self._last_team_time is None else ( self._timer.getstarttime() + self._last_team_time)) - results = ba.GameResults() + results = bs.GameResults() for team in self.teams: if team.time is not None: @@ -768,10 +769,10 @@ def end_game(self) -> None: # odd to be announcing that now. self.end(results=results, announce_winning_team=isinstance(self.session, - ba.DualTeamSession)) + bs.DualTeamSession)) def handlemessage(self, msg: Any) -> Any: - if isinstance(msg, ba.PlayerDiedMessage): + if isinstance(msg, bs.PlayerDiedMessage): # Augment default behavior. super().handlemessage(msg) player = msg.getplayer(Player) diff --git a/plugins/minigames/snake.py b/plugins/minigames/snake.py index 84e912b1..454a0703 100644 --- a/plugins/minigames/snake.py +++ b/plugins/minigames/snake.py @@ -1,19 +1,22 @@ +# Porting to api 8 made easier by baport.(https://github.com/bombsquad-community/baport) # snake # Released under the MIT License. See LICENSE for details. # """Snake game by SEBASTIAN2059""" -# ba_meta require api 7 +# ba_meta require api 8 # (see https://ballistica.net/wiki/meta-tag-system) from __future__ import annotations from typing import TYPE_CHECKING -import ba -from bastd.actor.playerspaz import PlayerSpaz -from bastd.actor.scoreboard import Scoreboard -from bastd.actor import bomb as stdbomb +import babase +import bauiv1 as bui +import bascenev1 as bs +from bascenev1lib.actor.playerspaz import PlayerSpaz +from bascenev1lib.actor.scoreboard import Scoreboard +from bascenev1lib.actor import bomb as stdbomb if TYPE_CHECKING: from typing import Any, Type, List, Dict, Tuple, Union, Sequence, Optional @@ -29,7 +32,7 @@ def getplayer(self): return self.player -class Player(ba.Player['Team']): +class Player(bs.Player['Team']): """Our player type for this game.""" def __init__(self) -> None: @@ -38,14 +41,14 @@ def __init__(self) -> None: self.actived = None -class Team(ba.Team[Player]): +class Team(bs.Team[Player]): """Our team type for this game.""" def __init__(self) -> None: self.score = 0 -lang = ba.app.lang.language +lang = bs.app.lang.language if lang == 'Spanish': description = 'Sobrevive a un número determinado de minas para ganar.' join_description = 'Corre y no te dejes matar.' @@ -65,15 +68,15 @@ def __init__(self, position, source_player): source_player=source_player) def handlemessage(self, msg: Any) -> Any: - if isinstance(msg, ba.HitMessage): + if isinstance(msg, bs.HitMessage): return else: super().handlemessage(msg) -# ba_meta export game +# ba_meta export bascenev1.GameActivity -class SnakeGame(ba.TeamGameActivity[Player, Team]): +class SnakeGame(bs.TeamGameActivity[Player, Team]): """A game type based on acquiring kills.""" name = 'Snake' @@ -84,15 +87,15 @@ class SnakeGame(ba.TeamGameActivity[Player, Team]): @classmethod def get_available_settings( - cls, sessiontype: Type[ba.Session]) -> List[ba.Setting]: + cls, sessiontype: Type[bs.Session]) -> List[babase.Setting]: settings = [ - ba.IntSetting( + bs.IntSetting( 'Score to Win', min_value=40, default=80, increment=5, ), - ba.IntChoiceSetting( + bs.IntChoiceSetting( 'Time Limit', choices=[ ('None', 0), @@ -104,7 +107,7 @@ def get_available_settings( ], default=0, ), - ba.FloatChoiceSetting( + bs.FloatChoiceSetting( 'Respawn Times', choices=[ ('Shorter', 0.25), @@ -115,27 +118,27 @@ def get_available_settings( ], default=1.0, ), - ba.BoolSetting('Epic Mode', default=False), + bs.BoolSetting('Epic Mode', default=False), ] return settings @classmethod - def supports_session_type(cls, sessiontype: Type[ba.Session]) -> bool: - return (issubclass(sessiontype, ba.DualTeamSession) - or issubclass(sessiontype, ba.FreeForAllSession)) + def supports_session_type(cls, sessiontype: Type[bs.Session]) -> bool: + return (issubclass(sessiontype, bs.DualTeamSession) + or issubclass(sessiontype, bs.FreeForAllSession)) @classmethod - def get_supported_maps(cls, sessiontype: Type[ba.Session]) -> List[str]: - return ba.getmaps('melee') + def get_supported_maps(cls, sessiontype: Type[bs.Session]) -> List[str]: + return bs.app.classic.getmaps('melee') def __init__(self, settings: dict): super().__init__(settings) self._scoreboard = Scoreboard() self._score_to_win: Optional[int] = None - self._dingsound = ba.getsound('dingSmall') + self._dingsound = bs.getsound('dingSmall') - self._beep_1_sound = ba.getsound('raceBeep1') - self._beep_2_sound = ba.getsound('raceBeep2') + self._beep_1_sound = bs.getsound('raceBeep1') + self._beep_2_sound = bs.getsound('raceBeep2') self._epic_mode = bool(settings['Epic Mode']) self._kills_to_win_per_player = int( @@ -146,8 +149,8 @@ def __init__(self, settings: dict): # Base class overrides. self.slow_motion = self._epic_mode - self.default_music = (ba.MusicType.EPIC if self._epic_mode else - ba.MusicType.TO_THE_DEATH) + self.default_music = (bs.MusicType.EPIC if self._epic_mode else + bs.MusicType.TO_THE_DEATH) def get_instance_description(self) -> Union[str, Sequence]: return join_description @@ -178,30 +181,30 @@ def on_begin(self) -> None: lstart = 7.1 * t_scale inc = 1.25 * t_scale - ba.timer(lstart, self._do_light_1) - ba.timer(lstart + inc, self._do_light_2) - ba.timer(lstart + 2 * inc, self._do_light_3) - ba.timer(lstart + 3 * inc, self._start_race) + bs.timer(lstart, self._do_light_1) + bs.timer(lstart + inc, self._do_light_2) + bs.timer(lstart + 2 * inc, self._do_light_3) + bs.timer(lstart + 3 * inc, self._start_race) self._start_lights = [] for i in range(4): - lnub = ba.newnode('image', + lnub = bs.newnode('image', attrs={ - 'texture': ba.gettexture('nub'), + 'texture': bs.gettexture('nub'), 'opacity': 1.0, 'absolute_scale': True, 'position': (-75 + i * 50, light_y), 'scale': (50, 50), 'attach': 'center' }) - ba.animate( + bs.animate( lnub, 'opacity', { 4.0 * t_scale: 0, 5.0 * t_scale: 1.0, 12.0 * t_scale: 1.0, 12.5 * t_scale: 0.0 }) - ba.timer(13.0 * t_scale, lnub.delete) + bs.timer(13.0 * t_scale, lnub.delete) self._start_lights.append(lnub) self._start_lights[0].color = (0.2, 0, 0) @@ -212,22 +215,22 @@ def on_begin(self) -> None: def _do_light_1(self) -> None: assert self._start_lights is not None self._start_lights[0].color = (1.0, 0, 0) - ba.playsound(self._beep_1_sound) + self._beep_1_sound.play() def _do_light_2(self) -> None: assert self._start_lights is not None self._start_lights[1].color = (1.0, 0, 0) - ba.playsound(self._beep_1_sound) + self._beep_1_sound.play() def _do_light_3(self) -> None: assert self._start_lights is not None self._start_lights[2].color = (1.0, 0.3, 0) - ba.playsound(self._beep_1_sound) + self._beep_1_sound.play() def _start_race(self) -> None: assert self._start_lights is not None self._start_lights[3].color = (0.0, 1.0, 0) - ba.playsound(self._beep_2_sound) + self._beep_2_sound.play() self._started = True @@ -235,7 +238,7 @@ def _start_race(self) -> None: self.generate_mines(player) # overriding the default character spawning.. - def spawn_player(self, player: Player) -> ba.Actor: + def spawn_player(self, player: Player) -> bs.Actor: spaz = self.spawn_player_spaz(player) # Let's reconnect this player's controls to this @@ -252,7 +255,7 @@ def spawn_player(self, player: Player) -> ba.Actor: def generate_mines(self, player: Player): try: - player.actived = ba.Timer(0.5, ba.Call(self.spawn_mine, player), repeat=True) + player.actived = bs.Timer(0.5, babase.Call(self.spawn_mine, player), repeat=True) except Exception as e: print('Exception -> ' + str(e)) @@ -271,7 +274,7 @@ def spawn_mine(self, player: Player): def arm(): mine.arm() - ba.timer(0.5, arm) + bs.timer(0.5, arm) player.mines.append(mine) if len(player.mines) > 15: @@ -286,7 +289,7 @@ def arm(): self.handlemessage(ScoreMessage(player)) def handlemessage(self, msg: Any) -> Any: - if isinstance(msg, ba.PlayerDiedMessage): + if isinstance(msg, bs.PlayerDiedMessage): # Augment standard behavior. super().handlemessage(msg) @@ -304,7 +307,7 @@ def handlemessage(self, msg: Any) -> Any: assert self._score_to_win is not None if any(team.score >= self._score_to_win for team in self.teams): - self.end_game() # ba.timer(0.5, self.end_game) + self.end_game() # bs.timer(0.5, self.end_game) else: return super().handlemessage(msg) return None @@ -315,7 +318,7 @@ def _update_scoreboard(self) -> None: self._score_to_win) def end_game(self) -> None: - results = ba.GameResults() + results = bs.GameResults() for team in self.teams: results.set_team_score(team, team.score) self.end(results=results) diff --git a/plugins/minigames/squid_race.py b/plugins/minigames/squid_race.py index d8cd54be..0dea3192 100644 --- a/plugins/minigames/squid_race.py +++ b/plugins/minigames/squid_race.py @@ -1,8 +1,9 @@ +# Porting to api 8 made easier by baport.(https://github.com/bombsquad-community/baport) # Released under the MIT License. See LICENSE for details. # """Defines Race mini-game.""" -# ba_meta require api 7 +# ba_meta require api 8 # (see https://ballistica.net/wiki/meta-tag-system) from __future__ import annotations @@ -11,16 +12,18 @@ from typing import TYPE_CHECKING from dataclasses import dataclass -import ba -from bastd.actor.bomb import Bomb, Blast, ExplodeHitMessage -from bastd.actor.playerspaz import PlayerSpaz -from bastd.actor.scoreboard import Scoreboard -from bastd.gameutils import SharedObjects +import babase +import bauiv1 as bui +import bascenev1 as bs +from bascenev1lib.actor.bomb import Bomb, Blast, ExplodeHitMessage +from bascenev1lib.actor.playerspaz import PlayerSpaz +from bascenev1lib.actor.scoreboard import Scoreboard +from bascenev1lib.gameutils import SharedObjects if TYPE_CHECKING: from typing import (Any, Type, Tuple, List, Sequence, Optional, Dict, Union) - from bastd.actor.onscreentimer import OnScreenTimer + from bascenev1lib.actor.onscreentimer import OnScreenTimer class NewBlast(Blast): @@ -38,7 +41,7 @@ class RaceMine: mine: Optional[Bomb] -class RaceRegion(ba.Actor): +class RaceRegion(bs.Actor): """Region used to track progress during a race.""" def __init__(self, pt: Sequence[float], index: int): @@ -47,7 +50,7 @@ def __init__(self, pt: Sequence[float], index: int): assert isinstance(activity, RaceGame) self.pos = pt self.index = index - self.node = ba.newnode( + self.node = bs.newnode( 'region', delegate=self, attrs={ @@ -58,11 +61,11 @@ def __init__(self, pt: Sequence[float], index: int): }) -class Player(ba.Player['Team']): +class Player(bs.Player['Team']): """Our player type for this game.""" def __init__(self) -> None: - self.distance_txt: Optional[ba.Node] = None + self.distance_txt: Optional[bs.Node] = None self.last_region = 0 self.lap = 0 self.distance = 0.0 @@ -70,7 +73,7 @@ def __init__(self) -> None: self.rank: Optional[int] = None -class Team(ba.Team[Player]): +class Team(bs.Team[Player]): """Our team type for this game.""" def __init__(self) -> None: @@ -79,22 +82,22 @@ def __init__(self) -> None: self.finished = False -# ba_meta export game -class SquidRaceGame(ba.TeamGameActivity[Player, Team]): +# ba_meta export bascenev1.GameActivity +class SquidRaceGame(bs.TeamGameActivity[Player, Team]): """Game of racing around a track.""" name = 'Squid Race' description = 'Run real fast!' - scoreconfig = ba.ScoreConfig(label='Time', + scoreconfig = bs.ScoreConfig(label='Time', lower_is_better=True, - scoretype=ba.ScoreType.MILLISECONDS) + scoretype=bs.ScoreType.MILLISECONDS) @classmethod def get_available_settings( - cls, sessiontype: Type[ba.Session]) -> List[ba.Setting]: + cls, sessiontype: Type[bs.Session]) -> List[babase.Setting]: settings = [ - ba.IntSetting('Laps', min_value=1, default=3, increment=1), - ba.IntChoiceSetting( + bs.IntSetting('Laps', min_value=1, default=3, increment=1), + bs.IntChoiceSetting( 'Time Limit', default=0, choices=[ @@ -106,7 +109,7 @@ def get_available_settings( ('20 Minutes', 1200), ], ), - ba.IntChoiceSetting( + bs.IntChoiceSetting( 'Mine Spawning', default=4000, choices=[ @@ -116,7 +119,7 @@ def get_available_settings( ('2 Seconds', 2000), ], ), - ba.IntChoiceSetting( + bs.IntChoiceSetting( 'Bomb Spawning', choices=[ ('None', 0), @@ -127,49 +130,49 @@ def get_available_settings( ], default=2000, ), - ba.BoolSetting('Epic Mode', default=False), + bs.BoolSetting('Epic Mode', default=False), ] # We have some specific settings in teams mode. - if issubclass(sessiontype, ba.DualTeamSession): + if issubclass(sessiontype, bs.DualTeamSession): settings.append( - ba.BoolSetting('Entire Team Must Finish', default=False)) + bs.BoolSetting('Entire Team Must Finish', default=False)) return settings @classmethod - def supports_session_type(cls, sessiontype: Type[ba.Session]) -> bool: - return issubclass(sessiontype, ba.MultiTeamSession) + def supports_session_type(cls, sessiontype: Type[bs.Session]) -> bool: + return issubclass(sessiontype, bs.MultiTeamSession) @classmethod - def get_supported_maps(cls, sessiontype: Type[ba.Session]) -> List[str]: - return ba.getmaps('race') + def get_supported_maps(cls, sessiontype: Type[bs.Session]) -> List[str]: + return bs.app.classic.getmaps('race') def __init__(self, settings: dict): self._race_started = False super().__init__(settings) self._scoreboard = Scoreboard() - self._score_sound = ba.getsound('score') - self._swipsound = ba.getsound('swip') + self._score_sound = bs.getsound('score') + self._swipsound = bs.getsound('swip') self._last_team_time: Optional[float] = None self._front_race_region: Optional[int] = None - self._nub_tex = ba.gettexture('nub') - self._beep_1_sound = ba.getsound('raceBeep1') - self._beep_2_sound = ba.getsound('raceBeep2') - self.race_region_material: Optional[ba.Material] = None + self._nub_tex = bs.gettexture('nub') + self._beep_1_sound = bs.getsound('raceBeep1') + self._beep_2_sound = bs.getsound('raceBeep2') + self.race_region_material: Optional[bs.Material] = None self._regions: List[RaceRegion] = [] self._team_finish_pts: Optional[int] = None - self._time_text: Optional[ba.Actor] = None + self._time_text: Optional[bs.Actor] = None self._timer: Optional[OnScreenTimer] = None self._race_mines: Optional[List[RaceMine]] = None - self._race_mine_timer: Optional[ba.Timer] = None - self._scoreboard_timer: Optional[ba.Timer] = None - self._player_order_update_timer: Optional[ba.Timer] = None - self._start_lights: Optional[List[ba.Node]] = None - self._squid_lights: Optional[List[ba.Node]] = None + self._race_mine_timer: Optional[bs.Timer] = None + self._scoreboard_timer: Optional[bs.Timer] = None + self._player_order_update_timer: Optional[bs.Timer] = None + self._start_lights: Optional[List[bs.Node]] = None + self._squid_lights: Optional[List[bs.Node]] = None self._countdown_timer: int = 0 self._sq_mode: str = 'Easy' - self._tick_timer: Optional[ba.Timer] = None - self._bomb_spawn_timer: Optional[ba.Timer] = None + self._tick_timer: Optional[bs.Timer] = None + self._bomb_spawn_timer: Optional[bs.Timer] = None self._laps = int(settings['Laps']) self._entire_team_must_finish = bool( settings.get('Entire Team Must Finish', False)) @@ -179,25 +182,25 @@ def __init__(self, settings: dict): self._epic_mode = bool(settings['Epic Mode']) self._countdownsounds = { - 10: ba.getsound('announceTen'), - 9: ba.getsound('announceNine'), - 8: ba.getsound('announceEight'), - 7: ba.getsound('announceSeven'), - 6: ba.getsound('announceSix'), - 5: ba.getsound('announceFive'), - 4: ba.getsound('announceFour'), - 3: ba.getsound('announceThree'), - 2: ba.getsound('announceTwo'), - 1: ba.getsound('announceOne') + 10: bs.getsound('announceTen'), + 9: bs.getsound('announceNine'), + 8: bs.getsound('announceEight'), + 7: bs.getsound('announceSeven'), + 6: bs.getsound('announceSix'), + 5: bs.getsound('announceFive'), + 4: bs.getsound('announceFour'), + 3: bs.getsound('announceThree'), + 2: bs.getsound('announceTwo'), + 1: bs.getsound('announceOne') } # Base class overrides. self.slow_motion = self._epic_mode - self.default_music = (ba.MusicType.EPIC_RACE - if self._epic_mode else ba.MusicType.RACE) + self.default_music = (bs.MusicType.EPIC_RACE + if self._epic_mode else bs.MusicType.RACE) def get_instance_description(self) -> Union[str, Sequence]: - if (isinstance(self.session, ba.DualTeamSession) + if (isinstance(self.session, bs.DualTeamSession) and self._entire_team_must_finish): t_str = ' Your entire team has to finish.' else: @@ -216,7 +219,7 @@ def on_transition_in(self) -> None: super().on_transition_in() shared = SharedObjects.get() pts = self.map.get_def_points('race_point') - mat = self.race_region_material = ba.Material() + mat = self.race_region_material = bs.Material() mat.add_actions(conditions=('they_have_material', shared.player_material), actions=( @@ -232,28 +235,28 @@ def _flash_player(self, player: Player, scale: float) -> None: assert isinstance(player.actor, PlayerSpaz) assert player.actor.node pos = player.actor.node.position - light = ba.newnode('light', + light = bs.newnode('light', attrs={ 'position': pos, 'color': (1, 1, 0), 'height_attenuated': False, 'radius': 0.4 }) - ba.timer(0.5, light.delete) - ba.animate(light, 'intensity', {0: 0, 0.1: 1.0 * scale, 0.5: 0}) + bs.timer(0.5, light.delete) + bs.animate(light, 'intensity', {0: 0, 0.1: 1.0 * scale, 0.5: 0}) def _handle_race_point_collide(self) -> None: # FIXME: Tidy this up. # pylint: disable=too-many-statements # pylint: disable=too-many-branches # pylint: disable=too-many-nested-blocks - collision = ba.getcollision() + collision = bs.getcollision() try: region = collision.sourcenode.getdelegate(RaceRegion, True) player = collision.opposingnode.getdelegate(PlayerSpaz, True).getplayer( Player, True) - except ba.NotFoundError: + except bs.NotFoundError: return last_region = player.last_region @@ -267,8 +270,8 @@ def _handle_race_point_collide(self) -> None: if this_region > last_region + 2: if player.is_alive(): assert player.actor - player.actor.handlemessage(ba.DieMessage()) - ba.screenmessage(ba.Lstr( + player.actor.handlemessage(bs.DieMessage()) + bs.broadcastmessage(babase.Lstr( translate=('statements', 'Killing ${NAME} for' ' skipping part of the track!'), subs=[('${NAME}', player.getname(full=True))]), @@ -287,7 +290,7 @@ def _handle_race_point_collide(self) -> None: # In teams mode with all-must-finish on, the team lap # value is the min of all team players. # Otherwise its the max. - if isinstance(self.session, ba.DualTeamSession + if isinstance(self.session, bs.DualTeamSession ) and self._entire_team_must_finish: team.lap = min([p.lap for p in team.players]) else: @@ -298,7 +301,7 @@ def _handle_race_point_collide(self) -> None: # In teams mode, hand out points based on the order # players come in. - if isinstance(self.session, ba.DualTeamSession): + if isinstance(self.session, bs.DualTeamSession): assert self._team_finish_pts is not None if self._team_finish_pts > 0: self.stats.player_scored(player, @@ -311,7 +314,7 @@ def _handle_race_point_collide(self) -> None: player.finished = True assert player.actor player.actor.handlemessage( - ba.DieMessage(immediate=True)) + bs.DieMessage(immediate=True)) # Makes sure noone behind them passes them in rank # while finishing. @@ -319,25 +322,25 @@ def _handle_race_point_collide(self) -> None: # If the whole team has finished the race. if team.lap == self._laps: - ba.playsound(self._score_sound) + self._score_sound.play() player.team.finished = True assert self._timer is not None - elapsed = ba.time() - self._timer.getstarttime() + elapsed = bs.time() - self._timer.getstarttime() self._last_team_time = player.team.time = elapsed # Team has yet to finish. else: - ba.playsound(self._swipsound) + self._swipsound.play() # They've just finished a lap but not the race. else: - ba.playsound(self._swipsound) + self._swipsound.play() self._flash_player(player, 0.3) # Print their lap number over their head. try: assert isinstance(player.actor, PlayerSpaz) - mathnode = ba.newnode('math', + mathnode = bs.newnode('math', owner=player.actor.node, attrs={ 'input1': (0, 1.9, 0), @@ -345,12 +348,12 @@ def _handle_race_point_collide(self) -> None: }) player.actor.node.connectattr( 'torso_position', mathnode, 'input2') - tstr = ba.Lstr(resource='lapNumberText', + tstr = babase.Lstr(resource='lapNumberText', subs=[('${CURRENT}', str(player.lap + 1)), ('${TOTAL}', str(self._laps)) ]) - txtnode = ba.newnode('text', + txtnode = bs.newnode('text', owner=mathnode, attrs={ 'text': tstr, @@ -360,15 +363,15 @@ def _handle_race_point_collide(self) -> None: 'h_align': 'center' }) mathnode.connectattr('output', txtnode, 'position') - ba.animate(txtnode, 'scale', { + bs.animate(txtnode, 'scale', { 0.0: 0, 0.2: 0.019, 2.0: 0.019, 2.2: 0 }) - ba.timer(2.3, mathnode.delete) + bs.timer(2.3, mathnode.delete) except Exception: - ba.print_exception('Error printing lap.') + babase.print_exception('Error printing lap.') def on_team_join(self, team: Team) -> None: self._update_scoreboard() @@ -377,8 +380,8 @@ def on_player_join(self, player: Player) -> None: # Don't allow joining after we start # (would enable leave/rejoin tomfoolery). if self.has_begun(): - ba.screenmessage( - ba.Lstr(resource='playerDelayedJoinText', + bs.broadcastmessage( + babase.Lstr(resource='playerDelayedJoinText', subs=[('${PLAYER}', player.getname(full=True))]), color=(0, 1, 0), ) @@ -391,9 +394,9 @@ def on_player_leave(self, player: Player) -> None: # A player leaving disqualifies the team if 'Entire Team Must Finish' # is on (otherwise in teams mode everyone could just leave except the # leading player to win). - if (isinstance(self.session, ba.DualTeamSession) + if (isinstance(self.session, bs.DualTeamSession) and self._entire_team_must_finish): - ba.screenmessage(ba.Lstr( + bs.broadcastmessage(babase.Lstr( translate=('statements', '${TEAM} is disqualified because ${PLAYER} left'), subs=[('${TEAM}', player.team.name), @@ -402,18 +405,18 @@ def on_player_leave(self, player: Player) -> None: player.team.finished = True player.team.time = None player.team.lap = 0 - ba.playsound(ba.getsound('boo')) + bs.getsound('boo').play() for otherplayer in player.team.players: otherplayer.lap = 0 otherplayer.finished = True try: if otherplayer.actor is not None: - otherplayer.actor.handlemessage(ba.DieMessage()) + otherplayer.actor.handlemessage(bs.DieMessage()) except Exception: - ba.print_exception('Error sending DieMessage.') + babase.print_exception('Error sending DieMessage.') # Defer so team/player lists will be updated. - ba.pushcall(self._check_end_game) + babase.pushcall(self._check_end_game) def _update_scoreboard(self) -> None: for team in self.teams: @@ -421,7 +424,7 @@ def _update_scoreboard(self) -> None: if not distances: teams_dist = 0.0 else: - if (isinstance(self.session, ba.DualTeamSession) + if (isinstance(self.session, bs.DualTeamSession) and self._entire_team_must_finish): teams_dist = min(distances) else: @@ -434,15 +437,15 @@ def _update_scoreboard(self) -> None: show_value=False) def on_begin(self) -> None: - from bastd.actor.onscreentimer import OnScreenTimer + from bascenev1lib.actor.onscreentimer import OnScreenTimer super().on_begin() self.setup_standard_time_limit(self._time_limit) self.setup_standard_powerup_drops() self._team_finish_pts = 100 # Throw a timer up on-screen. - self._time_text = ba.NodeActor( - ba.newnode('text', + self._time_text = bs.NodeActor( + bs.newnode('text', attrs={ 'v_attach': 'top', 'h_attach': 'center', @@ -462,14 +465,14 @@ def on_begin(self) -> None: for p in self.map.get_def_points('race_mine') ] if self._race_mines: - self._race_mine_timer = ba.Timer(0.001 * self._mine_spawning, + self._race_mine_timer = bs.Timer(0.001 * self._mine_spawning, self._update_race_mine, repeat=True) - self._scoreboard_timer = ba.Timer(0.25, + self._scoreboard_timer = bs.Timer(0.25, self._update_scoreboard, repeat=True) - self._player_order_update_timer = ba.Timer(0.25, + self._player_order_update_timer = bs.Timer(0.25, self._update_player_order, repeat=True) @@ -482,30 +485,30 @@ def on_begin(self) -> None: lstart = 7.1 * t_scale inc = 1.25 * t_scale - ba.timer(lstart, self._do_light_1) - ba.timer(lstart + inc, self._do_light_2) - ba.timer(lstart + 2 * inc, self._do_light_3) - ba.timer(lstart + 3 * inc, self._start_race) + bs.timer(lstart, self._do_light_1) + bs.timer(lstart + inc, self._do_light_2) + bs.timer(lstart + 2 * inc, self._do_light_3) + bs.timer(lstart + 3 * inc, self._start_race) self._start_lights = [] for i in range(4): - lnub = ba.newnode('image', + lnub = bs.newnode('image', attrs={ - 'texture': ba.gettexture('nub'), + 'texture': bs.gettexture('nub'), 'opacity': 1.0, 'absolute_scale': True, 'position': (-75 + i * 50, light_y), 'scale': (50, 50), 'attach': 'center' }) - ba.animate( + bs.animate( lnub, 'opacity', { 4.0 * t_scale: 0, 5.0 * t_scale: 1.0, 12.0 * t_scale: 1.0, 12.5 * t_scale: 0.0 }) - ba.timer(13.0 * t_scale, lnub.delete) + bs.timer(13.0 * t_scale, lnub.delete) self._start_lights.append(lnub) self._start_lights[0].color = (0.2, 0, 0) @@ -515,16 +518,16 @@ def on_begin(self) -> None: self._squid_lights = [] for i in range(2): - lnub = ba.newnode('image', + lnub = bs.newnode('image', attrs={ - 'texture': ba.gettexture('nub'), + 'texture': bs.gettexture('nub'), 'opacity': 1.0, 'absolute_scale': True, 'position': (-33 + i * 65, 220), 'scale': (60, 60), 'attach': 'center' }) - ba.animate( + bs.animate( lnub, 'opacity', { 4.0 * t_scale: 0, 5.0 * t_scale: 1.0}) @@ -532,12 +535,12 @@ def on_begin(self) -> None: self._squid_lights[0].color = (0.2, 0, 0) self._squid_lights[1].color = (0.0, 0.3, 0) - ba.timer(1.0, self._check_squid_end, repeat=True) + bs.timer(1.0, self._check_squid_end, repeat=True) self._squidgame_countdown() def _squidgame_countdown(self) -> None: self._countdown_timer = 80 * self._laps # 80 - ba.newnode( + bs.newnode( 'image', attrs={ 'opacity': 0.7, @@ -545,8 +548,8 @@ def _squidgame_countdown(self) -> None: 'attach': 'topCenter', 'position': (-220, -40), 'scale': (135, 45), - 'texture': ba.gettexture('bar')}) - ba.newnode( + 'texture': bs.gettexture('bar')}) + bs.newnode( 'image', attrs={ 'opacity': 1.0, @@ -554,9 +557,9 @@ def _squidgame_countdown(self) -> None: 'attach': 'topCenter', 'position': (-220, -38), 'scale': (155, 65), - 'texture': ba.gettexture('uiAtlas'), - 'model_transparent': ba.getmodel('meterTransparent')}) - self._sgcountdown_text = ba.newnode( + 'texture': bs.gettexture('uiAtlas'), + 'mesh_transparent': bs.getmesh('meterTransparent')}) + self._sgcountdown_text = bs.newnode( 'text', attrs={ 'v_attach': 'top', @@ -576,14 +579,14 @@ def _update_sgcountdown(self) -> None: self._squid_game_all_die() if self._countdown_timer == 20: self._sq_mode = 'Hard' - ba.playsound(ba.getsound('alarm')) + bs.getsound('alarm').play() if self._countdown_timer == 40: self._sq_mode = 'Normal' if self._countdown_timer <= 20: self._sgcountdown_text.color = (1.2, 0.0, 0.0) self._sgcountdown_text.scale = 1.2 if self._countdown_timer in self._countdownsounds: - ba.playsound(self._countdownsounds[self._countdown_timer]) + self._countdownsounds[self._countdown_timer].play() else: self._sgcountdown_text.color = (1.0, 1.0, 1.0) self._sgcountdown_text.text = str(self._countdown_timer)+"s" @@ -592,14 +595,14 @@ def _squid_game_all_die(self) -> None: for player in self.players: if player.is_alive(): player.actor._cursed = True - player.actor.handlemessage(ba.DieMessage()) + player.actor.handlemessage(bs.DieMessage()) NewBlast( position=player.actor.node.position, velocity=player.actor.node.velocity, blast_radius=3.0, blast_type='normal').autoretain() player.actor.handlemessage( - ba.HitMessage( + bs.HitMessage( pos=player.actor.node.position, velocity=player.actor.node.velocity, magnitude=2000, @@ -612,8 +615,8 @@ def _squid_game_all_die(self) -> None: def _do_ticks(self) -> None: def do_ticks(): if self._ticks: - ba.playsound(ba.getsound('tick')) - self._tick_timer = ba.timer(1.0, do_ticks, repeat=True) + bs.getsound('tick').play() + self._tick_timer = bs.timer(1.0, do_ticks, repeat=True) def _start_squid_game(self) -> None: easy = [4.5, 5, 5.5, 6] @@ -623,30 +626,30 @@ def _start_squid_game(self) -> None: hard if self._sq_mode == 'Hard' else normal if self._sq_mode == 'Normal' else easy) # if random_number == 6: - # ba.playsound(ba.getsound('lrlg_06s')) + # bs.getsound('lrlg_06s').play() # elif random_number == 5.5: - # ba.playsound(ba.getsound('lrlg_055s')) + # bs.getsound('lrlg_055s').play() # elif random_number == 5: - # ba.playsound(ba.getsound('lrlg_05s')) + # bs.getsound('lrlg_05s').play() # elif random_number == 4.5: - # ba.playsound(ba.getsound('lrlg_045s')) + # bs.getsound('lrlg_045s').play() # elif random_number == 4: - # ba.playsound(ba.getsound('lrlg_04s')) + # bs.getsound('lrlg_04s').play() # elif random_number == 3.5: - # ba.playsound(ba.getsound('lrlg_035s')) + # bs.getsound('lrlg_035s').play() # elif random_number == 3: - # ba.playsound(ba.getsound('lrlg_03s')) + # bs.getsound('lrlg_03s').play() self._squid_lights[0].color = (0.2, 0, 0) self._squid_lights[1].color = (0.0, 1.0, 0) self._do_delete = False self._ticks = True - ba.timer(random_number, self._stop_squid_game) + bs.timer(random_number, self._stop_squid_game) def _stop_squid_game(self) -> None: self._ticks = False self._squid_lights[0].color = (1.0, 0, 0) self._squid_lights[1].color = (0.0, 0.3, 0) - ba.timer(0.2, self._check_delete) + bs.timer(0.2, self._check_delete) def _check_delete(self) -> None: for player in self.players: @@ -654,7 +657,7 @@ def _check_delete(self) -> None: player.customdata['position'] = None player.customdata['position'] = player.actor.node.position self._do_delete = True - ba.timer(3.0 if self._sq_mode == 'Hard' else 4.0, + bs.timer(3.0 if self._sq_mode == 'Hard' else 4.0, self._start_squid_game) def _start_delete(self) -> None: @@ -684,14 +687,14 @@ def _start_delete(self) -> None: current_posz in posz_list) or not ( current_posy in posy_list): player.actor._cursed = True - player.actor.handlemessage(ba.DieMessage()) + player.actor.handlemessage(bs.DieMessage()) NewBlast( position=player.actor.node.position, velocity=player.actor.node.velocity, blast_radius=3.0, blast_type='normal').autoretain() player.actor.handlemessage( - ba.HitMessage( + bs.HitMessage( pos=player.actor.node.position, velocity=player.actor.node.velocity, magnitude=2000, @@ -713,34 +716,34 @@ def _check_squid_end(self) -> None: def _do_light_1(self) -> None: assert self._start_lights is not None self._start_lights[0].color = (1.0, 0, 0) - ba.playsound(self._beep_1_sound) + self._beep_1_sound.play() def _do_light_2(self) -> None: assert self._start_lights is not None self._start_lights[1].color = (1.0, 0, 0) - ba.playsound(self._beep_1_sound) + self._beep_1_sound.play() def _do_light_3(self) -> None: assert self._start_lights is not None self._start_lights[2].color = (1.0, 0.3, 0) - ba.playsound(self._beep_1_sound) + self._beep_1_sound.play() def _start_race(self) -> None: assert self._start_lights is not None self._start_lights[3].color = (0.0, 1.0, 0) - ba.playsound(self._beep_2_sound) + self._beep_2_sound.play() for player in self.players: if player.actor is not None: try: assert isinstance(player.actor, PlayerSpaz) player.actor.connect_controls_to_player() except Exception: - ba.print_exception('Error in race player connects.') + babase.print_exception('Error in race player connects.') assert self._timer is not None self._timer.start() if self._bomb_spawning != 0: - self._bomb_spawn_timer = ba.Timer(0.001 * self._bomb_spawning, + self._bomb_spawn_timer = bs.Timer(0.001 * self._bomb_spawning, self._spawn_bomb, repeat=True) @@ -748,25 +751,25 @@ def _start_race(self) -> None: self._squid_lights[1].color = (0.0, 1.0, 0) self._start_squid_game() self._do_ticks() - ba.timer(0.2, self._start_delete, repeat=True) - ba.timer(1.0, self._update_sgcountdown, repeat=True) + bs.timer(0.2, self._start_delete, repeat=True) + bs.timer(1.0, self._update_sgcountdown, repeat=True) def _update_player_order(self) -> None: # Calc all player distances. for player in self.players: - pos: Optional[ba.Vec3] + pos: Optional[babase.Vec3] try: pos = player.position - except ba.NotFoundError: + except bs.NotFoundError: pos = None if pos is not None: r_index = player.last_region rg1 = self._regions[r_index] - r1pt = ba.Vec3(rg1.pos[:3]) + r1pt = babase.Vec3(rg1.pos[:3]) rg2 = self._regions[0] if r_index == len( self._regions) - 1 else self._regions[r_index + 1] - r2pt = ba.Vec3(rg2.pos[:3]) + r2pt = babase.Vec3(rg2.pos[:3]) r2dist = (pos - r2pt).length() amt = 1.0 - (r2dist / (r2pt - r1pt).length()) amt = player.lap + (r_index + amt) * (1.0 / len(self._regions)) @@ -797,8 +800,8 @@ def _spawn_bomb(self) -> None: (-region_scale * pos[5], region_scale * pos[5])) pos = (pos[0] + random.uniform(*x_range), pos[1] + 1.0, pos[2] + random.uniform(*z_range)) - ba.timer(random.uniform(0.0, 2.0), - ba.WeakCall(self._spawn_bomb_at_pos, pos)) + bs.timer(random.uniform(0.0, 2.0), + bs.WeakCall(self._spawn_bomb_at_pos, pos)) def _spawn_bomb_at_pos(self, pos: Sequence[float]) -> None: if self.has_ended(): @@ -814,15 +817,15 @@ def _make_mine(self, i: int) -> None: def _flash_mine(self, i: int) -> None: assert self._race_mines is not None rmine = self._race_mines[i] - light = ba.newnode('light', + light = bs.newnode('light', attrs={ 'position': rmine.point[:3], 'color': (1, 0.2, 0.2), 'radius': 0.1, 'height_attenuated': False }) - ba.animate(light, 'intensity', {0.0: 0, 0.1: 1.0, 0.2: 0}, loop=True) - ba.timer(1.0, light.delete) + bs.animate(light, 'intensity', {0.0: 0, 0.1: 1.0, 0.2: 0}, loop=True) + bs.timer(1.0, light.delete) def _update_race_mine(self) -> None: assert self._race_mines is not None @@ -836,9 +839,9 @@ def _update_race_mine(self) -> None: assert rmine is not None if not rmine.mine: self._flash_mine(m_index) - ba.timer(0.95, ba.Call(self._make_mine, m_index)) + bs.timer(0.95, babase.Call(self._make_mine, m_index)) - def spawn_player(self, player: Player) -> ba.Actor: + def spawn_player(self, player: Player) -> bs.Actor: if player.team.finished: # FIXME: This is not type-safe! # This call is expected to always return an Actor! @@ -863,7 +866,7 @@ def spawn_player(self, player: Player) -> ba.Actor: if not self._race_started: spaz.disconnect_controls_from_player() - mathnode = ba.newnode('math', + mathnode = bs.newnode('math', owner=spaz.node, attrs={ 'input1': (0, 1.4, 0), @@ -871,7 +874,7 @@ def spawn_player(self, player: Player) -> ba.Actor: }) spaz.node.connectattr('torso_position', mathnode, 'input2') - distance_txt = ba.newnode('text', + distance_txt = bs.newnode('text', owner=spaz.node, attrs={ 'text': '', @@ -902,14 +905,14 @@ def _check_end_game(self) -> None: # In teams mode its over as soon as any team finishes the race # FIXME: The get_ffa_point_awards code looks dangerous. - if isinstance(session, ba.DualTeamSession): + if isinstance(session, bs.DualTeamSession): self.end_game() else: # In ffa we keep the race going while there's still any points # to be handed out. Find out how many points we have to award # and how many teams have finished, and once that matches # we're done. - assert isinstance(session, ba.FreeForAllSession) + assert isinstance(session, bs.FreeForAllSession) points_to_award = len(session.get_ffa_point_awards()) if teams_completed >= points_to_award - teams_completed: self.end_game() @@ -926,7 +929,7 @@ def end_game(self) -> None: endtime=None if self._last_team_time is None else ( self._timer.getstarttime() + self._last_team_time)) - results = ba.GameResults() + results = bs.GameResults() for team in self.teams: if team.time is not None: @@ -940,10 +943,10 @@ def end_game(self) -> None: # odd to be announcing that now. self.end(results=results, announce_winning_team=isinstance(self.session, - ba.DualTeamSession)) + bs.DualTeamSession)) def handlemessage(self, msg: Any) -> Any: - if isinstance(msg, ba.PlayerDiedMessage): + if isinstance(msg, bs.PlayerDiedMessage): # Augment default behavior. super().handlemessage(msg) else: diff --git a/plugins/minigames/the_spaz_game.py b/plugins/minigames/the_spaz_game.py index 278b5214..74857c18 100644 --- a/plugins/minigames/the_spaz_game.py +++ b/plugins/minigames/the_spaz_game.py @@ -1,5 +1,6 @@ +# Porting to api 8 made easier by baport.(https://github.com/bombsquad-community/baport) -# ba_meta require api 7 +# ba_meta require api 8 """ TheSpazGame - Mini game where all characters looks identical , identify enemies and kill them. Author: Mr.Smoothy @@ -12,9 +13,11 @@ from typing import TYPE_CHECKING -import ba -from bastd.game.elimination import EliminationGame, Player -from bastd.actor.spazfactory import SpazFactory +import babase +import bauiv1 as bui +import bascenev1 as bs +from bascenev1lib.game.elimination import EliminationGame, Player +from bascenev1lib.actor.spazfactory import SpazFactory import random if TYPE_CHECKING: @@ -23,14 +26,14 @@ CHARACTER = 'Spaz' -# ba_meta export game +# ba_meta export bascenev1.GameActivity class TheSpazGame(EliminationGame): name = 'TheSpazGame' description = 'Enemy Spaz AmongUs. Kill them all' - scoreconfig = ba.ScoreConfig( - label='Survived', scoretype=ba.ScoreType.SECONDS, none_is_winner=True + scoreconfig = bs.ScoreConfig( + label='Survived', scoretype=bs.ScoreType.SECONDS, none_is_winner=True ) announce_player_deaths = False @@ -39,17 +42,17 @@ class TheSpazGame(EliminationGame): @classmethod def get_available_settings( - cls, sessiontype: type[ba.Session] - ) -> list[ba.Setting]: + cls, sessiontype: type[bs.Session] + ) -> list[babase.Setting]: settings = [ - ba.IntSetting( + bs.IntSetting( 'Lives Per Player', default=1, min_value=1, max_value=10, increment=1, ), - ba.IntChoiceSetting( + bs.IntChoiceSetting( 'Time Limit', choices=[ ('None', 0), @@ -61,31 +64,31 @@ def get_available_settings( ], default=0, ), - ba.FloatChoiceSetting( + bs.FloatChoiceSetting( 'Respawn Times', choices=[ ('Shorter', 0.15) ], default=1.0, ), - ba.BoolSetting('Epic Mode', default=False), + bs.BoolSetting('Epic Mode', default=False), ] - if issubclass(sessiontype, ba.DualTeamSession): - settings.append(ba.BoolSetting('Solo Mode', default=False)) + if issubclass(sessiontype, bs.DualTeamSession): + settings.append(bs.BoolSetting('Solo Mode', default=False)) settings.append( - ba.BoolSetting('Balance Total Lives', default=False) + bs.BoolSetting('Balance Total Lives', default=False) ) return settings @classmethod - def supports_session_type(cls, sessiontype: type[ba.Session]) -> bool: - return issubclass(sessiontype, ba.DualTeamSession) or issubclass( - sessiontype, ba.FreeForAllSession + def supports_session_type(cls, sessiontype: type[bs.Session]) -> bool: + return issubclass(sessiontype, bs.DualTeamSession) or issubclass( + sessiontype, bs.FreeForAllSession ) @classmethod - def get_supported_maps(cls, sessiontype: type[ba.Session]) -> list[str]: - return ba.getmaps('melee') + def get_supported_maps(cls, sessiontype: type[bs.Session]) -> list[str]: + return bs.app.classic.getmaps('melee') def get_instance_description(self) -> str | Sequence: return ( @@ -101,7 +104,7 @@ def __init__(self, settings: dict): super().__init__(settings) self._solo_mode = False - def spawn_player(self, player: Player) -> ba.Actor: + def spawn_player(self, player: Player) -> bs.Actor: p = [-6, -4.3, -2.6, -0.9, 0.8, 2.5, 4.2, 5.9] q = [-4, -2.3, -0.6, 1.1, 2.8, 4.5] diff --git a/plugins/minigames/ufo_fight.py b/plugins/minigames/ufo_fight.py index 4823904d..d8849f87 100644 --- a/plugins/minigames/ufo_fight.py +++ b/plugins/minigames/ufo_fight.py @@ -1,4 +1,4 @@ -"""UFO Boss Fight v1.0: +"""UFO Boss Fight v2.0: Made by Cross Joy""" # Anyone who wanna help me in giving suggestion/ fix bugs/ by creating PR, @@ -8,21 +8,28 @@ # My Discord Id: Cross Joy#0721 # My BS Discord Server: https://discford.gg/JyBY6haARJ -# ba_meta require api 7 +# ba_meta require api 8 # (see https://ballistica.net/wiki/meta-tag-system) +# --------------------------------------- +# Update v2.0 + +# updated to api 8 +# --------------------------------------- + from __future__ import annotations import random from typing import TYPE_CHECKING -import ba -import _ba -from bastd.actor.playerspaz import PlayerSpaz -from bastd.actor.spaz import Spaz -from bastd.actor.bomb import Blast, Bomb -from bastd.actor.onscreentimer import OnScreenTimer -from bastd.actor.spazbot import SpazBotSet, StickyBot -from bastd.gameutils import SharedObjects + +import babase +import bascenev1 as bs +from bascenev1lib.actor.playerspaz import PlayerSpaz +from bascenev1lib.actor.spaz import Spaz +from bascenev1lib.actor.bomb import Blast, Bomb +from bascenev1lib.actor.onscreentimer import OnScreenTimer +from bascenev1lib.actor.spazbot import SpazBotSet, StickyBot +from bascenev1lib.gameutils import SharedObjects if TYPE_CHECKING: from typing import Any, Sequence, Union, Callable @@ -32,17 +39,17 @@ class UFODiedMessage: ufo: UFO """The UFO that was killed.""" - killerplayer: ba.Player | None - """The ba.Player that killed it (or None).""" + killerplayer: bs.Player | None + """The bs.Player that killed it (or None).""" - how: ba.DeathType + how: bs.DeathType """The particular type of death.""" def __init__( self, ufo: UFO, - killerplayer: ba.Player | None, - how: ba.DeathType, + killerplayer: bs.Player | None, + how: bs.DeathType, ): """Instantiate with given values.""" self.spazbot = ufo @@ -57,7 +64,7 @@ class RoboBot(StickyBot): highlight = (3, 3, 3) -class UFO(ba.Actor): +class UFO(bs.Actor): """ New AI for Boss """ @@ -65,7 +72,7 @@ class UFO(ba.Actor): # pylint: disable=too-many-public-methods # pylint: disable=too-many-locals - node: ba.Node + node: bs.Node def __init__(self, hitpoints: int = 5000): @@ -74,32 +81,29 @@ def __init__(self, hitpoints: int = 5000): self.update_callback: Callable[[UFO], Any] | None = None activity = self.activity - assert isinstance(activity, ba.GameActivity) + assert isinstance(activity, bs.GameActivity) - self.platform_material = ba.Material() + self.platform_material = bs.Material() self.platform_material.add_actions( conditions=('they_have_material', shared.footing_material), actions=( 'modify_part_collision', 'collide', True)) - self.ice_material = ba.Material() + self.ice_material = bs.Material() self.ice_material.add_actions( actions=('modify_part_collision', 'friction', 0.0)) - self._player_pts: list[tuple[ba.Vec3, ba.Vec3]] | None = None - self._ufo_update_timer: ba.Timer | None = None - self.last_player_attacked_by: ba.Player | None = None + self._player_pts: list[tuple[bs.Vec3, bs.Vec3]] | None = None + self._ufo_update_timer: bs.Timer | None = None + self.last_player_attacked_by: bs.Player | None = None self.last_attacked_time = 0.0 self.last_attacked_type: tuple[str, str] | None = None - self.to_target: ba.Vec3 = ba.Vec3(0, 0, 0) + self.to_target: bs.Vec3 = bs.Vec3(0, 0, 0) self.dist = (0, 0, 0) self._bots = SpazBotSet() self.frozen = False - self.y_pos = 3 - self.xz_pos = 1 self.bot_count = 3 - self.bot_dur_froze = False self.hitpoints = hitpoints self.hitpoints_max = hitpoints @@ -108,18 +112,18 @@ def __init__(self, hitpoints: int = 5000): self._height = 35 self._bar_width = 240 self._bar_height = 35 - self._bar_tex = self._backing_tex = ba.gettexture('bar') - self._cover_tex = ba.gettexture('uiAtlas') - self._model = ba.getmodel('meterTransparent') + self._bar_tex = self._backing_tex = bs.gettexture('bar') + self._cover_tex = bs.gettexture('uiAtlas') + self._mesh = bs.getmesh('meterTransparent') self.bar_posx = -120 self._last_hit_time: int | None = None self.impact_scale = 1.0 self._num_times_hit = 0 - self._sucker_mat = ba.Material() + self._sucker_mat = bs.Material() - self.ufo_material = ba.Material() + self.ufo_material = bs.Material() self.ufo_material.add_actions( conditions=('they_have_material', shared.player_material), @@ -135,31 +139,30 @@ def __init__(self, hitpoints: int = 5000): self.ufo_material)), actions=('modify_part_collision', 'physical', False)) - activity = _ba.get_foreground_host_activity() - with ba.Context(activity): - point = activity.map.get_flag_position(None) - boss_spawn_pos = (point[0], point[1] + 1, point[2]) + activity = bs.get_foreground_host_activity() + point = activity.map.get_flag_position(None) + boss_spawn_pos = (point[0], point[1] + 1, point[2]) - self.node = ba.newnode('prop', delegate=self, attrs={ + self.node = bs.newnode('prop', delegate=self, attrs={ 'position': boss_spawn_pos, 'velocity': (2, 0, 0), - 'color_texture': ba.gettexture('achievementFootballShutout'), - 'model': ba.getmodel('landMine'), - # 'light_model': ba.getmodel('powerupSimple'), - 'model_scale': 3.3, + 'color_texture': bs.gettexture('achievementFootballShutout'), + 'mesh': bs.getmesh('landMine'), + # 'light_mesh': bs.getmesh('powerupSimple'), + 'mesh_scale': 3.3, 'body': 'landMine', 'body_scale': 3.3, - 'gravity_scale': 0.05, + 'gravity_scale': 0.2, 'density': 1, 'reflection': 'soft', 'reflection_scale': [0.25], 'shadow_size': 0.1, 'max_speed': 1.5, 'is_area_of_interest': - True, + True, 'materials': [shared.footing_material, shared.object_material]}) - self.holder = ba.newnode('region', attrs={ + self.holder = bs.newnode('region', attrs={ 'position': ( boss_spawn_pos[0], boss_spawn_pos[1] - 0.25, boss_spawn_pos[2]), @@ -168,7 +171,7 @@ def __init__(self, hitpoints: int = 5000): 'materials': (self.platform_material, self.ice_material, shared.object_material)}) - self.suck_anim = ba.newnode('locator', + self.suck_anim = bs.newnode('locator', owner=self.node, attrs={'shape': 'circleOutline', 'position': ( @@ -181,7 +184,7 @@ def __init__(self, hitpoints: int = 5000): 'additive': True}) def suck_anim(): - ba.animate_array(self.suck_anim, 'position', 3, + bs.animate_array(self.suck_anim, 'position', 3, {0: ( self.node.position[0], self.node.position[1] - 5, @@ -194,7 +197,7 @@ def suck_anim(): self.node.position[ 2] + self.to_target.z / 2)}) - self.suck_timer = ba.Timer(0.5, suck_anim, repeat=True) + self.suck_timer = bs.Timer(0.5, suck_anim, repeat=True) self.blocks = [] @@ -209,14 +212,14 @@ def suck_anim(): )) - # self.sucker = ba.newnode('region', attrs={ + # self.sucker = bs.newnode('region', attrs={ # 'position': ( # boss_spawn_pos[0], boss_spawn_pos[1] - 2, boss_spawn_pos[2]), # 'scale': [2, 10, 2], # 'type': 'box', # 'materials': self._sucker_mat, }) - self.suck = ba.newnode('region', + self.suck = bs.newnode('region', attrs={'position': ( boss_spawn_pos[0], boss_spawn_pos[1] - 2, boss_spawn_pos[2]), @@ -227,69 +230,65 @@ def suck_anim(): self.node.connectattr('position', self.holder, 'position') self.node.connectattr('position', self.suck, 'position') - ba.animate(self.node, 'model_scale', { + bs.animate(self.node, 'mesh_scale', { 0: 0, - 0.2: self.node.model_scale * 1.1, - 0.26: self.node.model_scale}) + 0.2: self.node.mesh_scale * 1.1, + 0.26: self.node.mesh_scale}) - self.shield_deco = ba.newnode('shield', owner=self.node, + self.shield_deco = bs.newnode('shield', owner=self.node, attrs={'color': (4, 4, 4), 'radius': 1.2}) self.node.connectattr('position', self.shield_deco, 'position') self._scoreboard() self._update() - self.drop_bomb_timer = ba.Timer(1.5, ba.Call(self._drop_bomb), + self.drop_bomb_timer = bs.Timer(1.5, bs.Call(self._drop_bomb), repeat=True) - self.drop_bots_timer = ba.Timer(15.0, ba.Call(self._drop_bots), repeat=True) + self.drop_bots_timer = bs.Timer(15.0, bs.Call(self._drop_bots), repeat=True) def _drop_bots(self) -> None: p = self.node.position - if not self.frozen: - for i in range(self.bot_count): - ba.timer( - 1.0 + i, - lambda: self._bots.spawn_bot( - RoboBot, pos=(self.node.position[0], - self.node.position[1] - 1, - self.node.position[2]), spawn_time=0.0 - ), - ) - else: - self.bot_dur_froze = True + for i in range(self.bot_count): + bs.timer( + 1.0 + i, + lambda: self._bots.spawn_bot( + RoboBot, pos=(self.node.position[0], + self.node.position[1] - 1, + self.node.position[2]), spawn_time=0.0 + ), + ) def _drop_bomb(self) -> None: t = self.to_target p = self.node.position - if not self.frozen: - if abs(self.dist[0]) < 2 and abs(self.dist[2]) < 2: - Bomb(position=(p[0], p[1] - 0.5, p[2]), - velocity=(t[0] * 5, 0, t[2] * 5), - bomb_type='land_mine').autoretain().arm() - elif self.hitpoints > self.hitpoints_max * 3 / 4: - Bomb(position=(p[0], p[1] - 1.5, p[2]), - velocity=(t[0] * 8, 2, t[2] * 8), - bomb_type='normal').autoretain() - elif self.hitpoints > self.hitpoints_max * 1 / 2: - Bomb(position=(p[0], p[1] - 1.5, p[2]), - velocity=(t[0] * 8, 2, t[2] * 8), - bomb_type='ice').autoretain() - - elif self.hitpoints > self.hitpoints_max * 1 / 4: - Bomb(position=(p[0], p[1] - 1.5, p[2]), - velocity=(t[0] * 15, 2, t[2] * 15), - bomb_type='sticky').autoretain() - else: - Bomb(position=(p[0], p[1] - 1.5, p[2]), - velocity=(t[0] * 15, 2, t[2] * 15), - bomb_type='impact').autoretain() + if abs(self.dist[0]) < 2 and abs(self.dist[2]) < 2: + Bomb(position=(p[0], p[1] - 0.5, p[2]), + velocity=(t[0] * 5, 0, t[2] * 5), + bomb_type='land_mine').autoretain().arm() + elif self.hitpoints > self.hitpoints_max * 3 / 4: + Bomb(position=(p[0], p[1] - 1.5, p[2]), + velocity=(t[0] * 8, 2, t[2] * 8), + bomb_type='normal').autoretain() + elif self.hitpoints > self.hitpoints_max * 1 / 2: + Bomb(position=(p[0], p[1] - 1.5, p[2]), + velocity=(t[0] * 8, 2, t[2] * 8), + bomb_type='ice').autoretain() + + elif self.hitpoints > self.hitpoints_max * 1 / 4: + Bomb(position=(p[0], p[1] - 1.5, p[2]), + velocity=(t[0] * 15, 2, t[2] * 15), + bomb_type='sticky').autoretain() + else: + Bomb(position=(p[0], p[1] - 1.5, p[2]), + velocity=(t[0] * 15, 2, t[2] * 15), + bomb_type='impact').autoretain() def _levitate(self): - node = ba.getcollision().opposingnode + node = bs.getcollision().opposingnode if node.exists(): p = node.getdelegate(Spaz, True) - def raise_player(player: ba.Player): + def raise_player(player: bs.Player): if player.is_alive(): node = player.node try: @@ -298,12 +297,13 @@ def raise_player(player: ba.Player): node.position[2], 0, 5, 0, 3, 10, 0, 0, 0, 5, 0) + except: pass if not self.frozen: for i in range(7): - ba.timer(0.05 + i / 20, ba.Call(raise_player, p)) + bs.timer(0.05 + i / 20, bs.Call(raise_player, p)) def on_punched(self, damage: int) -> None: """Called when this spaz gets punched.""" @@ -315,24 +315,22 @@ def do_damage(self, msg: Any) -> None: damage = abs(msg.magnitude) if msg.hit_type == 'explosion': damage /= 20 - else: - damage /= 5 self.hitpoints -= int(damage) if self.hitpoints <= 0: - self.handlemessage(ba.DieMessage()) + self.handlemessage(bs.DieMessage()) def _get_target_player_pt(self) -> tuple[ - ba.Vec3 | None, ba.Vec3 | None]: + bs.Vec3 | None, bs.Vec3 | None]: """Returns the position and velocity of our target. Both values will be None in the case of no target. """ assert self.node - botpt = ba.Vec3(self.node.position) + botpt = bs.Vec3(self.node.position) closest_dist: float | None = None - closest_vel: ba.Vec3 | None = None - closest: ba.Vec3 | None = None + closest_vel: bs.Vec3 | None = None + closest: bs.Vec3 | None = None assert self._player_pts is not None for plpt, plvel in self._player_pts: dist = (plpt - botpt).length() @@ -349,12 +347,12 @@ def _get_target_player_pt(self) -> tuple[ assert closest_vel is not None assert closest is not None return ( - ba.Vec3(closest[0], closest[1], closest[2]), - ba.Vec3(closest_vel[0], closest_vel[1], closest_vel[2]), + bs.Vec3(closest[0], closest[1], closest[2]), + bs.Vec3(closest_vel[0], closest_vel[1], closest_vel[2]), ) return None, None - def set_player_points(self, pts: list[tuple[ba.Vec3, ba.Vec3]]) -> None: + def set_player_points(self, pts: list[tuple[bs.Vec3, bs.Vec3]]) -> None: """Provide the spaz-bot with the locations of its enemies.""" self._player_pts = pts @@ -368,13 +366,13 @@ def show_damage_count(self, damage: str, position: Sequence[float], Category: Gameplay Functions """ lifespan = 1.0 - app = ba.app + app = bs.app # FIXME: Should never vary game elements based on local config. # (connected clients may have differing configs so they won't # get the intended results). - do_big = app.ui.uiscale is ba.UIScale.SMALL or app.vr_mode - txtnode = ba.newnode('text', + do_big = app.ui.uiscale is bs.UIScale.SMALL or app.vr_mode + txtnode = bs.newnode('text', attrs={ 'text': damage, 'in_world': True, @@ -385,7 +383,7 @@ def show_damage_count(self, damage: str, position: Sequence[float], 'scale': 0.035 if do_big else 0.03 }) # Translate upward. - tcombine = ba.newnode('combine', owner=txtnode, attrs={'size': 3}) + tcombine = bs.newnode('combine', owner=txtnode, attrs={'size': 3}) tcombine.connectattr('output', txtnode, 'position') v_vals = [] pval = 0.0 @@ -397,25 +395,25 @@ def show_damage_count(self, damage: str, position: Sequence[float], vval *= 0.5 p_start = position[0] p_dir = direction[0] - ba.animate(tcombine, 'input0', + bs.animate(tcombine, 'input0', {i[0] * lifespan: p_start + p_dir * i[1] for i in v_vals}) p_start = position[1] p_dir = direction[1] - ba.animate(tcombine, 'input1', + bs.animate(tcombine, 'input1', {i[0] * lifespan: p_start + p_dir * i[1] for i in v_vals}) p_start = position[2] p_dir = direction[2] - ba.animate(tcombine, 'input2', + bs.animate(tcombine, 'input2', {i[0] * lifespan: p_start + p_dir * i[1] for i in v_vals}) - ba.animate(txtnode, 'opacity', {0.7 * lifespan: 1.0, lifespan: 0.0}) - ba.timer(lifespan, txtnode.delete) + bs.animate(txtnode, 'opacity', {0.7 * lifespan: 1.0, lifespan: 0.0}) + bs.timer(lifespan, txtnode.delete) def _scoreboard(self) -> None: - self._backing = ba.NodeActor( - ba.newnode('image', + self._backing = bs.NodeActor( + bs.newnode('image', attrs={ 'position': (self.bar_posx + self._width / 2, -100), 'scale': (self._width, self._height), @@ -427,15 +425,15 @@ def _scoreboard(self) -> None: 'attach': 'topCenter', 'texture': self._backing_tex })) - self._bar = ba.NodeActor( - ba.newnode('image', + self._bar = bs.NodeActor( + bs.newnode('image', attrs={ 'opacity': 1.0, 'color': (0.5, 0.5, 0.5), 'attach': 'topCenter', 'texture': self._bar_tex })) - self._bar_scale = ba.newnode('combine', + self._bar_scale = bs.newnode('combine', owner=self._bar.node, attrs={ 'size': 2, @@ -443,7 +441,7 @@ def _scoreboard(self) -> None: 'input1': self._bar_height }) self._bar_scale.connectattr('output', self._bar.node, 'scale') - self._bar_position = ba.newnode( + self._bar_position = bs.newnode( 'combine', owner=self._bar.node, attrs={ @@ -452,8 +450,8 @@ def _scoreboard(self) -> None: 'input1': -100 }) self._bar_position.connectattr('output', self._bar.node, 'position') - self._cover = ba.NodeActor( - ba.newnode('image', + self._cover = bs.NodeActor( + bs.newnode('image', attrs={ 'position': (self.bar_posx + 120, -100), 'scale': @@ -465,10 +463,10 @@ def _scoreboard(self) -> None: 'vr_depth': 2, 'attach': 'topCenter', 'texture': self._cover_tex, - 'model_transparent': self._model + 'mesh_transparent': self._mesh })) - self._score_text = ba.NodeActor( - ba.newnode('text', + self._score_text = bs.NodeActor( + bs.newnode('text', attrs={ 'position': (self.bar_posx + 120, -100), 'h_attach': 'center', @@ -487,35 +485,36 @@ def _update(self) -> None: self._score_text.node.text = str(self.hitpoints) self._bar_width = self.hitpoints * self._width_max / self.hitpoints_max cur_width = self._bar_scale.input0 - ba.animate(self._bar_scale, 'input0', { + bs.animate(self._bar_scale, 'input0', { 0.0: cur_width, 0.1: self._bar_width }) cur_x = self._bar_position.input0 - ba.animate(self._bar_position, 'input0', { + bs.animate(self._bar_position, 'input0', { 0.0: cur_x, 0.1: self.bar_posx + self._bar_width / 2 }) if self.hitpoints > self.hitpoints_max * 3 / 4: - ba.animate_array(self.shield_deco, 'color', 3, + bs.animate_array(self.shield_deco, 'color', 3, {0: self.shield_deco.color, 0.2: (4, 4, 4)}) elif self.hitpoints > self.hitpoints_max * 1 / 2: - ba.animate_array(self.shield_deco, 'color', 3, + bs.animate_array(self.shield_deco, 'color', 3, {0: self.shield_deco.color, 0.2: (3, 3, 5)}) self.bot_count = 4 elif self.hitpoints > self.hitpoints_max * 1 / 4: - ba.animate_array(self.shield_deco, 'color', 3, + bs.animate_array(self.shield_deco, 'color', 3, {0: self.shield_deco.color, 0.2: (1, 5, 1)}) self.bot_count = 5 else: - ba.animate_array(self.shield_deco, 'color', 3, + bs.animate_array(self.shield_deco, 'color', 3, {0: self.shield_deco.color, 0.2: (5, 0.2, 0.2)}) self.bot_count = 6 + def update_ai(self) -> None: """Should be called periodically to update the spaz' AI.""" # pylint: disable=too-many-branches @@ -530,10 +529,10 @@ def update_ai(self) -> None: return pos = self.node.position - our_pos = ba.Vec3(pos[0], pos[1] - self.y_pos, pos[2]) + our_pos = bs.Vec3(pos[0], pos[1] - 3, pos[2]) - target_pt_raw: ba.Vec3 | None - target_vel: ba.Vec3 | None + target_pt_raw: bs.Vec3 | None + target_vel: bs.Vec3 | None target_pt_raw, target_vel = self._get_target_player_pt() @@ -562,15 +561,12 @@ def update_ai(self) -> None: setattr(self.node, 'extra_acceleration', (0, self.to_target.y * 80 + 70, 0)) - else: + elif not self.frozen: setattr(self.node, 'velocity', - (self.to_target.x * self.xz_pos, - self.to_target.y, - self.to_target.z * self.xz_pos)) + (self.to_target.x, self.to_target.y, self.to_target.z)) setattr(self.node, 'extra_acceleration', - (self.to_target.x * self.xz_pos, - self.to_target.y * 80 + 70, - self.to_target.z * self.xz_pos)) + (self.to_target.x, self.to_target.y * 80 + 70, + self.to_target.z)) def on_expire(self) -> None: super().on_expire() @@ -579,14 +575,14 @@ def on_expire(self) -> None: # no chance of them keeping activities or other things alive. self.update_callback = None - def animate_model(self) -> None: + def animate_mesh(self) -> None: if not self.node: return None - # ba.animate(self.node, 'model_scale', { - # 0: self.node.model_scale, - # 0.08: self.node.model_scale * 0.9, - # 0.15: self.node.model_scale}) - ba.emitfx(position=self.node.position, + # bs.animate(self.node, 'mesh_scale', { + # 0: self.node.mesh_scale, + # 0.08: self.node.mesh_scale * 0.9, + # 0.15: self.node.mesh_scale}) + bs.emitfx(position=self.node.position, velocity=self.node.velocity, count=int(6 + random.random() * 10), scale=0.5, @@ -597,15 +593,15 @@ def handlemessage(self, msg: Any) -> Any: # pylint: disable=too-many-branches assert not self.expired - if isinstance(msg, ba.HitMessage): + if isinstance(msg, bs.HitMessage): # Don't die on punches (that's annoying). - self.animate_model() + self.animate_mesh() if self.hitpoints != 0: self.do_damage(msg) # self.show_damage_msg(msg) self._update() - elif isinstance(msg, ba.DieMessage): + elif isinstance(msg, bs.DieMessage): if self.node: self.hitpoints = 0 self.frozen = True @@ -629,46 +625,52 @@ def ded_explode(count): position=(p_x, p[1], p_z), blast_radius=2.0).autoretain() - ba.timer(0 + i, ba.Call(ded_explode, i)) + bs.timer(0 + i, bs.Call(ded_explode, i)) - ba.timer(5, self.node.delete) - ba.timer(0.1, self.suck.delete) - ba.timer(0.1, self.suck_anim.delete) + bs.timer(5, self.node.delete) + bs.timer(0.1, self.suck.delete) + bs.timer(0.1, self.suck_anim.delete) - elif isinstance(msg, ba.OutOfBoundsMessage): - activity = _ba.get_foreground_host_activity() + elif isinstance(msg, bs.OutOfBoundsMessage): + activity = bs.get_foreground_host_activity() try: point = activity.map.get_flag_position(None) boss_spawn_pos = (point[0], point[1] + 1.5, point[2]) assert self.node self.node.position = boss_spawn_pos except: - self.handlemessage(ba.DieMessage()) + self.handlemessage(bs.DieMessage()) - elif isinstance(msg, ba.FreezeMessage): + elif isinstance(msg, bs.FreezeMessage): if not self.frozen: self.frozen = True - self.y_pos = -1.5 - self.xz_pos = 0.01 + self.drop_bomb_timer = False + self.drop_bots_timer = False + setattr(self.node, 'velocity', + (0, self.to_target.y, 0)) + setattr(self.node, 'extra_acceleration', + (0, 0, 0)) self.node.reflection_scale = [2] def unfrozen(): self.frozen = False - if self.bot_dur_froze: - ba.timer(0.1, ba.Call(self._drop_bots)) - self.bot_dur_froze = False - self.y_pos = 3 - self.xz_pos = 1 + self.drop_bomb_timer = bs.Timer(1.5, + bs.Call(self._drop_bomb), + repeat=True) + + self.drop_bots_timer = bs.Timer(15.0, + bs.Call(self._drop_bots), + repeat=True) self.node.reflection_scale = [0.25] - ba.timer(5.0, unfrozen) + bs.timer(3.0, unfrozen) else: super().handlemessage(msg) class UFOSet: - """A container/controller for one or more ba.SpazBots. + """A container/controller for one or more bs.SpazBots. category: Bot Classes """ @@ -684,9 +686,9 @@ def __init__(self) -> None: self._ufo_bot_lists: list[list[UFO]] = [ [] for _ in range(self._ufo_bot_list_count) ] - self._ufo_spawn_sound = ba.getsound('spawn') + self._ufo_spawn_sound = bs.getsound('spawn') self._ufo_spawning_count = 0 - self._ufo_bot_update_timer: ba.Timer | None = None + self._ufo_bot_update_timer: bs.Timer | None = None self.start_moving() def _update(self) -> None: @@ -699,18 +701,18 @@ def _update(self) -> None: ] except Exception: bot_list = [] - ba.print_exception( + bs.print_exception( 'Error updating bot list: ' + str(self._ufo_bot_lists[self._ufo_bot_update_list]) ) self._bot_update_list = ( - self._ufo_bot_update_list + 1 - ) % self._ufo_bot_list_count + self._ufo_bot_update_list + 1 + ) % self._ufo_bot_list_count # Update our list of player points for the bots to use. player_pts = [] - for player in ba.getactivity().players: - assert isinstance(player, ba.Player) + for player in bs.getactivity().players: + assert isinstance(player, bs.Player) try: # TODO: could use abstracted player.position here so we # don't have to assume their actor type, but we have no @@ -720,12 +722,12 @@ def _update(self) -> None: assert player.actor.node player_pts.append( ( - ba.Vec3(player.actor.node.position), - ba.Vec3(player.actor.node.velocity), + bs.Vec3(player.actor.node.position), + bs.Vec3(player.actor.node.velocity), ) ) except Exception: - ba.print_exception('Error on bot-set _update.') + bs.print_exception('Error on bot-set _update.') for bot in bot_list: bot.set_player_points(player_pts) @@ -733,8 +735,8 @@ def _update(self) -> None: def start_moving(self) -> None: """Start processing bot AI updates so they start doing their thing.""" - self._ufo_bot_update_timer = ba.Timer( - 0.05, ba.WeakCall(self._update), repeat=True + self._ufo_bot_update_timer = bs.Timer( + 0.05, bs.WeakCall(self._update), repeat=True ) def spawn_bot( @@ -745,13 +747,13 @@ def spawn_bot( on_spawn_call: Callable[[UFO], Any] | None = None, ) -> None: """Spawn a bot from this set.""" - from bastd.actor import spawner + from bascenev1lib.actor import spawner spawner.Spawner( pt=pos, spawn_time=spawn_time, send_spawn_message=False, - spawn_callback=ba.Call( + spawn_callback=bs.Call( self._spawn_bot, bot_type, pos, on_spawn_call ), ) @@ -764,21 +766,21 @@ def _spawn_bot( on_spawn_call: Callable[[UFO], Any] | None, ) -> None: spaz = bot_type() - ba.playsound(self._ufo_spawn_sound, position=pos) + self._ufo_spawn_sound.play(position=pos) assert spaz.node spaz.node.handlemessage('flash') spaz.node.is_area_of_interest = False - spaz.handlemessage(ba.StandMessage(pos, random.uniform(0, 360))) + spaz.handlemessage(bs.StandMessage(pos, random.uniform(0, 360))) self.add_bot(spaz) self._ufo_spawning_count -= 1 if on_spawn_call is not None: on_spawn_call(spaz) def add_bot(self, bot: UFO) -> None: - """Add a ba.SpazBot instance to the set.""" + """Add a bs.SpazBot instance to the set.""" self._ufo_bot_lists[self._ufo_bot_add_list].append(bot) self._ufo_bot_add_list = ( - self._ufo_bot_add_list + 1) % self._ufo_bot_list_count + self._ufo_bot_add_list + 1) % self._ufo_bot_list_count def have_living_bots(self) -> bool: """Return whether any bots in the set are alive or spawning.""" @@ -799,26 +801,26 @@ def clear(self) -> None: """Immediately clear out any bots in the set.""" # Don't do this if the activity is shutting down or dead. - activity = ba.getactivity(doraise=False) + activity = bs.getactivity(doraise=False) if activity is None or activity.expired: return for i, bot_list in enumerate(self._ufo_bot_lists): for bot in bot_list: - bot.handlemessage(ba.DieMessage(immediate=True)) + bot.handlemessage(bs.DieMessage(immediate=True)) self._ufo_bot_lists[i] = [] -class Player(ba.Player['Team']): +class Player(bs.Player['Team']): """Our player type for this game.""" -class Team(ba.Team[Player]): +class Team(bs.Team[Player]): """Our team type for this game.""" -# ba_meta export game -class UFOightGame(ba.TeamGameActivity[Player, Team]): +# ba_meta export bascenev1.GameActivity +class UFOightGame(bs.TeamGameActivity[Player, Team]): """ A co-op game where you try to defeat UFO Boss as fast as possible @@ -826,47 +828,49 @@ class UFOightGame(ba.TeamGameActivity[Player, Team]): name = 'UFO Fight' description = 'REal Boss Fight?' - scoreconfig = ba.ScoreConfig( - label='Time', scoretype=ba.ScoreType.MILLISECONDS, lower_is_better=True + scoreconfig = bs.ScoreConfig( + label='Time', scoretype=bs.ScoreType.MILLISECONDS, lower_is_better=True ) - default_music = ba.MusicType.TO_THE_DEATH + default_music = bs.MusicType.TO_THE_DEATH @classmethod - def get_supported_maps(cls, sessiontype: type[ba.Session]) -> list[str]: + def get_supported_maps(cls, sessiontype: type[bs.Session]) -> list[str]: # For now we're hard-coding spawn positions and whatnot # so we need to be sure to specify that we only support # a specific map. return ['Football Stadium'] @classmethod - def supports_session_type(cls, sessiontype: type[ba.Session]) -> bool: + def supports_session_type(cls, sessiontype: type[bs.Session]) -> bool: # We currently support Co-Op only. - return issubclass(sessiontype, ba.CoopSession) + return issubclass(sessiontype, bs.CoopSession) # In the constructor we should load any media we need/etc. # ...but not actually create anything yet. def __init__(self, settings: dict): super().__init__(settings) - self._winsound = ba.getsound('score') + self._winsound = bs.getsound('score') self._won = False self._timer: OnScreenTimer | None = None self._bots = UFOSet() self._preset = str(settings['preset']) - self._credit = ba.newnode('text', - attrs={ - 'v_attach': 'bottom', - 'h_align': 'center', - 'color': (0.4, 0.4, 0.4), - 'flatness': 0.5, - 'shadow': 0.5, - 'position': (0, 20), - 'scale': 0.7, - 'text': 'By Cross Joy' - }) + self._credit = bs.newnode('text', + attrs={ + 'v_attach': 'bottom', + 'h_align': 'center', + 'color': (0.4, 0.4, 0.4), + 'flatness': 0.5, + 'shadow': 0.5, + 'position': (0, 20), + 'scale': 0.7, + 'text': 'By Cross Joy' + }) + + def on_transition_in(self) -> None: super().on_transition_in() - gnode = ba.getactivity().globalsnode + gnode = bs.getactivity().globalsnode gnode.tint = (0.42, 0.55, 0.66) # Called when our game actually begins. @@ -874,24 +878,26 @@ def on_begin(self) -> None: super().on_begin() self.setup_standard_powerup_drops() + + # In pro mode there's no powerups. # Make our on-screen timer and start it roughly when our bots appear. self._timer = OnScreenTimer() - ba.timer(4.0, self._timer.start) + bs.timer(4.0, self._timer.start) def checker(): if not self._won: - self.timer = ba.Timer(0.1, self._check_if_won, repeat=True) + self.timer = bs.Timer(0.1, self._check_if_won, repeat=True) - ba.timer(10, checker) - activity = _ba.get_foreground_host_activity() + bs.timer(10, checker) + activity = bs.get_foreground_host_activity() point = activity.map.get_flag_position(None) boss_spawn_pos = (point[0], point[1] + 1.5, point[2]) # Spawn some baddies. - ba.timer( + bs.timer( 1.0, lambda: self._bots.spawn_bot( UFO, pos=boss_spawn_pos, spawn_time=3.0 @@ -915,10 +921,10 @@ def _check_if_won(self) -> None: def handlemessage(self, msg: Any) -> Any: # A player has died. - if isinstance(msg, ba.PlayerDiedMessage): + if isinstance(msg, bs.PlayerDiedMessage): player = msg.getplayer(Player) self.stats.player_was_killed(player) - ba.timer(0.1, self._checkroundover) + bs.timer(0.1, self._checkroundover) # A spaz-bot has died. elif isinstance(msg, UFODiedMessage): @@ -926,7 +932,7 @@ def handlemessage(self, msg: Any) -> Any: # bots if we ask here (the currently-dying bot isn't officially # marked dead yet) ..so lets push a call into the event loop to # check once this guy has finished dying. - ba.pushcall(self._check_if_won) + bs.pushcall(self._check_if_won) # Let the base class handle anything we don't. else: @@ -948,20 +954,20 @@ def end_game(self) -> None: assert self._timer is not None self._timer.stop() - results = ba.GameResults() + results = bs.GameResults() # If we won, set our score to the elapsed time in milliseconds. # (there should just be 1 team here since this is co-op). # ..if we didn't win, leave scores as default (None) which means # we lost. if self._won: - elapsed_time_ms = int((ba.time() - self._timer.starttime) * 1000.0) - ba.cameraflash() - ba.playsound(self._winsound) + elapsed_time_ms = int((bs.time() - self._timer.starttime) * 1000.0) + bs.cameraflash() + self._winsound.play() for team in self.teams: for player in team.players: if player.actor: - player.actor.handlemessage(ba.CelebrateMessage()) + player.actor.handlemessage(bs.CelebrateMessage()) results.set_team_score(team, elapsed_time_ms) # Ends the activity. @@ -969,11 +975,11 @@ def end_game(self) -> None: # ba_meta export plugin -class MyUFOFightLevel(ba.Plugin): +class MyUFOFightLevel(babase.Plugin): def on_app_running(self) -> None: - ba.app.add_coop_practice_level( - ba.Level( + babase.app.classic.add_coop_practice_level( + bs.Level( name='The UFO Fight', displayname='${GAME}', gametype=UFOightGame, @@ -981,3 +987,4 @@ def on_app_running(self) -> None: preview_texture_name='footballStadiumPreview', ) ) + diff --git a/plugins/minigames/ultimate_last_stand.py b/plugins/minigames/ultimate_last_stand.py index b74d0027..842521dd 100644 --- a/plugins/minigames/ultimate_last_stand.py +++ b/plugins/minigames/ultimate_last_stand.py @@ -1,3 +1,4 @@ +# Porting to api 8 made easier by baport.(https://github.com/bombsquad-community/baport) """Ultimate Last Stand V2: Made by Cross Joy""" @@ -25,7 +26,7 @@ # ---------------------------------------------------------------------------- -# ba_meta require api 7 +# ba_meta require api 8 from __future__ import annotations @@ -33,13 +34,15 @@ from dataclasses import dataclass from typing import TYPE_CHECKING -import ba -from bastd.actor.playerspaz import PlayerSpaz -from bastd.actor.bomb import TNTSpawner -from bastd.actor.onscreentimer import OnScreenTimer -from bastd.actor.scoreboard import Scoreboard -from bastd.actor.spazfactory import SpazFactory -from bastd.actor.spazbot import (SpazBot, SpazBotSet, BomberBot, +import babase +import bauiv1 as bui +import bascenev1 as bs +from bascenev1lib.actor.playerspaz import PlayerSpaz +from bascenev1lib.actor.bomb import TNTSpawner +from bascenev1lib.actor.onscreentimer import OnScreenTimer +from bascenev1lib.actor.scoreboard import Scoreboard +from bascenev1lib.actor.spazfactory import SpazFactory +from bascenev1lib.actor.spazbot import (SpazBot, SpazBotSet, BomberBot, BomberBotPro, BomberBotProShielded, BrawlerBot, BrawlerBotPro, BrawlerBotProShielded, TriggerBot, @@ -48,7 +51,7 @@ if TYPE_CHECKING: from typing import Any, Sequence - from bastd.actor.spazbot import SpazBot + from bascenev1lib.actor.spazbot import SpazBot class IceBot(SpazBot): @@ -71,7 +74,7 @@ class IceBot(SpazBot): points_mult = 3 -class Icon(ba.Actor): +class Icon(bs.Actor): """Creates in in-game icon on screen.""" def __init__(self, @@ -90,10 +93,10 @@ def __init__(self, self._show_lives = show_lives self._show_death = show_death self._name_scale = name_scale - self._outline_tex = ba.gettexture('characterIconMask') + self._outline_tex = bs.gettexture('characterIconMask') icon = player.get_icon() - self.node = ba.newnode('image', + self.node = bs.newnode('image', delegate=self, attrs={ 'texture': icon['texture'], @@ -106,12 +109,12 @@ def __init__(self, 'absolute_scale': True, 'attach': 'bottomCenter' }) - self._name_text = ba.newnode( + self._name_text = bs.newnode( 'text', owner=self.node, attrs={ - 'text': ba.Lstr(value=player.getname()), - 'color': ba.safecolor(player.team.color), + 'text': babase.Lstr(value=player.getname()), + 'color': babase.safecolor(player.team.color), 'h_align': 'center', 'v_align': 'center', 'vr_depth': 410, @@ -122,7 +125,7 @@ def __init__(self, 'v_attach': 'bottom' }) if self._show_lives: - self._lives_text = ba.newnode('text', + self._lives_text = bs.newnode('text', owner=self.node, attrs={ 'text': 'x0', @@ -178,7 +181,7 @@ def handle_player_died(self) -> None: if not self.node: return if self._show_death: - ba.animate( + bs.animate( self.node, 'opacity', { 0.00: 1.0, 0.05: 0.0, @@ -195,10 +198,10 @@ def handle_player_died(self) -> None: }) lives = self._player.lives if lives == 0: - ba.timer(0.6, self.update_for_lives) + bs.timer(0.6, self.update_for_lives) def handlemessage(self, msg: Any) -> Any: - if isinstance(msg, ba.DieMessage): + if isinstance(msg, bs.DieMessage): self.node.delete() return None return super().handlemessage(msg) @@ -212,7 +215,7 @@ class SpawnInfo: dincrease: float -class Player(ba.Player['Team']): +class Player(bs.Player['Team']): """Our player type for this game.""" def __init__(self) -> None: @@ -222,7 +225,7 @@ def __init__(self) -> None: self.icons: list[Icon] = [] -class Team(ba.Team[Player]): +class Team(bs.Team[Player]): """Our team type for this game.""" def __init__(self) -> None: @@ -230,14 +233,14 @@ def __init__(self) -> None: self.spawn_order: list[Player] = [] -# ba_meta export game -class UltimateLastStand(ba.TeamGameActivity[Player, Team]): +# ba_meta export bascenev1.GameActivity +class UltimateLastStand(bs.TeamGameActivity[Player, Team]): """Minigame involving dodging falling bombs.""" name = 'Ultimate Last Stand' description = 'Only the strongest will stand at the end.' - scoreconfig = ba.ScoreConfig(label='Survived', - scoretype=ba.ScoreType.SECONDS, + scoreconfig = bs.ScoreConfig(label='Survived', + scoretype=bs.ScoreType.SECONDS, none_is_winner=True) # Print messages when players die (since its meaningful in this game). @@ -250,16 +253,16 @@ class UltimateLastStand(ba.TeamGameActivity[Player, Team]): @classmethod def get_available_settings( cls, - sessiontype: type[ba.Session]) -> list[ba.Setting]: + sessiontype: type[bs.Session]) -> list[babase.Setting]: settings = [ - ba.IntSetting( + bs.IntSetting( 'Lives Per Player', default=1, min_value=1, max_value=10, increment=1, ), - ba.FloatChoiceSetting( + bs.FloatChoiceSetting( 'Respawn Times', choices=[ ('Shorter', 0.25), @@ -270,31 +273,31 @@ def get_available_settings( ], default=1.0, ), - ba.BoolSetting('Epic Mode', default=False), + bs.BoolSetting('Epic Mode', default=False), ] - if issubclass(sessiontype, ba.DualTeamSession): + if issubclass(sessiontype, bs.DualTeamSession): settings.append( - ba.BoolSetting('Balance Total Lives', default=False)) + bs.BoolSetting('Balance Total Lives', default=False)) return settings # We're currently hard-coded for one map. @classmethod - def get_supported_maps(cls, sessiontype: type[ba.Session]) -> list[str]: + def get_supported_maps(cls, sessiontype: type[bs.Session]) -> list[str]: return ['Rampage'] # We support teams, free-for-all, and co-op sessions. @classmethod - def supports_session_type(cls, sessiontype: type[ba.Session]) -> bool: - return (issubclass(sessiontype, ba.DualTeamSession) - or issubclass(sessiontype, ba.FreeForAllSession)) + def supports_session_type(cls, sessiontype: type[bs.Session]) -> bool: + return (issubclass(sessiontype, bs.DualTeamSession) + or issubclass(sessiontype, bs.FreeForAllSession)) def __init__(self, settings: dict): super().__init__(settings) self._scoreboard = Scoreboard() self._start_time: float | None = None - self._vs_text: ba.Actor | None = None - self._round_end_timer: ba.Timer | None = None + self._vs_text: bs.Actor | None = None + self._round_end_timer: bs.Timer | None = None self._lives_per_player = int(settings['Lives Per Player']) self._balance_total_lives = bool( settings.get('Balance Total Lives', False)) @@ -302,17 +305,17 @@ def __init__(self, settings: dict): self._last_player_death_time: float | None = None self._timer: OnScreenTimer | None = None self._tntspawner: TNTSpawner | None = None - self._new_wave_sound = ba.getsound('scoreHit01') + self._new_wave_sound = bs.getsound('scoreHit01') self._bots = SpazBotSet() self._tntspawnpos = (0, 5.5, -6) self.spazList = [] # Base class overrides: self.slow_motion = self._epic_mode - self.default_music = (ba.MusicType.EPIC - if self._epic_mode else ba.MusicType.SURVIVAL) + self.default_music = (bs.MusicType.EPIC + if self._epic_mode else bs.MusicType.SURVIVAL) - self.node = ba.newnode('text', + self.node = bs.newnode('text', attrs={ 'v_attach': 'bottom', 'h_align': 'center', @@ -342,24 +345,24 @@ def __init__(self, settings: dict): } # yapf: disable # Some base class overrides: - self.default_music = (ba.MusicType.EPIC - if self._epic_mode else ba.MusicType.SURVIVAL) + self.default_music = (bs.MusicType.EPIC + if self._epic_mode else bs.MusicType.SURVIVAL) if self._epic_mode: self.slow_motion = True def get_instance_description(self) -> str | Sequence: return 'Only the strongest team will stand at the end.' if isinstance( self.session, - ba.DualTeamSession) else 'Only the strongest will stand at the end.' + bs.DualTeamSession) else 'Only the strongest will stand at the end.' def get_instance_description_short(self) -> str | Sequence: return 'Only the strongest team will stand at the end.' if isinstance( self.session, - ba.DualTeamSession) else 'Only the strongest will stand at the end.' + bs.DualTeamSession) else 'Only the strongest will stand at the end.' def on_transition_in(self) -> None: super().on_transition_in() - ba.timer(1.3, ba.Call(ba.playsound, self._new_wave_sound)) + bs.timer(1.3, babase.Call(babase.playsound, self._new_wave_sound)) def on_player_join(self, player: Player) -> None: player.lives = self._lives_per_player @@ -374,13 +377,13 @@ def on_player_join(self, player: Player) -> None: def on_begin(self) -> None: super().on_begin() - ba.animate_array(node=self.node, attr='color', size=3, keys={ + bs.animate_array(node=self.node, attr='color', size=3, keys={ 0.0: (0.5, 0.5, 0.5), 0.8: (0.83, 0.69, 0.21), 1.6: (0.5, 0.5, 0.5) }, loop=True) - ba.timer(0.001, ba.WeakCall(self._start_bot_updates)) + bs.timer(0.001, bs.WeakCall(self._start_bot_updates)) self._tntspawner = TNTSpawner(position=self._tntspawnpos, respawn_time=10.0) @@ -389,11 +392,11 @@ def on_begin(self) -> None: self.setup_standard_powerup_drops() # Check for immediate end (if we've only got 1 player, etc). - self._start_time = ba.time() + self._start_time = bs.time() # If balance-team-lives is on, add lives to the smaller team until # total lives match. - if (isinstance(self.session, ba.DualTeamSession) + if (isinstance(self.session, bs.DualTeamSession) and self._balance_total_lives and self.teams[0].players and self.teams[1].players): if self._get_total_team_lives( @@ -409,7 +412,7 @@ def on_begin(self) -> None: lesser_team.players[add_index].lives += 1 add_index = (add_index + 1) % len(lesser_team.players) - ba.timer(1.0, self._update, repeat=True) + bs.timer(1.0, self._update, repeat=True) self._update_icons() # We could check game-over conditions at explicit trigger points, @@ -419,7 +422,7 @@ def _update_icons(self) -> None: # pylint: disable=too-many-branches # In free-for-all mode, everyone is just lined up along the bottom. - if isinstance(self.session, ba.FreeForAllSession): + if isinstance(self.session, bs.FreeForAllSession): count = len(self.teams) x_offs = 85 xval = x_offs * (count - 1) * -0.5 @@ -453,21 +456,21 @@ def on_player_leave(self, player: Player) -> None: # Update icons in a moment since our team will be gone from the # list then. - ba.timer(0, self._update_icons) + bs.timer(0, self._update_icons) # If the player to leave was the last in spawn order and had # their final turn currently in-progress, mark the survival time # for their team. if self._get_total_team_lives(player.team) == 0: assert self._start_time is not None - player.team.survival_seconds = int(ba.time() - self._start_time) + player.team.survival_seconds = int(bs.time() - self._start_time) # A departing player may trigger game-over. # overriding the default character spawning.. - def spawn_player(self, player: Player) -> ba.Actor: + def spawn_player(self, player: Player) -> bs.Actor: actor = self.spawn_player_spaz(player) - ba.timer(0.3, ba.Call(self._print_lives, player)) + bs.timer(0.3, babase.Call(self._print_lives, player)) # If we have any icons, update their state. for icon in player.icons: @@ -475,7 +478,7 @@ def spawn_player(self, player: Player) -> ba.Actor: return actor def _print_lives(self, player: Player) -> None: - from bastd.actor import popuptext + from bascenev1lib.actor import popuptext # We get called in a timer so it's possible our player has left/etc. if not player or not player.is_alive() or not player.node: @@ -499,14 +502,14 @@ def _start_bot_updates(self) -> None: self._update_bots() if len(self.players) > 3: self._update_bots() - self._bot_update_timer = ba.Timer(self._bot_update_interval, - ba.WeakCall(self._update_bots)) + self._bot_update_timer = bs.Timer(self._bot_update_interval, + bs.WeakCall(self._update_bots)) def _update_bots(self) -> None: assert self._bot_update_interval is not None self._bot_update_interval = max(0.5, self._bot_update_interval * 0.98) - self._bot_update_timer = ba.Timer(self._bot_update_interval, - ba.WeakCall(self._update_bots)) + self._bot_update_timer = bs.Timer(self._bot_update_interval, + bs.WeakCall(self._update_bots)) botspawnpts: list[Sequence[float]] = [[-5.0, 5.5, -4.14], [0.0, 5.5, -4.14], [5.0, 5.5, -4.14]] @@ -516,7 +519,7 @@ def _update_bots(self) -> None: assert isinstance(player.actor, PlayerSpaz) assert player.actor.node except Exception: - ba.print_exception('Error updating bots.') + babase.print_exception('Error updating bots.') spawnpt = random.choice( [botspawnpts[0], botspawnpts[1], botspawnpts[2]]) @@ -550,12 +553,12 @@ def _update_bots(self) -> None: # Various high-level game events come through this method. def handlemessage(self, msg: Any) -> Any: - if isinstance(msg, ba.PlayerDiedMessage): + if isinstance(msg, bs.PlayerDiedMessage): # Augment standard behavior. super().handlemessage(msg) - curtime = ba.time() + curtime = bs.time() # Record the player's moment of death. # assert isinstance(msg.spaz.player @@ -574,14 +577,14 @@ def handlemessage(self, msg: Any) -> Any: # Play big death sound on our last death # or for every one in solo mode. if player.lives == 0: - ba.playsound(SpazFactory.get().single_player_death_sound) + SpazFactory.get().single_player_death_sound.play() # If we hit zero lives, we're dead (and our team might be too). if player.lives == 0: # If the whole team is now dead, mark their survival time. if self._get_total_team_lives(player.team) == 0: assert self._start_time is not None - player.team.survival_seconds = int(ba.time() - + player.team.survival_seconds = int(bs.time() - self._start_time) else: # Otherwise, in regular mode, respawn. @@ -599,7 +602,7 @@ def _update(self) -> None: # the game (allows the dust to settle and draws to occur if deaths # are close enough). if len(self._get_living_teams()) < 2: - self._round_end_timer = ba.Timer(0.5, self.end_game) + self._round_end_timer = bs.Timer(0.5, self.end_game) def end_game(self) -> None: # Stop updating our time text, and set the final time to match @@ -608,7 +611,7 @@ def end_game(self) -> None: # Ok now calc game results: set a score for each team and then tell # the game to end. - results = ba.GameResults() + results = bs.GameResults() # Remember that 'free-for-all' mode is simply a special form # of 'teams' mode where each player gets their own team, so we can diff --git a/plugins/minigames/zombie_horde.py b/plugins/minigames/zombie_horde.py index afb48f3b..0728409e 100644 --- a/plugins/minigames/zombie_horde.py +++ b/plugins/minigames/zombie_horde.py @@ -1,23 +1,26 @@ -# ba_meta require api 7 +# Porting to api 8 made easier by baport.(https://github.com/bombsquad-community/baport) +# ba_meta require api 8 # (see https://ballistica.net/wiki/meta-tag-system) from __future__ import annotations from typing import TYPE_CHECKING -import ba -import _ba +import babase +import bauiv1 as bui +import bascenev1 as bs +import _babase import copy import random -from ba import _math -from ba._coopsession import CoopSession -from ba._messages import PlayerDiedMessage, StandMessage -from bastd.actor.playerspaz import PlayerSpaz -from bastd.actor.scoreboard import Scoreboard -from bastd.game.elimination import Icon, Player -from bastd.actor.spaz import PickupMessage -from bastd.actor.spazbot import SpazBotSet, BrawlerBot, SpazBotDiedMessage -from bastd.actor.spazfactory import SpazFactory +from babase import _math +from bascenev1._coopsession import CoopSession +from bascenev1._messages import PlayerDiedMessage, StandMessage +from bascenev1lib.actor.playerspaz import PlayerSpaz +from bascenev1lib.actor.scoreboard import Scoreboard +from bascenev1lib.game.elimination import Icon, Player +from bascenev1lib.actor.spaz import PickupMessage +from bascenev1lib.actor.spazbot import SpazBotSet, BrawlerBot, SpazBotDiedMessage +from bascenev1lib.actor.spazfactory import SpazFactory if TYPE_CHECKING: @@ -26,7 +29,7 @@ class PlayerSpaz_Zom(PlayerSpaz): def handlemessage(self, m: Any) -> Any: - if isinstance(m, ba.HitMessage): + if isinstance(m, bs.HitMessage): if not self.node: return if not m._source_player is None: @@ -40,7 +43,7 @@ def handlemessage(self, m: Any) -> Any: else: super().handlemessage(m) - elif isinstance(m, ba.FreezeMessage): + elif isinstance(m, bs.FreezeMessage): pass elif isinstance(m, PickupMessage): @@ -48,10 +51,10 @@ def handlemessage(self, m: Any) -> Any: return None try: - collision = ba.getcollision() + collision = bs.getcollision() opposingnode = collision.opposingnode opposingbody = collision.opposingbody - except ba.NotFoundError: + except bs.NotFoundError: return True try: @@ -85,7 +88,7 @@ def handlemessage(self, m: Any) -> Any: class PlayerZombie(PlayerSpaz): def handlemessage(self, m: Any) -> Any: - if isinstance(m, ba.HitMessage): + if isinstance(m, bs.HitMessage): if not self.node: return None if not m._source_player is None: @@ -106,8 +109,8 @@ def handlemessage(self, m: Any) -> Any: class zBotSet(SpazBotSet): def start_moving(self) -> None: """Start processing bot AI updates so they start doing their thing.""" - self._bot_update_timer = ba.Timer(0.05, - ba.WeakCall(self.zUpdate), + self._bot_update_timer = bs.Timer(0.05, + bs.WeakCall(self.zUpdate), repeat=True) def zUpdate(self) -> None: @@ -118,31 +121,31 @@ def zUpdate(self) -> None: ]) except Exception: bot_list = [] - ba.print_exception('Error updating bot list: ' + + babase.print_exception('Error updating bot list: ' + str(self._bot_lists[self._bot_update_list])) self._bot_update_list = (self._bot_update_list + 1) % self._bot_list_count player_pts = [] - for player in ba.getactivity().players: - assert isinstance(player, ba.Player) + for player in bs.getactivity().players: + assert isinstance(player, bs.Player) try: if player.is_alive(): assert isinstance(player.actor, Spaz) assert player.actor.node if player.lives > 0: player_pts.append( - (ba.Vec3(player.actor.node.position), - ba.Vec3(player.actor.node.velocity))) + (babase.Vec3(player.actor.node.position), + babase.Vec3(player.actor.node.velocity))) except Exception: - ba.print_exception('Error on bot-set _update.') + babase.print_exception('Error on bot-set _update.') for bot in bot_list: bot.set_player_points(player_pts) bot.update_ai() -class Team(ba.Team[Player]): +class Team(bs.Team[Player]): """Our team type for this game.""" def __init__(self) -> None: @@ -150,13 +153,13 @@ def __init__(self) -> None: self.spawn_order: list[Player] = [] -# ba_meta export game -class ZombieHorde(ba.TeamGameActivity[Player, Team]): +# ba_meta export bascenev1.GameActivity +class ZombieHorde(bs.TeamGameActivity[Player, Team]): name = 'Zombie Horde' description = 'Kill walkers for points!' - scoreconfig = ba.ScoreConfig(label='Score', - scoretype=ba.ScoreType.POINTS, + scoreconfig = bs.ScoreConfig(label='Score', + scoretype=bs.ScoreType.POINTS, none_is_winner=False, lower_is_better=False) # Show messages when players die since it's meaningful here. @@ -164,23 +167,23 @@ class ZombieHorde(ba.TeamGameActivity[Player, Team]): @classmethod def get_available_settings( - cls, sessiontype: type[ba.Session]) -> list[ba.Setting]: + cls, sessiontype: type[bs.Session]) -> list[babase.Setting]: settings = [ - ba.IntSetting( + bs.IntSetting( 'Lives Per Player', default=1, min_value=1, max_value=10, increment=1, ), - ba.IntSetting( + bs.IntSetting( 'Max Zombies', default=10, min_value=5, max_value=50, increment=5, ), - ba.IntChoiceSetting( + bs.IntChoiceSetting( 'Time Limit', choices=[ ('None', 0), @@ -192,7 +195,7 @@ def get_available_settings( ], default=0, ), - ba.FloatChoiceSetting( + bs.FloatChoiceSetting( 'Respawn Times', choices=[ ('Shorter', 0.25), @@ -203,29 +206,29 @@ def get_available_settings( ], default=1.0, ), - ba.BoolSetting('Epic Mode', default=False), + bs.BoolSetting('Epic Mode', default=False), ] - if issubclass(sessiontype, ba.DualTeamSession): - settings.append(ba.BoolSetting('Solo Mode', default=False)) + if issubclass(sessiontype, bs.DualTeamSession): + settings.append(bs.BoolSetting('Solo Mode', default=False)) settings.append( - ba.BoolSetting('Balance Total Lives', default=False)) + bs.BoolSetting('Balance Total Lives', default=False)) return settings @classmethod - def supports_session_type(cls, sessiontype: type[ba.Session]) -> bool: - return (issubclass(sessiontype, ba.DualTeamSession) - or issubclass(sessiontype, ba.FreeForAllSession)) + def supports_session_type(cls, sessiontype: type[bs.Session]) -> bool: + return (issubclass(sessiontype, bs.DualTeamSession) + or issubclass(sessiontype, bs.FreeForAllSession)) @classmethod - def get_supported_maps(cls, sessiontype: type[ba.Session]) -> list[str]: - return ba.getmaps('melee') + def get_supported_maps(cls, sessiontype: type[bs.Session]) -> list[str]: + return bs.app.classic.getmaps('melee') def __init__(self, settings: dict): super().__init__(settings) self._scoreboard = Scoreboard() self._start_time: float | None = None - self._vs_text: ba.Actor | None = None - self._round_end_timer: ba.Timer | None = None + self._vs_text: bs.Actor | None = None + self._round_end_timer: bs.Timer | None = None self._epic_mode = bool(settings['Epic Mode']) self._lives_per_player = int(settings['Lives Per Player']) self._max_zombies = int(settings['Max Zombies']) @@ -236,53 +239,53 @@ def __init__(self, settings: dict): # Base class overrides: self.slow_motion = self._epic_mode - self.default_music = (ba.MusicType.EPIC - if self._epic_mode else ba.MusicType.SURVIVAL) + self.default_music = (bs.MusicType.EPIC + if self._epic_mode else bs.MusicType.SURVIVAL) self.spazList = [] self.zombieQ = 0 - activity = ba.getactivity() + activity = bs.getactivity() my_factory = SpazFactory.get() appears = ['Kronk', 'Zoe', 'Pixel', 'Agent Johnson', 'Bones', 'Frosty', 'Kronk2'] - myAppear = copy.copy(ba.app.spaz_appearances['Kronk']) + myAppear = copy.copy(babase.app.classic.spaz_appearances['Kronk']) myAppear.name = 'Kronk2' - ba.app.spaz_appearances['Kronk2'] = myAppear + babase.app.classic.spaz_appearances['Kronk2'] = myAppear for appear in appears: my_factory.get_media(appear) med = my_factory.spaz_media - med['Kronk2']['head_model'] = med['Zoe']['head_model'] + med['Kronk2']['head_mesh'] = med['Zoe']['head_mesh'] med['Kronk2']['color_texture'] = med['Agent Johnson']['color_texture'] med['Kronk2']['color_mask_texture'] = med['Pixel']['color_mask_texture'] - med['Kronk2']['torso_model'] = med['Bones']['torso_model'] - med['Kronk2']['pelvis_model'] = med['Pixel']['pelvis_model'] - med['Kronk2']['upper_arm_model'] = med['Frosty']['upper_arm_model'] - med['Kronk2']['forearm_model'] = med['Frosty']['forearm_model'] - med['Kronk2']['hand_model'] = med['Bones']['hand_model'] - med['Kronk2']['upper_leg_model'] = med['Bones']['upper_leg_model'] - med['Kronk2']['lower_leg_model'] = med['Pixel']['lower_leg_model'] - med['Kronk2']['toes_model'] = med['Bones']['toes_model'] + med['Kronk2']['torso_mesh'] = med['Bones']['torso_mesh'] + med['Kronk2']['pelvis_mesh'] = med['Pixel']['pelvis_mesh'] + med['Kronk2']['upper_arm_mesh'] = med['Frosty']['upper_arm_mesh'] + med['Kronk2']['forearm_mesh'] = med['Frosty']['forearm_mesh'] + med['Kronk2']['hand_mesh'] = med['Bones']['hand_mesh'] + med['Kronk2']['upper_leg_mesh'] = med['Bones']['upper_leg_mesh'] + med['Kronk2']['lower_leg_mesh'] = med['Pixel']['lower_leg_mesh'] + med['Kronk2']['toes_mesh'] = med['Bones']['toes_mesh'] def get_instance_description(self) -> str | Sequence: return ('Kill walkers for points! ', 'Dead player walker: 2 points!') if isinstance( - self.session, ba.DualTeamSession) else ( + self.session, bs.DualTeamSession) else ( 'Kill walkers for points! Dead player walker: 2 points!') def get_instance_description_short(self) -> str | Sequence: return ('Kill walkers for points! ', 'Dead player walker: 2 points!') if isinstance( - self.session, ba.DualTeamSession) else ( + self.session, bs.DualTeamSession) else ( 'Kill walkers for points! Dead player walker: 2 points!') def on_player_join(self, player: Player) -> None: if self.has_begun(): player.lives = 0 player.icons = [] - ba.screenmessage( - ba.Lstr(resource='playerDelayedJoinText', + bs.broadcastmessage( + babase.Lstr(resource='playerDelayedJoinText', subs=[('${PLAYER}', player.getname(full=True))]), color=(0, 1, 0), ) @@ -314,13 +317,13 @@ def _update_solo_mode(self) -> None: def on_begin(self) -> None: super().on_begin() - self._start_time = ba.time() + self._start_time = bs.time() self.setup_standard_time_limit(self._time_limit) self.setup_standard_powerup_drops() self.zombieQ = 1 if self._solo_mode: - self._vs_text = ba.NodeActor( - ba.newnode('text', + self._vs_text = bs.NodeActor( + bs.newnode('text', attrs={ 'position': (0, 105), 'h_attach': 'center', @@ -331,12 +334,12 @@ def on_begin(self) -> None: 'scale': 0.6, 'v_attach': 'bottom', 'color': (0.8, 0.8, 0.3, 1.0), - 'text': ba.Lstr(resource='vsText') + 'text': babase.Lstr(resource='vsText') })) # If balance-team-lives is on, add lives to the smaller team until # total lives match. - if (isinstance(self.session, ba.DualTeamSession) + if (isinstance(self.session, bs.DualTeamSession) and self._balance_total_lives and self.teams[0].players and self.teams[1].players): if self._get_total_team_lives( @@ -365,13 +368,13 @@ def on_begin(self) -> None: # We could check game-over conditions at explicit trigger points, # but lets just do the simple thing and poll it. - ba.timer(1.0, self._update, repeat=True) + bs.timer(1.0, self._update, repeat=True) def _update_icons(self) -> None: # pylint: disable=too-many-branches # In free-for-all mode, everyone is just lined up along the bottom. - if isinstance(self.session, ba.FreeForAllSession): + if isinstance(self.session, bs.FreeForAllSession): count = len(self.teams) x_offs = 85 xval = x_offs * (count - 1) * -0.5 @@ -437,7 +440,7 @@ def _update_icons(self) -> None: icon.update_for_lives() xval += x_offs - def _get_spawn_point(self, player: Player) -> ba.Vec3 | None: + def _get_spawn_point(self, player: Player) -> babase.Vec3 | None: del player # Unused. # In solo-mode, if there's an existing live player on the map, spawn at @@ -455,10 +458,10 @@ def _get_spawn_point(self, player: Player) -> ba.Vec3 | None: break if living_player: assert living_player_pos is not None - player_pos = ba.Vec3(living_player_pos) - points: list[tuple[float, ba.Vec3]] = [] + player_pos = babase.Vec3(living_player_pos) + points: list[tuple[float, babase.Vec3]] = [] for team in self.teams: - start_pos = ba.Vec3(self.map.get_start_position(team.id)) + start_pos = babase.Vec3(self.map.get_start_position(team.id)) points.append( ((start_pos - player_pos).length(), start_pos)) # Hmm.. we need to sorting vectors too? @@ -466,13 +469,13 @@ def _get_spawn_point(self, player: Player) -> ba.Vec3 | None: return points[-1][1] return None - def spawn_player(self, player: Player) -> ba.Actor: + def spawn_player(self, player: Player) -> bs.Actor: position = self.map.get_ffa_start_position(self.players) angle = 20 name = player.getname() light_color = _math.normalized_color(player.color) - display_color = _ba.safecolor(player.color, target_intensity=0.75) + display_color = _babase.safecolor(player.color, target_intensity=0.75) spaz = PlayerSpaz_Zom(color=player.color, highlight=player.highlight, character=player.character, @@ -500,14 +503,14 @@ def spawn_player(self, player: Player) -> ba.Actor: StandMessage( position, angle if angle is not None else random.uniform(0, 360))) - _ba.playsound(self._spawn_sound, 1, position=spaz.node.position) - light = _ba.newnode('light', attrs={'color': light_color}) + bs.Sound.play(self._spawn_sound, 1, position=spaz.node.position) + light = bs.newnode('light', attrs={'color': light_color}) spaz.node.connectattr('position', light, 'position') - ba.animate(light, 'intensity', {0: 0, 0.25: 1, 0.5: 0}) - _ba.timer(0.5, light.delete) + bs.animate(light, 'intensity', {0: 0, 0.25: 1, 0.5: 0}) + bs.timer(0.5, light.delete) if not self._solo_mode: - ba.timer(0.3, ba.Call(self._print_lives, player)) + bs.timer(0.3, babase.Call(self._print_lives, player)) for icon in player.icons: icon.handle_player_spawned() @@ -539,30 +542,30 @@ def respawn_player_zombie(self, 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, ba.WeakCall( + from bascenev1lib.actor.respawnicon import RespawnIcon + player.customdata['respawn_timer'] = bs.Timer( + respawn_time, bs.WeakCall( self.spawn_player_if_exists_as_zombie, player)) player.customdata['respawn_icon'] = RespawnIcon( player, respawn_time) - def spawn_player_if_exists_as_zombie(self, player: PlayerType) -> None: + def spawn_player_if_exists_as_zombie(self, player: PlayerT) -> None: """ A utility method which calls self.spawn_player() *only* if the - ba.Player provided still exists; handy for use in timers and whatnot. + bs.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_zombie(player) - def spawn_player_zombie(self, player: PlayerType) -> ba.Actor: + def spawn_player_zombie(self, player: PlayerT) -> bs.Actor: position = self.map.get_ffa_start_position(self.players) angle = 20 name = player.getname() light_color = _math.normalized_color(player.color) - display_color = _ba.safecolor(player.color, target_intensity=0.75) + display_color = _babase.safecolor(player.color, target_intensity=0.75) spaz = PlayerSpaz_Zom(color=player.color, highlight=player.highlight, character='Kronk2', @@ -591,21 +594,21 @@ def spawn_player_zombie(self, player: PlayerType) -> ba.Actor: StandMessage( position, angle if angle is not None else random.uniform(0, 360))) - _ba.playsound(self._spawn_sound, 1, position=spaz.node.position) - light = _ba.newnode('light', attrs={'color': light_color}) + bs.Sound.play(self._spawn_sound, 1, position=spaz.node.position) + light = bs.newnode('light', attrs={'color': light_color}) spaz.node.connectattr('position', light, 'position') - ba.animate(light, 'intensity', {0: 0, 0.25: 1, 0.5: 0}) - _ba.timer(0.5, light.delete) + bs.animate(light, 'intensity', {0: 0, 0.25: 1, 0.5: 0}) + bs.timer(0.5, light.delete) if not self._solo_mode: - ba.timer(0.3, ba.Call(self._print_lives, player)) + bs.timer(0.3, babase.Call(self._print_lives, player)) for icon in player.icons: icon.handle_player_spawned() return spaz def _print_lives(self, player: Player) -> None: - from bastd.actor import popuptext + from bascenev1lib.actor import popuptext # We get called in a timer so it's possible our player has left/etc. if not player or not player.is_alive() or not player.node: @@ -642,13 +645,13 @@ def on_player_leave(self, player: Player) -> None: # Update icons in a moment since our team will be gone from the # list then. - ba.timer(0, self._update_icons) + bs.timer(0, self._update_icons) def _get_total_team_lives(self, team: Team) -> int: return sum(player.lives for player in team.players) def handlemessage(self, msg: Any) -> Any: - if isinstance(msg, ba.PlayerDiedMessage): + if isinstance(msg, bs.PlayerDiedMessage): # Augment standard behavior. super().handlemessage(msg) @@ -665,7 +668,7 @@ def handlemessage(self, msg: Any) -> Any: if msg._player in self.spazList: self.spazList.remove(msg._player) if player.lives < 0: - ba.print_error( + babase.print_error( "Got lives < 0 in Elim; this shouldn't happen. solo:" + str(self._solo_mode)) player.lives = 0 @@ -677,7 +680,7 @@ def handlemessage(self, msg: Any) -> Any: # Play big death sound on our last death # or for every one in solo mode. if self._solo_mode or player.lives == 0: - ba.playsound(SpazFactory.get().single_player_death_sound) + SpazFactory.get().single_player_death_sound.play() # If we hit zero lives, we're dead (and our team might be too). if player.lives == 0: @@ -732,16 +735,16 @@ def _update(self) -> None: theScores) and theScores.count(max(theScores)) > 1: pass else: - self._round_end_timer = ba.Timer(0.5, self.end_game) + self._round_end_timer = bs.Timer(0.5, self.end_game) else: - self._round_end_timer = ba.Timer(0.5, self.end_game) + self._round_end_timer = bs.Timer(0.5, self.end_game) def spawn_zombie(self) -> None: # We need a Z height... thePt = list(self.get_random_point_in_play()) thePt2 = self.map.get_ffa_start_position(self.players) thePt[1] = thePt2[1] - ba.timer(0.1, ba.Call( + bs.timer(0.1, babase.Call( self._bots.spawn_bot, BrawlerBot, pos=thePt, spawn_time=1.0)) def _onSpazBotDied(self, DeathMsg) -> None: @@ -816,25 +819,25 @@ def end_game(self) -> None: setattr(BrawlerBot, 'color', (0.6, 0.6, 0.6)) setattr(BrawlerBot, 'highlight', (0.6, 0.6, 0.6)) setattr(BrawlerBot, 'character', 'Kronk') - results = ba.GameResults() + results = bs.GameResults() self._vs_text = None # Kill our 'vs' if its there. for team in self.teams: results.set_team_score(team, team.score) self.end(results=results) -# ba_meta export game +# ba_meta export bascenev1.GameActivity class ZombieHordeCoop(ZombieHorde): name = 'Zombie Horde' @classmethod - def get_supported_maps(cls, sessiontype: type[ba.Session]) -> list[str]: + def get_supported_maps(cls, sessiontype: type[bs.Session]) -> list[str]: return ['Football Stadium'] @classmethod - def supports_session_type(cls, sessiontype: type[ba.Session]) -> bool: - return (issubclass(sessiontype, ba.CoopSession)) + def supports_session_type(cls, sessiontype: type[bs.Session]) -> bool: + return (issubclass(sessiontype, bs.CoopSession)) def _update(self) -> None: if self.zombieQ > 0: @@ -855,12 +858,12 @@ def _update(self) -> None: break if not any(player.is_alive() for player in self.teams[0].players): - self._round_end_timer = ba.Timer(0.5, self.end_game) + self._round_end_timer = bs.Timer(0.5, self.end_game) def handlemessage(self, msg: Any) -> Any: - if isinstance(msg, ba.PlayerDiedMessage): + if isinstance(msg, bs.PlayerDiedMessage): # Augment standard behavior. - ba.TeamGameActivity.handlemessage(self, msg) + bs.TeamGameActivity.handlemessage(self, msg) player: Player = msg.getplayer(Player) # If we have any icons, update their state. for icon in player.icons: @@ -870,10 +873,10 @@ def handlemessage(self, msg: Any) -> Any: # ba_meta export plugin -class ZombieHordeLevel(ba.Plugin): +class ZombieHordeLevel(babase.Plugin): def on_app_running(self) -> None: - ba.app.add_coop_practice_level( - ba.Level( + babase.app.classic.add_coop_practice_level( + bs._level.Level( 'Zombie Horde', gametype=ZombieHordeCoop, settings={}, diff --git a/plugins/utilities/discord_richpresence.py b/plugins/utilities/discord_richpresence.py index 3028e649..2a748702 100644 --- a/plugins/utilities/discord_richpresence.py +++ b/plugins/utilities/discord_richpresence.py @@ -27,7 +27,7 @@ import bascenev1 as bs import bascenev1lib import bauiv1 as bui -from baenv import TARGET_BALLISTICA_BUILD +from baenv import TARGET_BALLISTICA_BUILD as build_number from typing import TYPE_CHECKING @@ -37,8 +37,8 @@ ANDROID = babase.app.classic.platform == "android" DIRPATH = Path( - f"{_babase.app.python_directory_user if TARGET_BALLISTICA_BUILD < 21282 else _babase.app.env.python_directory_user}/image_id.json") -APP_VERSION = _babase.app.version if TARGET_BALLISTICA_BUILD < 21282 else _babase.app.env.version + f"{_babase.app.python_directory_user if build_number < 21282 else _babase.app.env.python_directory_user}/image_id.json") +APP_VERSION = _babase.app.version if build_number < 21282 else _babase.app.env.version if ANDROID: # !can add ios in future diff --git a/plugins/utilities/ragdoll_b_gone.py b/plugins/utilities/ragdoll_b_gone.py index 6f229fc6..3bd5e8be 100644 --- a/plugins/utilities/ragdoll_b_gone.py +++ b/plugins/utilities/ragdoll_b_gone.py @@ -98,7 +98,7 @@ def wrapper(*args, **kwargs): # Pick a random death noise sound = death_sounds[random.randrange(len(death_sounds))] # Play the sound where our Spaz is - sound.play(position=args[0].node.position) + bs.Sound.play(sound, position=args[0].node.position) # Delete our Spaz node immediately. # Removing stuff is weird and prone to errors, so we're gonna delay it. bs.timer(0.001, args[0].node.delete) From d2e9830d8c3ebee3d7a8efba94265493bdc5ceef Mon Sep 17 00:00:00 2001 From: brostos <67740566+brostosjoined@users.noreply.github.com> Date: Wed, 17 Jan 2024 23:12:07 +0300 Subject: [PATCH 0800/1464] Delete plugins/minigames/port_7_to_8.py --- plugins/minigames/port_7_to_8.py | 441 ------------------------------- 1 file changed, 441 deletions(-) delete mode 100644 plugins/minigames/port_7_to_8.py diff --git a/plugins/minigames/port_7_to_8.py b/plugins/minigames/port_7_to_8.py deleted file mode 100644 index 1a8c94e4..00000000 --- a/plugins/minigames/port_7_to_8.py +++ /dev/null @@ -1,441 +0,0 @@ -# Usage: port_7_to_8.py - -# You'll have to manually update the following: -# with ba.Context(_ba.foreground_host_activity()): -# To: -# with _ba.foreground_host_activity().context: -# -# ba.time(timeformat=ba.TimeFormat.MILLISECONDS) -# To: -# ba.time() * 1000 -# -# ba.Timer((POWERUP_WEAR_OFF_TIME - 2000),ba.WeakCall(self._multi_bomb_wear_off_flash),timeformat=ba.TimeFormat.MILLISECONDS) -# To: -# ba.Timer((POWERUP_WEAR_OFF_TIME - 2000 / 1000),ba.WeakCall(self._multi_bomb_wear_off_flash)) - -import re -import sys -import codecs - -def detect_encoding(filename): - encodings = ['utf-8', 'latin-1', 'ascii', 'cp1252'] - for encoding in encodings: - try: - with open(filename, 'rb') as f: - f.read().decode(encoding) - return encoding - except UnicodeDecodeError: - pass - return None - -filename = sys.argv[2] -encoding = detect_encoding(filename) -if encoding: - with open(filename, 'r', encoding=encoding) as f: - print("Porting "+ sys.argv[2]) - content = f.read() -else: - print('Could not detect encoding') - -content = content.replace("# ba_meta require api 7", "# ba_meta require api 8") -content = content.replace("# ba_meta export game", "# ba_meta export bascenev1.GameActivity") - - -content = content.replace("user_agent_string", "legacy_user_agent_string") -content = re.sub(r'^(import\s+[\w]+(\s*,\s*[\w]+)+)', lambda match: re.sub(r'\s*,\s*', '\nimport ', match.group()), content, flags=re.MULTILINE) -content = content.replace("_ba.", "_babase.") -content = content.replace("_ba.", "_babase.") -content = content.replace("ba.", "babase.") -content = content.replace("import _ba", "import _babase") -content = content.replace("from ba import", "from babase import") -content = content.replace("from _ba import", "from _babase import") -content = re.sub(r'\bimport _ba\b', "import _babase", content) -content = re.sub(r'\bimport ba(\b|\.(\w+))', "import babase\nimport bauiv1\nimport bascenev1", content) -match = re.search(r'^(import\s+[\w]+(\s*,\s*[\w]+)*)', content, flags=re.MULTILINE) -affected_methods = ["build_number", "device_name", "config_file_path", "version", "debug_build", "test_build", "data_directory", "python_directory_user", "python_directory_app", "python_directory_app_site", "api_version", "on_tv", "vr_mode","toolbar_test", "arcade_test", "headless_mode", "demo_mode", "protocol_version", "get_connection_to_host_info"] -for word in affected_methods: - if f".{word}" in content: - first_import_index = match.start() - content = content[:first_import_index] + 'from baenv import TARGET_BALLISTICA_BUILD as build_number\n' + content[first_import_index:] -content = content.replace("babase.app.ui", "bauiv1.app.ui_v1") -content = content.replace("babase.app.accounts_v1", "bauiv1.app.classic.accounts") - -################################################################################### -# Comment out one of these as per your requirements, depending whether to -# stay local or if it'll also be needed to transmitted to the clients. - -## For local: -if sys.argv[1] == "client": - content = content.replace("_babase.screenmessage", "bauiv1.screenmessage") - content = content.replace("babase.screenmessage", "bauiv1.screenmessage") - content = content.replace("babase.getsound", "bauiv1.getsound") - content = content.replace("_babase.gettexture", "bauiv1.gettexture") - content = content.replace("babase.gettexture", "bauiv1.gettexture") - content = content.replace("babase.getmesh", "bauiv1.getmesh") - content = content.replace("babase.getcollisionmesh", "bauiv1.getcollisionmesh") -else: -## For transmission: - content = content.replace("_babase.screenmessage", "bascenev1.broadcastmessage") - content = content.replace("babase.screenmessage", "bascenev1.broadcastmessage") - content = content.replace("babase.getsound", "bascenev1.getsound") - content = content.replace("_babase.gettexture", "bascenev1.gettexture") - content = content.replace("babase.gettexture", "bascenev1.gettexture") - content = content.replace("babase.getmesh", "bascenev1.getmesh") - content = content.replace("babase.getcollisionmesh", "bascenev1.getcollisionmesh") -################################################################################### -content = content.replace("babase.getcollidemesh", "bascenev1.getcollisionmesh") -content = content.replace("collide_mesh", "collision_mesh") -content = content.replace("babase.open_url", "bauiv1.open_url") -content = content.replace("babase.IntSetting", "bascenev1.IntSetting") -content = content.replace("babase.IntChoiceSetting", "bascenev1.IntChoiceSetting") -content = content.replace("babase.FloatChoiceSetting", "bascenev1.FloatChoiceSetting") -content = content.replace("babase.BoolSetting", "bascenev1.BoolSetting") -content = content.replace("babase.Actor", "bascenev1.Actor") -content = content.replace("babase.Player", "bascenev1.Player") -content = content.replace("babase.PlayerDiedMessage", "bascenev1.PlayerDiedMessage") -content = content.replace("babase.time", "bascenev1.time") -content = content.replace("babase.Timer", "bascenev1.Timer") -content = content.replace("babase.newnode", "bascenev1.newnode") -content = content.replace("babase.Node", "bascenev1.Node") -content = content.replace("babase.emitfx", "bascenev1.emitfx") -content = content.replace("babase.animate", "bascenev1.animate") -content = content.replace("babase.FreeForAllSession", "bascenev1.FreeForAllSession") -content = content.replace("babase.DualTeamSession", "bascenev1.DualTeamSession") -content = content.replace("babase.MultiTeamSession", "bascenev1.MultiTeamSession") -content = content.replace("babase.EndSession", "bascenev1.EndSession") -content = content.replace("babase.CoopSession", "bascenev1.CoopSession") -content = content.replace("babase.TeamGameActivity", "bascenev1.TeamGameActivity") -content = content.replace("babase.Team", "bascenev1.Team") -content = content.replace("babase.Session", "bascenev1.Session") -content = content.replace("babase.getsession", "bascenev1.getsession") -content = content.replace("babase.Material", "bascenev1.Material") -content = content.replace("babase.WeakCall", "bascenev1.WeakCall") -content = content.replace("babase.DieMessage", "bascenev1.DieMessage") -content = content.replace("babase.OutOfBoundsMessage", "bascenev1.OutOfBoundsMessage") -content = content.replace("babase.DroppedMessage", "bascenev1.DroppedMessage") -content = content.replace("babase.HitMessage", "bascenev1.HitMessage") -content = content.replace("babase.ThawMessage", "bascenev1.ThawMessage") -content = content.replace("babase.NotFoundError", "bascenev1.NotFoundError") -content = content.replace("babase.getcollision", "bascenev1.getcollision") -content = content.replace("babase.app.lang", "bascenev1.app.lang") -content = content.replace("babase.MusicType", "bascenev1.MusicType") -content = content.replace("babase.getactivity", "bascenev1.getactivity") -content = content.replace("babase.getactivity", "bascenev1.getactivity") -content = content.replace("babase.CelebrateMessage", "bascenev1.CelebrateMessage") -content = content.replace("babase.ScoreConfig", "bascenev1.ScoreConfig") -content = content.replace("babase.ScoreType", "bascenev1.ScoreType") -content = content.replace("babase.GameResults", "bascenev1.GameResults") -content = content.replace("babase.getmaps", "bascenev1.app.classic.getmaps") -content = content.replace("babase.cameraflash", "bascenev1.cameraflash") -content = content.replace("babase.getmodel", "bascenev1.getmesh") -content = content.replace("babase.Map", "bascenev1.Map") -content = content.replace("babase.DeathType", "bascenev1.DeathType") -content = content.replace("babase.GameActivity", "bascenev1.GameActivity") -content = content.replace("_babase.app.stress_test_reset_timer", "_babase.app.classic.stress_test_reset_timer") -content = content.replace("babase.app.stress_test_reset_timer", "_babase.app.classic.stress_test_reset_timer") -content = content.replace("babase._map", "bascenev1._map") -content = content.replace("babase._session.", "bascenev1._session.") -content = content.replace("babase._activity", "bascenev1._activity") -content = content.replace("_babase.get_client_public_device_uuid", "_bascenev1.get_client_public_device_uuid") -content = content.replace("babase.PickedUpMessage", "bascenev1.PickedUpMessage") -content = content.replace("babase.PowerupMessage", "bascenev1.PowerupMessage") -content = content.replace("babase.FreezeMessage", "bascenev1.FreezeMessage") -content = content.replace("with babase.ContextRef(activity):", "with activity.context:") -content = content.replace("babase.Context", "babase.ContextRef") -content = content.replace("babase._dualteamsession", "bascenev1._dualteamsession") -content = content.replace("babase._freeforallsession", "bascenev1._freeforallsession") -content = content.replace("babase._multiteamsession", "bascenev1._multiteamsession") -content = content.replace("babase._gameactivity", "bascenev1._gameactivity") -content = content.replace("babase._powerup", "bascenev1._powerup") -content = content.replace("babase.Chooser", "bascenev1.Chooser") -content = content.replace("babase._lobby", "bascenev1._lobby") -content = content.replace("babase._stats", "bascenev1._stats") -content = content.replace("babase._team", "bascenev1._team") -content = content.replace("PlayerType", "PlayerT") -content = content.replace("babase.app.spaz_appearances", "babase.app.classic.spaz_appearances") -content = content.replace("babase._coopsession", "bascenev1._coopsession") -content = content.replace("babase._servermode", "baclassic._servermode") -content = content.replace("_babase.app.server", "babase.app.classic.server") -content = content.replace("_babase.chatmessage", "bascenev1.chatmessage") -content = content.replace("_babase.disconnect_client", "_bascenev1.disconnect_client") -content = content.replace("_babase.get_game_roster", "bascenev1.get_game_roster") -content = content.replace("_babase.get_public_party_max_size", "bascenev1.get_public_party_max_size") -content = content.replace("_babase.new_host_session", "bascenev1.new_host_session") -content = content.replace("babase._playlist", "bascenev1._playlist") -content = content.replace("model", "mesh") -content = content.replace("TimeType.REAL", "use `bascenev1.apptimer` in `activity.context` instead") -content = content.replace("_babase.app.coop_session_args", "babase.app.classic.coop_session_args") -content = content.replace("_babase.app.campaigns", "babase.app.classic.campaigns") - -content = content.replace("_babase.newactivity", "bascenev1.newactivity") -content = content.replace("babase.Window", "bauiv1.Window") -content = content.replace("babase.Widget", "bauiv1.Widget") -content = content.replace("babase.widget", "bauiv1.widget") -content = content.replace("babase.containerwidget", "bauiv1.containerwidget") -content = content.replace("babase.scrollwidget", "bauiv1.scrollwidget") -content = content.replace("babase.buttonwidget", "bauiv1.buttonwidget") -content = content.replace("babase.textwidget", "bauiv1.textwidget") -content = content.replace("babase.checkboxwidget", "bauiv1.checkboxwidget") -content = content.replace("babase.imagewidget", "bauiv1.imagewidget") -content = content.replace("babase.uicleanupcheck", "bauiv1.uicleanupcheck") -content = content.replace("_babase.set_public_party_max_size", "bascenev1.set_public_party_max_size") -content = content.replace("_bauiv1", "bauiv1") -content = content.replace("babase.show_damage_count", "bascenev1.show_damage_count") -content = content.replace("babase._gameutils", "bascenev1._gameutils") -content = content.replace("babase.StandMessage", "bascenev1.StandMessage") -content = content.replace("babase.PowerupAcceptMessage", "bascenev1.PowerupAcceptMessage") -content = content.replace("babase._gameutils", "bascenev1._gameutils") -content = content.replace("babase.camerashake", "bascenev1.camerashake") -content = content.replace("babase.app.add_coop_practice_level", "babase.app.classic.add_coop_practice_level") -content = content.replace("babase._campaign", "bascenev1._campaign") -content = content.replace("babase.Level", "bascenev1._level.Level") -content = content.replace("babase.app.cloud.send_message_cb", "bauiv1.app.plus.cloud.send_message_cb") -content = content.replace("_babase.get_special_widget", "bauiv1.get_special_widget") - -content = content.replace(".app.platform", ".app.classic.platform") -content = content.replace(".app.subplatform", ".app.classic.subplatform") -content = content.replace(".getlog", ".get_v1_cloud_log") -# Converting `ba.playsound(abc)` to `abc.play()` is tricky. -# Do it manually in case regex substitution fails.# Do it manually in case regex substitution fails. Are you sure!! -#! FIXME May cause syntax warning on 3.12 -content = re.sub( - r'babase\.playsound\(\s*([^,\n]+),\s*([^,\n]+)\)', - r'\1.play(\2)', - content, - flags=re.MULTILINE -) -content = re.sub( - r'babase\.playsound\(\s*([^,\n]+),\s*([^,\n]+),\s*position=([^,\n]+)\)', - r'\1.play(\2, position=\3)', - content, - flags=re.MULTILINE -) -content = re.sub("babase\.playsound\((.+?), (.+?), (.+?)\)", "\\1.play(\\2, \\3)", content) -content = re.sub( - r'babase\.playsound\(([^,\n]+),\s*position=([^,\n]+)\)', - r'\1.play(position=\2)', - content -) -content = re.sub("babase\.playsound\((.*)\)", "\\1.play()", content) - -content = content.replace("babase.internal.add_transaction", "bauiv1.app.plus.add_v1_account_transaction") -content = content.replace("babase.internal.run_transaction", "bauiv1.app.plus.run_v1_account_transaction") -content = content.replace("_babase.add_transaction", "bauiv1.app.plus.add_v1_account_transaction") -content = content.replace("_babase.run_transactions", "bauiv1.app.plus.run_v1_account_transactions") -content = content.replace("babase._store.get_store_layout", "bauiv1.app.classic.store.get_store_layout") -content = content.replace("babase.internal.get_store_layout", "bauiv1.app.classic.store.get_store_layout") -content = content.replace("babase.internal.connect_to_party", "bascenev1.connect_to_party") -content = content.replace("babase.internal.get_default_powerup_distribution", "bascenev1._powerup.get_default_powerup_distribution") -content = content.replace("babase.internal.DEFAULT_REQUEST_TIMEOUT_SECONDS", "babase.DEFAULT_REQUEST_TIMEOUT_SECONDS") -content = content.replace("babase.internal.DEFAULT_TEAM_COLORS", "bascenev1.DEFAULT_TEAM_COLORS") -content = content.replace("babase.internal.DEFAULT_TEAM_NAMES", "bascenev1.DEFAULT_TEAM_NAMES") -content = content.replace("babase.internal.JoinActivity", "bascenev1.JoinActivity") -content = content.replace("babase.internal.LoginAdapter", "babase._login.LoginAdapter") -content = content.replace("babase.internal.PlayerProfilesChangedMessage", "bascenev1._messages.PlayerProfilesChangedMessage") -content = content.replace("babase.internal.ScoreScreenActivity", "bascenev1.ScoreScreenActivity") -content = content.replace("babase.internal.add_clean_frame_callback", "babase.add_clean_frame_callback") -content = content.replace("babase.internal.android_get_external_files_dir", "babase.android_get_external_files_dir") -content = content.replace("babase.internal.appname", "babase.appname") -content = content.replace("babase.internal.appnameupper", "babase.appnameupper") -content = content.replace("babase.internal.capture_gamepad_input", "bascenev1.capture_gamepad_input") -content = content.replace("babase.internal.capture_keyboard_input", "bascenev1.capture_keyboard_input") -content = content.replace("babase.internal.charstr", "babase.charstr") -content = content.replace("babase.internal.chatmessage", "bascenev1.chatmessage") -content = content.replace("babase.internal.commit_app_config", "bauiv1.commit_app_config") -content = content.replace("babase.internal.disconnect_client", "bascenev1.disconnect_client") -content = content.replace("babase.internal.disconnect_from_host", "bascenev1.disconnect_from_host") -content = content.replace("babase.internal.do_play_music", "babase.app.classic.music.do_play_music") -content = content.replace("babase.internal.end_host_scanning", "bascenev1.end_host_scanning") -content = content.replace("babase.internal.fade_screen", "bauiv1.fade_screen") -content = content.replace("babase.internal.filter_playlist", "bascenev1.filter_playlist") -content = content.replace("babase.internal.game_service_has_leaderboard", "_baplus.game_service_has_leaderboard") -content = content.replace("babase.internal.get_available_purchase_count", "bauiv1.app.classic.store.get_available_purchase_count") -content = content.replace("babase.internal.get_available_sale_time", "bauiv1.app.classic.store.get_available_sale_time") -content = content.replace("babase.internal.get_chat_messages", "bascenev1.get_chat_messages") -content = content.replace("babase.internal.get_clean_price", "bauiv1.app.classic.store.get_clean_price") -content = content.replace("babase.internal.get_connection_to_host_info", "bascenev1.get_connection_to_host_info_2") -content = content.replace("babase.internal.get_default_free_for_all_playlist", "bascenev1._playlist.get_default_free_for_all_playlist") -content = content.replace("babase.internal.get_default_teams_playlist", "bascenev1._playlist.get_default_teams_playlist") -content = content.replace("babase.internal.get_display_resolution", "babase.get_display_resolution") -content = content.replace("babase.internal.get_filtered_map_name", "bascenev1._map.get_filtered_map_name") -content = content.replace("babase.internal.get_foreground_host_session", "bascenev1.get_foreground_host_session") -content = content.replace("babase.internal.get_game_port", "bascenev1.get_game_port") -content = content.replace("babase.internal.get_game_roster", "bascenev1.get_game_roster") -content = content.replace("babase.internal.get_input_device_config", "bauiv1.app.classic.get_input_device_config") -content = content.replace("babase.internal.get_ip_address_type", "babase.get_ip_address_type") -content = content.replace("babase.internal.get_local_active_input_devices_count", "bascenev1.get_local_active_input_devices_count") -content = content.replace("babase.internal.get_low_level_config_value", "bauiv1.get_low_level_config_value") -content = content.replace("babase.internal.get_map_class", "bascenev1.get_map_class") -content = content.replace("babase.internal.get_map_display_string", "bascenev1.get_map_display_string") -content = content.replace("babase.internal.get_master_server_address", "bauiv1.app.plus.get_master_server_address") -content = content.replace("babase.internal.get_max_graphics_quality", "babase.get_max_graphics_quality") -content = content.replace("babase.internal.get_news_show", "_babase.app.plus.get_news_show") -content = content.replace("babase.internal.get_next_tip", "bascenev1.app.classic.get_next_tip") -content = content.replace("babase.internal.get_player_colors", "bascenev1.get_player_colors") -content = content.replace("babase.internal.get_player_profile_colors", "bascenev1.get_player_profile_colors") -content = content.replace("babase.internal.get_player_profile_icon", "bascenev1.get_player_profile_icon") -content = content.replace("babase.internal.get_price", "bauiv1.app.plus.get_price") -content = content.replace("babase.internal.get_public_party_enabled", "bascenev1.get_public_party_enabled") -content = content.replace("babase.internal.get_public_party_max_size", "bascenev1.get_public_party_max_size") -content = content.replace("babase.internal.get_purchased", "bauiv1.app.plus.get_purchased") -content = content.replace("babase.internal.get_purchases_state", "_baplus.get_purchases_state") -content = content.replace("babase.internal.get_qrcode_texture", "bauiv1.get_qrcode_texture") -content = content.replace("babase.internal.get_random_names", "bascenev1.get_random_names") -content = content.replace("babase.internal.get_remote_app_name", "bascenev1.get_remote_app_name") -content = content.replace("babase.internal.get_replay_speed_exponent", "bascenev1.get_replay_speed_exponent") -content = content.replace("babase.internal.get_replays_dir", "babase.get_replays_dir") -content = content.replace("babase.internal.get_special_widget", "bauiv1.get_special_widget") -content = content.replace("babase.internal.get_store_item", "babase.app.classic.store.get_store_item") -content = content.replace("babase.internal.get_store_item_display_size", "babase.app.classic.store.get_store_item_display_size") -content = content.replace("babase.internal.get_store_item_name_translated", "babase.app.classic.store.get_store_item_name_translated") -content = content.replace("babase.internal.get_string_height", "babase.get_string_height") -content = content.replace("babase.internal.get_string_width", "babase.get_string_width") -content = content.replace("babase.internal.get_tournament_prize_strings", "bascenev1.app.classic.get_tournament_prize_strings") -content = content.replace("babase.internal.get_trophy_string", "bascenev1.get_trophy_string") -content = content.replace("babase.internal.get_type_name", "babase.get_type_name") -content = content.replace("babase.internal.get_ui_input_device", "bascenev1.get_ui_input_device") -content = content.replace("babase.internal.get_unowned_game_types", "babase.app.classic.store.get_unowned_game_types") -content = content.replace("babase.internal.get_unowned_maps", "babase.app.classic.store.get_unowned_maps") -content = content.replace("babase.internal.get_v1_account_display_string", "bauiv1.app.plus.get_v1_account_display_string") -content = content.replace("babase.internal.get_v1_account_misc_read_val", "bauiv1.app.plus.get_v1_account_misc_read_val") -content = content.replace("babase.internal.get_v1_account_misc_read_val_2", "bauiv1.app.plus.get_v1_account_misc_read_val_2") -content = content.replace("babase.internal.get_v1_account_misc_val", "bauiv1.app.plus.get_v1_account_misc_val") -content = content.replace("babase.internal.get_v1_account_name", "bauiv1.app.plus.get_v1_account_name") -content = content.replace("babase.internal.get_v1_account_state", "bauiv1.app.plus.get_v1_account_state") -content = content.replace("babase.internal.get_v1_account_state_num", "bauiv1.app.plus.get_v1_account_state_num") -content = content.replace("babase.internal.get_v1_account_ticket_count", "bauiv1.app.plus.get_v1_account_ticket_count") -content = content.replace("babase.internal.get_v1_account_type", "bauiv1.app.plus.get_v1_account_type") -content = content.replace("babase.internal.get_v2_fleet", "_baplus.get_v2_fleet") -content = content.replace("babase.internal.getcampaign", "bauiv1.app.classic.getcampaign") -content = content.replace("babase.internal.getclass", "babase.getclass") -content = content.replace("babase.internal.getinputdevice", "bascenev1.getinputdevice") -content = content.replace("babase.internal.has_gamma_control", "babase.has_gamma_control") -content = content.replace("babase.internal.has_video_ads", "bauiv1.has_video_ads") -content = content.replace("babase.internal.have_incentivized_ad", "bauiv1.have_incentivized_ad") -content = content.replace("babase.internal.have_permission", "babase.have_permission") -content = content.replace("babase.internal.have_touchscreen_input", "bascenev1.have_touchscreen_input") -content = content.replace("babase.internal.host_scan_cycle", "bascenev1.host_scan_cycle") -content = content.replace("babase.internal.in_game_purchase", "bui.app.plus.in_game_purchase") -content = content.replace("babase.internal.increment_analytics_count", "babase.increment_analytics_count") -content = content.replace("babase.internal.is_blessed", "bui.app.plus.is_blessed") -content = content.replace("babase.internal.is_browser_likely_available", "bauiv1.is_browser_likely_available") -content = content.replace("babase.internal.is_in_replay", "bascenev1.is_in_replay") -content = content.replace("babase.internal.is_party_icon_visible", "bauiv1.is_party_icon_visible") -content = content.replace("babase.internal.is_running_on_fire_tv", "babase.is_running_on_fire_tv") -content = content.replace("babase.internal.is_xcode_build", "babase.is_xcode_build") -content = content.replace("babase.internal.json_prep", "babase.json_prep") -content = content.replace("babase.internal.lock_all_input", "babase.lock_all_input") -content = content.replace("babase.internal.mark_config_dirty", "_babase.app.plus.mark_config_dirty") -content = content.replace("babase.internal.new_host_session", "bascenev1.new_host_session") -content = content.replace("babase.internal.new_replay_session", "bascenev1.new_replay_session") -content = content.replace("babase.internal.open_file_externally", "bauiv1.open_file_externally") -content = content.replace("babase.internal.power_ranking_query", "_baplus.power_ranking_query") -content = content.replace("babase.internal.preload_map_preview_media", "bauiv1.app.classic.preload_map_preview_media") -content = content.replace("babase.internal.purchase", "_baplus.purchase") -content = content.replace("babase.internal.register_map", "bascenev1.register_map") -content = content.replace("babase.internal.release_gamepad_input", "bascenev1.release_gamepad_input") -content = content.replace("babase.internal.release_keyboard_input", "bascenev1.release_keyboard_input") -content = content.replace("babase.internal.report_achievement", "babase.app.plus.report_achievement") -content = content.replace("babase.internal.request_permission", "babase.request_permission") -content = content.replace("babase.internal.reset_achievements", "_baplus.reset_achievements") -content = content.replace("babase.internal.reset_random_player_names", "bascenev1.reset_random_player_names") -content = content.replace("babase.internal.restore_purchases", "_baplus.restore_purchases") -content = content.replace("babase.internal.run_cpu_benchmark", "baclassic._benchmark.run_cpu_benchmark") -content = content.replace("babase.internal.run_gpu_benchmark", "baclassic._benchmark.run_gpu_benchmark") -content = content.replace("babase.internal.run_media_reload_benchmark", "baclassic._benchmark.run_media_reload_benchmark") -content = content.replace("babase.internal.run_stress_test", "babase.app.classic.run_stress_test") -content = content.replace("babase.internal.set_authenticate_clients", "bascenev1.set_authenticate_clients") -content = content.replace("babase.internal.set_debug_speed_exponent", "bascenev1.set_debug_speed_exponent") -content = content.replace("babase.internal.set_low_level_config_value", "babase.set_low_level_config_value") -content = content.replace("babase.internal.set_party_icon_always_visible", "bauiv1.set_party_icon_always_visible") -content = content.replace("babase.internal.set_party_window_open", "bauiv1.set_party_window_open") -content = content.replace("babase.internal.set_public_party_enabled", "bascenev1.set_public_party_enabled") -content = content.replace("babase.internal.set_public_party_max_size", "bascenev1.set_public_party_max_size") -content = content.replace("babase.internal.set_public_party_name", "bascenev1.set_public_party_name") -content = content.replace("babase.internal.set_public_party_queue_enabled", "bascenev1.set_public_party_queue_enabled") -content = content.replace("babase.internal.set_replay_speed_exponent", "bascenev1.set_replay_speed_exponent") -content = content.replace("babase.internal.set_touchscreen_editing", "bascenev1.set_touchscreen_editing") -content = content.replace("babase.internal.set_ui_input_device", "babase.set_ui_input_device") -content = content.replace("babase.internal.should_submit_debug_info", "babase._apputils.should_submit_debug_info") -content = content.replace("babase.internal.show_online_score_ui", "bauiv1.show_online_score_ui") -content = content.replace("babase.internal.sign_in_v1", "babase.app.plus.sign_in_v1") -content = content.replace("babase.internal.sign_out_v1", "babase.app.plus.sign_out_v1") -content = content.replace("babase.internal.submit_score", "bascenev1.app.plus.submit_score") -content = content.replace("babase.internal.tournament_query", "_baplus.tournament_query") -content = content.replace("babase.internal.unlock_all_input", "babase.unlock_all_input") -content = content.replace("babase.internal.value_test", "bauiv1.app.classic.value_test") -content = content.replace("babase.internal.workspaces_in_use", "babase.workspaces_in_use") -content = content.replace("babase.internal.dump_tracebacks", "babase._apputils.dump_app_state") -content = content.replace("babase.internal.show_app_invite", "_bauiv1.show_app_invite") -content = content.replace("babase._generated", "babase._mgen") -content = content.replace("_babase.disconnect_from_host", "bascenev1.disconnect_from_host") -content = content.replace("babase.disconnect_from_host", "bascenev1.disconnect_from_host") -content = content.replace("_babase.connect_to_party", "bascenev1.connect_to_party") -content = content.replace("babase.connect_to_party", "bascenev1.connect_to_party") -content = content.replace("babase.set_party_window_open", "bauiv1.set_party_window_open") -content = content.replace("babase.set_party_window_open", "bauiv1.set_party_window_open") -content = content.replace("babase.getcollidemesh", "bascenev1.getcollisionmesh") -content = content.replace("collide_mesh", "collision_mesh") -content = content.replace("babase.FloatSetting", "bascenev1.FloatSetting") -# Removed in API 8: -# content = content.replace("babase.internal.set_telnet_access_enabled", "") - -content = content.replace("babase.internal.master_server_get", "babase.app.classic.master_server_v1_get") -content = content.replace("babase.internal.master_server_post", "babase.app.classic.master_server_v1_post") -content = content.replace("babase.internal.log_dumped_tracebacks", "babase._apputils.log_dumped_app_state") -content = content.replace("babase.internal.have_outstanding_transactions", "bauiv1.app.plus.have_outstanding_v1_account_transactions") -content = content.replace("babase.internal.get_public_login_id", "bauiv1.app.plus.get_v1_account_public_login_id") -content = content.replace("babase.internal.get_input_map_hash", "bauiv1.app.classic.get_input_device_map_hash") -content = content.replace("babase.internal.get_device_value", "bauiv1.app.classic.get_input_device_mapped_value") - -# Depracations -content = content.replace("babase.app.build_number", "babase.app.build_number if build_number < 21282 else babase.app.env.build_number") -content = content.replace("babase.app.device_name", "babase.app.device_name if build_number < 21282 else babase.app.env.device_name") -content = content.replace("babase.app.config_file_path", "babase.app.config_file_path if build_number < 21282 else babase.app.env.config_file_path") -content = content.replace("babase.app.version", "babase.app.version if build_number < 21282 else babase.app.env") -content = content.replace("babase.app.debug_build", "babase.app.debug_build if build_number < 21282 else babase.app.env.debug_build") -content = content.replace("babase.app.test_build", "babase.app.test_build if build_number < 21282 else babase.app.env.test_build") -content = content.replace("babase.app.data_directory", "babase.app.data_directory if build_number < 21282 else babase.app.env.data_directory") -content = content.replace("babase.app.python_directory_user", "babase.app.python_directory_user if build_number < 21282 else babase.app.env.python_directory_user") -content = content.replace("babase.app.python_directory_app", "babase.app.env") -content = content.replace("babase.app.python_directory_app_site", "babase.app.python_directory_app_site if build_number < 21282 else babase.app.env.python_directory_app_site") -content = content.replace("babase.app.api_version", "babase.app.api_version if build_number < 21282 else babase.app.env.api_version") -content = content.replace("babase.app.on_tv", "babase.app.on_tv if build_number < 21282 else babase.app.env.on_tv") -content = content.replace("babase.app.vr_mode", "babase.app.vr_mode if build_number < 21282 else babase.app.env.vr") -content = content.replace("babase.app.toolbar_test", "babase.app.toolbar_test if build_number < 21282 else babase.app.env.toolbar_test") -content = content.replace("babase.app.arcade_mode", "babase.app.arcade_mode if build_number < 21282 else babase.app.env.arcade_mode") -content = content.replace("babase.app.headless_mode", "babase.app.headless_mode if build_number < 21282 else babase.app.env.headless_mode") -content = content.replace("babase.app.demo_mode", "babase.app.demo_mode if build_number < 21282 else babase.app.env.demo_mode") -content = content.replace("babase.app.protocol_version", "babase.app.protocol_version if build_number < 21282 else babase.app.env.protocol_version") -content = content.replace("bascenev1.get_connection_to_host_info", "bascenev1.get_connection_to_host_info if build_number < 21697 else bascenev1.get_connection_to_host_info_2") - -content = content.replace("babase._store", "bauiv1.app.classic.store") -# content = content.replace("babase.internal", "") -content = content.replace("bastd.ui", "bauiv1lib") -content = content.replace("bastd", "bascenev1lib") -content = content.replace("timetype=","") -content = content.replace("babase.columnwidget", "bauiv1.columnwidget") -content = content.replace("_babase.get_game_port", "bascenev1.get_game_port") -content = content.replace("_babase.get_chat_messages", "bascenev1.get_chat_messages") -content = content.replace("_babase.get_foreground_host_session", "bascenev1.get_foreground_host_session") -content = content.replace("_babase.get_foreground_host_activity", "bascenev1.get_foreground_host_activity") -content = content.replace("bascenev1.SessionPlayerNotFoundError", "babase.SessionPlayerNotFoundError") -content = content.replace("bascenev1", "bs") -content = content.replace("bauiv1", "bui") -content = content.replace("import bs", "import bascenev1 as bs") -content = content.replace("import bui", "import bauiv1 as bui") -content = content.replace("bslib", "bascenev1lib") -content = content.replace("builib", "bauiv1lib") -content = content.replace("from bs.", "from bascenev1.") -content = content.replace("from bui.", "from bauiv1.") -content = content.replace("import bascenev1 as bascenev1lib", "import bascenev1lib") -content = content.replace("import bauiv1 as bauiv1lib", "import bauiv1lib") -content = content.replace("# ba_meta export bs.GameActivity", "# ba_meta export bascenev1.GameActivity") -content = content.replace("_bs", "bs") - -content = re.sub(r'bs\.Timer\(([^)]*)\bTimeType\.REAL\b([^)]*)\)', r'babase.AppTimer(\1\2)', content) -trademark = "# Porting to api 8 made easier by baport.(https://github.com/bombsquad-community/baport)\n" -with open(sys.argv[2], "w", encoding=encoding) as f: - f.write(trademark + content) - - From 87b302a50f3802edcb72331aaf9c546fae5e9c70 Mon Sep 17 00:00:00 2001 From: brostosjoined Date: Thu, 18 Jan 2024 13:41:11 +0000 Subject: [PATCH 0801/1464] [ci] auto-format --- plugins/minigames/drone_war.py | 3 +- plugins/minigames/hot_potato.py | 6 +- plugins/minigames/simon_says.py | 6 +- plugins/minigames/sleep_race.py | 8 +- plugins/minigames/squid_race.py | 10 +- plugins/minigames/ufo_fight.py | 39 +- plugins/minigames/ultimate_last_stand.py | 10 +- plugins/minigames/zombie_horde.py | 4 +- plugins/utilities/auto_stunt.py | 3 +- plugins/utilities/chat_cmd.py | 13 +- plugins/utilities/disco_light.py | 62 +- plugins/utilities/discord_richpresence.py | 10 +- plugins/utilities/max_players.py | 2 +- plugins/utilities/mood_light.py | 28 +- plugins/utilities/quick_custom_game.py | 100 +- plugins/utilities/quickturn.py | 3 +- plugins/utilities/ragdoll_b_gone.py | 3 +- plugins/utilities/random_join.py | 16 +- plugins/utilities/tnt_respawn_text.py | 6 +- plugins/utilities/ultra_party_window.py | 1036 +++++++++++---------- 20 files changed, 693 insertions(+), 675 deletions(-) diff --git a/plugins/minigames/drone_war.py b/plugins/minigames/drone_war.py index 21eafb1a..6dcd5c32 100644 --- a/plugins/minigames/drone_war.py +++ b/plugins/minigames/drone_war.py @@ -282,7 +282,8 @@ def shot(self, spaz, x, z, position) -> None: direction = [x, 0, z] direction[1] = 0.0 - mag = 10.0 / 1 if babase.Vec3(*direction).length() == 0 else babase.Vec3(*direction).length() + mag = 10.0 / \ + 1 if babase.Vec3(*direction).length() == 0 else babase.Vec3(*direction).length() vel = [v * mag for v in direction] Rocket(position=position, velocity=vel, diff --git a/plugins/minigames/hot_potato.py b/plugins/minigames/hot_potato.py index 9acc3553..6a57edab 100644 --- a/plugins/minigames/hot_potato.py +++ b/plugins/minigames/hot_potato.py @@ -791,7 +791,8 @@ def marked_players_died(self) -> bool: self._end_game_timer = bs.Timer(1.25, babase.Call(self.end_game)) else: # There's still players remaining, so let's wait a while before marking a new player. - self.new_mark_timer = bs.Timer(2.0 if self.slow_motion else 4.0, babase.Call(self.new_mark)) + self.new_mark_timer = bs.Timer( + 2.0 if self.slow_motion else 4.0, babase.Call(self.new_mark)) # Another extensively used function that returns all alive players. def get_alive_players(self) -> Sequence[bs.Player]: @@ -852,7 +853,8 @@ def on_begin(self) -> None: self._round_end_timer = bs.Timer(0.5, self.end_game) else: # Pick random player(s) to get marked - self.new_mark_timer = bs.Timer(2.0 if self.slow_motion else 5.2, babase.Call(self.new_mark)) + self.new_mark_timer = bs.Timer( + 2.0 if self.slow_motion else 5.2, babase.Call(self.new_mark)) self._update_icons() # Create player state icons diff --git a/plugins/minigames/simon_says.py b/plugins/minigames/simon_says.py index 5640951d..7cb6887e 100644 --- a/plugins/minigames/simon_says.py +++ b/plugins/minigames/simon_says.py @@ -206,7 +206,7 @@ def on_player_join(self, player: Player) -> None: if self.has_begun(): bs.broadcastmessage( babase.Lstr(resource='playerDelayedJoinText', - subs=[('${PLAYER}', player.getname(full=True))]), + subs=[('${PLAYER}', player.getname(full=True))]), color=(0, 1, 0),) return else: @@ -232,7 +232,7 @@ def on_begin(self) -> None: if len(self.players) == 1: bs.timer(4000/1000, lambda: self.check_end()) else: - bs.timer(6000/1000, self.call_round) + bs.timer(6000/1000, self.call_round) def spawn_player(self, player: PlayerT) -> bs.Actor: assert player @@ -310,7 +310,7 @@ def check_round(self) -> None: if ((self.simon and safe == False) or ((not self.simon) and safe == True)): player.team.score = self.round_num player.actor.handlemessage(bs.DieMessage()) - bs.timer(1633/1000, self.call_round) + bs.timer(1633/1000, self.call_round) def in_circle(self, pos) -> None: circles = [] diff --git a/plugins/minigames/sleep_race.py b/plugins/minigames/sleep_race.py index 3f003122..21ad95af 100644 --- a/plugins/minigames/sleep_race.py +++ b/plugins/minigames/sleep_race.py @@ -340,10 +340,10 @@ def _handle_race_point_collide(self) -> None: player.actor.node.connectattr( 'torso_position', mathnode, 'input2') tstr = babase.Lstr(resource='lapNumberText', - subs=[('${CURRENT}', - str(player.lap + 1)), - ('${TOTAL}', str(self._laps)) - ]) + subs=[('${CURRENT}', + str(player.lap + 1)), + ('${TOTAL}', str(self._laps)) + ]) txtnode = bs.newnode('text', owner=mathnode, attrs={ diff --git a/plugins/minigames/squid_race.py b/plugins/minigames/squid_race.py index 0dea3192..d665e5b4 100644 --- a/plugins/minigames/squid_race.py +++ b/plugins/minigames/squid_race.py @@ -349,10 +349,10 @@ def _handle_race_point_collide(self) -> None: player.actor.node.connectattr( 'torso_position', mathnode, 'input2') tstr = babase.Lstr(resource='lapNumberText', - subs=[('${CURRENT}', - str(player.lap + 1)), - ('${TOTAL}', str(self._laps)) - ]) + subs=[('${CURRENT}', + str(player.lap + 1)), + ('${TOTAL}', str(self._laps)) + ]) txtnode = bs.newnode('text', owner=mathnode, attrs={ @@ -382,7 +382,7 @@ def on_player_join(self, player: Player) -> None: if self.has_begun(): bs.broadcastmessage( babase.Lstr(resource='playerDelayedJoinText', - subs=[('${PLAYER}', player.getname(full=True))]), + subs=[('${PLAYER}', player.getname(full=True))]), color=(0, 1, 0), ) return diff --git a/plugins/minigames/ufo_fight.py b/plugins/minigames/ufo_fight.py index d8849f87..0d99f63e 100644 --- a/plugins/minigames/ufo_fight.py +++ b/plugins/minigames/ufo_fight.py @@ -253,8 +253,8 @@ def _drop_bots(self) -> None: 1.0 + i, lambda: self._bots.spawn_bot( RoboBot, pos=(self.node.position[0], - self.node.position[1] - 1, - self.node.position[2]), spawn_time=0.0 + self.node.position[1] - 1, + self.node.position[2]), spawn_time=0.0 ), ) @@ -297,7 +297,6 @@ def raise_player(player: bs.Player): node.position[2], 0, 5, 0, 3, 10, 0, 0, 0, 5, 0) - except: pass @@ -321,7 +320,7 @@ def do_damage(self, msg: Any) -> None: self.handlemessage(bs.DieMessage()) def _get_target_player_pt(self) -> tuple[ - bs.Vec3 | None, bs.Vec3 | None]: + bs.Vec3 | None, bs.Vec3 | None]: """Returns the position and velocity of our target. Both values will be None in the case of no target. @@ -514,7 +513,6 @@ def _update(self) -> None: {0: self.shield_deco.color, 0.2: (5, 0.2, 0.2)}) self.bot_count = 6 - def update_ai(self) -> None: """Should be called periodically to update the spaz' AI.""" # pylint: disable=too-many-branches @@ -706,8 +704,8 @@ def _update(self) -> None: + str(self._ufo_bot_lists[self._ufo_bot_update_list]) ) self._bot_update_list = ( - self._ufo_bot_update_list + 1 - ) % self._ufo_bot_list_count + self._ufo_bot_update_list + 1 + ) % self._ufo_bot_list_count # Update our list of player points for the bots to use. player_pts = [] @@ -780,7 +778,7 @@ def add_bot(self, bot: UFO) -> None: """Add a bs.SpazBot instance to the set.""" self._ufo_bot_lists[self._ufo_bot_add_list].append(bot) self._ufo_bot_add_list = ( - self._ufo_bot_add_list + 1) % self._ufo_bot_list_count + self._ufo_bot_add_list + 1) % self._ufo_bot_list_count def have_living_bots(self) -> bool: """Return whether any bots in the set are alive or spawning.""" @@ -855,18 +853,16 @@ def __init__(self, settings: dict): self._bots = UFOSet() self._preset = str(settings['preset']) self._credit = bs.newnode('text', - attrs={ - 'v_attach': 'bottom', - 'h_align': 'center', - 'color': (0.4, 0.4, 0.4), - 'flatness': 0.5, - 'shadow': 0.5, - 'position': (0, 20), - 'scale': 0.7, - 'text': 'By Cross Joy' - }) - - + attrs={ + 'v_attach': 'bottom', + 'h_align': 'center', + 'color': (0.4, 0.4, 0.4), + 'flatness': 0.5, + 'shadow': 0.5, + 'position': (0, 20), + 'scale': 0.7, + 'text': 'By Cross Joy' + }) def on_transition_in(self) -> None: super().on_transition_in() @@ -878,8 +874,6 @@ def on_begin(self) -> None: super().on_begin() self.setup_standard_powerup_drops() - - # In pro mode there's no powerups. # Make our on-screen timer and start it roughly when our bots appear. @@ -987,4 +981,3 @@ def on_app_running(self) -> None: preview_texture_name='footballStadiumPreview', ) ) - diff --git a/plugins/minigames/ultimate_last_stand.py b/plugins/minigames/ultimate_last_stand.py index 842521dd..cff95266 100644 --- a/plugins/minigames/ultimate_last_stand.py +++ b/plugins/minigames/ultimate_last_stand.py @@ -43,11 +43,11 @@ from bascenev1lib.actor.scoreboard import Scoreboard from bascenev1lib.actor.spazfactory import SpazFactory from bascenev1lib.actor.spazbot import (SpazBot, SpazBotSet, BomberBot, - BomberBotPro, BomberBotProShielded, - BrawlerBot, BrawlerBotPro, - BrawlerBotProShielded, TriggerBot, - TriggerBotPro, TriggerBotProShielded, - ChargerBot, StickyBot, ExplodeyBot) + BomberBotPro, BomberBotProShielded, + BrawlerBot, BrawlerBotPro, + BrawlerBotProShielded, TriggerBot, + TriggerBotPro, TriggerBotProShielded, + ChargerBot, StickyBot, ExplodeyBot) if TYPE_CHECKING: from typing import Any, Sequence diff --git a/plugins/minigames/zombie_horde.py b/plugins/minigames/zombie_horde.py index 0728409e..bd8bf2b8 100644 --- a/plugins/minigames/zombie_horde.py +++ b/plugins/minigames/zombie_horde.py @@ -122,7 +122,7 @@ def zUpdate(self) -> None: except Exception: bot_list = [] babase.print_exception('Error updating bot list: ' + - str(self._bot_lists[self._bot_update_list])) + str(self._bot_lists[self._bot_update_list])) self._bot_update_list = (self._bot_update_list + 1) % self._bot_list_count @@ -286,7 +286,7 @@ def on_player_join(self, player: Player) -> None: player.icons = [] bs.broadcastmessage( babase.Lstr(resource='playerDelayedJoinText', - subs=[('${PLAYER}', player.getname(full=True))]), + subs=[('${PLAYER}', player.getname(full=True))]), color=(0, 1, 0), ) return diff --git a/plugins/utilities/auto_stunt.py b/plugins/utilities/auto_stunt.py index 85668212..c060ff27 100644 --- a/plugins/utilities/auto_stunt.py +++ b/plugins/utilities/auto_stunt.py @@ -284,7 +284,8 @@ def replay(player, stunt_name): else: bs.timer( move["time"], - babase.Call(player.actor.move_map[move["move"]["action"]], move["move"]["value"]) + babase.Call(player.actor.move_map[move["move"] + ["action"]], move["move"]["value"]) ) last_move_time = move["time"] time_to_hide_controls = last_move_time + 1 diff --git a/plugins/utilities/chat_cmd.py b/plugins/utilities/chat_cmd.py index 071073b6..1fa80e9f 100644 --- a/plugins/utilities/chat_cmd.py +++ b/plugins/utilities/chat_cmd.py @@ -40,7 +40,6 @@ def _process_cmd(): except: pass - def _handle(): messages = get_chat_messages() if len(messages) > 1: @@ -544,13 +543,16 @@ def _handle(): cmsg(u'\U0001F95A Nazz are past/present/future \U0001F95A') cmsg(u'\U0001F95A everything is Nazz \U0001F95A') + class NewMainMenuWindow(mainmenu.MainMenuWindow): def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) # Display chat icon, but if user open/close gather it may disappear bui.set_party_icon_always_visible(True) - + # bs.timer(0.05, _update, repeat=True) + + def same(): # bs.timer(0.5, _cmds._process_cmd, True) _cmds._process_cmd() @@ -558,10 +560,7 @@ def same(): class _enableee(babase.Plugin): - timer = bs.AppTimer(0.5, same,repeat=True) - + timer = bs.AppTimer(0.5, same, repeat=True) + def on_app_running(self): mainmenu.MainMenuWindow = NewMainMenuWindow - - - \ No newline at end of file diff --git a/plugins/utilities/disco_light.py b/plugins/utilities/disco_light.py index 572baa04..68d49795 100644 --- a/plugins/utilities/disco_light.py +++ b/plugins/utilities/disco_light.py @@ -55,7 +55,8 @@ def is_game_version_lower_than(version): version is lower than the passed version. Useful for addressing any breaking changes within game versions. """ - game_version = tuple(map(int, babase.app.version if build_number < 21282 else babase.app.env.split("."))) + game_version = tuple(map(int, babase.app.version if build_number < + 21282 else babase.app.env.split("."))) version = tuple(map(int, version.split("."))) return game_version < version @@ -103,23 +104,23 @@ def partyLight(switch=True): b = random.choice([0.5, 1]) light = NodeActor( bs.newnode('light', - attrs={ - 'position': (positions[i][0], 0, positions[i][1]), - 'radius': 1.0, - 'lights_volumes': False, - 'height_attenuated': False, - 'color': (r, g, b) - })) + attrs={ + 'position': (positions[i][0], 0, positions[i][1]), + 'radius': 1.0, + 'lights_volumes': False, + 'height_attenuated': False, + 'color': (r, g, b) + })) sval = 1.87 iscale = 1.3 tcombine = bs.newnode('combine', - owner=light.node, - attrs={ - 'size': 3, - 'input0': positions[i][0], - 'input1': 0, - 'input2': positions[i][1] - }) + owner=light.node, + attrs={ + 'size': 3, + 'input0': positions[i][0], + 'input1': 0, + 'input2': positions[i][1] + }) assert light.node tcombine.connectattr('output', light.node, 'position') xval = positions[i][0] @@ -154,7 +155,7 @@ def partyLight(switch=True): offset=times[i]) if not switch: bs.timer(0.1, - light.node.delete) + light.node.delete) activity.camera_flash_data.append(light) # type: ignore @@ -163,12 +164,12 @@ def rainbow(self) -> None: """Create RGB tint.""" c_existing = self.globalsnode.tint cnode = bs.newnode('combine', - attrs={ - 'input0': c_existing[0], - 'input1': c_existing[1], - 'input2': c_existing[2], - 'size': 3 - }) + attrs={ + 'input0': c_existing[0], + 'input1': c_existing[1], + 'input2': c_existing[2], + 'size': 3 + }) _gameutils.animate(cnode, 'input0', {0.0: 1.0, 1.0: 1.0, 2.0: 1.0, 3.0: 1.0, @@ -199,12 +200,12 @@ def stop_rainbow(self): tint = (1, 1, 1) cnode = bs.newnode('combine', - attrs={ - 'input0': c_existing[0], - 'input1': c_existing[1], - 'input2': c_existing[2], - 'size': 3 - }) + attrs={ + 'input0': c_existing[0], + 'input1': c_existing[1], + 'input2': c_existing[2], + 'size': 3 + }) _gameutils.animate(cnode, 'input0', {0: c_existing[0], 1.0: tint[0]}) _gameutils.animate(cnode, 'input1', {0: c_existing[1], 1.0: tint[1]}) @@ -268,12 +269,14 @@ def new_chat_message(msg: Union[str, babase.Lstr], clients: Sequence[int] = None if msg == '/disco off': stop() + class NewMainMenuWindow(mainmenu.MainMenuWindow): def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) # Display chat icon, but if user open/close gather it may disappear bui.set_party_icon_always_visible(True) - + + # Replace new chat func to the original game codes. bs.chatmessage = new_chat_message @@ -282,4 +285,3 @@ def __init__(self, *args, **kwargs): class ByCrossJoy(babase.Plugin): def on_app_running(self): mainmenu.MainMenuWindow = NewMainMenuWindow - \ No newline at end of file diff --git a/plugins/utilities/discord_richpresence.py b/plugins/utilities/discord_richpresence.py index 2a748702..4980a05f 100644 --- a/plugins/utilities/discord_richpresence.py +++ b/plugins/utilities/discord_richpresence.py @@ -370,7 +370,8 @@ def is_discord_running(): def _generate_join_secret(self): # resp = requests.get('https://legacy.ballistica.net/bsAccessCheck').text - connection_info = bs.get_connection_to_host_info() if build_number < 21697 else bs.get_connection_to_host_info_2() + connection_info = bs.get_connection_to_host_info( + ) if build_number < 21697 else bs.get_connection_to_host_info_2() if connection_info: addr = _last_server_addr port = _last_server_port @@ -794,7 +795,7 @@ def __init__(self) -> None: def on_app_running(self) -> None: if not ANDROID: self.rpc_thread.start() - + self.update_timer = bs.AppTimer( 1, bs.WeakCall(self.update_status), repeat=True ) @@ -803,7 +804,7 @@ def on_app_running(self) -> None: self.update_timer = bs.AppTimer( 4, bs.WeakCall(self.update_status), repeat=True ) - + def has_settings_ui(self): return True @@ -870,7 +871,8 @@ def _get_current_map_name(self) -> Tuple[str | None, str | None]: def update_status(self) -> None: roster = bs.get_game_roster() - connection_info = bs.get_connection_to_host_info() if build_number < 21697 else bs.get_connection_to_host_info_2() + connection_info = bs.get_connection_to_host_info( + ) if build_number < 21697 else bs.get_connection_to_host_info_2() self.rpc_thread.large_image_key = "bombsquadicon" self.rpc_thread.large_image_text = "BombSquad" diff --git a/plugins/utilities/max_players.py b/plugins/utilities/max_players.py index f18265f5..39d0672f 100644 --- a/plugins/utilities/max_players.py +++ b/plugins/utilities/max_players.py @@ -136,7 +136,7 @@ def __init__(self): icon=bui.gettexture('crossOut'), iconscale=1.2) bui.containerwidget(edit=self.root_widget, - cancel_button=self._cancel_button) + cancel_button=self._cancel_button) bui.textwidget( parent=self.root_widget, diff --git a/plugins/utilities/mood_light.py b/plugins/utilities/mood_light.py index ec822dd4..81ca17c5 100644 --- a/plugins/utilities/mood_light.py +++ b/plugins/utilities/mood_light.py @@ -61,7 +61,7 @@ def increase_limit(self): try: if Udefault >= 29 and self.selected == "upper": bui.textwidget(edit=self.warn_text, - text="Careful!You risk get blind beyond this point") + text="Careful!You risk get blind beyond this point") elif self.selected == "lower" and Ldefault >= -20 or self.selected == "upper" and Udefault <= 30: bui.textwidget(edit=self.warn_text, text="") if self.selected == "lower": @@ -78,7 +78,7 @@ def decrease_limit(self): try: if Ldefault <= -19 and self.selected == "lower": bui.textwidget(edit=self.warn_text, - text="DON'T BE AFRAID OF DARK,IT'S A PLACE WHERE YOU CAN HIDE") + text="DON'T BE AFRAID OF DARK,IT'S A PLACE WHERE YOU CAN HIDE") elif (self.selected == "upper" and Udefault <= 30) or (self.selected == "lower" and Ldefault >= -20): bui.textwidget(edit=self.warn_text, text="") if self.selected == "lower": @@ -218,23 +218,25 @@ def draw_ui(self): # ++++++++++++++++for keyboard navigation++++++++++++++++ bui.widget(edit=self.enable_button, up_widget=decrease_button, - down_widget=self.lower_text, left_widget=save_button, right_widget=save_button) + down_widget=self.lower_text, left_widget=save_button, right_widget=save_button) bui.widget(edit=save_button, up_widget=self.close_button, down_widget=self.upper_text, - left_widget=self.enable_button, right_widget=self.enable_button) + left_widget=self.enable_button, right_widget=self.enable_button) bui.widget(edit=self.close_button, up_widget=increase_button, down_widget=save_button, - left_widget=self.enable_button, right_widget=save_button) + left_widget=self.enable_button, right_widget=save_button) bui.widget(edit=self.lower_text, up_widget=self.enable_button, down_widget=decrease_button, - left_widget=self.upper_text, right_widget=self.upper_text) + left_widget=self.upper_text, right_widget=self.upper_text) bui.widget(edit=self.upper_text, up_widget=save_button, down_widget=increase_button, - left_widget=self.lower_text, right_widget=self.lower_text) + left_widget=self.lower_text, right_widget=self.lower_text) bui.widget(edit=decrease_button, up_widget=self.lower_text, down_widget=self.enable_button, - left_widget=increase_button, right_widget=increase_button) + left_widget=increase_button, right_widget=increase_button) bui.widget(edit=increase_button, up_widget=self.upper_text, down_widget=self.close_button, - left_widget=decrease_button, right_widget=decrease_button) + left_widget=decrease_button, right_widget=decrease_button) # -------------------------------------------------------------------------------------------------- - bui.textwidget(edit=self.upper_text, on_activate_call=babase.Call(self.on_text_click, "upper")) - bui.textwidget(edit=self.lower_text, on_activate_call=babase.Call(self.on_text_click, "lower")) + bui.textwidget(edit=self.upper_text, on_activate_call=babase.Call( + self.on_text_click, "upper")) + bui.textwidget(edit=self.lower_text, on_activate_call=babase.Call( + self.on_text_click, "lower")) def on_enableButton_press(self): global loop @@ -275,12 +277,14 @@ def new_chat_message(msg: Union[str, babase.Lstr], clients: Sequence[int] = None except Exception as err: Print(err, "-from new_chat_message") + class NewMainMenuWindow(MainMenuWindow): def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) # Display chat icon, but if user open/close gather it may disappear bui.set_party_icon_always_visible(True) - + + old_fcm = bs.chatmessage bs.chatmessage = new_chat_message Map._old_init = Map.__init__ diff --git a/plugins/utilities/quick_custom_game.py b/plugins/utilities/quick_custom_game.py index 08575142..a2888206 100644 --- a/plugins/utilities/quick_custom_game.py +++ b/plugins/utilities/quick_custom_game.py @@ -135,15 +135,15 @@ def get_session_type(self) -> Type[bs.Session]: stack_offset=(0, 1) if uiscale is babase.UIScale.SMALL else (0, 0)) self._back_button = bui.buttonwidget(parent=self._root_widget, - position=(58 + x_inset, - self._height - 53), - size=(165, 70), - scale=0.75, - text_scale=1.2, - label=babase.Lstr(resource='backText'), - autoselect=True, - button_type='back', - on_activate_call=self._back) + position=(58 + x_inset, + self._height - 53), + size=(165, 70), + scale=0.75, + text_scale=1.2, + label=babase.Lstr(resource='backText'), + autoselect=True, + button_type='back', + on_activate_call=self._back) self._select_button = select_button = bui.buttonwidget( parent=self._root_widget, position=(self._width - (172 + x_inset), self._height - 50), @@ -156,17 +156,17 @@ def get_session_type(self) -> Type[bs.Session]: if bui.app.ui_v1.use_toolbars: bui.widget(edit=select_button, - right_widget=bui.get_special_widget('party_button')) + right_widget=bui.get_special_widget('party_button')) bui.textwidget(parent=self._root_widget, - position=(self._width * 0.5, self._height - 28), - size=(0, 0), - scale=1.0, - text=babase.Lstr(resource=self._r + '.titleText'), - h_align='center', - color=bui.app.ui_v1.title_color, - maxwidth=250, - v_align='center') + position=(self._width * 0.5, self._height - 28), + size=(0, 0), + scale=1.0, + text=babase.Lstr(resource=self._r + '.titleText'), + h_align='center', + color=bui.app.ui_v1.title_color, + maxwidth=250, + v_align='center') v = self._height - 64 self._selected_title_text = bui.textwidget( @@ -194,32 +194,32 @@ def get_session_type(self) -> Type[bs.Session]: v = self._height - 60 self._scrollwidget = bui.scrollwidget(parent=self._root_widget, - position=(x_inset + 61, - v - scroll_height), - size=(self._scroll_width, - scroll_height), - highlight=False) + position=(x_inset + 61, + v - scroll_height), + size=(self._scroll_width, + scroll_height), + highlight=False) bui.widget(edit=self._scrollwidget, - up_widget=self._back_button, - left_widget=self._back_button, - right_widget=select_button) + up_widget=self._back_button, + left_widget=self._back_button, + right_widget=select_button) self._column: Optional[bui.Widget] = None v -= 35 bui.containerwidget(edit=self._root_widget, - cancel_button=self._back_button, - start_button=select_button) + cancel_button=self._back_button, + start_button=select_button) self._selected_game_type: Optional[Type[bs.GameActivity]] = None bui.containerwidget(edit=self._root_widget, - selected_child=self._scrollwidget) + selected_child=self._scrollwidget) self._game_types: list[type[bs.GameActivity]] = [] # Get actual games loading in the bg. babase.app.meta.load_exported_classes(bs.GameActivity, - self._on_game_types_loaded, - completion_cb_in_bg_thread=True) + self._on_game_types_loaded, + completion_cb_in_bg_thread=True) # Refresh with our initial empty list. We'll refresh again once # game loading is complete. @@ -240,29 +240,29 @@ def _refresh(self, self._column.delete() self._column = bui.columnwidget(parent=self._scrollwidget, - border=2, - margin=0) + border=2, + margin=0) for i, gametype in enumerate(self._game_types): def _doit() -> None: if self._select_button: bs.apptimer(0.1, - self._select_button.activate) + self._select_button.activate) txt = bui.textwidget(parent=self._column, - position=(0, 0), - size=(self._width - 88, 24), - text=gametype.get_display_string(), - h_align='left', - v_align='center', - color=(0.8, 0.8, 0.8, 1.0), - maxwidth=self._scroll_width * 0.8, - on_select_call=babase.Call( - self._set_selected_game_type, gametype), - always_highlight=True, - selectable=True, - on_activate_call=_doit) + position=(0, 0), + size=(self._width - 88, 24), + text=gametype.get_display_string(), + h_align='left', + v_align='center', + color=(0.8, 0.8, 0.8, 1.0), + maxwidth=self._scroll_width * 0.8, + on_select_call=babase.Call( + self._set_selected_game_type, gametype), + always_highlight=True, + selectable=True, + on_activate_call=_doit) if i == 0: bui.widget(edit=txt, up_widget=self._back_button) @@ -276,8 +276,8 @@ def _doit() -> None: size=(178, 50)) if select_get_more_games_button: bui.containerwidget(edit=self._column, - selected_child=self._get_more_games_button, - visible_child=self._get_more_games_button) + selected_child=self._get_more_games_button, + visible_child=self._get_more_games_button) def _add(self) -> None: _babase.lock_all_input() # Make sure no more commands happen. @@ -364,7 +364,7 @@ def _restore_state(self) -> None: return # ensure that our monkey patched init ran if self.__class__.__name__ not in bui.app.ui_v1.window_states: bui.containerwidget(edit=self._root_widget, - selected_child=self._coop_button) + selected_child=self._coop_button) return sel = states(self).get( bui.app.ui_v1.window_states[self.__class__.__name__], None) @@ -372,7 +372,7 @@ def _restore_state(self) -> None: bui.containerwidget(edit=self._root_widget, selected_child=sel) else: bui.containerwidget(edit=self._root_widget, - selected_child=self._coop_button) + selected_child=self._coop_button) babase.print_exception(f'Error restoring state for {self}.') diff --git a/plugins/utilities/quickturn.py b/plugins/utilities/quickturn.py index a175a3f4..80a5cd53 100644 --- a/plugins/utilities/quickturn.py +++ b/plugins/utilities/quickturn.py @@ -132,7 +132,8 @@ def wrapper(*args, **kwargs): func(*args, **kwargs) return wrapper - bascenev1lib.actor.spaz.Spaz.handlemessage = new_handlemessage(bascenev1lib.actor.spaz.Spaz.handlemessage) + bascenev1lib.actor.spaz.Spaz.handlemessage = new_handlemessage( + bascenev1lib.actor.spaz.Spaz.handlemessage) def new_on_run(func): def wrapper(*args, **kwargs): diff --git a/plugins/utilities/ragdoll_b_gone.py b/plugins/utilities/ragdoll_b_gone.py index 3bd5e8be..996160a9 100644 --- a/plugins/utilities/ragdoll_b_gone.py +++ b/plugins/utilities/ragdoll_b_gone.py @@ -119,4 +119,5 @@ def wrapper(*args, **kwargs): # Finally we """travel through the game files""" to replace the function we want with our own version. # We transplant the old function's arguments into our version. - bascenev1lib.actor.spaz.Spaz.handlemessage = new_handlemessage(bascenev1lib.actor.spaz.Spaz.handlemessage) + bascenev1lib.actor.spaz.Spaz.handlemessage = new_handlemessage( + bascenev1lib.actor.spaz.Spaz.handlemessage) diff --git a/plugins/utilities/random_join.py b/plugins/utilities/random_join.py index e29a5992..6d37d891 100644 --- a/plugins/utilities/random_join.py +++ b/plugins/utilities/random_join.py @@ -60,7 +60,7 @@ def _build_join_tab(self, region_width: float, on_activate_call=bs.WeakCall(self._join_random_server), ) bui.widget(edit=self._random_join_button, up_widget=self._host_text, - left_widget=self._filter_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: @@ -100,7 +100,7 @@ def _join_random_server(self) -> None: if not parties: bui.screenmessage('No suitable servers found; wait', - color=(1, 0, 0)) + color=(1, 0, 0)) bui.getsound('error').play() return @@ -228,7 +228,7 @@ def _save(self) -> None: bui.textwidget(query=self._minimum_players_edit)) except ValueError: bui.screenmessage('"Minimum players" should be integer', - color=(1, 0, 0)) + color=(1, 0, 0)) bui.getsound('error').play() errored = True try: @@ -236,7 +236,7 @@ def _save(self) -> None: bui.textwidget(query=self._maximum_ping_edit)) except ValueError: bui.screenmessage('"Maximum ping" should be integer', - color=(1, 0, 0)) + color=(1, 0, 0)) bui.getsound('error').play() errored = True if errored: @@ -247,16 +247,16 @@ def _save(self) -> None: if minimum_players < 0: bui.screenmessage('"Minimum players" should be at least 0', - color=(1, 0, 0)) + color=(1, 0, 0)) bui.getsound('error').play() errored = True if maximum_ping <= 0: bui.screenmessage('"Maximum ping" should be greater than 0', - color=(1, 0, 0)) + color=(1, 0, 0)) bui.getsound('error').play() bui.screenmessage('(use 9999 as dont-care value)', - color=(1, 0, 0)) + color=(1, 0, 0)) errored = True if errored: @@ -294,7 +294,7 @@ def load_config(self) -> None: self.minimum_players = cfg['minimum_players'] except KeyError: bui.screenmessage('Error: RandomJoin config is broken, resetting..', - color=(1, 0, 0), log=True) + color=(1, 0, 0), log=True) bui.getsound('error').play() self.commit_config() diff --git a/plugins/utilities/tnt_respawn_text.py b/plugins/utilities/tnt_respawn_text.py index 52b7f729..a15fab5e 100644 --- a/plugins/utilities/tnt_respawn_text.py +++ b/plugins/utilities/tnt_respawn_text.py @@ -129,7 +129,8 @@ def tnt_callback(): args[0]._tnt.node.add_death_action(tnt_callback) return wrapper # Let's replace the original init function with our modified version. - bascenev1lib.actor.bomb.TNTSpawner.__init__ = new_init(bascenev1lib.actor.bomb.TNTSpawner.__init__) + bascenev1lib.actor.bomb.TNTSpawner.__init__ = new_init( + bascenev1lib.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. @@ -215,4 +216,5 @@ def tnt_callback(): return wrapper # Let's replace the original update function with our modified version. - bascenev1lib.actor.bomb.TNTSpawner._update = new_update(bascenev1lib.actor.bomb.TNTSpawner._update) + bascenev1lib.actor.bomb.TNTSpawner._update = new_update( + bascenev1lib.actor.bomb.TNTSpawner._update) diff --git a/plugins/utilities/ultra_party_window.py b/plugins/utilities/ultra_party_window.py index 712b7be2..094e0048 100644 --- a/plugins/utilities/ultra_party_window.py +++ b/plugins/utilities/ultra_party_window.py @@ -302,7 +302,8 @@ def _get_local_time(utctime): def update_status(): if messenger.logged_in: if babase.app.config['Self Status'] == 'online': - host = bs.get_connection_to_host_info().get('name', '') if build_number < 21697 else bs.get_connection_to_host_info_2().get('name', '') + host = bs.get_connection_to_host_info().get( + 'name', '') if build_number < 21697 else bs.get_connection_to_host_info_2().get('name', '') if host: my_status = f'Playing in {host}' else: @@ -424,35 +425,35 @@ def __init__(self): 1.3 if uiscale is babase.UIScale.MEDIUM else 1.0), stack_offset=(0, -16) if uiscale is babase.UIScale.SMALL else (0, 0)) bui.textwidget(parent=self._root_widget, - position=(-10, self._height - 50), - size=(self._width, 25), - text='Sort Quick Messages', - color=bui.app.ui_v1.title_color, - scale=1.05, - h_align='center', - v_align='center', - maxwidth=270) + position=(-10, self._height - 50), + size=(self._width, 25), + text='Sort Quick Messages', + color=bui.app.ui_v1.title_color, + scale=1.05, + h_align='center', + v_align='center', + maxwidth=270) b_textcolor = (0.4, 0.75, 0.5) up_button = bui.buttonwidget(parent=self._root_widget, - position=(10, 170), - size=(75, 75), - on_activate_call=self._move_up, - label=babase.charstr(babase.SpecialChar.UP_ARROW), - button_type='square', - color=bg_color, - textcolor=b_textcolor, - autoselect=True, - repeat=True) + position=(10, 170), + size=(75, 75), + on_activate_call=self._move_up, + label=babase.charstr(babase.SpecialChar.UP_ARROW), + button_type='square', + color=bg_color, + textcolor=b_textcolor, + autoselect=True, + repeat=True) down_button = bui.buttonwidget(parent=self._root_widget, - position=(10, 75), - size=(75, 75), - on_activate_call=self._move_down, - label=babase.charstr(babase.SpecialChar.DOWN_ARROW), - button_type='square', - color=bg_color, - textcolor=b_textcolor, - autoselect=True, - repeat=True) + position=(10, 75), + size=(75, 75), + on_activate_call=self._move_down, + label=babase.charstr(babase.SpecialChar.DOWN_ARROW), + button_type='square', + color=bg_color, + textcolor=b_textcolor, + autoselect=True, + repeat=True) self._scroll_width = self._width - 150 self._scroll_height = self._height - 110 self._scrollwidget = bui.scrollwidget( @@ -469,7 +470,7 @@ def __init__(self): self._msg_selected = None self._refresh() bui.containerwidget(edit=self._root_widget, - on_cancel_call=self._save) + on_cancel_call=self._save) def _refresh(self): for child in self._columnwidget.get_children(): @@ -487,8 +488,8 @@ def _refresh(self): maxwidth=self._scroll_width) if msg == self._msg_selected: bui.columnwidget(edit=self._columnwidget, - selected_child=txt, - visible_child=txt) + selected_child=txt, + visible_child=txt) def _on_msg_select(self, msg): self._msg_selected = msg @@ -659,29 +660,29 @@ def __init__(self): 1.5 if uiscale is babase.UIScale.MEDIUM else 1.0), scale_origin_stack_offset=scale_origin) bui.textwidget(parent=self.root_widget, - position=(width * 0.5, height - 45), - size=(20, 20), - h_align='center', - v_align='center', - text="Text Translation", - scale=0.9, - color=(5, 5, 5)) + position=(width * 0.5, height - 45), + size=(20, 20), + h_align='center', + v_align='center', + text="Text Translation", + scale=0.9, + color=(5, 5, 5)) cbtn = btn = bui.buttonwidget(parent=self.root_widget, - autoselect=True, - position=(30, height - 60), - size=(30, 30), - label=babase.charstr(babase.SpecialChar.BACK), - button_type='backSmall', - on_activate_call=self._cancel) + autoselect=True, + position=(30, height - 60), + size=(30, 30), + label=babase.charstr(babase.SpecialChar.BACK), + button_type='backSmall', + on_activate_call=self._cancel) source_lang_text = bui.textwidget(parent=self.root_widget, - position=(40, height - 110), - size=(20, 20), - h_align='left', - v_align='center', - text="Source Language : ", - scale=0.9, - color=(1, 1, 1)) + position=(40, height - 110), + size=(20, 20), + h_align='left', + v_align='center', + text="Source Language : ", + scale=0.9, + color=(1, 1, 1)) source_lang_menu = PopupMenu( parent=self.root_widget, @@ -696,13 +697,13 @@ def __init__(self): on_value_change_call=self._change_source) destination_lang_text = bui.textwidget(parent=self.root_widget, - position=(40, height - 165), - size=(20, 20), - h_align='left', - v_align='center', - text="Destination Language : ", - scale=0.9, - color=(1, 1, 1)) + position=(40, height - 165), + size=(20, 20), + h_align='left', + v_align='center', + text="Destination Language : ", + scale=0.9, + color=(1, 1, 1)) destination_lang_menu = PopupMenu( parent=self.root_widget, @@ -719,39 +720,39 @@ def __init__(self): try: translation_mode_text = bui.textwidget(parent=self.root_widget, - position=(40, height - 215), - size=(20, 20), - h_align='left', - v_align='center', - text="Translate Mode", - scale=0.9, - color=(1, 1, 1)) + position=(40, height - 215), + size=(20, 20), + h_align='left', + v_align='center', + text="Translate Mode", + scale=0.9, + color=(1, 1, 1)) decoration = bui.textwidget(parent=self.root_widget, - position=(40, height - 225), - size=(20, 20), - h_align='left', - v_align='center', - text="________________", - scale=0.9, - color=(1, 1, 1)) + position=(40, height - 225), + size=(20, 20), + h_align='left', + v_align='center', + text="________________", + scale=0.9, + color=(1, 1, 1)) language_char_text = bui.textwidget(parent=self.root_widget, - position=(85, height - 273), - size=(20, 20), - h_align='left', - v_align='center', - text='Normal Translation', - scale=0.6, - color=(1, 1, 1)) + position=(85, height - 273), + size=(20, 20), + h_align='left', + v_align='center', + text='Normal Translation', + scale=0.6, + color=(1, 1, 1)) pronunciation_text = bui.textwidget(parent=self.root_widget, - position=(295, height - 273), - size=(20, 20), - h_align='left', - v_align='center', - text="Show Prononciation", - scale=0.6, - color=(1, 1, 1)) + position=(295, height - 273), + size=(20, 20), + h_align='left', + v_align='center', + text="Show Prononciation", + scale=0.6, + color=(1, 1, 1)) from bauiv1lib.radiogroup import make_radio_group cur_val = babase.app.config.get('Pronunciation', True) @@ -832,31 +833,31 @@ def __init__(self): 1.5 if uiscale is babase.UIScale.MEDIUM else 1.0), scale_origin_stack_offset=scale_origin) bui.textwidget(parent=self.root_widget, - position=(width * 0.5, height - 45), - size=(20, 20), - h_align='center', - v_align='center', - text="Custom Settings", - scale=0.9, - color=(5, 5, 5)) + position=(width * 0.5, height - 45), + size=(20, 20), + h_align='center', + v_align='center', + text="Custom Settings", + scale=0.9, + color=(5, 5, 5)) cbtn = btn = bui.buttonwidget(parent=self.root_widget, - autoselect=True, - position=(30, height - 60), - size=(30, 30), - label=babase.charstr(babase.SpecialChar.BACK), - button_type='backSmall', - on_activate_call=self._cancel) + autoselect=True, + position=(30, height - 60), + size=(30, 30), + label=babase.charstr(babase.SpecialChar.BACK), + button_type='backSmall', + on_activate_call=self._cancel) scroll_position = (30 if uiscale is babase.UIScale.SMALL else 40 if uiscale is babase.UIScale.MEDIUM else 50) self._scrollwidget = bui.scrollwidget(parent=self.root_widget, - position=(30, scroll_position), - simple_culling_v=20.0, - highlight=False, - size=(scroll_w, scroll_h), - selection_loops_to_parent=True) + position=(30, scroll_position), + simple_culling_v=20.0, + highlight=False, + size=(scroll_w, scroll_h), + selection_loops_to_parent=True) bui.widget(edit=self._scrollwidget, right_widget=self._scrollwidget) self._subcontainer = bui.columnwidget(parent=self._scrollwidget, - selection_loops_to_parent=True) + selection_loops_to_parent=True) ip_button = bui.checkboxwidget( parent=self._subcontainer, size=(300, 30), @@ -908,12 +909,12 @@ def __init__(self): text="Colorful Chat", on_value_change_call=self.colorful_chat) msg_notification_text = bui.textwidget(parent=self._subcontainer, - scale=0.8, - color=(1, 1, 1), - text='Message Notifcation:', - size=(100, 30), - h_align='left', - v_align='center') + scale=0.8, + color=(1, 1, 1), + text='Message Notifcation:', + size=(100, 30), + h_align='left', + v_align='center') msg_notification_widget = PopupMenu( parent=self._subcontainer, position=(100, height - 1200), @@ -925,12 +926,12 @@ def __init__(self): button_size=(80, 25), on_value_change_call=self._change_notification) self_status_text = bui.textwidget(parent=self._subcontainer, - scale=0.8, - color=(1, 1, 1), - text='Self Status:', - size=(100, 30), - h_align='left', - v_align='center') + scale=0.8, + color=(1, 1, 1), + text='Self Status:', + size=(100, 30), + h_align='left', + v_align='center') self_status_widget = PopupMenu( parent=self._subcontainer, position=(50, height - 1000), @@ -943,17 +944,17 @@ def __init__(self): on_value_change_call=self._change_status) bui.containerwidget(edit=self.root_widget, cancel_button=btn) bui.containerwidget(edit=self.root_widget, - selected_child=(cbtn if cbtn is not None - and cancel_is_selected else None), - start_button=None) + selected_child=(cbtn if cbtn is not None + and cancel_is_selected else None), + start_button=None) self._translation_btn = bui.buttonwidget(parent=self._subcontainer, - scale=1.2, - position=(100, 1200), - size=(150, 50), - label='Translate Settings', - on_activate_call=self._translaton_btn, - autoselect=True) + scale=1.2, + position=(100, 1200), + size=(150, 50), + label='Translate Settings', + on_activate_call=self._translaton_btn, + autoselect=True) def ip_button(self, value: bool): cfg = babase.app.config @@ -1049,17 +1050,17 @@ def __init__(self, origin: Sequence[float] = (0, 0)): 240, 0) if uiscale is babase.UIScale.MEDIUM else (330, 20))) self._cancel_button = bui.buttonwidget(parent=self._root_widget, - scale=0.7, - position=(30, self._height - 47), - size=(50, 50), - label='', - on_activate_call=self.close, - autoselect=True, - color=self.bg_color, - icon=bui.gettexture('crossOut'), - iconscale=1.2) + scale=0.7, + position=(30, self._height - 47), + size=(50, 50), + label='', + on_activate_call=self.close, + autoselect=True, + color=self.bg_color, + icon=bui.gettexture('crossOut'), + iconscale=1.2) bui.containerwidget(edit=self._root_widget, - cancel_button=self._cancel_button) + cancel_button=self._cancel_button) self._menu_button = bui.buttonwidget( parent=self._root_widget, @@ -1073,40 +1074,42 @@ def __init__(self, origin: Sequence[float] = (0, 0)): color=self.bg_color, iconscale=1.2) try: - info = bs.get_connection_to_host_info().get('name', '') if build_number < 21697 else bs.get_connection_to_host_info_2().name + info = bs.get_connection_to_host_info().get( + 'name', '') if build_number < 21697 else bs.get_connection_to_host_info_2().name if info != '': - self.title = babase.Lstr(value=info['name']) if build_number < 21697 else babase.Lstr(value=info) + self.title = babase.Lstr( + value=info['name']) if build_number < 21697 else babase.Lstr(value=info) except AttributeError: self.title = babase.Lstr(resource=self._r + '.titleText') - + self._title_text = bui.textwidget(parent=self._root_widget, - scale=0.9, - color=(0.5, 0.7, 0.5), - text=self.title, + scale=0.9, + color=(0.5, 0.7, 0.5), + text=self.title, + size=(0, 0), + position=(self._width * 0.47, + self._height - 29), + maxwidth=self._width * 0.6, + h_align='center', + v_align='center') + self._empty_str = bui.textwidget(parent=self._root_widget, + scale=0.75, size=(0, 0), - position=(self._width * 0.47, - self._height - 29), - maxwidth=self._width * 0.6, + position=(self._width * 0.5, + self._height - 65), + maxwidth=self._width * 0.85, h_align='center', v_align='center') - self._empty_str = bui.textwidget(parent=self._root_widget, - scale=0.75, - size=(0, 0), - position=(self._width * 0.5, - self._height - 65), - maxwidth=self._width * 0.85, - h_align='center', - v_align='center') self._scroll_width = self._width - 50 self._scrollwidget = bui.scrollwidget(parent=self._root_widget, - size=(self._scroll_width, - self._height - 200), - position=(30, 80), - color=self.bg_color) + size=(self._scroll_width, + self._height - 200), + position=(30, 80), + color=self.bg_color) self._columnwidget = bui.columnwidget(parent=self._scrollwidget, - border=2, - margin=0) + border=2, + margin=0) bui.widget(edit=self._menu_button, down_widget=self._columnwidget) self._muted_text = bui.textwidget( @@ -1132,63 +1135,65 @@ def __init__(self, origin: Sequence[float] = (0, 0)): corner_scale=0.7) bui.widget(edit=self._scrollwidget, - autoselect=True, - left_widget=self._cancel_button, - up_widget=self._cancel_button, - down_widget=self._text_field) + autoselect=True, + left_widget=self._cancel_button, + up_widget=self._cancel_button, + down_widget=self._text_field) bui.widget(edit=self._columnwidget, - autoselect=True, - up_widget=self._cancel_button, - down_widget=self._text_field) + autoselect=True, + up_widget=self._cancel_button, + down_widget=self._text_field) bui.containerwidget(edit=self._root_widget, selected_child=txt) self._send_button = btn = bui.buttonwidget(parent=self._root_widget, - size=(50, 35), - label=babase.Lstr(resource=self._r + '.sendText'), - button_type='square', - autoselect=True, - color=self.bg_color, - position=(self._width - 90, 35), - on_activate_call=self._send_chat_message) + size=(50, 35), + label=babase.Lstr( + resource=self._r + '.sendText'), + button_type='square', + autoselect=True, + color=self.bg_color, + position=(self._width - 90, 35), + on_activate_call=self._send_chat_message) bui.textwidget(edit=txt, on_return_press_call=btn.activate) self._previous_button = bui.buttonwidget(parent=self._root_widget, - size=(30, 30), - label=babase.charstr(babase.SpecialChar.UP_ARROW), - button_type='square', - autoselect=True, - position=(15, 57), - color=self.bg_color, - scale=0.75, - on_activate_call=self._previous_message) - self._next_button = bui.buttonwidget(parent=self._root_widget, - size=(30, 30), - label=babase.charstr(babase.SpecialChar.DOWN_ARROW), - button_type='square', - autoselect=True, - color=self.bg_color, - scale=0.75, - position=(15, 28), - on_activate_call=self._next_message) - self._translate_button = bui.buttonwidget(parent=self._root_widget, - size=(55, 47), - label="Trans", + size=(30, 30), + label=babase.charstr(babase.SpecialChar.UP_ARROW), button_type='square', autoselect=True, + position=(15, 57), color=self.bg_color, scale=0.75, - position=(self._width - 28, 35), - on_activate_call=self._translate) + on_activate_call=self._previous_message) + self._next_button = bui.buttonwidget(parent=self._root_widget, + size=(30, 30), + label=babase.charstr(babase.SpecialChar.DOWN_ARROW), + button_type='square', + autoselect=True, + color=self.bg_color, + scale=0.75, + position=(15, 28), + on_activate_call=self._next_message) + self._translate_button = bui.buttonwidget(parent=self._root_widget, + size=(55, 47), + label="Trans", + button_type='square', + autoselect=True, + color=self.bg_color, + scale=0.75, + position=(self._width - 28, 35), + on_activate_call=self._translate) if babase.app.config['copy button']: self._copy_button = bui.buttonwidget(parent=self._root_widget, - size=(15, 15), - label='©', - button_type='backSmall', - autoselect=True, - color=self.bg_color, - position=(self._width - 40, 80), - on_activate_call=self._copy_to_clipboard) + size=(15, 15), + label='©', + button_type='backSmall', + autoselect=True, + color=self.bg_color, + position=(self._width - 40, 80), + on_activate_call=self._copy_to_clipboard) self._ping_button = None try: - info = bs.get_connection_to_host_info().get('name', '') if build_number < 21697 else bs.get_connection_to_host_info_2().name + info = bs.get_connection_to_host_info().get( + 'name', '') if build_number < 21697 else bs.get_connection_to_host_info_2().name if info != '': if babase.app.config['ping button']: self._ping_button = bui.buttonwidget( @@ -1205,40 +1210,40 @@ def __init__(self, origin: Sequence[float] = (0, 0)): iconscale=1.2) if babase.app.config['IP button']: self._ip_port_button = bui.buttonwidget(parent=self._root_widget, - size=(30, 30), - label='IP', - button_type='square', - autoselect=True, - color=self.bg_color, - position=(self._width - 530, - self._height - 100), - on_activate_call=self._ip_port_msg) + size=(30, 30), + label='IP', + button_type='square', + autoselect=True, + color=self.bg_color, + position=(self._width - 530, + self._height - 100), + on_activate_call=self._ip_port_msg) except AttributeError: pass self._settings_button = bui.buttonwidget(parent=self._root_widget, - size=(50, 50), - scale=0.5, - button_type='square', - autoselect=True, - color=self.bg_color, - position=(self._width - 40, self._height - 47), - on_activate_call=self._on_setting_button_press, - icon=bui.gettexture('settingsIcon'), - iconscale=1.2) + size=(50, 50), + scale=0.5, + button_type='square', + autoselect=True, + color=self.bg_color, + position=(self._width - 40, self._height - 47), + on_activate_call=self._on_setting_button_press, + icon=bui.gettexture('settingsIcon'), + iconscale=1.2) self._privatechat_button = bui.buttonwidget(parent=self._root_widget, - size=(50, 50), - scale=0.5, - button_type='square', - autoselect=True, - color=self.bg_color, - position=(self._width - 40, self._height - 80), - on_activate_call=self._on_privatechat_button_press, - icon=bui.gettexture('ouyaOButton'), - iconscale=1.2) + size=(50, 50), + scale=0.5, + button_type='square', + autoselect=True, + color=self.bg_color, + position=(self._width - 40, self._height - 80), + on_activate_call=self._on_privatechat_button_press, + icon=bui.gettexture('ouyaOButton'), + iconscale=1.2) self._name_widgets: List[bui.Widget] = [] self._roster: Optional[List[Dict[str, Any]]] = None self._update_timer = bs.apptimer(1.0, - bs.WeakCall(self._update)) + bs.WeakCall(self._update)) self._update() def on_chat_message(self, msg: str, sent=None) -> None: @@ -1258,20 +1263,20 @@ def _add_msg(self, msg: str, sent=None) -> None: color = (1, 1, 1) maxwidth = self._scroll_width * 0.94 txt = bui.textwidget(parent=self._columnwidget, - text=msg, - h_align='left', - v_align='center', - size=(0, 13), - scale=0.55, - color=color, - maxwidth=maxwidth, - shadow=0.3, - flatness=1.0) + text=msg, + h_align='left', + v_align='center', + size=(0, 13), + scale=0.55, + color=color, + maxwidth=maxwidth, + shadow=0.3, + flatness=1.0) if sent: bui.textwidget(edit=txt, size=(100, 15), - selectable=True, - click_activate=True, - on_activate_call=babase.Call(bui.screenmessage, f'Message sent: {_get_local_time(sent)}')) + selectable=True, + click_activate=True, + on_activate_call=babase.Call(bui.screenmessage, f'Message sent: {_get_local_time(sent)}')) self._chat_texts.append(txt) if len(self._chat_texts) > 40: first = self._chat_texts.pop(0) @@ -1327,8 +1332,8 @@ def _update(self) -> None: bui.textwidget(edit=self._muted_text, color=(1, 1, 1, 0.0)) if self._ping_button: bui.buttonwidget(edit=self._ping_button, - label=f'{_ping}', - textcolor=self._get_ping_color()) + label=f'{_ping}', + textcolor=self._get_ping_color()) # update roster section roster = bs.get_game_roster() @@ -1343,11 +1348,11 @@ def _update(self) -> None: if not self._roster: top_section_height = 60 bui.textwidget(edit=self._empty_str, - text=babase.Lstr(resource=self._r + '.emptyText')) + text=babase.Lstr(resource=self._r + '.emptyText')) bui.scrollwidget(edit=self._scrollwidget, - size=(self._width - 50, - self._height - top_section_height - 110), - position=(30, 80)) + size=(self._width - 50, + self._height - top_section_height - 110), + position=(30, 80)) else: columns = 1 if len( self._roster) == 1 else 2 if len(self._roster) == 2 else 3 @@ -1391,19 +1396,19 @@ def _update(self) -> None: 'Error calcing client name str.') p_str = '???' widget = bui.textwidget(parent=self._root_widget, - position=(pos[0], pos[1]), - scale=t_scale, - size=(c_width * 0.85, 30), - maxwidth=c_width * 0.85, - color=(1, 1, - 1) if index == 0 else - (1, 1, 1), - selectable=True, - autoselect=True, - click_activate=True, - text=babase.Lstr(value=p_str), - h_align='left', - v_align='center') + position=(pos[0], pos[1]), + scale=t_scale, + size=(c_width * 0.85, 30), + maxwidth=c_width * 0.85, + color=(1, 1, + 1) if index == 0 else + (1, 1, 1), + selectable=True, + autoselect=True, + click_activate=True, + text=babase.Lstr(value=p_str), + h_align='left', + v_align='center') self._name_widgets.append(widget) # in newer versions client_id will be present and @@ -1420,10 +1425,10 @@ def _update(self) -> None: # calls; not spec-string (perhaps should wait till # client_id is more readily available though). bui.textwidget(edit=widget, - on_activate_call=babase.Call( - self._on_party_member_press, - self._roster[index]['client_id'], - is_host, widget)) + on_activate_call=babase.Call( + self._on_party_member_press, + self._roster[index]['client_id'], + is_host, widget)) pos = (self._width * 0.53 - c_width_total * 0.5 + c_width * x, self._height - 65 - c_height * y) @@ -1448,16 +1453,16 @@ def _update(self) -> None: maxwidth=c_width * 0.96 - twd, color=(0.1, 1, 0.1, 0.5), text=babase.Lstr(resource=self._r + - '.hostText'), + '.hostText'), scale=0.4, shadow=0.1, flatness=1.0)) bui.textwidget(edit=self._empty_str, text='') bui.scrollwidget(edit=self._scrollwidget, - size=(self._width - 50, - max(100, self._height - 139 - - c_height_total)), - position=(30, 80)) + size=(self._width - 50, + max(100, self._height - 139 - + c_height_total)), + position=(30, 80)) else: bui.set_party_window_open(False) for widget in self._name_widgets: @@ -1481,19 +1486,19 @@ def _update(self) -> None: scroll_height = (165 if uiscale is babase.UIScale.SMALL else 280 if uiscale is babase.UIScale.MEDIUM else 400) bui.scrollwidget(edit=self._scrollwidget, - size=(self._width - 50, scroll_height)) + size=(self._width - 50, scroll_height)) for msg in msgs: message = messenger._format_message(msg) self._add_msg(message, msg['sent']) self._filter_text = bui.textwidget(parent=self._root_widget, - scale=0.6, - color=(0.9, 1.0, 0.9), - text='Filter: ', - size=(0, 0), - position=(self._width * 0.3, - self._height - 70), - h_align='center', - v_align='center') + scale=0.6, + color=(0.9, 1.0, 0.9), + text='Filter: ', + size=(0, 0), + position=(self._width * 0.3, + self._height - 70), + h_align='center', + v_align='center') choices = [i for i in messenger.saved_ids] choices_display = [babase.Lstr(value=messenger.saved_ids[i]) for i in messenger.saved_ids] @@ -1521,19 +1526,19 @@ def _update(self) -> None: else: color = (0.9, 1.0, 0.9) self._status_text = bui.textwidget(parent=self._root_widget, - scale=0.5, - color=color, - text=f'Status:\t{user_status}', - size=(200, 30), - position=(self._width * 0.3, - self._height - 110), - h_align='center', - v_align='center', - autoselect=True, - selectable=True, - click_activate=True) + scale=0.5, + color=color, + text=f'Status:\t{user_status}', + size=(200, 30), + position=(self._width * 0.3, + self._height - 110), + h_align='center', + v_align='center', + autoselect=True, + selectable=True, + click_activate=True) bui.textwidget(edit=self._status_text, - on_activate_call=babase.Call(messenger._get_status, messenger.filter, 'last_seen')) + on_activate_call=babase.Call(messenger._get_status, messenger.filter, 'last_seen')) def _change_filter(self, choice): if choice == 'add': @@ -1792,7 +1797,7 @@ def _on_party_member_press(self, client_id: int, is_host: bool, kick_str = babase.Lstr(resource='kickText') else: # kick-votes appeared in build 14248 - if build_number <14248: + if build_number < 14248: return kick_str = babase.Lstr(resource='kickVoteText') uiscale = bui.app.ui_v1.uiscale @@ -1859,8 +1864,9 @@ def _send_chat_message(self) -> None: bs.chatmessage(f"My Unique ID : {myid}") elif msg == '/save': try: - info = bs.get_connection_to_host_info().get('name', '') if build_number < 21697 else bs.get_connection_to_host_info_2().name - config = babase.app.config + info = bs.get_connection_to_host_info().get( + 'name', '') if build_number < 21697 else bs.get_connection_to_host_info_2().name + config = babase.app.config if info != '': title = info['name'] if not isinstance(config.get('Saved Servers'), dict): @@ -1983,7 +1989,8 @@ def _ip_port_msg(self): def ping_server(self): try: - info = bs.get_connection_to_host_info().get('name', '') if build_number < 21697 else bs.get_connection_to_host_info_2().name + info = bs.get_connection_to_host_info().get( + 'name', '') if build_number < 21697 else bs.get_connection_to_host_info_2().name if info != '': self.pingThread = PingThread(_ip, _port) self.pingThread.start() @@ -2091,41 +2098,41 @@ def __init__(self, wtype): uiscale = bui.app.ui_v1.uiscale bg_color = babase.app.config.get('PartyWindow Main Color', (0.5, 0.5, 0.5)) self._root_widget = bui.containerwidget(size=(500, 250), - transition='in_scale', - color=bg_color, - toolbar_visibility='menu_minimal_no_back', - parent=bui.get_special_widget('overlay_stack'), - on_outside_click_call=self._close, - scale=(2.1 if uiscale is babase.UIScale.SMALL else - 1.5 if uiscale is babase.UIScale.MEDIUM else 1.0), - stack_offset=(0, -10) if uiscale is babase.UIScale.SMALL else ( - 240, 0) if uiscale is babase.UIScale.MEDIUM else (330, 20)) + transition='in_scale', + color=bg_color, + toolbar_visibility='menu_minimal_no_back', + parent=bui.get_special_widget('overlay_stack'), + on_outside_click_call=self._close, + scale=(2.1 if uiscale is babase.UIScale.SMALL else + 1.5 if uiscale is babase.UIScale.MEDIUM else 1.0), + stack_offset=(0, -10) if uiscale is babase.UIScale.SMALL else ( + 240, 0) if uiscale is babase.UIScale.MEDIUM else (330, 20)) self._title_text = bui.textwidget(parent=self._root_widget, - scale=0.8, - color=(1, 1, 1), - text=title, - size=(0, 0), - position=(250, 200), - h_align='center', - v_align='center') + scale=0.8, + color=(1, 1, 1), + text=title, + size=(0, 0), + position=(250, 200), + h_align='center', + v_align='center') self._id = bui.textwidget(parent=self._root_widget, - scale=0.5, - color=(1, 1, 1), - text=f'Account: ' + - bui.app.plus.get_v1_account_misc_read_val_2( - 'resolvedAccountID', ''), - size=(0, 0), - position=(220, 170), - h_align='center', - v_align='center') + scale=0.5, + color=(1, 1, 1), + text=f'Account: ' + + bui.app.plus.get_v1_account_misc_read_val_2( + 'resolvedAccountID', ''), + size=(0, 0), + position=(220, 170), + h_align='center', + v_align='center') self._registrationkey_text = bui.textwidget(parent=self._root_widget, - scale=0.5, - color=(1, 1, 1), - text=f'Registration Key:', - size=(0, 0), - position=(100, 140), - h_align='center', - v_align='center') + scale=0.5, + color=(1, 1, 1), + text=f'Registration Key:', + size=(0, 0), + position=(100, 140), + h_align='center', + v_align='center') self._text_field = bui.textwidget( parent=self._root_widget, editable=True, @@ -2138,25 +2145,25 @@ def __init__(self, wtype): v_align='center', corner_scale=0.7) self._connect_button = bui.buttonwidget(parent=self._root_widget, - size=(150, 30), - color=(0, 1, 0), - label='Get Registration Key', - button_type='square', - autoselect=True, - position=(150, 80), - on_activate_call=self._connect) + size=(150, 30), + color=(0, 1, 0), + label='Get Registration Key', + button_type='square', + autoselect=True, + position=(150, 80), + on_activate_call=self._connect) self._confirm_button = bui.buttonwidget(parent=self._root_widget, - size=(50, 30), - label=label, - button_type='square', - autoselect=True, - position=(200, 40), - on_activate_call=self._confirmcall) + size=(50, 30), + label=label, + button_type='square', + autoselect=True, + position=(200, 40), + on_activate_call=self._confirmcall) bui.textwidget(edit=self._text_field, on_return_press_call=self._confirm_button.activate) def _close(self): bui.containerwidget(edit=self._root_widget, - transition=('out_scale')) + transition=('out_scale')) def _connect(self): try: @@ -2184,29 +2191,29 @@ def __init__(self): uiscale = bui.app.ui_v1.uiscale bg_color = babase.app.config.get('PartyWindow Main Color', (0.5, 0.5, 0.5)) self._root_widget = bui.containerwidget(size=(500, 250), - transition='in_scale', - color=bg_color, - toolbar_visibility='menu_minimal_no_back', - parent=bui.get_special_widget('overlay_stack'), - on_outside_click_call=self._close, - scale=(2.1 if uiscale is babase.UIScale.SMALL else - 1.5 if uiscale is babase.UIScale.MEDIUM else 1.0)) + transition='in_scale', + color=bg_color, + toolbar_visibility='menu_minimal_no_back', + parent=bui.get_special_widget('overlay_stack'), + on_outside_click_call=self._close, + scale=(2.1 if uiscale is babase.UIScale.SMALL else + 1.5 if uiscale is babase.UIScale.MEDIUM else 1.0)) self._title_text = bui.textwidget(parent=self._root_widget, - scale=0.8, - color=(1, 1, 1), - text='Add New ID', - size=(0, 0), - position=(250, 200), - h_align='center', - v_align='center') + scale=0.8, + color=(1, 1, 1), + text='Add New ID', + size=(0, 0), + position=(250, 200), + h_align='center', + v_align='center') self._accountid_text = bui.textwidget(parent=self._root_widget, - scale=0.6, - color=(1, 1, 1), - text='pb-id: ', - size=(0, 0), - position=(50, 155), - h_align='center', - v_align='center') + scale=0.6, + color=(1, 1, 1), + text='pb-id: ', + size=(0, 0), + position=(50, 155), + h_align='center', + v_align='center') self._accountid_field = bui.textwidget( parent=self._root_widget, editable=True, @@ -2219,13 +2226,13 @@ def __init__(self): v_align='center', corner_scale=0.7) self._nickname_text = bui.textwidget(parent=self._root_widget, - scale=0.5, - color=(1, 1, 1), - text='Nickname: ', - size=(0, 0), - position=(50, 115), - h_align='center', - v_align='center') + scale=0.5, + color=(1, 1, 1), + text='Nickname: ', + size=(0, 0), + position=(50, 115), + h_align='center', + v_align='center') self._nickname_field = bui.textwidget( parent=self._root_widget, editable=True, @@ -2238,30 +2245,30 @@ def __init__(self): v_align='center', corner_scale=0.7) self._help_text = bui.textwidget(parent=self._root_widget, - scale=0.4, - color=(0.1, 0.9, 0.9), - text='Help:\nEnter pb-id of account you\n want to chat to\nEnter nickname of id to\n recognize id easily\nLeave nickname \n to use their default name', - size=(0, 0), - position=(325, 120), - h_align='left', - v_align='center') + scale=0.4, + color=(0.1, 0.9, 0.9), + text='Help:\nEnter pb-id of account you\n want to chat to\nEnter nickname of id to\n recognize id easily\nLeave nickname \n to use their default name', + size=(0, 0), + position=(325, 120), + h_align='left', + v_align='center') self._add = bui.buttonwidget(parent=self._root_widget, - size=(50, 30), - label='Add', - button_type='square', - autoselect=True, - position=(100, 50), - on_activate_call=babase.Call(self._relay_function)) + size=(50, 30), + label='Add', + button_type='square', + autoselect=True, + position=(100, 50), + on_activate_call=babase.Call(self._relay_function)) bui.textwidget(edit=self._accountid_field, on_return_press_call=self._add.activate) self._remove = bui.buttonwidget(parent=self._root_widget, - size=(75, 30), - label='Remove', - button_type='square', - autoselect=True, - position=(170, 50), - on_activate_call=self._remove_id) + size=(75, 30), + label='Remove', + button_type='square', + autoselect=True, + position=(170, 50), + on_activate_call=self._remove_id) bui.containerwidget(edit=self._root_widget, - on_cancel_call=self._close) + on_cancel_call=self._close) def _relay_function(self): account_id = bui.textwidget(query=self._accountid_field) @@ -2300,7 +2307,7 @@ def popup_menu_closing(self, popup_window: PopupWindow) -> None: def _close(self): bui.containerwidget(edit=self._root_widget, - transition=('out_scale')) + transition=('out_scale')) class AddNewChoiceWindow: @@ -2308,23 +2315,23 @@ def __init__(self): uiscale = bui.app.ui_v1.uiscale bg_color = babase.app.config.get('PartyWindow Main Color', (0.5, 0.5, 0.5)) self._root_widget = bui.containerwidget(size=(500, 250), - transition='in_scale', - color=bg_color, - toolbar_visibility='menu_minimal_no_back', - parent=bui.get_special_widget('overlay_stack'), - on_outside_click_call=self._close, - scale=(2.1 if uiscale is babase.UIScale.SMALL else - 1.5 if uiscale is babase.UIScale.MEDIUM else 1.0), - stack_offset=(0, -10) if uiscale is babase.UIScale.SMALL else ( - 240, 0) if uiscale is babase.UIScale.MEDIUM else (330, 20)) + transition='in_scale', + color=bg_color, + toolbar_visibility='menu_minimal_no_back', + parent=bui.get_special_widget('overlay_stack'), + on_outside_click_call=self._close, + scale=(2.1 if uiscale is babase.UIScale.SMALL else + 1.5 if uiscale is babase.UIScale.MEDIUM else 1.0), + stack_offset=(0, -10) if uiscale is babase.UIScale.SMALL else ( + 240, 0) if uiscale is babase.UIScale.MEDIUM else (330, 20)) self._title_text = bui.textwidget(parent=self._root_widget, - scale=0.8, - color=(1, 1, 1), - text='Add Custom Command', - size=(0, 0), - position=(250, 200), - h_align='center', - v_align='center') + scale=0.8, + color=(1, 1, 1), + text='Add Custom Command', + size=(0, 0), + position=(250, 200), + h_align='center', + v_align='center') self._text_field = bui.textwidget( parent=self._root_widget, editable=True, @@ -2337,30 +2344,30 @@ def __init__(self): v_align='center', corner_scale=0.7) self._help_text = bui.textwidget(parent=self._root_widget, - scale=0.4, - color=(0.2, 0.2, 0.2), - text='Use\n$c = client id\n$a = account id\n$n = name', - size=(0, 0), - position=(70, 75), - h_align='left', - v_align='center') + scale=0.4, + color=(0.2, 0.2, 0.2), + text='Use\n$c = client id\n$a = account id\n$n = name', + size=(0, 0), + position=(70, 75), + h_align='left', + v_align='center') self._add = bui.buttonwidget(parent=self._root_widget, - size=(50, 30), - label='Add', - button_type='square', - autoselect=True, - position=(150, 50), - on_activate_call=self._add_choice) + size=(50, 30), + label='Add', + button_type='square', + autoselect=True, + position=(150, 50), + on_activate_call=self._add_choice) bui.textwidget(edit=self._text_field, on_return_press_call=self._add.activate) self._remove = bui.buttonwidget(parent=self._root_widget, - size=(50, 30), - label='Remove', - button_type='square', - autoselect=True, - position=(350, 50), - on_activate_call=self._remove_custom_command) + size=(50, 30), + label='Remove', + button_type='square', + autoselect=True, + position=(350, 50), + on_activate_call=self._remove_custom_command) bui.containerwidget(edit=self._root_widget, - on_cancel_call=self._close) + on_cancel_call=self._close) def _add_choice(self): newCommand = bui.textwidget(query=self._text_field) @@ -2402,7 +2409,7 @@ def popup_menu_closing(self, popup_window: PopupWindow) -> None: def _close(self): bui.containerwidget(edit=self._root_widget, - transition=('out_scale')) + transition=('out_scale')) class Manual_camera_window: @@ -2412,63 +2419,63 @@ def __init__(self): size=(0, 0)) button_size = (30, 30) self._title_text = bui.textwidget(parent=self._root_widget, - scale=0.9, - color=(1, 1, 1), - text='Manual Camera Setup', - size=(0, 0), - position=(130, 153), - h_align='center', - v_align='center') + scale=0.9, + color=(1, 1, 1), + text='Manual Camera Setup', + size=(0, 0), + position=(130, 153), + h_align='center', + v_align='center') self._xminus = bui.buttonwidget(parent=self._root_widget, + size=button_size, + label=babase.charstr(babase.SpecialChar.LEFT_ARROW), + button_type='square', + autoselect=True, + position=(1, 60), + on_activate_call=babase.Call(self._change_camera_position, 'x-')) + self._xplus = bui.buttonwidget(parent=self._root_widget, size=button_size, - label=babase.charstr(babase.SpecialChar.LEFT_ARROW), + label=babase.charstr(babase.SpecialChar.RIGHT_ARROW), button_type='square', autoselect=True, - position=(1, 60), - on_activate_call=babase.Call(self._change_camera_position, 'x-')) - self._xplus = bui.buttonwidget(parent=self._root_widget, - size=button_size, - label=babase.charstr(babase.SpecialChar.RIGHT_ARROW), - button_type='square', - autoselect=True, - position=(60, 60), - on_activate_call=babase.Call(self._change_camera_position, 'x')) + position=(60, 60), + on_activate_call=babase.Call(self._change_camera_position, 'x')) self._yplus = bui.buttonwidget(parent=self._root_widget, - size=button_size, - label=babase.charstr(babase.SpecialChar.UP_ARROW), - button_type='square', - autoselect=True, - position=(30, 100), - on_activate_call=babase.Call(self._change_camera_position, 'y')) - self._yminus = bui.buttonwidget(parent=self._root_widget, size=button_size, - label=babase.charstr(babase.SpecialChar.DOWN_ARROW), + label=babase.charstr(babase.SpecialChar.UP_ARROW), button_type='square', autoselect=True, - position=(30, 20), - on_activate_call=babase.Call(self._change_camera_position, 'y-')) + position=(30, 100), + on_activate_call=babase.Call(self._change_camera_position, 'y')) + self._yminus = bui.buttonwidget(parent=self._root_widget, + size=button_size, + label=babase.charstr(babase.SpecialChar.DOWN_ARROW), + button_type='square', + autoselect=True, + position=(30, 20), + on_activate_call=babase.Call(self._change_camera_position, 'y-')) self.inwards = bui.buttonwidget(parent=self._root_widget, - size=(100, 30), - label='INWARDS', - button_type='square', - autoselect=True, - position=(120, 90), - on_activate_call=babase.Call(self._change_camera_position, 'z-')) + size=(100, 30), + label='INWARDS', + button_type='square', + autoselect=True, + position=(120, 90), + on_activate_call=babase.Call(self._change_camera_position, 'z-')) self._outwards = bui.buttonwidget(parent=self._root_widget, - size=(100, 30), - label='OUTWARDS', - button_type='square', - autoselect=True, - position=(120, 50), - on_activate_call=babase.Call(self._change_camera_position, 'z')) + size=(100, 30), + label='OUTWARDS', + button_type='square', + autoselect=True, + position=(120, 50), + on_activate_call=babase.Call(self._change_camera_position, 'z')) self._step_text = bui.textwidget(parent=self._root_widget, - scale=0.5, - color=(1, 1, 1), - text='Step:', - size=(0, 0), - position=(1, -20), - h_align='center', - v_align='center') + scale=0.5, + color=(1, 1, 1), + text='Step:', + size=(0, 0), + position=(1, -20), + h_align='center', + v_align='center') self._text_field = bui.textwidget( parent=self._root_widget, editable=True, @@ -2481,25 +2488,25 @@ def __init__(self): v_align='center', corner_scale=0.7) self._reset = bui.buttonwidget(parent=self._root_widget, + size=(50, 30), + label='Reset', + button_type='square', + autoselect=True, + position=(120, -35), + on_activate_call=babase.Call(self._change_camera_position, 'reset')) + self._done = bui.buttonwidget(parent=self._root_widget, size=(50, 30), - label='Reset', + label='Done', button_type='square', autoselect=True, - position=(120, -35), - on_activate_call=babase.Call(self._change_camera_position, 'reset')) - self._done = bui.buttonwidget(parent=self._root_widget, - size=(50, 30), - label='Done', - button_type='square', - autoselect=True, - position=(180, -35), - on_activate_call=self._close) + position=(180, -35), + on_activate_call=self._close) bui.containerwidget(edit=self._root_widget, - cancel_button=self._done) + cancel_button=self._done) def _close(self): bui.containerwidget(edit=self._root_widget, - transition=('out_scale')) + transition=('out_scale')) def _change_camera_position(self, direction): activity = bs.get_foreground_host_activity() @@ -2604,14 +2611,14 @@ def __popup_menu_window_init__(self, min( maxwidth, _babase.get_string_width(choice_display_name, - suppress_warning=True)) + 75) + suppress_warning=True)) + 75) else: self._width = max( self._width, min( maxwidth, _babase.get_string_width(choice_display_name, - suppress_warning=True)) + 60) + suppress_warning=True)) + 60) # init parent class - this will rescale and reposition things as # needed and create our root widget @@ -2623,23 +2630,23 @@ def __popup_menu_window_init__(self, if self._use_scroll: self._scrollwidget = bui.scrollwidget(parent=self.root_widget, - position=(20, 20), - highlight=False, - color=(0.35, 0.55, 0.15), - size=(self._width - 40, - self._height - 40)) + position=(20, 20), + highlight=False, + color=(0.35, 0.55, 0.15), + size=(self._width - 40, + self._height - 40)) self._columnwidget = bui.columnwidget(parent=self._scrollwidget, - border=2, - margin=0) + border=2, + margin=0) else: self._offset_widget = bui.containerwidget(parent=self.root_widget, - position=(30, 15), - size=(self._width - 40, - self._height), - background=False) + position=(30, 15), + size=(self._width - 40, + self._height), + background=False) self._columnwidget = bui.columnwidget(parent=self._offset_widget, - border=2, - margin=0) + border=2, + margin=0) for index, choice in enumerate(choices): if len(choices_display_fin) == len(choices): choice_display_name = choices_display_fin[index] @@ -2647,23 +2654,23 @@ def __popup_menu_window_init__(self, choice_display_name = choice inactive = (choice in self._choices_disabled) wdg = bui.textwidget(parent=self._columnwidget, - size=(self._width - 40, 28), - on_select_call=babase.Call(self._select, index), - click_activate=True, - color=(0.5, 0.5, 0.5, 0.5) if inactive else - ((0.5, 1, 0.5, + size=(self._width - 40, 28), + on_select_call=babase.Call(self._select, index), + click_activate=True, + color=(0.5, 0.5, 0.5, 0.5) if inactive else + ((0.5, 1, 0.5, 1) if choice == self._current_choice else - (0.8, 0.8, 0.8, 1.0)), - padding=0, - maxwidth=maxwidth, - text=choice_display_name, - on_activate_call=self._activate, - v_align='center', - selectable=(not inactive)) + (0.8, 0.8, 0.8, 1.0)), + padding=0, + maxwidth=maxwidth, + text=choice_display_name, + on_activate_call=self._activate, + v_align='center', + selectable=(not inactive)) if choice == self._current_choice: bui.containerwidget(edit=self._columnwidget, - selected_child=wdg, - visible_child=wdg) + selected_child=wdg, + visible_child=wdg) # ok from now on our delegate can be called self._delegate = weakref.ref(delegate) @@ -2745,6 +2752,7 @@ def _get_store_char_tex(self) -> str: 'storeCharacterEaster' if bui.app.plus.get_v1_account_misc_read_val( 'easter', False) else 'storeCharacter') + class NewMainMenuWindow(mainmenu.MainMenuWindow): def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) @@ -2752,6 +2760,8 @@ def __init__(self, *args, **kwargs): bui.set_party_icon_always_visible(True) # ba_meta export plugin + + class InitalRun(babase.Plugin): def __init__(self): if build_number >= 21140: From 910c27261331fb372dccf350375b1595b7418cdc Mon Sep 17 00:00:00 2001 From: brostosjoined Date: Thu, 18 Jan 2024 13:41:13 +0000 Subject: [PATCH 0802/1464] [ci] apply-version-metadata --- plugins/minigames.json | 112 +++++++++++++++++++++++++++++++++++------ plugins/utilities.json | 112 +++++++++++++++++++++++++++++++++++------ 2 files changed, 192 insertions(+), 32 deletions(-) diff --git a/plugins/minigames.json b/plugins/minigames.json index e3ad0927..a8252b02 100644 --- a/plugins/minigames.json +++ b/plugins/minigames.json @@ -77,7 +77,12 @@ } ], "versions": { - "1.0.1": null, + "1.0.1": { + "api_version": 8, + "commit_sha": "87b302a", + "released_on": "18-01-2024", + "md5sum": "3b55e82dc1c1d4d84760c23098233e30" + }, "1.0.0": { "api_version": 7, "commit_sha": "2fda676", @@ -97,7 +102,12 @@ } ], "versions": { - "1.0.1": null, + "1.0.1": { + "api_version": 8, + "commit_sha": "87b302a", + "released_on": "18-01-2024", + "md5sum": "74d61a487379d163c3f5713f001ec69d" + }, "1.0.0": { "api_version": 7, "commit_sha": "2fda676", @@ -117,7 +127,12 @@ } ], "versions": { - "1.0.1": null, + "1.0.1": { + "api_version": 8, + "commit_sha": "87b302a", + "released_on": "18-01-2024", + "md5sum": "25f9018fdc70173212e436d4e7c41e97" + }, "1.0.0": { "api_version": 7, "commit_sha": "2fda676", @@ -137,7 +152,12 @@ } ], "versions": { - "1.0.1": null, + "1.0.1": { + "api_version": 8, + "commit_sha": "87b302a", + "released_on": "18-01-2024", + "md5sum": "4630220820b08642e9c72f9f24675298" + }, "1.0.0": { "api_version": 7, "commit_sha": "2fda676", @@ -182,7 +202,12 @@ } ], "versions": { - "1.1.0": null, + "1.1.0": { + "api_version": 8, + "commit_sha": "87b302a", + "released_on": "18-01-2024", + "md5sum": "6c90c97151c31d240a760590c56d7dbf" + }, "1.0.1": { "api_version": 7, "commit_sha": "d511c15", @@ -208,12 +233,17 @@ } ], "versions": { - "1.0.0": null, "2.0.0": { "api_version": 7, "commit_sha": "8b257b3", "released_on": "22-10-2022", "md5sum": "4f99e4594cac5a9df137faa257f919dc" + }, + "1.0.0": { + "api_version": 8, + "commit_sha": "87b302a", + "released_on": "18-01-2024", + "md5sum": "e83ad2929caf883c24e2e81c93c39d4f" } } }, @@ -334,7 +364,12 @@ } ], "versions": { - "1.0.1": null, + "1.0.1": { + "api_version": 8, + "commit_sha": "87b302a", + "released_on": "18-01-2024", + "md5sum": "48f0768fe1715825e61c66f78dde51c4" + }, "1.0.0": { "api_version": 7, "commit_sha": "0841b9e", @@ -384,7 +419,12 @@ } ], "versions": { - "1.0.1": null, + "1.0.1": { + "api_version": 8, + "commit_sha": "87b302a", + "released_on": "18-01-2024", + "md5sum": "3730cdc9f922ac5a8c86e2c7debd09fe" + }, "1.0.0": { "api_version": 7, "commit_sha": "52094fc", @@ -429,7 +469,12 @@ } ], "versions": { - "1.0.1": null, + "1.0.1": { + "api_version": 8, + "commit_sha": "87b302a", + "released_on": "18-01-2024", + "md5sum": "a1d2d75303aaeb0b078a4c836d65ebee" + }, "1.0.0": { "api_version": 7, "commit_sha": "2aa1e50", @@ -468,7 +513,12 @@ } ], "versions": { - "1.0.1": null, + "1.0.1": { + "api_version": 8, + "commit_sha": "87b302a", + "released_on": "18-01-2024", + "md5sum": "3a99f089fda47e034b16e7fa086ee051" + }, "1.0.0": { "api_version": 7, "commit_sha": "2aa1e50", @@ -488,7 +538,12 @@ } ], "versions": { - "1.0.1": null, + "1.0.1": { + "api_version": 8, + "commit_sha": "87b302a", + "released_on": "18-01-2024", + "md5sum": "627390f50e18bd76d94abf35f538ec8f" + }, "1.0.0": { "api_version": 7, "commit_sha": "52094fc", @@ -599,7 +654,12 @@ } ], "versions": { - "1.0.1": null, + "1.0.1": { + "api_version": 8, + "commit_sha": "87b302a", + "released_on": "18-01-2024", + "md5sum": "7e741a7f4c1ace1124d8719a009f8948" + }, "1.0.0": { "api_version": 7, "commit_sha": "7219487", @@ -619,7 +679,12 @@ } ], "versions": { - "1.0.1": null, + "1.0.1": { + "api_version": 8, + "commit_sha": "87b302a", + "released_on": "18-01-2024", + "md5sum": "270961a492432e6199dec2d0915d8acf" + }, "1.0.0": { "api_version": 7, "commit_sha": "7219487", @@ -639,7 +704,12 @@ } ], "versions": { - "1.0.1": null, + "1.0.1": { + "api_version": 8, + "commit_sha": "87b302a", + "released_on": "18-01-2024", + "md5sum": "3fb424583f1e686854fe94bd22c5161c" + }, "1.0.0": { "api_version": 7, "commit_sha": "7219487", @@ -659,7 +729,12 @@ } ], "versions": { - "1.0.1": null, + "1.0.1": { + "api_version": 8, + "commit_sha": "87b302a", + "released_on": "18-01-2024", + "md5sum": "7e70fb037b49b183a9fb4eaa2babb90e" + }, "1.0.0": { "api_version": 7, "commit_sha": "7219487", @@ -679,7 +754,12 @@ } ], "versions": { - "1.0.1": null, + "1.0.1": { + "api_version": 8, + "commit_sha": "87b302a", + "released_on": "18-01-2024", + "md5sum": "febeeb370ac150f455ed27bc9d557d75" + }, "1.0.0": { "api_version": 7, "commit_sha": "7219487", diff --git a/plugins/utilities.json b/plugins/utilities.json index cccabfad..41cc663e 100644 --- a/plugins/utilities.json +++ b/plugins/utilities.json @@ -19,7 +19,12 @@ } ], "versions": { - "1.0.1": null, + "1.0.1": { + "api_version": 8, + "commit_sha": "87b302a", + "released_on": "18-01-2024", + "md5sum": "f81810220b0cc13cc436434014fbe8de" + }, "1.0.0": { "api_version": 7, "commit_sha": "2454845", @@ -107,7 +112,12 @@ } ], "versions": { - "1.0.1": null, + "1.0.1": { + "api_version": 8, + "commit_sha": "87b302a", + "released_on": "18-01-2024", + "md5sum": "beab6387e86bd842ffc8c857750b510e" + }, "1.0.0": { "api_version": 7, "commit_sha": "2fda676", @@ -127,7 +137,12 @@ } ], "versions": { - "1.0.1": null, + "1.0.1": { + "api_version": 8, + "commit_sha": "87b302a", + "released_on": "18-01-2024", + "md5sum": "80f8fd9e9bd23d33daace0059029378b" + }, "1.0.0": { "api_version": 7, "commit_sha": "2fda676", @@ -166,7 +181,12 @@ } ], "versions": { - "1.0.1": null, + "1.0.1": { + "api_version": 8, + "commit_sha": "87b302a", + "released_on": "18-01-2024", + "md5sum": "ee8187a63d9e205f0355aa5c21141af2" + }, "1.0.0": { "api_version": 7, "commit_sha": "fed7c24", @@ -191,7 +211,12 @@ } ], "versions": { - "1.0.1": null, + "1.0.1": { + "api_version": 8, + "commit_sha": "87b302a", + "released_on": "18-01-2024", + "md5sum": "ee666a289e34c7ceca1d64ed977de4ce" + }, "1.0.0": { "api_version": 7, "commit_sha": "2fda676", @@ -211,7 +236,12 @@ } ], "versions": { - "1.2.3": null, + "1.2.3": { + "api_version": 8, + "commit_sha": "87b302a", + "released_on": "18-01-2024", + "md5sum": "6601d41f60b276d54770c0718158e701" + }, "1.2.2": { "api_version": 7, "commit_sha": "7753b87", @@ -476,7 +506,12 @@ } ], "versions": { - "1.0.1": null, + "1.0.1": { + "api_version": 8, + "commit_sha": "87b302a", + "released_on": "18-01-2024", + "md5sum": "68340cb74a1227c70045e26bb1d1e859" + }, "1.0.0": { "api_version": 7, "commit_sha": "6acdea8", @@ -676,7 +711,12 @@ } ], "versions": { - "4.0.1": null, + "4.0.1": { + "api_version": 8, + "commit_sha": "87b302a", + "released_on": "18-01-2024", + "md5sum": "2b2c39e7c1c0779ee810b677ec8f6d7d" + }, "4.0.0": { "api_version": 7, "commit_sha": "a23e8cd", @@ -696,7 +736,12 @@ } ], "versions": { - "3.0.1": null, + "3.0.1": { + "api_version": 8, + "commit_sha": "87b302a", + "released_on": "18-01-2024", + "md5sum": "697f1204f7722f27f2bdbbff3994763c" + }, "3.0.0": { "api_version": 7, "commit_sha": "0841b9e", @@ -716,7 +761,12 @@ } ], "versions": { - "1.0.1": null, + "1.0.1": { + "api_version": 8, + "commit_sha": "87b302a", + "released_on": "18-01-2024", + "md5sum": "7b1dd1432930e6dc198780a134b88c88" + }, "1.0.0": { "api_version": 7, "commit_sha": "0841b9e", @@ -736,7 +786,12 @@ } ], "versions": { - "1.0.1": null, + "1.0.1": { + "api_version": 8, + "commit_sha": "87b302a", + "released_on": "18-01-2024", + "md5sum": "7313a54c35611e9d8f7d0854b6646bc7" + }, "1.0.0": { "api_version": 7, "commit_sha": "0841b9e", @@ -756,7 +811,12 @@ } ], "versions": { - "1.0.1": null, + "1.0.1": { + "api_version": 8, + "commit_sha": "87b302a", + "released_on": "18-01-2024", + "md5sum": "bb75b79a749f26ed359e0fc99f23a958" + }, "1.0.0": { "api_version": 7, "commit_sha": "800125c", @@ -825,7 +885,12 @@ } ], "versions": { - "1.0.1": null, + "1.0.1": { + "api_version": 8, + "commit_sha": "87b302a", + "released_on": "18-01-2024", + "md5sum": "c472b9ba7be0a1f109a757c1c06b25cd" + }, "1.0.0": { "api_version": 7, "commit_sha": "cb2d952", @@ -845,7 +910,12 @@ } ], "versions": { - "1.0.1": null, + "1.0.1": { + "api_version": 8, + "commit_sha": "87b302a", + "released_on": "18-01-2024", + "md5sum": "264b14d7ec65453b74d4680d507fcb4f" + }, "1.0.0": { "api_version": 7, "commit_sha": "05ffa9f", @@ -865,7 +935,12 @@ } ], "versions": { - "1.0.1": null, + "1.0.1": { + "api_version": 8, + "commit_sha": "87b302a", + "released_on": "18-01-2024", + "md5sum": "d4b1c74d4c6e6f893f0b50c4f863720e" + }, "1.0.0": { "api_version": 7, "commit_sha": "3221b3a", @@ -941,7 +1016,12 @@ } ], "versions": { - "1.4.2": null, + "1.4.2": { + "api_version": 8, + "commit_sha": "87b302a", + "released_on": "18-01-2024", + "md5sum": "f60a0fd81c5a367e644a7b9c123af662" + }, "1.4.1": { "api_version": 8, "commit_sha": "48c8abb", From 8e5970bd86486c05cab0c70d0cc6f2be3415329f Mon Sep 17 00:00:00 2001 From: brostosjoined Date: Thu, 18 Jan 2024 16:59:11 +0300 Subject: [PATCH 0803/1464] Maps json --- plugins/maps.json | 1 + 1 file changed, 1 insertion(+) diff --git a/plugins/maps.json b/plugins/maps.json index 7d509ef3..60f0a8b5 100644 --- a/plugins/maps.json +++ b/plugins/maps.json @@ -14,6 +14,7 @@ } ], "versions": { + "1.0.1": null, "1.0.0": { "api_version": 7, "commit_sha": "985e486", From e799daa510ef23d83ec49e35c9b8d58f3ef2fc24 Mon Sep 17 00:00:00 2001 From: brostosjoined Date: Thu, 18 Jan 2024 14:00:41 +0000 Subject: [PATCH 0804/1464] [ci] apply-version-metadata --- plugins/maps.json | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/plugins/maps.json b/plugins/maps.json index 60f0a8b5..6afd9f6a 100644 --- a/plugins/maps.json +++ b/plugins/maps.json @@ -14,7 +14,12 @@ } ], "versions": { - "1.0.1": null, + "1.0.1": { + "api_version": 8, + "commit_sha": "8e5970b", + "released_on": "18-01-2024", + "md5sum": "738e250e43633bafae357ed4b999864a" + }, "1.0.0": { "api_version": 7, "commit_sha": "985e486", From 7d7fc97300f4422b8eed5bed7840dc84ad37cb5b Mon Sep 17 00:00:00 2001 From: brostosjoined Date: Thu, 18 Jan 2024 17:43:43 +0300 Subject: [PATCH 0805/1464] Forgot some --- plugins/minigames.json | 1 + plugins/utilities.json | 1 + 2 files changed, 2 insertions(+) diff --git a/plugins/minigames.json b/plugins/minigames.json index a8252b02..0410e7d6 100644 --- a/plugins/minigames.json +++ b/plugins/minigames.json @@ -798,6 +798,7 @@ } ], "versions": { + "1.0.1": null, "1.0.0": { "api_version": 7, "commit_sha": "7219487", diff --git a/plugins/utilities.json b/plugins/utilities.json index 41cc663e..5f23c402 100644 --- a/plugins/utilities.json +++ b/plugins/utilities.json @@ -836,6 +836,7 @@ } ], "versions": { + "2.1.1": null, "2.1.0": { "api_version": 8, "commit_sha": "dcfe582", From c0fac8061afdd78007f264ae19b5bbe0c829deeb Mon Sep 17 00:00:00 2001 From: brostosjoined Date: Thu, 18 Jan 2024 14:44:49 +0000 Subject: [PATCH 0806/1464] [ci] apply-version-metadata --- plugins/minigames.json | 7 ++++++- plugins/utilities.json | 7 ++++++- 2 files changed, 12 insertions(+), 2 deletions(-) diff --git a/plugins/minigames.json b/plugins/minigames.json index 0410e7d6..93683d18 100644 --- a/plugins/minigames.json +++ b/plugins/minigames.json @@ -798,7 +798,12 @@ } ], "versions": { - "1.0.1": null, + "1.0.1": { + "api_version": 8, + "commit_sha": "5422dd6", + "released_on": "18-01-2024", + "md5sum": "82ffbb28961c57731bd64d4c4add06cd" + }, "1.0.0": { "api_version": 7, "commit_sha": "7219487", diff --git a/plugins/utilities.json b/plugins/utilities.json index 5f23c402..8c32b44a 100644 --- a/plugins/utilities.json +++ b/plugins/utilities.json @@ -836,7 +836,12 @@ } ], "versions": { - "2.1.1": null, + "2.1.1": { + "api_version": 8, + "commit_sha": "5422dd6", + "released_on": "18-01-2024", + "md5sum": "f2b5e4ff71c3952f57957ca3ab0c2e00" + }, "2.1.0": { "api_version": 8, "commit_sha": "dcfe582", From 06d63d907a68caf89fb0cf76a81c3bb5b913183d Mon Sep 17 00:00:00 2001 From: brostosjoined Date: Sat, 20 Jan 2024 22:05:35 +0300 Subject: [PATCH 0807/1464] fix quick custom game --- plugins/utilities/quick_custom_game.py | 309 ++++++++++++++----------- 1 file changed, 168 insertions(+), 141 deletions(-) diff --git a/plugins/utilities/quick_custom_game.py b/plugins/utilities/quick_custom_game.py index a2888206..9b8031f9 100644 --- a/plugins/utilities/quick_custom_game.py +++ b/plugins/utilities/quick_custom_game.py @@ -21,17 +21,17 @@ lang = bs.app.lang.language -if lang == 'Spanish': - custom_txt = 'personalizar...' +if lang == "Spanish": + custom_txt = "personalizar..." else: - custom_txt = 'custom...' + custom_txt = "custom..." -if 'quick_game_button' in babase.app.config: - config = babase.app.config['quick_game_button'] +if "quick_game_button" in babase.app.config: + config = babase.app.config["quick_game_button"] else: - config = {'selected': None, 'config': None} - babase.app.config['quick_game_button'] = config + config = {"selected": None, "config": None} + babase.app.config["quick_game_button"] = config babase.app.config.commit() @@ -43,7 +43,8 @@ def callback(): bs.new_host_session(session) except Exception: from bascenev1lib import mainmenu - babase.print_exception('exception running session', session) + + babase.print_exception("exception running session", session) # Drop back into a main menu session. bs.new_host_session(mainmenu.MainMenuSession) @@ -56,33 +57,31 @@ def callback(): class SimplePlaylist: - - def __init__(self, - settings: dict, - gametype: type[bs.GameActivity]): + def __init__(self, settings: dict, gametype: type[bs.GameActivity]): self.settings = settings self.gametype = gametype def pull_next(self) -> None: - if 'map' not in self.settings['settings']: - settings = dict( - map=self.settings['map'], **self.settings['settings']) + if "map" not in self.settings["settings"]: + settings = dict(map=self.settings["map"], **self.settings["settings"]) else: - settings = self.settings['settings'] + settings = self.settings["settings"] return dict(resolved_type=self.gametype, settings=settings) class CustomSession(FreeForAllSession): - def __init__(self, *args, **kwargs): # pylint: disable=cyclic-import self.use_teams = False self._tutorial_activity_instance = None - bs.Session.__init__(self, depsets=[], - team_names=None, - team_colors=None, - min_players=1, - max_players=self.get_max_players()) + bs.Session.__init__( + self, + depsets=[], + team_names=None, + team_colors=None, + min_players=1, + max_players=self.get_max_players(), + ) self._series_length = 1 self._ffa_series_length = 1 @@ -90,15 +89,14 @@ def __init__(self, *args, **kwargs): # Which game activity we're on. self._game_number = 0 self._playlist = SimplePlaylist(self._config, self._gametype) - config['selected'] = self._gametype.__name__ - config['config'] = self._config + config["selected"] = self._gametype.__name__ + config["config"] = self._config babase.app.config.commit() # Get a game on deck ready to go. self._current_game_spec: Optional[Dict[str, Any]] = None self._next_game_spec: Dict[str, Any] = self._playlist.pull_next() - self._next_game: Type[bs.GameActivity] = ( - self._next_game_spec['resolved_type']) + self._next_game: Type[bs.GameActivity] = self._next_game_spec["resolved_type"] # Go ahead and instantiate the next game we'll # use so it has lots of time to load. @@ -109,8 +107,7 @@ def __init__(self, *args, **kwargs): class SelectGameWindow(PlaylistAddGameWindow): - - def __init__(self, transition: str = 'in_right'): + def __init__(self, transition: str = "in_right"): class EditController: _sessiontype = bs.FreeForAllSession @@ -118,32 +115,44 @@ def get_session_type(self) -> Type[bs.Session]: return self._sessiontype self._editcontroller = EditController() - self._r = 'addGameWindow' + self._r = "addGameWindow" uiscale = bui.app.ui_v1.uiscale self._width = 750 if uiscale is babase.UIScale.SMALL else 650 x_inset = 50 if uiscale is babase.UIScale.SMALL else 0 - self._height = (346 if uiscale is babase.UIScale.SMALL else - 380 if uiscale is babase.UIScale.MEDIUM else 440) + self._height = ( + 346 + if uiscale is babase.UIScale.SMALL + else 380 + if uiscale is babase.UIScale.MEDIUM + else 440 + ) top_extra = 30 if uiscale is babase.UIScale.SMALL else 20 self._scroll_width = 210 self._root_widget = bui.containerwidget( size=(self._width, self._height + top_extra), transition=transition, - scale=(2.17 if uiscale is babase.UIScale.SMALL else - 1.5 if uiscale is babase.UIScale.MEDIUM else 1.0), - stack_offset=(0, 1) if uiscale is babase.UIScale.SMALL else (0, 0)) - - self._back_button = bui.buttonwidget(parent=self._root_widget, - position=(58 + x_inset, - self._height - 53), - size=(165, 70), - scale=0.75, - text_scale=1.2, - label=babase.Lstr(resource='backText'), - autoselect=True, - button_type='back', - on_activate_call=self._back) + scale=( + 2.17 + if uiscale is babase.UIScale.SMALL + else 1.5 + if uiscale is babase.UIScale.MEDIUM + else 1.0 + ), + stack_offset=(0, 1) if uiscale is babase.UIScale.SMALL else (0, 0), + ) + + self._back_button = bui.buttonwidget( + parent=self._root_widget, + position=(58 + x_inset, self._height - 53), + size=(165, 70), + scale=0.75, + text_scale=1.2, + label=babase.Lstr(resource="backText"), + autoselect=True, + button_type="back", + on_activate_call=self._back, + ) self._select_button = select_button = bui.buttonwidget( parent=self._root_widget, position=(self._width - (172 + x_inset), self._height - 50), @@ -151,22 +160,26 @@ def get_session_type(self) -> Type[bs.Session]: size=(160, 60), scale=0.75, text_scale=1.2, - label=babase.Lstr(resource='selectText'), - on_activate_call=self._add) + label=babase.Lstr(resource="selectText"), + on_activate_call=self._add, + ) if bui.app.ui_v1.use_toolbars: - bui.widget(edit=select_button, - right_widget=bui.get_special_widget('party_button')) - - bui.textwidget(parent=self._root_widget, - position=(self._width * 0.5, self._height - 28), - size=(0, 0), - scale=1.0, - text=babase.Lstr(resource=self._r + '.titleText'), - h_align='center', - color=bui.app.ui_v1.title_color, - maxwidth=250, - v_align='center') + bui.widget( + edit=select_button, right_widget=bui.get_special_widget("party_button") + ) + + bui.textwidget( + parent=self._root_widget, + position=(self._width * 0.5, self._height - 28), + size=(0, 0), + scale=1.0, + text=babase.Lstr(resource=self._r + ".titleText"), + h_align="center", + color=bui.app.ui_v1.title_color, + maxwidth=250, + v_align="center", + ) v = self._height - 64 self._selected_title_text = bui.textwidget( @@ -176,8 +189,9 @@ def get_session_type(self) -> Type[bs.Session]: scale=1.0, color=(0.7, 1.0, 0.7, 1.0), maxwidth=self._width - self._scroll_width - 150 - x_inset * 2, - h_align='left', - v_align='center') + h_align="left", + v_align="center", + ) v -= 30 self._selected_description_text = bui.textwidget( @@ -187,111 +201,115 @@ def get_session_type(self) -> Type[bs.Session]: scale=0.7, color=(0.5, 0.8, 0.5, 1.0), maxwidth=self._width - self._scroll_width - 150 - x_inset * 2, - h_align='left') + h_align="left", + ) scroll_height = self._height - 100 v = self._height - 60 - self._scrollwidget = bui.scrollwidget(parent=self._root_widget, - position=(x_inset + 61, - v - scroll_height), - size=(self._scroll_width, - scroll_height), - highlight=False) - bui.widget(edit=self._scrollwidget, - up_widget=self._back_button, - left_widget=self._back_button, - right_widget=select_button) + self._scrollwidget = bui.scrollwidget( + parent=self._root_widget, + position=(x_inset + 61, v - scroll_height), + size=(self._scroll_width, scroll_height), + highlight=False, + ) + bui.widget( + edit=self._scrollwidget, + up_widget=self._back_button, + left_widget=self._back_button, + right_widget=select_button, + ) self._column: Optional[bui.Widget] = None v -= 35 - bui.containerwidget(edit=self._root_widget, - cancel_button=self._back_button, - start_button=select_button) + bui.containerwidget( + edit=self._root_widget, + cancel_button=self._back_button, + start_button=select_button, + ) self._selected_game_type: Optional[Type[bs.GameActivity]] = None - bui.containerwidget(edit=self._root_widget, - selected_child=self._scrollwidget) + bui.containerwidget(edit=self._root_widget, selected_child=self._scrollwidget) self._game_types: list[type[bs.GameActivity]] = [] # Get actual games loading in the bg. - babase.app.meta.load_exported_classes(bs.GameActivity, - self._on_game_types_loaded, - completion_cb_in_bg_thread=True) + babase.app.meta.load_exported_classes( + bs.GameActivity, self._on_game_types_loaded, completion_cb_in_bg_thread=True + ) # Refresh with our initial empty list. We'll refresh again once # game loading is complete. self._refresh() - if config['selected']: + if config["selected"]: for gt in self._game_types: - if gt.__name__ == config['selected']: + if gt.__name__ == config["selected"]: self._refresh(selected=gt) self._set_selected_game_type(gt) - def _refresh(self, - select_get_more_games_button: bool = False, - selected: bool = None) -> None: + def _refresh( + self, select_get_more_games_button: bool = False, selected: bool = None + ) -> None: # from babase.internal import get_game_types if self._column is not None: self._column.delete() - self._column = bui.columnwidget(parent=self._scrollwidget, - border=2, - margin=0) + self._column = bui.columnwidget(parent=self._scrollwidget, border=2, margin=0) for i, gametype in enumerate(self._game_types): def _doit() -> None: if self._select_button: - bs.apptimer(0.1, - self._select_button.activate) - - txt = bui.textwidget(parent=self._column, - position=(0, 0), - size=(self._width - 88, 24), - text=gametype.get_display_string(), - h_align='left', - v_align='center', - color=(0.8, 0.8, 0.8, 1.0), - maxwidth=self._scroll_width * 0.8, - on_select_call=babase.Call( - self._set_selected_game_type, gametype), - always_highlight=True, - selectable=True, - on_activate_call=_doit) + bs.apptimer(0.1, self._select_button.activate) + + txt = bui.textwidget( + parent=self._column, + position=(0, 0), + size=(self._width - 88, 24), + text=gametype.get_display_string(), + h_align="left", + v_align="center", + color=(0.8, 0.8, 0.8, 1.0), + maxwidth=self._scroll_width * 0.8, + on_select_call=babase.Call(self._set_selected_game_type, gametype), + always_highlight=True, + selectable=True, + on_activate_call=_doit, + ) if i == 0: bui.widget(edit=txt, up_widget=self._back_button) self._get_more_games_button = bui.buttonwidget( parent=self._column, autoselect=True, - label=babase.Lstr(resource=self._r + '.getMoreGamesText'), + label=babase.Lstr(resource=self._r + ".getMoreGamesText"), color=(0.54, 0.52, 0.67), textcolor=(0.7, 0.65, 0.7), on_activate_call=self._on_get_more_games_press, - size=(178, 50)) + size=(178, 50), + ) if select_get_more_games_button: - bui.containerwidget(edit=self._column, - selected_child=self._get_more_games_button, - visible_child=self._get_more_games_button) + bui.containerwidget( + edit=self._column, + selected_child=self._get_more_games_button, + visible_child=self._get_more_games_button, + ) def _add(self) -> None: _babase.lock_all_input() # Make sure no more commands happen. bs.apptimer(0.1, _babase.unlock_all_input) gameconfig = {} - if config['selected'] == self._selected_game_type.__name__: - if config['config']: - gameconfig = config['config'] - if 'map' in gameconfig: - gameconfig['settings']['map'] = gameconfig.pop('map') + if config["selected"] == self._selected_game_type.__name__: + if config["config"]: + gameconfig = config["config"] + if "map" in gameconfig: + gameconfig["settings"]["map"] = gameconfig.pop("map") self._selected_game_type.create_settings_ui( - self._editcontroller.get_session_type(), - gameconfig, - self._edit_game_done) + self._editcontroller.get_session_type(), gameconfig, self._edit_game_done + ) def _edit_game_done(self, config: Optional[Dict[str, Any]]) -> None: if config: @@ -299,14 +317,21 @@ def _edit_game_done(self, config: Optional[Dict[str, Any]]) -> None: CustomSession._gametype = self._selected_game_type start_game(CustomSession) else: - bui.app.ui_v1.clear_main_menu_window(transition='out_right') + bui.app.ui_v1.clear_main_menu_window(transition="out_right") bui.app.ui_v1.set_main_menu_window( - SelectGameWindow(transition='in_left').get_root_widget()) + SelectGameWindow(transition="in_left").get_root_widget(), + from_window=None, + ) def _back(self) -> None: - bui.containerwidget(edit=self._root_widget, transition='out_right') + if not self._root_widget or self._root_widget.transitioning_out: + return + + bui.containerwidget(edit=self._root_widget, transition="out_right") bui.app.ui_v1.set_main_menu_window( - PlayWindow(transition='in_left').get_root_widget()) + PlayWindow(transition="in_left").get_root_widget(), + from_window=self._root_widget, + ) PlayWindow._old_init = PlayWindow.__init__ @@ -319,10 +344,14 @@ def __init__(self, *args, **kwargs): height = 550 def do_quick_game() -> None: + if not self._root_widget or self._root_widget.transitioning_out: + return + self._save_state() - bui.containerwidget(edit=self._root_widget, transition='out_left') + bui.containerwidget(edit=self._root_widget, transition="out_left") bui.app.ui_v1.set_main_menu_window( - SelectGameWindow().get_root_widget()) + SelectGameWindow().get_root_widget(), from_window=self._root_widget + ) self._quick_game_button = bui.buttonwidget( parent=self._root_widget, @@ -334,46 +363,44 @@ def do_quick_game() -> None: label=custom_txt, on_activate_call=do_quick_game, color=(0.54, 0.52, 0.67), - textcolor=(0.7, 0.65, 0.7)) + textcolor=(0.7, 0.65, 0.7), + ) self._restore_state() def states(self) -> None: return { - 'Team Games': self._teams_button, - 'Co-op Games': self._coop_button, - 'Free-for-All Games': self._free_for_all_button, - 'Back': self._back_button, - 'Quick Game': self._quick_game_button + "Team Games": self._teams_button, + "Co-op Games": self._coop_button, + "Free-for-All Games": self._free_for_all_button, + "Back": self._back_button, + "Quick Game": self._quick_game_button, } def _save_state(self) -> None: swapped = {v: k for k, v in states(self).items()} if self._root_widget.get_selected_child() in swapped: - bui.app.ui_v1.window_states[ - self.__class__.__name__] = swapped[ - self._root_widget.get_selected_child()] + bui.app.ui_v1.window_states[self.__class__.__name__] = swapped[ + self._root_widget.get_selected_child() + ] else: - babase.print_exception(f'Error saving state for {self}.') + babase.print_exception(f"Error saving state for {self}.") def _restore_state(self) -> None: - if not hasattr(self, '_quick_game_button'): + if not hasattr(self, "_quick_game_button"): return # ensure that our monkey patched init ran if self.__class__.__name__ not in bui.app.ui_v1.window_states: - bui.containerwidget(edit=self._root_widget, - selected_child=self._coop_button) + bui.containerwidget(edit=self._root_widget, selected_child=self._coop_button) return - sel = states(self).get( - bui.app.ui_v1.window_states[self.__class__.__name__], None) + sel = states(self).get(bui.app.ui_v1.window_states[self.__class__.__name__], None) if sel: bui.containerwidget(edit=self._root_widget, selected_child=sel) else: - bui.containerwidget(edit=self._root_widget, - selected_child=self._coop_button) - babase.print_exception(f'Error restoring state for {self}.') + bui.containerwidget(edit=self._root_widget, selected_child=self._coop_button) + babase.print_exception(f"Error restoring state for {self}.") # ba_meta export plugin From c98906f0493b285dc74846364bcffa27e3bd78ff Mon Sep 17 00:00:00 2001 From: brostosjoined Date: Sat, 20 Jan 2024 22:21:09 +0300 Subject: [PATCH 0808/1464] Update share_replays --- plugins/utilities.json | 2 + plugins/utilities/share_replay.py | 123 +++++++++++++++--------------- 2 files changed, 65 insertions(+), 60 deletions(-) diff --git a/plugins/utilities.json b/plugins/utilities.json index 8c32b44a..f9a20a98 100644 --- a/plugins/utilities.json +++ b/plugins/utilities.json @@ -63,6 +63,7 @@ } ], "versions": { + "1.3.2": null, "1.3.1": { "api_version": 7, "commit_sha": "d511c15", @@ -162,6 +163,7 @@ } ], "versions": { + "1.0.1": null, "1.0.0": { "api_version": 7, "commit_sha": "2fda676", diff --git a/plugins/utilities/share_replay.py b/plugins/utilities/share_replay.py index b0a2af34..5bf401fb 100644 --- a/plugins/utilities/share_replay.py +++ b/plugins/utilities/share_replay.py @@ -1,3 +1,4 @@ +# Porting to api 8 made easier by baport.(https://github.com/bombsquad-community/baport) """ Plugin by LoupGarou a.k.a Loup/Soup Discord →ʟօʊքɢǟʀօʊ#3063 @@ -12,7 +13,7 @@ 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 +# ba_meta require api 8 from __future__ import annotations from typing import TYPE_CHECKING, cast if TYPE_CHECKING: @@ -21,19 +22,21 @@ from os import listdir, mkdir, path, sep, remove from shutil import copy, copytree -import ba -import _ba +import babase +import bauiv1 as bui +import bascenev1 as bs +import _babase from enum import Enum -from bastd.ui.tabs import TabRow -from bastd.ui.confirm import ConfirmWindow -from bastd.ui.watch import WatchWindow -from bastd.ui.popup import PopupWindow +from bauiv1lib.tabs import TabRow +from bauiv1lib.confirm import ConfirmWindow +from bauiv1lib.watch import WatchWindow +from bauiv1lib.popup import PopupWindow 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 +internal_dir = _babase.get_replays_dir()+sep +external_dir = path.join(_babase.env()["python_directory_user"], "replays"+sep) +uiscale = bui.app.ui_v1.uiscale # colors pink = (1, 0.2, 0.8) @@ -45,12 +48,12 @@ b_textcolor = (0.75, 0.7, 0.8) -def Print(*args, color=None, top=None): +def Print(*args, color=None): out = "" for arg in args: a = str(arg) out += a - ba.screenmessage(out, color=color, top=top) + bui.screenmessage(out, color=color) def cprint(*args): @@ -58,7 +61,7 @@ def cprint(*args): for arg in args: a = str(arg) out += a - _ba.chatmessage(out) + bs.chatmessage(out) if not path.exists(external_dir): @@ -103,10 +106,10 @@ def _copy(self, selected_replay, tab_id): 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) + Print(selected_replay[0:-4]+" exported", color=pink) else: copy(external_dir+selected_replay, internal_dir+selected_replay) - Print(selected_replay[0:-4]+" imported", top=True, color=green) + Print(selected_replay[0:-4]+" imported", color=green) def delete_replay(self, selected_replay, tab_id, cls_inst): if selected_replay is None: @@ -119,7 +122,7 @@ def do_it(): 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) + Print(selected_replay[0:-4]+" was deleted", 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) @@ -137,16 +140,16 @@ class Help(PopupWindow): def __init__(self): self.width = 1200 self.height = 250 - self.root_widget = ba.Window(ba.containerwidget( + self.root_widget = bui.Window(bui.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, + bui.containerwidget(edit=self.root_widget, on_outside_click_call=self.close) + bui.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",) + bui.getsound('swish').play() + bui.containerwidget(edit=self.root_widget, transition="out_right",) class ShareTabUi(WatchWindow): @@ -155,7 +158,7 @@ def __init__(self, root_widget=None): self.selected_replay = None if root_widget is None: - self.root = ba.Window(ba.containerwidget( + self.root = bui.Window(bui.containerwidget( size=(1000, 600), on_outside_click_call=self.close, transition="in_right")).get_root_widget() else: @@ -166,8 +169,8 @@ def __init__(self, root_widget=None): 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)) + bui.textwidget(edit=i, color=(1, 1, 1)) + bui.textwidget(edit=widget, color=(1.0, 1, 0.4)) self.selected_replay = name def on_tab_select(self, tab_id): @@ -177,10 +180,10 @@ def on_tab_select(self, tab_id): if tab_id == MyTabId.INTERNAL: dir_list = listdir(internal_dir) - ba.buttonwidget(edit=self.share_button, label="Export\nReplay") + bui.buttonwidget(edit=self.share_button, label="Export\nReplay") else: dir_list = listdir(external_dir) - ba.buttonwidget(edit=self.share_button, label="Import\nReplay") + bui.buttonwidget(edit=self.share_button, label="Import\nReplay") self.tab_row.update_appearance(tab_id) dir_list = sorted(dir_list) @@ -192,7 +195,7 @@ def on_tab_select(self, tab_id): for i in dir_list: # making textwidgets for all replays height -= 50 a = i - i = ba.textwidget( + i = bui.textwidget( parent=self.scroll2, size=(self._my_replays_scroll_width/t_scale, 30), text=i.split(".")[0], @@ -202,18 +205,18 @@ def on_tab_select(self, tab_id): 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)) + bui.textwidget(edit=i, on_activate_call=babase.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 + x_inset = 100 if uiscale is babase.UIScale.SMALL else 0 scroll_buffer_h = 130 + 2 * x_inset - self._width = 1240 if uiscale is ba.UIScale.SMALL else 1040 + self._width = 1240 if uiscale is babase.UIScale.SMALL else 1040 self._height = ( 578 - if uiscale is ba.UIScale.SMALL + if uiscale is babase.UIScale.SMALL else 670 - if uiscale is ba.UIScale.MEDIUM + if uiscale is babase.UIScale.MEDIUM else 800) self._scroll_width = self._width - scroll_buffer_h self._scroll_height = self._height - 180 @@ -222,49 +225,49 @@ def draw_ui(self): 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 + 680 if uiscale is babase.UIScale.SMALL else 640 ) v = c_height - 30 - b_width = 140 if uiscale is ba.UIScale.SMALL else 178 + b_width = 140 if uiscale is babase.UIScale.SMALL else 178 b_height = ( 107 - if uiscale is ba.UIScale.SMALL + if uiscale is babase.UIScale.SMALL else 142 - if uiscale is ba.UIScale.MEDIUM + if uiscale is babase.UIScale.MEDIUM else 190 ) b_space_extra = ( 0 - if uiscale is ba.UIScale.SMALL + if uiscale is babase.UIScale.SMALL else -2 - if uiscale is ba.UIScale.MEDIUM + if uiscale is babase.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 + if uiscale is babase.UIScale.SMALL else 45 - if uiscale is ba.UIScale.MEDIUM + if uiscale is babase.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 + btnh = 40 if uiscale is babase.UIScale.SMALL else 40 + smlh = 190 if uiscale is babase.UIScale.SMALL else 225 + tscl = 1.0 if uiscale is babase.UIScale.SMALL else 1.2 stab_width = 500 stab_height = 300 stab_h = smlh v -= sub_scroll_height + 23 - scroll = ba.scrollwidget( + scroll = bui.scrollwidget( parent=self.root, position=(smlh, v), size=(sub_scroll_width, sub_scroll_height), ) - self.scroll2 = ba.columnwidget(parent=scroll, + self.scroll2 = bui.columnwidget(parent=scroll, size=(sub_scroll_width, sub_scroll_height)) tabdefs = [(MyTabId.INTERNAL, 'INTERNAL'), (MyTabId.EXTERNAL, "EXTERNAL")] @@ -275,7 +278,7 @@ def draw_ui(self): helpbtn_v = stab_h+stab_width+helpbtn_space+120 helpbtn_h = sub_scroll_height+helpbtn_space - ba.buttonwidget( + bui.buttonwidget( parent=self.root, position=(helpbtn_v, helpbtn_h), size=(35, 35), @@ -287,7 +290,7 @@ def draw_ui(self): on_activate_call=Help) def call_copy(): return CommonUtils._copy(self.selected_replay, self.tab_id) - self.share_button = ba.buttonwidget( + self.share_button = bui.buttonwidget( parent=self.root, size=(b_width, b_height), position=(btnh, btnv), @@ -299,7 +302,7 @@ def call_copy(): return CommonUtils._copy(self.selected_replay, self.tab_id) on_activate_call=call_copy) btnv -= b_height + b_space_extra - sync_button = ba.buttonwidget( + sync_button = bui.buttonwidget( parent=self.root, size=(b_width, b_height), position=(btnh, btnv), @@ -312,12 +315,12 @@ def call_copy(): return CommonUtils._copy(self.selected_replay, self.tab_id) 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( + delete_replay_button = bui.buttonwidget( parent=self.root, size=(b_width, b_height), position=(btnh, btnv), button_type="square", - label=ba.Lstr(resource=self._r + '.deleteReplayButtonText'), + label=babase.Lstr(resource=self._r + '.deleteReplayButtonText'), text_scale=tscl, color=b_color, textcolor=b_textcolor, @@ -326,13 +329,13 @@ def call_delete(): return CommonUtils.delete_replay(self.selected_replay, self.t self.on_tab_select(MyTabId.INTERNAL) def close(self): - ba.playsound(ba.getsound('swish')) - ba.containerwidget(edit=self.root, transition="out_right",) + bui.getsound('swish').play() + bui.containerwidget(edit=self.root, transition="out_right",) # ++++++++++++++++for keyboard navigation++++++++++++++++ - # ba.widget(edit=self.enable_button, up_widget=decrease_button, down_widget=self.lower_text,left_widget=save_button, right_widget=save_button) + # bui.widget(edit=self.enable_button, up_widget=decrease_button, down_widget=self.lower_text,left_widget=save_button, right_widget=save_button) # ---------------------------------------------------------------------------------------------------- @@ -341,7 +344,7 @@ class ShareTab(WatchWindow): @override(WatchWindow) def __init__(self, transition: str | None = 'in_right', - origin_widget: ba.Widget | None = None, + origin_widget: bui.Widget | None = None, oldmethod=None): self.my_tab_container = None self._old___init__(transition, origin_widget) @@ -349,11 +352,11 @@ def __init__(self, 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'),), + babase.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 + uiscale = bui.app.ui_v1.uiscale + x_inset = 100 if uiscale is babase.UIScale.SMALL else 0 tab_buffer_h = 750 + 2 * x_inset self._tab_row = TabRow( self._root_widget, @@ -378,10 +381,10 @@ def _set_tab(self, tab_id, oldfunc=None): 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 + 680 if uiscale is babase.UIScale.SMALL else 640 ) - self.my_tab_container = ba.containerwidget( + self.my_tab_container = bui.containerwidget( parent=self._root_widget, position=(scroll_left, scroll_bottom + (self._scroll_height - c_height) * 0.5,), @@ -395,7 +398,7 @@ def _set_tab(self, tab_id, oldfunc=None): # ba_meta export plugin -class Loup(ba.Plugin): +class Loup(babase.Plugin): def on_app_running(self): WatchWindow.__init__ = ShareTab.__init__ From a0bff952ceefae9c2cceb5c9860b28a93e910968 Mon Sep 17 00:00:00 2001 From: brostosjoined Date: Sat, 20 Jan 2024 19:21:55 +0000 Subject: [PATCH 0809/1464] [ci] auto-format --- plugins/utilities/share_replay.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/plugins/utilities/share_replay.py b/plugins/utilities/share_replay.py index 5bf401fb..424a9121 100644 --- a/plugins/utilities/share_replay.py +++ b/plugins/utilities/share_replay.py @@ -145,7 +145,7 @@ def __init__(self): bui.containerwidget(edit=self.root_widget, on_outside_click_call=self.close) bui.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)") + 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): bui.getsound('swish').play() @@ -268,7 +268,7 @@ def draw_ui(self): ) self.scroll2 = bui.columnwidget(parent=scroll, - size=(sub_scroll_width, sub_scroll_height)) + 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), From 311c1f6d0ea57340f22bee87388c6c9366c9f4cd Mon Sep 17 00:00:00 2001 From: brostosjoined Date: Sat, 20 Jan 2024 19:21:57 +0000 Subject: [PATCH 0810/1464] [ci] apply-version-metadata --- plugins/utilities.json | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/plugins/utilities.json b/plugins/utilities.json index f9a20a98..87a4b332 100644 --- a/plugins/utilities.json +++ b/plugins/utilities.json @@ -63,7 +63,12 @@ } ], "versions": { - "1.3.2": null, + "1.3.2": { + "api_version": 8, + "commit_sha": "a0bff95", + "released_on": "20-01-2024", + "md5sum": "1cf2d07d15dbacf0a277795f3742c14b" + }, "1.3.1": { "api_version": 7, "commit_sha": "d511c15", @@ -163,7 +168,12 @@ } ], "versions": { - "1.0.1": null, + "1.0.1": { + "api_version": 8, + "commit_sha": "a0bff95", + "released_on": "20-01-2024", + "md5sum": "6eb01543b28a9a2c95f873aa92dbe3b2" + }, "1.0.0": { "api_version": 7, "commit_sha": "2fda676", From e85962b13ac5520745775f62d012e3ec9090e64d Mon Sep 17 00:00:00 2001 From: brostos <67740566+brostosjoined@users.noreply.github.com> Date: Sat, 20 Jan 2024 22:26:54 +0300 Subject: [PATCH 0811/1464] remove ultra_party --- plugins/utilities.json | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/plugins/utilities.json b/plugins/utilities.json index 87a4b332..35e0ce5f 100644 --- a/plugins/utilities.json +++ b/plugins/utilities.json @@ -723,12 +723,6 @@ } ], "versions": { - "4.0.1": { - "api_version": 8, - "commit_sha": "87b302a", - "released_on": "18-01-2024", - "md5sum": "2b2c39e7c1c0779ee810b677ec8f6d7d" - }, "4.0.0": { "api_version": 7, "commit_sha": "a23e8cd", @@ -1079,4 +1073,4 @@ } } } -} \ No newline at end of file +} From aea147431a3e29ccadcc946deab85d343d32d624 Mon Sep 17 00:00:00 2001 From: brostosjoined Date: Sat, 20 Jan 2024 19:27:15 +0000 Subject: [PATCH 0812/1464] [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 35e0ce5f..af01c314 100644 --- a/plugins/utilities.json +++ b/plugins/utilities.json @@ -1073,4 +1073,4 @@ } } } -} +} \ No newline at end of file From 1757307106075c13ec3ada3cec3f61099d229487 Mon Sep 17 00:00:00 2001 From: brostos <67740566+brostosjoined@users.noreply.github.com> Date: Sat, 20 Jan 2024 22:28:34 +0300 Subject: [PATCH 0813/1464] Delete plugins/utilities/ultra_party_window.py --- plugins/utilities/ultra_party_window.py | 2782 ----------------------- 1 file changed, 2782 deletions(-) delete mode 100644 plugins/utilities/ultra_party_window.py diff --git a/plugins/utilities/ultra_party_window.py b/plugins/utilities/ultra_party_window.py deleted file mode 100644 index 094e0048..00000000 --- a/plugins/utilities/ultra_party_window.py +++ /dev/null @@ -1,2782 +0,0 @@ -# Porting to api 8 made easier by baport.(https://github.com/bombsquad-community/baport) -__author__ = 'Droopy' -__version__ = 4.0 - -# ba_meta require api 8 -import datetime -import json -import math -import os -import pickle -import random -import time -import urllib.request -import weakref -from threading import Thread -from typing import List, Tuple, Sequence, Optional, Dict, Any, cast -from hashlib import md5 - -import _babase -import babase -import bauiv1 as bui -import bascenev1 as bs -import bauiv1lib.party -from bauiv1lib.colorpicker import ColorPickerExact -from bauiv1lib import mainmenu -from bauiv1lib.confirm import ConfirmWindow -from bauiv1lib.mainmenu import MainMenuWindow -from bauiv1lib.popup import PopupMenuWindow, PopupWindow, PopupMenu -from baenv import TARGET_BALLISTICA_BUILD as build_number - -_ip = '127.0.0.1' -_port = 43210 -_ping = '-' -url = 'http://bombsquadprivatechat.ml' -last_msg = None - -my_directory = _babase.env()['python_directory_user'] + '/UltraPartyWindowFiles/' -quick_msg_file = my_directory + 'QuickMessages.txt' -cookies_file = my_directory + 'cookies.txt' -saved_ids_file = my_directory + 'saved_ids.json' -my_location = my_directory - - -def initialize(): - config_defaults = {'Party Chat Muted': False, - 'Chat Muted': False, - 'ping button': True, - 'IP button': True, - 'copy button': True, - 'Direct Send': False, - 'Colorful Chat': True, - 'Custom Commands': [], - 'Message Notification': 'bottom', - 'Self Status': 'online', - 'Translate Source Language': '', - 'Translate Destination Language': 'en', - 'Pronunciation': True - } - config = babase.app.config - for key in config_defaults: - if key not in config: - config[key] = config_defaults[key] - - if not os.path.exists(my_directory): - os.makedirs(my_directory) - if not os.path.exists(cookies_file): - with open(cookies_file, 'wb') as f: - pickle.dump({}, f) - if not os.path.exists(saved_ids_file): - with open(saved_ids_file, 'w') as f: - data = {} - json.dump(data, f) - - -def display_error(msg=None): - if msg: - bui.screenmessage(msg, (1, 0, 0)) - else: - bui.screenmessage('Failed!', (1, 0, 0)) - bui.getsound('error').play() - - -def display_success(msg=None): - if msg: - bui.screenmessage(msg, (0, 1, 0)) - else: - bui.screenmessage('Successful!', (0, 1, 0)) - - -class Translate(Thread): - def __init__(self, data, callback): - super().__init__() - self.data = data - self._callback = callback - - def run(self): - _babase.pushcall(babase.Call(bui.screenmessage, 'Translating...'), from_other_thread=True) - response = messenger._send_request(f'{url}/translate', self.data) - if response: - _babase.pushcall(babase.Call(self._callback, response), from_other_thread=True) - - -class ColorTracker: - def __init__(self): - self.saved = {} - - def _get_safe_color(self, sender): - while True: - color = (random.random(), random.random(), random.random()) - s = 0 - background = babase.app.config.get('PartyWindow Main Color', (0.5, 0.5, 0.5)) - for i, j in zip(color, background): - s += (i - j) ** 2 - if s > 0.1: - self.saved[sender] = color - if len(self.saved) > 20: - self.saved.pop(list(self.saved.keys())[0]) - break - time.sleep(0.1) - - def _get_sender_color(self, sender): - if sender not in self.saved: - self.thread = Thread(target=self._get_safe_color, args=(sender,)) - self.thread.start() - return (1, 1, 1) - else: - return self.saved[sender] - - -class PrivateChatHandler: - def __init__(self): - self.pvt_msgs = {} - self.login_id = None - self.last_msg_id = None - self.logged_in = False - self.cookieProcessor = urllib.request.HTTPCookieProcessor() - self.opener = urllib.request.build_opener(self.cookieProcessor) - self.filter = 'all' - self.pending_messages = [] - self.friends_status = {} - self.error = '' - Thread(target=self._ping).start() - - def _load_ids(self): - with open(saved_ids_file, 'r') as f: - saved = json.load(f) - if self.myid in saved: - self.saved_ids = saved[self.myid] - else: - self.saved_ids = {'all': ''} - - def _dump_ids(self): - with open(saved_ids_file, 'r') as f: - saved = json.load(f) - with open(saved_ids_file, 'w') as f: - saved[self.myid] = self.saved_ids - json.dump(saved, f) - - def _ping(self): - self.server_online = False - response = self._send_request(url=f'{url}') - if not response: - self.error = 'Server offline' - elif response: - try: - self.server_online = True - version = float(response.replace('v', '')) - except: - self.error = 'Server offline' - - def _signup(self, registration_key): - data = dict(pb_id=self.myid, registration_key=registration_key) - response = self._send_request(url=f'{url}/signup', data=data) - if response: - if response == 'successful': - display_success('Account Created Successfully') - self._login(registration_key=registration_key) - return True - display_error(response) - - def _save_cookie(self): - with open(cookies_file, 'rb') as f: - cookies = pickle.load(f) - with open(cookies_file, 'wb') as f: - for c in self.cookieProcessor.cookiejar: - cookie = pickle.dumps(c) - break - cookies[self.myid] = cookie - pickle.dump(cookies, f) - - def _cookie_login(self): - self.myid = bui.app.plus.get_v1_account_misc_read_val_2('resolvedAccountID', '') - try: - with open(cookies_file, 'rb') as f: - cookies = pickle.load(f) - except: - return False - if self.myid in cookies: - cookie = pickle.loads(cookies[self.myid]) - self.cookieProcessor.cookiejar.set_cookie(cookie) - self.opener = urllib.request.build_opener(self.cookieProcessor) - response = self._send_request(url=f'{url}/login') - if response.startswith('logged in as'): - self.logged_in = True - self._load_ids() - display_success(response) - return True - - def _login(self, registration_key): - self.myid = bui.app.plus.get_v1_account_misc_read_val_2('resolvedAccountID', '') - data = dict(pb_id=self.myid, registration_key=registration_key) - response = self._send_request(url=f'{url}/login', data=data) - if response == 'successful': - self.logged_in = True - self._load_ids() - self._save_cookie() - display_success('Account Logged in Successfully') - return True - else: - display_error(response) - - def _query(self, pb_id=None): - if not pb_id: - pb_id = self.myid - response = self._send_request(url=f'{url}/query/{pb_id}') - if response == 'exists': - return True - return False - - def _send_request(self, url, data=None): - try: - if not data: - response = self.opener.open(url) - else: - response = self.opener.open(url, data=json.dumps(data).encode()) - if response.getcode() != 200: - display_error(response.read().decode()) - return None - else: - return response.read().decode() - except: - return None - - def _save_id(self, account_id, nickname='', verify=True): - # display_success(f'Saving {account_id}. Please wait...') - if verify: - url = 'http://bombsquadgame.com/accountquery?id=' + account_id - response = json.loads(urllib.request.urlopen(url).read().decode()) - if 'error' in response: - display_error('Enter valid account id') - return False - self.saved_ids[account_id] = {} - name = None - if nickname == '': - name_html = response['name_html'] - name = name_html.split('>')[1] - nick = name if name else nickname - else: - nick = nickname - self.saved_ids[account_id] = nick - self._dump_ids() - display_success(f'Account added: {nick}({account_id})') - return True - - def _remove_id(self, account_id): - removed = self.saved_ids.pop(account_id) - self._dump_ids() - bui.screenmessage(f'Removed successfully: {removed}({account_id})', (0, 1, 0)) - bui.getsound('shieldDown').play() - - def _format_message(self, msg): - filter = msg['filter'] - if filter in self.saved_ids: - if self.filter == 'all': - message = '[' + self.saved_ids[filter] + ']' + msg['message'] - else: - message = msg['message'] - else: - message = '[' + msg['filter'] + ']: ' + \ - 'Message from unsaved id. Save id to view message.' - return message - - def _get_status(self, id, type='status'): - info = self.friends_status.get(id, {}) - if not info: - return '-' - if type == 'status': - return info['status'] - else: - last_seen = info["last_seen"] - last_seen = _get_local_time(last_seen) - bui.screenmessage(f'Last seen on: {last_seen}') - - -def _get_local_time(utctime): - d = datetime.datetime.strptime(utctime, '%d-%m-%Y %H:%M:%S') - d = d.replace(tzinfo=datetime.timezone.utc) - d = d.astimezone() - return d.strftime('%B %d,\t\t%H:%M:%S') - - -def update_status(): - if messenger.logged_in: - if babase.app.config['Self Status'] == 'online': - host = bs.get_connection_to_host_info().get( - 'name', '') if build_number < 21697 else bs.get_connection_to_host_info_2().get('name', '') - if host: - my_status = f'Playing in {host}' - else: - my_status = 'in Lobby' - ids_to_check = [i for i in messenger.saved_ids if i != 'all'] - response = messenger._send_request(url=f'{url}/updatestatus', - data=dict(self_status=my_status, ids=ids_to_check)) - if response: - messenger.friends_status = json.loads(response) - else: - messenger.friends_status = {} - - -def messenger_thread(): - counter = 0 - while True: - counter += 1 - time.sleep(0.6) - check_new_message() - if counter > 5: - counter = 0 - update_status() - - -def check_new_message(): - if messenger.logged_in: - if messenger.login_id != messenger.myid: - response = messenger._send_request(f'{url}/first') - if response: - messenger.pvt_msgs = json.loads(response) - if messenger.pvt_msgs['all']: - messenger.last_msg_id = messenger.pvt_msgs['all'][-1]['id'] - messenger.login_id = messenger.myid - else: - response = messenger._send_request(f'{url}/new/{messenger.last_msg_id}') - if response: - new_msgs = json.loads(response) - if new_msgs: - for msg in new_msgs['messages']: - if msg['id'] > messenger.last_msg_id: - messenger.last_msg_id = msg['id'] - messenger.pvt_msgs['all'].append( - dict(id=msg['id'], filter=msg['filter'], message=msg['message'], sent=msg['sent'])) - if len(messenger.pvt_msgs['all']) > 40: - messenger.pvt_msgs['all'].pop(0) - if msg['filter'] not in messenger.pvt_msgs: - messenger.pvt_msgs[msg['filter']] = [ - dict(id=msg['id'], filter=msg['filter'], message=msg['message'], sent=msg['sent'])] - else: - messenger.pvt_msgs[msg['filter']].append( - dict(id=msg['id'], filter=msg['filter'], message=msg['message'], sent=msg['sent'])) - if len(messenger.pvt_msgs[msg['filter']]) > 20: - messenger.pvt_msgs[msg['filter']].pop(0) - messenger.pending_messages.append( - (messenger._format_message(msg), msg['filter'], msg['sent'])) - - -def display_message(msg, msg_type, filter=None, sent=None): - flag = None - notification = babase.app.config['Message Notification'] - if bui.app.ui_v1.party_window: - if bui.app.ui_v1.party_window(): - if bui.app.ui_v1.party_window()._private_chat: - flag = 1 - if msg_type == 'private': - if messenger.filter == filter or messenger.filter == 'all': - bui.app.ui_v1.party_window().on_chat_message(msg, sent) - else: - if notification == 'top': - bui.screenmessage(msg, (1, 1, 0), True, bui.gettexture('coin')) - else: - bui.screenmessage(msg, (1, 1, 0), False) - else: - bui.screenmessage(msg, (0.2, 1.0, 1.0), True, bui.gettexture('circleShadow')) - else: - flag = 1 - if msg_type == 'private': - if notification == 'top': - bui.screenmessage(msg, (1, 1, 0), True, bui.gettexture('coin')) - else: - bui.screenmessage(msg, (1, 1, 0), False) - if not flag: - if msg_type == 'private': - if notification == 'top': - bui.screenmessage(msg, (1, 1, 0), True, bui.gettexture('coin')) - else: - bui.screenmessage(msg, (1, 1, 0), False) - else: - bui.screenmessage(msg, (0.2, 1.0, 1.0), True, bui.gettexture('circleShadow')) - - -def msg_displayer(): - for msg in messenger.pending_messages: - display_message(msg[0], 'private', msg[1], msg[2]) - messenger.pending_messages.remove(msg) - if babase.app.config['Chat Muted'] and not babase.app.config['Party Chat Muted']: - global last_msg - last = bs.get_chat_messages() - lm = last[-1] if last else None - if lm != last_msg: - last_msg = lm - display_message(lm, 'public') - - -class SortQuickMessages: - def __init__(self): - uiscale = bui.app.ui_v1.uiscale - bg_color = babase.app.config.get('PartyWindow Main Color', (0.5, 0.5, 0.5)) - self._width = 750 if uiscale is babase.UIScale.SMALL else 600 - self._height = (300 if uiscale is babase.UIScale.SMALL else - 325 if uiscale is babase.UIScale.MEDIUM else 350) - self._root_widget = bui.containerwidget( - size=(self._width, self._height), - transition='in_right', - on_outside_click_call=self._save, - color=bg_color, - parent=bui.get_special_widget('overlay_stack'), - scale=(2.0 if uiscale is babase.UIScale.SMALL else - 1.3 if uiscale is babase.UIScale.MEDIUM else 1.0), - stack_offset=(0, -16) if uiscale is babase.UIScale.SMALL else (0, 0)) - bui.textwidget(parent=self._root_widget, - position=(-10, self._height - 50), - size=(self._width, 25), - text='Sort Quick Messages', - color=bui.app.ui_v1.title_color, - scale=1.05, - h_align='center', - v_align='center', - maxwidth=270) - b_textcolor = (0.4, 0.75, 0.5) - up_button = bui.buttonwidget(parent=self._root_widget, - position=(10, 170), - size=(75, 75), - on_activate_call=self._move_up, - label=babase.charstr(babase.SpecialChar.UP_ARROW), - button_type='square', - color=bg_color, - textcolor=b_textcolor, - autoselect=True, - repeat=True) - down_button = bui.buttonwidget(parent=self._root_widget, - position=(10, 75), - size=(75, 75), - on_activate_call=self._move_down, - label=babase.charstr(babase.SpecialChar.DOWN_ARROW), - button_type='square', - color=bg_color, - textcolor=b_textcolor, - autoselect=True, - repeat=True) - self._scroll_width = self._width - 150 - self._scroll_height = self._height - 110 - self._scrollwidget = bui.scrollwidget( - parent=self._root_widget, - size=(self._scroll_width, self._scroll_height), - color=bg_color, - position=(100, 40)) - self._columnwidget = bui.columnwidget( - parent=self._scrollwidget, - border=2, - margin=0) - with open(quick_msg_file, 'r') as f: - self.msgs = f.read().split('\n') - self._msg_selected = None - self._refresh() - bui.containerwidget(edit=self._root_widget, - on_cancel_call=self._save) - - def _refresh(self): - for child in self._columnwidget.get_children(): - child.delete() - for msg in enumerate(self.msgs): - txt = bui.textwidget( - parent=self._columnwidget, - size=(self._scroll_width - 10, 30), - selectable=True, - always_highlight=True, - on_select_call=babase.Call(self._on_msg_select, msg), - text=msg[1], - h_align='left', - v_align='center', - maxwidth=self._scroll_width) - if msg == self._msg_selected: - bui.columnwidget(edit=self._columnwidget, - selected_child=txt, - visible_child=txt) - - def _on_msg_select(self, msg): - self._msg_selected = msg - - def _move_up(self): - index = self._msg_selected[0] - msg = self._msg_selected[1] - if index: - self.msgs.insert((index - 1), self.msgs.pop(index)) - self._msg_selected = (index - 1, msg) - self._refresh() - - def _move_down(self): - index = self._msg_selected[0] - msg = self._msg_selected[1] - if index + 1 < len(self.msgs): - self.msgs.insert((index + 1), self.msgs.pop(index)) - self._msg_selected = (index + 1, msg) - self._refresh() - - def _save(self) -> None: - try: - with open(quick_msg_file, 'w') as f: - f.write('\n'.join(self.msgs)) - except: - babase.print_exception() - bui.screenmessage('Error!', (1, 0, 0)) - bui.containerwidget( - edit=self._root_widget, - transition='out_right') - - -class TranslationSettings: - def __init__(self): - uiscale = bui.app.ui_v1.uiscale - height = (300 if uiscale is babase.UIScale.SMALL else - 350 if uiscale is babase.UIScale.MEDIUM else 400) - width = (500 if uiscale is babase.UIScale.SMALL else - 600 if uiscale is babase.UIScale.MEDIUM else 650) - self._transition_out: Optional[str] - scale_origin: Optional[Tuple[float, float]] - self._transition_out = 'out_scale' - scale_origin = 10 - transition = 'in_scale' - scale_origin = None - cancel_is_selected = False - cfg = babase.app.config - bg_color = cfg.get('PartyWindow Main Color', (0.5, 0.5, 0.5)) - - LANGUAGES = { - '': 'Auto-Detect', - 'af': 'afrikaans', - 'sq': 'albanian', - 'am': 'amharic', - 'ar': 'arabic', - 'hy': 'armenian', - 'az': 'azerbaijani', - 'eu': 'basque', - 'be': 'belarusian', - 'bn': 'bengali', - 'bs': 'bosnian', - 'bg': 'bulgarian', - 'ca': 'catalan', - 'ceb': 'cebuano', - 'ny': 'chichewa', - 'zh-cn': 'chinese (simplified)', - 'zh-tw': 'chinese (traditional)', - 'co': 'corsican', - 'hr': 'croatian', - 'cs': 'czech', - 'da': 'danish', - 'nl': 'dutch', - 'en': 'english', - 'eo': 'esperanto', - 'et': 'estonian', - 'tl': 'filipino', - 'fi': 'finnish', - 'fr': 'french', - 'fy': 'frisian', - 'gl': 'galician', - 'ka': 'georgian', - 'de': 'german', - 'el': 'greek', - 'gu': 'gujarati', - 'ht': 'haitian creole', - 'ha': 'hausa', - 'haw': 'hawaiian', - 'iw': 'hebrew', - 'he': 'hebrew', - 'hi': 'hindi', - 'hmn': 'hmong', - 'hu': 'hungarian', - 'is': 'icelandic', - 'ig': 'igbo', - 'id': 'indonesian', - 'ga': 'irish', - 'it': 'italian', - 'ja': 'japanese', - 'jw': 'javanese', - 'kn': 'kannada', - 'kk': 'kazakh', - 'km': 'khmer', - 'ko': 'korean', - 'ku': 'kurdish (kurmanji)', - 'ky': 'kyrgyz', - 'lo': 'lao', - 'la': 'latin', - 'lv': 'latvian', - 'lt': 'lithuanian', - 'lb': 'luxembourgish', - 'mk': 'macedonian', - 'mg': 'malagasy', - 'ms': 'malay', - 'ml': 'malayalam', - 'mt': 'maltese', - 'mi': 'maori', - 'mr': 'marathi', - 'mn': 'mongolian', - 'my': 'myanmar (burmese)', - 'ne': 'nepali', - 'no': 'norwegian', - 'or': 'odia', - 'ps': 'pashto', - 'fa': 'persian', - 'pl': 'polish', - 'pt': 'portuguese', - 'pa': 'punjabi', - 'ro': 'romanian', - 'ru': 'russian', - 'sm': 'samoan', - 'gd': 'scots gaelic', - 'sr': 'serbian', - 'st': 'sesotho', - 'sn': 'shona', - 'sd': 'sindhi', - 'si': 'sinhala', - 'sk': 'slovak', - 'sl': 'slovenian', - 'so': 'somali', - 'es': 'spanish', - 'su': 'sundanese', - 'sw': 'swahili', - 'sv': 'swedish', - 'tg': 'tajik', - 'ta': 'tamil', - 'te': 'telugu', - 'th': 'thai', - 'tr': 'turkish', - 'uk': 'ukrainian', - 'ur': 'urdu', - 'ug': 'uyghur', - 'uz': 'uzbek', - 'vi': 'vietnamese', - 'cy': 'welsh', - 'xh': 'xhosa', - 'yi': 'yiddish', - 'yo': 'yoruba', - 'zu': 'zulu'} - - self.root_widget = bui.containerwidget( - size=(width, height), - color=bg_color, - transition=transition, - toolbar_visibility='menu_minimal_no_back', - parent=bui.get_special_widget('overlay_stack'), - on_outside_click_call=self._cancel, - scale=(2.1 if uiscale is babase.UIScale.SMALL else - 1.5 if uiscale is babase.UIScale.MEDIUM else 1.0), - scale_origin_stack_offset=scale_origin) - bui.textwidget(parent=self.root_widget, - position=(width * 0.5, height - 45), - size=(20, 20), - h_align='center', - v_align='center', - text="Text Translation", - scale=0.9, - color=(5, 5, 5)) - cbtn = btn = bui.buttonwidget(parent=self.root_widget, - autoselect=True, - position=(30, height - 60), - size=(30, 30), - label=babase.charstr(babase.SpecialChar.BACK), - button_type='backSmall', - on_activate_call=self._cancel) - - source_lang_text = bui.textwidget(parent=self.root_widget, - position=(40, height - 110), - size=(20, 20), - h_align='left', - v_align='center', - text="Source Language : ", - scale=0.9, - color=(1, 1, 1)) - - source_lang_menu = PopupMenu( - parent=self.root_widget, - position=(330 if uiscale is babase.UIScale.SMALL else 400, height - 115), - width=200, - scale=(2.8 if uiscale is babase.UIScale.SMALL else - 1.8 if uiscale is babase.UIScale.MEDIUM else 1.2), - current_choice=cfg['Translate Source Language'], - choices=LANGUAGES.keys(), - choices_display=(babase.Lstr(value=i) for i in LANGUAGES.values()), - button_size=(130, 35), - on_value_change_call=self._change_source) - - destination_lang_text = bui.textwidget(parent=self.root_widget, - position=(40, height - 165), - size=(20, 20), - h_align='left', - v_align='center', - text="Destination Language : ", - scale=0.9, - color=(1, 1, 1)) - - destination_lang_menu = PopupMenu( - parent=self.root_widget, - position=(330 if uiscale is babase.UIScale.SMALL else 400, height - 170), - width=200, - scale=(2.8 if uiscale is babase.UIScale.SMALL else - 1.8 if uiscale is babase.UIScale.MEDIUM else 1.2), - current_choice=cfg['Translate Destination Language'], - choices=list(LANGUAGES.keys())[1:], - choices_display=list(babase.Lstr(value=i) for i in LANGUAGES.values())[1:], - button_size=(130, 35), - on_value_change_call=self._change_destination) - - try: - - translation_mode_text = bui.textwidget(parent=self.root_widget, - position=(40, height - 215), - size=(20, 20), - h_align='left', - v_align='center', - text="Translate Mode", - scale=0.9, - color=(1, 1, 1)) - decoration = bui.textwidget(parent=self.root_widget, - position=(40, height - 225), - size=(20, 20), - h_align='left', - v_align='center', - text="________________", - scale=0.9, - color=(1, 1, 1)) - - language_char_text = bui.textwidget(parent=self.root_widget, - position=(85, height - 273), - size=(20, 20), - h_align='left', - v_align='center', - text='Normal Translation', - scale=0.6, - color=(1, 1, 1)) - - pronunciation_text = bui.textwidget(parent=self.root_widget, - position=(295, height - 273), - size=(20, 20), - h_align='left', - v_align='center', - text="Show Prononciation", - scale=0.6, - color=(1, 1, 1)) - - from bauiv1lib.radiogroup import make_radio_group - cur_val = babase.app.config.get('Pronunciation', True) - cb1 = bui.checkboxwidget( - parent=self.root_widget, - position=(250, height - 275), - size=(20, 20), - maxwidth=300, - scale=1, - autoselect=True, - text="") - cb2 = bui.checkboxwidget( - parent=self.root_widget, - position=(40, height - 275), - size=(20, 20), - maxwidth=300, - scale=1, - autoselect=True, - text="") - make_radio_group((cb1, cb2), (True, False), cur_val, - self._actions_changed) - except Exception as e: - print(e) - pass - - bui.containerwidget(edit=self.root_widget, cancel_button=btn) - - def _change_source(self, choice): - cfg = babase.app.config - cfg['Translate Source Language'] = choice - cfg.apply_and_commit() - - def _change_destination(self, choice): - cfg = babase.app.config - cfg['Translate Destination Language'] = choice - cfg.apply_and_commit() - - def _actions_changed(self, v: str) -> None: - cfg = babase.app.config - cfg['Pronunciation'] = v - cfg.apply_and_commit() - - def _cancel(self) -> None: - bui.containerwidget(edit=self.root_widget, transition='out_scale') - SettingsWindow() - - -class SettingsWindow: - - def __init__(self): - uiscale = bui.app.ui_v1.uiscale - height = (300 if uiscale is babase.UIScale.SMALL else - 350 if uiscale is babase.UIScale.MEDIUM else 400) - width = (500 if uiscale is babase.UIScale.SMALL else - 600 if uiscale is babase.UIScale.MEDIUM else 650) - scroll_h = (200 if uiscale is babase.UIScale.SMALL else - 250 if uiscale is babase.UIScale.MEDIUM else 270) - scroll_w = (450 if uiscale is babase.UIScale.SMALL else - 550 if uiscale is babase.UIScale.MEDIUM else 600) - self._transition_out: Optional[str] - scale_origin: Optional[Tuple[float, float]] - self._transition_out = 'out_scale' - scale_origin = 10 - transition = 'in_scale' - scale_origin = None - cancel_is_selected = False - cfg = babase.app.config - bg_color = cfg.get('PartyWindow Main Color', (0.5, 0.5, 0.5)) - - self.root_widget = bui.containerwidget( - size=(width, height), - color=bg_color, - transition=transition, - toolbar_visibility='menu_minimal_no_back', - parent=bui.get_special_widget('overlay_stack'), - on_outside_click_call=self._cancel, - scale=(2.1 if uiscale is babase.UIScale.SMALL else - 1.5 if uiscale is babase.UIScale.MEDIUM else 1.0), - scale_origin_stack_offset=scale_origin) - bui.textwidget(parent=self.root_widget, - position=(width * 0.5, height - 45), - size=(20, 20), - h_align='center', - v_align='center', - text="Custom Settings", - scale=0.9, - color=(5, 5, 5)) - cbtn = btn = bui.buttonwidget(parent=self.root_widget, - autoselect=True, - position=(30, height - 60), - size=(30, 30), - label=babase.charstr(babase.SpecialChar.BACK), - button_type='backSmall', - on_activate_call=self._cancel) - scroll_position = (30 if uiscale is babase.UIScale.SMALL else - 40 if uiscale is babase.UIScale.MEDIUM else 50) - self._scrollwidget = bui.scrollwidget(parent=self.root_widget, - position=(30, scroll_position), - simple_culling_v=20.0, - highlight=False, - size=(scroll_w, scroll_h), - selection_loops_to_parent=True) - bui.widget(edit=self._scrollwidget, right_widget=self._scrollwidget) - self._subcontainer = bui.columnwidget(parent=self._scrollwidget, - selection_loops_to_parent=True) - ip_button = bui.checkboxwidget( - parent=self._subcontainer, - size=(300, 30), - maxwidth=300, - textcolor=((0, 1, 0) if cfg['IP button'] else (0.95, 0.65, 0)), - scale=1, - value=cfg['IP button'], - autoselect=True, - text="IP Button", - on_value_change_call=self.ip_button) - ping_button = bui.checkboxwidget( - parent=self._subcontainer, - size=(300, 30), - maxwidth=300, - textcolor=((0, 1, 0) if cfg['ping button'] else (0.95, 0.65, 0)), - scale=1, - value=cfg['ping button'], - autoselect=True, - text="Ping Button", - on_value_change_call=self.ping_button) - copy_button = bui.checkboxwidget( - parent=self._subcontainer, - size=(300, 30), - maxwidth=300, - textcolor=((0, 1, 0) if cfg['copy button'] else (0.95, 0.65, 0)), - scale=1, - value=cfg['copy button'], - autoselect=True, - text="Copy Text Button", - on_value_change_call=self.copy_button) - direct_send = bui.checkboxwidget( - parent=self._subcontainer, - size=(300, 30), - maxwidth=300, - textcolor=((0, 1, 0) if cfg['Direct Send'] else (0.95, 0.65, 0)), - scale=1, - value=cfg['Direct Send'], - autoselect=True, - text="Directly Send Custom Commands", - on_value_change_call=self.direct_send) - colorfulchat = bui.checkboxwidget( - parent=self._subcontainer, - size=(300, 30), - maxwidth=300, - textcolor=((0, 1, 0) if cfg['Colorful Chat'] else (0.95, 0.65, 0)), - scale=1, - value=cfg['Colorful Chat'], - autoselect=True, - text="Colorful Chat", - on_value_change_call=self.colorful_chat) - msg_notification_text = bui.textwidget(parent=self._subcontainer, - scale=0.8, - color=(1, 1, 1), - text='Message Notifcation:', - size=(100, 30), - h_align='left', - v_align='center') - msg_notification_widget = PopupMenu( - parent=self._subcontainer, - position=(100, height - 1200), - width=200, - scale=(2.8 if uiscale is babase.UIScale.SMALL else - 1.8 if uiscale is babase.UIScale.MEDIUM else 1.2), - choices=['top', 'bottom'], - current_choice=babase.app.config['Message Notification'], - button_size=(80, 25), - on_value_change_call=self._change_notification) - self_status_text = bui.textwidget(parent=self._subcontainer, - scale=0.8, - color=(1, 1, 1), - text='Self Status:', - size=(100, 30), - h_align='left', - v_align='center') - self_status_widget = PopupMenu( - parent=self._subcontainer, - position=(50, height - 1000), - width=200, - scale=(2.8 if uiscale is babase.UIScale.SMALL else - 1.8 if uiscale is babase.UIScale.MEDIUM else 1.2), - choices=['online', 'offline'], - current_choice=babase.app.config['Self Status'], - button_size=(80, 25), - on_value_change_call=self._change_status) - bui.containerwidget(edit=self.root_widget, cancel_button=btn) - bui.containerwidget(edit=self.root_widget, - selected_child=(cbtn if cbtn is not None - and cancel_is_selected else None), - start_button=None) - - self._translation_btn = bui.buttonwidget(parent=self._subcontainer, - scale=1.2, - position=(100, 1200), - size=(150, 50), - label='Translate Settings', - on_activate_call=self._translaton_btn, - autoselect=True) - - def ip_button(self, value: bool): - cfg = babase.app.config - cfg['IP button'] = value - cfg.apply_and_commit() - if cfg['IP button']: - bui.screenmessage("IP Button is now enabled", color=(0, 1, 0)) - else: - bui.screenmessage("IP Button is now disabled", color=(1, 0.7, 0)) - - def ping_button(self, value: bool): - cfg = babase.app.config - cfg['ping button'] = value - cfg.apply_and_commit() - if cfg['ping button']: - bui.screenmessage("Ping Button is now enabled", color=(0, 1, 0)) - else: - bui.screenmessage("Ping Button is now disabled", color=(1, 0.7, 0)) - - def copy_button(self, value: bool): - cfg = babase.app.config - cfg['copy button'] = value - cfg.apply_and_commit() - if cfg['copy button']: - bui.screenmessage("Copy Text Button is now enabled", color=(0, 1, 0)) - else: - bui.screenmessage("Copy Text Button is now disabled", color=(1, 0.7, 0)) - - def direct_send(self, value: bool): - cfg = babase.app.config - cfg['Direct Send'] = value - cfg.apply_and_commit() - - def colorful_chat(self, value: bool): - cfg = babase.app.config - cfg['Colorful Chat'] = value - cfg.apply_and_commit() - - def _change_notification(self, choice): - cfg = babase.app.config - cfg['Message Notification'] = choice - cfg.apply_and_commit() - - def _change_status(self, choice): - cfg = babase.app.config - cfg['Self Status'] = choice - cfg.apply_and_commit() - - def _translaton_btn(self): - try: - bui.containerwidget(edit=self.root_widget, transition='out_scale') - TranslationSettings() - except Exception as e: - print(e) - pass - - def _cancel(self) -> None: - bui.containerwidget(edit=self.root_widget, transition='out_scale') - - -class PartyWindow(bui.Window): - """Party list/chat window.""" - - def __del__(self) -> None: - bui.set_party_window_open(False) - - def __init__(self, origin: Sequence[float] = (0, 0)): - self._private_chat = False - self._firstcall = True - self.ping_server() - bui.set_party_window_open(True) - self._r = 'partyWindow' - self._popup_type: Optional[str] = None - self._popup_party_member_client_id: Optional[int] = None - self._popup_party_member_is_host: Optional[bool] = None - self._width = 500 - uiscale = bui.app.ui_v1.uiscale - self._height = (365 if uiscale is babase.UIScale.SMALL else - 480 if uiscale is babase.UIScale.MEDIUM else 600) - self.bg_color = babase.app.config.get('PartyWindow Main Color', (0.5, 0.5, 0.5)) - self.ping_timer = bs.apptimer(5, bs.WeakCall(self.ping_server)) - - bui.Window.__init__(self, root_widget=bui.containerwidget( - size=(self._width, self._height), - transition='in_scale', - color=self.bg_color, - parent=bui.get_special_widget('overlay_stack'), - on_outside_click_call=self.close_with_sound, - scale_origin_stack_offset=origin, - scale=(2.0 if uiscale is babase.UIScale.SMALL else - 1.35 if uiscale is babase.UIScale.MEDIUM else 1.0), - stack_offset=(0, -10) if uiscale is babase.UIScale.SMALL else ( - 240, 0) if uiscale is babase.UIScale.MEDIUM else (330, 20))) - - self._cancel_button = bui.buttonwidget(parent=self._root_widget, - scale=0.7, - position=(30, self._height - 47), - size=(50, 50), - label='', - on_activate_call=self.close, - autoselect=True, - color=self.bg_color, - icon=bui.gettexture('crossOut'), - iconscale=1.2) - bui.containerwidget(edit=self._root_widget, - cancel_button=self._cancel_button) - - self._menu_button = bui.buttonwidget( - parent=self._root_widget, - scale=0.7, - position=(self._width - 80, self._height - 47), - size=(50, 50), - label='...', - autoselect=True, - button_type='square', - on_activate_call=bs.WeakCall(self._on_menu_button_press), - color=self.bg_color, - iconscale=1.2) - try: - info = bs.get_connection_to_host_info().get( - 'name', '') if build_number < 21697 else bs.get_connection_to_host_info_2().name - if info != '': - self.title = babase.Lstr( - value=info['name']) if build_number < 21697 else babase.Lstr(value=info) - except AttributeError: - self.title = babase.Lstr(resource=self._r + '.titleText') - - self._title_text = bui.textwidget(parent=self._root_widget, - scale=0.9, - color=(0.5, 0.7, 0.5), - text=self.title, - size=(0, 0), - position=(self._width * 0.47, - self._height - 29), - maxwidth=self._width * 0.6, - h_align='center', - v_align='center') - self._empty_str = bui.textwidget(parent=self._root_widget, - scale=0.75, - size=(0, 0), - position=(self._width * 0.5, - self._height - 65), - maxwidth=self._width * 0.85, - h_align='center', - v_align='center') - - self._scroll_width = self._width - 50 - self._scrollwidget = bui.scrollwidget(parent=self._root_widget, - size=(self._scroll_width, - self._height - 200), - position=(30, 80), - color=self.bg_color) - self._columnwidget = bui.columnwidget(parent=self._scrollwidget, - border=2, - margin=0) - bui.widget(edit=self._menu_button, down_widget=self._columnwidget) - - self._muted_text = bui.textwidget( - parent=self._root_widget, - position=(self._width * 0.5, self._height * 0.5), - size=(0, 0), - h_align='center', - v_align='center', - text=babase.Lstr(resource='chatMutedText')) - - self._text_field = txt = bui.textwidget( - parent=self._root_widget, - editable=True, - size=(500, 40), - position=(54, 39), - text='', - maxwidth=494, - shadow=0.3, - flatness=1.0, - description=babase.Lstr(resource=self._r + '.chatMessageText'), - autoselect=True, - v_align='center', - corner_scale=0.7) - - bui.widget(edit=self._scrollwidget, - autoselect=True, - left_widget=self._cancel_button, - up_widget=self._cancel_button, - down_widget=self._text_field) - bui.widget(edit=self._columnwidget, - autoselect=True, - up_widget=self._cancel_button, - down_widget=self._text_field) - bui.containerwidget(edit=self._root_widget, selected_child=txt) - self._send_button = btn = bui.buttonwidget(parent=self._root_widget, - size=(50, 35), - label=babase.Lstr( - resource=self._r + '.sendText'), - button_type='square', - autoselect=True, - color=self.bg_color, - position=(self._width - 90, 35), - on_activate_call=self._send_chat_message) - bui.textwidget(edit=txt, on_return_press_call=btn.activate) - self._previous_button = bui.buttonwidget(parent=self._root_widget, - size=(30, 30), - label=babase.charstr(babase.SpecialChar.UP_ARROW), - button_type='square', - autoselect=True, - position=(15, 57), - color=self.bg_color, - scale=0.75, - on_activate_call=self._previous_message) - self._next_button = bui.buttonwidget(parent=self._root_widget, - size=(30, 30), - label=babase.charstr(babase.SpecialChar.DOWN_ARROW), - button_type='square', - autoselect=True, - color=self.bg_color, - scale=0.75, - position=(15, 28), - on_activate_call=self._next_message) - self._translate_button = bui.buttonwidget(parent=self._root_widget, - size=(55, 47), - label="Trans", - button_type='square', - autoselect=True, - color=self.bg_color, - scale=0.75, - position=(self._width - 28, 35), - on_activate_call=self._translate) - if babase.app.config['copy button']: - self._copy_button = bui.buttonwidget(parent=self._root_widget, - size=(15, 15), - label='©', - button_type='backSmall', - autoselect=True, - color=self.bg_color, - position=(self._width - 40, 80), - on_activate_call=self._copy_to_clipboard) - self._ping_button = None - try: - info = bs.get_connection_to_host_info().get( - 'name', '') if build_number < 21697 else bs.get_connection_to_host_info_2().name - if info != '': - if babase.app.config['ping button']: - self._ping_button = bui.buttonwidget( - parent=self._root_widget, - scale=0.7, - position=(self._width - 538, self._height - 57), - size=(75, 75), - autoselect=True, - button_type='square', - label=f'{_ping}', - on_activate_call=self._send_ping, - color=self.bg_color, - text_scale=2.3, - iconscale=1.2) - if babase.app.config['IP button']: - self._ip_port_button = bui.buttonwidget(parent=self._root_widget, - size=(30, 30), - label='IP', - button_type='square', - autoselect=True, - color=self.bg_color, - position=(self._width - 530, - self._height - 100), - on_activate_call=self._ip_port_msg) - except AttributeError: - pass - self._settings_button = bui.buttonwidget(parent=self._root_widget, - size=(50, 50), - scale=0.5, - button_type='square', - autoselect=True, - color=self.bg_color, - position=(self._width - 40, self._height - 47), - on_activate_call=self._on_setting_button_press, - icon=bui.gettexture('settingsIcon'), - iconscale=1.2) - self._privatechat_button = bui.buttonwidget(parent=self._root_widget, - size=(50, 50), - scale=0.5, - button_type='square', - autoselect=True, - color=self.bg_color, - position=(self._width - 40, self._height - 80), - on_activate_call=self._on_privatechat_button_press, - icon=bui.gettexture('ouyaOButton'), - iconscale=1.2) - self._name_widgets: List[bui.Widget] = [] - self._roster: Optional[List[Dict[str, Any]]] = None - self._update_timer = bs.apptimer(1.0, - bs.WeakCall(self._update)) - self._update() - - def on_chat_message(self, msg: str, sent=None) -> None: - """Called when a new chat message comes through.""" - if babase.app.config['Party Chat Muted'] and not bui.app.ui_v1.party_window()._private_chat: - return - if sent: - self._add_msg(msg, sent) - else: - self._add_msg(msg) - - def _add_msg(self, msg: str, sent=None) -> None: - if babase.app.config['Colorful Chat']: - sender = msg.split(': ')[0] - color = color_tracker._get_sender_color(sender) if sender else (1, 1, 1) - else: - color = (1, 1, 1) - maxwidth = self._scroll_width * 0.94 - txt = bui.textwidget(parent=self._columnwidget, - text=msg, - h_align='left', - v_align='center', - size=(0, 13), - scale=0.55, - color=color, - maxwidth=maxwidth, - shadow=0.3, - flatness=1.0) - if sent: - bui.textwidget(edit=txt, size=(100, 15), - selectable=True, - click_activate=True, - on_activate_call=babase.Call(bui.screenmessage, f'Message sent: {_get_local_time(sent)}')) - self._chat_texts.append(txt) - if len(self._chat_texts) > 40: - first = self._chat_texts.pop(0) - first.delete() - bui.containerwidget(edit=self._columnwidget, visible_child=txt) - - def _on_menu_button_press(self) -> None: - is_muted = babase.app.config['Party Chat Muted'] - uiscale = bui.app.ui_v1.uiscale - - choices = ['muteOption', 'modifyColor', 'addQuickReply', 'removeQuickReply', 'credits'] - choices_display = ['Mute Option', 'Modify Main Color', - 'Add as Quick Reply', 'Remove a Quick Reply', 'Credits'] - - if hasattr(bs.get_foreground_host_activity(), '_map'): - choices.append('manualCamera') - choices_display.append('Manual Camera') - - PopupMenuWindow( - position=self._menu_button.get_screen_space_center(), - color=self.bg_color, - scale=(2.3 if uiscale is babase.UIScale.SMALL else - 1.65 if uiscale is babase.UIScale.MEDIUM else 1.23), - choices=choices, - choices_display=self._create_baLstr_list(choices_display), - current_choice='muteOption', - delegate=self) - self._popup_type = 'menu' - - def _update(self) -> None: - if not self._private_chat: - bui.set_party_window_open(True) - bui.textwidget(edit=self._title_text, text=self.title) - if self._firstcall: - if hasattr(self, '_status_text'): - self._status_text.delete() - self._roster = [] - self._firstcall = False - self._chat_texts: List[bui.Widget] = [] - if not babase.app.config['Party Chat Muted']: - msgs = bs.get_chat_messages() - for msg in msgs: - self._add_msg(msg) - # update muted state - if babase.app.config['Party Chat Muted']: - bui.textwidget(edit=self._muted_text, color=(1, 1, 1, 0.3)) - # clear any chat texts we're showing - if self._chat_texts: - while self._chat_texts: - first = self._chat_texts.pop() - first.delete() - else: - bui.textwidget(edit=self._muted_text, color=(1, 1, 1, 0.0)) - if self._ping_button: - bui.buttonwidget(edit=self._ping_button, - label=f'{_ping}', - textcolor=self._get_ping_color()) - - # update roster section - roster = bs.get_game_roster() - if roster != self._roster or self._firstcall: - - self._roster = roster - - # clear out old - for widget in self._name_widgets: - widget.delete() - self._name_widgets = [] - if not self._roster: - top_section_height = 60 - bui.textwidget(edit=self._empty_str, - text=babase.Lstr(resource=self._r + '.emptyText')) - bui.scrollwidget(edit=self._scrollwidget, - size=(self._width - 50, - self._height - top_section_height - 110), - position=(30, 80)) - else: - columns = 1 if len( - self._roster) == 1 else 2 if len(self._roster) == 2 else 3 - rows = int(math.ceil(float(len(self._roster)) / columns)) - c_width = (self._width * 0.9) / max(3, columns) - c_width_total = c_width * columns - c_height = 24 - c_height_total = c_height * rows - for y in range(rows): - for x in range(columns): - index = y * columns + x - if index < len(self._roster): - t_scale = 0.65 - pos = (self._width * 0.53 - c_width_total * 0.5 + - c_width * x - 23, - self._height - 65 - c_height * y - 15) - - # if there are players present for this client, use - # their names as a display string instead of the - # client spec-string - try: - if self._roster[index]['players']: - # if there's just one, use the full name; - # otherwise combine short names - if len(self._roster[index] - ['players']) == 1: - p_str = self._roster[index]['players'][ - 0]['name_full'] - else: - p_str = ('/'.join([ - entry['name'] for entry in - self._roster[index]['players'] - ])) - if len(p_str) > 25: - p_str = p_str[:25] + '...' - else: - p_str = self._roster[index][ - 'display_string'] - except Exception: - babase.print_exception( - 'Error calcing client name str.') - p_str = '???' - widget = bui.textwidget(parent=self._root_widget, - position=(pos[0], pos[1]), - scale=t_scale, - size=(c_width * 0.85, 30), - maxwidth=c_width * 0.85, - color=(1, 1, - 1) if index == 0 else - (1, 1, 1), - selectable=True, - autoselect=True, - click_activate=True, - text=babase.Lstr(value=p_str), - h_align='left', - v_align='center') - self._name_widgets.append(widget) - - # in newer versions client_id will be present and - # we can use that to determine who the host is. - # in older versions we assume the first client is - # host - if self._roster[index]['client_id'] is not None: - is_host = self._roster[index][ - 'client_id'] == -1 - else: - is_host = (index == 0) - - # FIXME: Should pass client_id to these sort of - # calls; not spec-string (perhaps should wait till - # client_id is more readily available though). - bui.textwidget(edit=widget, - on_activate_call=babase.Call( - self._on_party_member_press, - self._roster[index]['client_id'], - is_host, widget)) - pos = (self._width * 0.53 - c_width_total * 0.5 + - c_width * x, - self._height - 65 - c_height * y) - - # Make the assumption that the first roster - # entry is the server. - # FIXME: Shouldn't do this. - if is_host: - twd = min( - c_width * 0.85, - _babase.get_string_width( - p_str, suppress_warning=True) * - t_scale) - self._name_widgets.append( - bui.textwidget( - parent=self._root_widget, - position=(pos[0] + twd + 1, - pos[1] - 0.5), - size=(0, 0), - h_align='left', - v_align='center', - maxwidth=c_width * 0.96 - twd, - color=(0.1, 1, 0.1, 0.5), - text=babase.Lstr(resource=self._r + - '.hostText'), - scale=0.4, - shadow=0.1, - flatness=1.0)) - bui.textwidget(edit=self._empty_str, text='') - bui.scrollwidget(edit=self._scrollwidget, - size=(self._width - 50, - max(100, self._height - 139 - - c_height_total)), - position=(30, 80)) - else: - bui.set_party_window_open(False) - for widget in self._name_widgets: - widget.delete() - self._name_widgets = [] - bui.textwidget(edit=self._title_text, text='Private Chat') - bui.textwidget(edit=self._empty_str, text='') - if self._firstcall: - self._firstcall = False - if hasattr(self, '_status_text'): - self._status_text.delete() - try: - msgs = messenger.pvt_msgs[messenger.filter] - except: - msgs = [] - if self._chat_texts: - while self._chat_texts: - first = self._chat_texts.pop() - first.delete() - uiscale = bui.app.ui_v1.uiscale - scroll_height = (165 if uiscale is babase.UIScale.SMALL else - 280 if uiscale is babase.UIScale.MEDIUM else 400) - bui.scrollwidget(edit=self._scrollwidget, - size=(self._width - 50, scroll_height)) - for msg in msgs: - message = messenger._format_message(msg) - self._add_msg(message, msg['sent']) - self._filter_text = bui.textwidget(parent=self._root_widget, - scale=0.6, - color=(0.9, 1.0, 0.9), - text='Filter: ', - size=(0, 0), - position=(self._width * 0.3, - self._height - 70), - h_align='center', - v_align='center') - choices = [i for i in messenger.saved_ids] - choices_display = [babase.Lstr(value=messenger.saved_ids[i]) - for i in messenger.saved_ids] - choices.append('add') - choices_display.append(babase.Lstr(value='***Add New***')) - filter_widget = PopupMenu( - parent=self._root_widget, - position=(self._width * 0.4, - self._height - 80), - width=200, - scale=(2.8 if uiscale is babase.UIScale.SMALL else - 1.8 if uiscale is babase.UIScale.MEDIUM else 1.2), - choices=choices, - choices_display=choices_display, - current_choice=messenger.filter, - button_size=(120, 30), - on_value_change_call=self._change_filter) - self._popup_button = filter_widget.get_button() - if messenger.filter != 'all': - user_status = messenger._get_status(messenger.filter) - if user_status == 'Offline': - color = (1, 0, 0) - elif user_status.startswith(('Playing in', 'in Lobby')): - color = (0, 1, 0) - else: - color = (0.9, 1.0, 0.9) - self._status_text = bui.textwidget(parent=self._root_widget, - scale=0.5, - color=color, - text=f'Status:\t{user_status}', - size=(200, 30), - position=(self._width * 0.3, - self._height - 110), - h_align='center', - v_align='center', - autoselect=True, - selectable=True, - click_activate=True) - bui.textwidget(edit=self._status_text, - on_activate_call=babase.Call(messenger._get_status, messenger.filter, 'last_seen')) - - def _change_filter(self, choice): - if choice == 'add': - self.close() - AddNewIdWindow() - else: - messenger.filter = choice - self._firstcall = True - self._filter_text.delete() - self._popup_button.delete() - if self._chat_texts: - while self._chat_texts: - first = self._chat_texts.pop() - first.delete() - self._update() - - def popup_menu_selected_choice(self, popup_window: PopupMenuWindow, - choice: str) -> None: - """Called when a choice is selected in the popup.""" - if self._popup_type == 'partyMemberPress': - playerinfo = self._get_player_info(self._popup_party_member_client_id) - if choice == 'kick': - name = playerinfo['ds'] - ConfirmWindow(text=f'Are you sure to kick {name}?', - action=self._vote_kick_player, - cancel_button=True, - cancel_is_selected=True, - color=self.bg_color, - text_scale=1.0, - origin_widget=self.get_root_widget()) - elif choice == 'mention': - players = playerinfo['players'] - choices = [] - namelist = [playerinfo['ds']] - for player in players: - name = player['name_full'] - if name not in namelist: - namelist.append(name) - choices_display = self._create_baLstr_list(namelist) - for i in namelist: - i = i.replace('"', '\"') - i = i.replace("'", "\'") - choices.append(f'self._edit_text_msg_box("{i}")') - PopupMenuWindow(position=popup_window.root_widget.get_screen_space_center(), - color=self.bg_color, - scale=self._get_popup_window_scale(), - choices=choices, - choices_display=choices_display, - current_choice=choices[0], - delegate=self) - self._popup_type = "executeChoice" - elif choice == 'adminkick': - name = playerinfo['ds'] - ConfirmWindow(text=f'Are you sure to use admin\ncommand to kick {name}', - action=self._send_admin_kick_command, - cancel_button=True, - cancel_is_selected=True, - color=self.bg_color, - text_scale=1.0, - origin_widget=self.get_root_widget()) - elif choice == 'customCommands': - choices = [] - choices_display = [] - playerinfo = self._get_player_info(self._popup_party_member_client_id) - account = playerinfo['ds'] - try: - name = playerinfo['players'][0]['name_full'] - except: - name = account - for i in babase.app.config.get('Custom Commands'): - i = i.replace('$c', str(self._popup_party_member_client_id)) - i = i.replace('$a', str(account)) - i = i.replace('$n', str(name)) - if babase.app.config['Direct Send']: - choices.append(f'bs.chatmessage("{i}")') - else: - choices.append(f'self._edit_text_msg_box("{i}")') - choices_display.append(babase.Lstr(value=i)) - choices.append('AddNewChoiceWindow()') - choices_display.append(babase.Lstr(value='***Add New***')) - PopupMenuWindow(position=popup_window.root_widget.get_screen_space_center(), - color=self.bg_color, - scale=self._get_popup_window_scale(), - choices=choices, - choices_display=choices_display, - current_choice=choices[0], - delegate=self) - self._popup_type = 'executeChoice' - - elif choice == 'addNew': - AddNewChoiceWindow() - - elif self._popup_type == 'menu': - if choice == 'muteOption': - current_choice = self._get_current_mute_type() - PopupMenuWindow( - position=(self._width - 60, self._height - 47), - color=self.bg_color, - scale=self._get_popup_window_scale(), - choices=['muteInGameOnly', 'mutePartyWindowOnly', 'muteAll', 'unmuteAll'], - choices_display=self._create_baLstr_list( - ['Mute In Game Messages Only', 'Mute Party Window Messages Only', 'Mute all', 'Unmute All']), - current_choice=current_choice, - delegate=self - ) - self._popup_type = 'muteType' - elif choice == 'modifyColor': - ColorPickerExact(parent=self.get_root_widget(), - position=self.get_root_widget().get_screen_space_center(), - initial_color=self.bg_color, - delegate=self, tag='') - elif choice == 'addQuickReply': - try: - newReply = bui.textwidget(query=self._text_field) - oldReplies = self._get_quick_responds() - oldReplies.append(newReply) - self._write_quick_responds(oldReplies) - bui.screenmessage(f'"{newReply}" is added.', (0, 1, 0)) - bui.getsound('dingSmallHigh').play() - except: - babase.print_exception() - elif choice == 'removeQuickReply': - quick_reply = self._get_quick_responds() - PopupMenuWindow(position=self._send_button.get_screen_space_center(), - color=self.bg_color, - scale=self._get_popup_window_scale(), - choices=quick_reply, - choices_display=self._create_baLstr_list(quick_reply), - current_choice=quick_reply[0], - delegate=self) - self._popup_type = 'removeQuickReplySelect' - elif choice == 'credits': - ConfirmWindow( - text=u'\ue043Party Window Reloaded V3\ue043\n\nCredits - Droopy#3730\nSpecial Thanks - BoTT-Vishah#4150', - action=self.join_discord, - width=420, - height=230, - color=self.bg_color, - text_scale=1.0, - ok_text="Join Discord", - origin_widget=self.get_root_widget()) - elif choice == 'manualCamera': - bui.containerwidget(edit=self._root_widget, transition='out_scale') - Manual_camera_window() - - elif self._popup_type == 'muteType': - self._change_mute_type(choice) - - elif self._popup_type == 'executeChoice': - exec(choice) - - elif self._popup_type == 'quickMessage': - if choice == '*** EDIT ORDER ***': - SortQuickMessages() - else: - self._edit_text_msg_box(choice) - - elif self._popup_type == 'removeQuickReplySelect': - data = self._get_quick_responds() - data.remove(choice) - self._write_quick_responds(data) - bui.screenmessage(f'"{choice}" is removed.', (1, 0, 0)) - bui.getsound('shieldDown').play() - - else: - print(f'unhandled popup type: {self._popup_type}') - del popup_window # unused - - def _vote_kick_player(self): - if self._popup_party_member_is_host: - bui.getsound('error').play() - bui.screenmessage( - babase.Lstr(resource='internal.cantKickHostError'), - color=(1, 0, 0)) - else: - assert self._popup_party_member_client_id is not None - - # Ban for 5 minutes. - result = bs.disconnect_client( - self._popup_party_member_client_id, ban_time=5 * 60) - if not result: - bui.getsound('error').play() - bui.screenmessage( - babase.Lstr(resource='getTicketsWindow.unavailableText'), - color=(1, 0, 0)) - - def _send_admin_kick_command(self): - bs.chatmessage('/kick ' + str(self._popup_party_member_client_id)) - - def _translate(self): - def _apply_translation(translated): - if self._text_field.exists(): - bui.textwidget(edit=self._text_field, text=translated) - msg = bui.textwidget(query=self._text_field) - cfg = babase.app.config - if msg == '': - bui.screenmessage('Nothing to translate.', (1, 0, 0)) - bui.getsound('error').play() - else: - data = dict(message=msg) - if cfg['Translate Source Language']: - data['src'] = cfg['Translate Source Language'] - if cfg['Translate Destination Language']: - data['dest'] = cfg['Translate Destination Language'] - if cfg['Pronunciation']: - data['type'] = 'pronunciation' - Translate(data, _apply_translation).start() - - def _copy_to_clipboard(self): - msg = bui.textwidget(query=self._text_field) - if msg == '': - bui.screenmessage('Nothing to copy.', (1, 0, 0)) - bui.getsound('error').play() - else: - babase.clipboard_set_text(msg) - bui.screenmessage(f'"{msg}" is copied to clipboard.', (0, 1, 0)) - bui.getsound('dingSmallHigh').play() - - def _get_current_mute_type(self): - cfg = babase.app.config - if cfg['Chat Muted'] == True: - if cfg['Party Chat Muted'] == True: - return 'muteAll' - else: - return 'muteInGameOnly' - else: - if cfg['Party Chat Muted'] == True: - return 'mutePartyWindowOnly' - else: - return 'unmuteAll' - - def _change_mute_type(self, choice): - cfg = babase.app.config - if choice == 'muteInGameOnly': - cfg['Chat Muted'] = True - cfg['Party Chat Muted'] = False - elif choice == 'mutePartyWindowOnly': - cfg['Chat Muted'] = False - cfg['Party Chat Muted'] = True - elif choice == 'muteAll': - cfg['Chat Muted'] = True - cfg['Party Chat Muted'] = True - else: - cfg['Chat Muted'] = False - cfg['Party Chat Muted'] = False - cfg.apply_and_commit() - self._update() - - def popup_menu_closing(self, popup_window: PopupWindow) -> None: - """Called when the popup is closing.""" - - def _on_party_member_press(self, client_id: int, is_host: bool, - widget: bui.Widget) -> None: - # if we're the host, pop up 'kick' options for all non-host members - if bs.get_foreground_host_session() is not None: - kick_str = babase.Lstr(resource='kickText') - else: - # kick-votes appeared in build 14248 - if build_number < 14248: - return - kick_str = babase.Lstr(resource='kickVoteText') - uiscale = bui.app.ui_v1.uiscale - choices = ['kick', 'mention', 'adminkick'] - choices_display = [kick_str] + \ - list(self._create_baLstr_list(['Mention this guy', f'Kick ID: {client_id}'])) - choices.append('customCommands') - choices_display.append(babase.Lstr(value='Custom Commands')) - PopupMenuWindow( - position=widget.get_screen_space_center(), - color=self.bg_color, - scale=(2.3 if uiscale is babase.UIScale.SMALL else - 1.65 if uiscale is babase.UIScale.MEDIUM else 1.23), - choices=choices, - choices_display=choices_display, - current_choice='mention', - delegate=self) - self._popup_type = 'partyMemberPress' - self._popup_party_member_client_id = client_id - self._popup_party_member_is_host = is_host - - def _send_chat_message(self) -> None: - msg = bui.textwidget(query=self._text_field) - bui.textwidget(edit=self._text_field, text='') - if '\\' in msg: - msg = msg.replace('\\d', ('\ue048')) - msg = msg.replace('\\c', ('\ue043')) - msg = msg.replace('\\h', ('\ue049')) - msg = msg.replace('\\s', ('\ue046')) - msg = msg.replace('\\n', ('\ue04b')) - msg = msg.replace('\\f', ('\ue04f')) - msg = msg.replace('\\g', ('\ue027')) - msg = msg.replace('\\i', ('\ue03a')) - msg = msg.replace('\\m', ('\ue04d')) - msg = msg.replace('\\t', ('\ue01f')) - msg = msg.replace('\\bs', ('\ue01e')) - msg = msg.replace('\\j', ('\ue010')) - msg = msg.replace('\\e', ('\ue045')) - msg = msg.replace('\\l', ('\ue047')) - msg = msg.replace('\\a', ('\ue020')) - msg = msg.replace('\\b', ('\ue00c')) - if not msg: - choices = self._get_quick_responds() - choices.append('*** EDIT ORDER ***') - PopupMenuWindow(position=self._send_button.get_screen_space_center(), - scale=self._get_popup_window_scale(), - color=self.bg_color, - choices=choices, - current_choice=choices[0], - delegate=self) - self._popup_type = 'quickMessage' - return - elif msg.startswith('/info '): - account = msg.replace('/info ', '') - if account: - from bauiv1lib.account import viewer - viewer.AccountViewerWindow( - account_id=account) - bui.textwidget(edit=self._text_field, text='') - return - if not self._private_chat: - if msg == '/id': - myid = bui.app.plus.get_v1_account_misc_read_val_2('resolvedAccountID', '') - bs.chatmessage(f"My Unique ID : {myid}") - elif msg == '/save': - try: - info = bs.get_connection_to_host_info().get( - 'name', '') if build_number < 21697 else bs.get_connection_to_host_info_2().name - config = babase.app.config - if info != '': - title = info['name'] - if not isinstance(config.get('Saved Servers'), dict): - config['Saved Servers'] = {} - config['Saved Servers'][f'{_ip}@{_port}'] = { - 'addr': _ip, - 'port': _port, - 'name': title - } - config.commit() - bui.screenmessage("Server Added To Manual", color=(0, 1, 0), transient=True) - bui.getsound('gunCocking').play() - except AttributeError: - pass - elif msg != '': - bs.chatmessage(cast(str, msg)) - else: - receiver = messenger.filter - name = bui.app.plus.get_v1_account_display_string() - if not receiver: - display_error('Choose a valid receiver id') - return - data = {'receiver': receiver, 'message': f'{name}: {msg}'} - if msg.startswith('/rename '): - if messenger.filter != 'all': - nickname = msg.replace('/rename ', '') - messenger._save_id(messenger.filter, nickname, verify=False) - self._change_filter(messenger.filter) - elif msg == '/remove': - if messenger.filter != 'all': - messenger._remove_id(messenger.filter) - self._change_filter('all') - else: - display_error('Cant delete this') - bui.textwidget(edit=self._text_field, text='') - return - babase.Call(messenger._send_request, url, data) - babase.Call(check_new_message) - Thread(target=messenger._send_request, args=(url, data)).start() - Thread(target=check_new_message).start() - bui.textwidget(edit=self._text_field, text='') - - def _write_quick_responds(self, data): - try: - with open(quick_msg_file, 'w') as f: - f.write('\n'.join(data)) - except: - babase.print_exception() - bui.screenmessage('Error!', (1, 0, 0)) - bui.getsound('error').play() - - def _get_quick_responds(self): - if os.path.exists(quick_msg_file): - with open(quick_msg_file, 'r') as f: - return f.read().split('\n') - else: - default_replies = ['What the hell?', 'Dude that\'s amazing!'] - self._write_quick_responds(default_replies) - return default_replies - - def color_picker_selected_color(self, picker, color) -> None: - bui.containerwidget(edit=self._root_widget, color=color) - color = tuple(round(i, 2) for i in color) - self.bg_color = color - babase.app.config['PartyWindow Main Color'] = color - - def color_picker_closing(self, picker) -> None: - babase.app.config.apply_and_commit() - - def _remove_sender_from_message(self, msg=''): - msg_start = msg.find(": ") + 2 - return msg[msg_start:] - - def _previous_message(self): - msgs = self._chat_texts - if not hasattr(self, 'msg_index'): - self.msg_index = len(msgs) - 1 - else: - if self.msg_index > 0: - self.msg_index -= 1 - else: - del self.msg_index - try: - msg_widget = msgs[self.msg_index] - msg = bui.textwidget(query=msg_widget) - msg = self._remove_sender_from_message(msg) - if msg in ('', ' '): - self._previous_message() - return - except: - msg = '' - self._edit_text_msg_box(msg, 'replace') - - def _next_message(self): - msgs = self._chat_texts - if not hasattr(self, 'msg_index'): - self.msg_index = 0 - else: - if self.msg_index < len(msgs) - 1: - self.msg_index += 1 - else: - del self.msg_index - try: - msg_widget = msgs[self.msg_index] - msg = bui.textwidget(query=msg_widget) - msg = self._remove_sender_from_message(msg) - if msg in ('', ' '): - self._next_message() - return - except: - msg = '' - self._edit_text_msg_box(msg, 'replace') - - def _ip_port_msg(self): - try: - msg = f'IP : {_ip} PORT : {_port}' - except: - msg = '' - self._edit_text_msg_box(msg, 'replace') - - def ping_server(self): - try: - info = bs.get_connection_to_host_info().get( - 'name', '') if build_number < 21697 else bs.get_connection_to_host_info_2().name - if info != '': - self.pingThread = PingThread(_ip, _port) - self.pingThread.start() - except AttributeError: - pass - - def _get_ping_color(self): - try: - if _ping < 100: - return (0, 1, 0) - elif _ping < 500: - return (1, 1, 0) - else: - return (1, 0, 0) - except: - return (0.1, 0.1, 0.1) - - def _send_ping(self): - if isinstance(_ping, int): - bs.chatmessage(f'My ping = {_ping}ms') - - def close(self) -> None: - """Close the window.""" - bui.containerwidget(edit=self._root_widget, transition='out_scale') - - def close_with_sound(self) -> None: - """Close the window and make a lovely sound.""" - bui.getsound('swish').play() - self.close() - - def _get_popup_window_scale(self) -> float: - uiscale = bui.app.ui_v1.uiscale - return (2.4 if uiscale is babase.UIScale.SMALL else - 1.5 if uiscale is babase.UIScale.MEDIUM else 1.0) - - def _create_baLstr_list(self, list1): - return (babase.Lstr(value=i) for i in list1) - - def _get_player_info(self, clientID): - info = {} - for i in bs.get_game_roster(): - if i['client_id'] == clientID: - info['ds'] = i['display_string'] - info['players'] = i['players'] - info['aid'] = i['account_id'] - break - return info - - def _edit_text_msg_box(self, text, action='add'): - if isinstance(text, str): - if action == 'add': - bui.textwidget(edit=self._text_field, text=bui.textwidget( - query=self._text_field) + text) - elif action == 'replace': - bui.textwidget(edit=self._text_field, text=text) - - def _on_setting_button_press(self): - try: - SettingsWindow() - except Exception as e: - babase.print_exception() - pass - - def _on_privatechat_button_press(self): - try: - if messenger.logged_in: - self._firstcall = True - if self._chat_texts: - while self._chat_texts: - first = self._chat_texts.pop() - first.delete() - if not self._private_chat: - self._private_chat = True - else: - self._filter_text.delete() - self._popup_button.delete() - self._private_chat = False - self._update() - else: - if messenger.server_online: - if not messenger._cookie_login(): - if messenger._query(): - LoginWindow(wtype='login') - else: - LoginWindow(wtype='signup') - else: - display_error(messenger.error) - except Exception as e: - babase.print_exception() - pass - - def join_discord(self): - bui.open_url("https://discord.gg/KvYgpEg2JR") - - -class LoginWindow: - def __init__(self, wtype): - self.wtype = wtype - if self.wtype == 'signup': - title = 'Sign Up Window' - label = 'Sign Up' - else: - title = 'Login Window' - label = 'Log In' - uiscale = bui.app.ui_v1.uiscale - bg_color = babase.app.config.get('PartyWindow Main Color', (0.5, 0.5, 0.5)) - self._root_widget = bui.containerwidget(size=(500, 250), - transition='in_scale', - color=bg_color, - toolbar_visibility='menu_minimal_no_back', - parent=bui.get_special_widget('overlay_stack'), - on_outside_click_call=self._close, - scale=(2.1 if uiscale is babase.UIScale.SMALL else - 1.5 if uiscale is babase.UIScale.MEDIUM else 1.0), - stack_offset=(0, -10) if uiscale is babase.UIScale.SMALL else ( - 240, 0) if uiscale is babase.UIScale.MEDIUM else (330, 20)) - self._title_text = bui.textwidget(parent=self._root_widget, - scale=0.8, - color=(1, 1, 1), - text=title, - size=(0, 0), - position=(250, 200), - h_align='center', - v_align='center') - self._id = bui.textwidget(parent=self._root_widget, - scale=0.5, - color=(1, 1, 1), - text=f'Account: ' + - bui.app.plus.get_v1_account_misc_read_val_2( - 'resolvedAccountID', ''), - size=(0, 0), - position=(220, 170), - h_align='center', - v_align='center') - self._registrationkey_text = bui.textwidget(parent=self._root_widget, - scale=0.5, - color=(1, 1, 1), - text=f'Registration Key:', - size=(0, 0), - position=(100, 140), - h_align='center', - v_align='center') - self._text_field = bui.textwidget( - parent=self._root_widget, - editable=True, - size=(200, 40), - position=(175, 130), - text='', - maxwidth=410, - flatness=1.0, - autoselect=True, - v_align='center', - corner_scale=0.7) - self._connect_button = bui.buttonwidget(parent=self._root_widget, - size=(150, 30), - color=(0, 1, 0), - label='Get Registration Key', - button_type='square', - autoselect=True, - position=(150, 80), - on_activate_call=self._connect) - self._confirm_button = bui.buttonwidget(parent=self._root_widget, - size=(50, 30), - label=label, - button_type='square', - autoselect=True, - position=(200, 40), - on_activate_call=self._confirmcall) - bui.textwidget(edit=self._text_field, on_return_press_call=self._confirm_button.activate) - - def _close(self): - bui.containerwidget(edit=self._root_widget, - transition=('out_scale')) - - def _connect(self): - try: - host = url.split('http://')[1].split(':')[0] - import socket - address = socket.gethostbyname(host) - bs.disconnect_from_host() - bs.connect_to_party(address, port=11111) - except Exception: - display_error('Cant get ip from hostname') - - def _confirmcall(self): - if self.wtype == 'signup': - key = bui.textwidget(query=self._text_field) - answer = messenger._signup(registration_key=key) if key else None - if answer: - self._close() - else: - if messenger._login(registration_key=bui.textwidget(query=self._text_field)): - self._close() - - -class AddNewIdWindow: - def __init__(self): - uiscale = bui.app.ui_v1.uiscale - bg_color = babase.app.config.get('PartyWindow Main Color', (0.5, 0.5, 0.5)) - self._root_widget = bui.containerwidget(size=(500, 250), - transition='in_scale', - color=bg_color, - toolbar_visibility='menu_minimal_no_back', - parent=bui.get_special_widget('overlay_stack'), - on_outside_click_call=self._close, - scale=(2.1 if uiscale is babase.UIScale.SMALL else - 1.5 if uiscale is babase.UIScale.MEDIUM else 1.0)) - self._title_text = bui.textwidget(parent=self._root_widget, - scale=0.8, - color=(1, 1, 1), - text='Add New ID', - size=(0, 0), - position=(250, 200), - h_align='center', - v_align='center') - self._accountid_text = bui.textwidget(parent=self._root_widget, - scale=0.6, - color=(1, 1, 1), - text='pb-id: ', - size=(0, 0), - position=(50, 155), - h_align='center', - v_align='center') - self._accountid_field = bui.textwidget( - parent=self._root_widget, - editable=True, - size=(250, 40), - position=(100, 140), - text='', - maxwidth=410, - flatness=1.0, - autoselect=True, - v_align='center', - corner_scale=0.7) - self._nickname_text = bui.textwidget(parent=self._root_widget, - scale=0.5, - color=(1, 1, 1), - text='Nickname: ', - size=(0, 0), - position=(50, 115), - h_align='center', - v_align='center') - self._nickname_field = bui.textwidget( - parent=self._root_widget, - editable=True, - size=(250, 40), - position=(100, 100), - text='', - maxwidth=410, - flatness=1.0, - autoselect=True, - v_align='center', - corner_scale=0.7) - self._help_text = bui.textwidget(parent=self._root_widget, - scale=0.4, - color=(0.1, 0.9, 0.9), - text='Help:\nEnter pb-id of account you\n want to chat to\nEnter nickname of id to\n recognize id easily\nLeave nickname \n to use their default name', - size=(0, 0), - position=(325, 120), - h_align='left', - v_align='center') - self._add = bui.buttonwidget(parent=self._root_widget, - size=(50, 30), - label='Add', - button_type='square', - autoselect=True, - position=(100, 50), - on_activate_call=babase.Call(self._relay_function)) - bui.textwidget(edit=self._accountid_field, on_return_press_call=self._add.activate) - self._remove = bui.buttonwidget(parent=self._root_widget, - size=(75, 30), - label='Remove', - button_type='square', - autoselect=True, - position=(170, 50), - on_activate_call=self._remove_id) - bui.containerwidget(edit=self._root_widget, - on_cancel_call=self._close) - - def _relay_function(self): - account_id = bui.textwidget(query=self._accountid_field) - nickname = bui.textwidget(query=self._nickname_field) - try: - if messenger._save_id(account_id, nickname): - self._close() - except: - display_error('Enter valid pb-id') - - def _remove_id(self): - uiscale = bui.app.ui_v1.uiscale - if len(messenger.saved_ids) > 1: - choices = [i for i in messenger.saved_ids] - choices.remove('all') - choices_display = [babase.Lstr(value=messenger.saved_ids[i]) for i in choices] - PopupMenuWindow(position=self._remove.get_screen_space_center(), - color=babase.app.config.get('PartyWindow Main Color', (0.5, 0.5, 0.5)), - scale=(2.4 if uiscale is babase.UIScale.SMALL else - 1.5 if uiscale is babase.UIScale.MEDIUM else 1.0), - choices=choices, - choices_display=choices_display, - current_choice=choices[0], - delegate=self) - self._popup_type = 'removeSelectedID' - - def popup_menu_selected_choice(self, popup_window: PopupMenuWindow, - choice: str) -> None: - """Called when a choice is selected in the popup.""" - if self._popup_type == 'removeSelectedID': - messenger._remove_id(choice) - self._close() - - def popup_menu_closing(self, popup_window: PopupWindow) -> None: - """Called when the popup is closing.""" - - def _close(self): - bui.containerwidget(edit=self._root_widget, - transition=('out_scale')) - - -class AddNewChoiceWindow: - def __init__(self): - uiscale = bui.app.ui_v1.uiscale - bg_color = babase.app.config.get('PartyWindow Main Color', (0.5, 0.5, 0.5)) - self._root_widget = bui.containerwidget(size=(500, 250), - transition='in_scale', - color=bg_color, - toolbar_visibility='menu_minimal_no_back', - parent=bui.get_special_widget('overlay_stack'), - on_outside_click_call=self._close, - scale=(2.1 if uiscale is babase.UIScale.SMALL else - 1.5 if uiscale is babase.UIScale.MEDIUM else 1.0), - stack_offset=(0, -10) if uiscale is babase.UIScale.SMALL else ( - 240, 0) if uiscale is babase.UIScale.MEDIUM else (330, 20)) - self._title_text = bui.textwidget(parent=self._root_widget, - scale=0.8, - color=(1, 1, 1), - text='Add Custom Command', - size=(0, 0), - position=(250, 200), - h_align='center', - v_align='center') - self._text_field = bui.textwidget( - parent=self._root_widget, - editable=True, - size=(500, 40), - position=(75, 140), - text='', - maxwidth=410, - flatness=1.0, - autoselect=True, - v_align='center', - corner_scale=0.7) - self._help_text = bui.textwidget(parent=self._root_widget, - scale=0.4, - color=(0.2, 0.2, 0.2), - text='Use\n$c = client id\n$a = account id\n$n = name', - size=(0, 0), - position=(70, 75), - h_align='left', - v_align='center') - self._add = bui.buttonwidget(parent=self._root_widget, - size=(50, 30), - label='Add', - button_type='square', - autoselect=True, - position=(150, 50), - on_activate_call=self._add_choice) - bui.textwidget(edit=self._text_field, on_return_press_call=self._add.activate) - self._remove = bui.buttonwidget(parent=self._root_widget, - size=(50, 30), - label='Remove', - button_type='square', - autoselect=True, - position=(350, 50), - on_activate_call=self._remove_custom_command) - bui.containerwidget(edit=self._root_widget, - on_cancel_call=self._close) - - def _add_choice(self): - newCommand = bui.textwidget(query=self._text_field) - cfg = babase.app.config - if any(i in newCommand for i in ('$c', '$a', '$n')): - cfg['Custom Commands'].append(newCommand) - cfg.apply_and_commit() - bui.screenmessage('Added successfully', (0, 1, 0)) - bui.getsound('dingSmallHigh').play() - self._close() - else: - bui.screenmessage('Use at least of these ($c, $a, $n)', (1, 0, 0)) - bui.getsound('error').play() - - def _remove_custom_command(self): - uiscale = bui.app.ui_v1.uiscale - commands = babase.app.config['Custom Commands'] - PopupMenuWindow(position=self._remove.get_screen_space_center(), - color=babase.app.config.get('PartyWindow Main Color', (0.5, 0.5, 0.5)), - scale=(2.4 if uiscale is babase.UIScale.SMALL else - 1.5 if uiscale is babase.UIScale.MEDIUM else 1.0), - choices=commands, - current_choice=commands[0], - delegate=self) - self._popup_type = 'removeCustomCommandSelect' - - def popup_menu_selected_choice(self, popup_window: PopupMenuWindow, - choice: str) -> None: - """Called when a choice is selected in the popup.""" - if self._popup_type == 'removeCustomCommandSelect': - config = babase.app.config - config['Custom Commands'].remove(choice) - config.apply_and_commit() - bui.screenmessage('Removed successfully', (0, 1, 0)) - bui.getsound('shieldDown').play() - - def popup_menu_closing(self, popup_window: PopupWindow) -> None: - """Called when the popup is closing.""" - - def _close(self): - bui.containerwidget(edit=self._root_widget, - transition=('out_scale')) - - -class Manual_camera_window: - def __init__(self): - self._root_widget = bui.containerwidget( - on_outside_click_call=None, - size=(0, 0)) - button_size = (30, 30) - self._title_text = bui.textwidget(parent=self._root_widget, - scale=0.9, - color=(1, 1, 1), - text='Manual Camera Setup', - size=(0, 0), - position=(130, 153), - h_align='center', - v_align='center') - self._xminus = bui.buttonwidget(parent=self._root_widget, - size=button_size, - label=babase.charstr(babase.SpecialChar.LEFT_ARROW), - button_type='square', - autoselect=True, - position=(1, 60), - on_activate_call=babase.Call(self._change_camera_position, 'x-')) - self._xplus = bui.buttonwidget(parent=self._root_widget, - size=button_size, - label=babase.charstr(babase.SpecialChar.RIGHT_ARROW), - button_type='square', - autoselect=True, - position=(60, 60), - on_activate_call=babase.Call(self._change_camera_position, 'x')) - self._yplus = bui.buttonwidget(parent=self._root_widget, - size=button_size, - label=babase.charstr(babase.SpecialChar.UP_ARROW), - button_type='square', - autoselect=True, - position=(30, 100), - on_activate_call=babase.Call(self._change_camera_position, 'y')) - self._yminus = bui.buttonwidget(parent=self._root_widget, - size=button_size, - label=babase.charstr(babase.SpecialChar.DOWN_ARROW), - button_type='square', - autoselect=True, - position=(30, 20), - on_activate_call=babase.Call(self._change_camera_position, 'y-')) - self.inwards = bui.buttonwidget(parent=self._root_widget, - size=(100, 30), - label='INWARDS', - button_type='square', - autoselect=True, - position=(120, 90), - on_activate_call=babase.Call(self._change_camera_position, 'z-')) - self._outwards = bui.buttonwidget(parent=self._root_widget, - size=(100, 30), - label='OUTWARDS', - button_type='square', - autoselect=True, - position=(120, 50), - on_activate_call=babase.Call(self._change_camera_position, 'z')) - self._step_text = bui.textwidget(parent=self._root_widget, - scale=0.5, - color=(1, 1, 1), - text='Step:', - size=(0, 0), - position=(1, -20), - h_align='center', - v_align='center') - self._text_field = bui.textwidget( - parent=self._root_widget, - editable=True, - size=(100, 40), - position=(26, -35), - text='', - maxwidth=120, - flatness=1.0, - autoselect=True, - v_align='center', - corner_scale=0.7) - self._reset = bui.buttonwidget(parent=self._root_widget, - size=(50, 30), - label='Reset', - button_type='square', - autoselect=True, - position=(120, -35), - on_activate_call=babase.Call(self._change_camera_position, 'reset')) - self._done = bui.buttonwidget(parent=self._root_widget, - size=(50, 30), - label='Done', - button_type='square', - autoselect=True, - position=(180, -35), - on_activate_call=self._close) - bui.containerwidget(edit=self._root_widget, - cancel_button=self._done) - - def _close(self): - bui.containerwidget(edit=self._root_widget, - transition=('out_scale')) - - def _change_camera_position(self, direction): - activity = bs.get_foreground_host_activity() - node = activity.globalsnode - aoi = list(node.area_of_interest_bounds) - center = [(aoi[0] + aoi[3]) / 2, - (aoi[1] + aoi[4]) / 2, - (aoi[2] + aoi[5]) / 2] - size = (aoi[3] - aoi[0], - aoi[4] - aoi[1], - aoi[5] - aoi[2]) - - try: - increment = float(bui.textwidget(query=self._text_field)) - except: - # babase.print_exception() - increment = 1 - - if direction == 'x': - center[0] += increment - elif direction == 'x-': - center[0] -= increment - elif direction == 'y': - center[1] += increment - elif direction == 'y-': - center[1] -= increment - elif direction == 'z': - center[2] += increment - elif direction == 'z-': - center[2] -= increment - elif direction == 'reset': - node.area_of_interest_bounds = activity._map.get_def_bound_box( - 'area_of_interest_bounds') - return - - aoi = (center[0] - size[0] / 2, - center[1] - size[1] / 2, - center[2] - size[2] / 2, - center[0] + size[0] / 2, - center[1] + size[1] / 2, - center[2] + size[2] / 2) - node.area_of_interest_bounds = tuple(aoi) - - -def __popup_menu_window_init__(self, - position: Tuple[float, float], - choices: Sequence[str], - current_choice: str, - delegate: Any = None, - width: float = 230.0, - maxwidth: float = None, - scale: float = 1.0, - color: Tuple[float, float, float] = (0.35, 0.55, 0.15), - choices_disabled: Sequence[str] = None, - choices_display: Sequence[babase.Lstr] = None): - # FIXME: Clean up a bit. - # pylint: disable=too-many-branches - # pylint: disable=too-many-locals - # pylint: disable=too-many-statements - if choices_disabled is None: - choices_disabled = [] - if choices_display is None: - choices_display = [] - - # FIXME: For the moment we base our width on these strings so - # we need to flatten them. - choices_display_fin: List[str] = [] - for choice_display in choices_display: - choices_display_fin.append(choice_display.evaluate()) - - if maxwidth is None: - maxwidth = width * 1.5 - - self._transitioning_out = False - self._choices = list(choices) - self._choices_display = list(choices_display_fin) - self._current_choice = current_choice - self._color = color - self._choices_disabled = list(choices_disabled) - self._done_building = False - if not choices: - raise TypeError('Must pass at least one choice') - self._width = width - self._scale = scale - if len(choices) > 8: - self._height = 280 - self._use_scroll = True - else: - self._height = 20 + len(choices) * 33 - self._use_scroll = False - self._delegate = None # don't want this stuff called just yet.. - - # extend width to fit our longest string (or our max-width) - for index, choice in enumerate(choices): - if len(choices_display_fin) == len(choices): - choice_display_name = choices_display_fin[index] - else: - choice_display_name = choice - if self._use_scroll: - self._width = max( - self._width, - min( - maxwidth, - _babase.get_string_width(choice_display_name, - suppress_warning=True)) + 75) - else: - self._width = max( - self._width, - min( - maxwidth, - _babase.get_string_width(choice_display_name, - suppress_warning=True)) + 60) - - # init parent class - this will rescale and reposition things as - # needed and create our root widget - PopupWindow.__init__(self, - position, - size=(self._width, self._height), - bg_color=self._color, - scale=self._scale) - - if self._use_scroll: - self._scrollwidget = bui.scrollwidget(parent=self.root_widget, - position=(20, 20), - highlight=False, - color=(0.35, 0.55, 0.15), - size=(self._width - 40, - self._height - 40)) - self._columnwidget = bui.columnwidget(parent=self._scrollwidget, - border=2, - margin=0) - else: - self._offset_widget = bui.containerwidget(parent=self.root_widget, - position=(30, 15), - size=(self._width - 40, - self._height), - background=False) - self._columnwidget = bui.columnwidget(parent=self._offset_widget, - border=2, - margin=0) - for index, choice in enumerate(choices): - if len(choices_display_fin) == len(choices): - choice_display_name = choices_display_fin[index] - else: - choice_display_name = choice - inactive = (choice in self._choices_disabled) - wdg = bui.textwidget(parent=self._columnwidget, - size=(self._width - 40, 28), - on_select_call=babase.Call(self._select, index), - click_activate=True, - color=(0.5, 0.5, 0.5, 0.5) if inactive else - ((0.5, 1, 0.5, - 1) if choice == self._current_choice else - (0.8, 0.8, 0.8, 1.0)), - padding=0, - maxwidth=maxwidth, - text=choice_display_name, - on_activate_call=self._activate, - v_align='center', - selectable=(not inactive)) - if choice == self._current_choice: - bui.containerwidget(edit=self._columnwidget, - selected_child=wdg, - visible_child=wdg) - - # ok from now on our delegate can be called - self._delegate = weakref.ref(delegate) - self._done_building = True - - -original_connect_to_party = bs.connect_to_party -original_sign_in = babase.app.plus.sign_in_v1 - - -def modify_connect_to_party(address: str, port: int = 43210, print_progress: bool = True) -> None: - global _ip, _port - _ip = address - _port = port - original_connect_to_party(_ip, _port, print_progress) - - -temptimer = None - - -def modify_sign_in(account_type: str) -> None: - original_sign_in(account_type) - if messenger.server_online: - messenger.logged_in = False - global temptimer - temptimer = bs.Timer(2, messenger._cookie_login) - - -class PingThread(Thread): - """Thread for sending out game pings.""" - - def __init__(self, address: str, port: int): - super().__init__() - self._address = address - self._port = port - - def run(self) -> None: - sock: Optional[socket.socket] = None - try: - import socket - from babase._net import get_ip_address_type - socket_type = get_ip_address_type(self._address) - sock = socket.socket(socket_type, socket.SOCK_DGRAM) - sock.connect((self._address, self._port)) - - starttime = time.time() - - # Send a few pings and wait a second for - # a response. - sock.settimeout(1) - for _i in range(3): - sock.send(b'\x0b') - result: Optional[bytes] - try: - # 11: BA_PACKET_SIMPLE_PING - result = sock.recv(10) - except Exception: - result = None - if result == b'\x0c': - # 12: BA_PACKET_SIMPLE_PONG - accessible = True - break - time.sleep(1) - global _ping - _ping = int((time.time() - starttime) * 1000.0) - except Exception: - babase.print_exception('Error on gather ping', once=True) - finally: - try: - if sock is not None: - sock.close() - except Exception: - babase.print_exception('Error on gather ping cleanup', once=True) - - -def _get_store_char_tex(self) -> str: - return ('storeCharacterXmas' if bui.app.plus.get_v1_account_misc_read_val( - 'xmas', False) else - 'storeCharacterEaster' if bui.app.plus.get_v1_account_misc_read_val( - 'easter', False) else 'storeCharacter') - - -class NewMainMenuWindow(mainmenu.MainMenuWindow): - def __init__(self, *args, **kwargs): - super().__init__(*args, **kwargs) - # Display chat icon, but if user open/close gather it may disappear - bui.set_party_icon_always_visible(True) - -# ba_meta export plugin - - -class InitalRun(babase.Plugin): - def __init__(self): - if build_number >= 21140: - global messenger, listener, displayer, color_tracker - initialize() - messenger = PrivateChatHandler() - listener = Thread(target=messenger_thread) - listener.start() - displayer = bs.AppTimer(0.4, msg_displayer, repeat=True) - color_tracker = ColorTracker() - bauiv1lib.party.PartyWindow = PartyWindow - mainmenu.MainMenuWindow = NewMainMenuWindow - PopupMenuWindow.__init__ = __popup_menu_window_init__ - bs.connect_to_party = modify_connect_to_party - babase.app.plus.sign_in_v1 = modify_sign_in - MainMenuWindow._get_store_char_tex = _get_store_char_tex - else: - display_error("This Party Window only runs with BombSquad version higer than 1.7.19.") From 284055e896bf2aaefee9b9be7d84194ac54451b3 Mon Sep 17 00:00:00 2001 From: brostos <67740566+brostosjoined@users.noreply.github.com> Date: Sun, 21 Jan 2024 16:21:33 +0300 Subject: [PATCH 0814/1464] Update utilities.json --- plugins/utilities.json | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/plugins/utilities.json b/plugins/utilities.json index af01c314..463afd4a 100644 --- a/plugins/utilities.json +++ b/plugins/utilities.json @@ -63,12 +63,7 @@ } ], "versions": { - "1.3.2": { - "api_version": 8, - "commit_sha": "a0bff95", - "released_on": "20-01-2024", - "md5sum": "1cf2d07d15dbacf0a277795f3742c14b" - }, + "1.3.2": null, "1.3.1": { "api_version": 7, "commit_sha": "d511c15", @@ -1073,4 +1068,4 @@ } } } -} \ No newline at end of file +} From 51439fc5d059e0cef71247fb4fe3419991823450 Mon Sep 17 00:00:00 2001 From: brostosjoined Date: Sun, 21 Jan 2024 13:21:57 +0000 Subject: [PATCH 0815/1464] [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 463afd4a..a070a104 100644 --- a/plugins/utilities.json +++ b/plugins/utilities.json @@ -63,7 +63,12 @@ } ], "versions": { - "1.3.2": null, + "1.3.2": { + "api_version": 8, + "commit_sha": "284055e", + "released_on": "21-01-2024", + "md5sum": "1cf2d07d15dbacf0a277795f3742c14b" + }, "1.3.1": { "api_version": 7, "commit_sha": "d511c15", @@ -1068,4 +1073,4 @@ } } } -} +} \ No newline at end of file From e3d12d577bda7ac8af27cb6affcd6fc3874ed7fc Mon Sep 17 00:00:00 2001 From: brostosjoined Date: Sun, 21 Jan 2024 16:30:56 +0300 Subject: [PATCH 0816/1464] ultra_party -> api7 --- plugins/utilities/ultra_party_window.py | 2755 +++++++++++++++++++++++ 1 file changed, 2755 insertions(+) create mode 100644 plugins/utilities/ultra_party_window.py diff --git a/plugins/utilities/ultra_party_window.py b/plugins/utilities/ultra_party_window.py new file mode 100644 index 00000000..2d39444b --- /dev/null +++ b/plugins/utilities/ultra_party_window.py @@ -0,0 +1,2755 @@ +__author__ = 'Droopy' +__version__ = 4.0 + +# ba_meta require api 7 +import datetime +import json +import math +import os +import pickle +import random +import time +import urllib.request +import weakref +from threading import Thread +from typing import List, Tuple, Sequence, Optional, Dict, Any, cast +from hashlib import md5 + +import _ba +import ba +import bastd.ui.party +from bastd.ui.colorpicker import ColorPickerExact +from bastd.ui.confirm import ConfirmWindow +from bastd.ui.mainmenu import MainMenuWindow +from bastd.ui.popup import PopupMenuWindow, PopupWindow, PopupMenu + +_ip = '127.0.0.1' +_port = 43210 +_ping = '-' +url = 'http://bombsquadprivatechat.ml' +last_msg = None + +my_directory = _ba.env()['python_directory_user'] + '/UltraPartyWindowFiles/' +quick_msg_file = my_directory + 'QuickMessages.txt' +cookies_file = my_directory + 'cookies.txt' +saved_ids_file = my_directory + 'saved_ids.json' +my_location = my_directory + + +def initialize(): + config_defaults = {'Party Chat Muted': False, + 'Chat Muted': False, + 'ping button': True, + 'IP button': True, + 'copy button': True, + 'Direct Send': False, + 'Colorful Chat': True, + 'Custom Commands': [], + 'Message Notification': 'bottom', + 'Self Status': 'online', + 'Translate Source Language': '', + 'Translate Destination Language': 'en', + 'Pronunciation': True + } + config = ba.app.config + for key in config_defaults: + if key not in config: + config[key] = config_defaults[key] + + if not os.path.exists(my_directory): + os.makedirs(my_directory) + if not os.path.exists(cookies_file): + with open(cookies_file, 'wb') as f: + pickle.dump({}, f) + if not os.path.exists(saved_ids_file): + with open(saved_ids_file, 'w') as f: + data = {} + json.dump(data, f) + + +def display_error(msg=None): + if msg: + ba.screenmessage(msg, (1, 0, 0)) + else: + ba.screenmessage('Failed!', (1, 0, 0)) + ba.playsound(ba.getsound('error')) + + +def display_success(msg=None): + if msg: + ba.screenmessage(msg, (0, 1, 0)) + else: + ba.screenmessage('Successful!', (0, 1, 0)) + + +class Translate(Thread): + def __init__(self, data, callback): + super().__init__() + self.data = data + self._callback = callback + + def run(self): + _ba.pushcall(ba.Call(ba.screenmessage, 'Translating...'), from_other_thread=True) + response = messenger._send_request(f'{url}/translate', self.data) + if response: + _ba.pushcall(ba.Call(self._callback, response), from_other_thread=True) + + +class ColorTracker: + def __init__(self): + self.saved = {} + + def _get_safe_color(self, sender): + while True: + color = (random.random(), random.random(), random.random()) + s = 0 + background = ba.app.config.get('PartyWindow Main Color', (0.5, 0.5, 0.5)) + for i, j in zip(color, background): + s += (i - j) ** 2 + if s > 0.1: + self.saved[sender] = color + if len(self.saved) > 20: + self.saved.pop(list(self.saved.keys())[0]) + break + time.sleep(0.1) + + def _get_sender_color(self, sender): + if sender not in self.saved: + self.thread = Thread(target=self._get_safe_color, args=(sender,)) + self.thread.start() + return (1, 1, 1) + else: + return self.saved[sender] + + +class PrivateChatHandler: + def __init__(self): + self.pvt_msgs = {} + self.login_id = None + self.last_msg_id = None + self.logged_in = False + self.cookieProcessor = urllib.request.HTTPCookieProcessor() + self.opener = urllib.request.build_opener(self.cookieProcessor) + self.filter = 'all' + self.pending_messages = [] + self.friends_status = {} + self.error = '' + Thread(target=self._ping).start() + + def _load_ids(self): + with open(saved_ids_file, 'r') as f: + saved = json.load(f) + if self.myid in saved: + self.saved_ids = saved[self.myid] + else: + self.saved_ids = {'all': ''} + + def _dump_ids(self): + with open(saved_ids_file, 'r') as f: + saved = json.load(f) + with open(saved_ids_file, 'w') as f: + saved[self.myid] = self.saved_ids + json.dump(saved, f) + + def _ping(self): + self.server_online = False + response = self._send_request(url=f'{url}') + if not response: + self.error = 'Server offline' + elif response: + try: + self.server_online = True + version = float(response.replace('v', '')) + except: + self.error = 'Server offline' + + def _signup(self, registration_key): + data = dict(pb_id=self.myid, registration_key=registration_key) + response = self._send_request(url=f'{url}/signup', data=data) + if response: + if response == 'successful': + display_success('Account Created Successfully') + self._login(registration_key=registration_key) + return True + display_error(response) + + def _save_cookie(self): + with open(cookies_file, 'rb') as f: + cookies = pickle.load(f) + with open(cookies_file, 'wb') as f: + for c in self.cookieProcessor.cookiejar: + cookie = pickle.dumps(c) + break + cookies[self.myid] = cookie + pickle.dump(cookies, f) + + def _cookie_login(self): + self.myid = ba.internal.get_v1_account_misc_read_val_2('resolvedAccountID', '') + try: + with open(cookies_file, 'rb') as f: + cookies = pickle.load(f) + except: + return False + if self.myid in cookies: + cookie = pickle.loads(cookies[self.myid]) + self.cookieProcessor.cookiejar.set_cookie(cookie) + self.opener = urllib.request.build_opener(self.cookieProcessor) + response = self._send_request(url=f'{url}/login') + if response.startswith('logged in as'): + self.logged_in = True + self._load_ids() + display_success(response) + return True + + def _login(self, registration_key): + self.myid = ba.internal.get_v1_account_misc_read_val_2('resolvedAccountID', '') + data = dict(pb_id=self.myid, registration_key=registration_key) + response = self._send_request(url=f'{url}/login', data=data) + if response == 'successful': + self.logged_in = True + self._load_ids() + self._save_cookie() + display_success('Account Logged in Successfully') + return True + else: + display_error(response) + + def _query(self, pb_id=None): + if not pb_id: + pb_id = self.myid + response = self._send_request(url=f'{url}/query/{pb_id}') + if response == 'exists': + return True + return False + + def _send_request(self, url, data=None): + try: + if not data: + response = self.opener.open(url) + else: + response = self.opener.open(url, data=json.dumps(data).encode()) + if response.getcode() != 200: + display_error(response.read().decode()) + return None + else: + return response.read().decode() + except: + return None + + def _save_id(self, account_id, nickname='', verify=True): + # display_success(f'Saving {account_id}. Please wait...') + if verify: + url = 'http://bombsquadgame.com/accountquery?id=' + account_id + response = json.loads(urllib.request.urlopen(url).read().decode()) + if 'error' in response: + display_error('Enter valid account id') + return False + self.saved_ids[account_id] = {} + name = None + if nickname == '': + name_html = response['name_html'] + name = name_html.split('>')[1] + nick = name if name else nickname + else: + nick = nickname + self.saved_ids[account_id] = nick + self._dump_ids() + display_success(f'Account added: {nick}({account_id})') + return True + + def _remove_id(self, account_id): + removed = self.saved_ids.pop(account_id) + self._dump_ids() + ba.screenmessage(f'Removed successfully: {removed}({account_id})', (0, 1, 0)) + ba.playsound(ba.getsound('shieldDown')) + + def _format_message(self, msg): + filter = msg['filter'] + if filter in self.saved_ids: + if self.filter == 'all': + message = '[' + self.saved_ids[filter] + ']' + msg['message'] + else: + message = msg['message'] + else: + message = '[' + msg['filter'] + ']: ' + \ + 'Message from unsaved id. Save id to view message.' + return message + + def _get_status(self, id, type='status'): + info = self.friends_status.get(id, {}) + if not info: + return '-' + if type == 'status': + return info['status'] + else: + last_seen = info["last_seen"] + last_seen = _get_local_time(last_seen) + ba.screenmessage(f'Last seen on: {last_seen}') + + +def _get_local_time(utctime): + d = datetime.datetime.strptime(utctime, '%d-%m-%Y %H:%M:%S') + d = d.replace(tzinfo=datetime.timezone.utc) + d = d.astimezone() + return d.strftime('%B %d,\t\t%H:%M:%S') + + +def update_status(): + if messenger.logged_in: + if ba.app.config['Self Status'] == 'online': + host = _ba.get_connection_to_host_info().get('name', '') + if host: + my_status = f'Playing in {host}' + else: + my_status = 'in Lobby' + ids_to_check = [i for i in messenger.saved_ids if i != 'all'] + response = messenger._send_request(url=f'{url}/updatestatus', + data=dict(self_status=my_status, ids=ids_to_check)) + if response: + messenger.friends_status = json.loads(response) + else: + messenger.friends_status = {} + + +def messenger_thread(): + counter = 0 + while True: + counter += 1 + time.sleep(0.6) + check_new_message() + if counter > 5: + counter = 0 + update_status() + + +def check_new_message(): + if messenger.logged_in: + if messenger.login_id != messenger.myid: + response = messenger._send_request(f'{url}/first') + if response: + messenger.pvt_msgs = json.loads(response) + if messenger.pvt_msgs['all']: + messenger.last_msg_id = messenger.pvt_msgs['all'][-1]['id'] + messenger.login_id = messenger.myid + else: + response = messenger._send_request(f'{url}/new/{messenger.last_msg_id}') + if response: + new_msgs = json.loads(response) + if new_msgs: + for msg in new_msgs['messages']: + if msg['id'] > messenger.last_msg_id: + messenger.last_msg_id = msg['id'] + messenger.pvt_msgs['all'].append( + dict(id=msg['id'], filter=msg['filter'], message=msg['message'], sent=msg['sent'])) + if len(messenger.pvt_msgs['all']) > 40: + messenger.pvt_msgs['all'].pop(0) + if msg['filter'] not in messenger.pvt_msgs: + messenger.pvt_msgs[msg['filter']] = [ + dict(id=msg['id'], filter=msg['filter'], message=msg['message'], sent=msg['sent'])] + else: + messenger.pvt_msgs[msg['filter']].append( + dict(id=msg['id'], filter=msg['filter'], message=msg['message'], sent=msg['sent'])) + if len(messenger.pvt_msgs[msg['filter']]) > 20: + messenger.pvt_msgs[msg['filter']].pop(0) + messenger.pending_messages.append( + (messenger._format_message(msg), msg['filter'], msg['sent'])) + + +def display_message(msg, msg_type, filter=None, sent=None): + flag = None + notification = ba.app.config['Message Notification'] + if _ba.app.ui.party_window: + if _ba.app.ui.party_window(): + if _ba.app.ui.party_window()._private_chat: + flag = 1 + if msg_type == 'private': + if messenger.filter == filter or messenger.filter == 'all': + _ba.app.ui.party_window().on_chat_message(msg, sent) + else: + if notification == 'top': + ba.screenmessage(msg, (1, 1, 0), True, ba.gettexture('coin')) + else: + ba.screenmessage(msg, (1, 1, 0), False) + else: + ba.screenmessage(msg, (0.2, 1.0, 1.0), True, ba.gettexture('circleShadow')) + else: + flag = 1 + if msg_type == 'private': + if notification == 'top': + ba.screenmessage(msg, (1, 1, 0), True, ba.gettexture('coin')) + else: + ba.screenmessage(msg, (1, 1, 0), False) + if not flag: + if msg_type == 'private': + if notification == 'top': + ba.screenmessage(msg, (1, 1, 0), True, ba.gettexture('coin')) + else: + ba.screenmessage(msg, (1, 1, 0), False) + else: + ba.screenmessage(msg, (0.2, 1.0, 1.0), True, ba.gettexture('circleShadow')) + + +def msg_displayer(): + for msg in messenger.pending_messages: + display_message(msg[0], 'private', msg[1], msg[2]) + messenger.pending_messages.remove(msg) + if ba.app.config['Chat Muted'] and not ba.app.config['Party Chat Muted']: + global last_msg + last = _ba.get_chat_messages() + lm = last[-1] if last else None + if lm != last_msg: + last_msg = lm + display_message(lm, 'public') + + +class SortQuickMessages: + def __init__(self): + uiscale = ba.app.ui.uiscale + bg_color = ba.app.config.get('PartyWindow Main Color', (0.5, 0.5, 0.5)) + self._width = 750 if uiscale is ba.UIScale.SMALL else 600 + self._height = (300 if uiscale is ba.UIScale.SMALL else + 325 if uiscale is ba.UIScale.MEDIUM else 350) + self._root_widget = ba.containerwidget( + size=(self._width, self._height), + transition='in_right', + on_outside_click_call=self._save, + color=bg_color, + parent=_ba.get_special_widget('overlay_stack'), + scale=(2.0 if uiscale is ba.UIScale.SMALL else + 1.3 if uiscale is ba.UIScale.MEDIUM else 1.0), + stack_offset=(0, -16) if uiscale is ba.UIScale.SMALL else (0, 0)) + ba.textwidget(parent=self._root_widget, + position=(-10, self._height - 50), + size=(self._width, 25), + text='Sort Quick Messages', + color=ba.app.ui.title_color, + scale=1.05, + h_align='center', + v_align='center', + maxwidth=270) + b_textcolor = (0.4, 0.75, 0.5) + up_button = ba.buttonwidget(parent=self._root_widget, + position=(10, 170), + size=(75, 75), + on_activate_call=self._move_up, + label=ba.charstr(ba.SpecialChar.UP_ARROW), + button_type='square', + color=bg_color, + textcolor=b_textcolor, + autoselect=True, + repeat=True) + down_button = ba.buttonwidget(parent=self._root_widget, + position=(10, 75), + size=(75, 75), + on_activate_call=self._move_down, + label=ba.charstr(ba.SpecialChar.DOWN_ARROW), + button_type='square', + color=bg_color, + textcolor=b_textcolor, + autoselect=True, + repeat=True) + self._scroll_width = self._width - 150 + self._scroll_height = self._height - 110 + self._scrollwidget = ba.scrollwidget( + parent=self._root_widget, + size=(self._scroll_width, self._scroll_height), + color=bg_color, + position=(100, 40)) + self._columnwidget = ba.columnwidget( + parent=self._scrollwidget, + border=2, + margin=0) + with open(quick_msg_file, 'r') as f: + self.msgs = f.read().split('\n') + self._msg_selected = None + self._refresh() + ba.containerwidget(edit=self._root_widget, + on_cancel_call=self._save) + + def _refresh(self): + for child in self._columnwidget.get_children(): + child.delete() + for msg in enumerate(self.msgs): + txt = ba.textwidget( + parent=self._columnwidget, + size=(self._scroll_width - 10, 30), + selectable=True, + always_highlight=True, + on_select_call=ba.Call(self._on_msg_select, msg), + text=msg[1], + h_align='left', + v_align='center', + maxwidth=self._scroll_width) + if msg == self._msg_selected: + ba.columnwidget(edit=self._columnwidget, + selected_child=txt, + visible_child=txt) + + def _on_msg_select(self, msg): + self._msg_selected = msg + + def _move_up(self): + index = self._msg_selected[0] + msg = self._msg_selected[1] + if index: + self.msgs.insert((index - 1), self.msgs.pop(index)) + self._msg_selected = (index - 1, msg) + self._refresh() + + def _move_down(self): + index = self._msg_selected[0] + msg = self._msg_selected[1] + if index + 1 < len(self.msgs): + self.msgs.insert((index + 1), self.msgs.pop(index)) + self._msg_selected = (index + 1, msg) + self._refresh() + + def _save(self) -> None: + try: + with open(quick_msg_file, 'w') as f: + f.write('\n'.join(self.msgs)) + except: + ba.print_exception() + ba.screenmessage('Error!', (1, 0, 0)) + ba.containerwidget( + edit=self._root_widget, + transition='out_right') + + +class TranslationSettings: + def __init__(self): + uiscale = ba.app.ui.uiscale + height = (300 if uiscale is ba.UIScale.SMALL else + 350 if uiscale is ba.UIScale.MEDIUM else 400) + width = (500 if uiscale is ba.UIScale.SMALL else + 600 if uiscale is ba.UIScale.MEDIUM else 650) + self._transition_out: Optional[str] + scale_origin: Optional[Tuple[float, float]] + self._transition_out = 'out_scale' + scale_origin = 10 + transition = 'in_scale' + scale_origin = None + cancel_is_selected = False + cfg = ba.app.config + bg_color = cfg.get('PartyWindow Main Color', (0.5, 0.5, 0.5)) + + LANGUAGES = { + '': 'Auto-Detect', + 'af': 'afrikaans', + 'sq': 'albanian', + 'am': 'amharic', + 'ar': 'arabic', + 'hy': 'armenian', + 'az': 'azerbaijani', + 'eu': 'basque', + 'be': 'belarusian', + 'bn': 'bengali', + 'bs': 'bosnian', + 'bg': 'bulgarian', + 'ca': 'catalan', + 'ceb': 'cebuano', + 'ny': 'chichewa', + 'zh-cn': 'chinese (simplified)', + 'zh-tw': 'chinese (traditional)', + 'co': 'corsican', + 'hr': 'croatian', + 'cs': 'czech', + 'da': 'danish', + 'nl': 'dutch', + 'en': 'english', + 'eo': 'esperanto', + 'et': 'estonian', + 'tl': 'filipino', + 'fi': 'finnish', + 'fr': 'french', + 'fy': 'frisian', + 'gl': 'galician', + 'ka': 'georgian', + 'de': 'german', + 'el': 'greek', + 'gu': 'gujarati', + 'ht': 'haitian creole', + 'ha': 'hausa', + 'haw': 'hawaiian', + 'iw': 'hebrew', + 'he': 'hebrew', + 'hi': 'hindi', + 'hmn': 'hmong', + 'hu': 'hungarian', + 'is': 'icelandic', + 'ig': 'igbo', + 'id': 'indonesian', + 'ga': 'irish', + 'it': 'italian', + 'ja': 'japanese', + 'jw': 'javanese', + 'kn': 'kannada', + 'kk': 'kazakh', + 'km': 'khmer', + 'ko': 'korean', + 'ku': 'kurdish (kurmanji)', + 'ky': 'kyrgyz', + 'lo': 'lao', + 'la': 'latin', + 'lv': 'latvian', + 'lt': 'lithuanian', + 'lb': 'luxembourgish', + 'mk': 'macedonian', + 'mg': 'malagasy', + 'ms': 'malay', + 'ml': 'malayalam', + 'mt': 'maltese', + 'mi': 'maori', + 'mr': 'marathi', + 'mn': 'mongolian', + 'my': 'myanmar (burmese)', + 'ne': 'nepali', + 'no': 'norwegian', + 'or': 'odia', + 'ps': 'pashto', + 'fa': 'persian', + 'pl': 'polish', + 'pt': 'portuguese', + 'pa': 'punjabi', + 'ro': 'romanian', + 'ru': 'russian', + 'sm': 'samoan', + 'gd': 'scots gaelic', + 'sr': 'serbian', + 'st': 'sesotho', + 'sn': 'shona', + 'sd': 'sindhi', + 'si': 'sinhala', + 'sk': 'slovak', + 'sl': 'slovenian', + 'so': 'somali', + 'es': 'spanish', + 'su': 'sundanese', + 'sw': 'swahili', + 'sv': 'swedish', + 'tg': 'tajik', + 'ta': 'tamil', + 'te': 'telugu', + 'th': 'thai', + 'tr': 'turkish', + 'uk': 'ukrainian', + 'ur': 'urdu', + 'ug': 'uyghur', + 'uz': 'uzbek', + 'vi': 'vietnamese', + 'cy': 'welsh', + 'xh': 'xhosa', + 'yi': 'yiddish', + 'yo': 'yoruba', + 'zu': 'zulu'} + + self.root_widget = ba.containerwidget( + size=(width, height), + color=bg_color, + transition=transition, + toolbar_visibility='menu_minimal_no_back', + parent=_ba.get_special_widget('overlay_stack'), + on_outside_click_call=self._cancel, + scale=(2.1 if uiscale is ba.UIScale.SMALL else + 1.5 if uiscale is ba.UIScale.MEDIUM else 1.0), + scale_origin_stack_offset=scale_origin) + ba.textwidget(parent=self.root_widget, + position=(width * 0.5, height - 45), + size=(20, 20), + h_align='center', + v_align='center', + text="Text Translation", + scale=0.9, + color=(5, 5, 5)) + cbtn = btn = ba.buttonwidget(parent=self.root_widget, + autoselect=True, + position=(30, height - 60), + size=(30, 30), + label=ba.charstr(ba.SpecialChar.BACK), + button_type='backSmall', + on_activate_call=self._cancel) + + source_lang_text = ba.textwidget(parent=self.root_widget, + position=(40, height - 110), + size=(20, 20), + h_align='left', + v_align='center', + text="Source Language : ", + scale=0.9, + color=(1, 1, 1)) + + source_lang_menu = PopupMenu( + parent=self.root_widget, + position=(330 if uiscale is ba.UIScale.SMALL else 400, height - 115), + width=200, + scale=(2.8 if uiscale is ba.UIScale.SMALL else + 1.8 if uiscale is ba.UIScale.MEDIUM else 1.2), + current_choice=cfg['Translate Source Language'], + choices=LANGUAGES.keys(), + choices_display=(ba.Lstr(value=i) for i in LANGUAGES.values()), + button_size=(130, 35), + on_value_change_call=self._change_source) + + destination_lang_text = ba.textwidget(parent=self.root_widget, + position=(40, height - 165), + size=(20, 20), + h_align='left', + v_align='center', + text="Destination Language : ", + scale=0.9, + color=(1, 1, 1)) + + destination_lang_menu = PopupMenu( + parent=self.root_widget, + position=(330 if uiscale is ba.UIScale.SMALL else 400, height - 170), + width=200, + scale=(2.8 if uiscale is ba.UIScale.SMALL else + 1.8 if uiscale is ba.UIScale.MEDIUM else 1.2), + current_choice=cfg['Translate Destination Language'], + choices=list(LANGUAGES.keys())[1:], + choices_display=list(ba.Lstr(value=i) for i in LANGUAGES.values())[1:], + button_size=(130, 35), + on_value_change_call=self._change_destination) + + try: + + translation_mode_text = ba.textwidget(parent=self.root_widget, + position=(40, height - 215), + size=(20, 20), + h_align='left', + v_align='center', + text="Translate Mode", + scale=0.9, + color=(1, 1, 1)) + decoration = ba.textwidget(parent=self.root_widget, + position=(40, height - 225), + size=(20, 20), + h_align='left', + v_align='center', + text="________________", + scale=0.9, + color=(1, 1, 1)) + + language_char_text = ba.textwidget(parent=self.root_widget, + position=(85, height - 273), + size=(20, 20), + h_align='left', + v_align='center', + text='Normal Translation', + scale=0.6, + color=(1, 1, 1)) + + pronunciation_text = ba.textwidget(parent=self.root_widget, + position=(295, height - 273), + size=(20, 20), + h_align='left', + v_align='center', + text="Show Prononciation", + scale=0.6, + color=(1, 1, 1)) + + from bastd.ui.radiogroup import make_radio_group + cur_val = ba.app.config.get('Pronunciation', True) + cb1 = ba.checkboxwidget( + parent=self.root_widget, + position=(250, height - 275), + size=(20, 20), + maxwidth=300, + scale=1, + autoselect=True, + text="") + cb2 = ba.checkboxwidget( + parent=self.root_widget, + position=(40, height - 275), + size=(20, 20), + maxwidth=300, + scale=1, + autoselect=True, + text="") + make_radio_group((cb1, cb2), (True, False), cur_val, + self._actions_changed) + except Exception as e: + print(e) + pass + + ba.containerwidget(edit=self.root_widget, cancel_button=btn) + + def _change_source(self, choice): + cfg = ba.app.config + cfg['Translate Source Language'] = choice + cfg.apply_and_commit() + + def _change_destination(self, choice): + cfg = ba.app.config + cfg['Translate Destination Language'] = choice + cfg.apply_and_commit() + + def _actions_changed(self, v: str) -> None: + cfg = ba.app.config + cfg['Pronunciation'] = v + cfg.apply_and_commit() + + def _cancel(self) -> None: + ba.containerwidget(edit=self.root_widget, transition='out_scale') + SettingsWindow() + + +class SettingsWindow: + + def __init__(self): + uiscale = ba.app.ui.uiscale + height = (300 if uiscale is ba.UIScale.SMALL else + 350 if uiscale is ba.UIScale.MEDIUM else 400) + width = (500 if uiscale is ba.UIScale.SMALL else + 600 if uiscale is ba.UIScale.MEDIUM else 650) + scroll_h = (200 if uiscale is ba.UIScale.SMALL else + 250 if uiscale is ba.UIScale.MEDIUM else 270) + scroll_w = (450 if uiscale is ba.UIScale.SMALL else + 550 if uiscale is ba.UIScale.MEDIUM else 600) + self._transition_out: Optional[str] + scale_origin: Optional[Tuple[float, float]] + self._transition_out = 'out_scale' + scale_origin = 10 + transition = 'in_scale' + scale_origin = None + cancel_is_selected = False + cfg = ba.app.config + bg_color = cfg.get('PartyWindow Main Color', (0.5, 0.5, 0.5)) + + self.root_widget = ba.containerwidget( + size=(width, height), + color=bg_color, + transition=transition, + toolbar_visibility='menu_minimal_no_back', + parent=_ba.get_special_widget('overlay_stack'), + on_outside_click_call=self._cancel, + scale=(2.1 if uiscale is ba.UIScale.SMALL else + 1.5 if uiscale is ba.UIScale.MEDIUM else 1.0), + scale_origin_stack_offset=scale_origin) + ba.textwidget(parent=self.root_widget, + position=(width * 0.5, height - 45), + size=(20, 20), + h_align='center', + v_align='center', + text="Custom Settings", + scale=0.9, + color=(5, 5, 5)) + cbtn = btn = ba.buttonwidget(parent=self.root_widget, + autoselect=True, + position=(30, height - 60), + size=(30, 30), + label=ba.charstr(ba.SpecialChar.BACK), + button_type='backSmall', + on_activate_call=self._cancel) + scroll_position = (30 if uiscale is ba.UIScale.SMALL else + 40 if uiscale is ba.UIScale.MEDIUM else 50) + self._scrollwidget = ba.scrollwidget(parent=self.root_widget, + position=(30, scroll_position), + simple_culling_v=20.0, + highlight=False, + size=(scroll_w, scroll_h), + selection_loops_to_parent=True) + ba.widget(edit=self._scrollwidget, right_widget=self._scrollwidget) + self._subcontainer = ba.columnwidget(parent=self._scrollwidget, + selection_loops_to_parent=True) + ip_button = ba.checkboxwidget( + parent=self._subcontainer, + size=(300, 30), + maxwidth=300, + textcolor=((0, 1, 0) if cfg['IP button'] else (0.95, 0.65, 0)), + scale=1, + value=cfg['IP button'], + autoselect=True, + text="IP Button", + on_value_change_call=self.ip_button) + ping_button = ba.checkboxwidget( + parent=self._subcontainer, + size=(300, 30), + maxwidth=300, + textcolor=((0, 1, 0) if cfg['ping button'] else (0.95, 0.65, 0)), + scale=1, + value=cfg['ping button'], + autoselect=True, + text="Ping Button", + on_value_change_call=self.ping_button) + copy_button = ba.checkboxwidget( + parent=self._subcontainer, + size=(300, 30), + maxwidth=300, + textcolor=((0, 1, 0) if cfg['copy button'] else (0.95, 0.65, 0)), + scale=1, + value=cfg['copy button'], + autoselect=True, + text="Copy Text Button", + on_value_change_call=self.copy_button) + direct_send = ba.checkboxwidget( + parent=self._subcontainer, + size=(300, 30), + maxwidth=300, + textcolor=((0, 1, 0) if cfg['Direct Send'] else (0.95, 0.65, 0)), + scale=1, + value=cfg['Direct Send'], + autoselect=True, + text="Directly Send Custom Commands", + on_value_change_call=self.direct_send) + colorfulchat = ba.checkboxwidget( + parent=self._subcontainer, + size=(300, 30), + maxwidth=300, + textcolor=((0, 1, 0) if cfg['Colorful Chat'] else (0.95, 0.65, 0)), + scale=1, + value=cfg['Colorful Chat'], + autoselect=True, + text="Colorful Chat", + on_value_change_call=self.colorful_chat) + msg_notification_text = ba.textwidget(parent=self._subcontainer, + scale=0.8, + color=(1, 1, 1), + text='Message Notifcation:', + size=(100, 30), + h_align='left', + v_align='center') + msg_notification_widget = PopupMenu( + parent=self._subcontainer, + position=(100, height - 1200), + width=200, + scale=(2.8 if uiscale is ba.UIScale.SMALL else + 1.8 if uiscale is ba.UIScale.MEDIUM else 1.2), + choices=['top', 'bottom'], + current_choice=ba.app.config['Message Notification'], + button_size=(80, 25), + on_value_change_call=self._change_notification) + self_status_text = ba.textwidget(parent=self._subcontainer, + scale=0.8, + color=(1, 1, 1), + text='Self Status:', + size=(100, 30), + h_align='left', + v_align='center') + self_status_widget = PopupMenu( + parent=self._subcontainer, + position=(50, height - 1000), + width=200, + scale=(2.8 if uiscale is ba.UIScale.SMALL else + 1.8 if uiscale is ba.UIScale.MEDIUM else 1.2), + choices=['online', 'offline'], + current_choice=ba.app.config['Self Status'], + button_size=(80, 25), + on_value_change_call=self._change_status) + ba.containerwidget(edit=self.root_widget, cancel_button=btn) + ba.containerwidget(edit=self.root_widget, + selected_child=(cbtn if cbtn is not None + and cancel_is_selected else None), + start_button=None) + + self._translation_btn = ba.buttonwidget(parent=self._subcontainer, + scale=1.2, + position=(100, 1200), + size=(150, 50), + label='Translate Settings', + on_activate_call=self._translaton_btn, + autoselect=True) + + def ip_button(self, value: bool): + cfg = ba.app.config + cfg['IP button'] = value + cfg.apply_and_commit() + if cfg['IP button']: + ba.screenmessage("IP Button is now enabled", color=(0, 1, 0)) + else: + ba.screenmessage("IP Button is now disabled", color=(1, 0.7, 0)) + + def ping_button(self, value: bool): + cfg = ba.app.config + cfg['ping button'] = value + cfg.apply_and_commit() + if cfg['ping button']: + ba.screenmessage("Ping Button is now enabled", color=(0, 1, 0)) + else: + ba.screenmessage("Ping Button is now disabled", color=(1, 0.7, 0)) + + def copy_button(self, value: bool): + cfg = ba.app.config + cfg['copy button'] = value + cfg.apply_and_commit() + if cfg['copy button']: + ba.screenmessage("Copy Text Button is now enabled", color=(0, 1, 0)) + else: + ba.screenmessage("Copy Text Button is now disabled", color=(1, 0.7, 0)) + + def direct_send(self, value: bool): + cfg = ba.app.config + cfg['Direct Send'] = value + cfg.apply_and_commit() + + def colorful_chat(self, value: bool): + cfg = ba.app.config + cfg['Colorful Chat'] = value + cfg.apply_and_commit() + + def _change_notification(self, choice): + cfg = ba.app.config + cfg['Message Notification'] = choice + cfg.apply_and_commit() + + def _change_status(self, choice): + cfg = ba.app.config + cfg['Self Status'] = choice + cfg.apply_and_commit() + + def _translaton_btn(self): + try: + ba.containerwidget(edit=self.root_widget, transition='out_scale') + TranslationSettings() + except Exception as e: + print(e) + pass + + def _cancel(self) -> None: + ba.containerwidget(edit=self.root_widget, transition='out_scale') + + +class PartyWindow(ba.Window): + """Party list/chat window.""" + + def __del__(self) -> None: + _ba.set_party_window_open(False) + + def __init__(self, origin: Sequence[float] = (0, 0)): + self._private_chat = False + self._firstcall = True + self.ping_server() + _ba.set_party_window_open(True) + self._r = 'partyWindow' + self._popup_type: Optional[str] = None + self._popup_party_member_client_id: Optional[int] = None + self._popup_party_member_is_host: Optional[bool] = None + self._width = 500 + uiscale = ba.app.ui.uiscale + self._height = (365 if uiscale is ba.UIScale.SMALL else + 480 if uiscale is ba.UIScale.MEDIUM else 600) + self.bg_color = ba.app.config.get('PartyWindow Main Color', (0.5, 0.5, 0.5)) + self.ping_timer = ba.Timer(5, ba.WeakCall(self.ping_server), repeat=True) + + ba.Window.__init__(self, root_widget=ba.containerwidget( + size=(self._width, self._height), + transition='in_scale', + color=self.bg_color, + parent=_ba.get_special_widget('overlay_stack'), + on_outside_click_call=self.close_with_sound, + scale_origin_stack_offset=origin, + scale=(2.0 if uiscale is ba.UIScale.SMALL else + 1.35 if uiscale is ba.UIScale.MEDIUM else 1.0), + stack_offset=(0, -10) if uiscale is ba.UIScale.SMALL else ( + 240, 0) if uiscale is ba.UIScale.MEDIUM else (330, 20))) + + self._cancel_button = ba.buttonwidget(parent=self._root_widget, + scale=0.7, + position=(30, self._height - 47), + size=(50, 50), + label='', + on_activate_call=self.close, + autoselect=True, + color=self.bg_color, + icon=ba.gettexture('crossOut'), + iconscale=1.2) + ba.containerwidget(edit=self._root_widget, + cancel_button=self._cancel_button) + + self._menu_button = ba.buttonwidget( + parent=self._root_widget, + scale=0.7, + position=(self._width - 80, self._height - 47), + size=(50, 50), + label='...', + autoselect=True, + button_type='square', + on_activate_call=ba.WeakCall(self._on_menu_button_press), + color=self.bg_color, + iconscale=1.2) + + info = _ba.get_connection_to_host_info() + if info.get('name', '') != '': + self.title = ba.Lstr(value=info['name']) + else: + self.title = ba.Lstr(resource=self._r + '.titleText') + + self._title_text = ba.textwidget(parent=self._root_widget, + scale=0.9, + color=(0.5, 0.7, 0.5), + text=self.title, + size=(0, 0), + position=(self._width * 0.47, + self._height - 29), + maxwidth=self._width * 0.6, + h_align='center', + v_align='center') + self._empty_str = ba.textwidget(parent=self._root_widget, + scale=0.75, + size=(0, 0), + position=(self._width * 0.5, + self._height - 65), + maxwidth=self._width * 0.85, + h_align='center', + v_align='center') + + self._scroll_width = self._width - 50 + self._scrollwidget = ba.scrollwidget(parent=self._root_widget, + size=(self._scroll_width, + self._height - 200), + position=(30, 80), + color=self.bg_color) + self._columnwidget = ba.columnwidget(parent=self._scrollwidget, + border=2, + margin=0) + ba.widget(edit=self._menu_button, down_widget=self._columnwidget) + + self._muted_text = ba.textwidget( + parent=self._root_widget, + position=(self._width * 0.5, self._height * 0.5), + size=(0, 0), + h_align='center', + v_align='center', + text=ba.Lstr(resource='chatMutedText')) + + self._text_field = txt = ba.textwidget( + parent=self._root_widget, + editable=True, + size=(500, 40), + position=(54, 39), + text='', + maxwidth=494, + shadow=0.3, + flatness=1.0, + description=ba.Lstr(resource=self._r + '.chatMessageText'), + autoselect=True, + v_align='center', + corner_scale=0.7) + + ba.widget(edit=self._scrollwidget, + autoselect=True, + left_widget=self._cancel_button, + up_widget=self._cancel_button, + down_widget=self._text_field) + ba.widget(edit=self._columnwidget, + autoselect=True, + up_widget=self._cancel_button, + down_widget=self._text_field) + ba.containerwidget(edit=self._root_widget, selected_child=txt) + self._send_button = btn = ba.buttonwidget(parent=self._root_widget, + size=(50, 35), + label=ba.Lstr(resource=self._r + '.sendText'), + button_type='square', + autoselect=True, + color=self.bg_color, + position=(self._width - 90, 35), + on_activate_call=self._send_chat_message) + ba.textwidget(edit=txt, on_return_press_call=btn.activate) + self._previous_button = ba.buttonwidget(parent=self._root_widget, + size=(30, 30), + label=ba.charstr(ba.SpecialChar.UP_ARROW), + button_type='square', + autoselect=True, + position=(15, 57), + color=self.bg_color, + scale=0.75, + on_activate_call=self._previous_message) + self._next_button = ba.buttonwidget(parent=self._root_widget, + size=(30, 30), + label=ba.charstr(ba.SpecialChar.DOWN_ARROW), + button_type='square', + autoselect=True, + color=self.bg_color, + scale=0.75, + position=(15, 28), + on_activate_call=self._next_message) + self._translate_button = ba.buttonwidget(parent=self._root_widget, + size=(55, 47), + label="Trans", + button_type='square', + autoselect=True, + color=self.bg_color, + scale=0.75, + position=(self._width - 28, 35), + on_activate_call=self._translate) + if ba.app.config['copy button']: + self._copy_button = ba.buttonwidget(parent=self._root_widget, + size=(15, 15), + label='©', + button_type='backSmall', + autoselect=True, + color=self.bg_color, + position=(self._width - 40, 80), + on_activate_call=self._copy_to_clipboard) + self._ping_button = None + if info.get('name', '') != '': + if ba.app.config['ping button']: + self._ping_button = ba.buttonwidget( + parent=self._root_widget, + scale=0.7, + position=(self._width - 538, self._height - 57), + size=(75, 75), + autoselect=True, + button_type='square', + label=f'{_ping}', + on_activate_call=self._send_ping, + color=self.bg_color, + text_scale=2.3, + iconscale=1.2) + if ba.app.config['IP button']: + self._ip_port_button = ba.buttonwidget(parent=self._root_widget, + size=(30, 30), + label='IP', + button_type='square', + autoselect=True, + color=self.bg_color, + position=(self._width - 530, + self._height - 100), + on_activate_call=self._ip_port_msg) + self._settings_button = ba.buttonwidget(parent=self._root_widget, + size=(50, 50), + scale=0.5, + button_type='square', + autoselect=True, + color=self.bg_color, + position=(self._width - 40, self._height - 47), + on_activate_call=self._on_setting_button_press, + icon=ba.gettexture('settingsIcon'), + iconscale=1.2) + self._privatechat_button = ba.buttonwidget(parent=self._root_widget, + size=(50, 50), + scale=0.5, + button_type='square', + autoselect=True, + color=self.bg_color, + position=(self._width - 40, self._height - 80), + on_activate_call=self._on_privatechat_button_press, + icon=ba.gettexture('ouyaOButton'), + iconscale=1.2) + self._name_widgets: List[ba.Widget] = [] + self._roster: Optional[List[Dict[str, Any]]] = None + self._update_timer = ba.Timer(1.0, + ba.WeakCall(self._update), + repeat=True, + timetype=ba.TimeType.REAL) + self._update() + + def on_chat_message(self, msg: str, sent=None) -> None: + """Called when a new chat message comes through.""" + if ba.app.config['Party Chat Muted'] and not _ba.app.ui.party_window()._private_chat: + return + if sent: + self._add_msg(msg, sent) + else: + self._add_msg(msg) + + def _add_msg(self, msg: str, sent=None) -> None: + if ba.app.config['Colorful Chat']: + sender = msg.split(': ')[0] + color = color_tracker._get_sender_color(sender) if sender else (1, 1, 1) + else: + color = (1, 1, 1) + maxwidth = self._scroll_width * 0.94 + txt = ba.textwidget(parent=self._columnwidget, + text=msg, + h_align='left', + v_align='center', + size=(0, 13), + scale=0.55, + color=color, + maxwidth=maxwidth, + shadow=0.3, + flatness=1.0) + if sent: + ba.textwidget(edit=txt, size=(100, 15), + selectable=True, + click_activate=True, + on_activate_call=ba.Call(ba.screenmessage, f'Message sent: {_get_local_time(sent)}')) + self._chat_texts.append(txt) + if len(self._chat_texts) > 40: + first = self._chat_texts.pop(0) + first.delete() + ba.containerwidget(edit=self._columnwidget, visible_child=txt) + + def _on_menu_button_press(self) -> None: + is_muted = ba.app.config['Party Chat Muted'] + uiscale = ba.app.ui.uiscale + + choices = ['muteOption', 'modifyColor', 'addQuickReply', 'removeQuickReply', 'credits'] + choices_display = ['Mute Option', 'Modify Main Color', + 'Add as Quick Reply', 'Remove a Quick Reply', 'Credits'] + + if hasattr(_ba.get_foreground_host_activity(), '_map'): + choices.append('manualCamera') + choices_display.append('Manual Camera') + + PopupMenuWindow( + position=self._menu_button.get_screen_space_center(), + color=self.bg_color, + scale=(2.3 if uiscale is ba.UIScale.SMALL else + 1.65 if uiscale is ba.UIScale.MEDIUM else 1.23), + choices=choices, + choices_display=self._create_baLstr_list(choices_display), + current_choice='muteOption', + delegate=self) + self._popup_type = 'menu' + + def _update(self) -> None: + if not self._private_chat: + _ba.set_party_window_open(True) + ba.textwidget(edit=self._title_text, text=self.title) + if self._firstcall: + if hasattr(self, '_status_text'): + self._status_text.delete() + self._roster = [] + self._firstcall = False + self._chat_texts: List[ba.Widget] = [] + if not ba.app.config['Party Chat Muted']: + msgs = _ba.get_chat_messages() + for msg in msgs: + self._add_msg(msg) + # update muted state + if ba.app.config['Party Chat Muted']: + ba.textwidget(edit=self._muted_text, color=(1, 1, 1, 0.3)) + # clear any chat texts we're showing + if self._chat_texts: + while self._chat_texts: + first = self._chat_texts.pop() + first.delete() + else: + ba.textwidget(edit=self._muted_text, color=(1, 1, 1, 0.0)) + if self._ping_button: + ba.buttonwidget(edit=self._ping_button, + label=f'{_ping}', + textcolor=self._get_ping_color()) + + # update roster section + roster = _ba.get_game_roster() + if roster != self._roster or self._firstcall: + + self._roster = roster + + # clear out old + for widget in self._name_widgets: + widget.delete() + self._name_widgets = [] + if not self._roster: + top_section_height = 60 + ba.textwidget(edit=self._empty_str, + text=ba.Lstr(resource=self._r + '.emptyText')) + ba.scrollwidget(edit=self._scrollwidget, + size=(self._width - 50, + self._height - top_section_height - 110), + position=(30, 80)) + else: + columns = 1 if len( + self._roster) == 1 else 2 if len(self._roster) == 2 else 3 + rows = int(math.ceil(float(len(self._roster)) / columns)) + c_width = (self._width * 0.9) / max(3, columns) + c_width_total = c_width * columns + c_height = 24 + c_height_total = c_height * rows + for y in range(rows): + for x in range(columns): + index = y * columns + x + if index < len(self._roster): + t_scale = 0.65 + pos = (self._width * 0.53 - c_width_total * 0.5 + + c_width * x - 23, + self._height - 65 - c_height * y - 15) + + # if there are players present for this client, use + # their names as a display string instead of the + # client spec-string + try: + if self._roster[index]['players']: + # if there's just one, use the full name; + # otherwise combine short names + if len(self._roster[index] + ['players']) == 1: + p_str = self._roster[index]['players'][ + 0]['name_full'] + else: + p_str = ('/'.join([ + entry['name'] for entry in + self._roster[index]['players'] + ])) + if len(p_str) > 25: + p_str = p_str[:25] + '...' + else: + p_str = self._roster[index][ + 'display_string'] + except Exception: + ba.print_exception( + 'Error calcing client name str.') + p_str = '???' + widget = ba.textwidget(parent=self._root_widget, + position=(pos[0], pos[1]), + scale=t_scale, + size=(c_width * 0.85, 30), + maxwidth=c_width * 0.85, + color=(1, 1, + 1) if index == 0 else + (1, 1, 1), + selectable=True, + autoselect=True, + click_activate=True, + text=ba.Lstr(value=p_str), + h_align='left', + v_align='center') + self._name_widgets.append(widget) + + # in newer versions client_id will be present and + # we can use that to determine who the host is. + # in older versions we assume the first client is + # host + if self._roster[index]['client_id'] is not None: + is_host = self._roster[index][ + 'client_id'] == -1 + else: + is_host = (index == 0) + + # FIXME: Should pass client_id to these sort of + # calls; not spec-string (perhaps should wait till + # client_id is more readily available though). + ba.textwidget(edit=widget, + on_activate_call=ba.Call( + self._on_party_member_press, + self._roster[index]['client_id'], + is_host, widget)) + pos = (self._width * 0.53 - c_width_total * 0.5 + + c_width * x, + self._height - 65 - c_height * y) + + # Make the assumption that the first roster + # entry is the server. + # FIXME: Shouldn't do this. + if is_host: + twd = min( + c_width * 0.85, + _ba.get_string_width( + p_str, suppress_warning=True) * + t_scale) + self._name_widgets.append( + ba.textwidget( + parent=self._root_widget, + position=(pos[0] + twd + 1, + pos[1] - 0.5), + size=(0, 0), + h_align='left', + v_align='center', + maxwidth=c_width * 0.96 - twd, + color=(0.1, 1, 0.1, 0.5), + text=ba.Lstr(resource=self._r + + '.hostText'), + scale=0.4, + shadow=0.1, + flatness=1.0)) + ba.textwidget(edit=self._empty_str, text='') + ba.scrollwidget(edit=self._scrollwidget, + size=(self._width - 50, + max(100, self._height - 139 - + c_height_total)), + position=(30, 80)) + else: + _ba.set_party_window_open(False) + for widget in self._name_widgets: + widget.delete() + self._name_widgets = [] + ba.textwidget(edit=self._title_text, text='Private Chat') + ba.textwidget(edit=self._empty_str, text='') + if self._firstcall: + self._firstcall = False + if hasattr(self, '_status_text'): + self._status_text.delete() + try: + msgs = messenger.pvt_msgs[messenger.filter] + except: + msgs = [] + if self._chat_texts: + while self._chat_texts: + first = self._chat_texts.pop() + first.delete() + uiscale = ba.app.ui.uiscale + scroll_height = (165 if uiscale is ba.UIScale.SMALL else + 280 if uiscale is ba.UIScale.MEDIUM else 400) + ba.scrollwidget(edit=self._scrollwidget, + size=(self._width - 50, scroll_height)) + for msg in msgs: + message = messenger._format_message(msg) + self._add_msg(message, msg['sent']) + self._filter_text = ba.textwidget(parent=self._root_widget, + scale=0.6, + color=(0.9, 1.0, 0.9), + text='Filter: ', + size=(0, 0), + position=(self._width * 0.3, + self._height - 70), + h_align='center', + v_align='center') + choices = [i for i in messenger.saved_ids] + choices_display = [ba.Lstr(value=messenger.saved_ids[i]) + for i in messenger.saved_ids] + choices.append('add') + choices_display.append(ba.Lstr(value='***Add New***')) + filter_widget = PopupMenu( + parent=self._root_widget, + position=(self._width * 0.4, + self._height - 80), + width=200, + scale=(2.8 if uiscale is ba.UIScale.SMALL else + 1.8 if uiscale is ba.UIScale.MEDIUM else 1.2), + choices=choices, + choices_display=choices_display, + current_choice=messenger.filter, + button_size=(120, 30), + on_value_change_call=self._change_filter) + self._popup_button = filter_widget.get_button() + if messenger.filter != 'all': + user_status = messenger._get_status(messenger.filter) + if user_status == 'Offline': + color = (1, 0, 0) + elif user_status.startswith(('Playing in', 'in Lobby')): + color = (0, 1, 0) + else: + color = (0.9, 1.0, 0.9) + self._status_text = ba.textwidget(parent=self._root_widget, + scale=0.5, + color=color, + text=f'Status:\t{user_status}', + size=(200, 30), + position=(self._width * 0.3, + self._height - 110), + h_align='center', + v_align='center', + autoselect=True, + selectable=True, + click_activate=True) + ba.textwidget(edit=self._status_text, + on_activate_call=ba.Call(messenger._get_status, messenger.filter, 'last_seen')) + + def _change_filter(self, choice): + if choice == 'add': + self.close() + AddNewIdWindow() + else: + messenger.filter = choice + self._firstcall = True + self._filter_text.delete() + self._popup_button.delete() + if self._chat_texts: + while self._chat_texts: + first = self._chat_texts.pop() + first.delete() + self._update() + + def popup_menu_selected_choice(self, popup_window: PopupMenuWindow, + choice: str) -> None: + """Called when a choice is selected in the popup.""" + if self._popup_type == 'partyMemberPress': + playerinfo = self._get_player_info(self._popup_party_member_client_id) + if choice == 'kick': + name = playerinfo['ds'] + ConfirmWindow(text=f'Are you sure to kick {name}?', + action=self._vote_kick_player, + cancel_button=True, + cancel_is_selected=True, + color=self.bg_color, + text_scale=1.0, + origin_widget=self.get_root_widget()) + elif choice == 'mention': + players = playerinfo['players'] + choices = [] + namelist = [playerinfo['ds']] + for player in players: + name = player['name_full'] + if name not in namelist: + namelist.append(name) + choices_display = self._create_baLstr_list(namelist) + for i in namelist: + i = i.replace('"', '\"') + i = i.replace("'", "\'") + choices.append(f'self._edit_text_msg_box("{i}")') + PopupMenuWindow(position=popup_window.root_widget.get_screen_space_center(), + color=self.bg_color, + scale=self._get_popup_window_scale(), + choices=choices, + choices_display=choices_display, + current_choice=choices[0], + delegate=self) + self._popup_type = "executeChoice" + elif choice == 'adminkick': + name = playerinfo['ds'] + ConfirmWindow(text=f'Are you sure to use admin\ncommand to kick {name}', + action=self._send_admin_kick_command, + cancel_button=True, + cancel_is_selected=True, + color=self.bg_color, + text_scale=1.0, + origin_widget=self.get_root_widget()) + elif choice == 'customCommands': + choices = [] + choices_display = [] + playerinfo = self._get_player_info(self._popup_party_member_client_id) + account = playerinfo['ds'] + try: + name = playerinfo['players'][0]['name_full'] + except: + name = account + for i in ba.app.config.get('Custom Commands'): + i = i.replace('$c', str(self._popup_party_member_client_id)) + i = i.replace('$a', str(account)) + i = i.replace('$n', str(name)) + if ba.app.config['Direct Send']: + choices.append(f'_ba.chatmessage("{i}")') + else: + choices.append(f'self._edit_text_msg_box("{i}")') + choices_display.append(ba.Lstr(value=i)) + choices.append('AddNewChoiceWindow()') + choices_display.append(ba.Lstr(value='***Add New***')) + PopupMenuWindow(position=popup_window.root_widget.get_screen_space_center(), + color=self.bg_color, + scale=self._get_popup_window_scale(), + choices=choices, + choices_display=choices_display, + current_choice=choices[0], + delegate=self) + self._popup_type = 'executeChoice' + + elif choice == 'addNew': + AddNewChoiceWindow() + + elif self._popup_type == 'menu': + if choice == 'muteOption': + current_choice = self._get_current_mute_type() + PopupMenuWindow( + position=(self._width - 60, self._height - 47), + color=self.bg_color, + scale=self._get_popup_window_scale(), + choices=['muteInGameOnly', 'mutePartyWindowOnly', 'muteAll', 'unmuteAll'], + choices_display=self._create_baLstr_list( + ['Mute In Game Messages Only', 'Mute Party Window Messages Only', 'Mute all', 'Unmute All']), + current_choice=current_choice, + delegate=self + ) + self._popup_type = 'muteType' + elif choice == 'modifyColor': + ColorPickerExact(parent=self.get_root_widget(), + position=self.get_root_widget().get_screen_space_center(), + initial_color=self.bg_color, + delegate=self, tag='') + elif choice == 'addQuickReply': + try: + newReply = ba.textwidget(query=self._text_field) + oldReplies = self._get_quick_responds() + oldReplies.append(newReply) + self._write_quick_responds(oldReplies) + ba.screenmessage(f'"{newReply}" is added.', (0, 1, 0)) + ba.playsound(ba.getsound('dingSmallHigh')) + except: + ba.print_exception() + elif choice == 'removeQuickReply': + quick_reply = self._get_quick_responds() + PopupMenuWindow(position=self._send_button.get_screen_space_center(), + color=self.bg_color, + scale=self._get_popup_window_scale(), + choices=quick_reply, + choices_display=self._create_baLstr_list(quick_reply), + current_choice=quick_reply[0], + delegate=self) + self._popup_type = 'removeQuickReplySelect' + elif choice == 'credits': + ConfirmWindow( + text=u'\ue043Party Window Reloaded V3\ue043\n\nCredits - Droopy#3730\nSpecial Thanks - BoTT-Vishah#4150', + action=self.join_discord, + width=420, + height=230, + color=self.bg_color, + text_scale=1.0, + ok_text="Join Discord", + origin_widget=self.get_root_widget()) + elif choice == 'manualCamera': + ba.containerwidget(edit=self._root_widget, transition='out_scale') + Manual_camera_window() + + elif self._popup_type == 'muteType': + self._change_mute_type(choice) + + elif self._popup_type == 'executeChoice': + exec(choice) + + elif self._popup_type == 'quickMessage': + if choice == '*** EDIT ORDER ***': + SortQuickMessages() + else: + self._edit_text_msg_box(choice) + + elif self._popup_type == 'removeQuickReplySelect': + data = self._get_quick_responds() + data.remove(choice) + self._write_quick_responds(data) + ba.screenmessage(f'"{choice}" is removed.', (1, 0, 0)) + ba.playsound(ba.getsound('shieldDown')) + + else: + print(f'unhandled popup type: {self._popup_type}') + del popup_window # unused + + def _vote_kick_player(self): + if self._popup_party_member_is_host: + ba.playsound(ba.getsound('error')) + ba.screenmessage( + ba.Lstr(resource='internal.cantKickHostError'), + color=(1, 0, 0)) + else: + assert self._popup_party_member_client_id is not None + + # Ban for 5 minutes. + result = _ba.disconnect_client( + self._popup_party_member_client_id, ban_time=5 * 60) + if not result: + ba.playsound(ba.getsound('error')) + ba.screenmessage( + ba.Lstr(resource='getTicketsWindow.unavailableText'), + color=(1, 0, 0)) + + def _send_admin_kick_command(self): + _ba.chatmessage('/kick ' + str(self._popup_party_member_client_id)) + + def _translate(self): + def _apply_translation(translated): + if self._text_field.exists(): + ba.textwidget(edit=self._text_field, text=translated) + msg = ba.textwidget(query=self._text_field) + cfg = ba.app.config + if msg == '': + ba.screenmessage('Nothing to translate.', (1, 0, 0)) + ba.playsound(ba.getsound('error')) + else: + data = dict(message=msg) + if cfg['Translate Source Language']: + data['src'] = cfg['Translate Source Language'] + if cfg['Translate Destination Language']: + data['dest'] = cfg['Translate Destination Language'] + if cfg['Pronunciation']: + data['type'] = 'pronunciation' + Translate(data, _apply_translation).start() + + def _copy_to_clipboard(self): + msg = ba.textwidget(query=self._text_field) + if msg == '': + ba.screenmessage('Nothing to copy.', (1, 0, 0)) + ba.playsound(ba.getsound('error')) + else: + ba.clipboard_set_text(msg) + ba.screenmessage(f'"{msg}" is copied to clipboard.', (0, 1, 0)) + ba.playsound(ba.getsound('dingSmallHigh')) + + def _get_current_mute_type(self): + cfg = ba.app.config + if cfg['Chat Muted'] == True: + if cfg['Party Chat Muted'] == True: + return 'muteAll' + else: + return 'muteInGameOnly' + else: + if cfg['Party Chat Muted'] == True: + return 'mutePartyWindowOnly' + else: + return 'unmuteAll' + + def _change_mute_type(self, choice): + cfg = ba.app.config + if choice == 'muteInGameOnly': + cfg['Chat Muted'] = True + cfg['Party Chat Muted'] = False + elif choice == 'mutePartyWindowOnly': + cfg['Chat Muted'] = False + cfg['Party Chat Muted'] = True + elif choice == 'muteAll': + cfg['Chat Muted'] = True + cfg['Party Chat Muted'] = True + else: + cfg['Chat Muted'] = False + cfg['Party Chat Muted'] = False + cfg.apply_and_commit() + self._update() + + def popup_menu_closing(self, popup_window: PopupWindow) -> None: + """Called when the popup is closing.""" + + def _on_party_member_press(self, client_id: int, is_host: bool, + widget: ba.Widget) -> None: + # if we're the host, pop up 'kick' options for all non-host members + if _ba.get_foreground_host_session() is not None: + kick_str = ba.Lstr(resource='kickText') + else: + # kick-votes appeared in build 14248 + if (_ba.get_connection_to_host_info().get('build_number', 0) < + 14248): + return + kick_str = ba.Lstr(resource='kickVoteText') + uiscale = ba.app.ui.uiscale + choices = ['kick', 'mention', 'adminkick'] + choices_display = [kick_str] + \ + list(self._create_baLstr_list(['Mention this guy', f'Kick ID: {client_id}'])) + choices.append('customCommands') + choices_display.append(ba.Lstr(value='Custom Commands')) + PopupMenuWindow( + position=widget.get_screen_space_center(), + color=self.bg_color, + scale=(2.3 if uiscale is ba.UIScale.SMALL else + 1.65 if uiscale is ba.UIScale.MEDIUM else 1.23), + choices=choices, + choices_display=choices_display, + current_choice='mention', + delegate=self) + self._popup_type = 'partyMemberPress' + self._popup_party_member_client_id = client_id + self._popup_party_member_is_host = is_host + + def _send_chat_message(self) -> None: + msg = ba.textwidget(query=self._text_field) + ba.textwidget(edit=self._text_field, text='') + if '\\' in msg: + msg = msg.replace('\\d', ('\ue048')) + msg = msg.replace('\\c', ('\ue043')) + msg = msg.replace('\\h', ('\ue049')) + msg = msg.replace('\\s', ('\ue046')) + msg = msg.replace('\\n', ('\ue04b')) + msg = msg.replace('\\f', ('\ue04f')) + msg = msg.replace('\\g', ('\ue027')) + msg = msg.replace('\\i', ('\ue03a')) + msg = msg.replace('\\m', ('\ue04d')) + msg = msg.replace('\\t', ('\ue01f')) + msg = msg.replace('\\bs', ('\ue01e')) + msg = msg.replace('\\j', ('\ue010')) + msg = msg.replace('\\e', ('\ue045')) + msg = msg.replace('\\l', ('\ue047')) + msg = msg.replace('\\a', ('\ue020')) + msg = msg.replace('\\b', ('\ue00c')) + if not msg: + choices = self._get_quick_responds() + choices.append('*** EDIT ORDER ***') + PopupMenuWindow(position=self._send_button.get_screen_space_center(), + scale=self._get_popup_window_scale(), + color=self.bg_color, + choices=choices, + current_choice=choices[0], + delegate=self) + self._popup_type = 'quickMessage' + return + elif msg.startswith('/info '): + account = msg.replace('/info ', '') + if account: + from bastd.ui.account import viewer + viewer.AccountViewerWindow( + account_id=account) + ba.textwidget(edit=self._text_field, text='') + return + if not self._private_chat: + if msg == '/id': + myid = ba.internal.get_v1_account_misc_read_val_2('resolvedAccountID', '') + _ba.chatmessage(f"My Unique ID : {myid}") + elif msg == '/save': + info = _ba.get_connection_to_host_info() + config = ba.app.config + if info.get('name', '') != '': + title = info['name'] + if not isinstance(config.get('Saved Servers'), dict): + config['Saved Servers'] = {} + config['Saved Servers'][f'{_ip}@{_port}'] = { + 'addr': _ip, + 'port': _port, + 'name': title + } + config.commit() + ba.screenmessage("Server Added To Manual", color=(0, 1, 0), transient=True) + ba.playsound(ba.getsound('gunCocking')) + elif msg != '': + _ba.chatmessage(cast(str, msg)) + else: + receiver = messenger.filter + name = ba.internal.get_v1_account_display_string() + if not receiver: + display_error('Choose a valid receiver id') + return + data = {'receiver': receiver, 'message': f'{name}: {msg}'} + if msg.startswith('/rename '): + if messenger.filter != 'all': + nickname = msg.replace('/rename ', '') + messenger._save_id(messenger.filter, nickname, verify=False) + self._change_filter(messenger.filter) + elif msg == '/remove': + if messenger.filter != 'all': + messenger._remove_id(messenger.filter) + self._change_filter('all') + else: + display_error('Cant delete this') + ba.textwidget(edit=self._text_field, text='') + return + ba.Call(messenger._send_request, url, data) + ba.Call(check_new_message) + Thread(target=messenger._send_request, args=(url, data)).start() + Thread(target=check_new_message).start() + ba.textwidget(edit=self._text_field, text='') + + def _write_quick_responds(self, data): + try: + with open(quick_msg_file, 'w') as f: + f.write('\n'.join(data)) + except: + ba.print_exception() + ba.screenmessage('Error!', (1, 0, 0)) + ba.playsound(ba.getsound('error')) + + def _get_quick_responds(self): + if os.path.exists(quick_msg_file): + with open(quick_msg_file, 'r') as f: + return f.read().split('\n') + else: + default_replies = ['What the hell?', 'Dude that\'s amazing!'] + self._write_quick_responds(default_replies) + return default_replies + + def color_picker_selected_color(self, picker, color) -> None: + ba.containerwidget(edit=self._root_widget, color=color) + color = tuple(round(i, 2) for i in color) + self.bg_color = color + ba.app.config['PartyWindow Main Color'] = color + + def color_picker_closing(self, picker) -> None: + ba.app.config.apply_and_commit() + + def _remove_sender_from_message(self, msg=''): + msg_start = msg.find(": ") + 2 + return msg[msg_start:] + + def _previous_message(self): + msgs = self._chat_texts + if not hasattr(self, 'msg_index'): + self.msg_index = len(msgs) - 1 + else: + if self.msg_index > 0: + self.msg_index -= 1 + else: + del self.msg_index + try: + msg_widget = msgs[self.msg_index] + msg = ba.textwidget(query=msg_widget) + msg = self._remove_sender_from_message(msg) + if msg in ('', ' '): + self._previous_message() + return + except: + msg = '' + self._edit_text_msg_box(msg, 'replace') + + def _next_message(self): + msgs = self._chat_texts + if not hasattr(self, 'msg_index'): + self.msg_index = 0 + else: + if self.msg_index < len(msgs) - 1: + self.msg_index += 1 + else: + del self.msg_index + try: + msg_widget = msgs[self.msg_index] + msg = ba.textwidget(query=msg_widget) + msg = self._remove_sender_from_message(msg) + if msg in ('', ' '): + self._next_message() + return + except: + msg = '' + self._edit_text_msg_box(msg, 'replace') + + def _ip_port_msg(self): + try: + msg = f'IP : {_ip} PORT : {_port}' + except: + msg = '' + self._edit_text_msg_box(msg, 'replace') + + def ping_server(self): + info = _ba.get_connection_to_host_info() + if info.get('name', '') != '': + self.pingThread = PingThread(_ip, _port) + self.pingThread.start() + + def _get_ping_color(self): + try: + if _ping < 100: + return (0, 1, 0) + elif _ping < 500: + return (1, 1, 0) + else: + return (1, 0, 0) + except: + return (0.1, 0.1, 0.1) + + def _send_ping(self): + if isinstance(_ping, int): + _ba.chatmessage(f'My ping = {_ping}ms') + + def close(self) -> None: + """Close the window.""" + ba.containerwidget(edit=self._root_widget, transition='out_scale') + + def close_with_sound(self) -> None: + """Close the window and make a lovely sound.""" + ba.playsound(ba.getsound('swish')) + self.close() + + def _get_popup_window_scale(self) -> float: + uiscale = ba.app.ui.uiscale + return (2.4 if uiscale is ba.UIScale.SMALL else + 1.5 if uiscale is ba.UIScale.MEDIUM else 1.0) + + def _create_baLstr_list(self, list1): + return (ba.Lstr(value=i) for i in list1) + + def _get_player_info(self, clientID): + info = {} + for i in _ba.get_game_roster(): + if i['client_id'] == clientID: + info['ds'] = i['display_string'] + info['players'] = i['players'] + info['aid'] = i['account_id'] + break + return info + + def _edit_text_msg_box(self, text, action='add'): + if isinstance(text, str): + if action == 'add': + ba.textwidget(edit=self._text_field, text=ba.textwidget( + query=self._text_field) + text) + elif action == 'replace': + ba.textwidget(edit=self._text_field, text=text) + + def _on_setting_button_press(self): + try: + SettingsWindow() + except Exception as e: + ba.print_exception() + pass + + def _on_privatechat_button_press(self): + try: + if messenger.logged_in: + self._firstcall = True + if self._chat_texts: + while self._chat_texts: + first = self._chat_texts.pop() + first.delete() + if not self._private_chat: + self._private_chat = True + else: + self._filter_text.delete() + self._popup_button.delete() + self._private_chat = False + self._update() + else: + if messenger.server_online: + if not messenger._cookie_login(): + if messenger._query(): + LoginWindow(wtype='login') + else: + LoginWindow(wtype='signup') + else: + display_error(messenger.error) + except Exception as e: + ba.print_exception() + pass + + def join_discord(self): + ba.open_url("https://discord.gg/KvYgpEg2JR") + + +class LoginWindow: + def __init__(self, wtype): + self.wtype = wtype + if self.wtype == 'signup': + title = 'Sign Up Window' + label = 'Sign Up' + else: + title = 'Login Window' + label = 'Log In' + uiscale = ba.app.ui.uiscale + bg_color = ba.app.config.get('PartyWindow Main Color', (0.5, 0.5, 0.5)) + self._root_widget = ba.containerwidget(size=(500, 250), + transition='in_scale', + color=bg_color, + toolbar_visibility='menu_minimal_no_back', + parent=_ba.get_special_widget('overlay_stack'), + on_outside_click_call=self._close, + scale=(2.1 if uiscale is ba.UIScale.SMALL else + 1.5 if uiscale is ba.UIScale.MEDIUM else 1.0), + stack_offset=(0, -10) if uiscale is ba.UIScale.SMALL else ( + 240, 0) if uiscale is ba.UIScale.MEDIUM else (330, 20)) + self._title_text = ba.textwidget(parent=self._root_widget, + scale=0.8, + color=(1, 1, 1), + text=title, + size=(0, 0), + position=(250, 200), + h_align='center', + v_align='center') + self._id = ba.textwidget(parent=self._root_widget, + scale=0.5, + color=(1, 1, 1), + text=f'Account: ' + + ba.internal.get_v1_account_misc_read_val_2( + 'resolvedAccountID', ''), + size=(0, 0), + position=(220, 170), + h_align='center', + v_align='center') + self._registrationkey_text = ba.textwidget(parent=self._root_widget, + scale=0.5, + color=(1, 1, 1), + text=f'Registration Key:', + size=(0, 0), + position=(100, 140), + h_align='center', + v_align='center') + self._text_field = ba.textwidget( + parent=self._root_widget, + editable=True, + size=(200, 40), + position=(175, 130), + text='', + maxwidth=410, + flatness=1.0, + autoselect=True, + v_align='center', + corner_scale=0.7) + self._connect_button = ba.buttonwidget(parent=self._root_widget, + size=(150, 30), + color=(0, 1, 0), + label='Get Registration Key', + button_type='square', + autoselect=True, + position=(150, 80), + on_activate_call=self._connect) + self._confirm_button = ba.buttonwidget(parent=self._root_widget, + size=(50, 30), + label=label, + button_type='square', + autoselect=True, + position=(200, 40), + on_activate_call=self._confirmcall) + ba.textwidget(edit=self._text_field, on_return_press_call=self._confirm_button.activate) + + def _close(self): + ba.containerwidget(edit=self._root_widget, + transition=('out_scale')) + + def _connect(self): + try: + host = url.split('http://')[1].split(':')[0] + import socket + address = socket.gethostbyname(host) + _ba.disconnect_from_host() + _ba.connect_to_party(address, port=11111) + except Exception: + display_error('Cant get ip from hostname') + + def _confirmcall(self): + if self.wtype == 'signup': + key = ba.textwidget(query=self._text_field) + answer = messenger._signup(registration_key=key) if key else None + if answer: + self._close() + else: + if messenger._login(registration_key=ba.textwidget(query=self._text_field)): + self._close() + + +class AddNewIdWindow: + def __init__(self): + uiscale = ba.app.ui.uiscale + bg_color = ba.app.config.get('PartyWindow Main Color', (0.5, 0.5, 0.5)) + self._root_widget = ba.containerwidget(size=(500, 250), + transition='in_scale', + color=bg_color, + toolbar_visibility='menu_minimal_no_back', + parent=_ba.get_special_widget('overlay_stack'), + on_outside_click_call=self._close, + scale=(2.1 if uiscale is ba.UIScale.SMALL else + 1.5 if uiscale is ba.UIScale.MEDIUM else 1.0)) + self._title_text = ba.textwidget(parent=self._root_widget, + scale=0.8, + color=(1, 1, 1), + text='Add New ID', + size=(0, 0), + position=(250, 200), + h_align='center', + v_align='center') + self._accountid_text = ba.textwidget(parent=self._root_widget, + scale=0.6, + color=(1, 1, 1), + text='pb-id: ', + size=(0, 0), + position=(50, 155), + h_align='center', + v_align='center') + self._accountid_field = ba.textwidget( + parent=self._root_widget, + editable=True, + size=(250, 40), + position=(100, 140), + text='', + maxwidth=410, + flatness=1.0, + autoselect=True, + v_align='center', + corner_scale=0.7) + self._nickname_text = ba.textwidget(parent=self._root_widget, + scale=0.5, + color=(1, 1, 1), + text='Nickname: ', + size=(0, 0), + position=(50, 115), + h_align='center', + v_align='center') + self._nickname_field = ba.textwidget( + parent=self._root_widget, + editable=True, + size=(250, 40), + position=(100, 100), + text='', + maxwidth=410, + flatness=1.0, + autoselect=True, + v_align='center', + corner_scale=0.7) + self._help_text = ba.textwidget(parent=self._root_widget, + scale=0.4, + color=(0.1, 0.9, 0.9), + text='Help:\nEnter pb-id of account you\n want to chat to\nEnter nickname of id to\n recognize id easily\nLeave nickname \n to use their default name', + size=(0, 0), + position=(325, 120), + h_align='left', + v_align='center') + self._add = ba.buttonwidget(parent=self._root_widget, + size=(50, 30), + label='Add', + button_type='square', + autoselect=True, + position=(100, 50), + on_activate_call=ba.Call(self._relay_function)) + ba.textwidget(edit=self._accountid_field, on_return_press_call=self._add.activate) + self._remove = ba.buttonwidget(parent=self._root_widget, + size=(75, 30), + label='Remove', + button_type='square', + autoselect=True, + position=(170, 50), + on_activate_call=self._remove_id) + ba.containerwidget(edit=self._root_widget, + on_cancel_call=self._close) + + def _relay_function(self): + account_id = ba.textwidget(query=self._accountid_field) + nickname = ba.textwidget(query=self._nickname_field) + try: + if messenger._save_id(account_id, nickname): + self._close() + except: + display_error('Enter valid pb-id') + + def _remove_id(self): + uiscale = ba.app.ui.uiscale + if len(messenger.saved_ids) > 1: + choices = [i for i in messenger.saved_ids] + choices.remove('all') + choices_display = [ba.Lstr(value=messenger.saved_ids[i]) for i in choices] + PopupMenuWindow(position=self._remove.get_screen_space_center(), + color=ba.app.config.get('PartyWindow Main Color', (0.5, 0.5, 0.5)), + scale=(2.4 if uiscale is ba.UIScale.SMALL else + 1.5 if uiscale is ba.UIScale.MEDIUM else 1.0), + choices=choices, + choices_display=choices_display, + current_choice=choices[0], + delegate=self) + self._popup_type = 'removeSelectedID' + + def popup_menu_selected_choice(self, popup_window: PopupMenuWindow, + choice: str) -> None: + """Called when a choice is selected in the popup.""" + if self._popup_type == 'removeSelectedID': + messenger._remove_id(choice) + self._close() + + def popup_menu_closing(self, popup_window: PopupWindow) -> None: + """Called when the popup is closing.""" + + def _close(self): + ba.containerwidget(edit=self._root_widget, + transition=('out_scale')) + + +class AddNewChoiceWindow: + def __init__(self): + uiscale = ba.app.ui.uiscale + bg_color = ba.app.config.get('PartyWindow Main Color', (0.5, 0.5, 0.5)) + self._root_widget = ba.containerwidget(size=(500, 250), + transition='in_scale', + color=bg_color, + toolbar_visibility='menu_minimal_no_back', + parent=_ba.get_special_widget('overlay_stack'), + on_outside_click_call=self._close, + scale=(2.1 if uiscale is ba.UIScale.SMALL else + 1.5 if uiscale is ba.UIScale.MEDIUM else 1.0), + stack_offset=(0, -10) if uiscale is ba.UIScale.SMALL else ( + 240, 0) if uiscale is ba.UIScale.MEDIUM else (330, 20)) + self._title_text = ba.textwidget(parent=self._root_widget, + scale=0.8, + color=(1, 1, 1), + text='Add Custom Command', + size=(0, 0), + position=(250, 200), + h_align='center', + v_align='center') + self._text_field = ba.textwidget( + parent=self._root_widget, + editable=True, + size=(500, 40), + position=(75, 140), + text='', + maxwidth=410, + flatness=1.0, + autoselect=True, + v_align='center', + corner_scale=0.7) + self._help_text = ba.textwidget(parent=self._root_widget, + scale=0.4, + color=(0.2, 0.2, 0.2), + text='Use\n$c = client id\n$a = account id\n$n = name', + size=(0, 0), + position=(70, 75), + h_align='left', + v_align='center') + self._add = ba.buttonwidget(parent=self._root_widget, + size=(50, 30), + label='Add', + button_type='square', + autoselect=True, + position=(150, 50), + on_activate_call=self._add_choice) + ba.textwidget(edit=self._text_field, on_return_press_call=self._add.activate) + self._remove = ba.buttonwidget(parent=self._root_widget, + size=(50, 30), + label='Remove', + button_type='square', + autoselect=True, + position=(350, 50), + on_activate_call=self._remove_custom_command) + ba.containerwidget(edit=self._root_widget, + on_cancel_call=self._close) + + def _add_choice(self): + newCommand = ba.textwidget(query=self._text_field) + cfg = ba.app.config + if any(i in newCommand for i in ('$c', '$a', '$n')): + cfg['Custom Commands'].append(newCommand) + cfg.apply_and_commit() + ba.screenmessage('Added successfully', (0, 1, 0)) + ba.playsound(ba.getsound('dingSmallHigh')) + self._close() + else: + ba.screenmessage('Use at least of these ($c, $a, $n)', (1, 0, 0)) + ba.playsound(ba.getsound('error')) + + def _remove_custom_command(self): + uiscale = ba.app.ui.uiscale + commands = ba.app.config['Custom Commands'] + PopupMenuWindow(position=self._remove.get_screen_space_center(), + color=ba.app.config.get('PartyWindow Main Color', (0.5, 0.5, 0.5)), + scale=(2.4 if uiscale is ba.UIScale.SMALL else + 1.5 if uiscale is ba.UIScale.MEDIUM else 1.0), + choices=commands, + current_choice=commands[0], + delegate=self) + self._popup_type = 'removeCustomCommandSelect' + + def popup_menu_selected_choice(self, popup_window: PopupMenuWindow, + choice: str) -> None: + """Called when a choice is selected in the popup.""" + if self._popup_type == 'removeCustomCommandSelect': + config = ba.app.config + config['Custom Commands'].remove(choice) + config.apply_and_commit() + ba.screenmessage('Removed successfully', (0, 1, 0)) + ba.playsound(ba.getsound('shieldDown')) + + def popup_menu_closing(self, popup_window: PopupWindow) -> None: + """Called when the popup is closing.""" + + def _close(self): + ba.containerwidget(edit=self._root_widget, + transition=('out_scale')) + + +class Manual_camera_window: + def __init__(self): + self._root_widget = ba.containerwidget( + on_outside_click_call=None, + size=(0, 0)) + button_size = (30, 30) + self._title_text = ba.textwidget(parent=self._root_widget, + scale=0.9, + color=(1, 1, 1), + text='Manual Camera Setup', + size=(0, 0), + position=(130, 153), + h_align='center', + v_align='center') + self._xminus = ba.buttonwidget(parent=self._root_widget, + size=button_size, + label=ba.charstr(ba.SpecialChar.LEFT_ARROW), + button_type='square', + autoselect=True, + position=(1, 60), + on_activate_call=ba.Call(self._change_camera_position, 'x-')) + self._xplus = ba.buttonwidget(parent=self._root_widget, + size=button_size, + label=ba.charstr(ba.SpecialChar.RIGHT_ARROW), + button_type='square', + autoselect=True, + position=(60, 60), + on_activate_call=ba.Call(self._change_camera_position, 'x')) + self._yplus = ba.buttonwidget(parent=self._root_widget, + size=button_size, + label=ba.charstr(ba.SpecialChar.UP_ARROW), + button_type='square', + autoselect=True, + position=(30, 100), + on_activate_call=ba.Call(self._change_camera_position, 'y')) + self._yminus = ba.buttonwidget(parent=self._root_widget, + size=button_size, + label=ba.charstr(ba.SpecialChar.DOWN_ARROW), + button_type='square', + autoselect=True, + position=(30, 20), + on_activate_call=ba.Call(self._change_camera_position, 'y-')) + self.inwards = ba.buttonwidget(parent=self._root_widget, + size=(100, 30), + label='INWARDS', + button_type='square', + autoselect=True, + position=(120, 90), + on_activate_call=ba.Call(self._change_camera_position, 'z-')) + self._outwards = ba.buttonwidget(parent=self._root_widget, + size=(100, 30), + label='OUTWARDS', + button_type='square', + autoselect=True, + position=(120, 50), + on_activate_call=ba.Call(self._change_camera_position, 'z')) + self._step_text = ba.textwidget(parent=self._root_widget, + scale=0.5, + color=(1, 1, 1), + text='Step:', + size=(0, 0), + position=(1, -20), + h_align='center', + v_align='center') + self._text_field = ba.textwidget( + parent=self._root_widget, + editable=True, + size=(100, 40), + position=(26, -35), + text='', + maxwidth=120, + flatness=1.0, + autoselect=True, + v_align='center', + corner_scale=0.7) + self._reset = ba.buttonwidget(parent=self._root_widget, + size=(50, 30), + label='Reset', + button_type='square', + autoselect=True, + position=(120, -35), + on_activate_call=ba.Call(self._change_camera_position, 'reset')) + self._done = ba.buttonwidget(parent=self._root_widget, + size=(50, 30), + label='Done', + button_type='square', + autoselect=True, + position=(180, -35), + on_activate_call=self._close) + ba.containerwidget(edit=self._root_widget, + cancel_button=self._done) + + def _close(self): + ba.containerwidget(edit=self._root_widget, + transition=('out_scale')) + + def _change_camera_position(self, direction): + activity = _ba.get_foreground_host_activity() + node = activity.globalsnode + aoi = list(node.area_of_interest_bounds) + center = [(aoi[0] + aoi[3]) / 2, + (aoi[1] + aoi[4]) / 2, + (aoi[2] + aoi[5]) / 2] + size = (aoi[3] - aoi[0], + aoi[4] - aoi[1], + aoi[5] - aoi[2]) + + try: + increment = float(ba.textwidget(query=self._text_field)) + except: + # ba.print_exception() + increment = 1 + + if direction == 'x': + center[0] += increment + elif direction == 'x-': + center[0] -= increment + elif direction == 'y': + center[1] += increment + elif direction == 'y-': + center[1] -= increment + elif direction == 'z': + center[2] += increment + elif direction == 'z-': + center[2] -= increment + elif direction == 'reset': + node.area_of_interest_bounds = activity._map.get_def_bound_box( + 'area_of_interest_bounds') + return + + aoi = (center[0] - size[0] / 2, + center[1] - size[1] / 2, + center[2] - size[2] / 2, + center[0] + size[0] / 2, + center[1] + size[1] / 2, + center[2] + size[2] / 2) + node.area_of_interest_bounds = tuple(aoi) + + +def __popup_menu_window_init__(self, + position: Tuple[float, float], + choices: Sequence[str], + current_choice: str, + delegate: Any = None, + width: float = 230.0, + maxwidth: float = None, + scale: float = 1.0, + color: Tuple[float, float, float] = (0.35, 0.55, 0.15), + choices_disabled: Sequence[str] = None, + choices_display: Sequence[ba.Lstr] = None): + # FIXME: Clean up a bit. + # pylint: disable=too-many-branches + # pylint: disable=too-many-locals + # pylint: disable=too-many-statements + if choices_disabled is None: + choices_disabled = [] + if choices_display is None: + choices_display = [] + + # FIXME: For the moment we base our width on these strings so + # we need to flatten them. + choices_display_fin: List[str] = [] + for choice_display in choices_display: + choices_display_fin.append(choice_display.evaluate()) + + if maxwidth is None: + maxwidth = width * 1.5 + + self._transitioning_out = False + self._choices = list(choices) + self._choices_display = list(choices_display_fin) + self._current_choice = current_choice + self._color = color + self._choices_disabled = list(choices_disabled) + self._done_building = False + if not choices: + raise TypeError('Must pass at least one choice') + self._width = width + self._scale = scale + if len(choices) > 8: + self._height = 280 + self._use_scroll = True + else: + self._height = 20 + len(choices) * 33 + self._use_scroll = False + self._delegate = None # don't want this stuff called just yet.. + + # extend width to fit our longest string (or our max-width) + for index, choice in enumerate(choices): + if len(choices_display_fin) == len(choices): + choice_display_name = choices_display_fin[index] + else: + choice_display_name = choice + if self._use_scroll: + self._width = max( + self._width, + min( + maxwidth, + _ba.get_string_width(choice_display_name, + suppress_warning=True)) + 75) + else: + self._width = max( + self._width, + min( + maxwidth, + _ba.get_string_width(choice_display_name, + suppress_warning=True)) + 60) + + # init parent class - this will rescale and reposition things as + # needed and create our root widget + PopupWindow.__init__(self, + position, + size=(self._width, self._height), + bg_color=self._color, + scale=self._scale) + + if self._use_scroll: + self._scrollwidget = ba.scrollwidget(parent=self.root_widget, + position=(20, 20), + highlight=False, + color=(0.35, 0.55, 0.15), + size=(self._width - 40, + self._height - 40)) + self._columnwidget = ba.columnwidget(parent=self._scrollwidget, + border=2, + margin=0) + else: + self._offset_widget = ba.containerwidget(parent=self.root_widget, + position=(30, 15), + size=(self._width - 40, + self._height), + background=False) + self._columnwidget = ba.columnwidget(parent=self._offset_widget, + border=2, + margin=0) + for index, choice in enumerate(choices): + if len(choices_display_fin) == len(choices): + choice_display_name = choices_display_fin[index] + else: + choice_display_name = choice + inactive = (choice in self._choices_disabled) + wdg = ba.textwidget(parent=self._columnwidget, + size=(self._width - 40, 28), + on_select_call=ba.Call(self._select, index), + click_activate=True, + color=(0.5, 0.5, 0.5, 0.5) if inactive else + ((0.5, 1, 0.5, + 1) if choice == self._current_choice else + (0.8, 0.8, 0.8, 1.0)), + padding=0, + maxwidth=maxwidth, + text=choice_display_name, + on_activate_call=self._activate, + v_align='center', + selectable=(not inactive)) + if choice == self._current_choice: + ba.containerwidget(edit=self._columnwidget, + selected_child=wdg, + visible_child=wdg) + + # ok from now on our delegate can be called + self._delegate = weakref.ref(delegate) + self._done_building = True + + +original_connect_to_party = _ba.connect_to_party +original_sign_in = ba.internal.sign_in_v1 + + +def modify_connect_to_party(address: str, port: int = 43210, print_progress: bool = True) -> None: + global _ip, _port + _ip = address + _port = port + original_connect_to_party(_ip, _port, print_progress) + + +temptimer = None + + +def modify_sign_in(account_type: str) -> None: + original_sign_in(account_type) + if messenger.server_online: + messenger.logged_in = False + global temptimer + temptimer = ba.Timer(2, messenger._cookie_login) + + +class PingThread(Thread): + """Thread for sending out game pings.""" + + def __init__(self, address: str, port: int): + super().__init__() + self._address = address + self._port = port + + def run(self) -> None: + sock: Optional[socket.socket] = None + try: + import socket + from ba.internal import get_ip_address_type + socket_type = get_ip_address_type(self._address) + sock = socket.socket(socket_type, socket.SOCK_DGRAM) + sock.connect((self._address, self._port)) + + starttime = time.time() + + # Send a few pings and wait a second for + # a response. + sock.settimeout(1) + for _i in range(3): + sock.send(b'\x0b') + result: Optional[bytes] + try: + # 11: BA_PACKET_SIMPLE_PING + result = sock.recv(10) + except Exception: + result = None + if result == b'\x0c': + # 12: BA_PACKET_SIMPLE_PONG + accessible = True + break + time.sleep(1) + global _ping + _ping = int((time.time() - starttime) * 1000.0) + except Exception: + ba.print_exception('Error on gather ping', once=True) + finally: + try: + if sock is not None: + sock.close() + except Exception: + ba.print_exception('Error on gather ping cleanup', once=True) + + +def _get_store_char_tex(self) -> str: + _ba.set_party_icon_always_visible(True) + return ('storeCharacterXmas' if ba.internal.get_v1_account_misc_read_val( + 'xmas', False) else + 'storeCharacterEaster' if ba.internal.get_v1_account_misc_read_val( + 'easter', False) else 'storeCharacter') + + +# ba_meta export plugin +class InitalRun(ba.Plugin): + def __init__(self): + if _ba.env().get("build_number", 0) >= 20124: + global messenger, listener, displayer, color_tracker + initialize() + messenger = PrivateChatHandler() + listener = Thread(target=messenger_thread) + listener.start() + displayer = ba.Timer(0.4, msg_displayer, True) + color_tracker = ColorTracker() + bastd.ui.party.PartyWindow = PartyWindow + PopupMenuWindow.__init__ = __popup_menu_window_init__ + _ba.connect_to_party = modify_connect_to_party + ba.internal.sign_in_v1 = modify_sign_in + MainMenuWindow._get_store_char_tex = _get_store_char_tex + else: + display_error("This Party Window only runs with BombSquad version higer than 1.6.0.") From 184c2a1951d92fe597f738704334740fe5856d48 Mon Sep 17 00:00:00 2001 From: brostosjoined Date: Sun, 21 Jan 2024 16:36:31 +0300 Subject: [PATCH 0817/1464] Fix --- plugins/minigames.json | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/plugins/minigames.json b/plugins/minigames.json index 93683d18..9c326d92 100644 --- a/plugins/minigames.json +++ b/plugins/minigames.json @@ -233,18 +233,13 @@ } ], "versions": { + "2.0.1": null, "2.0.0": { "api_version": 7, "commit_sha": "8b257b3", "released_on": "22-10-2022", "md5sum": "4f99e4594cac5a9df137faa257f919dc" - }, - "1.0.0": { - "api_version": 8, - "commit_sha": "87b302a", - "released_on": "18-01-2024", - "md5sum": "e83ad2929caf883c24e2e81c93c39d4f" - } + } } }, "alliance_elimination": { From 2567669ae590b96ac00cc8e091cf047e35dda7b7 Mon Sep 17 00:00:00 2001 From: brostosjoined Date: Sun, 21 Jan 2024 13:37:30 +0000 Subject: [PATCH 0818/1464] [ci] apply-version-metadata --- plugins/minigames.json | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/plugins/minigames.json b/plugins/minigames.json index 9c326d92..e95cab1e 100644 --- a/plugins/minigames.json +++ b/plugins/minigames.json @@ -233,13 +233,18 @@ } ], "versions": { - "2.0.1": null, + "2.0.1": { + "api_version": 8, + "commit_sha": "184c2a1", + "released_on": "21-01-2024", + "md5sum": "e83ad2929caf883c24e2e81c93c39d4f" + }, "2.0.0": { "api_version": 7, "commit_sha": "8b257b3", "released_on": "22-10-2022", "md5sum": "4f99e4594cac5a9df137faa257f919dc" - } + } } }, "alliance_elimination": { From 038ef742bf6120e1f826136b0be3fa67705a5fe5 Mon Sep 17 00:00:00 2001 From: brostosjoined Date: Sun, 21 Jan 2024 16:39:43 +0300 Subject: [PATCH 0819/1464] fix --- plugins/minigames.json | 1 + 1 file changed, 1 insertion(+) diff --git a/plugins/minigames.json b/plugins/minigames.json index e95cab1e..2b77bfce 100644 --- a/plugins/minigames.json +++ b/plugins/minigames.json @@ -494,6 +494,7 @@ } ], "versions": { + "1.0.1": null, "1.0.0": { "api_version": 7, "commit_sha": "2aa1e50", From d9d122642339a73d9306870e167d81b9aa4326a1 Mon Sep 17 00:00:00 2001 From: brostosjoined Date: Sun, 21 Jan 2024 13:40:23 +0000 Subject: [PATCH 0820/1464] [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 2b77bfce..ad0b4754 100644 --- a/plugins/minigames.json +++ b/plugins/minigames.json @@ -494,7 +494,12 @@ } ], "versions": { - "1.0.1": null, + "1.0.1": { + "api_version": 8, + "commit_sha": "038ef74", + "released_on": "21-01-2024", + "md5sum": "aa03952868be8e978d7b23891883b52a" + }, "1.0.0": { "api_version": 7, "commit_sha": "2aa1e50", From bfb5d25467329e355183efeac7211a7a91778ae6 Mon Sep 17 00:00:00 2001 From: brostosjoined Date: Mon, 22 Jan 2024 12:06:37 +0300 Subject: [PATCH 0821/1464] ^->8 --- plugins/minigames.json | 126 ++++------------------ plugins/minigames/hot_potato.py | 20 ++-- plugins/minigames/ultimate_last_stand.py | 2 +- plugins/utilities.json | 119 +++----------------- plugins/utilities/auto_stunt.py | 37 ++++--- plugins/utilities/discord_richpresence.py | 20 ++-- 6 files changed, 80 insertions(+), 244 deletions(-) diff --git a/plugins/minigames.json b/plugins/minigames.json index ad0b4754..5f3b9e29 100644 --- a/plugins/minigames.json +++ b/plugins/minigames.json @@ -77,12 +77,7 @@ } ], "versions": { - "1.0.1": { - "api_version": 8, - "commit_sha": "87b302a", - "released_on": "18-01-2024", - "md5sum": "3b55e82dc1c1d4d84760c23098233e30" - }, + "1.0.1": null, "1.0.0": { "api_version": 7, "commit_sha": "2fda676", @@ -102,12 +97,7 @@ } ], "versions": { - "1.0.1": { - "api_version": 8, - "commit_sha": "87b302a", - "released_on": "18-01-2024", - "md5sum": "74d61a487379d163c3f5713f001ec69d" - }, + "1.0.1": null, "1.0.0": { "api_version": 7, "commit_sha": "2fda676", @@ -127,12 +117,7 @@ } ], "versions": { - "1.0.1": { - "api_version": 8, - "commit_sha": "87b302a", - "released_on": "18-01-2024", - "md5sum": "25f9018fdc70173212e436d4e7c41e97" - }, + "1.0.1": null, "1.0.0": { "api_version": 7, "commit_sha": "2fda676", @@ -152,12 +137,7 @@ } ], "versions": { - "1.0.1": { - "api_version": 8, - "commit_sha": "87b302a", - "released_on": "18-01-2024", - "md5sum": "4630220820b08642e9c72f9f24675298" - }, + "1.0.1": null, "1.0.0": { "api_version": 7, "commit_sha": "2fda676", @@ -202,12 +182,7 @@ } ], "versions": { - "1.1.0": { - "api_version": 8, - "commit_sha": "87b302a", - "released_on": "18-01-2024", - "md5sum": "6c90c97151c31d240a760590c56d7dbf" - }, + "1.1.0": null, "1.0.1": { "api_version": 7, "commit_sha": "d511c15", @@ -233,12 +208,7 @@ } ], "versions": { - "2.0.1": { - "api_version": 8, - "commit_sha": "184c2a1", - "released_on": "21-01-2024", - "md5sum": "e83ad2929caf883c24e2e81c93c39d4f" - }, + "2.0.1": null, "2.0.0": { "api_version": 7, "commit_sha": "8b257b3", @@ -364,12 +334,7 @@ } ], "versions": { - "1.0.1": { - "api_version": 8, - "commit_sha": "87b302a", - "released_on": "18-01-2024", - "md5sum": "48f0768fe1715825e61c66f78dde51c4" - }, + "1.0.1": null, "1.0.0": { "api_version": 7, "commit_sha": "0841b9e", @@ -419,12 +384,7 @@ } ], "versions": { - "1.0.1": { - "api_version": 8, - "commit_sha": "87b302a", - "released_on": "18-01-2024", - "md5sum": "3730cdc9f922ac5a8c86e2c7debd09fe" - }, + "1.0.1": null, "1.0.0": { "api_version": 7, "commit_sha": "52094fc", @@ -469,12 +429,7 @@ } ], "versions": { - "1.0.1": { - "api_version": 8, - "commit_sha": "87b302a", - "released_on": "18-01-2024", - "md5sum": "a1d2d75303aaeb0b078a4c836d65ebee" - }, + "1.0.1": null, "1.0.0": { "api_version": 7, "commit_sha": "2aa1e50", @@ -494,12 +449,7 @@ } ], "versions": { - "1.0.1": { - "api_version": 8, - "commit_sha": "038ef74", - "released_on": "21-01-2024", - "md5sum": "aa03952868be8e978d7b23891883b52a" - }, + "1.0.1": null, "1.0.0": { "api_version": 7, "commit_sha": "2aa1e50", @@ -519,12 +469,7 @@ } ], "versions": { - "1.0.1": { - "api_version": 8, - "commit_sha": "87b302a", - "released_on": "18-01-2024", - "md5sum": "3a99f089fda47e034b16e7fa086ee051" - }, + "1.0.1": null, "1.0.0": { "api_version": 7, "commit_sha": "2aa1e50", @@ -544,12 +489,7 @@ } ], "versions": { - "1.0.1": { - "api_version": 8, - "commit_sha": "87b302a", - "released_on": "18-01-2024", - "md5sum": "627390f50e18bd76d94abf35f538ec8f" - }, + "1.0.1": null, "1.0.0": { "api_version": 7, "commit_sha": "52094fc", @@ -660,12 +600,7 @@ } ], "versions": { - "1.0.1": { - "api_version": 8, - "commit_sha": "87b302a", - "released_on": "18-01-2024", - "md5sum": "7e741a7f4c1ace1124d8719a009f8948" - }, + "1.0.1": null, "1.0.0": { "api_version": 7, "commit_sha": "7219487", @@ -685,12 +620,7 @@ } ], "versions": { - "1.0.1": { - "api_version": 8, - "commit_sha": "87b302a", - "released_on": "18-01-2024", - "md5sum": "270961a492432e6199dec2d0915d8acf" - }, + "1.0.1": null, "1.0.0": { "api_version": 7, "commit_sha": "7219487", @@ -710,12 +640,7 @@ } ], "versions": { - "1.0.1": { - "api_version": 8, - "commit_sha": "87b302a", - "released_on": "18-01-2024", - "md5sum": "3fb424583f1e686854fe94bd22c5161c" - }, + "1.0.1": null, "1.0.0": { "api_version": 7, "commit_sha": "7219487", @@ -735,12 +660,7 @@ } ], "versions": { - "1.0.1": { - "api_version": 8, - "commit_sha": "87b302a", - "released_on": "18-01-2024", - "md5sum": "7e70fb037b49b183a9fb4eaa2babb90e" - }, + "1.0.1": null, "1.0.0": { "api_version": 7, "commit_sha": "7219487", @@ -760,12 +680,7 @@ } ], "versions": { - "1.0.1": { - "api_version": 8, - "commit_sha": "87b302a", - "released_on": "18-01-2024", - "md5sum": "febeeb370ac150f455ed27bc9d557d75" - }, + "1.0.1": null, "1.0.0": { "api_version": 7, "commit_sha": "7219487", @@ -804,12 +719,7 @@ } ], "versions": { - "1.0.1": { - "api_version": 8, - "commit_sha": "5422dd6", - "released_on": "18-01-2024", - "md5sum": "82ffbb28961c57731bd64d4c4add06cd" - }, + "1.0.1": null, "1.0.0": { "api_version": 7, "commit_sha": "7219487", diff --git a/plugins/minigames/hot_potato.py b/plugins/minigames/hot_potato.py index 6a57edab..658f440e 100644 --- a/plugins/minigames/hot_potato.py +++ b/plugins/minigames/hot_potato.py @@ -92,7 +92,7 @@ def __init__(self, self._player = player self._name_scale = name_scale - self._outline_tex = bui.gettexture('characterIconMask') + self._outline_tex = bs.gettexture('characterIconMask') # Character portrait icon = player.get_icon() @@ -640,16 +640,16 @@ def __init__(self, settings: dict): self.settings = settings # Let's define all of the sounds we need. - self._tick_sound = bui.getsound('tick') - self._player_eliminated_sound = bui.getsound('playerDeath') + self._tick_sound = bs.getsound('tick') + self._player_eliminated_sound = bs.getsound('playerDeath') # These next sounds are arrays instead of single sounds. # We'll use that fact later. - self._danger_tick_sounds = [bui.getsound('orchestraHit'), - bui.getsound('orchestraHit2'), - bui.getsound('orchestraHit3')] - self._marked_sounds = [bui.getsound('powerdown01'), - bui.getsound('activateBeep'), - bui.getsound('hiss')] + self._danger_tick_sounds = [bs.getsound('orchestraHit'), + bs.getsound('orchestraHit2'), + bs.getsound('orchestraHit3')] + self._marked_sounds = [bs.getsound('powerdown01'), + bs.getsound('activateBeep'), + bs.getsound('hiss')] # Normally play KOTH music, but switch to Epic music if we're in slow motion. self._epic_mode = bool(settings['Epic Mode']) @@ -837,7 +837,7 @@ def new_mark(self) -> None: # To make a nice marked sound effect, I play multiple sounds at once # All of them are contained in the array. for sound in self._marked_sounds: - sound.play(1.0, new_victim.actor.node.position) + bs.Sound.play(sound, 1.0, new_victim.actor.node.position) self.mark(new_victim) # This function is called when the gamemode first loads. diff --git a/plugins/minigames/ultimate_last_stand.py b/plugins/minigames/ultimate_last_stand.py index cff95266..67f36cf3 100644 --- a/plugins/minigames/ultimate_last_stand.py +++ b/plugins/minigames/ultimate_last_stand.py @@ -362,7 +362,7 @@ def get_instance_description_short(self) -> str | Sequence: def on_transition_in(self) -> None: super().on_transition_in() - bs.timer(1.3, babase.Call(babase.playsound, self._new_wave_sound)) + bs.timer(1.3, self._new_wave_sound.play) def on_player_join(self, player: Player) -> None: player.lives = self._lives_per_player diff --git a/plugins/utilities.json b/plugins/utilities.json index a070a104..5404ffd6 100644 --- a/plugins/utilities.json +++ b/plugins/utilities.json @@ -19,12 +19,7 @@ } ], "versions": { - "1.0.1": { - "api_version": 8, - "commit_sha": "87b302a", - "released_on": "18-01-2024", - "md5sum": "f81810220b0cc13cc436434014fbe8de" - }, + "1.0.1": null, "1.0.0": { "api_version": 7, "commit_sha": "2454845", @@ -63,12 +58,7 @@ } ], "versions": { - "1.3.2": { - "api_version": 8, - "commit_sha": "284055e", - "released_on": "21-01-2024", - "md5sum": "1cf2d07d15dbacf0a277795f3742c14b" - }, + "1.3.2": null, "1.3.1": { "api_version": 7, "commit_sha": "d511c15", @@ -118,12 +108,7 @@ } ], "versions": { - "1.0.1": { - "api_version": 8, - "commit_sha": "87b302a", - "released_on": "18-01-2024", - "md5sum": "beab6387e86bd842ffc8c857750b510e" - }, + "1.0.1": null, "1.0.0": { "api_version": 7, "commit_sha": "2fda676", @@ -143,12 +128,7 @@ } ], "versions": { - "1.0.1": { - "api_version": 8, - "commit_sha": "87b302a", - "released_on": "18-01-2024", - "md5sum": "80f8fd9e9bd23d33daace0059029378b" - }, + "1.0.1": null, "1.0.0": { "api_version": 7, "commit_sha": "2fda676", @@ -168,12 +148,7 @@ } ], "versions": { - "1.0.1": { - "api_version": 8, - "commit_sha": "a0bff95", - "released_on": "20-01-2024", - "md5sum": "6eb01543b28a9a2c95f873aa92dbe3b2" - }, + "1.0.1": null, "1.0.0": { "api_version": 7, "commit_sha": "2fda676", @@ -193,12 +168,7 @@ } ], "versions": { - "1.0.1": { - "api_version": 8, - "commit_sha": "87b302a", - "released_on": "18-01-2024", - "md5sum": "ee8187a63d9e205f0355aa5c21141af2" - }, + "1.0.1": null, "1.0.0": { "api_version": 7, "commit_sha": "fed7c24", @@ -223,12 +193,7 @@ } ], "versions": { - "1.0.1": { - "api_version": 8, - "commit_sha": "87b302a", - "released_on": "18-01-2024", - "md5sum": "ee666a289e34c7ceca1d64ed977de4ce" - }, + "1.0.1": null, "1.0.0": { "api_version": 7, "commit_sha": "2fda676", @@ -248,12 +213,7 @@ } ], "versions": { - "1.2.3": { - "api_version": 8, - "commit_sha": "87b302a", - "released_on": "18-01-2024", - "md5sum": "6601d41f60b276d54770c0718158e701" - }, + "1.2.3": null, "1.2.2": { "api_version": 7, "commit_sha": "7753b87", @@ -518,12 +478,7 @@ } ], "versions": { - "1.0.1": { - "api_version": 8, - "commit_sha": "87b302a", - "released_on": "18-01-2024", - "md5sum": "68340cb74a1227c70045e26bb1d1e859" - }, + "1.0.1": null, "1.0.0": { "api_version": 7, "commit_sha": "6acdea8", @@ -742,12 +697,7 @@ } ], "versions": { - "3.0.1": { - "api_version": 8, - "commit_sha": "87b302a", - "released_on": "18-01-2024", - "md5sum": "697f1204f7722f27f2bdbbff3994763c" - }, + "3.0.1": null, "3.0.0": { "api_version": 7, "commit_sha": "0841b9e", @@ -767,12 +717,7 @@ } ], "versions": { - "1.0.1": { - "api_version": 8, - "commit_sha": "87b302a", - "released_on": "18-01-2024", - "md5sum": "7b1dd1432930e6dc198780a134b88c88" - }, + "1.0.1": null, "1.0.0": { "api_version": 7, "commit_sha": "0841b9e", @@ -792,12 +737,7 @@ } ], "versions": { - "1.0.1": { - "api_version": 8, - "commit_sha": "87b302a", - "released_on": "18-01-2024", - "md5sum": "7313a54c35611e9d8f7d0854b6646bc7" - }, + "1.0.1": null, "1.0.0": { "api_version": 7, "commit_sha": "0841b9e", @@ -817,12 +757,7 @@ } ], "versions": { - "1.0.1": { - "api_version": 8, - "commit_sha": "87b302a", - "released_on": "18-01-2024", - "md5sum": "bb75b79a749f26ed359e0fc99f23a958" - }, + "1.0.1": null, "1.0.0": { "api_version": 7, "commit_sha": "800125c", @@ -897,12 +832,7 @@ } ], "versions": { - "1.0.1": { - "api_version": 8, - "commit_sha": "87b302a", - "released_on": "18-01-2024", - "md5sum": "c472b9ba7be0a1f109a757c1c06b25cd" - }, + "1.0.1": null, "1.0.0": { "api_version": 7, "commit_sha": "cb2d952", @@ -922,12 +852,7 @@ } ], "versions": { - "1.0.1": { - "api_version": 8, - "commit_sha": "87b302a", - "released_on": "18-01-2024", - "md5sum": "264b14d7ec65453b74d4680d507fcb4f" - }, + "1.0.1": null, "1.0.0": { "api_version": 7, "commit_sha": "05ffa9f", @@ -947,12 +872,7 @@ } ], "versions": { - "1.0.1": { - "api_version": 8, - "commit_sha": "87b302a", - "released_on": "18-01-2024", - "md5sum": "d4b1c74d4c6e6f893f0b50c4f863720e" - }, + "1.0.1": null, "1.0.0": { "api_version": 7, "commit_sha": "3221b3a", @@ -1028,12 +948,7 @@ } ], "versions": { - "1.4.2": { - "api_version": 8, - "commit_sha": "87b302a", - "released_on": "18-01-2024", - "md5sum": "f60a0fd81c5a367e644a7b9c123af662" - }, + "1.4.2": null, "1.4.1": { "api_version": 8, "commit_sha": "48c8abb", diff --git a/plugins/utilities/auto_stunt.py b/plugins/utilities/auto_stunt.py index c060ff27..57603fbf 100644 --- a/plugins/utilities/auto_stunt.py +++ b/plugins/utilities/auto_stunt.py @@ -20,6 +20,7 @@ from bascenev1lib.actor.powerupbox import PowerupBoxFactory from bascenev1lib.actor.spazfactory import SpazFactory from bascenev1lib.game.elimination import EliminationGame +from bauiv1lib import mainmenu import math import json import os @@ -246,7 +247,7 @@ def mirror(clieid): def capture(player): - with babase.ContextRef(player.actor._activity()): + with player.actor._activity().context: player.recording_start_time = bs.time() PLAYERS_STUNT_INFO[player.sessionplayer] = [] @@ -272,7 +273,7 @@ def replay(player, stunt_name): bui.screenmessage(f"{stunt_name} doesn't exists") return player.in_replay = True - with babase.ContextRef(player.actor._activity()): + with player.actor._activity().context: ControlsUI.display(player.actor._activity()) for move in stunt: value = move["move"]["value"] @@ -294,7 +295,7 @@ def replay(player, stunt_name): def spawn_mirror_spaz(player): player.mirror_mode = True - with babase.ContextRef(player.actor._activity()): + with player.actor._activity().context: bot = spaz.Spaz(player.color, player.highlight, character=player.character).autoretain() bot.handlemessage(bs.StandMessage( (player.actor.node.position[0], player.actor.node.position[1], player.actor.node.position[2]+1), 93)) @@ -317,7 +318,7 @@ def ghost(player, stunt_name): return player.in_replay = True - with babase.ContextRef(player.actor._activity()): + with player.actor._activity().context: bot = spaz.Spaz((1, 0, 0), character="Spaz").autoretain() bot.handlemessage(bs.StandMessage(player.actor.node.position, 93)) give_ghost_power(bot) @@ -389,6 +390,7 @@ def give_ghost_power(spaz): def new_chatmessage(msg): + #! Fix here to make it work with other mods modifying chat message if not msg.startswith("*"): return original_chatmessage(msg) @@ -397,7 +399,11 @@ def new_chatmessage(msg): command = msg_splits[0] client_id = -1 - player = get_player_from_client_id(client_id) + try: + player = get_player_from_client_id(client_id) + except AttributeError: + bui.screenmessage("Start a game to use", color=(0, 1, 0)) + return if command == "start": capture(player) @@ -477,25 +483,25 @@ def set_stick_image_position(self, x: float, y: float) -> None: def on_begin(self, *args, **kwargs) -> None: self._jump_image = Image( - bui.gettexture('buttonJump'), + bs.gettexture('buttonJump'), position=(385, 160), scale=(50, 50), color=[0.1, 0.45, 0.1, 0] ) self._pickup_image = Image( - bui.gettexture('buttonPickUp'), + bs.gettexture('buttonPickUp'), position=(385, 240), scale=(50, 50), color=[0, 0.35, 0, 0] ) self._punch_image = Image( - bui.gettexture('buttonPunch'), + bs.gettexture('buttonPunch'), position=(345, 200), scale=(50, 50), color=[0.45, 0.45, 0, 0] ) self._bomb_image = Image( - bui.gettexture('buttonBomb'), + bs.gettexture('buttonBomb'), position=(425, 200), scale=(50, 50), color=[0.45, 0.1, 0.1, 0] @@ -506,7 +512,7 @@ def on_begin(self, *args, **kwargs) -> None: self._stick_base_image = bs.newnode( 'image', attrs={ - 'texture': bui.gettexture('nub'), + 'texture': bs.gettexture('nub'), 'absolute_scale': True, 'vr_depth': -40, 'position': p, @@ -517,7 +523,7 @@ def on_begin(self, *args, **kwargs) -> None: self._stick_nub_image_color = c3 = (0.4, 0.4, 0.4, 1.0) self._stick_nub_image = bs.newnode('image', attrs={ - 'texture': bui.gettexture('nub'), + 'texture': bs.gettexture('nub'), 'absolute_scale': True, 'position': p, 'scale': (110*0.6, 110*0.66), @@ -528,11 +534,16 @@ def on_begin(self, *args, **kwargs) -> None: self.set_stick_image_position = set_stick_image_position return original_on_begin(self, *args, **kwargs) - +class NewMainMenuWindow(mainmenu.MainMenuWindow): + def __init__(self, *args, **kwargs): + super().__init__(*args, **kwargs) + # Display chat icon, but if user open/close gather it may disappear + bui.set_party_icon_always_visible(True) + # ba_meta export plugin class byHeySmoothy(babase.Plugin): def on_app_running(self): - bui.set_party_icon_always_visible(True) + mainmenu.MainMenuWindow = NewMainMenuWindow bs._activity.Activity.on_begin = on_begin bs.chatmessage = new_chatmessage bascenev1lib.actor.playerspaz.PlayerSpaz = NewPlayerSpaz diff --git a/plugins/utilities/discord_richpresence.py b/plugins/utilities/discord_richpresence.py index 4980a05f..7e01d2c6 100644 --- a/plugins/utilities/discord_richpresence.py +++ b/plugins/utilities/discord_richpresence.py @@ -370,13 +370,13 @@ def is_discord_running(): def _generate_join_secret(self): # resp = requests.get('https://legacy.ballistica.net/bsAccessCheck').text - connection_info = bs.get_connection_to_host_info( - ) if build_number < 21697 else bs.get_connection_to_host_info_2() - if connection_info: - addr = _last_server_addr - port = _last_server_port - else: - try: + try: + connection_info = bs.get_connection_to_host_info( + ) if build_number < 21727 else bs.get_connection_to_host_info_2() + if connection_info: + addr = _last_server_addr + port = _last_server_port + else: with urlopen( "https://legacy.ballistica.net/bsAccessCheck" ) as resp: @@ -390,8 +390,8 @@ def _generate_join_secret(self): "port": port, } self.join_secret = json.dumps(secret_dict) - except: - pass + except: + pass def _update_secret(self): threading.Thread(target=self._generate_join_secret, daemon=True).start() @@ -872,7 +872,7 @@ def _get_current_map_name(self) -> Tuple[str | None, str | None]: def update_status(self) -> None: roster = bs.get_game_roster() connection_info = bs.get_connection_to_host_info( - ) if build_number < 21697 else bs.get_connection_to_host_info_2() + ) if build_number < 21727 else bs.get_connection_to_host_info_2() self.rpc_thread.large_image_key = "bombsquadicon" self.rpc_thread.large_image_text = "BombSquad" From 2b5c9eeecd39861c6a2fe8d920a5dc09b1970b1e Mon Sep 17 00:00:00 2001 From: brostosjoined Date: Mon, 22 Jan 2024 09:10:33 +0000 Subject: [PATCH 0822/1464] [ci] auto-format --- plugins/utilities/auto_stunt.py | 5 ++++- plugins/utilities/discord_richpresence.py | 4 ++-- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/plugins/utilities/auto_stunt.py b/plugins/utilities/auto_stunt.py index 57603fbf..aadf8c74 100644 --- a/plugins/utilities/auto_stunt.py +++ b/plugins/utilities/auto_stunt.py @@ -534,13 +534,16 @@ def on_begin(self, *args, **kwargs) -> None: self.set_stick_image_position = set_stick_image_position return original_on_begin(self, *args, **kwargs) + class NewMainMenuWindow(mainmenu.MainMenuWindow): def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) # Display chat icon, but if user open/close gather it may disappear bui.set_party_icon_always_visible(True) - + # ba_meta export plugin + + class byHeySmoothy(babase.Plugin): def on_app_running(self): mainmenu.MainMenuWindow = NewMainMenuWindow diff --git a/plugins/utilities/discord_richpresence.py b/plugins/utilities/discord_richpresence.py index 7e01d2c6..64257adb 100644 --- a/plugins/utilities/discord_richpresence.py +++ b/plugins/utilities/discord_richpresence.py @@ -372,7 +372,7 @@ def _generate_join_secret(self): # resp = requests.get('https://legacy.ballistica.net/bsAccessCheck').text try: connection_info = bs.get_connection_to_host_info( - ) if build_number < 21727 else bs.get_connection_to_host_info_2() + ) if build_number < 21727 else bs.get_connection_to_host_info_2() if connection_info: addr = _last_server_addr port = _last_server_port @@ -872,7 +872,7 @@ def _get_current_map_name(self) -> Tuple[str | None, str | None]: def update_status(self) -> None: roster = bs.get_game_roster() connection_info = bs.get_connection_to_host_info( - ) if build_number < 21727 else bs.get_connection_to_host_info_2() + ) if build_number < 21727 else bs.get_connection_to_host_info_2() self.rpc_thread.large_image_key = "bombsquadicon" self.rpc_thread.large_image_text = "BombSquad" From d2467c129828f7f8c5f8ddbc99defd1e29fafbea Mon Sep 17 00:00:00 2001 From: brostosjoined Date: Mon, 22 Jan 2024 09:10:34 +0000 Subject: [PATCH 0823/1464] [ci] apply-version-metadata --- plugins/minigames.json | 126 +++++++++++++++++++++++++++++++++++------ plugins/utilities.json | 119 ++++++++++++++++++++++++++++++++------ 2 files changed, 210 insertions(+), 35 deletions(-) diff --git a/plugins/minigames.json b/plugins/minigames.json index 5f3b9e29..ce3d820b 100644 --- a/plugins/minigames.json +++ b/plugins/minigames.json @@ -77,7 +77,12 @@ } ], "versions": { - "1.0.1": null, + "1.0.1": { + "api_version": 8, + "commit_sha": "2b5c9ee", + "released_on": "22-01-2024", + "md5sum": "3b55e82dc1c1d4d84760c23098233e30" + }, "1.0.0": { "api_version": 7, "commit_sha": "2fda676", @@ -97,7 +102,12 @@ } ], "versions": { - "1.0.1": null, + "1.0.1": { + "api_version": 8, + "commit_sha": "2b5c9ee", + "released_on": "22-01-2024", + "md5sum": "74d61a487379d163c3f5713f001ec69d" + }, "1.0.0": { "api_version": 7, "commit_sha": "2fda676", @@ -117,7 +127,12 @@ } ], "versions": { - "1.0.1": null, + "1.0.1": { + "api_version": 8, + "commit_sha": "2b5c9ee", + "released_on": "22-01-2024", + "md5sum": "25f9018fdc70173212e436d4e7c41e97" + }, "1.0.0": { "api_version": 7, "commit_sha": "2fda676", @@ -137,7 +152,12 @@ } ], "versions": { - "1.0.1": null, + "1.0.1": { + "api_version": 8, + "commit_sha": "2b5c9ee", + "released_on": "22-01-2024", + "md5sum": "4630220820b08642e9c72f9f24675298" + }, "1.0.0": { "api_version": 7, "commit_sha": "2fda676", @@ -182,7 +202,12 @@ } ], "versions": { - "1.1.0": null, + "1.1.0": { + "api_version": 8, + "commit_sha": "2b5c9ee", + "released_on": "22-01-2024", + "md5sum": "6c90c97151c31d240a760590c56d7dbf" + }, "1.0.1": { "api_version": 7, "commit_sha": "d511c15", @@ -208,7 +233,12 @@ } ], "versions": { - "2.0.1": null, + "2.0.1": { + "api_version": 8, + "commit_sha": "2b5c9ee", + "released_on": "22-01-2024", + "md5sum": "c7d3cc971090ee5a4cb0f096dad9f118" + }, "2.0.0": { "api_version": 7, "commit_sha": "8b257b3", @@ -334,7 +364,12 @@ } ], "versions": { - "1.0.1": null, + "1.0.1": { + "api_version": 8, + "commit_sha": "2b5c9ee", + "released_on": "22-01-2024", + "md5sum": "3272ee5dd06d5ad603c6a1be189ad1d1" + }, "1.0.0": { "api_version": 7, "commit_sha": "0841b9e", @@ -384,7 +419,12 @@ } ], "versions": { - "1.0.1": null, + "1.0.1": { + "api_version": 8, + "commit_sha": "2b5c9ee", + "released_on": "22-01-2024", + "md5sum": "3730cdc9f922ac5a8c86e2c7debd09fe" + }, "1.0.0": { "api_version": 7, "commit_sha": "52094fc", @@ -429,7 +469,12 @@ } ], "versions": { - "1.0.1": null, + "1.0.1": { + "api_version": 8, + "commit_sha": "2b5c9ee", + "released_on": "22-01-2024", + "md5sum": "a1d2d75303aaeb0b078a4c836d65ebee" + }, "1.0.0": { "api_version": 7, "commit_sha": "2aa1e50", @@ -449,7 +494,12 @@ } ], "versions": { - "1.0.1": null, + "1.0.1": { + "api_version": 8, + "commit_sha": "2b5c9ee", + "released_on": "22-01-2024", + "md5sum": "aa03952868be8e978d7b23891883b52a" + }, "1.0.0": { "api_version": 7, "commit_sha": "2aa1e50", @@ -469,7 +519,12 @@ } ], "versions": { - "1.0.1": null, + "1.0.1": { + "api_version": 8, + "commit_sha": "2b5c9ee", + "released_on": "22-01-2024", + "md5sum": "3a99f089fda47e034b16e7fa086ee051" + }, "1.0.0": { "api_version": 7, "commit_sha": "2aa1e50", @@ -489,7 +544,12 @@ } ], "versions": { - "1.0.1": null, + "1.0.1": { + "api_version": 8, + "commit_sha": "2b5c9ee", + "released_on": "22-01-2024", + "md5sum": "627390f50e18bd76d94abf35f538ec8f" + }, "1.0.0": { "api_version": 7, "commit_sha": "52094fc", @@ -600,7 +660,12 @@ } ], "versions": { - "1.0.1": null, + "1.0.1": { + "api_version": 8, + "commit_sha": "2b5c9ee", + "released_on": "22-01-2024", + "md5sum": "7e741a7f4c1ace1124d8719a009f8948" + }, "1.0.0": { "api_version": 7, "commit_sha": "7219487", @@ -620,7 +685,12 @@ } ], "versions": { - "1.0.1": null, + "1.0.1": { + "api_version": 8, + "commit_sha": "2b5c9ee", + "released_on": "22-01-2024", + "md5sum": "270961a492432e6199dec2d0915d8acf" + }, "1.0.0": { "api_version": 7, "commit_sha": "7219487", @@ -640,7 +710,12 @@ } ], "versions": { - "1.0.1": null, + "1.0.1": { + "api_version": 8, + "commit_sha": "2b5c9ee", + "released_on": "22-01-2024", + "md5sum": "3fb424583f1e686854fe94bd22c5161c" + }, "1.0.0": { "api_version": 7, "commit_sha": "7219487", @@ -660,7 +735,12 @@ } ], "versions": { - "1.0.1": null, + "1.0.1": { + "api_version": 8, + "commit_sha": "2b5c9ee", + "released_on": "22-01-2024", + "md5sum": "7e70fb037b49b183a9fb4eaa2babb90e" + }, "1.0.0": { "api_version": 7, "commit_sha": "7219487", @@ -680,7 +760,12 @@ } ], "versions": { - "1.0.1": null, + "1.0.1": { + "api_version": 8, + "commit_sha": "2b5c9ee", + "released_on": "22-01-2024", + "md5sum": "febeeb370ac150f455ed27bc9d557d75" + }, "1.0.0": { "api_version": 7, "commit_sha": "7219487", @@ -719,7 +804,12 @@ } ], "versions": { - "1.0.1": null, + "1.0.1": { + "api_version": 8, + "commit_sha": "2b5c9ee", + "released_on": "22-01-2024", + "md5sum": "82ffbb28961c57731bd64d4c4add06cd" + }, "1.0.0": { "api_version": 7, "commit_sha": "7219487", diff --git a/plugins/utilities.json b/plugins/utilities.json index 5404ffd6..949c6ee9 100644 --- a/plugins/utilities.json +++ b/plugins/utilities.json @@ -19,7 +19,12 @@ } ], "versions": { - "1.0.1": null, + "1.0.1": { + "api_version": 8, + "commit_sha": "2b5c9ee", + "released_on": "22-01-2024", + "md5sum": "f81810220b0cc13cc436434014fbe8de" + }, "1.0.0": { "api_version": 7, "commit_sha": "2454845", @@ -58,7 +63,12 @@ } ], "versions": { - "1.3.2": null, + "1.3.2": { + "api_version": 8, + "commit_sha": "2b5c9ee", + "released_on": "22-01-2024", + "md5sum": "1cf2d07d15dbacf0a277795f3742c14b" + }, "1.3.1": { "api_version": 7, "commit_sha": "d511c15", @@ -108,7 +118,12 @@ } ], "versions": { - "1.0.1": null, + "1.0.1": { + "api_version": 8, + "commit_sha": "2b5c9ee", + "released_on": "22-01-2024", + "md5sum": "beab6387e86bd842ffc8c857750b510e" + }, "1.0.0": { "api_version": 7, "commit_sha": "2fda676", @@ -128,7 +143,12 @@ } ], "versions": { - "1.0.1": null, + "1.0.1": { + "api_version": 8, + "commit_sha": "2b5c9ee", + "released_on": "22-01-2024", + "md5sum": "80f8fd9e9bd23d33daace0059029378b" + }, "1.0.0": { "api_version": 7, "commit_sha": "2fda676", @@ -148,7 +168,12 @@ } ], "versions": { - "1.0.1": null, + "1.0.1": { + "api_version": 8, + "commit_sha": "2b5c9ee", + "released_on": "22-01-2024", + "md5sum": "6eb01543b28a9a2c95f873aa92dbe3b2" + }, "1.0.0": { "api_version": 7, "commit_sha": "2fda676", @@ -168,7 +193,12 @@ } ], "versions": { - "1.0.1": null, + "1.0.1": { + "api_version": 8, + "commit_sha": "2b5c9ee", + "released_on": "22-01-2024", + "md5sum": "ee8187a63d9e205f0355aa5c21141af2" + }, "1.0.0": { "api_version": 7, "commit_sha": "fed7c24", @@ -193,7 +223,12 @@ } ], "versions": { - "1.0.1": null, + "1.0.1": { + "api_version": 8, + "commit_sha": "2b5c9ee", + "released_on": "22-01-2024", + "md5sum": "ee666a289e34c7ceca1d64ed977de4ce" + }, "1.0.0": { "api_version": 7, "commit_sha": "2fda676", @@ -213,7 +248,12 @@ } ], "versions": { - "1.2.3": null, + "1.2.3": { + "api_version": 8, + "commit_sha": "2b5c9ee", + "released_on": "22-01-2024", + "md5sum": "6601d41f60b276d54770c0718158e701" + }, "1.2.2": { "api_version": 7, "commit_sha": "7753b87", @@ -478,7 +518,12 @@ } ], "versions": { - "1.0.1": null, + "1.0.1": { + "api_version": 8, + "commit_sha": "2b5c9ee", + "released_on": "22-01-2024", + "md5sum": "e80ed956d637392c948725899da135e3" + }, "1.0.0": { "api_version": 7, "commit_sha": "6acdea8", @@ -697,7 +742,12 @@ } ], "versions": { - "3.0.1": null, + "3.0.1": { + "api_version": 8, + "commit_sha": "2b5c9ee", + "released_on": "22-01-2024", + "md5sum": "697f1204f7722f27f2bdbbff3994763c" + }, "3.0.0": { "api_version": 7, "commit_sha": "0841b9e", @@ -717,7 +767,12 @@ } ], "versions": { - "1.0.1": null, + "1.0.1": { + "api_version": 8, + "commit_sha": "2b5c9ee", + "released_on": "22-01-2024", + "md5sum": "7b1dd1432930e6dc198780a134b88c88" + }, "1.0.0": { "api_version": 7, "commit_sha": "0841b9e", @@ -737,7 +792,12 @@ } ], "versions": { - "1.0.1": null, + "1.0.1": { + "api_version": 8, + "commit_sha": "2b5c9ee", + "released_on": "22-01-2024", + "md5sum": "7313a54c35611e9d8f7d0854b6646bc7" + }, "1.0.0": { "api_version": 7, "commit_sha": "0841b9e", @@ -757,7 +817,12 @@ } ], "versions": { - "1.0.1": null, + "1.0.1": { + "api_version": 8, + "commit_sha": "2b5c9ee", + "released_on": "22-01-2024", + "md5sum": "bb75b79a749f26ed359e0fc99f23a958" + }, "1.0.0": { "api_version": 7, "commit_sha": "800125c", @@ -832,7 +897,12 @@ } ], "versions": { - "1.0.1": null, + "1.0.1": { + "api_version": 8, + "commit_sha": "2b5c9ee", + "released_on": "22-01-2024", + "md5sum": "c472b9ba7be0a1f109a757c1c06b25cd" + }, "1.0.0": { "api_version": 7, "commit_sha": "cb2d952", @@ -852,7 +922,12 @@ } ], "versions": { - "1.0.1": null, + "1.0.1": { + "api_version": 8, + "commit_sha": "2b5c9ee", + "released_on": "22-01-2024", + "md5sum": "264b14d7ec65453b74d4680d507fcb4f" + }, "1.0.0": { "api_version": 7, "commit_sha": "05ffa9f", @@ -872,7 +947,12 @@ } ], "versions": { - "1.0.1": null, + "1.0.1": { + "api_version": 8, + "commit_sha": "2b5c9ee", + "released_on": "22-01-2024", + "md5sum": "d4b1c74d4c6e6f893f0b50c4f863720e" + }, "1.0.0": { "api_version": 7, "commit_sha": "3221b3a", @@ -948,7 +1028,12 @@ } ], "versions": { - "1.4.2": null, + "1.4.2": { + "api_version": 8, + "commit_sha": "2b5c9ee", + "released_on": "22-01-2024", + "md5sum": "7301fb55984f9caa4018bab40c4945d0" + }, "1.4.1": { "api_version": 8, "commit_sha": "48c8abb", From e01840c83d35766a2ddb5e90a6715d56cd785785 Mon Sep 17 00:00:00 2001 From: brostosjoined Date: Wed, 24 Jan 2024 14:17:05 +0300 Subject: [PATCH 0824/1464] Update request from bombsquaders --- plugins/minigames.json | 98 ++ plugins/minigames/Avalanche.py | 143 +++ plugins/minigames/EggGame.py | 491 ++++++++ plugins/minigames/HYPER_RACE.py | 1239 ++++++++++++++++++++ plugins/minigames/SnowBallFight.py | 643 ++++++++++ plugins/minigames/meteorshowerdeluxe.py | 67 ++ plugins/minigames/ofuuuAttack.py | 340 ++++++ plugins/minigames/safe_zone.py | 720 ++++++++++++ plugins/utilities.json | 58 +- plugins/utilities/InfinityShield.py | 81 ++ plugins/utilities/OnlyNight.py | 50 + plugins/utilities/Tag.py | 565 +++++++++ plugins/utilities/disable_friendly_fire.py | 108 ++ 13 files changed, 4602 insertions(+), 1 deletion(-) create mode 100644 plugins/minigames/Avalanche.py create mode 100644 plugins/minigames/EggGame.py create mode 100644 plugins/minigames/HYPER_RACE.py create mode 100644 plugins/minigames/SnowBallFight.py create mode 100644 plugins/minigames/meteorshowerdeluxe.py create mode 100644 plugins/minigames/ofuuuAttack.py create mode 100644 plugins/minigames/safe_zone.py create mode 100644 plugins/utilities/InfinityShield.py create mode 100644 plugins/utilities/OnlyNight.py create mode 100644 plugins/utilities/Tag.py create mode 100644 plugins/utilities/disable_friendly_fire.py diff --git a/plugins/minigames.json b/plugins/minigames.json index 5f3b9e29..01a7b96d 100644 --- a/plugins/minigames.json +++ b/plugins/minigames.json @@ -877,6 +877,104 @@ "md5sum": "1cbe5b3e85b5dfcee1eb322f33568fd4" } } + }, + "Avalanche": { + "description": "Dodge the falling ice bombs", + "external_url": "", + "authors": [ + { + "name": "", + "email": "", + "discord": "" + } + ], + "versions": { + "1.0.0": null + } + }, + "HYPER_RACE": { + "description": "Race and avoid the obsatacles", + "external_url": "", + "authors": [ + { + "name": "JoseAng3l", + "email": "", + "discord": "joseang3l" + } + ], + "versions": { + "1.0.0": null + } + }, + "meteorshowerdeluxe": { + "description": "Meteor shower on all maps support", + "external_url": "", + "authors": [ + { + "name": "EraOSBeta", + "email": "", + "discord": "3ra0" + } + ], + "versions": { + "1.0.0": null + } + }, + "ofuuuAttack": { + "description": "Dodge the falling bombs.", + "external_url": "", + "authors": [ + { + "name": "Riyukii", + "email": "", + "discord": "" + } + ], + "versions": { + "1.0.0": null + } + }, + "safe_zone": { + "description": "Stay in the safe zone", + "external_url": "", + "authors": [ + { + "name": "SEBASTIAN2059", + "email": "", + "discord": "sebastian2059" + } + ], + "versions": { + "1.0.0": null + } + }, + "SnowBallFight": { + "description": "Throw snoballs and dominate", + "external_url": "https://youtu.be/uXyb_meBjGI?si=D_N_OXZT5BFh8R5C", + "authors": [ + { + "name": "JoseAng3l", + "email": "", + "discord": "joseang3l" + } + ], + "versions": { + "1.0.0": null + } + }, + "EggGame": { + "description": "Throw Egg as far u can", + "external_url": "https://youtu.be/82vLp9ceCcw?si=OSC5Hu3Ns7PevlwP", + "authors": [ + { + "name": "Mr.Smoothy", + "email": "", + "discord": "mr.smoothy" + } + ], + "versions": { + "1.0.0": null + } } } } \ No newline at end of file diff --git a/plugins/minigames/Avalanche.py b/plugins/minigames/Avalanche.py new file mode 100644 index 00000000..1e362080 --- /dev/null +++ b/plugins/minigames/Avalanche.py @@ -0,0 +1,143 @@ +# Porting to api 8 made easier by baport.(https://github.com/bombsquad-community/baport) +"""Avalancha mini-game.""" + +# ba_meta require api 8 +# (see https://ballistica.net/wiki/meta-tag-system) + +from __future__ import annotations +import random +from typing import TYPE_CHECKING + +import babase +import bauiv1 as bui +import bascenev1 as bs +from bascenev1lib.actor.bomb import Bomb +from bascenev1lib.actor.onscreentimer import OnScreenTimer +from bascenev1lib.game.meteorshower import * +from bascenev1lib.actor.spazbot import * +from bascenev1lib.actor.spaz import PunchHitMessage +from bascenev1lib.gameutils import SharedObjects + +if TYPE_CHECKING: + from typing import Any, Sequence, Optional, List, Dict, Type, Type + +## MoreMinigames.py support ## +randomPic = ["lakeFrigidPreview", "hockeyStadiumPreview"] + + +def ba_get_api_version(): + return 6 + + +def ba_get_levels(): + return [ + babase._level.Level( + "Icy Emits", + gametype=IcyEmitsGame, + settings={}, + preview_texture_name=random.choice(randomPic), + ) + ] + + +## MoreMinigames.py support ## + + +class PascalBot(BrawlerBot): + color = (0, 0, 3) + highlight = (0.2, 0.2, 1) + character = "Pascal" + bouncy = True + punchiness = 0.7 + + def handlemessage(self, msg: Any) -> Any: + assert not self.expired + if isinstance(msg, bs.FreezeMessage): + return + else: + super().handlemessage(msg) + + +# ba_meta export bascenev1.GameActivity +class AvalanchaGame(MeteorShowerGame): + """Minigame involving dodging falling bombs.""" + + name = "Avalanche" + description = "Dodge the ice-bombs." + available_settings = [ + bs.BoolSetting("Epic Mode", default=False), + bs.IntSetting("Difficulty", default=1, min_value=1, max_value=3, increment=1), + ] + scoreconfig = bs.ScoreConfig( + label="Survived", scoretype=bs.ScoreType.MILLISECONDS, version="B" + ) + + announce_player_deaths = True + + @classmethod + def get_supported_maps(cls, sessiontype: Type[bs.Session]) -> List[str]: + return ["Tip Top"] + + def __init__(self, settings: dict): + super().__init__(settings) + + self._epic_mode = settings.get("Epic Mode", False) + self._last_player_death_time: Optional[float] = None + self._meteor_time = 2.0 + if settings["Difficulty"] == 1: + self._min_delay = 0.4 + elif settings["Difficulty"] == 2: + self._min_delay = 0.3 + else: + self._min_delay = 0.1 + + self._timer: Optional[OnScreenTimer] = None + self._bots = SpazBotSet() + + self.default_music = ( + bs.MusicType.EPIC if self._epic_mode else bs.MusicType.SURVIVAL + ) + if self._epic_mode: + self.slow_motion = True + + def on_transition_in(self) -> None: + super().on_transition_in() + gnode = bs.getactivity().globalsnode + gnode.tint = (0.5, 0.5, 1) + + act = bs.getactivity().map + shared = SharedObjects.get() + mat = bs.Material() + mat.add_actions(actions=("modify_part_collision", "friction", 0.18)) + + act.node.color = act.bottom.color = (1, 1, 1.2) + act.node.reflection = act.bottom.reflection = "soft" + act.node.materials = [shared.footing_material, mat] + + def _set_meteor_timer(self) -> None: + bs.timer( + (1.0 + 0.2 * random.random()) * self._meteor_time, self._drop_bomb_cluster + ) + + def _drop_bomb_cluster(self) -> None: + defs = self.map.defs + delay = 0.0 + for _i in range(random.randrange(1, 3)): + pos = defs.points["flag_default"] + pos = (pos[0], pos[1] + 0.4, pos[2]) + dropdir = -1.0 if pos[0] > 0 else 1.0 + vel = (random.randrange(-4, 4), 7.0, random.randrange(0, 4)) + bs.timer(delay, babase.Call(self._drop_bomb, pos, vel)) + delay += 0.1 + self._set_meteor_timer() + + def _drop_bomb(self, position: Sequence[float], velocity: Sequence[float]) -> None: + Bomb(position=position, velocity=velocity, bomb_type="ice").autoretain() + + def _decrement_meteor_time(self) -> None: + if self._meteor_time < self._min_delay: + return + self._meteor_time = max(0.01, self._meteor_time * 0.9) + if random.choice([0, 0, 1]) == 1: + pos = self.map.defs.points["flag_default"] + self._bots.spawn_bot(PascalBot, pos=pos, spawn_time=2) diff --git a/plugins/minigames/EggGame.py b/plugins/minigames/EggGame.py new file mode 100644 index 00000000..e2d2030e --- /dev/null +++ b/plugins/minigames/EggGame.py @@ -0,0 +1,491 @@ +# Ported by brostos to api 8 +# Tool used to make porting easier.(https://github.com/bombsquad-community/baport) +# Released under the MIT License. See LICENSE for details. + +"""Egg game and support classes.""" +# The Egg Game - throw egg as far as you can +# created in BCS (Bombsquad Consultancy Service) - opensource bombsquad mods for all +# discord.gg/ucyaesh join now and give your contribution +# The Egg game by mr.smoothy +# ba_meta require api 8 +# (see https://ballistica.net/wiki/meta-tag-system) + +from __future__ import annotations + +from typing import TYPE_CHECKING + +import babase +import bauiv1 as bui +import bascenev1 as bs +from bascenev1lib.actor.playerspaz import PlayerSpaz +from bascenev1lib.actor.scoreboard import Scoreboard +from bascenev1lib.actor.powerupbox import PowerupBoxFactory +from bascenev1lib.gameutils import SharedObjects +from bascenev1lib.actor.flag import Flag +import math +import random +if TYPE_CHECKING: + from typing import Any, Sequence, Dict, Type, List, Optional, Union + + +class PuckDiedMessage: + """Inform something that a puck has died.""" + + def __init__(self, puck: Puck): + self.puck = puck + + +class Puck(bs.Actor): + """A lovely giant hockey puck.""" + + def __init__(self, position: Sequence[float] = (0.0, 1.0, 0.0)): + super().__init__() + shared = SharedObjects.get() + activity = self.getactivity() + + # Spawn just above the provided point. + self._spawn_pos = (position[0], position[1] + 1.0, position[2]) + self.last_players_to_touch =None + self.scored = False + self.egg_mesh = bs.getmesh('egg') + self.egg_tex_1 = bs.gettexture('eggTex1') + self.egg_tex_2 = bs.gettexture('eggTex2') + self.egg_tex_3 = bs.gettexture('eggTex3') + self.eggtx=[self.egg_tex_1,self.egg_tex_2,self.egg_tex_3] + regg=random.randrange(0,3) + assert activity is not None + assert isinstance(activity, EggGame) + pmats = [shared.object_material, activity.puck_material] + self.node = bs.newnode('prop', + delegate=self, + attrs={ + 'mesh': self.egg_mesh, + 'color_texture': self.eggtx[regg], + 'body': 'capsule', + 'reflection': 'soft', + 'reflection_scale': [0.2], + 'shadow_size': 0.5, + 'body_scale':0.7, + 'is_area_of_interest': True, + 'position': self._spawn_pos, + 'materials': pmats + }) + bs.animate(self.node, 'mesh_scale', {0: 0, 0.2: 0.7, 0.26: 0.6}) + + def handlemessage(self, msg: Any) -> Any: + if isinstance(msg, bs.DieMessage): + assert self.node + self.node.delete() + activity = self._activity() + if activity and not msg.immediate: + activity.handlemessage(PuckDiedMessage(self)) + + # If we go out of bounds, move back to where we started. + elif isinstance(msg, bs.OutOfBoundsMessage): + assert self.node + self.node.position = self._spawn_pos + + elif isinstance(msg, bs.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 + else: + super().handlemessage(msg) + + +class Player(bs.Player['Team']): + """Our player type for this game.""" + + +class Team(bs.Team[Player]): + """Our team type for this game.""" + + def on_app_running(self) -> None: + self.score = 0 + + +# ba_meta export bascenev1.GameActivity +class EggGame(bs.TeamGameActivity[Player, Team]): + """Egg game.""" + + name = 'Epic Egg Game' + description = 'Score some goals.' + available_settings = [ + bs.IntSetting( + 'Score to Win', + min_value=1, + default=1, + increment=1, + ), + bs.IntChoiceSetting( + 'Time Limit', + choices=[ + ('None', 0), + ('40 Seconds', 40), + ('1 Minute', 60), + ('2 Minutes', 120), + ('5 Minutes', 300), + ('10 Minutes', 600), + ('20 Minutes', 1200), + ], + default=0, + ), + bs.FloatChoiceSetting( + 'Respawn Times', + choices=[ + ('Shorter', 0.1), + ('Short', 0.5), + ('Normal', 1.0), + ('Long', 2.0), + ('Longer', 4.0), + ], + default=1.0, + ), + ] + default_music = bs.MusicType.HOCKEY + + @classmethod + def supports_session_type(cls, sessiontype: Type[bs.Session]) -> bool: + return issubclass(sessiontype, bs.DualTeamSession) + + @classmethod + def get_supported_maps(cls, sessiontype: Type[bs.Session]) -> List[str]: + return bs.app.classic.getmaps('football') + + def __init__(self, settings: dict): + super().__init__(settings) + shared = SharedObjects.get() + self.slow_motion = True + self._scoreboard = Scoreboard() + self._cheer_sound = bui.getsound('cheer') + self._chant_sound = bui.getsound('crowdChant') + self._foghorn_sound = bui.getsound('foghorn') + self._swipsound = bui.getsound('swip') + self._whistle_sound = bui.getsound('refWhistle') + self.puck_mesh = bs.getmesh('bomb') + self.puck_tex = bs.gettexture('landMine') + self.puck_scored_tex = bs.gettexture('landMineLit') + self._puck_sound = bui.getsound('metalHit') + self.puck_material = bs.Material() + self._fake_wall_material=bs.Material() + self.HIGHEST=0 + self._fake_wall_material.add_actions( + conditions=('they_have_material', shared.player_material), + actions=( + ('modify_part_collision', 'collide', True), + ('modify_part_collision', 'physical', True) + + )) + self.puck_material.add_actions(actions=(('modify_part_collision', + 'friction', 0.5))) + self.puck_material.add_actions(conditions=('they_have_material', + shared.pickup_material), + actions=('modify_part_collision', + 'collide', True)) + self.puck_material.add_actions( + conditions=( + ('we_are_younger_than', 100), + 'and', + ('they_have_material', shared.object_material), + ), + actions=('modify_node_collision', 'collide', False), + ) + # self.puck_material.add_actions(conditions=('they_have_material', + # shared.footing_material), + # actions=('impact_sound', + # self._puck_sound, 0.2, 5)) + + # Keep track of which player last touched the puck + self.puck_material.add_actions( + conditions=('they_have_material', shared.player_material), + actions=(('call', 'at_connect', + self._handle_puck_player_collide), )) + + # We want the puck to kill powerups; not get stopped by them + self.puck_material.add_actions( + conditions=('they_have_material', + PowerupBoxFactory.get().powerup_material), + actions=(('modify_part_collision', 'physical', False), + ('message', 'their_node', 'at_connect', bs.DieMessage()))) + # self.puck_material.add_actions( + # conditions=('they_have_material',shared.footing_material) + # actions=(('modify_part_collision', 'collide', + # True), ('modify_part_collision', 'physical', True), + # ('call', 'at_connect', self._handle_egg_collision)) + # ) + self._score_region_material = bs.Material() + self._score_region_material.add_actions( + conditions=('they_have_material', self.puck_material), + actions=(('modify_part_collision', 'collide', + True), ('modify_part_collision', 'physical', False), + ('call', 'at_connect', self._handle_score))) + self.main_ground_material= bs.Material() + + self.main_ground_material.add_actions( + conditions=('they_have_material', self.puck_material), + actions=(('modify_part_collision', 'collide', + True), ('modify_part_collision', 'physical', False), + ('call', 'at_connect', self._handle_egg_collision))) + + self._puck_spawn_pos: Optional[Sequence[float]] = None + self._score_regions: Optional[List[bs.NodeActor]] = None + self._puck: Optional[Puck] = None + self._pucks=[] + self._score_to_win = int(settings['Score to Win']) + self._time_limit = float(settings['Time Limit']) + + def get_instance_description(self) -> Union[str, Sequence]: + return "Throw Egg as far u can" + + def get_instance_description_short(self) -> Union[str, Sequence]: + return "Throw Egg as far u can" + + def on_begin(self) -> None: + super().on_begin() + if self._time_limit==0.0: + self._time_limit=60 + self.setup_standard_time_limit(self._time_limit) + # self.setup_standard_powerup_drops() + self._puck_spawn_pos = self.map.get_flag_position(None) + self._spawn_puck() + self._spawn_puck() + self._spawn_puck() + self._spawn_puck() + self._spawn_puck() + + # Set up the two score regions. + defs = self.map.defs + self._score_regions = [] + pos=(11.88630542755127, 0.3009839951992035, 1.33331298828125) + # mat=bs.Material() + # mat.add_actions( + + # actions=( ('modify_part_collision','physical',True), + # ('modify_part_collision','collide',True)) + # ) + # self._score_regions.append( + # bs.NodeActor( + # bs.newnode('region', + # attrs={ + # 'position': pos, + # 'scale': (2,3,5), + # 'type': 'box', + # 'materials': [self._score_region_material] + # }))) + # pos=(-11.88630542755127, 0.3009839951992035, 1.33331298828125) + # self._score_regions.append( + # bs.NodeActor( + # bs.newnode('region', + # attrs={ + # 'position': pos, + # 'scale': (2,3,5), + # 'type': 'box', + # 'materials': [self._score_region_material] + # }))) + self._score_regions.append( + bs.NodeActor( + bs.newnode('region', + attrs={ + 'position': (-9.21,defs.boxes['goal2'][0:3][1],defs.boxes['goal2'][0:3][2]), + 'scale': defs.boxes['goal2'][6:9], + 'type': 'box', + 'materials': (self._fake_wall_material, ) + }))) + pos=(0,0.1,-5) + self.main_ground=bs.newnode('region',attrs={'position': pos,'scale': (25,0.001,22),'type': 'box','materials': [self.main_ground_material]}) + self._update_scoreboard() + self._chant_sound.play() + + def on_team_join(self, team: Team) -> None: + self._update_scoreboard() + + def _handle_puck_player_collide(self) -> None: + collision = bs.getcollision() + try: + puck = collision.sourcenode.getdelegate(Puck, True) + player = collision.opposingnode.getdelegate(PlayerSpaz, + True).getplayer( + Player, True) + except bs.NotFoundError: + return + + puck.last_players_to_touch = player + + def _kill_puck(self) -> None: + self._puck = None + def _handle_egg_collision(self) -> None: + + no=bs.getcollision().opposingnode + pos=no.position + egg=no.getdelegate(Puck) + source_player=egg.last_players_to_touch + if source_player==None or pos[0]< -8 or not source_player.node.exists() : + return + + + try: + col=source_player.team.color + self.flagg=Flag(pos,touchable=False,color=col).autoretain() + self.flagg.is_area_of_interest=True + player_pos=source_player.node.position + + distance = math.sqrt( pow(player_pos[0]-pos[0],2) + pow(player_pos[2]-pos[2],2)) + + + dis_mark=bs.newnode('text', + + attrs={ + 'text':str(round(distance,2))+"m", + 'in_world':True, + 'scale':0.02, + 'h_align':'center', + 'position':(pos[0],1.6,pos[2]), + 'color':col + }) + bs.animate(dis_mark,'scale',{ + 0.0:0, 0.5:0.01 + }) + if distance > self.HIGHEST: + self.HIGHEST=distance + self.stats.player_scored( + source_player, + 10, + big_message=False) + + no.delete() + bs.timer(2,self._spawn_puck) + source_player.team.score=int(distance) + + except(): + pass + def spawn_player(self, player: Player) -> bs.Actor: + + + zoo=random.randrange(-4,5) + pos=(-11.204887390136719, 0.2998693287372589, zoo) + spaz = self.spawn_player_spaz( + player, position=pos, angle=90 ) + assert spaz.node + + # Prevent controlling of characters before the start of the race. + + return spaz + def _handle_score(self) -> None: + """A point has been scored.""" + + assert self._puck is not None + assert self._score_regions is not None + + # Our puck might stick around for a second or two + # we don't want it to be able to score again. + if self._puck.scored: + return + + region = bs.getcollision().sourcenode + index = 0 + for index in range(len(self._score_regions)): + if region == self._score_regions[index].node: + break + + for team in self.teams: + if team.id == index: + scoring_team = team + team.score += 1 + + # Tell all players to celebrate. + for player in team.players: + if player.actor: + player.actor.handlemessage(bs.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._puck.last_players_to_touch + and self._puck.last_players_to_touch[scoring_team.id]): + self.stats.player_scored( + self._puck.last_players_to_touch[scoring_team.id], + 20, + big_message=True) + + # End game if we won. + if team.score >= self._score_to_win: + self.end_game() + + self._foghorn_sound.play() + self._cheer_sound.play() + + # self._puck.scored = True + + # Change puck texture to something cool + # self._puck.node.color_texture = self.puck_scored_tex + # Kill the puck (it'll respawn itself shortly). + bs.timer(1.0, self._kill_puck) + + # light = bs.newnode('light', + # attrs={ + # 'position': bs.getcollision().position, + # 'height_attenuated': False, + # 'color': (1, 0, 0) + # }) + # bs.animate(light, 'intensity', {0: 0, 0.5: 1, 1.0: 0}, loop=True) + # bs.timer(1.0, light.delete) + + bs.cameraflash(duration=10.0) + self._update_scoreboard() + + def end_game(self) -> None: + results = bs.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, bs.PlayerDiedMessage): + # Augment standard behavior... + super().handlemessage(msg) + self.respawn_player(msg.getplayer(Player)) + + # Respawn dead pucks. + elif isinstance(msg, PuckDiedMessage): + if not self.has_ended(): + bs.timer(3.0, self._spawn_puck) + else: + super().handlemessage(msg) + + def _flash_puck_spawn(self) -> None: + # light = bs.newnode('light', + # attrs={ + # 'position': self._puck_spawn_pos, + # 'height_attenuated': False, + # 'color': (1, 0, 0) + # }) + # bs.animate(light, 'intensity', {0.0: 0, 0.25: 1, 0.5: 0}, loop=True) + # bs.timer(1.0, light.delete) + pass + def _spawn_puck(self) -> None: + # self._swipsound.play() + # self._whistle_sound.play() + self._flash_puck_spawn() + assert self._puck_spawn_pos is not None + zoo=random.randrange(-5,6) + pos=(-11.204887390136719, 0.2998693287372589, zoo) + self._pucks.append (Puck(position=pos)) diff --git a/plugins/minigames/HYPER_RACE.py b/plugins/minigames/HYPER_RACE.py new file mode 100644 index 00000000..e09478ce --- /dev/null +++ b/plugins/minigames/HYPER_RACE.py @@ -0,0 +1,1239 @@ +# Porting to api 8 made easier by baport.(https://github.com/bombsquad-community/baport) +# ba_meta require api 8 + +from __future__ import annotations + +import random +from typing import TYPE_CHECKING +from dataclasses import dataclass + +import babase +import bauiv1 as bui +import bascenev1 as bs +from bascenev1 import _map +from bascenev1lib.actor.bomb import Bomb, Blast, BombFactory +from bascenev1lib.actor.powerupbox import PowerupBox +from bascenev1lib.actor.playerspaz import PlayerSpaz +from bascenev1lib.actor.scoreboard import Scoreboard +from bascenev1lib.gameutils import SharedObjects + +if TYPE_CHECKING: + from typing import (Any, Type, Tuple, List, Sequence, Optional, Dict, + Union) + from bascenev1lib.actor.onscreentimer import OnScreenTimer + + +class ThePadDefs: + points = {} + boxes = {} + points['race_mine1'] = (0, 5, 12) + points['race_point1'] = (0.2, 5, 2.86308) + (0.507, 4.673, 1.1) + points['race_point2'] = (6.9301, 5.04988, 2.82066) + (0.911, 4.577, 1.073) + points['race_point3'] = (6.98857, 4.5011, -8.88703) + (1.083, 4.673, 1.076) + points['race_point4'] = (-6.4441, 4.5011, -8.88703) + (1.083, 4.673, 1.076) + points['race_point5'] = (-6.31128, 4.5011, 2.82669) + (0.894, 4.673, 0.941) + boxes['area_of_interest_bounds'] = ( + 0.3544110667, 4.493562578, -2.518391331) + ( + 0.0, 0.0, 0.0) + (16.64754831, 8.06138989, 18.5029888) + points['ffa_spawn1'] = (-0, 5, 2.5) + points['flag1'] = (-7.026110145, 4.308759233, -6.302807727) + points['flag2'] = (7.632557137, 4.366002373, -6.287969342) + points['flagDefault'] = (0.4611826686, 4.382076338, 3.680881802) + boxes['map_bounds'] = (0.2608783669, 4.899663734, -3.543675157) + ( + 0.0, 0.0, 0.0) + (29.23565494, 14.19991443, 29.92689344) + points['powerup_spawn1'] = (-4.166594349, 5.281834349, -6.427493781) + points['powerup_spawn2'] = (4.426873526, 5.342460464, -6.329745237) + points['powerup_spawn3'] = (-4.201686731, 5.123385835, 0.4400721376) + points['powerup_spawn4'] = (4.758924722, 5.123385835, 0.3494054559) + points['shadow_lower_bottom'] = (-0.2912522507, 2.020798381, 5.341226521) + points['shadow_lower_top'] = (-0.2912522507, 3.206066063, 5.341226521) + points['shadow_upper_bottom'] = (-0.2912522507, 6.062361813, 5.341226521) + points['shadow_upper_top'] = (-0.2912522507, 9.827201965, 5.341226521) + points['spawn1'] = (-0, 5, 2.5) + points['tnt1'] = (0.4599593402, 4.044276501, -6.573537395) + + +class ThePadMapb(bs.Map): + defs = ThePadDefs() + name = 'Racing' + + @classmethod + def get_play_types(cls) -> List[str]: + """Return valid play types for this map.""" + return ['hyper'] + + @classmethod + def get_preview_texture_name(cls) -> str: + return 'thePadPreview' + + @classmethod + def on_preload(cls) -> Any: + data: Dict[str, Any] = { + 'mesh': bs.getmesh('thePadLevel'), + 'bottom_mesh': bs.getmesh('thePadLevelBottom'), + 'collision_mesh': bs.getcollisionmesh('thePadLevelCollide'), + 'tex': bs.gettexture('thePadLevelColor'), + 'bgtex': bs.gettexture('black'), + 'bgmesh': bs.getmesh('thePadBG'), + 'railing_collision_mesh': bs.getcollisionmesh('thePadLevelBumper'), + 'vr_fill_mound_mesh': bs.getmesh('thePadVRFillMound'), + 'vr_fill_mound_tex': bs.gettexture('vrFillMound') + } + # fixme should chop this into vr/non-vr sections for efficiency + return data + + def __init__(self) -> None: + super().__init__() + shared = SharedObjects.get() + self.node = bs.newnode( + 'terrain', + delegate=self, + attrs={ + 'collision_mesh': self.preloaddata['collision_mesh'], + 'mesh': self.preloaddata['mesh'], + 'color_texture': self.preloaddata['tex'], + 'materials': [shared.footing_material] + }) + self.bottom = bs.newnode('terrain', + attrs={ + 'mesh': self.preloaddata['bottom_mesh'], + 'lighting': False, + 'color_texture': self.preloaddata['tex'] + }) + self.background = bs.newnode( + 'terrain', + attrs={ + 'mesh': self.preloaddata['bgmesh'], + 'lighting': False, + 'background': True, + 'color_texture': self.preloaddata['bgtex'] + }) + self.railing = bs.newnode( + 'terrain', + attrs={ + 'collision_mesh': self.preloaddata['railing_collision_mesh'], + 'materials': [shared.railing_material], + 'bumper': True + }) + bs.newnode('terrain', + attrs={ + 'mesh': self.preloaddata['vr_fill_mound_mesh'], + 'lighting': False, + 'vr_only': True, + 'color': (0.56, 0.55, 0.47), + 'background': True, + 'color_texture': self.preloaddata['vr_fill_mound_tex'] + }) + gnode = bs.getactivity().globalsnode + gnode.tint = (1.1, 1.1, 1.0) + gnode.ambient_color = (1.1, 1.1, 1.0) + gnode.vignette_outer = (0.7, 0.65, 0.75) + gnode.vignette_inner = (0.95, 0.95, 0.93) + + +# ba_meta export plugin +class NewMap(babase.Plugin): + """My first ballistica plugin!""" + + def on_app_running(self) -> None: + _map.register_map(ThePadMapb) + + +class NewBlast(Blast): + + def __init__(self, + position: Sequence[float] = (0.0, 1.0, 0.0), + velocity: Sequence[float] = (0.0, 0.0, 0.0), + blast_radius: float = 2.0, + blast_type: str = 'normal', + source_player: bs.Player = None, + hit_type: str = 'explosion', + hit_subtype: str = 'normal'): + bs.Actor.__init__(self) + + shared = SharedObjects.get() + factory = BombFactory.get() + + self.blast_type = blast_type + self._source_player = source_player + self.hit_type = hit_type + self.hit_subtype = hit_subtype + self.radius = blast_radius + + # Set our position a bit lower so we throw more things upward. + rmats = (factory.blast_material, shared.attack_material) + self.node = bs.newnode( + 'region', + delegate=self, + attrs={ + 'position': (position[0], position[1] - 0.1, position[2]), + 'scale': (self.radius, self.radius, self.radius), + 'type': 'sphere', + 'materials': rmats + }, + ) + + bs.timer(0.05, self.node.delete) + + # Throw in an explosion and flash. + evel = (velocity[0], max(-1.0, velocity[1]), velocity[2]) + explosion = bs.newnode('explosion', + attrs={ + 'position': position, + 'velocity': evel, + 'radius': self.radius, + 'big': (self.blast_type == 'tnt') + }) + if self.blast_type == 'ice': + explosion.color = (0, 0.05, 0.4) + + bs.timer(1.0, explosion.delete) + + if self.blast_type != 'ice': + bs.emitfx(position=position, + velocity=velocity, + count=int(1.0 + random.random() * 4), + emit_type='tendrils', + tendril_type='thin_smoke') + bs.emitfx(position=position, + velocity=velocity, + count=int(4.0 + random.random() * 4), + emit_type='tendrils', + tendril_type='ice' if self.blast_type == 'ice' else 'smoke') + bs.emitfx(position=position, + emit_type='distortion', + spread=1.0 if self.blast_type == 'tnt' else 2.0) + + # And emit some shrapnel. + if self.blast_type == 'ice': + + def emit() -> None: + bs.emitfx(position=position, + velocity=velocity, + count=30, + spread=2.0, + scale=0.4, + chunk_type='ice', + emit_type='stickers') + + # It looks better if we delay a bit. + bs.timer(0.05, emit) + + elif self.blast_type == 'sticky': + + def emit() -> None: + bs.emitfx(position=position, + velocity=velocity, + count=int(4.0 + random.random() * 8), + spread=0.7, + chunk_type='slime') + bs.emitfx(position=position, + velocity=velocity, + count=int(4.0 + random.random() * 8), + scale=0.5, + spread=0.7, + chunk_type='slime') + bs.emitfx(position=position, + velocity=velocity, + count=15, + scale=0.6, + chunk_type='slime', + emit_type='stickers') + bs.emitfx(position=position, + velocity=velocity, + count=20, + scale=0.7, + chunk_type='spark', + emit_type='stickers') + bs.emitfx(position=position, + velocity=velocity, + count=int(6.0 + random.random() * 12), + scale=0.8, + spread=1.5, + chunk_type='spark') + + # It looks better if we delay a bit. + bs.timer(0.05, emit) + + elif self.blast_type == 'impact': + + def emit() -> None: + bs.emitfx(position=position, + velocity=velocity, + count=int(4.0 + random.random() * 8), + scale=0.8, + chunk_type='metal') + bs.emitfx(position=position, + velocity=velocity, + count=int(4.0 + random.random() * 8), + scale=0.4, + chunk_type='metal') + bs.emitfx(position=position, + velocity=velocity, + count=20, + scale=0.7, + chunk_type='spark', + emit_type='stickers') + bs.emitfx(position=position, + velocity=velocity, + count=int(8.0 + random.random() * 15), + scale=0.8, + spread=1.5, + chunk_type='spark') + + # It looks better if we delay a bit. + bs.timer(0.05, emit) + + else: # Regular or land mine bomb shrapnel. + + def emit() -> None: + if self.blast_type != 'tnt': + bs.emitfx(position=position, + velocity=velocity, + count=int(4.0 + random.random() * 8), + chunk_type='rock') + bs.emitfx(position=position, + velocity=velocity, + count=int(4.0 + random.random() * 8), + scale=0.5, + chunk_type='rock') + bs.emitfx(position=position, + velocity=velocity, + count=30, + scale=1.0 if self.blast_type == 'tnt' else 0.7, + chunk_type='spark', + emit_type='stickers') + bs.emitfx(position=position, + velocity=velocity, + count=int(18.0 + random.random() * 20), + scale=1.0 if self.blast_type == 'tnt' else 0.8, + spread=1.5, + chunk_type='spark') + + # TNT throws splintery chunks. + if self.blast_type == 'tnt': + + def emit_splinters() -> None: + bs.emitfx(position=position, + velocity=velocity, + count=int(20.0 + random.random() * 25), + scale=0.8, + spread=1.0, + chunk_type='splinter') + + bs.timer(0.01, emit_splinters) + + # Every now and then do a sparky one. + if self.blast_type == 'tnt' or random.random() < 0.1: + + def emit_extra_sparks() -> None: + bs.emitfx(position=position, + velocity=velocity, + count=int(10.0 + random.random() * 20), + scale=0.8, + spread=1.5, + chunk_type='spark') + + bs.timer(0.02, emit_extra_sparks) + + # It looks better if we delay a bit. + bs.timer(0.05, emit) + + lcolor = ((0.6, 0.6, 1.0) if self.blast_type == 'ice' else + (1, 0.3, 0.1)) + light = bs.newnode('light', + attrs={ + 'position': position, + 'volume_intensity_scale': 10.0, + 'color': lcolor + }) + + scl = random.uniform(0.6, 0.9) + scorch_radius = light_radius = self.radius + if self.blast_type == 'tnt': + light_radius *= 1.4 + scorch_radius *= 1.15 + scl *= 3.0 + + iscale = 1.6 + bs.animate( + light, 'intensity', { + 0: 2.0 * iscale, + scl * 0.02: 0.1 * iscale, + scl * 0.025: 0.2 * iscale, + scl * 0.05: 17.0 * iscale, + scl * 0.06: 5.0 * iscale, + scl * 0.08: 4.0 * iscale, + scl * 0.2: 0.6 * iscale, + scl * 2.0: 0.00 * iscale, + scl * 3.0: 0.0 + }) + bs.animate( + light, 'radius', { + 0: light_radius * 0.2, + scl * 0.05: light_radius * 0.55, + scl * 0.1: light_radius * 0.3, + scl * 0.3: light_radius * 0.15, + scl * 1.0: light_radius * 0.05 + }) + bs.timer(scl * 3.0, light.delete) + + # Make a scorch that fades over time. + scorch = bs.newnode('scorch', + attrs={ + 'position': position, + 'size': scorch_radius * 0.5, + 'big': (self.blast_type == 'tnt') + }) + if self.blast_type == 'ice': + scorch.color = (1, 1, 1.5) + + bs.animate(scorch, 'presence', {3.000: 1, 13.000: 0}) + bs.timer(13.0, scorch.delete) + + if self.blast_type == 'ice': + factory.hiss_sound.play(position=light.position) + + lpos = light.position + factory.random_explode_sound().play(position=lpos) + factory.debris_fall_sound.play(position=lpos) + + bs.camerashake(0.0) + + # TNT is more epic. + if self.blast_type == 'tnt': + factory.random_explode_sound().play(position=lpos) + + def _extra_boom() -> None: + factory.random_explode_sound().play(position=lpos) + + bs.timer(0.25, _extra_boom) + + def _extra_debris_sound() -> None: + factory.debris_fall_sound.play(position=lpos) + factory.wood_debris_fall_sound.play(position=lpos) + + bs.timer(0.4, _extra_debris_sound) + + +class NewBomb(Bomb): + + def explode(self) -> None: + """Blows up the bomb if it has not yet done so.""" + if self._exploded: + return + self._exploded = True + if self.node: + blast = NewBlast(position=self.node.position, + velocity=self.node.velocity, + blast_radius=self.blast_radius, + blast_type=self.bomb_type, + source_player=babase.existing(self._source_player), + hit_type=self.hit_type, + hit_subtype=self.hit_subtype).autoretain() + for callback in self._explode_callbacks: + callback(self, blast) + + # We blew up so we need to go away. + # NOTE TO SELF: do we actually need this delay? + bs.timer(0.001, bs.WeakCall(self.handlemessage, bs.DieMessage())) + + +class TNT(bs.Actor): + + def __init__(self, + position: Sequence[float] = (0.0, 1.0, 0.0), + velocity: Sequence[float] = (0.0, 0.0, 0.0), + tnt_scale: float = 1.0, + teleport: bool = True): + super().__init__() + self.position = position + self.teleport = teleport + + self._no_collide_material = bs.Material() + self._no_collide_material.add_actions( + actions=('modify_part_collision', 'collide', False), + ) + self._collide_material = bs.Material() + self._collide_material.add_actions( + actions=('modify_part_collision', 'collide', True), + ) + + if teleport: + collide = self._collide_material + else: + collide = self._no_collide_material + self.node = bs.newnode( + 'prop', + delegate=self, + attrs={ + 'position': position, + 'velocity': velocity, + 'mesh': bs.getmesh('tnt'), + 'color_texture': bs.gettexture('tnt'), + 'body': 'crate', + 'mesh_scale': tnt_scale, + 'body_scale': tnt_scale, + 'density': 2.0, + 'gravity_scale': 2.0, + 'materials': [collide] + } + ) + if not teleport: + bs.timer(0.1, self._collide) + + def _collide(self) -> None: + self.node.materials += (self._collide_material,) + + def handlemessage(self, msg: Any) -> Any: + if isinstance(msg, bs.OutOfBoundsMessage): + if self.teleport: + self.node.position = self.position + self.node.velocity = (0, 0, 0) + else: + self.node.delete() + else: + super().handlemessage(msg) + + +class RaceRegion(bs.Actor): + """Region used to track progress during a race.""" + + def __init__(self, pt: Sequence[float], index: int): + super().__init__() + activity = self.activity + assert isinstance(activity, RaceGame) + self.pos = pt + self.index = index + self.node = bs.newnode( + 'region', + delegate=self, + attrs={ + 'position': pt[:3], + 'scale': (pt[3] * 2.0, pt[4] * 2.0, pt[5] * 2.0), + 'type': 'box', + 'materials': [activity.race_region_material] + }) + + +# MINIGAME +class Player(bs.Player['Team']): + """Our player type for this game.""" + + def __init__(self) -> None: + self.distance_txt: Optional[bs.Node] = None + self.last_region = 0 + self.lap = 0 + self.distance = 0.0 + self.finished = False + self.rank: Optional[int] = None + + +class Team(bs.Team[Player]): + """Our team type for this game.""" + + def __init__(self) -> None: + self.time: Optional[float] = None + self.lap = 0 + self.finished = False + + +# ba_meta export bascenev1.GameActivity +class RaceGame(bs.TeamGameActivity[Player, Team]): + """Game of racing around a track.""" + + name = 'Hyper Race' + description = 'Creado Por Cebolla!!' + scoreconfig = bs.ScoreConfig(label='Time', + lower_is_better=True, + scoretype=bs.ScoreType.MILLISECONDS) + + @classmethod + def get_available_settings( + cls, sessiontype: Type[bs.Session]) -> List[babase.Setting]: + settings = [ + bs.IntSetting('Laps', min_value=1, default=3, increment=1), + bs.IntChoiceSetting( + 'Time Limit', + default=0, + choices=[ + ('None', 0), + ('1 Minute', 60), + ('2 Minutes', 120), + ('5 Minutes', 300), + ('10 Minutes', 600), + ('20 Minutes', 1200), + ], + ), + bs.BoolSetting('Epic Mode', default=False), + ] + + # We have some specific settings in teams mode. + if issubclass(sessiontype, bs.DualTeamSession): + settings.append( + bs.BoolSetting('Entire Team Must Finish', default=False)) + return settings + + @classmethod + def supports_session_type(cls, sessiontype: Type[bs.Session]) -> bool: + return issubclass(sessiontype, bs.MultiTeamSession) + + @classmethod + def get_supported_maps(cls, sessiontype: Type[bs.Session]) -> List[str]: + return bs.app.classic.getmaps('hyper') + + def __init__(self, settings: dict): + self._race_started = False + super().__init__(settings) + self.factory = factory = BombFactory.get() + self.shared = shared = SharedObjects.get() + self._scoreboard = Scoreboard() + self._score_sound = bs.getsound('score') + self._swipsound = bs.getsound('swip') + self._last_team_time: Optional[float] = None + self._front_race_region: Optional[int] = None + self._nub_tex = bs.gettexture('nub') + self._beep_1_sound = bs.getsound('raceBeep1') + self._beep_2_sound = bs.getsound('raceBeep2') + self.race_region_material: Optional[bs.Material] = None + self._regions: List[RaceRegion] = [] + self._team_finish_pts: Optional[int] = None + self._time_text: Optional[bs.Actor] = None + self._timer: Optional[OnScreenTimer] = None + self._scoreboard_timer: Optional[bs.Timer] = None + self._player_order_update_timer: Optional[bs.Timer] = None + self._start_lights: Optional[List[bs.Node]] = None + self._laps = int(settings['Laps']) + self._entire_team_must_finish = bool( + settings.get('Entire Team Must Finish', False)) + self._time_limit = float(settings['Time Limit']) + self._epic_mode = bool(settings['Epic Mode']) + + # Base class overrides. + self.slow_motion = self._epic_mode + self.default_music = (bs.MusicType.EPIC_RACE + if self._epic_mode else bs.MusicType.RACE) + + self._safe_region_material = bs.Material() + self._safe_region_material.add_actions( + conditions=('they_have_material', shared.player_material), + actions=(('modify_part_collision', 'collide', True), + ('modify_part_collision', 'physical', True)) + ) + + def get_instance_description(self) -> Union[str, Sequence]: + if (isinstance(self.session, bs.DualTeamSession) + and self._entire_team_must_finish): + t_str = ' Your entire team has to finish.' + else: + t_str = '' + + if self._laps > 1: + return 'Run ${ARG1} laps.' + t_str, self._laps + return 'Run 1 lap.' + t_str + + def get_instance_description_short(self) -> Union[str, Sequence]: + if self._laps > 1: + return 'run ${ARG1} laps', self._laps + return 'run 1 lap' + + def on_transition_in(self) -> None: + super().on_transition_in() + shared = SharedObjects.get() + pts = self.map.get_def_points('race_point') + mat = self.race_region_material = bs.Material() + mat.add_actions(conditions=('they_have_material', + shared.player_material), + actions=( + ('modify_part_collision', 'collide', True), + ('modify_part_collision', 'physical', False), + ('call', 'at_connect', + self._handle_race_point_collide), + )) + for rpt in pts: + self._regions.append(RaceRegion(rpt, len(self._regions))) + + bs.newnode( + 'region', + attrs={ + 'position': (0.3, 4.044276501, -2.9), + 'scale': (11.7, 15, 9.5), + 'type': 'box', + 'materials': [self._safe_region_material] + } + ) + + def _flash_player(self, player: Player, scale: float) -> None: + assert isinstance(player.actor, PlayerSpaz) + assert player.actor.node + pos = player.actor.node.position + light = bs.newnode('light', + attrs={ + 'position': pos, + 'color': (1, 1, 0), + 'height_attenuated': False, + 'radius': 0.4 + }) + bs.timer(0.5, light.delete) + bs.animate(light, 'intensity', {0: 0, 0.1: 1.0 * scale, 0.5: 0}) + + def _handle_race_point_collide(self) -> None: + # FIXME: Tidy this up. + # pylint: disable=too-many-statements + # pylint: disable=too-many-branches + # pylint: disable=too-many-nested-blocks + collision = bs.getcollision() + try: + region = collision.sourcenode.getdelegate(RaceRegion, True) + spaz = collision.opposingnode.getdelegate(PlayerSpaz,True) + except bs.NotFoundError: + return + + if not spaz.is_alive(): + return + + try: + player = spaz.getplayer(Player, True) + except bs.NotFoundError: + return + + last_region = player.last_region + this_region = region.index + + if last_region != this_region: + + # If a player tries to skip regions, smite them. + # Allow a one region leeway though (its plausible players can get + # blown over a region, etc). + if this_region > last_region + 2: + if player.is_alive(): + assert player.actor + player.actor.handlemessage(bs.DieMessage()) + bs.broadcastmessage(babase.Lstr( + translate=('statements', 'Killing ${NAME} for' + ' skipping part of the track!'), + subs=[('${NAME}', player.getname(full=True))]), + color=(1, 0, 0)) + else: + # If this player is in first, note that this is the + # front-most race-point. + if player.rank == 0: + self._front_race_region = this_region + + player.last_region = this_region + if last_region >= len(self._regions) - 2 and this_region == 0: + team = player.team + player.lap = min(self._laps, player.lap + 1) + + # In teams mode with all-must-finish on, the team lap + # value is the min of all team players. + # Otherwise its the max. + if isinstance(self.session, bs.DualTeamSession + ) and self._entire_team_must_finish: + team.lap = min([p.lap for p in team.players]) + else: + team.lap = max([p.lap for p in team.players]) + + # A player is finishing. + if player.lap == self._laps: + + # In teams mode, hand out points based on the order + # players come in. + if isinstance(self.session, bs.DualTeamSession): + assert self._team_finish_pts is not None + if self._team_finish_pts > 0: + self.stats.player_scored(player, + self._team_finish_pts, + screenmessage=False) + self._team_finish_pts -= 25 + + # Flash where the player is. + self._flash_player(player, 1.0) + player.finished = True + assert player.actor + player.actor.handlemessage( + bs.DieMessage(immediate=True)) + + # Makes sure noone behind them passes them in rank + # while finishing. + player.distance = 9999.0 + + # If the whole team has finished the race. + if team.lap == self._laps: + self._score_sound.play() + player.team.finished = True + assert self._timer is not None + elapsed = bs.time() - self._timer.getstarttime() + self._last_team_time = player.team.time = elapsed + self._check_end_game() + + # Team has yet to finish. + else: + self._swipsound.play() + + # They've just finished a lap but not the race. + else: + self._swipsound.play() + self._flash_player(player, 0.3) + + # Print their lap number over their head. + try: + assert isinstance(player.actor, PlayerSpaz) + mathnode = bs.newnode('math', + owner=player.actor.node, + attrs={ + 'input1': (0, 1.9, 0), + 'operation': 'add' + }) + player.actor.node.connectattr( + 'torso_position', mathnode, 'input2') + tstr = babase.Lstr(resource='lapNumberText', + subs=[('${CURRENT}', + str(player.lap + 1)), + ('${TOTAL}', str(self._laps)) + ]) + txtnode = bs.newnode('text', + owner=mathnode, + attrs={ + 'text': tstr, + 'in_world': True, + 'color': (1, 1, 0, 1), + 'scale': 0.015, + 'h_align': 'center' + }) + mathnode.connectattr('output', txtnode, 'position') + bs.animate(txtnode, 'scale', { + 0.0: 0, + 0.2: 0.019, + 2.0: 0.019, + 2.2: 0 + }) + bs.timer(2.3, mathnode.delete) + except Exception: + babase.print_exception('Error printing lap.') + + def on_team_join(self, team: Team) -> None: + self._update_scoreboard() + + def on_player_leave(self, player: Player) -> None: + super().on_player_leave(player) + + # A player leaving disqualifies the team if 'Entire Team Must Finish' + # is on (otherwise in teams mode everyone could just leave except the + # leading player to win). + if (isinstance(self.session, bs.DualTeamSession) + and self._entire_team_must_finish): + bs.broadcastmessage(babase.Lstr( + translate=('statements', + '${TEAM} is disqualified because ${PLAYER} left'), + subs=[('${TEAM}', player.team.name), + ('${PLAYER}', player.getname(full=True))]), + color=(1, 1, 0)) + player.team.finished = True + player.team.time = None + player.team.lap = 0 + bs.getsound('boo').play() + for otherplayer in player.team.players: + otherplayer.lap = 0 + otherplayer.finished = True + try: + if otherplayer.actor is not None: + otherplayer.actor.handlemessage(bs.DieMessage()) + except Exception: + babase.print_exception('Error sending DieMessage.') + + # Defer so team/player lists will be updated. + babase.pushcall(self._check_end_game) + + def _update_scoreboard(self) -> None: + for team in self.teams: + distances = [player.distance for player in team.players] + if not distances: + teams_dist = 0.0 + else: + if (isinstance(self.session, bs.DualTeamSession) + and self._entire_team_must_finish): + teams_dist = min(distances) + else: + teams_dist = max(distances) + self._scoreboard.set_team_value( + team, + teams_dist, + self._laps, + flash=(teams_dist >= float(self._laps)), + show_value=False) + + def on_begin(self) -> None: + from bascenev1lib.actor.onscreentimer import OnScreenTimer + super().on_begin() + self.setup_standard_time_limit(self._time_limit) + # self.setup_standard_powerup_drops() + self._team_finish_pts = 100 + + # Throw a timer up on-screen. + self._time_text = bs.NodeActor( + bs.newnode('text', + attrs={ + 'v_attach': 'top', + 'h_attach': 'center', + 'h_align': 'center', + 'color': (1, 1, 0.5, 1), + 'flatness': 0.5, + 'shadow': 0.5, + 'position': (0, -50), + 'scale': 1.4, + 'text': '' + })) + self._timer = OnScreenTimer() + + self._scoreboard_timer = bs.Timer(0.25, + self._update_scoreboard, + repeat=True) + self._player_order_update_timer = bs.Timer(0.25, + self._update_player_order, + repeat=True) + + if self.slow_motion: + t_scale = 0.4 + light_y = 50 + else: + t_scale = 1.0 + light_y = 150 + lstart = 7.1 * t_scale + inc = 1.25 * t_scale + + bs.timer(lstart, self._do_light_1) + bs.timer(lstart + inc, self._do_light_2) + bs.timer(lstart + 2 * inc, self._do_light_3) + bs.timer(lstart + 3 * inc, self._start_race) + + self._start_lights = [] + for i in range(4): + lnub = bs.newnode('image', + attrs={ + 'texture': bs.gettexture('nub'), + 'opacity': 1.0, + 'absolute_scale': True, + 'position': (-75 + i * 50, light_y), + 'scale': (50, 50), + 'attach': 'center' + }) + bs.animate( + lnub, 'opacity', { + 4.0 * t_scale: 0, + 5.0 * t_scale: 1.0, + 12.0 * t_scale: 1.0, + 12.5 * t_scale: 0.0 + }) + bs.timer(13.0 * t_scale, lnub.delete) + self._start_lights.append(lnub) + + self._obstacles() + + pts = self.map.get_def_points('race_point') + for rpt in pts: + bs.newnode( + 'locator', + attrs={ + 'shape': 'circle', + 'position': (rpt[0], 4.382076338, rpt[2]), + 'size': (rpt[3] * 2.0, 0, rpt[5] * 2.0), + 'color': (0, 1, 0), + 'opacity': 1.0, + 'draw_beauty': False, + 'additive': True + } + ) + + def _obstacles(self) -> None: + self._start_lights[0].color = (0.2, 0, 0) + self._start_lights[1].color = (0.2, 0, 0) + self._start_lights[2].color = (0.2, 0.05, 0) + self._start_lights[3].color = (0.0, 0.3, 0) + + self._tnt((1.5, 5, 2.3), (0, 0, 0), 1.0) + self._tnt((1.5, 5, 3.3), (0, 0, 0), 1.0) + + self._tnt((3.5, 5, 2.3), (0, 0, 0), 1.0) + self._tnt((3.5, 5, 3.3), (0, 0, 0), 1.0) + + self._tnt((5.5, 5, 2.3), (0, 0, 0), 1.0) + self._tnt((5.5, 5, 3.3), (0, 0, 0), 1.0) + + self._tnt((-6, 5, -7), (0, 0, 0), 1.3) + self._tnt((-7, 5, -5), (0, 0, 0), 1.3) + self._tnt((-6, 5, -3), (0, 0, 0), 1.3) + self._tnt((-7, 5, -1), (0, 0, 0), 1.3) + self._tnt((-6, 5, 1), (0, 0, 0), 1.3) + + bs.timer(0.1, bs.WeakCall(self._tnt, (-3.2, 5, 1), + (0, 0, 0), 1.0, (0, 20, 60)), repeat=True) + + bs.timer(1.6, bs.WeakCall(self._bomb, 'impact', + (6, 7, 1), (0, 0, 0), 1.0, 1.0), repeat=True) + bs.timer(1.6, bs.WeakCall(self._bomb, 'impact', + (6.8, 7, 1), (0, 0, 0), 1.0, 1.0), repeat=True) + bs.timer(1.6, bs.WeakCall(self._bomb, 'impact', + (7.6, 7, 1), (0, 0, 0), 1.0, 1.0), repeat=True) + + bs.timer(1.6, bs.WeakCall(self._bomb, 'impact', + (6, 7, -2.2), (0, 0, 0), 1.0, 1.0), repeat=True) + bs.timer(1.6, bs.WeakCall(self._bomb, 'impact', + (6.8, 7, -2.2), (0, 0, 0), 1.0, 1.0), repeat=True) + bs.timer(1.6, bs.WeakCall(self._bomb, 'impact', + (7.6, 7, -2.2), (0, 0, 0), 1.0, 1.0), repeat=True) + + bs.timer(1.6, bs.WeakCall(self._bomb, 'impact', + (6, 7, -5.2), (0, 0, 0), 1.0, 1.0), repeat=True) + bs.timer(1.6, bs.WeakCall(self._bomb, 'impact', + (6.8, 7, -5.2), (0, 0, 0), 1.0, 1.0), repeat=True) + bs.timer(1.6, bs.WeakCall(self._bomb, 'impact', + (7.6, 7, -5.2), (0, 0, 0), 1.0, 1.0), repeat=True) + + bs.timer(1.6, bs.WeakCall(self._bomb, 'impact', + (6, 7, -8), (0, 0, 0), 1.0, 1.0), repeat=True) + bs.timer(1.6, bs.WeakCall(self._bomb, 'impact', + (6.8, 7, -8), (0, 0, 0), 1.0, 1.0), repeat=True) + bs.timer(1.6, bs.WeakCall(self._bomb, 'impact', + (7.6, 7, -8), (0, 0, 0), 1.0, 1.0), repeat=True) + + bs.timer(1.6, bs.WeakCall(self._bomb, 'impact', + (-5, 5, 0), (0, 0, 0), 1.0, 1.0, (0, 20, 3)), repeat=True) + bs.timer(1.6, bs.WeakCall(self._bomb, 'impact', + (-1.5, 5, 0), (0, 0, 0), 1.0, 1.0, (0, 20, 3)), repeat=True) + + + bs.timer(1.6, bs.WeakCall(self._bomb, 'sticky', + (-1, 5, -8), (0, 10, 0), 1.0, 1.0), repeat=True) + bs.timer(1.6, bs.WeakCall(self._bomb, 'sticky', + (-1, 5, -9), (0, 10, 0), 1.0, 1.0), repeat=True) + bs.timer(1.6, bs.WeakCall(self._bomb, 'sticky', + (-1, 5, -10), (0, 10, 0), 1.0, 1.0), repeat=True) + + bs.timer(1.6, bs.WeakCall(self._bomb, 'sticky', + (-4.6, 5, -8), (0, 10, 0), 1.0, 1.0), repeat=True) + bs.timer(1.6, bs.WeakCall(self._bomb, 'sticky', + (-4.6, 5, -9), (0, 10, 0), 1.0, 1.0), repeat=True) + bs.timer(1.6, bs.WeakCall(self._bomb, 'sticky', + (-4.6, 5, -10), (0, 10, 0), 1.0, 1.0), repeat=True) + + bs.timer(1.6, bs.WeakCall( + self._powerup, (2, 5, -5), 'curse', (0, 20, -3)), repeat=True) + bs.timer(1.6, bs.WeakCall( + self._powerup, (4, 5, -5), 'curse', (0, 20, -3)), repeat=True) + + def _tnt(self, + position: float, + velocity: float, + tnt_scale: float, + extra_acceleration: float = None) -> None: + if extra_acceleration: + TNT(position, velocity, tnt_scale, False).autoretain( + ).node.extra_acceleration = extra_acceleration + else: + TNT(position, velocity, tnt_scale).autoretain() + + def _bomb(self, + type: str, + position: float, + velocity: float, + mesh_scale: float, + body_scale: float, + extra_acceleration: float = None) -> None: + if extra_acceleration: + NewBomb(position=position, + velocity=velocity, + bomb_type=type).autoretain( + ).node.extra_acceleration = extra_acceleration + else: + NewBomb(position=position, + velocity=velocity, + bomb_type=type).autoretain() + + def _powerup(self, + position: float, + poweruptype: str, + extra_acceleration: float = None) -> None: + if extra_acceleration: + PowerupBox(position=position, + poweruptype=poweruptype).autoretain( + ).node.extra_acceleration = extra_acceleration + else: + PowerupBox(position=position, poweruptype=poweruptype).autoretain() + + def _do_light_1(self) -> None: + assert self._start_lights is not None + self._start_lights[0].color = (1.0, 0, 0) + self._beep_1_sound.play() + + def _do_light_2(self) -> None: + assert self._start_lights is not None + self._start_lights[1].color = (1.0, 0, 0) + self._beep_1_sound.play() + + def _do_light_3(self) -> None: + assert self._start_lights is not None + self._start_lights[2].color = (1.0, 0.3, 0) + self._beep_1_sound.play() + + def _start_race(self) -> None: + assert self._start_lights is not None + self._start_lights[3].color = (0.0, 1.0, 0) + self._beep_2_sound.play() + for player in self.players: + if player.actor is not None: + try: + assert isinstance(player.actor, PlayerSpaz) + player.actor.connect_controls_to_player() + except Exception: + babase.print_exception('Error in race player connects.') + assert self._timer is not None + self._timer.start() + + self._race_started = True + + def _update_player_order(self) -> None: + + # Calc all player distances. + for player in self.players: + pos: Optional[babase.Vec3] + try: + pos = player.position + except bs.NotFoundError: + pos = None + if pos is not None: + r_index = player.last_region + rg1 = self._regions[r_index] + r1pt = babase.Vec3(rg1.pos[:3]) + rg2 = self._regions[0] if r_index == len( + self._regions) - 1 else self._regions[r_index + 1] + r2pt = babase.Vec3(rg2.pos[:3]) + r2dist = (pos - r2pt).length() + amt = 1.0 - (r2dist / (r2pt - r1pt).length()) + amt = player.lap + (r_index + amt) * (1.0 / len(self._regions)) + player.distance = amt + + # Sort players by distance and update their ranks. + p_list = [(player.distance, player) for player in self.players] + + p_list.sort(reverse=True, key=lambda x: x[0]) + for i, plr in enumerate(p_list): + plr[1].rank = i + if plr[1].actor: + node = plr[1].distance_txt + if node: + node.text = str(i + 1) if plr[1].is_alive() else '' + + def spawn_player(self, player: Player) -> bs.Actor: + if player.team.finished: + # FIXME: This is not type-safe! + # This call is expected to always return an Actor! + # Perhaps we need something like can_spawn_player()... + # noinspection PyTypeChecker + return None # type: ignore + pos = self._regions[player.last_region].pos + + # Don't use the full region so we're less likely to spawn off a cliff. + region_scale = 0.8 + x_range = ((-0.5, 0.5) if pos[3] == 0 else + (-region_scale * pos[3], region_scale * pos[3])) + z_range = ((-0.5, 0.5) if pos[5] == 0 else + (-region_scale * pos[5], region_scale * pos[5])) + pos = (pos[0] + random.uniform(*x_range), pos[1], + pos[2] + random.uniform(*z_range)) + spaz = self.spawn_player_spaz( + player, position=pos, angle=90 if not self._race_started else None) + assert spaz.node + + # Prevent controlling of characters before the start of the race. + if not self._race_started: + spaz.disconnect_controls_from_player() + + mathnode = bs.newnode('math', + owner=spaz.node, + attrs={ + 'input1': (0, 1.4, 0), + 'operation': 'add' + }) + spaz.node.connectattr('torso_position', mathnode, 'input2') + + distance_txt = bs.newnode('text', + owner=spaz.node, + attrs={ + 'text': '', + 'in_world': True, + 'color': (1, 1, 0.4), + 'scale': 0.02, + 'h_align': 'center' + }) + player.distance_txt = distance_txt + mathnode.connectattr('output', distance_txt, 'position') + return spaz + + def _check_end_game(self) -> None: + + # If there's no teams left racing, finish. + teams_still_in = len([t for t in self.teams if not t.finished]) + if teams_still_in == 0: + self.end_game() + return + + # Count the number of teams that have completed the race. + teams_completed = len( + [t for t in self.teams if t.finished and t.time is not None]) + + if teams_completed > 0: + session = self.session + + # In teams mode its over as soon as any team finishes the race + + # FIXME: The get_ffa_point_awards code looks dangerous. + if isinstance(session, bs.DualTeamSession): + self.end_game() + else: + # In ffa we keep the race going while there's still any points + # to be handed out. Find out how many points we have to award + # and how many teams have finished, and once that matches + # we're done. + assert isinstance(session, bs.FreeForAllSession) + points_to_award = len(session.get_ffa_point_awards()) + if teams_completed >= points_to_award - teams_completed: + self.end_game() + return + + def end_game(self) -> None: + + # Stop updating our time text, and set it to show the exact last + # finish time if we have one. (so users don't get upset if their + # final time differs from what they see onscreen by a tiny amount) + assert self._timer is not None + if self._timer.has_started(): + self._timer.stop( + endtime=None if self._last_team_time is None else ( + self._timer.getstarttime() + self._last_team_time)) + + results = bs.GameResults() + + for team in self.teams: + if team.time is not None: + # We store time in seconds, but pass a score in milliseconds. + results.set_team_score(team, int(team.time * 1000.0)) + else: + results.set_team_score(team, None) + + # We don't announce a winner in ffa mode since its probably been a + # while since the first place guy crossed the finish line so it seems + # odd to be announcing that now. + self.end(results=results, + announce_winning_team=isinstance(self.session, + bs.DualTeamSession)) + + def handlemessage(self, msg: Any) -> Any: + if isinstance(msg, bs.PlayerDiedMessage): + # Augment default behavior. + super().handlemessage(msg) + player = msg.getplayer(Player) + if not player.finished: + self.respawn_player(player, respawn_time=1) + else: + super().handlemessage(msg) diff --git a/plugins/minigames/SnowBallFight.py b/plugins/minigames/SnowBallFight.py new file mode 100644 index 00000000..29afe38e --- /dev/null +++ b/plugins/minigames/SnowBallFight.py @@ -0,0 +1,643 @@ +# Porting to api 8 made easier by baport.(https://github.com/bombsquad-community/baport) +# ba_meta require api 8 +# (see https://ballistica.net/wiki/meta-tag-system) + +from __future__ import annotations + +from typing import TYPE_CHECKING + +import babase +import bauiv1 as bui +import bascenev1 as bs +import random +from bascenev1lib.actor.bomb import Blast +from bascenev1lib.gameutils import SharedObjects +from bascenev1lib.actor.spaz import PunchHitMessage +from bascenev1lib.actor.playerspaz import PlayerSpaz +from bascenev1lib.actor.scoreboard import Scoreboard +from bascenev1lib.actor.spazfactory import SpazFactory + +if TYPE_CHECKING: + from typing import Any, Sequence + + +lang = bs.app.lang.language + +if lang == 'Spanish': + name = 'Guerra de Nieve' + snowball_rate = 'Intervalo de Ataque' + snowball_slowest = 'Más Lento' + snowball_slow = 'Lento' + snowball_fast = 'Rápido' + snowball_lagcity = 'Más Rápido' + snowball_scale = 'Tamaño de Bola de Nieve' + snowball_smallest = 'Más Pequeño' + snowball_small = 'Pequeño' + snowball_big = 'Grande' + snowball_biggest = 'Más Grande' + snowball_insane = 'Insano' + snowball_melt = 'Derretir Bola de Nieve' + snowball_bust = 'Rebotar Bola de Nieve' + snowball_explode = 'Explotar al Impactar' + snowball_snow = 'Modo Nieve' +else: + name = 'Snowball Fight' + snowball_rate = 'Snowball Rate' + snowball_slowest = 'Slowest' + snowball_slow = 'Slow' + snowball_fast = 'Fast' + snowball_lagcity = 'Lag City' + snowball_scale = 'Snowball Scale' + snowball_smallest = 'Smallest' + snowball_small = 'Small' + snowball_big = 'Big' + snowball_biggest = 'Biggest' + snowball_insane = 'Insane' + snowball_melt = 'Snowballs Melt' + snowball_bust = 'Snowballs Bust' + snowball_explode = 'Snowballs Explode' + snowball_snow = 'Snow Mode' + + +class Snowball(bs.Actor): + + def __init__(self, + position: Sequence[float] = (0.0, 1.0, 0.0), + velocity: Sequence[float] = (0.0, 0.0, 0.0), + blast_radius: float = 0.7, + bomb_scale: float = 0.8, + source_player: bs.Player | None = None, + owner: bs.Node | None = None, + melt: bool = True, + bounce: bool = True, + explode: bool = False): + super().__init__() + shared = SharedObjects.get() + self._exploded = False + self.scale = bomb_scale + self.blast_radius = blast_radius + self._source_player = source_player + self.owner = owner + self._hit_nodes = set() + self.snowball_melt = melt + self.snowball_bounce = bounce + self.snowball_explode = explode + self.radius = bomb_scale * 0.1 + if bomb_scale <= 1.0: + shadow_size = 0.6 + elif bomb_scale <= 2.0: + shadow_size = 0.4 + elif bomb_scale <= 3.0: + shadow_size = 0.2 + else: + shadow_size = 0.1 + + self.snowball_material = bs.Material() + self.snowball_material.add_actions( + conditions=( + ( + ('we_are_younger_than', 5), + 'or', + ('they_are_younger_than', 100), + ), + 'and', + ('they_have_material', shared.object_material), + ), + actions=('modify_node_collision', 'collide', False), + ) + + self.snowball_material.add_actions( + conditions=('they_have_material', shared.pickup_material), + actions=('modify_part_collision', 'use_node_collide', False), + ) + + self.snowball_material.add_actions(actions=('modify_part_collision', + 'friction', 0.3)) + + self.snowball_material.add_actions( + conditions=('they_have_material', shared.player_material), + actions=(('modify_part_collision', 'physical', False), + ('call', 'at_connect', self.hit))) + + self.snowball_material.add_actions( + conditions=(('they_dont_have_material', shared.player_material), + 'and', + ('they_have_material', shared.object_material), + 'or', + ('they_have_material', shared.footing_material)), + actions=('call', 'at_connect', self.bounce)) + + self.node = bs.newnode( + 'prop', + delegate=self, + attrs={ + 'position': position, + 'velocity': velocity, + 'body': 'sphere', + 'body_scale': self.scale, + 'mesh': bs.getmesh('frostyPelvis'), + 'shadow_size': shadow_size, + 'color_texture': bs.gettexture('bunnyColor'), + 'reflection': 'soft', + 'reflection_scale': [0.15], + 'density': 1.0, + 'materials': [self.snowball_material] + }) + self.light = bs.newnode( + 'light', + owner=self.node, + attrs={ + 'color': (0.6, 0.6, 1.0), + 'intensity': 0.8, + 'radius': self.radius + }) + self.node.connectattr('position', self.light, 'position') + bs.animate(self.node, 'mesh_scale', { + 0: 0, + 0.2: 1.3 * self.scale, + 0.26: self.scale + }) + bs.animate(self.light, 'radius', { + 0: 0, + 0.2: 1.3 * self.radius, + 0.26: self.radius + }) + if self.snowball_melt: + bs.timer(1.5, bs.WeakCall(self._disappear)) + + def hit(self) -> None: + if not self.node: + return + if self._exploded: + return + if self.snowball_explode: + self._exploded = True + self.do_explode() + bs.timer(0.001, bs.WeakCall(self.handlemessage, bs.DieMessage())) + else: + self.do_hit() + + def do_hit(self) -> None: + v = self.node.velocity + if babase.Vec3(*v).length() > 5.0: + node = bs.getcollision().opposingnode + if node is not None and node and not ( + node in self._hit_nodes): + t = self.node.position + hitdir = self.node.velocity + self._hit_nodes.add(node) + node.handlemessage( + bs.HitMessage( + pos=t, + velocity=v, + magnitude=babase.Vec3(*v).length()*0.5, + velocity_magnitude=babase.Vec3(*v).length()*0.5, + radius=0, + srcnode=self.node, + source_player=self._source_player, + force_direction=hitdir, + hit_type='snoBall', + hit_subtype='default')) + + if not self.snowball_bounce: + bs.timer(0.05, bs.WeakCall(self.do_bounce)) + + def do_explode(self) -> None: + Blast(position=self.node.position, + velocity=self.node.velocity, + blast_radius=self.blast_radius, + source_player=babase.existing(self._source_player), + blast_type='impact', + hit_subtype='explode').autoretain() + + def bounce(self) -> None: + if not self.node: + return + if self._exploded: + return + if not self.snowball_bounce: + vel = self.node.velocity + bs.timer(0.01, bs.WeakCall(self.calc_bounce, vel)) + else: + return + + def calc_bounce(self, vel) -> None: + if not self.node: + return + ospd = babase.Vec3(*vel).length() + dot = sum(x*y for x, y in zip(vel, self.node.velocity)) + if ospd*ospd - dot > 50.0: + bs.timer(0.05, bs.WeakCall(self.do_bounce)) + + def do_bounce(self) -> None: + if not self.node: + return + if not self._exploded: + self.do_effect() + + def do_effect(self) -> None: + self._exploded = True + bs.emitfx(position=self.node.position, + velocity=[v*0.1 for v in self.node.velocity], + count=10, + spread=0.1, + scale=0.4, + chunk_type='ice') + sound = bs.getsound('impactMedium') + sound.play(1.0, position=self.node.position) + scl = self.node.mesh_scale + bs.animate(self.node, 'mesh_scale', { + 0.0: scl*1.0, + 0.02: scl*0.5, + 0.05: 0.0 + }) + lr = self.light.radius + bs.animate(self.light, 'radius', { + 0.0: lr*1.0, + 0.02: lr*0.5, + 0.05: 0.0 + }) + bs.timer(0.08, + bs.WeakCall(self.handlemessage, bs.DieMessage())) + + def _disappear(self) -> None: + self._exploded = True + if self.node: + scl = self.node.mesh_scale + bs.animate(self.node, 'mesh_scale', { + 0.0: scl*1.0, + 0.3: scl*0.5, + 0.5: 0.0 + }) + lr = self.light.radius + bs.animate(self.light, 'radius', { + 0.0: lr*1.0, + 0.3: lr*0.5, + 0.5: 0.0 + }) + bs.timer(0.55, + bs.WeakCall(self.handlemessage, bs.DieMessage())) + + def handlemessage(self, msg: Any) -> Any: + if isinstance(msg, bs.DieMessage): + if self.node: + self.node.delete() + elif isinstance(msg, bs.OutOfBoundsMessage): + self.handlemessage(bs.DieMessage()) + else: + super().handlemessage(msg) + + +class NewPlayerSpaz(PlayerSpaz): + + def __init__(self, *args: Any, **kwds: Any): + super().__init__(*args, **kwds) + self.snowball_scale = 1.0 + self.snowball_melt = True + self.snowball_bounce = True + self.snowball_explode = False + + def on_punch_press(self) -> None: + if not self.node or self.frozen or self.node.knockout > 0.0: + return + t_ms = bs.time() * 1000 + assert isinstance(t_ms, int) + if t_ms - self.last_punch_time_ms >= self._punch_cooldown: + if self.punch_callback is not None: + self.punch_callback(self) + + # snowball + pos = self.node.position + p1 = self.node.position_center + p2 = self.node.position_forward + direction = [p1[0]-p2[0],p2[1]-p1[1],p1[2]-p2[2]] + direction[1] = 0.03 + mag = 20.0/babase.Vec3(*direction).length() + vel = [v * mag for v in direction] + Snowball(position=(pos[0], pos[1] + 0.1, pos[2]), + velocity=vel, + blast_radius=self.blast_radius, + bomb_scale=self.snowball_scale, + source_player=self.source_player, + owner=self.node, + melt=self.snowball_melt, + bounce=self.snowball_bounce, + explode=self.snowball_explode).autoretain() + + self._punched_nodes = set() # Reset this. + self.last_punch_time_ms = t_ms + self.node.punch_pressed = True + if not self.node.hold_node: + bs.timer( + 0.1, + bs.WeakCall(self._safe_play_sound, + SpazFactory.get().swish_sound, 0.8)) + self._turbo_filter_add_press('punch') + + def handlemessage(self, msg: Any) -> Any: + if isinstance(msg, PunchHitMessage): + pass + else: + return super().handlemessage(msg) + return None + + +class Player(bs.Player['Team']): + """Our player type for this game.""" + + +class Team(bs.Team[Player]): + """Our team type for this game.""" + + def __init__(self) -> None: + self.score = 0 + + +# ba_meta export bascenev1.GameActivity +class SnowballFightGame(bs.TeamGameActivity[Player, Team]): + """A game type based on acquiring kills.""" + + name = name + description = 'Kill a set number of enemies to win.' + + # Print messages when players die since it matters here. + announce_player_deaths = True + + @classmethod + def get_available_settings( + cls, sessiontype: type[bs.Session]) -> list[babase.Setting]: + settings = [ + bs.IntSetting( + 'Kills to Win Per Player', + min_value=1, + default=5, + increment=1, + ), + bs.IntChoiceSetting( + 'Time Limit', + choices=[ + ('None', 0), + ('1 Minute', 60), + ('2 Minutes', 120), + ('5 Minutes', 300), + ('10 Minutes', 600), + ('20 Minutes', 1200), + ], + default=0, + ), + bs.FloatChoiceSetting( + 'Respawn Times', + choices=[ + ('Shorter', 0.25), + ('Short', 0.5), + ('Normal', 1.0), + ('Long', 2.0), + ('Longer', 4.0), + ], + default=1.0, + ), + bs.IntChoiceSetting( + snowball_rate, + choices=[ + (snowball_slowest, 500), + (snowball_slow, 400), + ('Normal', 300), + (snowball_fast, 200), + (snowball_lagcity, 100), + ], + default=300, + ), + bs.FloatChoiceSetting( + snowball_scale, + choices=[ + (snowball_smallest, 0.4), + (snowball_small, 0.6), + ('Normal', 0.8), + (snowball_big, 1.4), + (snowball_biggest, 3.0), + (snowball_insane, 6.0), + ], + default=0.8, + ), + bs.BoolSetting(snowball_melt, default=True), + bs.BoolSetting(snowball_bust, default=True), + bs.BoolSetting(snowball_explode, default=False), + bs.BoolSetting(snowball_snow, default=True), + bs.BoolSetting('Epic Mode', default=False), + ] + + # In teams mode, a suicide gives a point to the other team, but in + # free-for-all it subtracts from your own score. By default we clamp + # this at zero to benefit new players, but pro players might like to + # be able to go negative. (to avoid a strategy of just + # suiciding until you get a good drop) + if issubclass(sessiontype, bs.FreeForAllSession): + settings.append( + bs.BoolSetting('Allow Negative Scores', default=False)) + + return settings + + @classmethod + def supports_session_type(cls, sessiontype: type[bs.Session]) -> bool: + return (issubclass(sessiontype, bs.DualTeamSession) + or issubclass(sessiontype, bs.FreeForAllSession)) + + @classmethod + def get_supported_maps(cls, sessiontype: type[bs.Session]) -> list[str]: + return bs.app.classic.getmaps('melee') + + def __init__(self, settings: dict): + super().__init__(settings) + self._scoreboard = Scoreboard() + self._score_to_win: int | None = None + self._dingsound = bs.getsound('dingSmall') + self._epic_mode = bool(settings['Epic Mode']) + self._kills_to_win_per_player = int( + settings['Kills to Win Per Player']) + self._time_limit = float(settings['Time Limit']) + self._allow_negative_scores = bool( + settings.get('Allow Negative Scores', False)) + self._snowball_rate = int(settings[snowball_rate]) + self._snowball_scale = float(settings[snowball_scale]) + self._snowball_melt = bool(settings[snowball_melt]) + self._snowball_bounce = bool(settings[snowball_bust]) + self._snowball_explode = bool(settings[snowball_explode]) + self._snow_mode = bool(settings[snowball_snow]) + + # Base class overrides. + self.slow_motion = self._epic_mode + self.default_music = (bs.MusicType.EPIC if self._epic_mode else + bs.MusicType.TO_THE_DEATH) + + def get_instance_description(self) -> str | Sequence: + return 'Crush ${ARG1} of your enemies.', self._score_to_win + + def get_instance_description_short(self) -> str | Sequence: + return 'kill ${ARG1} enemies', self._score_to_win + + def on_team_join(self, team: Team) -> None: + if self.has_begun(): + self._update_scoreboard() + + def on_transition_in(self) -> None: + super().on_transition_in() + if self._snow_mode: + gnode = bs.getactivity().globalsnode + gnode.tint = (0.8, 0.8, 1.3) + bs.timer(0.02, self.emit_snowball, repeat=True) + + def on_begin(self) -> None: + super().on_begin() + self.setup_standard_time_limit(self._time_limit) + # self.setup_standard_powerup_drops() + + # Base kills needed to win on the size of the largest team. + self._score_to_win = (self._kills_to_win_per_player * + max(1, max(len(t.players) for t in self.teams))) + self._update_scoreboard() + + def emit_snowball(self) -> None: + pos = (-10 + (random.random() * 30), 15, + -10 + (random.random() * 30)) + vel = ((-5.0 + random.random() * 30.0) * (-1.0 if pos[0] > 0 else 1.0), + -50.0, (-5.0 + random.random() * 30.0) * ( + -1.0 if pos[0] > 0 else 1.0)) + bs.emitfx(position=pos, + velocity=vel, + count=10, + scale=1.0 + random.random(), + spread=0.0, + chunk_type='spark') + + def spawn_player_spaz(self, + player: Player, + position: Sequence[float] = (0, 0, 0), + angle: float | None = None) -> PlayerSpaz: + from babase import _math + from bascenev1._gameutils import animate + from bascenev1._coopsession import CoopSession + + if isinstance(self.session, bs.DualTeamSession): + position = self.map.get_start_position(player.team.id) + else: + # otherwise do free-for-all spawn locations + position = self.map.get_ffa_start_position(self.players) + + name = player.getname() + color = player.color + highlight = player.highlight + + light_color = _math.normalized_color(color) + display_color = babase.safecolor(color, target_intensity=0.75) + + spaz = NewPlayerSpaz(color=color, + highlight=highlight, + character=player.character, + player=player) + + player.actor = spaz + assert spaz.node + + # If this is co-op and we're on Courtyard or Runaround, add the + # material that allows us to collide with the player-walls. + # FIXME: Need to generalize this. + if isinstance(self.session, CoopSession) and self.map.getname() in [ + 'Courtyard', 'Tower D' + ]: + mat = self.map.preloaddata['collide_with_wall_material'] + assert isinstance(spaz.node.materials, tuple) + assert isinstance(spaz.node.roller_materials, tuple) + spaz.node.materials += (mat, ) + spaz.node.roller_materials += (mat, ) + + spaz.node.name = name + spaz.node.name_color = display_color + spaz.connect_controls_to_player( + enable_pickup=False, enable_bomb=False) + + # Move to the stand position and add a flash of light. + spaz.handlemessage( + bs.StandMessage( + position, + angle if angle is not None else random.uniform(0, 360))) + self._spawn_sound.play(1, position=spaz.node.position) + light = bs.newnode('light', attrs={'color': light_color}) + spaz.node.connectattr('position', light, 'position') + animate(light, 'intensity', {0: 0, 0.25: 1, 0.5: 0}) + bs.timer(0.5, light.delete) + + # custom + spaz._punch_cooldown = self._snowball_rate + spaz.snowball_scale = self._snowball_scale + spaz.snowball_melt = self._snowball_melt + spaz.snowball_bounce = self._snowball_bounce + spaz.snowball_explode = self._snowball_explode + + return spaz + + def handlemessage(self, msg: Any) -> Any: + + if isinstance(msg, bs.PlayerDiedMessage): + + # Augment standard behavior. + super().handlemessage(msg) + + player = msg.getplayer(Player) + self.respawn_player(player) + + killer = msg.getkillerplayer(Player) + if killer is None: + return None + + # Handle team-kills. + if killer.team is player.team: + + # In free-for-all, killing yourself loses you a point. + if isinstance(self.session, bs.FreeForAllSession): + new_score = player.team.score - 1 + if not self._allow_negative_scores: + new_score = max(0, new_score) + player.team.score = new_score + + # In teams-mode it gives a point to the other team. + else: + self._dingsound.play() + for team in self.teams: + if team is not killer.team: + team.score += 1 + + # Killing someone on another team nets a kill. + else: + killer.team.score += 1 + self._dingsound.play() + + # In FFA show scores since its hard to find on the scoreboard. + if isinstance(killer.actor, PlayerSpaz) and killer.actor: + killer.actor.set_score_text(str(killer.team.score) + '/' + + str(self._score_to_win), + color=killer.team.color, + flash=True) + + self._update_scoreboard() + + # If someone has won, set a timer to end shortly. + # (allows the dust to clear and draws to occur if deaths are + # close enough) + assert self._score_to_win is not None + if any(team.score >= self._score_to_win for team in self.teams): + bs.timer(0.5, self.end_game) + + else: + return super().handlemessage(msg) + return None + + def _update_scoreboard(self) -> None: + for team in self.teams: + self._scoreboard.set_team_value(team, team.score, + self._score_to_win) + + def end_game(self) -> None: + results = bs.GameResults() + for team in self.teams: + results.set_team_score(team, team.score) + self.end(results=results) diff --git a/plugins/minigames/meteorshowerdeluxe.py b/plugins/minigames/meteorshowerdeluxe.py new file mode 100644 index 00000000..296c8dcd --- /dev/null +++ b/plugins/minigames/meteorshowerdeluxe.py @@ -0,0 +1,67 @@ +# Porting to api 8 made easier by baport.(https://github.com/bombsquad-community/baport) +# ba_meta require api 8 +""" +GNU AFFERO GENERAL PUBLIC LICENSE +Version 3, 19 November 2007 + +Copyright (C) 2007 Free Software Foundation, Inc. <[1](https://fsf.org/)> + +Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. + +This license is designed to ensure cooperation with the community in the case of network server software. It is a free, copyleft license for software and other kinds of works. The license guarantees your freedom to share and change all versions of a program, to make sure it remains free software for all its users. + +The license identifier refers to the choice to use code under AGPL-3.0-or-later (i.e., AGPL-3.0 or some later version), as distinguished from use of code under AGPL-3.0-only. The license notice states which of these applies the code in the file. + + +""" +import random +import babase +import bauiv1 as bui +import bascenev1 as bs +from bascenev1lib.game.meteorshower import MeteorShowerGame +from bascenev1lib.actor.bomb import Bomb + + +class NewMeteorShowerGame(MeteorShowerGame): + @classmethod + def get_supported_maps(cls, sessiontype: type[bs.Session]) -> list[str]: + return bs.app.classic.getmaps("melee") + + def _drop_bomb_cluster(self) -> None: + # Drop several bombs in series. + delay = 0.0 + bounds = list(self._map.get_def_bound_box("map_bounds")) + for _i in range(random.randrange(1, 3)): + # Drop them somewhere within our bounds with velocity pointing + # toward the opposite side. + pos = ( + random.uniform(bounds[0], bounds[3]), + bounds[4], + random.uniform(bounds[2], bounds[5]), + ) + dropdirx = -1 if pos[0] > 0 else 1 + dropdirz = -1 if pos[2] > 0 else 1 + forcex = ( + bounds[0] - bounds[3] + if bounds[0] - bounds[3] > 0 + else -(bounds[0] - bounds[3]) + ) + forcez = ( + bounds[2] - bounds[5] + if bounds[2] - bounds[5] > 0 + else -(bounds[2] - bounds[5]) + ) + vel = ( + (-5 + random.random() * forcex) * dropdirx, + random.uniform(-3.066, -4.12), + (-5 + random.random() * forcez) * dropdirz, + ) + bs.timer(delay, babase.Call(self._drop_bomb, pos, vel)) + delay += 0.1 + self._set_meteor_timer() + + +# ba_meta export plugin +class byEra0S(babase.Plugin): + MeteorShowerGame.get_supported_maps = NewMeteorShowerGame.get_supported_maps + MeteorShowerGame._drop_bomb_cluster = NewMeteorShowerGame._drop_bomb_cluster diff --git a/plugins/minigames/ofuuuAttack.py b/plugins/minigames/ofuuuAttack.py new file mode 100644 index 00000000..49b2afb9 --- /dev/null +++ b/plugins/minigames/ofuuuAttack.py @@ -0,0 +1,340 @@ +# Porting to api 8 made easier by baport.(https://github.com/bombsquad-community/baport) +# ba_meta require api 8 +# (see https://ballistica.net/wiki/meta-tag-system) + +from __future__ import annotations + +from typing import TYPE_CHECKING + +import babase +import bauiv1 as bui +import bascenev1 as bs +import random +from bascenev1lib.actor.bomb import BombFactory, Bomb +from bascenev1lib.gameutils import SharedObjects +from bascenev1lib.actor.onscreentimer import OnScreenTimer + +if TYPE_CHECKING: + from typing import Any, Sequence, Optional, List, Dict, Type, Type + +class _GotTouched(): + pass + +class UFO(bs.Actor): + + def __init__(self, pos: float = (0,0,0)): + super().__init__() + shared = SharedObjects.get() + self.r: Optional[int] = 0 + self.dis: Optional[List] = [] + self.target: float = (0.0, 0.0, 0.0) + self.regs: List[bs.NodeActor] = [] + self.node = bs.newnode('prop', + delegate=self, + attrs={'body':'landMine', + 'position': pos, + 'mesh':bs.getmesh('landMine'), + 'mesh_scale': 1.5, + 'body_scale': 0.01, + 'shadow_size': 0.000001, + 'gravity_scale': 0.0, + 'color_texture': bs.gettexture("achievementCrossHair"), + 'materials': [shared.object_material]}) + self.ufo_collide = None + + def create_target(self): + if not self.node.exists(): return + self.dis = [] + shared = SharedObjects.get() + try: + def pass_(): + self.regs.clear() + bs.timer(3875*0.001, self.move) + try: bs.timer(3277*0.001, lambda: Bomb(velocity=(0,0,0), position=(self.target[0], self.node.position[1]-0.43999, self.target[2]), bomb_type='impact').autoretain().arm()) + except: pass + key = bs.Material() + key.add_actions( + conditions=('they_have_material', shared.object_material), + actions=( + ('modify_part_collision', 'collide', True), + ('modify_part_collision', 'physical', False), + ('call', 'at_connect', pass_()), + )) + except: pass + self.regs.append(bs.NodeActor(bs.newnode('region', + attrs={ + 'position': self.target, + 'scale': (0.04, 22, 0.04), + 'type': 'sphere', + 'materials':[key]}))) + + def move(self): + if not self.node.exists(): return + try: + self.create_target() + for j in bs.getnodes(): + n = j.getdelegate(object) + if j.getnodetype() == 'prop' and isinstance(n, TileFloor): + if n.node.exists(): self.dis.append(n.node) + self.r = random.randint(0,len(self.dis)-1) + self.target = (self.dis[self.r].position[0], self.node.position[1], self.dis[self.r].position[2]) + bs.animate_array(self.node, 'position', 3, { + 0:self.node.position, + 3.0:self.target}) + except: pass + def handlemessage(self, msg): + + if isinstance(msg, bs.DieMessage): + self.node.delete() + elif isinstance(msg ,bs.OutOfBoundsMessage): self.handlemessage(bs.DieMessage()) + else: super().handlemessage(msg) + + +class TileFloor(bs.Actor): + def __init__(self, + pos: float = (0, 0, 0)): + super().__init__() + get_mat = SharedObjects.get() + self.pos = pos + self.scale = 1.5 + self.mat, self.mat2, self.test = bs.Material(), bs.Material(), bs.Material() + self.mat.add_actions(conditions=('we_are_older_than', 1), actions=(('modify_part_collision', 'collide', False))) + self.mat2.add_actions(conditions=('we_are_older_than', 1), actions=(('modify_part_collision', 'collide', True))) + self.test.add_actions( + conditions=('they_have_material', BombFactory.get().bomb_material), + actions=( + ('modify_part_collision', 'collide', True), + ('modify_part_collision', 'physical', False), + ('message', 'our_node', 'at_connect', _GotTouched()))) + self.node = bs.newnode('prop', + delegate=self, + attrs={'body':'puck', + 'position': self.pos, + 'mesh':bs.getmesh('buttonSquareOpaque'), + 'mesh_scale': self.scale*1.16, + 'body_scale': self.scale, + 'shadow_size': 0.0002, + 'gravity_scale': 0.0, + 'color_texture': bs.gettexture("tnt"), + 'is_area_of_interest': True, + 'materials': [self.mat, self.test]}) + self.node_support = bs.newnode('region', + attrs={ + 'position': self.pos, + 'scale': (self.scale*0.8918, 0.1, self.scale*0.8918), + 'type': 'box', + 'materials':[get_mat.footing_material, self.mat2] + }) + def handlemessage(self, msg): + if isinstance(msg, bs.DieMessage): + self.node.delete() + self.node_support.delete() + elif isinstance(msg, _GotTouched): + def do(): self.handlemessage(bs.DieMessage()) + bs.timer(0.1, do) + else: super().handlemessage(msg) + +class defs(): + points = boxes = {} + boxes['area_of_interest_bounds'] = (-1.3440, 1.185751251, 3.7326226188) + ( + 0.0, 0.0, 0.0) + (29.8180273, 15.57249038, 22.93859993) + boxes['map_bounds'] = (0.0, 2.585751251, 0.4326226188) + (0.0, 0.0, 0.0) + (29.09506485, 15.81173179, 33.76723155) + +class DummyMapForGame(bs.Map): + defs, name = defs(), 'Tile Lands' + @classmethod + def get_play_types(cls) -> List[str]: + return [] + @classmethod + def get_preview_texture_name(cls) -> str: + return 'achievementCrossHair' + @classmethod + def on_preload(cls) -> Any: + data: Dict[str, Any] = {'bg_1': bs.gettexture('rampageBGColor'),'bg_2': bs.gettexture('rampageBGColor2'),'bg_mesh_1': bs.getmesh('rampageBG'),'bg_mesh_2': bs.getmesh('rampageBG2'),} + return data + def __init__(self) -> None: + super().__init__() + self.bg1 = bs.newnode('terrain',attrs={'mesh': self.preloaddata['bg_mesh_1'],'lighting': False,'background': True,'color_texture': self.preloaddata['bg_2']}) + self.bg2 = bs.newnode('terrain',attrs={ 'mesh': self.preloaddata['bg_mesh_2'], 'lighting': False,'background': True, 'color_texture': self.preloaddata['bg_2']}) + a = bs.getactivity().globalsnode + a.tint, a.ambient_color, a.vignette_outer, a.vignette_inner = (1.2, 1.1, 0.97), (1.3, 1.2, 1.03), (0.62, 0.64, 0.69), (0.97, 0.95, 0.93) + +class DummyMapForGame2(bs.Map): + defs, name = defs(), 'Tile Lands Night' + @classmethod + def get_play_types(cls) -> List[str]: + return [] + @classmethod + def get_preview_texture_name(cls) -> str: + return 'achievementCrossHair' + @classmethod + def on_preload(cls) -> Any: + data: Dict[str, Any] = {'bg_1': bs.gettexture('menuBG'),'bg_2': bs.gettexture('menuBG'),'bg_mesh_1': bs.getmesh('thePadBG'),'bg_mesh_2': bs.getmesh('thePadBG'),} + return data + def __init__(self) -> None: + super().__init__() + self.bg1 = bs.newnode('terrain',attrs={'mesh': self.preloaddata['bg_mesh_1'],'lighting': False,'background': True,'color_texture': self.preloaddata['bg_2']}) + self.bg2 = bs.newnode('terrain',attrs={ 'mesh': self.preloaddata['bg_mesh_2'], 'lighting': False,'background': True, 'color_texture': self.preloaddata['bg_2']}) + a = bs.getactivity().globalsnode + a.tint, a.ambient_color, a.vignette_outer, a.vignette_inner = (0.5, 0.7, 1.27), (2.5, 2.5, 2.5), (0.62, 0.64, 0.69), (0.97, 0.95, 0.93) + +bs._map.register_map(DummyMapForGame) +bs._map.register_map(DummyMapForGame2) + + + + +class Player(bs.Player['Team']): + """Our player type for this game.""" + + def __init__(self) -> None: + super().__init__() + self.death_time: Optional[float] = None + + +class Team(bs.Team[Player]): + """Our team type for this game.""" + + +# ba_meta export bascenev1.GameActivity +class UFOAttackGame(bs.TeamGameActivity[Player, Team]): + + name = 'UFO Attack' + description = 'Dodge the falling bombs.' + available_settings = [ + bs.BoolSetting('Epic Mode', default=False), + bs.BoolSetting('Enable Run', default=True), + bs.BoolSetting('Enable Jump', default=True), + bs.BoolSetting('Display Map Area Dimension', default=False), + bs.IntSetting('No. of Rows' + u' →',max_value=13, min_value=1, default=8, increment=1), + bs.IntSetting('No. of Columns' + u' ↓', max_value=12, min_value=1, default=6, increment=1) + ] + scoreconfig = bs.ScoreConfig(label='Survived', + scoretype=bs.ScoreType.SECONDS, + version='B') + + # Print messages when players die (since its meaningful in this game). + announce_player_deaths = True + @classmethod + def get_supported_maps(cls, sessiontype: Type[bs.Session]) -> List[str]: + return ['Tile Lands', 'Tile Lands Night'] + @classmethod + def supports_session_type(cls, sessiontype: Type[bs.Session]) -> bool: + return (issubclass(sessiontype, bs.DualTeamSession) + or issubclass(sessiontype, bs.FreeForAllSession)) + + def __init__(self, settings: dict): + super().__init__(settings) + + self.col = int(settings['No. of Columns' + u' ↓']) + self.row = int(settings['No. of Rows' + u' →']) + self.bool1 = bool(settings['Enable Run']) + self.bool2 = bool(settings['Enable Jump']) + self._epic_mode = settings.get('Epic Mode', False) + self._last_player_death_time: Optional[float] = None + self._timer: Optional[OnScreenTimer] = None + self.default_music = (bs.MusicType.EPIC + if self._epic_mode else bs.MusicType.SURVIVAL) + if bool(settings["Display Map Area Dimension"]): + self.game_name = "UFO Attack " + "(" + str(self.col) + "x" + str(self.row) + ")" + else: self.game_name = "UFO Attack" + if self._epic_mode: + self.slow_motion = True + + def get_instance_display_string(self) -> babase.Lstr: + return self.game_name + + def on_begin(self) -> None: + super().on_begin() + self._timer = OnScreenTimer() + self._timer.start() + #bs.timer(5.0, self._check_end_game) + for r in range(self.col): + for j in range(self.row): + tile = TileFloor(pos=(-6.204283+(j*1.399), 3.425666, + -1.3538+(r*1.399))).autoretain() + self.ufo = UFO(pos=(-5.00410667, 6.616383286, -2.503472)).autoretain() + bs.timer(7000*0.001, lambda: self.ufo.move()) + for t in self.players: + self.spawn_player(t) + + def on_player_join(self, player: Player) -> None: + if self.has_begun(): + bs.broadcastmessage( + babase.Lstr(resource='playerDelayedJoinText', + subs=[('${PLAYER}', player.getname(full=True))]), + color=(0, 1, 0), + ) + assert self._timer is not None + player.death_time = self._timer.getstarttime() + return + + def on_player_leave(self, player: Player) -> None: + super().on_player_leave(player) + self._check_end_game() + + def spawn_player(self, player: Player) -> bs.Actor: + dis = [] + for a in bs.getnodes(): + g = a.getdelegate(object) + if a.getnodetype() == 'prop' and isinstance(g, TileFloor): + dis.append(g.node) + r = random.randint(0, len(dis)-1) + spaz = self.spawn_player_spaz(player, position=(dis[r].position[0], dis[r].position[1]+1.005958, dis[r].position[2])) + spaz.connect_controls_to_player(enable_punch=False, + enable_bomb=False, + enable_run=self.bool1, + enable_jump=self.bool2, + enable_pickup=False) + spaz.play_big_death_sound = True + return spaz + def handlemessage(self, msg: Any) -> Any: + if isinstance(msg, bs.PlayerDiedMessage): + super().handlemessage(msg) + + curtime = bs.time() + msg.getplayer(Player).death_time = curtime + bs.timer(1.0, self._check_end_game) + + else: + return super().handlemessage(msg) + return None + + def _check_end_game(self) -> None: + living_team_count = 0 + for team in self.teams: + for player in team.players: + if player.is_alive(): + living_team_count += 1 + break + if living_team_count <= 1: + self.end_game() + + def end_game(self) -> None: + self.ufo.handlemessage(bs.DieMessage()) + cur_time = bs.time() + assert self._timer is not None + start_time = self._timer.getstarttime() + for team in self.teams: + for player in team.players: + survived = False + if player.death_time is None: + survived = True + player.death_time = cur_time + 1 + score = int(player.death_time - self._timer.getstarttime()) + if survived: + score += 2 + self.stats.player_scored(player, score, screenmessage=False) + self._timer.stop(endtime=self._last_player_death_time) + results = bs.GameResults() + for team in self.teams: + longest_life = 0.0 + for player in team.players: + assert player.death_time is not None + longest_life = max(longest_life, + player.death_time - start_time) + + # Submit the score value in milliseconds. + results.set_team_score(team, int(longest_life)) + + self.end(results=results) \ No newline at end of file diff --git a/plugins/minigames/safe_zone.py b/plugins/minigames/safe_zone.py new file mode 100644 index 00000000..4c2620f0 --- /dev/null +++ b/plugins/minigames/safe_zone.py @@ -0,0 +1,720 @@ +# Porting to api 8 made easier by baport.(https://github.com/bombsquad-community/baport) +# Released under the MIT License. See LICENSE for details. +# +"""Elimination mini-game.""" + +# Maded by Froshlee14 +# Update by SEBASTIAN2059 + +# ba_meta require api 8 +# (see https://ballistica.net/wiki/meta-tag-system) + +from __future__ import annotations + +from typing import TYPE_CHECKING + +import babase +import bauiv1 as bui +import bascenev1 as bs +import _babase +import random +from bascenev1lib.actor.spazfactory import SpazFactory +from bascenev1lib.actor.scoreboard import Scoreboard +from bascenev1lib.actor import spazbot as stdbot +from bascenev1lib.gameutils import SharedObjects as so + +if TYPE_CHECKING: + from typing import (Any, Tuple, Dict, Type, List, Sequence, Optional, + Union) + + +class Icon(bs.Actor): + """Creates in in-game icon on screen.""" + + def __init__(self, + player: Player, + position: Tuple[float, float], + scale: float, + show_lives: bool = True, + show_death: bool = True, + name_scale: float = 1.0, + name_maxwidth: float = 115.0, + flatness: float = 1.0, + shadow: float = 1.0): + super().__init__() + + self._player = player + self._show_lives = show_lives + self._show_death = show_death + self._name_scale = name_scale + self._outline_tex = bs.gettexture('characterIconMask') + + icon = player.get_icon() + self.node = bs.newnode('image', + delegate=self, + attrs={ + 'texture': icon['texture'], + 'tint_texture': icon['tint_texture'], + 'tint_color': icon['tint_color'], + 'vr_depth': 400, + 'tint2_color': icon['tint2_color'], + 'mask_texture': self._outline_tex, + 'opacity': 1.0, + 'absolute_scale': True, + 'attach': 'bottomCenter' + }) + self._name_text = bs.newnode( + 'text', + owner=self.node, + attrs={ + 'text': babase.Lstr(value=player.getname()), + 'color': babase.safecolor(player.team.color), + 'h_align': 'center', + 'v_align': 'center', + 'vr_depth': 410, + 'maxwidth': name_maxwidth, + 'shadow': shadow, + 'flatness': flatness, + 'h_attach': 'center', + 'v_attach': 'bottom' + }) + if self._show_lives: + self._lives_text = bs.newnode('text', + owner=self.node, + attrs={ + 'text': 'x0', + 'color': (1, 1, 0.5), + 'h_align': 'left', + 'vr_depth': 430, + 'shadow': 1.0, + 'flatness': 1.0, + 'h_attach': 'center', + 'v_attach': 'bottom' + }) + self.set_position_and_scale(position, scale) + + def set_position_and_scale(self, position: Tuple[float, float], + scale: float) -> None: + """(Re)position the icon.""" + assert self.node + self.node.position = position + self.node.scale = [70.0 * scale] + self._name_text.position = (position[0], position[1] + scale * 52.0) + self._name_text.scale = 1.0 * scale * self._name_scale + if self._show_lives: + self._lives_text.position = (position[0] + scale * 10.0, + position[1] - scale * 43.0) + self._lives_text.scale = 1.0 * scale + + def update_for_lives(self) -> None: + """Update for the target player's current lives.""" + if self._player: + lives = self._player.lives + else: + lives = 0 + if self._show_lives: + if lives > 0: + self._lives_text.text = 'x' + str(lives - 1) + else: + self._lives_text.text = '' + if lives == 0: + self._name_text.opacity = 0.2 + assert self.node + self.node.color = (0.7, 0.3, 0.3) + self.node.opacity = 0.2 + + def handle_player_spawned(self) -> None: + """Our player spawned; hooray!""" + if not self.node: + return + self.node.opacity = 1.0 + self.update_for_lives() + + def handle_player_died(self) -> None: + """Well poo; our player died.""" + if not self.node: + return + if self._show_death: + bs.animate( + self.node, 'opacity', { + 0.00: 1.0, + 0.05: 0.0, + 0.10: 1.0, + 0.15: 0.0, + 0.20: 1.0, + 0.25: 0.0, + 0.30: 1.0, + 0.35: 0.0, + 0.40: 1.0, + 0.45: 0.0, + 0.50: 1.0, + 0.55: 0.2 + }) + lives = self._player.lives + if lives == 0: + bs.timer(0.6, self.update_for_lives) + + def handlemessage(self, msg: Any) -> Any: + if isinstance(msg, bs.DieMessage): + self.node.delete() + return None + return super().handlemessage(msg) + + +class Player(bs.Player['Team']): + """Our player type for this game.""" + + def __init__(self) -> None: + self.lives = 0 + self.icons: List[Icon] = [] + + +class Team(bs.Team[Player]): + """Our team type for this game.""" + + def __init__(self) -> None: + self.survival_seconds: Optional[int] = None + self.spawn_order: List[Player] = [] + +lang = bs.app.lang.language +if lang == 'Spanish': + description = 'Mantente en la zona segura.' + join_description = 'Corre hacia la zona segura.' + kill_timer = 'Kill timer: ' +else: + description = 'Stay in the safe zone.' + join_description = 'Run into the safe zone' + kill_timer = 'Kill timer: ' + +# ba_meta export bascenev1.GameActivity +class SafeZoneGame(bs.TeamGameActivity[Player, Team]): + """Game type where last player(s) left alive win.""" + + name = 'Safe Zone' + description = description + scoreconfig = bs.ScoreConfig(label='Survived', + scoretype=bs.ScoreType.SECONDS, + none_is_winner=True) + # Show messages when players die since it's meaningful here. + announce_player_deaths = True + + @classmethod + def get_available_settings( + cls, sessiontype: Type[bs.Session]) -> List[babase.Setting]: + settings = [ + bs.IntSetting( + 'Lives Per Player', + default=2, + min_value=1, + max_value=10, + increment=1, + ), + bs.IntChoiceSetting( + 'Time Limit', + choices=[ + ('None', 0), + ('1 Minute', 60), + ('2 Minutes', 120), + ('5 Minutes', 300), + ('10 Minutes', 600), + ('20 Minutes', 1200), + ], + default=0, + ), + bs.FloatChoiceSetting( + 'Respawn Times', + choices=[ + ('Short', 0.25), + ('Normal', 0.5), + ], + default=0.5, + ), + bs.BoolSetting('Epic Mode', default=False), + ] + if issubclass(sessiontype, bs.DualTeamSession): + settings.append(bs.BoolSetting('Solo Mode', default=False)) + settings.append( + bs.BoolSetting('Balance Total Lives', default=False)) + return settings + + @classmethod + def supports_session_type(cls, sessiontype: Type[bs.Session]) -> bool: + return (issubclass(sessiontype, bs.DualTeamSession) + or issubclass(sessiontype, bs.FreeForAllSession)) + + @classmethod + def get_supported_maps(cls, sessiontype: Type[bs.Session]) -> List[str]: + return ['Football Stadium','Hockey Stadium'] + + def __init__(self, settings: dict): + super().__init__(settings) + self._scoreboard = Scoreboard() + self._start_time: Optional[float] = None + self._vs_text: Optional[bs.Actor] = None + self._round_end_timer: Optional[bs.Timer] = None + self._epic_mode = bool(settings['Epic Mode']) + self._lives_per_player = int(settings['Lives Per Player']) + self._time_limit = float(settings['Time Limit']) + self._balance_total_lives = bool( + settings.get('Balance Total Lives', False)) + self._solo_mode = bool(settings.get('Solo Mode', False)) + + # Base class overrides: + self.slow_motion = self._epic_mode + self.default_music = (bs.MusicType.EPIC + if self._epic_mode else bs.MusicType.SURVIVAL) + + self._tick_sound = bs.getsound('tick') + + def get_instance_description(self) -> Union[str, Sequence]: + return join_description + + def get_instance_description_short(self) -> Union[str, Sequence]: + return 'last team standing wins' if isinstance( + self.session, bs.DualTeamSession) else 'last one standing wins' + + def on_player_join(self, player: Player) -> None: + + # No longer allowing mid-game joiners here; too easy to exploit. + if self.has_begun(): + + # Make sure their team has survival seconds set if they're all dead + # (otherwise blocked new ffa players are considered 'still alive' + # in score tallying). + if (self._get_total_team_lives(player.team) == 0 + and player.team.survival_seconds is None): + player.team.survival_seconds = 0 + bs.broadcastmessage( + babase.Lstr(resource='playerDelayedJoinText', + subs=[('${PLAYER}', player.getname(full=True))]), + color=(0, 1, 0), + ) + return + + player.lives = self._lives_per_player + + if self._solo_mode: + player.team.spawn_order.append(player) + self._update_solo_mode() + else: + # Create our icon and spawn. + player.icons = [Icon(player, position=(0, 50), scale=0.8)] + if player.lives > 0: + self.spawn_player(player) + + # Don't waste time doing this until begin. + if self.has_begun(): + self._update_icons() + + def on_begin(self) -> None: + super().on_begin() + self._start_time = bs.time() + self.setup_standard_time_limit(self._time_limit) + #self.setup_standard_powerup_drops() + + bs.timer(5,self.spawn_zone) + self._bots = stdbot.SpazBotSet() + bs.timer(3,babase.Call(self.add_bot,'left')) + bs.timer(3,babase.Call(self.add_bot,'right')) + if len(self.initialplayerinfos) > 4: + bs.timer(5,babase.Call(self.add_bot,'right')) + bs.timer(5,babase.Call(self.add_bot,'left')) + + if self._solo_mode: + self._vs_text = bs.NodeActor( + bs.newnode('text', + attrs={ + 'position': (0, 105), + 'h_attach': 'center', + 'h_align': 'center', + 'maxwidth': 200, + 'shadow': 0.5, + 'vr_depth': 390, + 'scale': 0.6, + 'v_attach': 'bottom', + 'color': (0.8, 0.8, 0.3, 1.0), + 'text': babase.Lstr(resource='vsText') + })) + + # If balance-team-lives is on, add lives to the smaller team until + # total lives match. + if (isinstance(self.session, bs.DualTeamSession) + and self._balance_total_lives and self.teams[0].players + and self.teams[1].players): + if self._get_total_team_lives( + self.teams[0]) < self._get_total_team_lives(self.teams[1]): + lesser_team = self.teams[0] + greater_team = self.teams[1] + else: + lesser_team = self.teams[1] + greater_team = self.teams[0] + add_index = 0 + while (self._get_total_team_lives(lesser_team) < + self._get_total_team_lives(greater_team)): + lesser_team.players[add_index].lives += 1 + add_index = (add_index + 1) % len(lesser_team.players) + + self._update_icons() + + # We could check game-over conditions at explicit trigger points, + # but lets just do the simple thing and poll it. + bs.timer(1.0, self._update, repeat=True) + + def spawn_zone(self): + self.zone_pos = (random.randrange(-10,10),0.05,random.randrange(-5,5)) + self.zone = bs.newnode('locator',attrs={'shape':'circle','position':self.zone_pos,'color':(1, 1, 0),'opacity':0.8,'draw_beauty':True,'additive':False,'drawShadow':False}) + self.zone_limit = bs.newnode('locator',attrs={'shape':'circleOutline','position':self.zone_pos,'color':(1, 0.2, 0.2),'opacity':0.8,'draw_beauty':True,'additive':False,'drawShadow':False}) + bs.animate_array(self.zone, 'size', 1,{0:[0], 0.3:[self.get_players_count()*0.85], 0.35:[self.get_players_count()*0.8]}) + bs.animate_array(self.zone_limit, 'size', 1,{0:[0], 0.3:[self.get_players_count()*1.2], 0.35:[self.get_players_count()*0.95]}) + self.last_players_count = self.get_players_count() + bs.getsound('laserReverse').play() + self.start_timer() + self.move_zone() + + def delete_zone(self): + self.zone.delete() + self.zone = None + self.zone_limit.delete() + self.zone_limit = None + bs.getsound('shieldDown').play() + bs.timer(1,self.spawn_zone) + + def move_zone(self): + if self.zone_pos[0] > 0: x = random.randrange(0,10) + else: x = random.randrange(-10,0) + + if self.zone_pos[2] > 0: y = random.randrange(0,5) + else: y = random.randrange(-5,0) + + new_pos = (x,0.05,y) + bs.animate_array(self.zone, 'position', 3,{0:self.zone.position, 8:new_pos}) + bs.animate_array(self.zone_limit, 'position', 3,{0:self.zone_limit.position,8:new_pos}) + + def start_timer(self): + count = self.get_players_count() + self._time_remaining = 10 if count > 9 else count-1 if count > 6 else count if count > 2 else count*2 + self._timer_x = bs.Timer(1.0,bs.WeakCall(self.tick),repeat=True) + # gnode = bs.getactivity().globalsnode + # tint = gnode.tint + # bs.animate_array(gnode,'tint',3,{0:tint,self._time_remaining*1.5:(1.0,0.5,0.5),self._time_remaining*1.55:tint}) + + def stop_timer(self): + self._time = None + self._timer_x = None + + def tick(self): + self.check_players() + self._time = bs.NodeActor(bs.newnode('text', + attrs={'v_attach':'top','h_attach':'center', + 'text':kill_timer+str(self._time_remaining)+'s', + 'opacity':0.8,'maxwidth':100,'h_align':'center', + 'v_align':'center','shadow':1.0,'flatness':1.0, + 'color':(1,1,1),'scale':1.5,'position':(0,-50)} + ) + ) + self._time_remaining -= 1 + self._tick_sound.play() + + def check_players(self): + if self._time_remaining <= 0: + self.stop_timer() + bs.animate_array(self.zone, 'size', 1,{0:[self.last_players_count*0.8], 1.4:[self.last_players_count*0.8],1.5:[0]}) + bs.animate_array(self.zone_limit, 'size', 1,{0:[self.last_players_count*0.95], 1.45:[self.last_players_count*0.95],1.5:[0]}) + bs.timer(1.5,self.delete_zone) + for player in self.players: + if not player.actor is None: + if player.actor.is_alive(): + p1 = player.actor.node.position + p2 = self.zone.position + diff = (babase.Vec3(p1[0]-p2[0],0.0,p1[2]-p2[2])) + dist = (diff.length()) + if dist > (self.get_players_count()*0.7): + player.actor.handlemessage(bs.DieMessage()) + + def get_players_count(self): + count = 0 + for player in self.players: + if not player.actor is None: + if player.actor.is_alive(): + count += 1 + return count + + def _update_solo_mode(self) -> None: + # For both teams, find the first player on the spawn order list with + # lives remaining and spawn them if they're not alive. + for team in self.teams: + # Prune dead players from the spawn order. + team.spawn_order = [p for p in team.spawn_order if p] + for player in team.spawn_order: + assert isinstance(player, Player) + if player.lives > 0: + if not player.is_alive(): + self.spawn_player(player) + break + + def _update_icons(self) -> None: + # pylint: disable=too-many-branches + + # In free-for-all mode, everyone is just lined up along the bottom. + if isinstance(self.session, bs.FreeForAllSession): + count = len(self.teams) + x_offs = 85 + xval = x_offs * (count - 1) * -0.5 + for team in self.teams: + if len(team.players) == 1: + player = team.players[0] + for icon in player.icons: + icon.set_position_and_scale((xval, 30), 0.7) + icon.update_for_lives() + xval += x_offs + + # In teams mode we split up teams. + else: + if self._solo_mode: + # First off, clear out all icons. + for player in self.players: + player.icons = [] + + # Now for each team, cycle through our available players + # adding icons. + for team in self.teams: + if team.id == 0: + xval = -60 + x_offs = -78 + else: + xval = 60 + x_offs = 78 + is_first = True + test_lives = 1 + while True: + players_with_lives = [ + p for p in team.spawn_order + if p and p.lives >= test_lives + ] + if not players_with_lives: + break + for player in players_with_lives: + player.icons.append( + Icon(player, + position=(xval, (40 if is_first else 25)), + scale=1.0 if is_first else 0.5, + name_maxwidth=130 if is_first else 75, + name_scale=0.8 if is_first else 1.0, + flatness=0.0 if is_first else 1.0, + shadow=0.5 if is_first else 1.0, + show_death=is_first, + show_lives=False)) + xval += x_offs * (0.8 if is_first else 0.56) + is_first = False + test_lives += 1 + # Non-solo mode. + else: + for team in self.teams: + if team.id == 0: + xval = -50 + x_offs = -85 + else: + xval = 50 + x_offs = 85 + for player in team.players: + for icon in player.icons: + icon.set_position_and_scale((xval, 30), 0.7) + icon.update_for_lives() + xval += x_offs + + def _get_spawn_point(self, player: Player) -> Optional[babase.Vec3]: + del player # Unused. + + # In solo-mode, if there's an existing live player on the map, spawn at + # whichever spot is farthest from them (keeps the action spread out). + if self._solo_mode: + living_player = None + living_player_pos = None + for team in self.teams: + for tplayer in team.players: + if tplayer.is_alive(): + assert tplayer.node + ppos = tplayer.node.position + living_player = tplayer + living_player_pos = ppos + break + if living_player: + assert living_player_pos is not None + player_pos = babase.Vec3(living_player_pos) + points: List[Tuple[float, babase.Vec3]] = [] + for team in self.teams: + start_pos = babase.Vec3(self.map.get_start_position(team.id)) + points.append( + ((start_pos - player_pos).length(), start_pos)) + # Hmm.. we need to sorting vectors too? + points.sort(key=lambda x: x[0]) + return points[-1][1] + return None + + def spawn_player(self, player: Player) -> bs.Actor: + actor = self.spawn_player_spaz(player, self._get_spawn_point(player)) + if not self._solo_mode: + bs.timer(0.3, babase.Call(self._print_lives, player)) + + # spaz but *without* the ability to attack or pick stuff up. + actor.connect_controls_to_player(enable_punch=False, + enable_bomb=False, + enable_pickup=False) + + # If we have any icons, update their state. + for icon in player.icons: + icon.handle_player_spawned() + return actor + + def _print_lives(self, player: Player) -> None: + from bascenev1lib.actor import popuptext + + # We get called in a timer so it's possible our player has left/etc. + if not player or not player.is_alive() or not player.node: + return + + popuptext.PopupText('x' + str(player.lives - 1), + color=(1, 1, 0, 1), + offset=(0, -0.8, 0), + random_offset=0.0, + scale=1.8, + position=player.node.position).autoretain() + + def on_player_leave(self, player: Player) -> None: + super().on_player_leave(player) + player.icons = [] + + # Remove us from spawn-order. + if self._solo_mode: + if player in player.team.spawn_order: + player.team.spawn_order.remove(player) + + # Update icons in a moment since our team will be gone from the + # list then. + bs.timer(0, self._update_icons) + + # If the player to leave was the last in spawn order and had + # their final turn currently in-progress, mark the survival time + # for their team. + if self._get_total_team_lives(player.team) == 0: + assert self._start_time is not None + player.team.survival_seconds = int(bs.time() - self._start_time) + + def _get_total_team_lives(self, team: Team) -> int: + return sum(player.lives for player in team.players) + + def handlemessage(self, msg: Any) -> Any: + if isinstance(msg, bs.PlayerDiedMessage): + + # Augment standard behavior. + super().handlemessage(msg) + player: Player = msg.getplayer(Player) + + player.lives -= 1 + if player.lives < 0: + babase.print_error( + "Got lives < 0 in Elim; this shouldn't happen. solo:" + + str(self._solo_mode)) + player.lives = 0 + + # If we have any icons, update their state. + for icon in player.icons: + icon.handle_player_died() + + # Play big death sound on our last death + # or for every one in solo mode. + if self._solo_mode or player.lives == 0: + SpazFactory.get().single_player_death_sound.play() + + # If we hit zero lives, we're dead (and our team might be too). + if player.lives == 0: + # If the whole team is now dead, mark their survival time. + if self._get_total_team_lives(player.team) == 0: + assert self._start_time is not None + player.team.survival_seconds = int(bs.time() - + self._start_time) + else: + # Otherwise, in regular mode, respawn. + if not self._solo_mode: + self.respawn_player(player) + + # In solo, put ourself at the back of the spawn order. + if self._solo_mode: + player.team.spawn_order.remove(player) + player.team.spawn_order.append(player) + elif isinstance(msg,stdbot.SpazBotDiedMessage): + self._on_spaz_bot_died(msg) + + def _on_spaz_bot_died(self,die_msg): + bs.timer(1,babase.Call(self.add_bot,die_msg.spazbot.node.position)) + + def _on_bot_spawn(self,spaz): + spaz.update_callback = self.move_bot + spaz_type = type(spaz) + spaz._charge_speed = self._get_bot_speed(spaz_type) + + def add_bot(self,pos=None): + if pos == 'left': position = (-11,0,random.randrange(-5,5)) + elif pos == 'right': position = (11,0,random.randrange(-5,5)) + else: position = pos + self._bots.spawn_bot(self.get_random_bot(),pos=position,spawn_time=1,on_spawn_call=babase.Call(self._on_bot_spawn)) + + def move_bot(self,bot): + p = bot.node.position + speed = -bot._charge_speed if(p[0]>=-11 and p[0]<0) else bot._charge_speed + + if (p[0]>=-11) and (p[0]<=11): + bot.node.move_left_right = speed + bot.node.move_up_down = 0.0 + bot.node.run = 0.0 + return True + return False + + def get_random_bot(self): + bots = [stdbot.BomberBotStatic, stdbot.TriggerBotStatic] + return (random.choice(bots)) + + def _get_bot_speed(self, bot_type): + if bot_type == stdbot.BomberBotStatic: + return 0.48 + elif bot_type == stdbot.TriggerBotStatic: + return 0.73 + else: + raise Exception('Invalid bot type to _getBotSpeed(): '+str(bot_type)) + + def _update(self) -> None: + if self._solo_mode: + # For both teams, find the first player on the spawn order + # list with lives remaining and spawn them if they're not alive. + for team in self.teams: + # Prune dead players from the spawn order. + team.spawn_order = [p for p in team.spawn_order if p] + for player in team.spawn_order: + assert isinstance(player, Player) + if player.lives > 0: + if not player.is_alive(): + self.spawn_player(player) + self._update_icons() + break + + # If we're down to 1 or fewer living teams, start a timer to end + # the game (allows the dust to settle and draws to occur if deaths + # are close enough). + if len(self._get_living_teams()) < 2: + self._round_end_timer = bs.Timer(0.5, self.end_game) + + def _get_living_teams(self) -> List[Team]: + return [ + team for team in self.teams + if len(team.players) > 0 and any(player.lives > 0 + for player in team.players) + ] + + def end_game(self) -> None: + if self.has_ended(): + return + results = bs.GameResults() + self._vs_text = None # Kill our 'vs' if its there. + for team in self.teams: + results.set_team_score(team, team.survival_seconds) + self.end(results=results) diff --git a/plugins/utilities.json b/plugins/utilities.json index 5404ffd6..0b16c155 100644 --- a/plugins/utilities.json +++ b/plugins/utilities.json @@ -986,6 +986,62 @@ "md5sum": "5fa8706f36d618f8302551dd2a0403a0" } } - } + }, + "disable_friendly_fire": { + "description": "Disables friendly fire", + "external_url": "", + "authors": [ + { + "name": "EmperoR", + "email": "", + "discord": "EmperoR#4098" + } + ], + "versions": { + "1.0.0": null + } + }, + "infinityShield": { + "description": "Gives you unbreakable shield", + "external_url": "https://youtu.be/hp7vbB-hUPg?si=i7Th0NP5xDPLN2P_", + "authors": [ + { + "name": "JoseAng3l", + "email": "", + "discord": "joseang3l" + } + ], + "versions": { + "1.0.0": null + } + }, + "OnlyNight": { + "description": "Night Mode", + "external_url": "", + "authors": [ + { + "name": "", + "email": "", + "discord": "" + } + ], + "versions": { + "1.0.0": null + } + }, + "Tag": { + "description": "Get a tag", + "external_url": "", + "authors": [ + { + "name": "pranav", + "email": "", + "discord": "" + } + ], + "versions": { + "2.0.1": null + } + } } } \ No newline at end of file diff --git a/plugins/utilities/InfinityShield.py b/plugins/utilities/InfinityShield.py new file mode 100644 index 00000000..a224ba3f --- /dev/null +++ b/plugins/utilities/InfinityShield.py @@ -0,0 +1,81 @@ +# Ported to api 8 by brostos using baport.(https://github.com/bombsquad-community/baport) +# ba_meta require api 8 +# (see https://ballistica.net/wiki/meta-tag-system) + +from __future__ import annotations + +from typing import TYPE_CHECKING + +import babase +import bauiv1 as bui +import bascenev1 as bs +import random +from bascenev1lib.actor.spaz import Spaz +from bascenev1lib.actor.spazfactory import SpazFactory + +if TYPE_CHECKING: + pass + + +Spaz._old_init = Spaz.__init__ +def __init__(self, + color: Sequence[float] = (1.0, 1.0, 1.0), + highlight: Sequence[float] = (0.5, 0.5, 0.5), + character: str = 'Spaz', + source_player: bs.Player = None, + start_invincible: bool = True, + can_accept_powerups: bool = True, + powerups_expire: bool = False, + demo_mode: bool = False): + self._old_init(color,highlight,character,source_player,start_invincible, + can_accept_powerups,powerups_expire,demo_mode) + if self.source_player: + self.equip_shields() + def animate_shield(): + if not self.shield: + return + bs.animate_array(self.shield, 'color', 3, { + 0.0: self.shield.color, + 0.2: (random.random(), random.random(), random.random()) + }) + bs.timer(0.2, animate_shield, repeat=True) + self.impact_scale = 0 + +def equip_shields(self, decay: bool = False) -> None: + """ + Give this spaz a nice energy shield. + """ + + if not self.node: + babase.print_error('Can\'t equip shields; no node.') + return + + factory = SpazFactory.get() + if self.shield is None: + self.shield = bs.newnode('shield', + owner=self.node, + attrs={ + 'color': (0.3, 0.2, 2.0), + 'radius': 1.3 + }) + self.node.connectattr('position_center', self.shield, 'position') + self.shield_hitpoints = self.shield_hitpoints_max = 650 + self.shield_decay_rate = factory.shield_decay_rate if decay else 0 + self.shield.hurt = 0 + factory.shield_up_sound.play(1.0, position=self.node.position) + + if self.impact_scale == 0: + return + + if self.shield_decay_rate > 0: + self.shield_decay_timer = bs.Timer(0.5, + bs.WeakCall(self.shield_decay), + repeat=True) + # So user can see the decay. + self.shield.always_show_health_bar = True + + +# ba_meta export plugin +class InfinityShieldPlugin(babase.Plugin): + Spaz.__init__ = __init__ + Spaz.equip_shields = equip_shields diff --git a/plugins/utilities/OnlyNight.py b/plugins/utilities/OnlyNight.py new file mode 100644 index 00000000..b3376476 --- /dev/null +++ b/plugins/utilities/OnlyNight.py @@ -0,0 +1,50 @@ +# Ported by brostos to api 8 +# Tool used to make porting easier.(https://github.com/bombsquad-community/baport) +"""Only Night.""" + +# ba_meta require api 8 + +from __future__ import annotations + +from typing import TYPE_CHECKING + +import babase +import bascenev1 as bs +from bascenev1._gameactivity import GameActivity + +if TYPE_CHECKING: + pass + + +# ba_meta export plugin +class OnlyNight(babase.Plugin): + GameActivity.old_on_transition_in = GameActivity.on_transition_in + + def new_on_transition_in(self) -> None: + self.old_on_transition_in() + gnode = bs.getactivity().globalsnode + if self.map.getname() in [ + "Monkey Face", + "Rampage", + "Roundabout", + "Step Right Up", + "Tip Top", + "Zigzag", + "The Pad", + ]: + gnode.tint = (0.4, 0.4, 0.4) + elif self.map.getname() in [ + "Big G", + "Bridgit", + "Courtyard", + "Crag Castle", + "Doom Shroom", + "Football Stadium", + "Happy Thoughts", + "Hockey Stadium", + ]: + gnode.tint = (0.5, 0.5, 0.5) + else: + gnode.tint = (0.3, 0.3, 0.3) + + GameActivity.on_transition_in = new_on_transition_in diff --git a/plugins/utilities/Tag.py b/plugins/utilities/Tag.py new file mode 100644 index 00000000..4ec9a9d4 --- /dev/null +++ b/plugins/utilities/Tag.py @@ -0,0 +1,565 @@ +# Ported by brostos to api 8 +# Tool used to make porting easier.(https://github.com/bombsquad-community/baport) +""" +I apreciate any kind of modification. So feel free to use or edit code or change credit string.... no problem. + +really awsome servers: + Bombsquad Consultancy Service - https://discord.gg/2RKd9QQdQY + bombspot - https://discord.gg/ucyaesh + cyclones - https://discord.gg/pJXxkbQ7kH + +how to use: + Account -> PlayerProfile -> Edit(new profile -> edit) + Open profile you like (every profile has dirrent tags, settings (Configs)) + enable tag for profile you like, edit tag you want. enable cool flashy animation +""" + +from __future__ import annotations +from bauiv1lib.profile.edit import EditProfileWindow +from bauiv1lib.colorpicker import ColorPicker +from bauiv1lib.popup import PopupMenu +from bascenev1lib.actor.playerspaz import PlayerSpaz +from baenv import TARGET_BALLISTICA_BUILD as build_number +import babase +import bauiv1 as bui +import bascenev1 as bs +import _babase + +from typing import ( + Tuple, + Optional, + Sequence, + Union, + Callable, + Any, + List, + cast +) + +__version__ = 2.0 +__author__ = "pranav1711#2006" + + +# Default Confings/Settings +Configs = { + "enabletag": False, + "tag": "", + "scale": "medium", + "opacity": 1.0, + "shadow": 0.0, + "animtag": False, + "frequency": 0.5 +} + +# Useful global fucntions +def setconfigs() -> None: + """ + Set required defualt configs for mod + """ + cnfg = babase.app.config + profiles = cnfg['Player Profiles'] + if not "TagConf" in cnfg: cnfg["TagConf"] = {} + for p in profiles: + if not p in cnfg["TagConf"]: + cnfg["TagConf"][str(p)] = Configs + babase.app.config.apply_and_commit() + +def getanimcolor(name: str) -> dict: + """ + Returns dictnary of colors with prefective time -> {seconds: (r, g, b)} + """ + freq = babase.app.config['TagConf'][str(name)]['frequency'] + s1 = 0.0 + s2 = s1 + freq + s3 = s2 + freq + + animcolor = { + s1: (1,0,0), + s2: (0,1,0), + s3: (0,0,1) + } + return animcolor + +def gethostname() -> str: + """ + Return player name, by using -1 only host can use tags. + """ + session = bs.get_foreground_host_session() + with session.context: + for player in session.sessionplayers: + if player.inputdevice.client_id == -1: + name = player.getname(full=True, icon=False) + break + if name == bui.app.plus.get_v1_account_name: + return '__account__' + return name + +# Dummy functions for extend functionality for class object +PlayerSpaz.init = PlayerSpaz.__init__ +EditProfileWindow.init = EditProfileWindow.__init__ + +# PlayerSpaz object at -> bascenev1lib.actor.playerspaz +def NewPlayerSzapInit(self, + player: bs.Player, + color: Sequence[float] = (1.0, 1.0, 1.0), + highlight: Sequence[float] = (0.5, 0.5, 0.5), + character: str = 'Spaz', + powerups_expire: bool = True) -> None: + self.init(player, color, highlight, character, powerups_expire) + self.curname = gethostname() + + try: + cnfg = babase.app.config["TagConf"] + if cnfg[str(self.curname)]["enabletag"]: + # Tag node + self.mnode = bs.newnode('math', owner=self.node, attrs={'input1': (0, 1.5, 0),'operation': 'add'}) + self.node.connectattr('torso_position', self.mnode, 'input2') + + tagtext = cnfg[str(self.curname)]["tag"] + opacity = cnfg[str(self.curname)]["opacity"] + shadow = cnfg[str(self.curname)]["shadow"] + sl = cnfg[str(self.curname)]["scale"] + scale = 0.01 if sl == 'mediam' else 0.009 if not sl == 'large' else 0.02 + + self.Tag = bs.newnode( + type='text', + owner=self.node, + attrs={ + 'text': str(tagtext), + 'in_world': True, + 'shadow': shadow, + 'color': (0,0,0), + 'scale': scale, + 'opacity': opacity, + 'flatness': 1.0, + 'h_align': 'center'}) + self.mnode.connectattr('output', self.Tag, 'position') + + if cnfg[str(self.curname)]["animtag"]: + kys = getanimcolor(self.curname) + bs.animate_array(node=self.Tag, attr='color', size=3, keys=kys, loop=True) + except Exception: pass + + +def NewEditProfileWindowInit(self, + existing_profile: Optional[str], + in_main_menu: bool, + transition: str = 'in_right') -> None: + """ + New boilerplate for editprofilewindow, addeds button to call TagSettings window + """ + self.existing_profile = existing_profile + self.in_main_menu = in_main_menu + self.init(existing_profile, in_main_menu, transition) + + v = self._height - 115.0 + x_inset = self._x_inset + b_width = 50 + b_height = 30 + + self.tagwinbtn = bui.buttonwidget( + parent=self._root_widget, + autoselect=True, + position=(505 + x_inset, v - 38 - 15), + size=(b_width, b_height), + color=(0.6, 0.5, 0.6), + label='Tag', + button_type='square', + text_scale=1.2, + on_activate_call=babase.Call(_on_tagwinbtn_press, self)) + +def _on_tagwinbtn_press(self): + """ + Calls tag config window passes all paramisters + """ + bui.containerwidget(edit=self._root_widget, transition='out_scale') + bui.app.ui_v1.set_main_menu_window( + TagWindow(self.existing_profile, + self.in_main_menu, + self._name, + transition='in_right').get_root_widget(), from_window=self._root_widget) + + +# ba_meta require api 8 +# ba_meta export plugin +class Tag(babase.Plugin): + def __init__(self) -> None: + """ + Tag above actor player head, replacing PlayerSpaz class for getting actor, + using EditProfileWindow for UI. + """ + if _babase.env().get("build_number",0) >= 20327: + setconfigs() + self.Replace() + + def Replace(self) -> None: + """ + Replacing bolierplates no harm to relative funtionality only extending + """ + PlayerSpaz.__init__ = NewPlayerSzapInit + EditProfileWindow.__init__ = NewEditProfileWindowInit + + +class TagWindow(bui.Window): + + def __init__(self, + existing_profile: Optional[str], + in_main_menu: bool, + profilename: str, + transition: Optional[str] = 'in_right'): + self.existing_profile = existing_profile + self.in_main_menu = in_main_menu + self.profilename = profilename + + uiscale = bui.app.ui_v1.uiscale + self._width = 870.0 if uiscale is babase.UIScale.SMALL else 670.0 + self._height = (390.0 if uiscale is babase.UIScale.SMALL else + 450.0 if uiscale is babase.UIScale.MEDIUM else 520.0) + extra_x = 100 if uiscale is babase.UIScale.SMALL else 0 + self.extra_x = extra_x + top_extra = 20 if uiscale is babase.UIScale.SMALL else 0 + + super().__init__( + root_widget=bui.containerwidget( + size=(self._width, self._height), + transition=transition, + scale=(2.06 if uiscale is babase.UIScale.SMALL else + 1.4 if uiscale is babase.UIScale.MEDIUM else 1.0))) + + self._back_button = bui.buttonwidget( + parent=self._root_widget, + autoselect=True, + selectable=False, # FIXME: when press a in text field it selets to button + position=(52 + self.extra_x, self._height - 60), + size=(60, 60), + scale=0.8, + label=babase.charstr(babase.SpecialChar.BACK), + button_type='backSmall', + on_activate_call=self._back) + bui.containerwidget(edit=self._root_widget, cancel_button=self._back_button) + + self._save_button = bui.buttonwidget( + parent=self._root_widget, + position=(self._width - (177 + extra_x), + self._height - 60), + size=(155, 60), + color=(0, 0.7, 0.5), + autoselect=True, + selectable=False, # FIXME: when press a in text field it selets to button + scale=0.8, + label=babase.Lstr(resource='saveText'), + on_activate_call=self.on_save) + bui.widget(edit=self._save_button, left_widget=self._back_button) + bui.widget(edit=self._back_button, right_widget=self._save_button) + bui.containerwidget(edit=self._root_widget, start_button=self._save_button) + + self._title_text = bui.textwidget( + parent=self._root_widget, + position=(0, self._height - 52 - top_extra), + size=(self._width, 25), + text='Tag', + color=bui.app.ui_v1.title_color, + scale=1.5, + h_align='center', + v_align='top') + + self._scroll_width = self._width - (100 + 2 * extra_x) + self._scroll_height = self._height - 115.0 + self._sub_width = self._scroll_width * 0.95 + self._sub_height = 724.0 + self._spacing = 32 + self._extra_button_spacing = self._spacing * 2.5 + + self._scrollwidget = bui.scrollwidget( + parent=self._root_widget, + position=(50 + extra_x, 50), + simple_culling_v=20.0, + highlight=False, + size=(self._scroll_width, + self._scroll_height), + selection_loops_to_parent=True) + bui.widget(edit=self._scrollwidget, right_widget=self._scrollwidget) + + self._subcontainer = bui.containerwidget( + parent=self._scrollwidget, + size=(self._sub_width, + self._sub_height), + background=False, + selection_loops_to_parent=True) + + v = self._sub_height - 35 + v -= self._spacing * 1.2 + + self._prof = babase.app.config["TagConf"][self.profilename] + self.enabletagcb = bui.checkboxwidget( + parent=self._subcontainer, + autoselect=False, + position=(10.0, v + 30), + size=(10, 10), + text='Enable Tag', + textcolor=(0.8, 0.8, 0.8), + value=self._prof['enabletag'], + on_value_change_call=babase.Call(self.change_val, [f'{self.profilename}', 'enabletag']), + scale=1.1 if uiscale is babase.UIScale.SMALL else 1.5, + maxwidth=430) + + self.tag_text = bui.textwidget( + parent=self._subcontainer, + text='Tag', + position=(25.0, v - 30), + flatness=1.0, + scale=1.55, + maxwidth=430, + h_align='center', + v_align='center', + color=(0.8, 0.8, 0.8)) + + self.tagtextfield = bui.textwidget( + parent=self._subcontainer, + position=(100.0, v - 45), + size=(350, 50), + text=self._prof["tag"], + h_align='center', + v_align='center', + max_chars=16, + autoselect=True, + editable=True, + padding=4, + color=(0.9, 0.9, 0.9, 1.0)) + + self.tag_color_text = bui.textwidget( + parent=self._subcontainer, + text='Color', + position=(40.0, v - 80), + flatness=1.0, + scale=1.25, + maxwidth=430, + h_align='center', + v_align='center', + color=(0.8, 0.8, 0.8)) + + self.tag_scale_text = bui.textwidget( + parent=self._subcontainer, + text='Scale', + position=(40.0, v - 130), + flatness=1.0, + scale=1.25, + maxwidth=430, + h_align='center', + v_align='center', + color=(0.8, 0.8, 0.8)) + + self.tag_scale_button = PopupMenu( + parent=self._subcontainer, + position=(330.0, v - 145), + width=150, + autoselect=True, + on_value_change_call=bs.WeakCall(self._on_menu_choice), + choices=['large', 'medium', 'small'], + button_size=(150, 50), + #choices_display=('large', 'medium', 'small'), + current_choice=self._prof["scale"]) + + CustomConfigNumberEdit( + parent=self._subcontainer, + position=(40.0, v - 180), + xoffset=65, + displayname='Opacity', + configkey=['TagConf', f'{self.profilename}', 'opacity'], + changesound=False, + minval=0.5, + maxval=2.0, + increment=0.1, + textscale=1.25) + + CustomConfigNumberEdit( + parent=self._subcontainer, + position=(40.0, v - 230), + xoffset=65, + displayname='Shadow', + configkey=['TagConf', f'{self.profilename}', 'shadow'], + changesound=False, + minval=0.0, + maxval=2.0, + increment=0.1, + textscale=1.25) + + self.enabletaganim = bui.checkboxwidget( + parent=self._subcontainer, + autoselect=True, + position=(10.0, v - 280), + size=(10, 10), + text='Animate tag', + textcolor=(0.8, 0.8, 0.8), + value=self._prof['enabletag'], + on_value_change_call=babase.Call(self.change_val, [f'{self.profilename}', 'animtag']), + scale=1.1 if uiscale is babase.UIScale.SMALL else 1.5, + maxwidth=430) + + CustomConfigNumberEdit( + parent=self._subcontainer, + position=(40.0, v - 330), + xoffset=65, + displayname='Frequency', + configkey=['TagConf', f'{self.profilename}', 'frequency'], + changesound=False, + minval=0.1, + maxval=5.0, + increment=0.1, + textscale=1.25) + + def _back(self) -> None: + """ + transit window into back window + """ + bui.containerwidget(edit=self._root_widget, + transition='out_scale') + bui.app.ui_v1.set_main_menu_window(EditProfileWindow( + self.existing_profile, + self.in_main_menu, + transition='in_left').get_root_widget(), from_window=self._root_widget) + + def change_val(self, config: List[str], val: bool) -> None: + """ + chamges the value of check boxes + """ + cnfg = babase.app.config["TagConf"] + try: + cnfg[config[0]][config[1]] = val + bui.getsound('gunCocking').play() + except Exception: + bui.screenmessage("error", color=(1,0,0)) + bui.getsound('error').play() + babase.app.config.apply_and_commit() + + def _on_menu_choice(self, choice: str): + """ + Changes the given choice in configs + """ + cnfg = babase.app.config["TagConf"][self.profilename] + cnfg["scale"] = choice + babase.app.config.apply_and_commit() + + def on_save(self): + """ + Gets the text in text field of tag and then save it + """ + text: str = cast(str, bui.textwidget(query=self.tagtextfield)) + profile = babase.app.config["TagConf"][self.profilename] + if not text == "" or not text.strip(): + profile['tag'] = text + babase.app.config.apply_and_commit() + bui.getsound('gunCocking').play() + else: + bui.screenmessage(f"please define tag", color=(1,0,0)) + bui.getsound('error').play() + + bui.containerwidget(edit=self._root_widget, + transition='out_scale') + bui.app.ui_v1.set_main_menu_window(EditProfileWindow( + self.existing_profile, + self.in_main_menu, + transition='in_left').get_root_widget(), from_window=self._root_widget) + + +class CustomConfigNumberEdit: + """A set of controls for editing a numeric config value. + + It will automatically save and apply the config when its + value changes. + + Attributes: + + nametext + The text widget displaying the name. + + valuetext + The text widget displaying the current value. + + minusbutton + The button widget used to reduce the value. + + plusbutton + The button widget used to increase the value. + """ + + def __init__(self, + parent: bui.Widget, + configkey: List[str], + position: Tuple[float, float], + minval: float = 0.0, + maxval: float = 100.0, + increment: float = 1.0, + callback: Callable[[float], Any] = None, + xoffset: float = 0.0, + displayname: Union[str, babase.Lstr] = None, + changesound: bool = True, + textscale: float = 1.0): + self._minval = minval + self._maxval = maxval + self._increment = increment + self._callback = callback + self._configkey = configkey + self._value = babase.app.config[configkey[0]][configkey[1]][configkey[2]] + + self.nametext = bui.textwidget( + parent=parent, + position=position, + size=(100, 30), + text=displayname, + maxwidth=160 + xoffset, + color=(0.8, 0.8, 0.8, 1.0), + h_align='left', + v_align='center', + scale=textscale) + + self.valuetext = bui.textwidget( + parent=parent, + position=(246 + xoffset, position[1]), + size=(60, 28), + editable=False, + color=(0.3, 1.0, 0.3, 1.0), + h_align='right', + v_align='center', + text=str(self._value), + padding=2) + + self.minusbutton = bui.buttonwidget( + parent=parent, + position=(330 + xoffset, position[1]), + size=(28, 28), + label='-', + autoselect=True, + on_activate_call=babase.Call(self._down), + repeat=True, + enable_sound=changesound) + + self.plusbutton = bui.buttonwidget(parent=parent, + position=(380 + xoffset, position[1]), + size=(28, 28), + label='+', + autoselect=True, + on_activate_call=babase.Call(self._up), + repeat=True, + enable_sound=changesound) + + bui.uicleanupcheck(self, self.nametext) + self._update_display() + + def _up(self) -> None: + self._value = min(self._maxval, self._value + self._increment) + self._changed() + + def _down(self) -> None: + self._value = max(self._minval, self._value - self._increment) + self._changed() + + def _changed(self) -> None: + self._update_display() + if self._callback: + self._callback(self._value) + babase.app.config[self._configkey[0]][self._configkey[1]][self._configkey[2]] = float(str(f'{self._value:.1f}')) + babase.app.config.apply_and_commit() + + def _update_display(self) -> None: + bui.textwidget(edit=self.valuetext, text=f'{self._value:.1f}') \ No newline at end of file diff --git a/plugins/utilities/disable_friendly_fire.py b/plugins/utilities/disable_friendly_fire.py new file mode 100644 index 00000000..0771cfe5 --- /dev/null +++ b/plugins/utilities/disable_friendly_fire.py @@ -0,0 +1,108 @@ +# Ported to api 8 by brostos using baport.(https://github.com/bombsquad-community/baport) +# ba_meta require api 8 +from __future__ import annotations +from typing import TYPE_CHECKING + +import babase +import bauiv1 as bui +import bascenev1 as bs +import bascenev1lib +from bascenev1lib.gameutils import SharedObjects + +if TYPE_CHECKING: + pass + +class BombPickupMessage: + """ message says that someone pick up the dropped bomb """ + +# for bs.FreezeMessage +freeze: bool = True + +# ba_meta export plugin +class Plugin(babase.Plugin): + + # there are two ways to ignore our team player hits + # either change playerspaz handlemessage or change spaz handlemessage + def playerspaz_new_handlemessage(func: fuction) -> fuction: + def wrapper(*args, **kwargs): + global freeze + + # only run if session is dual team + if isinstance(args[0].activity.session, bs.DualTeamSession): + # when spaz got hurt by any reason this statement is runs. + if isinstance(args[1], bs.HitMessage): + our_team_players: list[type(args[0]._player)] + + # source_player + attacker = args[1].get_source_player(type(args[0]._player)) + + # our team payers + our_team_players = args[0]._player.team.players.copy() + + if len(our_team_players) > 0: + + # removing our self + our_team_players.remove(args[0]._player) + + # if we honding teammate or if we have a shield, do hit. + for player in our_team_players: + if player.actor.exists() and args[0]._player.actor.exists(): + if args[0]._player.actor.node.hold_node == player.actor.node or args[0]._player.actor.shield: + our_team_players.remove(player) + break + + if attacker in our_team_players: + freeze = False + return None + else: + freeze = True + + # if ice_bomb blast hits any spaz this statement runs. + elif isinstance(args[1], bs.FreezeMessage): + if not freeze: + freeze = True # use it and reset it + return None + + # orignal unchanged code goes here + func(*args, **kwargs) + + return wrapper + + # replace original fuction to modified function + bascenev1lib.actor.playerspaz.PlayerSpaz.handlemessage = playerspaz_new_handlemessage( + bascenev1lib.actor.playerspaz.PlayerSpaz.handlemessage) + + # let's add a message when bomb is pick by player + def bombfact_new_init(func: function) -> function: + def wrapper(*args): + + func(*args) # original code + + args[0].bomb_material.add_actions( + conditions=('they_have_material', SharedObjects.get().pickup_material), + actions=('message', 'our_node', 'at_connect', BombPickupMessage()), + ) + return wrapper + + # you get the idea + bascenev1lib.actor.bomb.BombFactory.__init__ = bombfact_new_init( + bascenev1lib.actor.bomb.BombFactory.__init__) + + def bomb_new_handlemessage(func: function) -> function: + def wrapper(*args, **kwargs): + # only run if session is dual team + if isinstance(args[0].activity.session, bs.DualTeamSession): + if isinstance(args[1], BombPickupMessage): + # get the pickuper and assign the pickuper to the source_player(attacker) of bomb blast + for player in args[0].activity.players: + if player.actor.exists(): + if player.actor.node.hold_node == args[0].node: + args[0]._source_player = player + break + + func(*args, **kwargs) # original + + return wrapper + + bascenev1lib.actor.bomb.Bomb.handlemessage = bomb_new_handlemessage( + bascenev1lib.actor.bomb.Bomb.handlemessage) \ No newline at end of file From 36673fc3683f0a1f87232862e518592128bc0730 Mon Sep 17 00:00:00 2001 From: brostosjoined Date: Wed, 24 Jan 2024 11:26:19 +0000 Subject: [PATCH 0825/1464] [ci] auto-format --- plugins/minigames/EggGame.py | 128 +-- plugins/minigames/HYPER_RACE.py | 85 +- plugins/minigames/SnowBallFight.py | 1196 ++++++++++---------- plugins/minigames/ofuuuAttack.py | 304 ++--- plugins/minigames/safe_zone.py | 157 +-- plugins/utilities/InfinityShield.py | 8 +- plugins/utilities/Tag.py | 502 ++++---- plugins/utilities/disable_friendly_fire.py | 78 +- 8 files changed, 1269 insertions(+), 1189 deletions(-) diff --git a/plugins/minigames/EggGame.py b/plugins/minigames/EggGame.py index e2d2030e..4c0ffc13 100644 --- a/plugins/minigames/EggGame.py +++ b/plugins/minigames/EggGame.py @@ -4,8 +4,8 @@ """Egg game and support classes.""" # The Egg Game - throw egg as far as you can -# created in BCS (Bombsquad Consultancy Service) - opensource bombsquad mods for all -# discord.gg/ucyaesh join now and give your contribution +# created in BCS (Bombsquad Consultancy Service) - opensource bombsquad mods for all +# discord.gg/ucyaesh join now and give your contribution # The Egg game by mr.smoothy # ba_meta require api 8 # (see https://ballistica.net/wiki/meta-tag-system) @@ -45,14 +45,14 @@ def __init__(self, position: Sequence[float] = (0.0, 1.0, 0.0)): # Spawn just above the provided point. self._spawn_pos = (position[0], position[1] + 1.0, position[2]) - self.last_players_to_touch =None + self.last_players_to_touch = None self.scored = False self.egg_mesh = bs.getmesh('egg') self.egg_tex_1 = bs.gettexture('eggTex1') self.egg_tex_2 = bs.gettexture('eggTex2') self.egg_tex_3 = bs.gettexture('eggTex3') - self.eggtx=[self.egg_tex_1,self.egg_tex_2,self.egg_tex_3] - regg=random.randrange(0,3) + self.eggtx = [self.egg_tex_1, self.egg_tex_2, self.egg_tex_3] + regg = random.randrange(0, 3) assert activity is not None assert isinstance(activity, EggGame) pmats = [shared.object_material, activity.puck_material] @@ -65,7 +65,7 @@ def __init__(self, position: Sequence[float] = (0.0, 1.0, 0.0)): 'reflection': 'soft', 'reflection_scale': [0.2], 'shadow_size': 0.5, - 'body_scale':0.7, + 'body_scale': 0.7, 'is_area_of_interest': True, 'position': self._spawn_pos, 'materials': pmats @@ -180,14 +180,14 @@ def __init__(self, settings: dict): self.puck_scored_tex = bs.gettexture('landMineLit') self._puck_sound = bui.getsound('metalHit') self.puck_material = bs.Material() - self._fake_wall_material=bs.Material() - self.HIGHEST=0 + self._fake_wall_material = bs.Material() + self.HIGHEST = 0 self._fake_wall_material.add_actions( conditions=('they_have_material', shared.player_material), actions=( ('modify_part_collision', 'collide', True), ('modify_part_collision', 'physical', True) - + )) self.puck_material.add_actions(actions=(('modify_part_collision', 'friction', 0.5))) @@ -232,8 +232,8 @@ def __init__(self, settings: dict): actions=(('modify_part_collision', 'collide', True), ('modify_part_collision', 'physical', False), ('call', 'at_connect', self._handle_score))) - self.main_ground_material= bs.Material() - + self.main_ground_material = bs.Material() + self.main_ground_material.add_actions( conditions=('they_have_material', self.puck_material), actions=(('modify_part_collision', 'collide', @@ -243,7 +243,7 @@ def __init__(self, settings: dict): self._puck_spawn_pos: Optional[Sequence[float]] = None self._score_regions: Optional[List[bs.NodeActor]] = None self._puck: Optional[Puck] = None - self._pucks=[] + self._pucks = [] self._score_to_win = int(settings['Score to Win']) self._time_limit = float(settings['Time Limit']) @@ -255,8 +255,8 @@ def get_instance_description_short(self) -> Union[str, Sequence]: def on_begin(self) -> None: super().on_begin() - if self._time_limit==0.0: - self._time_limit=60 + if self._time_limit == 0.0: + self._time_limit = 60 self.setup_standard_time_limit(self._time_limit) # self.setup_standard_powerup_drops() self._puck_spawn_pos = self.map.get_flag_position(None) @@ -269,10 +269,10 @@ def on_begin(self) -> None: # Set up the two score regions. defs = self.map.defs self._score_regions = [] - pos=(11.88630542755127, 0.3009839951992035, 1.33331298828125) + pos = (11.88630542755127, 0.3009839951992035, 1.33331298828125) # mat=bs.Material() # mat.add_actions( - + # actions=( ('modify_part_collision','physical',True), # ('modify_part_collision','collide',True)) # ) @@ -299,13 +299,14 @@ def on_begin(self) -> None: bs.NodeActor( bs.newnode('region', attrs={ - 'position': (-9.21,defs.boxes['goal2'][0:3][1],defs.boxes['goal2'][0:3][2]), + 'position': (-9.21, defs.boxes['goal2'][0:3][1], defs.boxes['goal2'][0:3][2]), 'scale': defs.boxes['goal2'][6:9], 'type': 'box', 'materials': (self._fake_wall_material, ) }))) - pos=(0,0.1,-5) - self.main_ground=bs.newnode('region',attrs={'position': pos,'scale': (25,0.001,22),'type': 'box','materials': [self.main_ground_material]}) + pos = (0, 0.1, -5) + self.main_ground = bs.newnode('region', attrs={'position': pos, 'scale': ( + 25, 0.001, 22), 'type': 'box', 'materials': [self.main_ground_material]}) self._update_scoreboard() self._chant_sound.play() @@ -326,63 +327,63 @@ def _handle_puck_player_collide(self) -> None: def _kill_puck(self) -> None: self._puck = None + def _handle_egg_collision(self) -> None: - no=bs.getcollision().opposingnode - pos=no.position - egg=no.getdelegate(Puck) - source_player=egg.last_players_to_touch - if source_player==None or pos[0]< -8 or not source_player.node.exists() : + no = bs.getcollision().opposingnode + pos = no.position + egg = no.getdelegate(Puck) + source_player = egg.last_players_to_touch + if source_player == None or pos[0] < -8 or not source_player.node.exists(): return - try: - col=source_player.team.color - self.flagg=Flag(pos,touchable=False,color=col).autoretain() - self.flagg.is_area_of_interest=True - player_pos=source_player.node.position - - distance = math.sqrt( pow(player_pos[0]-pos[0],2) + pow(player_pos[2]-pos[2],2)) - - - dis_mark=bs.newnode('text', - - attrs={ - 'text':str(round(distance,2))+"m", - 'in_world':True, - 'scale':0.02, - 'h_align':'center', - 'position':(pos[0],1.6,pos[2]), - 'color':col - }) - bs.animate(dis_mark,'scale',{ - 0.0:0, 0.5:0.01 + col = source_player.team.color + self.flagg = Flag(pos, touchable=False, color=col).autoretain() + self.flagg.is_area_of_interest = True + player_pos = source_player.node.position + + distance = math.sqrt(pow(player_pos[0]-pos[0], 2) + pow(player_pos[2]-pos[2], 2)) + + dis_mark = bs.newnode('text', + + attrs={ + 'text': str(round(distance, 2))+"m", + 'in_world': True, + 'scale': 0.02, + 'h_align': 'center', + 'position': (pos[0], 1.6, pos[2]), + 'color': col + }) + bs.animate(dis_mark, 'scale', { + 0.0: 0, 0.5: 0.01 }) if distance > self.HIGHEST: - self.HIGHEST=distance + self.HIGHEST = distance self.stats.player_scored( - source_player, - 10, - big_message=False) - + source_player, + 10, + big_message=False) + no.delete() - bs.timer(2,self._spawn_puck) - source_player.team.score=int(distance) - - except(): + bs.timer(2, self._spawn_puck) + source_player.team.score = int(distance) + + except (): pass + def spawn_player(self, player: Player) -> bs.Actor: - - - zoo=random.randrange(-4,5) - pos=(-11.204887390136719, 0.2998693287372589, zoo) + + zoo = random.randrange(-4, 5) + pos = (-11.204887390136719, 0.2998693287372589, zoo) spaz = self.spawn_player_spaz( - player, position=pos, angle=90 ) + player, position=pos, angle=90) assert spaz.node # Prevent controlling of characters before the start of the race. - + return spaz + def _handle_score(self) -> None: """A point has been scored.""" @@ -481,11 +482,12 @@ def _flash_puck_spawn(self) -> None: # bs.animate(light, 'intensity', {0.0: 0, 0.25: 1, 0.5: 0}, loop=True) # bs.timer(1.0, light.delete) pass + def _spawn_puck(self) -> None: # self._swipsound.play() # self._whistle_sound.play() self._flash_puck_spawn() assert self._puck_spawn_pos is not None - zoo=random.randrange(-5,6) - pos=(-11.204887390136719, 0.2998693287372589, zoo) - self._pucks.append (Puck(position=pos)) + zoo = random.randrange(-5, 6) + pos = (-11.204887390136719, 0.2998693287372589, zoo) + self._pucks.append(Puck(position=pos)) diff --git a/plugins/minigames/HYPER_RACE.py b/plugins/minigames/HYPER_RACE.py index e09478ce..c5f5aaa9 100644 --- a/plugins/minigames/HYPER_RACE.py +++ b/plugins/minigames/HYPER_RACE.py @@ -425,12 +425,12 @@ def explode(self) -> None: self._exploded = True if self.node: blast = NewBlast(position=self.node.position, - velocity=self.node.velocity, - blast_radius=self.blast_radius, - blast_type=self.bomb_type, - source_player=babase.existing(self._source_player), - hit_type=self.hit_type, - hit_subtype=self.hit_subtype).autoretain() + velocity=self.node.velocity, + blast_radius=self.blast_radius, + blast_type=self.bomb_type, + source_player=babase.existing(self._source_player), + hit_type=self.hit_type, + hit_subtype=self.hit_subtype).autoretain() for callback in self._explode_callbacks: callback(self, blast) @@ -458,7 +458,7 @@ def __init__(self, self._collide_material.add_actions( actions=('modify_part_collision', 'collide', True), ) - + if teleport: collide = self._collide_material else: @@ -649,7 +649,7 @@ def on_transition_in(self) -> None: ('modify_part_collision', 'physical', False), ('call', 'at_connect', self._handle_race_point_collide), - )) + )) for rpt in pts: self._regions.append(RaceRegion(rpt, len(self._regions))) @@ -685,18 +685,18 @@ def _handle_race_point_collide(self) -> None: collision = bs.getcollision() try: region = collision.sourcenode.getdelegate(RaceRegion, True) - spaz = collision.opposingnode.getdelegate(PlayerSpaz,True) + spaz = collision.opposingnode.getdelegate(PlayerSpaz, True) except bs.NotFoundError: return - + if not spaz.is_alive(): return - + try: player = spaz.getplayer(Player, True) except bs.NotFoundError: return - + last_region = player.last_region this_region = region.index @@ -713,7 +713,7 @@ def _handle_race_point_collide(self) -> None: translate=('statements', 'Killing ${NAME} for' ' skipping part of the track!'), subs=[('${NAME}', player.getname(full=True))]), - color=(1, 0, 0)) + color=(1, 0, 0)) else: # If this player is in first, note that this is the # front-most race-point. @@ -788,10 +788,10 @@ def _handle_race_point_collide(self) -> None: player.actor.node.connectattr( 'torso_position', mathnode, 'input2') tstr = babase.Lstr(resource='lapNumberText', - subs=[('${CURRENT}', - str(player.lap + 1)), - ('${TOTAL}', str(self._laps)) - ]) + subs=[('${CURRENT}', + str(player.lap + 1)), + ('${TOTAL}', str(self._laps)) + ]) txtnode = bs.newnode('text', owner=mathnode, attrs={ @@ -828,7 +828,7 @@ def on_player_leave(self, player: Player) -> None: '${TEAM} is disqualified because ${PLAYER} left'), subs=[('${TEAM}', player.team.name), ('${PLAYER}', player.getname(full=True))]), - color=(1, 1, 0)) + color=(1, 1, 0)) player.team.finished = True player.team.time = None player.team.lap = 0 @@ -967,55 +967,54 @@ def _obstacles(self) -> None: self._tnt((-6, 5, 1), (0, 0, 0), 1.3) bs.timer(0.1, bs.WeakCall(self._tnt, (-3.2, 5, 1), - (0, 0, 0), 1.0, (0, 20, 60)), repeat=True) + (0, 0, 0), 1.0, (0, 20, 60)), repeat=True) bs.timer(1.6, bs.WeakCall(self._bomb, 'impact', - (6, 7, 1), (0, 0, 0), 1.0, 1.0), repeat=True) + (6, 7, 1), (0, 0, 0), 1.0, 1.0), repeat=True) bs.timer(1.6, bs.WeakCall(self._bomb, 'impact', - (6.8, 7, 1), (0, 0, 0), 1.0, 1.0), repeat=True) + (6.8, 7, 1), (0, 0, 0), 1.0, 1.0), repeat=True) bs.timer(1.6, bs.WeakCall(self._bomb, 'impact', - (7.6, 7, 1), (0, 0, 0), 1.0, 1.0), repeat=True) + (7.6, 7, 1), (0, 0, 0), 1.0, 1.0), repeat=True) bs.timer(1.6, bs.WeakCall(self._bomb, 'impact', - (6, 7, -2.2), (0, 0, 0), 1.0, 1.0), repeat=True) + (6, 7, -2.2), (0, 0, 0), 1.0, 1.0), repeat=True) bs.timer(1.6, bs.WeakCall(self._bomb, 'impact', - (6.8, 7, -2.2), (0, 0, 0), 1.0, 1.0), repeat=True) + (6.8, 7, -2.2), (0, 0, 0), 1.0, 1.0), repeat=True) bs.timer(1.6, bs.WeakCall(self._bomb, 'impact', - (7.6, 7, -2.2), (0, 0, 0), 1.0, 1.0), repeat=True) + (7.6, 7, -2.2), (0, 0, 0), 1.0, 1.0), repeat=True) bs.timer(1.6, bs.WeakCall(self._bomb, 'impact', - (6, 7, -5.2), (0, 0, 0), 1.0, 1.0), repeat=True) + (6, 7, -5.2), (0, 0, 0), 1.0, 1.0), repeat=True) bs.timer(1.6, bs.WeakCall(self._bomb, 'impact', - (6.8, 7, -5.2), (0, 0, 0), 1.0, 1.0), repeat=True) + (6.8, 7, -5.2), (0, 0, 0), 1.0, 1.0), repeat=True) bs.timer(1.6, bs.WeakCall(self._bomb, 'impact', - (7.6, 7, -5.2), (0, 0, 0), 1.0, 1.0), repeat=True) + (7.6, 7, -5.2), (0, 0, 0), 1.0, 1.0), repeat=True) bs.timer(1.6, bs.WeakCall(self._bomb, 'impact', - (6, 7, -8), (0, 0, 0), 1.0, 1.0), repeat=True) + (6, 7, -8), (0, 0, 0), 1.0, 1.0), repeat=True) bs.timer(1.6, bs.WeakCall(self._bomb, 'impact', - (6.8, 7, -8), (0, 0, 0), 1.0, 1.0), repeat=True) + (6.8, 7, -8), (0, 0, 0), 1.0, 1.0), repeat=True) bs.timer(1.6, bs.WeakCall(self._bomb, 'impact', - (7.6, 7, -8), (0, 0, 0), 1.0, 1.0), repeat=True) + (7.6, 7, -8), (0, 0, 0), 1.0, 1.0), repeat=True) bs.timer(1.6, bs.WeakCall(self._bomb, 'impact', - (-5, 5, 0), (0, 0, 0), 1.0, 1.0, (0, 20, 3)), repeat=True) + (-5, 5, 0), (0, 0, 0), 1.0, 1.0, (0, 20, 3)), repeat=True) bs.timer(1.6, bs.WeakCall(self._bomb, 'impact', - (-1.5, 5, 0), (0, 0, 0), 1.0, 1.0, (0, 20, 3)), repeat=True) - + (-1.5, 5, 0), (0, 0, 0), 1.0, 1.0, (0, 20, 3)), repeat=True) bs.timer(1.6, bs.WeakCall(self._bomb, 'sticky', - (-1, 5, -8), (0, 10, 0), 1.0, 1.0), repeat=True) + (-1, 5, -8), (0, 10, 0), 1.0, 1.0), repeat=True) bs.timer(1.6, bs.WeakCall(self._bomb, 'sticky', - (-1, 5, -9), (0, 10, 0), 1.0, 1.0), repeat=True) + (-1, 5, -9), (0, 10, 0), 1.0, 1.0), repeat=True) bs.timer(1.6, bs.WeakCall(self._bomb, 'sticky', - (-1, 5, -10), (0, 10, 0), 1.0, 1.0), repeat=True) + (-1, 5, -10), (0, 10, 0), 1.0, 1.0), repeat=True) bs.timer(1.6, bs.WeakCall(self._bomb, 'sticky', - (-4.6, 5, -8), (0, 10, 0), 1.0, 1.0), repeat=True) + (-4.6, 5, -8), (0, 10, 0), 1.0, 1.0), repeat=True) bs.timer(1.6, bs.WeakCall(self._bomb, 'sticky', - (-4.6, 5, -9), (0, 10, 0), 1.0, 1.0), repeat=True) + (-4.6, 5, -9), (0, 10, 0), 1.0, 1.0), repeat=True) bs.timer(1.6, bs.WeakCall(self._bomb, 'sticky', - (-4.6, 5, -10), (0, 10, 0), 1.0, 1.0), repeat=True) + (-4.6, 5, -10), (0, 10, 0), 1.0, 1.0), repeat=True) bs.timer(1.6, bs.WeakCall( self._powerup, (2, 5, -5), 'curse', (0, 20, -3)), repeat=True) @@ -1029,7 +1028,7 @@ def _tnt(self, extra_acceleration: float = None) -> None: if extra_acceleration: TNT(position, velocity, tnt_scale, False).autoretain( - ).node.extra_acceleration = extra_acceleration + ).node.extra_acceleration = extra_acceleration else: TNT(position, velocity, tnt_scale).autoretain() @@ -1044,7 +1043,7 @@ def _bomb(self, NewBomb(position=position, velocity=velocity, bomb_type=type).autoretain( - ).node.extra_acceleration = extra_acceleration + ).node.extra_acceleration = extra_acceleration else: NewBomb(position=position, velocity=velocity, @@ -1057,7 +1056,7 @@ def _powerup(self, if extra_acceleration: PowerupBox(position=position, poweruptype=poweruptype).autoretain( - ).node.extra_acceleration = extra_acceleration + ).node.extra_acceleration = extra_acceleration else: PowerupBox(position=position, poweruptype=poweruptype).autoretain() diff --git a/plugins/minigames/SnowBallFight.py b/plugins/minigames/SnowBallFight.py index 29afe38e..0bffe2db 100644 --- a/plugins/minigames/SnowBallFight.py +++ b/plugins/minigames/SnowBallFight.py @@ -18,626 +18,626 @@ from bascenev1lib.actor.spazfactory import SpazFactory if TYPE_CHECKING: - from typing import Any, Sequence + from typing import Any, Sequence lang = bs.app.lang.language if lang == 'Spanish': - name = 'Guerra de Nieve' - snowball_rate = 'Intervalo de Ataque' - snowball_slowest = 'Más Lento' - snowball_slow = 'Lento' - snowball_fast = 'Rápido' - snowball_lagcity = 'Más Rápido' - snowball_scale = 'Tamaño de Bola de Nieve' - snowball_smallest = 'Más Pequeño' - snowball_small = 'Pequeño' - snowball_big = 'Grande' - snowball_biggest = 'Más Grande' - snowball_insane = 'Insano' - snowball_melt = 'Derretir Bola de Nieve' - snowball_bust = 'Rebotar Bola de Nieve' - snowball_explode = 'Explotar al Impactar' - snowball_snow = 'Modo Nieve' + name = 'Guerra de Nieve' + snowball_rate = 'Intervalo de Ataque' + snowball_slowest = 'Más Lento' + snowball_slow = 'Lento' + snowball_fast = 'Rápido' + snowball_lagcity = 'Más Rápido' + snowball_scale = 'Tamaño de Bola de Nieve' + snowball_smallest = 'Más Pequeño' + snowball_small = 'Pequeño' + snowball_big = 'Grande' + snowball_biggest = 'Más Grande' + snowball_insane = 'Insano' + snowball_melt = 'Derretir Bola de Nieve' + snowball_bust = 'Rebotar Bola de Nieve' + snowball_explode = 'Explotar al Impactar' + snowball_snow = 'Modo Nieve' else: - name = 'Snowball Fight' - snowball_rate = 'Snowball Rate' - snowball_slowest = 'Slowest' - snowball_slow = 'Slow' - snowball_fast = 'Fast' - snowball_lagcity = 'Lag City' - snowball_scale = 'Snowball Scale' - snowball_smallest = 'Smallest' - snowball_small = 'Small' - snowball_big = 'Big' - snowball_biggest = 'Biggest' - snowball_insane = 'Insane' - snowball_melt = 'Snowballs Melt' - snowball_bust = 'Snowballs Bust' - snowball_explode = 'Snowballs Explode' - snowball_snow = 'Snow Mode' + name = 'Snowball Fight' + snowball_rate = 'Snowball Rate' + snowball_slowest = 'Slowest' + snowball_slow = 'Slow' + snowball_fast = 'Fast' + snowball_lagcity = 'Lag City' + snowball_scale = 'Snowball Scale' + snowball_smallest = 'Smallest' + snowball_small = 'Small' + snowball_big = 'Big' + snowball_biggest = 'Biggest' + snowball_insane = 'Insane' + snowball_melt = 'Snowballs Melt' + snowball_bust = 'Snowballs Bust' + snowball_explode = 'Snowballs Explode' + snowball_snow = 'Snow Mode' class Snowball(bs.Actor): - def __init__(self, - position: Sequence[float] = (0.0, 1.0, 0.0), - velocity: Sequence[float] = (0.0, 0.0, 0.0), - blast_radius: float = 0.7, - bomb_scale: float = 0.8, - source_player: bs.Player | None = None, - owner: bs.Node | None = None, - melt: bool = True, - bounce: bool = True, - explode: bool = False): - super().__init__() - shared = SharedObjects.get() - self._exploded = False - self.scale = bomb_scale - self.blast_radius = blast_radius - self._source_player = source_player - self.owner = owner - self._hit_nodes = set() - self.snowball_melt = melt - self.snowball_bounce = bounce - self.snowball_explode = explode - self.radius = bomb_scale * 0.1 - if bomb_scale <= 1.0: - shadow_size = 0.6 - elif bomb_scale <= 2.0: - shadow_size = 0.4 - elif bomb_scale <= 3.0: - shadow_size = 0.2 - else: - shadow_size = 0.1 - - self.snowball_material = bs.Material() - self.snowball_material.add_actions( - conditions=( - ( - ('we_are_younger_than', 5), - 'or', - ('they_are_younger_than', 100), - ), - 'and', - ('they_have_material', shared.object_material), - ), - actions=('modify_node_collision', 'collide', False), - ) - - self.snowball_material.add_actions( - conditions=('they_have_material', shared.pickup_material), - actions=('modify_part_collision', 'use_node_collide', False), - ) - - self.snowball_material.add_actions(actions=('modify_part_collision', - 'friction', 0.3)) - - self.snowball_material.add_actions( - conditions=('they_have_material', shared.player_material), - actions=(('modify_part_collision', 'physical', False), - ('call', 'at_connect', self.hit))) - - self.snowball_material.add_actions( - conditions=(('they_dont_have_material', shared.player_material), - 'and', - ('they_have_material', shared.object_material), - 'or', - ('they_have_material', shared.footing_material)), - actions=('call', 'at_connect', self.bounce)) - - self.node = bs.newnode( - 'prop', - delegate=self, - attrs={ - 'position': position, - 'velocity': velocity, - 'body': 'sphere', - 'body_scale': self.scale, - 'mesh': bs.getmesh('frostyPelvis'), - 'shadow_size': shadow_size, - 'color_texture': bs.gettexture('bunnyColor'), - 'reflection': 'soft', - 'reflection_scale': [0.15], - 'density': 1.0, - 'materials': [self.snowball_material] - }) - self.light = bs.newnode( - 'light', - owner=self.node, - attrs={ - 'color': (0.6, 0.6, 1.0), - 'intensity': 0.8, - 'radius': self.radius - }) - self.node.connectattr('position', self.light, 'position') - bs.animate(self.node, 'mesh_scale', { - 0: 0, - 0.2: 1.3 * self.scale, - 0.26: self.scale - }) - bs.animate(self.light, 'radius', { - 0: 0, - 0.2: 1.3 * self.radius, - 0.26: self.radius - }) - if self.snowball_melt: - bs.timer(1.5, bs.WeakCall(self._disappear)) - - def hit(self) -> None: - if not self.node: - return - if self._exploded: - return - if self.snowball_explode: - self._exploded = True - self.do_explode() - bs.timer(0.001, bs.WeakCall(self.handlemessage, bs.DieMessage())) - else: - self.do_hit() - - def do_hit(self) -> None: - v = self.node.velocity - if babase.Vec3(*v).length() > 5.0: - node = bs.getcollision().opposingnode - if node is not None and node and not ( - node in self._hit_nodes): - t = self.node.position - hitdir = self.node.velocity - self._hit_nodes.add(node) - node.handlemessage( - bs.HitMessage( - pos=t, - velocity=v, - magnitude=babase.Vec3(*v).length()*0.5, - velocity_magnitude=babase.Vec3(*v).length()*0.5, - radius=0, - srcnode=self.node, - source_player=self._source_player, - force_direction=hitdir, - hit_type='snoBall', - hit_subtype='default')) - - if not self.snowball_bounce: - bs.timer(0.05, bs.WeakCall(self.do_bounce)) - - def do_explode(self) -> None: - Blast(position=self.node.position, - velocity=self.node.velocity, - blast_radius=self.blast_radius, - source_player=babase.existing(self._source_player), - blast_type='impact', - hit_subtype='explode').autoretain() - - def bounce(self) -> None: - if not self.node: - return - if self._exploded: - return - if not self.snowball_bounce: - vel = self.node.velocity - bs.timer(0.01, bs.WeakCall(self.calc_bounce, vel)) - else: - return - - def calc_bounce(self, vel) -> None: - if not self.node: - return - ospd = babase.Vec3(*vel).length() - dot = sum(x*y for x, y in zip(vel, self.node.velocity)) - if ospd*ospd - dot > 50.0: - bs.timer(0.05, bs.WeakCall(self.do_bounce)) - - def do_bounce(self) -> None: - if not self.node: - return - if not self._exploded: - self.do_effect() - - def do_effect(self) -> None: - self._exploded = True - bs.emitfx(position=self.node.position, - velocity=[v*0.1 for v in self.node.velocity], - count=10, - spread=0.1, - scale=0.4, - chunk_type='ice') - sound = bs.getsound('impactMedium') - sound.play(1.0, position=self.node.position) - scl = self.node.mesh_scale - bs.animate(self.node, 'mesh_scale', { - 0.0: scl*1.0, - 0.02: scl*0.5, - 0.05: 0.0 - }) - lr = self.light.radius - bs.animate(self.light, 'radius', { - 0.0: lr*1.0, - 0.02: lr*0.5, - 0.05: 0.0 - }) - bs.timer(0.08, - bs.WeakCall(self.handlemessage, bs.DieMessage())) - - def _disappear(self) -> None: - self._exploded = True - if self.node: - scl = self.node.mesh_scale - bs.animate(self.node, 'mesh_scale', { - 0.0: scl*1.0, - 0.3: scl*0.5, - 0.5: 0.0 - }) - lr = self.light.radius - bs.animate(self.light, 'radius', { - 0.0: lr*1.0, - 0.3: lr*0.5, - 0.5: 0.0 - }) - bs.timer(0.55, - bs.WeakCall(self.handlemessage, bs.DieMessage())) - - def handlemessage(self, msg: Any) -> Any: - if isinstance(msg, bs.DieMessage): - if self.node: - self.node.delete() - elif isinstance(msg, bs.OutOfBoundsMessage): - self.handlemessage(bs.DieMessage()) - else: - super().handlemessage(msg) + def __init__(self, + position: Sequence[float] = (0.0, 1.0, 0.0), + velocity: Sequence[float] = (0.0, 0.0, 0.0), + blast_radius: float = 0.7, + bomb_scale: float = 0.8, + source_player: bs.Player | None = None, + owner: bs.Node | None = None, + melt: bool = True, + bounce: bool = True, + explode: bool = False): + super().__init__() + shared = SharedObjects.get() + self._exploded = False + self.scale = bomb_scale + self.blast_radius = blast_radius + self._source_player = source_player + self.owner = owner + self._hit_nodes = set() + self.snowball_melt = melt + self.snowball_bounce = bounce + self.snowball_explode = explode + self.radius = bomb_scale * 0.1 + if bomb_scale <= 1.0: + shadow_size = 0.6 + elif bomb_scale <= 2.0: + shadow_size = 0.4 + elif bomb_scale <= 3.0: + shadow_size = 0.2 + else: + shadow_size = 0.1 + + self.snowball_material = bs.Material() + self.snowball_material.add_actions( + conditions=( + ( + ('we_are_younger_than', 5), + 'or', + ('they_are_younger_than', 100), + ), + 'and', + ('they_have_material', shared.object_material), + ), + actions=('modify_node_collision', 'collide', False), + ) + + self.snowball_material.add_actions( + conditions=('they_have_material', shared.pickup_material), + actions=('modify_part_collision', 'use_node_collide', False), + ) + + self.snowball_material.add_actions(actions=('modify_part_collision', + 'friction', 0.3)) + + self.snowball_material.add_actions( + conditions=('they_have_material', shared.player_material), + actions=(('modify_part_collision', 'physical', False), + ('call', 'at_connect', self.hit))) + + self.snowball_material.add_actions( + conditions=(('they_dont_have_material', shared.player_material), + 'and', + ('they_have_material', shared.object_material), + 'or', + ('they_have_material', shared.footing_material)), + actions=('call', 'at_connect', self.bounce)) + + self.node = bs.newnode( + 'prop', + delegate=self, + attrs={ + 'position': position, + 'velocity': velocity, + 'body': 'sphere', + 'body_scale': self.scale, + 'mesh': bs.getmesh('frostyPelvis'), + 'shadow_size': shadow_size, + 'color_texture': bs.gettexture('bunnyColor'), + 'reflection': 'soft', + 'reflection_scale': [0.15], + 'density': 1.0, + 'materials': [self.snowball_material] + }) + self.light = bs.newnode( + 'light', + owner=self.node, + attrs={ + 'color': (0.6, 0.6, 1.0), + 'intensity': 0.8, + 'radius': self.radius + }) + self.node.connectattr('position', self.light, 'position') + bs.animate(self.node, 'mesh_scale', { + 0: 0, + 0.2: 1.3 * self.scale, + 0.26: self.scale + }) + bs.animate(self.light, 'radius', { + 0: 0, + 0.2: 1.3 * self.radius, + 0.26: self.radius + }) + if self.snowball_melt: + bs.timer(1.5, bs.WeakCall(self._disappear)) + + def hit(self) -> None: + if not self.node: + return + if self._exploded: + return + if self.snowball_explode: + self._exploded = True + self.do_explode() + bs.timer(0.001, bs.WeakCall(self.handlemessage, bs.DieMessage())) + else: + self.do_hit() + + def do_hit(self) -> None: + v = self.node.velocity + if babase.Vec3(*v).length() > 5.0: + node = bs.getcollision().opposingnode + if node is not None and node and not ( + node in self._hit_nodes): + t = self.node.position + hitdir = self.node.velocity + self._hit_nodes.add(node) + node.handlemessage( + bs.HitMessage( + pos=t, + velocity=v, + magnitude=babase.Vec3(*v).length()*0.5, + velocity_magnitude=babase.Vec3(*v).length()*0.5, + radius=0, + srcnode=self.node, + source_player=self._source_player, + force_direction=hitdir, + hit_type='snoBall', + hit_subtype='default')) + + if not self.snowball_bounce: + bs.timer(0.05, bs.WeakCall(self.do_bounce)) + + def do_explode(self) -> None: + Blast(position=self.node.position, + velocity=self.node.velocity, + blast_radius=self.blast_radius, + source_player=babase.existing(self._source_player), + blast_type='impact', + hit_subtype='explode').autoretain() + + def bounce(self) -> None: + if not self.node: + return + if self._exploded: + return + if not self.snowball_bounce: + vel = self.node.velocity + bs.timer(0.01, bs.WeakCall(self.calc_bounce, vel)) + else: + return + + def calc_bounce(self, vel) -> None: + if not self.node: + return + ospd = babase.Vec3(*vel).length() + dot = sum(x*y for x, y in zip(vel, self.node.velocity)) + if ospd*ospd - dot > 50.0: + bs.timer(0.05, bs.WeakCall(self.do_bounce)) + + def do_bounce(self) -> None: + if not self.node: + return + if not self._exploded: + self.do_effect() + + def do_effect(self) -> None: + self._exploded = True + bs.emitfx(position=self.node.position, + velocity=[v*0.1 for v in self.node.velocity], + count=10, + spread=0.1, + scale=0.4, + chunk_type='ice') + sound = bs.getsound('impactMedium') + sound.play(1.0, position=self.node.position) + scl = self.node.mesh_scale + bs.animate(self.node, 'mesh_scale', { + 0.0: scl*1.0, + 0.02: scl*0.5, + 0.05: 0.0 + }) + lr = self.light.radius + bs.animate(self.light, 'radius', { + 0.0: lr*1.0, + 0.02: lr*0.5, + 0.05: 0.0 + }) + bs.timer(0.08, + bs.WeakCall(self.handlemessage, bs.DieMessage())) + + def _disappear(self) -> None: + self._exploded = True + if self.node: + scl = self.node.mesh_scale + bs.animate(self.node, 'mesh_scale', { + 0.0: scl*1.0, + 0.3: scl*0.5, + 0.5: 0.0 + }) + lr = self.light.radius + bs.animate(self.light, 'radius', { + 0.0: lr*1.0, + 0.3: lr*0.5, + 0.5: 0.0 + }) + bs.timer(0.55, + bs.WeakCall(self.handlemessage, bs.DieMessage())) + + def handlemessage(self, msg: Any) -> Any: + if isinstance(msg, bs.DieMessage): + if self.node: + self.node.delete() + elif isinstance(msg, bs.OutOfBoundsMessage): + self.handlemessage(bs.DieMessage()) + else: + super().handlemessage(msg) class NewPlayerSpaz(PlayerSpaz): - def __init__(self, *args: Any, **kwds: Any): - super().__init__(*args, **kwds) - self.snowball_scale = 1.0 - self.snowball_melt = True - self.snowball_bounce = True - self.snowball_explode = False - - def on_punch_press(self) -> None: - if not self.node or self.frozen or self.node.knockout > 0.0: - return - t_ms = bs.time() * 1000 - assert isinstance(t_ms, int) - if t_ms - self.last_punch_time_ms >= self._punch_cooldown: - if self.punch_callback is not None: - self.punch_callback(self) - - # snowball - pos = self.node.position - p1 = self.node.position_center - p2 = self.node.position_forward - direction = [p1[0]-p2[0],p2[1]-p1[1],p1[2]-p2[2]] - direction[1] = 0.03 - mag = 20.0/babase.Vec3(*direction).length() - vel = [v * mag for v in direction] - Snowball(position=(pos[0], pos[1] + 0.1, pos[2]), - velocity=vel, - blast_radius=self.blast_radius, - bomb_scale=self.snowball_scale, - source_player=self.source_player, - owner=self.node, - melt=self.snowball_melt, - bounce=self.snowball_bounce, - explode=self.snowball_explode).autoretain() - - self._punched_nodes = set() # Reset this. - self.last_punch_time_ms = t_ms - self.node.punch_pressed = True - if not self.node.hold_node: - bs.timer( - 0.1, - bs.WeakCall(self._safe_play_sound, - SpazFactory.get().swish_sound, 0.8)) - self._turbo_filter_add_press('punch') - - def handlemessage(self, msg: Any) -> Any: - if isinstance(msg, PunchHitMessage): - pass - else: - return super().handlemessage(msg) - return None + def __init__(self, *args: Any, **kwds: Any): + super().__init__(*args, **kwds) + self.snowball_scale = 1.0 + self.snowball_melt = True + self.snowball_bounce = True + self.snowball_explode = False + + def on_punch_press(self) -> None: + if not self.node or self.frozen or self.node.knockout > 0.0: + return + t_ms = bs.time() * 1000 + assert isinstance(t_ms, int) + if t_ms - self.last_punch_time_ms >= self._punch_cooldown: + if self.punch_callback is not None: + self.punch_callback(self) + + # snowball + pos = self.node.position + p1 = self.node.position_center + p2 = self.node.position_forward + direction = [p1[0]-p2[0], p2[1]-p1[1], p1[2]-p2[2]] + direction[1] = 0.03 + mag = 20.0/babase.Vec3(*direction).length() + vel = [v * mag for v in direction] + Snowball(position=(pos[0], pos[1] + 0.1, pos[2]), + velocity=vel, + blast_radius=self.blast_radius, + bomb_scale=self.snowball_scale, + source_player=self.source_player, + owner=self.node, + melt=self.snowball_melt, + bounce=self.snowball_bounce, + explode=self.snowball_explode).autoretain() + + self._punched_nodes = set() # Reset this. + self.last_punch_time_ms = t_ms + self.node.punch_pressed = True + if not self.node.hold_node: + bs.timer( + 0.1, + bs.WeakCall(self._safe_play_sound, + SpazFactory.get().swish_sound, 0.8)) + self._turbo_filter_add_press('punch') + + def handlemessage(self, msg: Any) -> Any: + if isinstance(msg, PunchHitMessage): + pass + else: + return super().handlemessage(msg) + return None class Player(bs.Player['Team']): - """Our player type for this game.""" + """Our player type for this game.""" class Team(bs.Team[Player]): - """Our team type for this game.""" + """Our team type for this game.""" - def __init__(self) -> None: - self.score = 0 + def __init__(self) -> None: + self.score = 0 # ba_meta export bascenev1.GameActivity class SnowballFightGame(bs.TeamGameActivity[Player, Team]): - """A game type based on acquiring kills.""" - - name = name - description = 'Kill a set number of enemies to win.' - - # Print messages when players die since it matters here. - announce_player_deaths = True - - @classmethod - def get_available_settings( - cls, sessiontype: type[bs.Session]) -> list[babase.Setting]: - settings = [ - bs.IntSetting( - 'Kills to Win Per Player', - min_value=1, - default=5, - increment=1, - ), - bs.IntChoiceSetting( - 'Time Limit', - choices=[ - ('None', 0), - ('1 Minute', 60), - ('2 Minutes', 120), - ('5 Minutes', 300), - ('10 Minutes', 600), - ('20 Minutes', 1200), - ], - default=0, - ), - bs.FloatChoiceSetting( - 'Respawn Times', - choices=[ - ('Shorter', 0.25), - ('Short', 0.5), - ('Normal', 1.0), - ('Long', 2.0), - ('Longer', 4.0), - ], - default=1.0, - ), - bs.IntChoiceSetting( - snowball_rate, - choices=[ - (snowball_slowest, 500), - (snowball_slow, 400), - ('Normal', 300), - (snowball_fast, 200), - (snowball_lagcity, 100), - ], - default=300, - ), - bs.FloatChoiceSetting( - snowball_scale, - choices=[ - (snowball_smallest, 0.4), - (snowball_small, 0.6), - ('Normal', 0.8), - (snowball_big, 1.4), - (snowball_biggest, 3.0), - (snowball_insane, 6.0), - ], - default=0.8, - ), - bs.BoolSetting(snowball_melt, default=True), - bs.BoolSetting(snowball_bust, default=True), - bs.BoolSetting(snowball_explode, default=False), - bs.BoolSetting(snowball_snow, default=True), - bs.BoolSetting('Epic Mode', default=False), - ] - - # In teams mode, a suicide gives a point to the other team, but in - # free-for-all it subtracts from your own score. By default we clamp - # this at zero to benefit new players, but pro players might like to - # be able to go negative. (to avoid a strategy of just - # suiciding until you get a good drop) - if issubclass(sessiontype, bs.FreeForAllSession): - settings.append( - bs.BoolSetting('Allow Negative Scores', default=False)) - - return settings - - @classmethod - def supports_session_type(cls, sessiontype: type[bs.Session]) -> bool: - return (issubclass(sessiontype, bs.DualTeamSession) - or issubclass(sessiontype, bs.FreeForAllSession)) - - @classmethod - def get_supported_maps(cls, sessiontype: type[bs.Session]) -> list[str]: - return bs.app.classic.getmaps('melee') - - def __init__(self, settings: dict): - super().__init__(settings) - self._scoreboard = Scoreboard() - self._score_to_win: int | None = None - self._dingsound = bs.getsound('dingSmall') - self._epic_mode = bool(settings['Epic Mode']) - self._kills_to_win_per_player = int( - settings['Kills to Win Per Player']) - self._time_limit = float(settings['Time Limit']) - self._allow_negative_scores = bool( - settings.get('Allow Negative Scores', False)) - self._snowball_rate = int(settings[snowball_rate]) - self._snowball_scale = float(settings[snowball_scale]) - self._snowball_melt = bool(settings[snowball_melt]) - self._snowball_bounce = bool(settings[snowball_bust]) - self._snowball_explode = bool(settings[snowball_explode]) - self._snow_mode = bool(settings[snowball_snow]) - - # Base class overrides. - self.slow_motion = self._epic_mode - self.default_music = (bs.MusicType.EPIC if self._epic_mode else - bs.MusicType.TO_THE_DEATH) - - def get_instance_description(self) -> str | Sequence: - return 'Crush ${ARG1} of your enemies.', self._score_to_win - - def get_instance_description_short(self) -> str | Sequence: - return 'kill ${ARG1} enemies', self._score_to_win - - def on_team_join(self, team: Team) -> None: - if self.has_begun(): - self._update_scoreboard() - - def on_transition_in(self) -> None: - super().on_transition_in() - if self._snow_mode: - gnode = bs.getactivity().globalsnode - gnode.tint = (0.8, 0.8, 1.3) - bs.timer(0.02, self.emit_snowball, repeat=True) - - def on_begin(self) -> None: - super().on_begin() - self.setup_standard_time_limit(self._time_limit) - # self.setup_standard_powerup_drops() - - # Base kills needed to win on the size of the largest team. - self._score_to_win = (self._kills_to_win_per_player * - max(1, max(len(t.players) for t in self.teams))) - self._update_scoreboard() - - def emit_snowball(self) -> None: - pos = (-10 + (random.random() * 30), 15, - -10 + (random.random() * 30)) - vel = ((-5.0 + random.random() * 30.0) * (-1.0 if pos[0] > 0 else 1.0), - -50.0, (-5.0 + random.random() * 30.0) * ( - -1.0 if pos[0] > 0 else 1.0)) - bs.emitfx(position=pos, - velocity=vel, - count=10, - scale=1.0 + random.random(), - spread=0.0, - chunk_type='spark') - - def spawn_player_spaz(self, - player: Player, - position: Sequence[float] = (0, 0, 0), - angle: float | None = None) -> PlayerSpaz: - from babase import _math - from bascenev1._gameutils import animate - from bascenev1._coopsession import CoopSession - - if isinstance(self.session, bs.DualTeamSession): - position = self.map.get_start_position(player.team.id) - else: - # otherwise do free-for-all spawn locations - position = self.map.get_ffa_start_position(self.players) - - name = player.getname() - color = player.color - highlight = player.highlight - - light_color = _math.normalized_color(color) - display_color = babase.safecolor(color, target_intensity=0.75) - - spaz = NewPlayerSpaz(color=color, - highlight=highlight, - character=player.character, - player=player) - - player.actor = spaz - assert spaz.node - - # If this is co-op and we're on Courtyard or Runaround, add the - # material that allows us to collide with the player-walls. - # FIXME: Need to generalize this. - if isinstance(self.session, CoopSession) and self.map.getname() in [ - 'Courtyard', 'Tower D' - ]: - mat = self.map.preloaddata['collide_with_wall_material'] - assert isinstance(spaz.node.materials, tuple) - assert isinstance(spaz.node.roller_materials, tuple) - spaz.node.materials += (mat, ) - spaz.node.roller_materials += (mat, ) - - spaz.node.name = name - spaz.node.name_color = display_color - spaz.connect_controls_to_player( - enable_pickup=False, enable_bomb=False) - - # Move to the stand position and add a flash of light. - spaz.handlemessage( - bs.StandMessage( - position, - angle if angle is not None else random.uniform(0, 360))) - self._spawn_sound.play(1, position=spaz.node.position) - light = bs.newnode('light', attrs={'color': light_color}) - spaz.node.connectattr('position', light, 'position') - animate(light, 'intensity', {0: 0, 0.25: 1, 0.5: 0}) - bs.timer(0.5, light.delete) - - # custom - spaz._punch_cooldown = self._snowball_rate - spaz.snowball_scale = self._snowball_scale - spaz.snowball_melt = self._snowball_melt - spaz.snowball_bounce = self._snowball_bounce - spaz.snowball_explode = self._snowball_explode - - return spaz - - def handlemessage(self, msg: Any) -> Any: - - if isinstance(msg, bs.PlayerDiedMessage): - - # Augment standard behavior. - super().handlemessage(msg) - - player = msg.getplayer(Player) - self.respawn_player(player) - - killer = msg.getkillerplayer(Player) - if killer is None: - return None - - # Handle team-kills. - if killer.team is player.team: - - # In free-for-all, killing yourself loses you a point. - if isinstance(self.session, bs.FreeForAllSession): - new_score = player.team.score - 1 - if not self._allow_negative_scores: - new_score = max(0, new_score) - player.team.score = new_score - - # In teams-mode it gives a point to the other team. - else: - self._dingsound.play() - for team in self.teams: - if team is not killer.team: - team.score += 1 - - # Killing someone on another team nets a kill. - else: - killer.team.score += 1 - self._dingsound.play() - - # In FFA show scores since its hard to find on the scoreboard. - if isinstance(killer.actor, PlayerSpaz) and killer.actor: - killer.actor.set_score_text(str(killer.team.score) + '/' + - str(self._score_to_win), - color=killer.team.color, - flash=True) - - self._update_scoreboard() - - # If someone has won, set a timer to end shortly. - # (allows the dust to clear and draws to occur if deaths are - # close enough) - assert self._score_to_win is not None - if any(team.score >= self._score_to_win for team in self.teams): - bs.timer(0.5, self.end_game) - - else: - return super().handlemessage(msg) - return None - - def _update_scoreboard(self) -> None: - for team in self.teams: - self._scoreboard.set_team_value(team, team.score, - self._score_to_win) - - def end_game(self) -> None: - results = bs.GameResults() - for team in self.teams: - results.set_team_score(team, team.score) - self.end(results=results) + """A game type based on acquiring kills.""" + + name = name + description = 'Kill a set number of enemies to win.' + + # Print messages when players die since it matters here. + announce_player_deaths = True + + @classmethod + def get_available_settings( + cls, sessiontype: type[bs.Session]) -> list[babase.Setting]: + settings = [ + bs.IntSetting( + 'Kills to Win Per Player', + min_value=1, + default=5, + increment=1, + ), + bs.IntChoiceSetting( + 'Time Limit', + choices=[ + ('None', 0), + ('1 Minute', 60), + ('2 Minutes', 120), + ('5 Minutes', 300), + ('10 Minutes', 600), + ('20 Minutes', 1200), + ], + default=0, + ), + bs.FloatChoiceSetting( + 'Respawn Times', + choices=[ + ('Shorter', 0.25), + ('Short', 0.5), + ('Normal', 1.0), + ('Long', 2.0), + ('Longer', 4.0), + ], + default=1.0, + ), + bs.IntChoiceSetting( + snowball_rate, + choices=[ + (snowball_slowest, 500), + (snowball_slow, 400), + ('Normal', 300), + (snowball_fast, 200), + (snowball_lagcity, 100), + ], + default=300, + ), + bs.FloatChoiceSetting( + snowball_scale, + choices=[ + (snowball_smallest, 0.4), + (snowball_small, 0.6), + ('Normal', 0.8), + (snowball_big, 1.4), + (snowball_biggest, 3.0), + (snowball_insane, 6.0), + ], + default=0.8, + ), + bs.BoolSetting(snowball_melt, default=True), + bs.BoolSetting(snowball_bust, default=True), + bs.BoolSetting(snowball_explode, default=False), + bs.BoolSetting(snowball_snow, default=True), + bs.BoolSetting('Epic Mode', default=False), + ] + + # In teams mode, a suicide gives a point to the other team, but in + # free-for-all it subtracts from your own score. By default we clamp + # this at zero to benefit new players, but pro players might like to + # be able to go negative. (to avoid a strategy of just + # suiciding until you get a good drop) + if issubclass(sessiontype, bs.FreeForAllSession): + settings.append( + bs.BoolSetting('Allow Negative Scores', default=False)) + + return settings + + @classmethod + def supports_session_type(cls, sessiontype: type[bs.Session]) -> bool: + return (issubclass(sessiontype, bs.DualTeamSession) + or issubclass(sessiontype, bs.FreeForAllSession)) + + @classmethod + def get_supported_maps(cls, sessiontype: type[bs.Session]) -> list[str]: + return bs.app.classic.getmaps('melee') + + def __init__(self, settings: dict): + super().__init__(settings) + self._scoreboard = Scoreboard() + self._score_to_win: int | None = None + self._dingsound = bs.getsound('dingSmall') + self._epic_mode = bool(settings['Epic Mode']) + self._kills_to_win_per_player = int( + settings['Kills to Win Per Player']) + self._time_limit = float(settings['Time Limit']) + self._allow_negative_scores = bool( + settings.get('Allow Negative Scores', False)) + self._snowball_rate = int(settings[snowball_rate]) + self._snowball_scale = float(settings[snowball_scale]) + self._snowball_melt = bool(settings[snowball_melt]) + self._snowball_bounce = bool(settings[snowball_bust]) + self._snowball_explode = bool(settings[snowball_explode]) + self._snow_mode = bool(settings[snowball_snow]) + + # Base class overrides. + self.slow_motion = self._epic_mode + self.default_music = (bs.MusicType.EPIC if self._epic_mode else + bs.MusicType.TO_THE_DEATH) + + def get_instance_description(self) -> str | Sequence: + return 'Crush ${ARG1} of your enemies.', self._score_to_win + + def get_instance_description_short(self) -> str | Sequence: + return 'kill ${ARG1} enemies', self._score_to_win + + def on_team_join(self, team: Team) -> None: + if self.has_begun(): + self._update_scoreboard() + + def on_transition_in(self) -> None: + super().on_transition_in() + if self._snow_mode: + gnode = bs.getactivity().globalsnode + gnode.tint = (0.8, 0.8, 1.3) + bs.timer(0.02, self.emit_snowball, repeat=True) + + def on_begin(self) -> None: + super().on_begin() + self.setup_standard_time_limit(self._time_limit) + # self.setup_standard_powerup_drops() + + # Base kills needed to win on the size of the largest team. + self._score_to_win = (self._kills_to_win_per_player * + max(1, max(len(t.players) for t in self.teams))) + self._update_scoreboard() + + def emit_snowball(self) -> None: + pos = (-10 + (random.random() * 30), 15, + -10 + (random.random() * 30)) + vel = ((-5.0 + random.random() * 30.0) * (-1.0 if pos[0] > 0 else 1.0), + -50.0, (-5.0 + random.random() * 30.0) * ( + -1.0 if pos[0] > 0 else 1.0)) + bs.emitfx(position=pos, + velocity=vel, + count=10, + scale=1.0 + random.random(), + spread=0.0, + chunk_type='spark') + + def spawn_player_spaz(self, + player: Player, + position: Sequence[float] = (0, 0, 0), + angle: float | None = None) -> PlayerSpaz: + from babase import _math + from bascenev1._gameutils import animate + from bascenev1._coopsession import CoopSession + + if isinstance(self.session, bs.DualTeamSession): + position = self.map.get_start_position(player.team.id) + else: + # otherwise do free-for-all spawn locations + position = self.map.get_ffa_start_position(self.players) + + name = player.getname() + color = player.color + highlight = player.highlight + + light_color = _math.normalized_color(color) + display_color = babase.safecolor(color, target_intensity=0.75) + + spaz = NewPlayerSpaz(color=color, + highlight=highlight, + character=player.character, + player=player) + + player.actor = spaz + assert spaz.node + + # If this is co-op and we're on Courtyard or Runaround, add the + # material that allows us to collide with the player-walls. + # FIXME: Need to generalize this. + if isinstance(self.session, CoopSession) and self.map.getname() in [ + 'Courtyard', 'Tower D' + ]: + mat = self.map.preloaddata['collide_with_wall_material'] + assert isinstance(spaz.node.materials, tuple) + assert isinstance(spaz.node.roller_materials, tuple) + spaz.node.materials += (mat, ) + spaz.node.roller_materials += (mat, ) + + spaz.node.name = name + spaz.node.name_color = display_color + spaz.connect_controls_to_player( + enable_pickup=False, enable_bomb=False) + + # Move to the stand position and add a flash of light. + spaz.handlemessage( + bs.StandMessage( + position, + angle if angle is not None else random.uniform(0, 360))) + self._spawn_sound.play(1, position=spaz.node.position) + light = bs.newnode('light', attrs={'color': light_color}) + spaz.node.connectattr('position', light, 'position') + animate(light, 'intensity', {0: 0, 0.25: 1, 0.5: 0}) + bs.timer(0.5, light.delete) + + # custom + spaz._punch_cooldown = self._snowball_rate + spaz.snowball_scale = self._snowball_scale + spaz.snowball_melt = self._snowball_melt + spaz.snowball_bounce = self._snowball_bounce + spaz.snowball_explode = self._snowball_explode + + return spaz + + def handlemessage(self, msg: Any) -> Any: + + if isinstance(msg, bs.PlayerDiedMessage): + + # Augment standard behavior. + super().handlemessage(msg) + + player = msg.getplayer(Player) + self.respawn_player(player) + + killer = msg.getkillerplayer(Player) + if killer is None: + return None + + # Handle team-kills. + if killer.team is player.team: + + # In free-for-all, killing yourself loses you a point. + if isinstance(self.session, bs.FreeForAllSession): + new_score = player.team.score - 1 + if not self._allow_negative_scores: + new_score = max(0, new_score) + player.team.score = new_score + + # In teams-mode it gives a point to the other team. + else: + self._dingsound.play() + for team in self.teams: + if team is not killer.team: + team.score += 1 + + # Killing someone on another team nets a kill. + else: + killer.team.score += 1 + self._dingsound.play() + + # In FFA show scores since its hard to find on the scoreboard. + if isinstance(killer.actor, PlayerSpaz) and killer.actor: + killer.actor.set_score_text(str(killer.team.score) + '/' + + str(self._score_to_win), + color=killer.team.color, + flash=True) + + self._update_scoreboard() + + # If someone has won, set a timer to end shortly. + # (allows the dust to clear and draws to occur if deaths are + # close enough) + assert self._score_to_win is not None + if any(team.score >= self._score_to_win for team in self.teams): + bs.timer(0.5, self.end_game) + + else: + return super().handlemessage(msg) + return None + + def _update_scoreboard(self) -> None: + for team in self.teams: + self._scoreboard.set_team_value(team, team.score, + self._score_to_win) + + def end_game(self) -> None: + results = bs.GameResults() + for team in self.teams: + results.set_team_score(team, team.score) + self.end(results=results) diff --git a/plugins/minigames/ofuuuAttack.py b/plugins/minigames/ofuuuAttack.py index 49b2afb9..1e5b6d47 100644 --- a/plugins/minigames/ofuuuAttack.py +++ b/plugins/minigames/ofuuuAttack.py @@ -17,173 +17,210 @@ if TYPE_CHECKING: from typing import Any, Sequence, Optional, List, Dict, Type, Type + class _GotTouched(): - pass + pass + class UFO(bs.Actor): - def __init__(self, pos: float = (0,0,0)): - super().__init__() - shared = SharedObjects.get() - self.r: Optional[int] = 0 - self.dis: Optional[List] = [] - self.target: float = (0.0, 0.0, 0.0) - self.regs: List[bs.NodeActor] = [] - self.node = bs.newnode('prop', - delegate=self, - attrs={'body':'landMine', - 'position': pos, - 'mesh':bs.getmesh('landMine'), - 'mesh_scale': 1.5, - 'body_scale': 0.01, - 'shadow_size': 0.000001, - 'gravity_scale': 0.0, - 'color_texture': bs.gettexture("achievementCrossHair"), - 'materials': [shared.object_material]}) - self.ufo_collide = None - - def create_target(self): - if not self.node.exists(): return - self.dis = [] - shared = SharedObjects.get() - try: - def pass_(): - self.regs.clear() - bs.timer(3875*0.001, self.move) - try: bs.timer(3277*0.001, lambda: Bomb(velocity=(0,0,0), position=(self.target[0], self.node.position[1]-0.43999, self.target[2]), bomb_type='impact').autoretain().arm()) - except: pass - key = bs.Material() - key.add_actions( - conditions=('they_have_material', shared.object_material), - actions=( - ('modify_part_collision', 'collide', True), - ('modify_part_collision', 'physical', False), - ('call', 'at_connect', pass_()), - )) - except: pass - self.regs.append(bs.NodeActor(bs.newnode('region', - attrs={ - 'position': self.target, - 'scale': (0.04, 22, 0.04), - 'type': 'sphere', - 'materials':[key]}))) - - def move(self): - if not self.node.exists(): return - try: - self.create_target() - for j in bs.getnodes(): - n = j.getdelegate(object) - if j.getnodetype() == 'prop' and isinstance(n, TileFloor): - if n.node.exists(): self.dis.append(n.node) - self.r = random.randint(0,len(self.dis)-1) - self.target = (self.dis[self.r].position[0], self.node.position[1], self.dis[self.r].position[2]) - bs.animate_array(self.node, 'position', 3, { - 0:self.node.position, - 3.0:self.target}) - except: pass - def handlemessage(self, msg): - - if isinstance(msg, bs.DieMessage): - self.node.delete() - elif isinstance(msg ,bs.OutOfBoundsMessage): self.handlemessage(bs.DieMessage()) - else: super().handlemessage(msg) + def __init__(self, pos: float = (0, 0, 0)): + super().__init__() + shared = SharedObjects.get() + self.r: Optional[int] = 0 + self.dis: Optional[List] = [] + self.target: float = (0.0, 0.0, 0.0) + self.regs: List[bs.NodeActor] = [] + self.node = bs.newnode('prop', + delegate=self, + attrs={'body': 'landMine', + 'position': pos, + 'mesh': bs.getmesh('landMine'), + 'mesh_scale': 1.5, + 'body_scale': 0.01, + 'shadow_size': 0.000001, + 'gravity_scale': 0.0, + 'color_texture': bs.gettexture("achievementCrossHair"), + 'materials': [shared.object_material]}) + self.ufo_collide = None + + def create_target(self): + if not self.node.exists(): + return + self.dis = [] + shared = SharedObjects.get() + try: + def pass_(): + self.regs.clear() + bs.timer(3875*0.001, self.move) + try: + bs.timer(3277*0.001, lambda: Bomb(velocity=(0, 0, 0), position=( + self.target[0], self.node.position[1]-0.43999, self.target[2]), bomb_type='impact').autoretain().arm()) + except: + pass + key = bs.Material() + key.add_actions( + conditions=('they_have_material', shared.object_material), + actions=( + ('modify_part_collision', 'collide', True), + ('modify_part_collision', 'physical', False), + ('call', 'at_connect', pass_()), + )) + except: + pass + self.regs.append(bs.NodeActor(bs.newnode('region', + attrs={ + 'position': self.target, + 'scale': (0.04, 22, 0.04), + 'type': 'sphere', + 'materials': [key]}))) + + def move(self): + if not self.node.exists(): + return + try: + self.create_target() + for j in bs.getnodes(): + n = j.getdelegate(object) + if j.getnodetype() == 'prop' and isinstance(n, TileFloor): + if n.node.exists(): + self.dis.append(n.node) + self.r = random.randint(0, len(self.dis)-1) + self.target = (self.dis[self.r].position[0], + self.node.position[1], self.dis[self.r].position[2]) + bs.animate_array(self.node, 'position', 3, { + 0: self.node.position, + 3.0: self.target}) + except: + pass + + def handlemessage(self, msg): + + if isinstance(msg, bs.DieMessage): + self.node.delete() + elif isinstance(msg, bs.OutOfBoundsMessage): + self.handlemessage(bs.DieMessage()) + else: + super().handlemessage(msg) class TileFloor(bs.Actor): - def __init__(self, - pos: float = (0, 0, 0)): - super().__init__() - get_mat = SharedObjects.get() - self.pos = pos - self.scale = 1.5 - self.mat, self.mat2, self.test = bs.Material(), bs.Material(), bs.Material() - self.mat.add_actions(conditions=('we_are_older_than', 1), actions=(('modify_part_collision', 'collide', False))) - self.mat2.add_actions(conditions=('we_are_older_than', 1), actions=(('modify_part_collision', 'collide', True))) - self.test.add_actions( + def __init__(self, + pos: float = (0, 0, 0)): + super().__init__() + get_mat = SharedObjects.get() + self.pos = pos + self.scale = 1.5 + self.mat, self.mat2, self.test = bs.Material(), bs.Material(), bs.Material() + self.mat.add_actions(conditions=('we_are_older_than', 1), + actions=(('modify_part_collision', 'collide', False))) + self.mat2.add_actions(conditions=('we_are_older_than', 1), + actions=(('modify_part_collision', 'collide', True))) + self.test.add_actions( conditions=('they_have_material', BombFactory.get().bomb_material), actions=( ('modify_part_collision', 'collide', True), ('modify_part_collision', 'physical', False), ('message', 'our_node', 'at_connect', _GotTouched()))) - self.node = bs.newnode('prop', - delegate=self, - attrs={'body':'puck', - 'position': self.pos, - 'mesh':bs.getmesh('buttonSquareOpaque'), - 'mesh_scale': self.scale*1.16, - 'body_scale': self.scale, - 'shadow_size': 0.0002, - 'gravity_scale': 0.0, - 'color_texture': bs.gettexture("tnt"), - 'is_area_of_interest': True, - 'materials': [self.mat, self.test]}) - self.node_support = bs.newnode('region', - attrs={ - 'position': self.pos, - 'scale': (self.scale*0.8918, 0.1, self.scale*0.8918), - 'type': 'box', - 'materials':[get_mat.footing_material, self.mat2] - }) - def handlemessage(self, msg): - if isinstance(msg, bs.DieMessage): - self.node.delete() - self.node_support.delete() - elif isinstance(msg, _GotTouched): - def do(): self.handlemessage(bs.DieMessage()) - bs.timer(0.1, do) - else: super().handlemessage(msg) + self.node = bs.newnode('prop', + delegate=self, + attrs={'body': 'puck', + 'position': self.pos, + 'mesh': bs.getmesh('buttonSquareOpaque'), + 'mesh_scale': self.scale*1.16, + 'body_scale': self.scale, + 'shadow_size': 0.0002, + 'gravity_scale': 0.0, + 'color_texture': bs.gettexture("tnt"), + 'is_area_of_interest': True, + 'materials': [self.mat, self.test]}) + self.node_support = bs.newnode('region', + attrs={ + 'position': self.pos, + 'scale': (self.scale*0.8918, 0.1, self.scale*0.8918), + 'type': 'box', + 'materials': [get_mat.footing_material, self.mat2] + }) + + def handlemessage(self, msg): + if isinstance(msg, bs.DieMessage): + self.node.delete() + self.node_support.delete() + elif isinstance(msg, _GotTouched): + def do(): self.handlemessage(bs.DieMessage()) + bs.timer(0.1, do) + else: + super().handlemessage(msg) + class defs(): points = boxes = {} boxes['area_of_interest_bounds'] = (-1.3440, 1.185751251, 3.7326226188) + ( - 0.0, 0.0, 0.0) + (29.8180273, 15.57249038, 22.93859993) - boxes['map_bounds'] = (0.0, 2.585751251, 0.4326226188) + (0.0, 0.0, 0.0) + (29.09506485, 15.81173179, 33.76723155) + 0.0, 0.0, 0.0) + (29.8180273, 15.57249038, 22.93859993) + boxes['map_bounds'] = (0.0, 2.585751251, 0.4326226188) + (0.0, 0.0, + 0.0) + (29.09506485, 15.81173179, 33.76723155) + class DummyMapForGame(bs.Map): defs, name = defs(), 'Tile Lands' + @classmethod def get_play_types(cls) -> List[str]: return [] + @classmethod def get_preview_texture_name(cls) -> str: return 'achievementCrossHair' + @classmethod def on_preload(cls) -> Any: - data: Dict[str, Any] = {'bg_1': bs.gettexture('rampageBGColor'),'bg_2': bs.gettexture('rampageBGColor2'),'bg_mesh_1': bs.getmesh('rampageBG'),'bg_mesh_2': bs.getmesh('rampageBG2'),} + data: Dict[str, Any] = {'bg_1': bs.gettexture('rampageBGColor'), 'bg_2': bs.gettexture( + 'rampageBGColor2'), 'bg_mesh_1': bs.getmesh('rampageBG'), 'bg_mesh_2': bs.getmesh('rampageBG2'), } return data + def __init__(self) -> None: super().__init__() - self.bg1 = bs.newnode('terrain',attrs={'mesh': self.preloaddata['bg_mesh_1'],'lighting': False,'background': True,'color_texture': self.preloaddata['bg_2']}) - self.bg2 = bs.newnode('terrain',attrs={ 'mesh': self.preloaddata['bg_mesh_2'], 'lighting': False,'background': True, 'color_texture': self.preloaddata['bg_2']}) + self.bg1 = bs.newnode('terrain', attrs={ + 'mesh': self.preloaddata['bg_mesh_1'], 'lighting': False, 'background': True, 'color_texture': self.preloaddata['bg_2']}) + self.bg2 = bs.newnode('terrain', attrs={ + 'mesh': self.preloaddata['bg_mesh_2'], 'lighting': False, 'background': True, 'color_texture': self.preloaddata['bg_2']}) a = bs.getactivity().globalsnode - a.tint, a.ambient_color, a.vignette_outer, a.vignette_inner = (1.2, 1.1, 0.97), (1.3, 1.2, 1.03), (0.62, 0.64, 0.69), (0.97, 0.95, 0.93) + a.tint, a.ambient_color, a.vignette_outer, a.vignette_inner = ( + 1.2, 1.1, 0.97), (1.3, 1.2, 1.03), (0.62, 0.64, 0.69), (0.97, 0.95, 0.93) + class DummyMapForGame2(bs.Map): defs, name = defs(), 'Tile Lands Night' + @classmethod def get_play_types(cls) -> List[str]: return [] + @classmethod def get_preview_texture_name(cls) -> str: return 'achievementCrossHair' + @classmethod def on_preload(cls) -> Any: - data: Dict[str, Any] = {'bg_1': bs.gettexture('menuBG'),'bg_2': bs.gettexture('menuBG'),'bg_mesh_1': bs.getmesh('thePadBG'),'bg_mesh_2': bs.getmesh('thePadBG'),} + data: Dict[str, Any] = {'bg_1': bs.gettexture('menuBG'), 'bg_2': bs.gettexture( + 'menuBG'), 'bg_mesh_1': bs.getmesh('thePadBG'), 'bg_mesh_2': bs.getmesh('thePadBG'), } return data + def __init__(self) -> None: super().__init__() - self.bg1 = bs.newnode('terrain',attrs={'mesh': self.preloaddata['bg_mesh_1'],'lighting': False,'background': True,'color_texture': self.preloaddata['bg_2']}) - self.bg2 = bs.newnode('terrain',attrs={ 'mesh': self.preloaddata['bg_mesh_2'], 'lighting': False,'background': True, 'color_texture': self.preloaddata['bg_2']}) + self.bg1 = bs.newnode('terrain', attrs={ + 'mesh': self.preloaddata['bg_mesh_1'], 'lighting': False, 'background': True, 'color_texture': self.preloaddata['bg_2']}) + self.bg2 = bs.newnode('terrain', attrs={ + 'mesh': self.preloaddata['bg_mesh_2'], 'lighting': False, 'background': True, 'color_texture': self.preloaddata['bg_2']}) a = bs.getactivity().globalsnode - a.tint, a.ambient_color, a.vignette_outer, a.vignette_inner = (0.5, 0.7, 1.27), (2.5, 2.5, 2.5), (0.62, 0.64, 0.69), (0.97, 0.95, 0.93) + a.tint, a.ambient_color, a.vignette_outer, a.vignette_inner = ( + 0.5, 0.7, 1.27), (2.5, 2.5, 2.5), (0.62, 0.64, 0.69), (0.97, 0.95, 0.93) + bs._map.register_map(DummyMapForGame) bs._map.register_map(DummyMapForGame2) - - class Player(bs.Player['Team']): """Our player type for this game.""" @@ -202,12 +239,12 @@ class UFOAttackGame(bs.TeamGameActivity[Player, Team]): name = 'UFO Attack' description = 'Dodge the falling bombs.' available_settings = [ - bs.BoolSetting('Epic Mode', default=False), - bs.BoolSetting('Enable Run', default=True), - bs.BoolSetting('Enable Jump', default=True), - bs.BoolSetting('Display Map Area Dimension', default=False), - bs.IntSetting('No. of Rows' + u' →',max_value=13, min_value=1, default=8, increment=1), - bs.IntSetting('No. of Columns' + u' ↓', max_value=12, min_value=1, default=6, increment=1) + bs.BoolSetting('Epic Mode', default=False), + bs.BoolSetting('Enable Run', default=True), + bs.BoolSetting('Enable Jump', default=True), + bs.BoolSetting('Display Map Area Dimension', default=False), + bs.IntSetting('No. of Rows' + u' →', max_value=13, min_value=1, default=8, increment=1), + bs.IntSetting('No. of Columns' + u' ↓', max_value=12, min_value=1, default=6, increment=1) ] scoreconfig = bs.ScoreConfig(label='Survived', scoretype=bs.ScoreType.SECONDS, @@ -215,9 +252,11 @@ class UFOAttackGame(bs.TeamGameActivity[Player, Team]): # Print messages when players die (since its meaningful in this game). announce_player_deaths = True + @classmethod def get_supported_maps(cls, sessiontype: Type[bs.Session]) -> List[str]: return ['Tile Lands', 'Tile Lands Night'] + @classmethod def supports_session_type(cls, sessiontype: Type[bs.Session]) -> bool: return (issubclass(sessiontype, bs.DualTeamSession) @@ -225,7 +264,7 @@ def supports_session_type(cls, sessiontype: Type[bs.Session]) -> bool: def __init__(self, settings: dict): super().__init__(settings) - + self.col = int(settings['No. of Columns' + u' ↓']) self.row = int(settings['No. of Rows' + u' →']) self.bool1 = bool(settings['Enable Run']) @@ -237,7 +276,8 @@ def __init__(self, settings: dict): if self._epic_mode else bs.MusicType.SURVIVAL) if bool(settings["Display Map Area Dimension"]): self.game_name = "UFO Attack " + "(" + str(self.col) + "x" + str(self.row) + ")" - else: self.game_name = "UFO Attack" + else: + self.game_name = "UFO Attack" if self._epic_mode: self.slow_motion = True @@ -248,11 +288,11 @@ def on_begin(self) -> None: super().on_begin() self._timer = OnScreenTimer() self._timer.start() - #bs.timer(5.0, self._check_end_game) + # bs.timer(5.0, self._check_end_game) for r in range(self.col): for j in range(self.row): tile = TileFloor(pos=(-6.204283+(j*1.399), 3.425666, - -1.3538+(r*1.399))).autoretain() + -1.3538+(r*1.399))).autoretain() self.ufo = UFO(pos=(-5.00410667, 6.616383286, -2.503472)).autoretain() bs.timer(7000*0.001, lambda: self.ufo.move()) for t in self.players: @@ -262,7 +302,7 @@ def on_player_join(self, player: Player) -> None: if self.has_begun(): bs.broadcastmessage( babase.Lstr(resource='playerDelayedJoinText', - subs=[('${PLAYER}', player.getname(full=True))]), + subs=[('${PLAYER}', player.getname(full=True))]), color=(0, 1, 0), ) assert self._timer is not None @@ -278,9 +318,10 @@ def spawn_player(self, player: Player) -> bs.Actor: for a in bs.getnodes(): g = a.getdelegate(object) if a.getnodetype() == 'prop' and isinstance(g, TileFloor): - dis.append(g.node) + dis.append(g.node) r = random.randint(0, len(dis)-1) - spaz = self.spawn_player_spaz(player, position=(dis[r].position[0], dis[r].position[1]+1.005958, dis[r].position[2])) + spaz = self.spawn_player_spaz(player, position=( + dis[r].position[0], dis[r].position[1]+1.005958, dis[r].position[2])) spaz.connect_controls_to_player(enable_punch=False, enable_bomb=False, enable_run=self.bool1, @@ -288,6 +329,7 @@ def spawn_player(self, player: Player) -> bs.Actor: enable_pickup=False) spaz.play_big_death_sound = True return spaz + def handlemessage(self, msg: Any) -> Any: if isinstance(msg, bs.PlayerDiedMessage): super().handlemessage(msg) @@ -308,7 +350,7 @@ def _check_end_game(self) -> None: living_team_count += 1 break if living_team_count <= 1: - self.end_game() + self.end_game() def end_game(self) -> None: self.ufo.handlemessage(bs.DieMessage()) @@ -337,4 +379,4 @@ def end_game(self) -> None: # Submit the score value in milliseconds. results.set_team_score(team, int(longest_life)) - self.end(results=results) \ No newline at end of file + self.end(results=results) diff --git a/plugins/minigames/safe_zone.py b/plugins/minigames/safe_zone.py index 4c2620f0..56808770 100644 --- a/plugins/minigames/safe_zone.py +++ b/plugins/minigames/safe_zone.py @@ -176,6 +176,7 @@ def __init__(self) -> None: self.survival_seconds: Optional[int] = None self.spawn_order: List[Player] = [] + lang = bs.app.lang.language if lang == 'Spanish': description = 'Mantente en la zona segura.' @@ -187,6 +188,8 @@ def __init__(self) -> None: kill_timer = 'Kill timer: ' # ba_meta export bascenev1.GameActivity + + class SafeZoneGame(bs.TeamGameActivity[Player, Team]): """Game type where last player(s) left alive win.""" @@ -244,7 +247,7 @@ def supports_session_type(cls, sessiontype: Type[bs.Session]) -> bool: @classmethod def get_supported_maps(cls, sessiontype: Type[bs.Session]) -> List[str]: - return ['Football Stadium','Hockey Stadium'] + return ['Football Stadium', 'Hockey Stadium'] def __init__(self, settings: dict): super().__init__(settings) @@ -263,7 +266,7 @@ def __init__(self, settings: dict): self.slow_motion = self._epic_mode self.default_music = (bs.MusicType.EPIC if self._epic_mode else bs.MusicType.SURVIVAL) - + self._tick_sound = bs.getsound('tick') def get_instance_description(self) -> Union[str, Sequence]: @@ -286,7 +289,7 @@ def on_player_join(self, player: Player) -> None: player.team.survival_seconds = 0 bs.broadcastmessage( babase.Lstr(resource='playerDelayedJoinText', - subs=[('${PLAYER}', player.getname(full=True))]), + subs=[('${PLAYER}', player.getname(full=True))]), color=(0, 1, 0), ) return @@ -305,21 +308,21 @@ def on_player_join(self, player: Player) -> None: # Don't waste time doing this until begin. if self.has_begun(): self._update_icons() - + def on_begin(self) -> None: super().on_begin() self._start_time = bs.time() self.setup_standard_time_limit(self._time_limit) - #self.setup_standard_powerup_drops() - - bs.timer(5,self.spawn_zone) + # self.setup_standard_powerup_drops() + + bs.timer(5, self.spawn_zone) self._bots = stdbot.SpazBotSet() - bs.timer(3,babase.Call(self.add_bot,'left')) - bs.timer(3,babase.Call(self.add_bot,'right')) + bs.timer(3, babase.Call(self.add_bot, 'left')) + bs.timer(3, babase.Call(self.add_bot, 'right')) if len(self.initialplayerinfos) > 4: - bs.timer(5,babase.Call(self.add_bot,'right')) - bs.timer(5,babase.Call(self.add_bot,'left')) - + bs.timer(5, babase.Call(self.add_bot, 'right')) + bs.timer(5, babase.Call(self.add_bot, 'left')) + if self._solo_mode: self._vs_text = bs.NodeActor( bs.newnode('text', @@ -359,78 +362,88 @@ def on_begin(self) -> None: # We could check game-over conditions at explicit trigger points, # but lets just do the simple thing and poll it. bs.timer(1.0, self._update, repeat=True) - + def spawn_zone(self): - self.zone_pos = (random.randrange(-10,10),0.05,random.randrange(-5,5)) - self.zone = bs.newnode('locator',attrs={'shape':'circle','position':self.zone_pos,'color':(1, 1, 0),'opacity':0.8,'draw_beauty':True,'additive':False,'drawShadow':False}) - self.zone_limit = bs.newnode('locator',attrs={'shape':'circleOutline','position':self.zone_pos,'color':(1, 0.2, 0.2),'opacity':0.8,'draw_beauty':True,'additive':False,'drawShadow':False}) - bs.animate_array(self.zone, 'size', 1,{0:[0], 0.3:[self.get_players_count()*0.85], 0.35:[self.get_players_count()*0.8]}) - bs.animate_array(self.zone_limit, 'size', 1,{0:[0], 0.3:[self.get_players_count()*1.2], 0.35:[self.get_players_count()*0.95]}) + self.zone_pos = (random.randrange(-10, 10), 0.05, random.randrange(-5, 5)) + self.zone = bs.newnode('locator', attrs={'shape': 'circle', 'position': self.zone_pos, 'color': ( + 1, 1, 0), 'opacity': 0.8, 'draw_beauty': True, 'additive': False, 'drawShadow': False}) + self.zone_limit = bs.newnode('locator', attrs={'shape': 'circleOutline', 'position': self.zone_pos, 'color': ( + 1, 0.2, 0.2), 'opacity': 0.8, 'draw_beauty': True, 'additive': False, 'drawShadow': False}) + bs.animate_array(self.zone, 'size', 1, {0: [0], 0.3: [ + self.get_players_count()*0.85], 0.35: [self.get_players_count()*0.8]}) + bs.animate_array(self.zone_limit, 'size', 1, {0: [0], 0.3: [ + self.get_players_count()*1.2], 0.35: [self.get_players_count()*0.95]}) self.last_players_count = self.get_players_count() bs.getsound('laserReverse').play() self.start_timer() self.move_zone() - + def delete_zone(self): self.zone.delete() self.zone = None self.zone_limit.delete() self.zone_limit = None bs.getsound('shieldDown').play() - bs.timer(1,self.spawn_zone) - + bs.timer(1, self.spawn_zone) + def move_zone(self): - if self.zone_pos[0] > 0: x = random.randrange(0,10) - else: x = random.randrange(-10,0) - - if self.zone_pos[2] > 0: y = random.randrange(0,5) - else: y = random.randrange(-5,0) - - new_pos = (x,0.05,y) - bs.animate_array(self.zone, 'position', 3,{0:self.zone.position, 8:new_pos}) - bs.animate_array(self.zone_limit, 'position', 3,{0:self.zone_limit.position,8:new_pos}) - + if self.zone_pos[0] > 0: + x = random.randrange(0, 10) + else: + x = random.randrange(-10, 0) + + if self.zone_pos[2] > 0: + y = random.randrange(0, 5) + else: + y = random.randrange(-5, 0) + + new_pos = (x, 0.05, y) + bs.animate_array(self.zone, 'position', 3, {0: self.zone.position, 8: new_pos}) + bs.animate_array(self.zone_limit, 'position', 3, {0: self.zone_limit.position, 8: new_pos}) + def start_timer(self): count = self.get_players_count() - self._time_remaining = 10 if count > 9 else count-1 if count > 6 else count if count > 2 else count*2 - self._timer_x = bs.Timer(1.0,bs.WeakCall(self.tick),repeat=True) + self._time_remaining = 10 if count > 9 else count-1 if count > 6 else count if count > 2 else count*2 + self._timer_x = bs.Timer(1.0, bs.WeakCall(self.tick), repeat=True) # gnode = bs.getactivity().globalsnode # tint = gnode.tint # bs.animate_array(gnode,'tint',3,{0:tint,self._time_remaining*1.5:(1.0,0.5,0.5),self._time_remaining*1.55:tint}) - + def stop_timer(self): self._time = None self._timer_x = None - + def tick(self): self.check_players() self._time = bs.NodeActor(bs.newnode('text', - attrs={'v_attach':'top','h_attach':'center', - 'text':kill_timer+str(self._time_remaining)+'s', - 'opacity':0.8,'maxwidth':100,'h_align':'center', - 'v_align':'center','shadow':1.0,'flatness':1.0, - 'color':(1,1,1),'scale':1.5,'position':(0,-50)} - ) - ) + attrs={'v_attach': 'top', 'h_attach': 'center', + 'text': kill_timer+str(self._time_remaining)+'s', + 'opacity': 0.8, 'maxwidth': 100, 'h_align': 'center', + 'v_align': 'center', 'shadow': 1.0, 'flatness': 1.0, + 'color': (1, 1, 1), 'scale': 1.5, 'position': (0, -50)} + ) + ) self._time_remaining -= 1 self._tick_sound.play() - + def check_players(self): if self._time_remaining <= 0: self.stop_timer() - bs.animate_array(self.zone, 'size', 1,{0:[self.last_players_count*0.8], 1.4:[self.last_players_count*0.8],1.5:[0]}) - bs.animate_array(self.zone_limit, 'size', 1,{0:[self.last_players_count*0.95], 1.45:[self.last_players_count*0.95],1.5:[0]}) - bs.timer(1.5,self.delete_zone) + bs.animate_array(self.zone, 'size', 1, { + 0: [self.last_players_count*0.8], 1.4: [self.last_players_count*0.8], 1.5: [0]}) + bs.animate_array(self.zone_limit, 'size', 1, { + 0: [self.last_players_count*0.95], 1.45: [self.last_players_count*0.95], 1.5: [0]}) + bs.timer(1.5, self.delete_zone) for player in self.players: if not player.actor is None: if player.actor.is_alive(): p1 = player.actor.node.position p2 = self.zone.position - diff = (babase.Vec3(p1[0]-p2[0],0.0,p1[2]-p2[2])) + diff = (babase.Vec3(p1[0]-p2[0], 0.0, p1[2]-p2[2])) dist = (diff.length()) if dist > (self.get_players_count()*0.7): player.actor.handlemessage(bs.DieMessage()) - + def get_players_count(self): count = 0 for player in self.players: @@ -438,7 +451,7 @@ def get_players_count(self): if player.actor.is_alive(): count += 1 return count - + def _update_solo_mode(self) -> None: # For both teams, find the first player on the spawn order list with # lives remaining and spawn them if they're not alive. @@ -558,9 +571,9 @@ def spawn_player(self, player: Player) -> bs.Actor: # spaz but *without* the ability to attack or pick stuff up. actor.connect_controls_to_player(enable_punch=False, - enable_bomb=False, - enable_pickup=False) - + enable_bomb=False, + enable_pickup=False) + # If we have any icons, update their state. for icon in player.icons: icon.handle_player_spawned() @@ -642,38 +655,42 @@ def handlemessage(self, msg: Any) -> Any: if self._solo_mode: player.team.spawn_order.remove(player) player.team.spawn_order.append(player) - elif isinstance(msg,stdbot.SpazBotDiedMessage): + elif isinstance(msg, stdbot.SpazBotDiedMessage): self._on_spaz_bot_died(msg) - - def _on_spaz_bot_died(self,die_msg): - bs.timer(1,babase.Call(self.add_bot,die_msg.spazbot.node.position)) - - def _on_bot_spawn(self,spaz): + + def _on_spaz_bot_died(self, die_msg): + bs.timer(1, babase.Call(self.add_bot, die_msg.spazbot.node.position)) + + def _on_bot_spawn(self, spaz): spaz.update_callback = self.move_bot spaz_type = type(spaz) spaz._charge_speed = self._get_bot_speed(spaz_type) - def add_bot(self,pos=None): - if pos == 'left': position = (-11,0,random.randrange(-5,5)) - elif pos == 'right': position = (11,0,random.randrange(-5,5)) - else: position = pos - self._bots.spawn_bot(self.get_random_bot(),pos=position,spawn_time=1,on_spawn_call=babase.Call(self._on_bot_spawn)) + def add_bot(self, pos=None): + if pos == 'left': + position = (-11, 0, random.randrange(-5, 5)) + elif pos == 'right': + position = (11, 0, random.randrange(-5, 5)) + else: + position = pos + self._bots.spawn_bot(self.get_random_bot(), pos=position, spawn_time=1, + on_spawn_call=babase.Call(self._on_bot_spawn)) - def move_bot(self,bot): + def move_bot(self, bot): p = bot.node.position - speed = -bot._charge_speed if(p[0]>=-11 and p[0]<0) else bot._charge_speed - - if (p[0]>=-11) and (p[0]<=11): + speed = -bot._charge_speed if (p[0] >= -11 and p[0] < 0) else bot._charge_speed + + if (p[0] >= -11) and (p[0] <= 11): bot.node.move_left_right = speed bot.node.move_up_down = 0.0 bot.node.run = 0.0 return True return False - + def get_random_bot(self): bots = [stdbot.BomberBotStatic, stdbot.TriggerBotStatic] return (random.choice(bots)) - + def _get_bot_speed(self, bot_type): if bot_type == stdbot.BomberBotStatic: return 0.48 @@ -681,7 +698,7 @@ def _get_bot_speed(self, bot_type): return 0.73 else: raise Exception('Invalid bot type to _getBotSpeed(): '+str(bot_type)) - + def _update(self) -> None: if self._solo_mode: # For both teams, find the first player on the spawn order diff --git a/plugins/utilities/InfinityShield.py b/plugins/utilities/InfinityShield.py index a224ba3f..95104523 100644 --- a/plugins/utilities/InfinityShield.py +++ b/plugins/utilities/InfinityShield.py @@ -18,6 +18,8 @@ Spaz._old_init = Spaz.__init__ + + def __init__(self, color: Sequence[float] = (1.0, 1.0, 1.0), highlight: Sequence[float] = (0.5, 0.5, 0.5), @@ -27,10 +29,11 @@ def __init__(self, can_accept_powerups: bool = True, powerups_expire: bool = False, demo_mode: bool = False): - self._old_init(color,highlight,character,source_player,start_invincible, - can_accept_powerups,powerups_expire,demo_mode) + self._old_init(color, highlight, character, source_player, start_invincible, + can_accept_powerups, powerups_expire, demo_mode) if self.source_player: self.equip_shields() + def animate_shield(): if not self.shield: return @@ -41,6 +44,7 @@ def animate_shield(): bs.timer(0.2, animate_shield, repeat=True) self.impact_scale = 0 + def equip_shields(self, decay: bool = False) -> None: """ Give this spaz a nice energy shield. diff --git a/plugins/utilities/Tag.py b/plugins/utilities/Tag.py index 4ec9a9d4..24139ae4 100644 --- a/plugins/utilities/Tag.py +++ b/plugins/utilities/Tag.py @@ -29,7 +29,7 @@ Tuple, Optional, Sequence, - Union, + Union, Callable, Any, List, @@ -52,18 +52,22 @@ } # Useful global fucntions + + def setconfigs() -> None: """ Set required defualt configs for mod """ cnfg = babase.app.config profiles = cnfg['Player Profiles'] - if not "TagConf" in cnfg: cnfg["TagConf"] = {} + if not "TagConf" in cnfg: + cnfg["TagConf"] = {} for p in profiles: if not p in cnfg["TagConf"]: cnfg["TagConf"][str(p)] = Configs babase.app.config.apply_and_commit() + def getanimcolor(name: str) -> dict: """ Returns dictnary of colors with prefective time -> {seconds: (r, g, b)} @@ -72,14 +76,15 @@ def getanimcolor(name: str) -> dict: s1 = 0.0 s2 = s1 + freq s3 = s2 + freq - + animcolor = { - s1: (1,0,0), - s2: (0,1,0), - s3: (0,0,1) + s1: (1, 0, 0), + s2: (0, 1, 0), + s3: (0, 0, 1) } return animcolor + def gethostname() -> str: """ Return player name, by using -1 only host can use tags. @@ -94,17 +99,20 @@ def gethostname() -> str: return '__account__' return name + # Dummy functions for extend functionality for class object PlayerSpaz.init = PlayerSpaz.__init__ EditProfileWindow.init = EditProfileWindow.__init__ # PlayerSpaz object at -> bascenev1lib.actor.playerspaz + + def NewPlayerSzapInit(self, - player: bs.Player, - color: Sequence[float] = (1.0, 1.0, 1.0), - highlight: Sequence[float] = (0.5, 0.5, 0.5), - character: str = 'Spaz', - powerups_expire: bool = True) -> None: + player: bs.Player, + color: Sequence[float] = (1.0, 1.0, 1.0), + highlight: Sequence[float] = (0.5, 0.5, 0.5), + character: str = 'Spaz', + powerups_expire: bool = True) -> None: self.init(player, color, highlight, character, powerups_expire) self.curname = gethostname() @@ -112,7 +120,8 @@ def NewPlayerSzapInit(self, cnfg = babase.app.config["TagConf"] if cnfg[str(self.curname)]["enabletag"]: # Tag node - self.mnode = bs.newnode('math', owner=self.node, attrs={'input1': (0, 1.5, 0),'operation': 'add'}) + self.mnode = bs.newnode('math', owner=self.node, attrs={ + 'input1': (0, 1.5, 0), 'operation': 'add'}) self.node.connectattr('torso_position', self.mnode, 'input2') tagtext = cnfg[str(self.curname)]["tag"] @@ -120,7 +129,7 @@ def NewPlayerSzapInit(self, shadow = cnfg[str(self.curname)]["shadow"] sl = cnfg[str(self.curname)]["scale"] scale = 0.01 if sl == 'mediam' else 0.009 if not sl == 'large' else 0.02 - + self.Tag = bs.newnode( type='text', owner=self.node, @@ -128,7 +137,7 @@ def NewPlayerSzapInit(self, 'text': str(tagtext), 'in_world': True, 'shadow': shadow, - 'color': (0,0,0), + 'color': (0, 0, 0), 'scale': scale, 'opacity': opacity, 'flatness': 1.0, @@ -138,13 +147,14 @@ def NewPlayerSzapInit(self, if cnfg[str(self.curname)]["animtag"]: kys = getanimcolor(self.curname) bs.animate_array(node=self.Tag, attr='color', size=3, keys=kys, loop=True) - except Exception: pass + except Exception: + pass def NewEditProfileWindowInit(self, - existing_profile: Optional[str], - in_main_menu: bool, - transition: str = 'in_right') -> None: + existing_profile: Optional[str], + in_main_menu: bool, + transition: str = 'in_right') -> None: """ New boilerplate for editprofilewindow, addeds button to call TagSettings window """ @@ -156,17 +166,18 @@ def NewEditProfileWindowInit(self, x_inset = self._x_inset b_width = 50 b_height = 30 - + self.tagwinbtn = bui.buttonwidget( - parent=self._root_widget, - autoselect=True, - position=(505 + x_inset, v - 38 - 15), - size=(b_width, b_height), - color=(0.6, 0.5, 0.6), - label='Tag', - button_type='square', - text_scale=1.2, - on_activate_call=babase.Call(_on_tagwinbtn_press, self)) + parent=self._root_widget, + autoselect=True, + position=(505 + x_inset, v - 38 - 15), + size=(b_width, b_height), + color=(0.6, 0.5, 0.6), + label='Tag', + button_type='square', + text_scale=1.2, + on_activate_call=babase.Call(_on_tagwinbtn_press, self)) + def _on_tagwinbtn_press(self): """ @@ -174,10 +185,10 @@ def _on_tagwinbtn_press(self): """ bui.containerwidget(edit=self._root_widget, transition='out_scale') bui.app.ui_v1.set_main_menu_window( - TagWindow(self.existing_profile, - self.in_main_menu, - self._name, - transition='in_right').get_root_widget(), from_window=self._root_widget) + TagWindow(self.existing_profile, + self.in_main_menu, + self._name, + transition='in_right').get_root_widget(), from_window=self._root_widget) # ba_meta require api 8 @@ -188,10 +199,10 @@ def __init__(self) -> None: Tag above actor player head, replacing PlayerSpaz class for getting actor, using EditProfileWindow for UI. """ - if _babase.env().get("build_number",0) >= 20327: + if _babase.env().get("build_number", 0) >= 20327: setconfigs() self.Replace() - + def Replace(self) -> None: """ Replacing bolierplates no harm to relative funtionality only extending @@ -203,10 +214,10 @@ def Replace(self) -> None: class TagWindow(bui.Window): def __init__(self, - existing_profile: Optional[str], - in_main_menu: bool, - profilename: str, - transition: Optional[str] = 'in_right'): + existing_profile: Optional[str], + in_main_menu: bool, + profilename: str, + transition: Optional[str] = 'in_right'): self.existing_profile = existing_profile self.in_main_menu = in_main_menu self.profilename = profilename @@ -220,205 +231,205 @@ def __init__(self, top_extra = 20 if uiscale is babase.UIScale.SMALL else 0 super().__init__( - root_widget=bui.containerwidget( + root_widget=bui.containerwidget( size=(self._width, self._height), transition=transition, scale=(2.06 if uiscale is babase.UIScale.SMALL else - 1.4 if uiscale is babase.UIScale.MEDIUM else 1.0))) - + 1.4 if uiscale is babase.UIScale.MEDIUM else 1.0))) + self._back_button = bui.buttonwidget( - parent=self._root_widget, - autoselect=True, - selectable=False, # FIXME: when press a in text field it selets to button - position=(52 + self.extra_x, self._height - 60), - size=(60, 60), - scale=0.8, - label=babase.charstr(babase.SpecialChar.BACK), - button_type='backSmall', - on_activate_call=self._back) + parent=self._root_widget, + autoselect=True, + selectable=False, # FIXME: when press a in text field it selets to button + position=(52 + self.extra_x, self._height - 60), + size=(60, 60), + scale=0.8, + label=babase.charstr(babase.SpecialChar.BACK), + button_type='backSmall', + on_activate_call=self._back) bui.containerwidget(edit=self._root_widget, cancel_button=self._back_button) self._save_button = bui.buttonwidget( - parent=self._root_widget, - position=(self._width - (177 + extra_x), - self._height - 60), - size=(155, 60), - color=(0, 0.7, 0.5), - autoselect=True, - selectable=False, # FIXME: when press a in text field it selets to button - scale=0.8, - label=babase.Lstr(resource='saveText'), - on_activate_call=self.on_save) + parent=self._root_widget, + position=(self._width - (177 + extra_x), + self._height - 60), + size=(155, 60), + color=(0, 0.7, 0.5), + autoselect=True, + selectable=False, # FIXME: when press a in text field it selets to button + scale=0.8, + label=babase.Lstr(resource='saveText'), + on_activate_call=self.on_save) bui.widget(edit=self._save_button, left_widget=self._back_button) bui.widget(edit=self._back_button, right_widget=self._save_button) bui.containerwidget(edit=self._root_widget, start_button=self._save_button) self._title_text = bui.textwidget( - parent=self._root_widget, - position=(0, self._height - 52 - top_extra), - size=(self._width, 25), - text='Tag', - color=bui.app.ui_v1.title_color, - scale=1.5, - h_align='center', - v_align='top') - + parent=self._root_widget, + position=(0, self._height - 52 - top_extra), + size=(self._width, 25), + text='Tag', + color=bui.app.ui_v1.title_color, + scale=1.5, + h_align='center', + v_align='top') + self._scroll_width = self._width - (100 + 2 * extra_x) self._scroll_height = self._height - 115.0 self._sub_width = self._scroll_width * 0.95 self._sub_height = 724.0 self._spacing = 32 self._extra_button_spacing = self._spacing * 2.5 - + self._scrollwidget = bui.scrollwidget( - parent=self._root_widget, - position=(50 + extra_x, 50), - simple_culling_v=20.0, - highlight=False, - size=(self._scroll_width, - self._scroll_height), - selection_loops_to_parent=True) + parent=self._root_widget, + position=(50 + extra_x, 50), + simple_culling_v=20.0, + highlight=False, + size=(self._scroll_width, + self._scroll_height), + selection_loops_to_parent=True) bui.widget(edit=self._scrollwidget, right_widget=self._scrollwidget) - + self._subcontainer = bui.containerwidget( - parent=self._scrollwidget, - size=(self._sub_width, - self._sub_height), - background=False, - selection_loops_to_parent=True) - + parent=self._scrollwidget, + size=(self._sub_width, + self._sub_height), + background=False, + selection_loops_to_parent=True) + v = self._sub_height - 35 v -= self._spacing * 1.2 - + self._prof = babase.app.config["TagConf"][self.profilename] self.enabletagcb = bui.checkboxwidget( - parent=self._subcontainer, - autoselect=False, - position=(10.0, v + 30), - size=(10, 10), - text='Enable Tag', - textcolor=(0.8, 0.8, 0.8), - value=self._prof['enabletag'], - on_value_change_call=babase.Call(self.change_val, [f'{self.profilename}', 'enabletag']), - scale=1.1 if uiscale is babase.UIScale.SMALL else 1.5, - maxwidth=430) - + parent=self._subcontainer, + autoselect=False, + position=(10.0, v + 30), + size=(10, 10), + text='Enable Tag', + textcolor=(0.8, 0.8, 0.8), + value=self._prof['enabletag'], + on_value_change_call=babase.Call(self.change_val, [f'{self.profilename}', 'enabletag']), + scale=1.1 if uiscale is babase.UIScale.SMALL else 1.5, + maxwidth=430) + self.tag_text = bui.textwidget( - parent=self._subcontainer, - text='Tag', - position=(25.0, v - 30), - flatness=1.0, - scale=1.55, - maxwidth=430, - h_align='center', - v_align='center', - color=(0.8, 0.8, 0.8)) - + parent=self._subcontainer, + text='Tag', + position=(25.0, v - 30), + flatness=1.0, + scale=1.55, + maxwidth=430, + h_align='center', + v_align='center', + color=(0.8, 0.8, 0.8)) + self.tagtextfield = bui.textwidget( - parent=self._subcontainer, - position=(100.0, v - 45), - size=(350, 50), - text=self._prof["tag"], - h_align='center', - v_align='center', - max_chars=16, - autoselect=True, - editable=True, - padding=4, - color=(0.9, 0.9, 0.9, 1.0)) - + parent=self._subcontainer, + position=(100.0, v - 45), + size=(350, 50), + text=self._prof["tag"], + h_align='center', + v_align='center', + max_chars=16, + autoselect=True, + editable=True, + padding=4, + color=(0.9, 0.9, 0.9, 1.0)) + self.tag_color_text = bui.textwidget( - parent=self._subcontainer, - text='Color', - position=(40.0, v - 80), - flatness=1.0, - scale=1.25, - maxwidth=430, - h_align='center', - v_align='center', - color=(0.8, 0.8, 0.8)) - + parent=self._subcontainer, + text='Color', + position=(40.0, v - 80), + flatness=1.0, + scale=1.25, + maxwidth=430, + h_align='center', + v_align='center', + color=(0.8, 0.8, 0.8)) + self.tag_scale_text = bui.textwidget( - parent=self._subcontainer, - text='Scale', - position=(40.0, v - 130), - flatness=1.0, - scale=1.25, - maxwidth=430, - h_align='center', - v_align='center', - color=(0.8, 0.8, 0.8)) - + parent=self._subcontainer, + text='Scale', + position=(40.0, v - 130), + flatness=1.0, + scale=1.25, + maxwidth=430, + h_align='center', + v_align='center', + color=(0.8, 0.8, 0.8)) + self.tag_scale_button = PopupMenu( - parent=self._subcontainer, - position=(330.0, v - 145), - width=150, - autoselect=True, - on_value_change_call=bs.WeakCall(self._on_menu_choice), - choices=['large', 'medium', 'small'], - button_size=(150, 50), - #choices_display=('large', 'medium', 'small'), - current_choice=self._prof["scale"]) - + parent=self._subcontainer, + position=(330.0, v - 145), + width=150, + autoselect=True, + on_value_change_call=bs.WeakCall(self._on_menu_choice), + choices=['large', 'medium', 'small'], + button_size=(150, 50), + # choices_display=('large', 'medium', 'small'), + current_choice=self._prof["scale"]) + CustomConfigNumberEdit( - parent=self._subcontainer, - position=(40.0, v - 180), - xoffset=65, - displayname='Opacity', - configkey=['TagConf', f'{self.profilename}', 'opacity'], - changesound=False, - minval=0.5, - maxval=2.0, - increment=0.1, - textscale=1.25) - + parent=self._subcontainer, + position=(40.0, v - 180), + xoffset=65, + displayname='Opacity', + configkey=['TagConf', f'{self.profilename}', 'opacity'], + changesound=False, + minval=0.5, + maxval=2.0, + increment=0.1, + textscale=1.25) + CustomConfigNumberEdit( - parent=self._subcontainer, - position=(40.0, v - 230), - xoffset=65, - displayname='Shadow', - configkey=['TagConf', f'{self.profilename}', 'shadow'], - changesound=False, - minval=0.0, - maxval=2.0, - increment=0.1, - textscale=1.25) - + parent=self._subcontainer, + position=(40.0, v - 230), + xoffset=65, + displayname='Shadow', + configkey=['TagConf', f'{self.profilename}', 'shadow'], + changesound=False, + minval=0.0, + maxval=2.0, + increment=0.1, + textscale=1.25) + self.enabletaganim = bui.checkboxwidget( - parent=self._subcontainer, - autoselect=True, - position=(10.0, v - 280), - size=(10, 10), - text='Animate tag', - textcolor=(0.8, 0.8, 0.8), - value=self._prof['enabletag'], - on_value_change_call=babase.Call(self.change_val, [f'{self.profilename}', 'animtag']), - scale=1.1 if uiscale is babase.UIScale.SMALL else 1.5, - maxwidth=430) - + parent=self._subcontainer, + autoselect=True, + position=(10.0, v - 280), + size=(10, 10), + text='Animate tag', + textcolor=(0.8, 0.8, 0.8), + value=self._prof['enabletag'], + on_value_change_call=babase.Call(self.change_val, [f'{self.profilename}', 'animtag']), + scale=1.1 if uiscale is babase.UIScale.SMALL else 1.5, + maxwidth=430) + CustomConfigNumberEdit( - parent=self._subcontainer, - position=(40.0, v - 330), - xoffset=65, - displayname='Frequency', - configkey=['TagConf', f'{self.profilename}', 'frequency'], - changesound=False, - minval=0.1, - maxval=5.0, - increment=0.1, - textscale=1.25) - + parent=self._subcontainer, + position=(40.0, v - 330), + xoffset=65, + displayname='Frequency', + configkey=['TagConf', f'{self.profilename}', 'frequency'], + changesound=False, + minval=0.1, + maxval=5.0, + increment=0.1, + textscale=1.25) + def _back(self) -> None: """ transit window into back window """ bui.containerwidget(edit=self._root_widget, - transition='out_scale') + transition='out_scale') bui.app.ui_v1.set_main_menu_window(EditProfileWindow( - self.existing_profile, - self.in_main_menu, - transition='in_left').get_root_widget(), from_window=self._root_widget) - + self.existing_profile, + self.in_main_menu, + transition='in_left').get_root_widget(), from_window=self._root_widget) + def change_val(self, config: List[str], val: bool) -> None: """ chamges the value of check boxes @@ -428,10 +439,10 @@ def change_val(self, config: List[str], val: bool) -> None: cnfg[config[0]][config[1]] = val bui.getsound('gunCocking').play() except Exception: - bui.screenmessage("error", color=(1,0,0)) + bui.screenmessage("error", color=(1, 0, 0)) bui.getsound('error').play() babase.app.config.apply_and_commit() - + def _on_menu_choice(self, choice: str): """ Changes the given choice in configs @@ -439,7 +450,7 @@ def _on_menu_choice(self, choice: str): cnfg = babase.app.config["TagConf"][self.profilename] cnfg["scale"] = choice babase.app.config.apply_and_commit() - + def on_save(self): """ Gets the text in text field of tag and then save it @@ -451,15 +462,15 @@ def on_save(self): babase.app.config.apply_and_commit() bui.getsound('gunCocking').play() else: - bui.screenmessage(f"please define tag", color=(1,0,0)) + bui.screenmessage(f"please define tag", color=(1, 0, 0)) bui.getsound('error').play() - + bui.containerwidget(edit=self._root_widget, - transition='out_scale') + transition='out_scale') bui.app.ui_v1.set_main_menu_window(EditProfileWindow( - self.existing_profile, - self.in_main_menu, - transition='in_left').get_root_widget(), from_window=self._root_widget) + self.existing_profile, + self.in_main_menu, + transition='in_left').get_root_widget(), from_window=self._root_widget) class CustomConfigNumberEdit: @@ -503,46 +514,46 @@ def __init__(self, self._value = babase.app.config[configkey[0]][configkey[1]][configkey[2]] self.nametext = bui.textwidget( - parent=parent, - position=position, - size=(100, 30), - text=displayname, - maxwidth=160 + xoffset, - color=(0.8, 0.8, 0.8, 1.0), - h_align='left', - v_align='center', - scale=textscale) - + parent=parent, + position=position, + size=(100, 30), + text=displayname, + maxwidth=160 + xoffset, + color=(0.8, 0.8, 0.8, 1.0), + h_align='left', + v_align='center', + scale=textscale) + self.valuetext = bui.textwidget( - parent=parent, - position=(246 + xoffset, position[1]), - size=(60, 28), - editable=False, - color=(0.3, 1.0, 0.3, 1.0), - h_align='right', - v_align='center', - text=str(self._value), - padding=2) - + parent=parent, + position=(246 + xoffset, position[1]), + size=(60, 28), + editable=False, + color=(0.3, 1.0, 0.3, 1.0), + h_align='right', + v_align='center', + text=str(self._value), + padding=2) + self.minusbutton = bui.buttonwidget( - parent=parent, - position=(330 + xoffset, position[1]), - size=(28, 28), - label='-', - autoselect=True, - on_activate_call=babase.Call(self._down), - repeat=True, - enable_sound=changesound) - + parent=parent, + position=(330 + xoffset, position[1]), + size=(28, 28), + label='-', + autoselect=True, + on_activate_call=babase.Call(self._down), + repeat=True, + enable_sound=changesound) + self.plusbutton = bui.buttonwidget(parent=parent, - position=(380 + xoffset, position[1]), - size=(28, 28), - label='+', - autoselect=True, - on_activate_call=babase.Call(self._up), - repeat=True, - enable_sound=changesound) - + position=(380 + xoffset, position[1]), + size=(28, 28), + label='+', + autoselect=True, + on_activate_call=babase.Call(self._up), + repeat=True, + enable_sound=changesound) + bui.uicleanupcheck(self, self.nametext) self._update_display() @@ -558,8 +569,9 @@ def _changed(self) -> None: self._update_display() if self._callback: self._callback(self._value) - babase.app.config[self._configkey[0]][self._configkey[1]][self._configkey[2]] = float(str(f'{self._value:.1f}')) + babase.app.config[self._configkey[0]][self._configkey[1] + ][self._configkey[2]] = float(str(f'{self._value:.1f}')) babase.app.config.apply_and_commit() def _update_display(self) -> None: - bui.textwidget(edit=self.valuetext, text=f'{self._value:.1f}') \ No newline at end of file + bui.textwidget(edit=self.valuetext, text=f'{self._value:.1f}') diff --git a/plugins/utilities/disable_friendly_fire.py b/plugins/utilities/disable_friendly_fire.py index 0771cfe5..e8bf84e7 100644 --- a/plugins/utilities/disable_friendly_fire.py +++ b/plugins/utilities/disable_friendly_fire.py @@ -12,85 +12,89 @@ if TYPE_CHECKING: pass + class BombPickupMessage: """ message says that someone pick up the dropped bomb """ + # for bs.FreezeMessage freeze: bool = True # ba_meta export plugin + + class Plugin(babase.Plugin): - + # there are two ways to ignore our team player hits # either change playerspaz handlemessage or change spaz handlemessage def playerspaz_new_handlemessage(func: fuction) -> fuction: def wrapper(*args, **kwargs): global freeze - - # only run if session is dual team + + # only run if session is dual team if isinstance(args[0].activity.session, bs.DualTeamSession): # when spaz got hurt by any reason this statement is runs. if isinstance(args[1], bs.HitMessage): our_team_players: list[type(args[0]._player)] - + # source_player attacker = args[1].get_source_player(type(args[0]._player)) - + # our team payers our_team_players = args[0]._player.team.players.copy() - + if len(our_team_players) > 0: - - # removing our self - our_team_players.remove(args[0]._player) - - # if we honding teammate or if we have a shield, do hit. - for player in our_team_players: - if player.actor.exists() and args[0]._player.actor.exists(): - if args[0]._player.actor.node.hold_node == player.actor.node or args[0]._player.actor.shield: - our_team_players.remove(player) - break - - if attacker in our_team_players: - freeze = False - return None - else: - freeze = True - + + # removing our self + our_team_players.remove(args[0]._player) + + # if we honding teammate or if we have a shield, do hit. + for player in our_team_players: + if player.actor.exists() and args[0]._player.actor.exists(): + if args[0]._player.actor.node.hold_node == player.actor.node or args[0]._player.actor.shield: + our_team_players.remove(player) + break + + if attacker in our_team_players: + freeze = False + return None + else: + freeze = True + # if ice_bomb blast hits any spaz this statement runs. elif isinstance(args[1], bs.FreezeMessage): if not freeze: - freeze = True # use it and reset it + freeze = True # use it and reset it return None # orignal unchanged code goes here func(*args, **kwargs) - + return wrapper - + # replace original fuction to modified function bascenev1lib.actor.playerspaz.PlayerSpaz.handlemessage = playerspaz_new_handlemessage( bascenev1lib.actor.playerspaz.PlayerSpaz.handlemessage) - + # let's add a message when bomb is pick by player def bombfact_new_init(func: function) -> function: def wrapper(*args): - - func(*args) # original code - + + func(*args) # original code + args[0].bomb_material.add_actions( conditions=('they_have_material', SharedObjects.get().pickup_material), actions=('message', 'our_node', 'at_connect', BombPickupMessage()), ) return wrapper - + # you get the idea bascenev1lib.actor.bomb.BombFactory.__init__ = bombfact_new_init( bascenev1lib.actor.bomb.BombFactory.__init__) - + def bomb_new_handlemessage(func: function) -> function: def wrapper(*args, **kwargs): - # only run if session is dual team + # only run if session is dual team if isinstance(args[0].activity.session, bs.DualTeamSession): if isinstance(args[1], BombPickupMessage): # get the pickuper and assign the pickuper to the source_player(attacker) of bomb blast @@ -99,10 +103,10 @@ def wrapper(*args, **kwargs): if player.actor.node.hold_node == args[0].node: args[0]._source_player = player break - - func(*args, **kwargs) # original - + + func(*args, **kwargs) # original + return wrapper bascenev1lib.actor.bomb.Bomb.handlemessage = bomb_new_handlemessage( - bascenev1lib.actor.bomb.Bomb.handlemessage) \ No newline at end of file + bascenev1lib.actor.bomb.Bomb.handlemessage) From f744c41d7d59efe3bf61c77d2c0f5f7137a7a9f0 Mon Sep 17 00:00:00 2001 From: brostosjoined Date: Wed, 24 Jan 2024 14:28:11 +0300 Subject: [PATCH 0826/1464] i -> I --- plugins/utilities.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/utilities.json b/plugins/utilities.json index 2c5f0253..d48ee7b0 100644 --- a/plugins/utilities.json +++ b/plugins/utilities.json @@ -1086,7 +1086,7 @@ "1.0.0": null } }, - "infinityShield": { + "InfinityShield": { "description": "Gives you unbreakable shield", "external_url": "https://youtu.be/hp7vbB-hUPg?si=i7Th0NP5xDPLN2P_", "authors": [ From 6de5f5f3a7fcc0e82c61d40493fedd38b9426f8b Mon Sep 17 00:00:00 2001 From: brostosjoined Date: Wed, 24 Jan 2024 11:29:20 +0000 Subject: [PATCH 0827/1464] [ci] apply-version-metadata --- plugins/minigames.json | 49 ++++++++++++++++++++++++++++++++++++------ plugins/utilities.json | 30 +++++++++++++++++++++----- 2 files changed, 67 insertions(+), 12 deletions(-) diff --git a/plugins/minigames.json b/plugins/minigames.json index d9d5323a..06a4091b 100644 --- a/plugins/minigames.json +++ b/plugins/minigames.json @@ -979,7 +979,12 @@ } ], "versions": { - "1.0.0": null + "1.0.0": { + "api_version": 8, + "commit_sha": "f744c41", + "released_on": "24-01-2024", + "md5sum": "c1c96450fbdb6e5b2f0d26bb4e797236" + } } }, "HYPER_RACE": { @@ -993,7 +998,12 @@ } ], "versions": { - "1.0.0": null + "1.0.0": { + "api_version": 8, + "commit_sha": "f744c41", + "released_on": "24-01-2024", + "md5sum": "8b423bdae256bd411489528b550b8bd9" + } } }, "meteorshowerdeluxe": { @@ -1007,7 +1017,12 @@ } ], "versions": { - "1.0.0": null + "1.0.0": { + "api_version": 8, + "commit_sha": "f744c41", + "released_on": "24-01-2024", + "md5sum": "7e86bbc8e3ebb26a66602068950adfbf" + } } }, "ofuuuAttack": { @@ -1021,7 +1036,12 @@ } ], "versions": { - "1.0.0": null + "1.0.0": { + "api_version": 8, + "commit_sha": "f744c41", + "released_on": "24-01-2024", + "md5sum": "982c72f2d2cb3d50280f50b022e7865f" + } } }, "safe_zone": { @@ -1035,7 +1055,12 @@ } ], "versions": { - "1.0.0": null + "1.0.0": { + "api_version": 8, + "commit_sha": "f744c41", + "released_on": "24-01-2024", + "md5sum": "862fab0c26947c70397542742fb82635" + } } }, "SnowBallFight": { @@ -1049,7 +1074,12 @@ } ], "versions": { - "1.0.0": null + "1.0.0": { + "api_version": 8, + "commit_sha": "f744c41", + "released_on": "24-01-2024", + "md5sum": "ef6bd7cd0404674f65e8f8d4da3ab8c8" + } } }, "EggGame": { @@ -1063,7 +1093,12 @@ } ], "versions": { - "1.0.0": null + "1.0.0": { + "api_version": 8, + "commit_sha": "f744c41", + "released_on": "24-01-2024", + "md5sum": "e1d401ec8f2d06dec741d713d6602710" + } } } } diff --git a/plugins/utilities.json b/plugins/utilities.json index d48ee7b0..8a7d763a 100644 --- a/plugins/utilities.json +++ b/plugins/utilities.json @@ -1083,7 +1083,12 @@ } ], "versions": { - "1.0.0": null + "1.0.0": { + "api_version": 8, + "commit_sha": "f744c41", + "released_on": "24-01-2024", + "md5sum": "203ecefa1c1eb9894cfb0d87e2d7fe09" + } } }, "InfinityShield": { @@ -1097,7 +1102,12 @@ } ], "versions": { - "1.0.0": null + "1.0.0": { + "api_version": 8, + "commit_sha": "f744c41", + "released_on": "24-01-2024", + "md5sum": "eb917ca19d206dfd19667181dacc1df5" + } } }, "OnlyNight": { @@ -1111,7 +1121,12 @@ } ], "versions": { - "1.0.0": null + "1.0.0": { + "api_version": 8, + "commit_sha": "f744c41", + "released_on": "24-01-2024", + "md5sum": "255d3d6694008cc2f73d115182100b52" + } } }, "Tag": { @@ -1125,8 +1140,13 @@ } ], "versions": { - "2.0.1": null + "2.0.1": { + "api_version": 8, + "commit_sha": "f744c41", + "released_on": "24-01-2024", + "md5sum": "01cf9e10ab0e1bf51c07d80ff842c632" + } } - } + } } } \ No newline at end of file From fcd4cc8169fbee92d183d6294d93a78ea91bd2c1 Mon Sep 17 00:00:00 2001 From: brostosjoined Date: Wed, 24 Jan 2024 21:14:55 +0300 Subject: [PATCH 0828/1464] =?UTF-8?q?=F0=9F=90=8D=F0=9F=92=BC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- plugins/minigames.json | 73 +-- plugins/minigames/{EggGame.py => egg_game.py} | 0 ...howerdeluxe.py => meteor_shower_deluxe.py} | 0 .../{ofuuuAttack.py => ofuuu_attack.py} | 0 .../{SnowBallFight.py => snow_ball_fight.py} | 0 plugins/minigames/you_vs_bombsquad.py | 486 ++++++++++++++++++ plugins/utilities.json | 27 +- .../{InfinityShield.py => infinity_shield.py} | 0 .../utilities/{OnlyNight.py => only_night.py} | 0 9 files changed, 518 insertions(+), 68 deletions(-) rename plugins/minigames/{EggGame.py => egg_game.py} (100%) rename plugins/minigames/{meteorshowerdeluxe.py => meteor_shower_deluxe.py} (100%) rename plugins/minigames/{ofuuuAttack.py => ofuuu_attack.py} (100%) rename plugins/minigames/{SnowBallFight.py => snow_ball_fight.py} (100%) create mode 100644 plugins/minigames/you_vs_bombsquad.py rename plugins/utilities/{InfinityShield.py => infinity_shield.py} (100%) rename plugins/utilities/{OnlyNight.py => only_night.py} (100%) diff --git a/plugins/minigames.json b/plugins/minigames.json index 06a4091b..44e1e93a 100644 --- a/plugins/minigames.json +++ b/plugins/minigames.json @@ -968,7 +968,7 @@ } } }, - "Avalanche": { + "avalanche": { "description": "Dodge the falling ice bombs", "external_url": "", "authors": [ @@ -979,15 +979,10 @@ } ], "versions": { - "1.0.0": { - "api_version": 8, - "commit_sha": "f744c41", - "released_on": "24-01-2024", - "md5sum": "c1c96450fbdb6e5b2f0d26bb4e797236" - } + "1.0.0": null } }, - "HYPER_RACE": { + "hyper_race": { "description": "Race and avoid the obsatacles", "external_url": "", "authors": [ @@ -998,15 +993,10 @@ } ], "versions": { - "1.0.0": { - "api_version": 8, - "commit_sha": "f744c41", - "released_on": "24-01-2024", - "md5sum": "8b423bdae256bd411489528b550b8bd9" - } + "1.0.0": null } }, - "meteorshowerdeluxe": { + "meteor_shower_deluxe": { "description": "Meteor shower on all maps support", "external_url": "", "authors": [ @@ -1017,15 +1007,10 @@ } ], "versions": { - "1.0.0": { - "api_version": 8, - "commit_sha": "f744c41", - "released_on": "24-01-2024", - "md5sum": "7e86bbc8e3ebb26a66602068950adfbf" - } + "1.0.0": null } }, - "ofuuuAttack": { + "ofuuu_attack": { "description": "Dodge the falling bombs.", "external_url": "", "authors": [ @@ -1036,12 +1021,7 @@ } ], "versions": { - "1.0.0": { - "api_version": 8, - "commit_sha": "f744c41", - "released_on": "24-01-2024", - "md5sum": "982c72f2d2cb3d50280f50b022e7865f" - } + "1.0.0": null } }, "safe_zone": { @@ -1055,15 +1035,10 @@ } ], "versions": { - "1.0.0": { - "api_version": 8, - "commit_sha": "f744c41", - "released_on": "24-01-2024", - "md5sum": "862fab0c26947c70397542742fb82635" - } + "1.0.0": null } }, - "SnowBallFight": { + "snow_ball_fight": { "description": "Throw snoballs and dominate", "external_url": "https://youtu.be/uXyb_meBjGI?si=D_N_OXZT5BFh8R5C", "authors": [ @@ -1074,15 +1049,10 @@ } ], "versions": { - "1.0.0": { - "api_version": 8, - "commit_sha": "f744c41", - "released_on": "24-01-2024", - "md5sum": "ef6bd7cd0404674f65e8f8d4da3ab8c8" - } + "1.0.0": null } }, - "EggGame": { + "egg_game": { "description": "Throw Egg as far u can", "external_url": "https://youtu.be/82vLp9ceCcw?si=OSC5Hu3Ns7PevlwP", "authors": [ @@ -1093,12 +1063,21 @@ } ], "versions": { - "1.0.0": { - "api_version": 8, - "commit_sha": "f744c41", - "released_on": "24-01-2024", - "md5sum": "e1d401ec8f2d06dec741d713d6602710" + "1.0.0": null + } + }, + "you_vs_bombsquad": { + "description": "You against bombsquad solo or with friends", + "external_url": "", + "authors": [ + { + "name": "JoseAng3l", + "email": "", + "discord": "joseang3l" } + ], + "versions": { + "1.0.0": null } } } diff --git a/plugins/minigames/EggGame.py b/plugins/minigames/egg_game.py similarity index 100% rename from plugins/minigames/EggGame.py rename to plugins/minigames/egg_game.py diff --git a/plugins/minigames/meteorshowerdeluxe.py b/plugins/minigames/meteor_shower_deluxe.py similarity index 100% rename from plugins/minigames/meteorshowerdeluxe.py rename to plugins/minigames/meteor_shower_deluxe.py diff --git a/plugins/minigames/ofuuuAttack.py b/plugins/minigames/ofuuu_attack.py similarity index 100% rename from plugins/minigames/ofuuuAttack.py rename to plugins/minigames/ofuuu_attack.py diff --git a/plugins/minigames/SnowBallFight.py b/plugins/minigames/snow_ball_fight.py similarity index 100% rename from plugins/minigames/SnowBallFight.py rename to plugins/minigames/snow_ball_fight.py diff --git a/plugins/minigames/you_vs_bombsquad.py b/plugins/minigames/you_vs_bombsquad.py new file mode 100644 index 00000000..5d662d11 --- /dev/null +++ b/plugins/minigames/you_vs_bombsquad.py @@ -0,0 +1,486 @@ +# Ported to api 8 by brostos using baport.(https://github.com/bombsquad-community/baport) +"""you vs BombSquad / Created by: byANG3L""" + +# ba_meta require api 8 +# (see https://ballistica.net/wiki/meta-tag-system) + +from __future__ import annotations + +from typing import TYPE_CHECKING + +import babase +import bauiv1 as bui +import bascenev1 as bs +import _babase +import random +from bascenev1lib.actor.spazbot import SpazBotSet, BrawlerBot, SpazBotDiedMessage +from bascenev1lib.actor.onscreentimer import OnScreenTimer + +if TYPE_CHECKING: + from typing import Any, Optional + +lang = bs.app.lang.language +if lang == 'Spanish': + name = 'Tu vs BombSquad' + name_easy = 'Tu vs BS Fácil' + name_easy_epic = 'Tu vs BS Fácil Épico' + name_hard = 'Tu vs BS Difícil' + name_hard_epic = 'Tu vs BS Difícil Épico' +else: + name = 'You vs BombSquad' + name_easy = 'You vs BS Easy' + name_easy_epic = 'You vs BS Easy Epic' + name_hard = 'You vs BS Hard' + name_hard_epic = 'You vs BS Hard Epic' + +# def ba_get_api_version(): +# return 6 + +def ba_get_levels(): + return [babase._level.Level( + name_easy, + gametype=TUvsBombSquad, + settings={}, + preview_texture_name='footballStadiumPreview'), + babase._level.Level( + name_easy_epic, + gametype=TUvsBombSquad, + settings={'Epic Mode': True}, + preview_texture_name='footballStadiumPreview'), + + babase._level.Level( + name_hard, + gametype=TUvsBombSquad, + settings={'Hard Mode': True}, + preview_texture_name='footballStadiumPreview'), + babase._level.Level( + name_hard_epic, + gametype=TUvsBombSquad, + settings={'Hard Mode': True, + 'Epic Mode': True}, + preview_texture_name='footballStadiumPreview')] + +#### BOTS #### +class SpazBot(BrawlerBot): + character = 'Spaz' + color=(0.1,0.35,0.1) + highlight=(1,0.15,0.15) + +class ZoeBot(BrawlerBot): + character = 'Zoe' + color=(0.6,0.6,0.6) + highlight=(0,1,0) + +class SnakeBot(BrawlerBot): + character = 'Snake Shadow' + color=(1,1,1) + highlight=(0.55,0.8,0.55) + +class MelBot(BrawlerBot): + character = 'Mel' + color=(1,1,1) + highlight=(0.1,0.6,0.1) + +class JackBot(BrawlerBot): + character = 'Jack Morgan' + color=(1,0.2,0.1) + highlight=(1,1,0) + +class SantaBot(BrawlerBot): + character = 'Santa Claus' + color=(1,0,0) + highlight=(1,1,1) + +class FrostyBot(BrawlerBot): + character = 'Frosty' + color=(0.5,0.5,1) + highlight=(1,0.5,0) + +class BonesBot(BrawlerBot): + character = 'Bones' + color=(0.6,0.9,1) + highlight=(0.6,0.9,1) + +class BernardBot(BrawlerBot): + character = 'Bernard' + color=(0.7,0.5,0.0) + highlight=(0.6,0.5,0.8) + +class PascalBot(BrawlerBot): + character = 'Pascal' + color=(0.3,0.5,0.8) + highlight=(1,0,0) + +class TaobaoBot(BrawlerBot): + character = 'Taobao Mascot' + color=(1,0.5,0) + highlight=(1,1,1) + +class BBot(BrawlerBot): + character = 'B-9000' + color=(0.5,0.5,0.5) + highlight=(1,0,0) + +class AgentBot(BrawlerBot): + character = 'Agent Johnson' + color=(0.3,0.3,0.33) + highlight=(1,0.5,0.3) + +class GrumbledorfBot(BrawlerBot): + character = 'Grumbledorf' + color=(0.2,0.4,1.0) + highlight=(0.06,0.15,0.4) + +class PixelBot(BrawlerBot): + character = 'Pixel' + color=(0,1,0.7) + highlight=(0.65,0.35,0.75) + +class BunnyBot(BrawlerBot): + character = 'Easter Bunny' + color=(1,1,1) + highlight=(1,0.5,0.5) + +class Player(bs.Player['Team']): + """Our player type for this game.""" + + +class Team(bs.Team[Player]): + """Our team type for this game.""" + + +# ba_meta export bascenev1.GameActivity +class TUvsBombSquad(bs.TeamGameActivity[Player, Team]): + """A game type based on acquiring kills.""" + + name = name + description = 'Defeat all enemies.' + scoreconfig = bs.ScoreConfig(label='Time', + scoretype=bs.ScoreType.MILLISECONDS, + lower_is_better=True) + + @classmethod + def get_available_settings( + cls, sessiontype: Type[bs.Session]) -> List[babase.Setting]: + settings = [ + bs.BoolSetting('Hard Mode', default=False), + bs.BoolSetting('Epic Mode', default=False), + ] + return settings + + @classmethod + def supports_session_type(cls, sessiontype: Type[bs.Session]) -> bool: + return (issubclass(sessiontype, bs.CoopSession) + or issubclass(sessiontype, bs.MultiTeamSession)) + + @classmethod + def get_supported_maps(cls, sessiontype: Type[bs.Session]) -> List[str]: + return ['Football Stadium'] + + def __init__(self, settings: dict): + super().__init__(settings) + self._winsound = bs.getsound('score') + self._won = False + self._timer: Optional[OnScreenTimer] = None + self._bots = SpazBotSet() + self._hard_mode = bool(settings['Hard Mode']) + self._epic_mode = bool(settings['Epic Mode']) + + # Base class overrides. + self.slow_motion = self._epic_mode + self.default_music = (bs.MusicType.EPIC if self._epic_mode else + bs.MusicType.SURVIVAL) + + self._spaz_easy: list = [[(-5.4146, 0.9515, -3.0379), 23.0], + [(-5.4146, 0.9515, 1.0379), 23.0]] + self._spaz_hard: list = [[(11.4146, 0.9515, -5.0379), 3.0], + [(-8.4146, 0.9515, -5.0379), 5.0], + [(5.4146, 0.9515, -3.0379), 8.0], + [(5.4146, 0.9515, 1.0379), 8.0]] + self._zoe_easy: list = [[(5.4146, 0.9515, -1.0379), 23.0], + [(-5.4146, 0.9515, 5.0379), 23.0]] + self._zoe_hard: list = [[(-11.4146, 0.9515, -5.0379), 3.0], + [(8.4146, 0.9515, -3.0379), 5.0], + [(-5.4146, 0.9515, -3.0379), 8.0], + [(-5.4146, 0.9515, 1.0379), 8.0]] + self._snake_easy: list = [[(-5.4146, 0.9515, -1.0379), 23.0], + [(5.4146, 0.9515, -5.0379), 23.0]] + self._snake_hard: list = [[(11.4146, 0.9515, -3.0379), 3.0], + [(-8.4146, 0.9515, -3.0379), 5.0], + [(5.4146, 0.9515, -1.0379), 8.0], + [(5.4146, 0.9515, 1.0379), 8.0]] + self._kronk_easy: list = [[(8.4146, 0.9515, 1.0379), 10.0], + [(5.4146, 0.9515, 3.0379), 23.0]] + self._kronk_hard: list = [[(-11.4146, 0.9515, -3.0379), 3.0], + [(8.4146, 0.9515, -1.0379), 5.0], + [(-5.4146, 0.9515, -1.0379), 8.0], + [(5.4146, 0.9515, 1.0379), 8.0]] + self._mel_easy: list = [[(5.4146, 0.9515, 1.0379), 23.0], + [(-11.4146, 0.9515, 1.0379), 3.0]] + self._mel_hard: list = [[(11.4146, 0.9515, -1.0379), 3.0], + [(-8.4146, 0.9515, -1.0379), 5.0], + [(5.4146, 0.9515, 1.0379), 8.0], + [(5.4146, 0.9515, 5.0379), 8.0]] + self._jack_easy: list = [[(-8.4146, 0.9515, 1.0379), 10.0], + [(5.4146, 0.9515, 1.0379), 23.0]] + self._jack_hard: list = [[(-11.4146, 0.9515, -1.0379), 3.0], + [(8.4146, 0.9515, 1.0379), 5.0], + [(-5.4146, 0.9515, 1.0379), 8.0], + [(-5.4146, 0.9515, 5.0379), 8.0], + [(5.4146, 0.9515, -5.0379), 8.0]] + self._frosty_easy: list = [[(8.4146, 0.9515, 1.0379), 10.0], + [(8.4146, 0.9515, -5.0379), 10.0]] + self._frosty_hard: list = [[(-11.4146, 0.9515, 1.0379), 3.0], + [(-5.4146, 0.9515, 3.0379), 8.0], + [(-5.4146, 0.9515, -5.0379), 8.0], + [(5.4146, 0.9515, 3.0379), 8.0]] + self._bunny_easy: list = [[(-8.4146, 0.9515, 3.0379), 10.0], + [(5.4146, 0.9515, 5.0379), 23.0]] + self._bunny_hard: list = [[(8.4146, 0.9515, -5.0379), 5.0], + [(-5.4146, 0.9515, -5.0379), 8.0], + [(-5.4146, 0.9515, 3.0379), 8.0], + [(8.4146, 0.9515, 3.0379), 5.0]] + self._bones_easy: list = [[(11.4146, 0.9515, -5.0379), 3.0], + [(-8.4146, 0.9515, -5.0379), 10.0]] + self._bones_hard: list = [[(5.4146, 0.9515, -3.0379), 8.0], + [(-5.4146, 0.9515, 3.0379), 8.0], + [(5.4146, 0.9515, 1.0379), 8.0], + [(8.4146, 0.9515, 3.0379), 5.0]] + self._bernard_easy: list = [[(-11.4146, 0.9515, -5.0379), 3.0], + [(8.4146, 0.9515, -3.0379), 10.0]] + self._bernard_hard: list = [[(-5.4146, 0.9515, -3.0379), 8.0], + [(5.4146, 0.9515, 1.0379), 8.0], + [(-5.4146, 0.9515, 1.0379), 8.0], + [(-8.4146, 0.9515, 3.0379), 5.0]] + self._pascal_easy: list = [[(11.4146, 0.9515, -3.0379), 3.0], + [(-8.4146, 0.9515, -3.0379), 10.0]] + self._pascal_hard: list = [[(5.4146, 0.9515, -1.0379), 8.0], + [(-5.4146, 0.9515, 1.0379), 8.0], + [(5.4146, 0.9515, 1.0379), 8.0], + [(8.4146, 0.9515, 1.0379), 5.0]] + self._taobao_easy: list = [[(-11.4146, 0.9515, -3.0379), 3.0], + [(8.4146, 0.9515, -1.0379), 10.0]] + self._taobao_hard: list = [[(-5.4146, 0.9515, -1.0379), 8.0], + [(5.4146, 0.9515, 1.0379), 8.0], + [(-5.4146, 0.9515, 1.0379), 8.0], + [(-5.4146, 0.9515, 1.0379), 8.0]] + self._bbot_easy: list = [[(11.4146, 0.9515, -1.0379), 3.0], + [(-8.4146, 0.9515, -1.0379), 10.0]] + self._bbot_hard: list = [[(-5.4146, 0.9515, 1.0379), 8.0], + [(8.4146, 0.9515, 1.0379), 5.0], + [(-5.4146, 0.9515, 1.0379), 8.0], + [(-5.4146, 0.9515, 1.0379), 8.0]] + self._agent_easy: list = [[(-11.4146, 0.9515, -1.0379), 3.0], + [(8.4146, 0.9515, 1.0379), 10.0]] + self._agent_hard: list = [[(5.4146, 0.9515, 5.0379), 8.0], + [(-8.4146, 0.9515, 1.0379), 5.0], + [(-11.4146, 0.9515, 1.0379), 3.0], + [(-11.4146, 0.9515, 1.0379), 3.0]] + self._wizard_easy: list = [[(11.4146, 0.9515, 1.0379), 3.0], + [(-8.4146, 0.9515, 1.0379), 10.0]] + self._wizard_hard: list = [[(-5.4146, 0.9515, 5.0379), 8.0], + [(8.4146, 0.9515, 5.0379), 5.0], + [(-5.4146, 0.9515, 1.0379), 8.0], + [(11.4146, 0.9515, 1.0379), 3.0]] + self._pixel_easy: list = [[(-5.4146, 0.9515, -5.0379), 23.0]] + self._pixel_hard: list = [[(5.4146, 0.9515, -5.0379), 8.0], + [(5.4146, 0.9515, 3.0379), 5.0], + [(-8.4146, 0.9515, 5.0379), 5.0]] + self._santa_easy: list = [[(-8.4146, 0.9515, 5.0379), 23.0]] + self._santa_hard: list = [[(-8.4146, 0.9515, 1.0379), 5.0], + [(-8.4146, 0.9515, 5.0379), 5.0], + [(5.4146, 0.9515, 1.0379), 8.0]] + + def on_begin(self) -> None: + super().on_begin() + self.setup_standard_powerup_drops() + self._timer = OnScreenTimer() + bs.timer(4.0, self._timer.start) + + for i in range(len(self._spaz_easy)): + self._spawn_bots(4.0, SpazBot, + self._spaz_easy[i][0], self._spaz_easy[i][1]) + for i in range(len(self._zoe_easy)): + self._spawn_bots(4.0, ZoeBot, + self._zoe_easy[i][0], self._zoe_easy[i][1]) + for i in range(len(self._snake_easy)): + self._spawn_bots(4.0, SnakeBot, + self._snake_easy[i][0], self._snake_easy[i][1]) + for i in range(len(self._kronk_easy)): + self._spawn_bots(4.0, BrawlerBot, + self._kronk_easy[i][0], self._kronk_easy[i][1]) + for i in range(len(self._mel_easy)): + self._spawn_bots(4.0, MelBot, + self._mel_easy[i][0], self._mel_easy[i][1]) + for i in range(len(self._jack_easy)): + self._spawn_bots(4.0, JackBot, + self._jack_easy[i][0], self._jack_easy[i][1]) + for i in range(len(self._santa_easy)): + self._spawn_bots(4.0, SantaBot, + self._santa_easy[i][0], self._santa_easy[i][1]) + for i in range(len(self._frosty_easy)): + self._spawn_bots(4.0, FrostyBot, + self._frosty_easy[i][0], self._frosty_easy[i][1]) + for i in range(len(self._bunny_easy)): + self._spawn_bots(4.0, BunnyBot, + self._bunny_easy[i][0], self._bunny_easy[i][1]) + for i in range(len(self._bones_easy)): + self._spawn_bots(4.0, BonesBot, + self._bones_easy[i][0], self._bones_easy[i][1]) + for i in range(len(self._bernard_easy)): + self._spawn_bots(4.0, BernardBot, + self._bernard_easy[i][0], self._bernard_easy[i][1]) + for i in range(len(self._pascal_easy)): + self._spawn_bots(4.0, PascalBot, + self._pascal_easy[i][0], self._pascal_easy[i][1]) + for i in range(len(self._taobao_easy)): + self._spawn_bots(4.0, TaobaoBot, + self._taobao_easy[i][0], self._taobao_easy[i][1]) + for i in range(len(self._bbot_easy)): + self._spawn_bots(4.0, BBot, + self._bbot_easy[i][0], self._bbot_easy[i][1]) + for i in range(len(self._agent_easy)): + self._spawn_bots(4.0, AgentBot, + self._agent_easy[i][0], self._agent_easy[i][1]) + for i in range(len(self._wizard_easy)): + self._spawn_bots(4.0, GrumbledorfBot, + self._wizard_easy[i][0], self._wizard_easy[i][1]) + for i in range(len(self._pixel_easy)): + self._spawn_bots(4.0, PixelBot, + self._pixel_easy[i][0], self._pixel_easy[i][1]) + + if self._hard_mode: + for i in range(len(self._spaz_hard)): + self._spawn_bots(4.0, SpazBot, + self._spaz_hard[i][0], self._spaz_hard[i][1]) + for i in range(len(self._zoe_hard)): + self._spawn_bots(4.0, ZoeBot, + self._zoe_hard[i][0], self._zoe_hard[i][1]) + for i in range(len(self._snake_hard)): + self._spawn_bots(4.0, SnakeBot, + self._snake_hard[i][0], self._snake_hard[i][1]) + for i in range(len(self._kronk_hard)): + self._spawn_bots(4.0, BrawlerBot, + self._kronk_hard[i][0], self._kronk_hard[i][1]) + for i in range(len(self._mel_hard)): + self._spawn_bots(4.0, MelBot, + self._mel_hard[i][0], self._mel_hard[i][1]) + for i in range(len(self._jack_hard)): + self._spawn_bots(4.0, JackBot, + self._jack_hard[i][0], self._jack_hard[i][1]) + for i in range(len(self._santa_hard)): + self._spawn_bots(4.0, SantaBot, + self._santa_hard[i][0], self._santa_hard[i][1]) + for i in range(len(self._frosty_hard)): + self._spawn_bots(4.0, FrostyBot, + self._frosty_hard[i][0], self._frosty_hard[i][1]) + for i in range(len(self._bunny_hard)): + self._spawn_bots(4.0, BunnyBot, + self._bunny_hard[i][0], self._bunny_hard[i][1]) + for i in range(len(self._bones_hard)): + self._spawn_bots(4.0, BonesBot, + self._bones_hard[i][0], self._bones_hard[i][1]) + for i in range(len(self._bernard_hard)): + self._spawn_bots(4.0, BernardBot, + self._bernard_hard[i][0], self._bernard_hard[i][1]) + for i in range(len(self._pascal_hard)): + self._spawn_bots(4.0, PascalBot, + self._pascal_hard[i][0], self._pascal_hard[i][1]) + for i in range(len(self._taobao_hard)): + self._spawn_bots(4.0, TaobaoBot, + self._taobao_hard[i][0], self._taobao_hard[i][1]) + for i in range(len(self._bbot_hard)): + self._spawn_bots(4.0, BBot, + self._bbot_hard[i][0], self._bbot_hard[i][1]) + for i in range(len(self._agent_hard)): + self._spawn_bots(4.0, AgentBot, + self._agent_hard[i][0], self._agent_hard[i][1]) + for i in range(len(self._wizard_hard)): + self._spawn_bots(4.0, GrumbledorfBot, + self._wizard_hard[i][0], self._wizard_hard[i][1]) + for i in range(len(self._pixel_hard)): + self._spawn_bots(4.0, PixelBot, + self._pixel_hard[i][0], self._pixel_hard[i][1]) + + def _spawn_bots(self, time: float, bot: Any, + pos: float, spawn_time: float) -> None: + bs.timer(time, lambda: self._bots.spawn_bot( + bot, pos=pos, spawn_time=spawn_time)) + + def on_player_join(self, player: Player) -> None: + if self.has_begun(): + bs.broadcastmessage( + babase.Lstr(resource='playerDelayedJoinText', + subs=[('${PLAYER}', player.getname(full=True))]), + color=(0, 1, 0), + ) + return + self.spawn_player(player) + + # Called for each spawning player. + def spawn_player(self, player: Player) -> bs.Actor: + + # Let's spawn close to the center. + spawn_center = (0.0728, 0.0227, -1.9888) + pos = (spawn_center[0] + random.uniform(-0.5, 0.5), spawn_center[1], + spawn_center[2] + random.uniform(-0.5, 0.5)) + return self.spawn_player_spaz(player, position=pos) + + def _check_if_won(self) -> None: + # Simply end the game if there's no living bots. + # FIXME: Should also make sure all bots have been spawned; + # if spawning is spread out enough that we're able to kill + # all living bots before the next spawns, it would incorrectly + # count as a win. + if not self._bots.have_living_bots(): + self._won = True + self.end_game() + + # Called for miscellaneous messages. + def handlemessage(self, msg: Any) -> Any: + + # A player has died. + if isinstance(msg, bs.PlayerDiedMessage): + super().handlemessage(msg) # Augment standard behavior. + self.respawn_player(msg.getplayer(Player)) + + # A spaz-bot has died. + elif isinstance(msg, SpazBotDiedMessage): + # Unfortunately the bot-set will always tell us there are living + # bots if we ask here (the currently-dying bot isn't officially + # marked dead yet) ..so lets push a call into the event loop to + # check once this guy has finished dying. + babase.pushcall(self._check_if_won) + + # Let the base class handle anything we don't. + else: + return super().handlemessage(msg) + return None + + # When this is called, we should fill out results and end the game + # *regardless* of whether is has been won. (this may be called due + # to a tournament ending or other external reason). + def end_game(self) -> None: + + # Stop our on-screen timer so players can see what they got. + assert self._timer is not None + self._timer.stop() + + results = bs.GameResults() + + # If we won, set our score to the elapsed time in milliseconds. + # (there should just be 1 team here since this is co-op). + # ..if we didn't win, leave scores as default (None) which means + # we lost. + if self._won: + elapsed_time_ms = int((bs.time() - self._timer.starttime) * 1000.0) + bs.cameraflash() + self._winsound.play() + for team in self.teams: + for player in team.players: + if player.actor: + player.actor.handlemessage(bs.CelebrateMessage()) + results.set_team_score(team, elapsed_time_ms) + + # Ends the activity. + self.end(results) diff --git a/plugins/utilities.json b/plugins/utilities.json index 8a7d763a..743c3724 100644 --- a/plugins/utilities.json +++ b/plugins/utilities.json @@ -1091,7 +1091,7 @@ } } }, - "InfinityShield": { + "infinity_shield": { "description": "Gives you unbreakable shield", "external_url": "https://youtu.be/hp7vbB-hUPg?si=i7Th0NP5xDPLN2P_", "authors": [ @@ -1102,15 +1102,10 @@ } ], "versions": { - "1.0.0": { - "api_version": 8, - "commit_sha": "f744c41", - "released_on": "24-01-2024", - "md5sum": "eb917ca19d206dfd19667181dacc1df5" - } + "1.0.0": null } }, - "OnlyNight": { + "0nly_night": { "description": "Night Mode", "external_url": "", "authors": [ @@ -1121,15 +1116,10 @@ } ], "versions": { - "1.0.0": { - "api_version": 8, - "commit_sha": "f744c41", - "released_on": "24-01-2024", - "md5sum": "255d3d6694008cc2f73d115182100b52" - } + "1.0.0": null } }, - "Tag": { + "tag": { "description": "Get a tag", "external_url": "", "authors": [ @@ -1140,12 +1130,7 @@ } ], "versions": { - "2.0.1": { - "api_version": 8, - "commit_sha": "f744c41", - "released_on": "24-01-2024", - "md5sum": "01cf9e10ab0e1bf51c07d80ff842c632" - } + "2.0.1": null } } } diff --git a/plugins/utilities/InfinityShield.py b/plugins/utilities/infinity_shield.py similarity index 100% rename from plugins/utilities/InfinityShield.py rename to plugins/utilities/infinity_shield.py diff --git a/plugins/utilities/OnlyNight.py b/plugins/utilities/only_night.py similarity index 100% rename from plugins/utilities/OnlyNight.py rename to plugins/utilities/only_night.py From 89295db5cc107ba2d4f3d90ccda9b79b5a0cc843 Mon Sep 17 00:00:00 2001 From: brostosjoined Date: Wed, 24 Jan 2024 18:17:42 +0000 Subject: [PATCH 0829/1464] [ci] auto-format --- plugins/minigames/you_vs_bombsquad.py | 197 ++++++++++++++------------ 1 file changed, 108 insertions(+), 89 deletions(-) diff --git a/plugins/minigames/you_vs_bombsquad.py b/plugins/minigames/you_vs_bombsquad.py index 5d662d11..c28a5391 100644 --- a/plugins/minigames/you_vs_bombsquad.py +++ b/plugins/minigames/you_vs_bombsquad.py @@ -36,110 +36,129 @@ # def ba_get_api_version(): # return 6 + def ba_get_levels(): - return [babase._level.Level( - name_easy, - gametype=TUvsBombSquad, - settings={}, - preview_texture_name='footballStadiumPreview'), - babase._level.Level( - name_easy_epic, - gametype=TUvsBombSquad, - settings={'Epic Mode': True}, - preview_texture_name='footballStadiumPreview'), - - babase._level.Level( - name_hard, - gametype=TUvsBombSquad, - settings={'Hard Mode': True}, - preview_texture_name='footballStadiumPreview'), - babase._level.Level( - name_hard_epic, - gametype=TUvsBombSquad, - settings={'Hard Mode': True, - 'Epic Mode': True}, - preview_texture_name='footballStadiumPreview')] + return [babase._level.Level( + name_easy, + gametype=TUvsBombSquad, + settings={}, + preview_texture_name='footballStadiumPreview'), + babase._level.Level( + name_easy_epic, + gametype=TUvsBombSquad, + settings={'Epic Mode': True}, + preview_texture_name='footballStadiumPreview'), + + babase._level.Level( + name_hard, + gametype=TUvsBombSquad, + settings={'Hard Mode': True}, + preview_texture_name='footballStadiumPreview'), + babase._level.Level( + name_hard_epic, + gametype=TUvsBombSquad, + settings={'Hard Mode': True, + 'Epic Mode': True}, + preview_texture_name='footballStadiumPreview')] #### BOTS #### + + class SpazBot(BrawlerBot): character = 'Spaz' - color=(0.1,0.35,0.1) - highlight=(1,0.15,0.15) + color = (0.1, 0.35, 0.1) + highlight = (1, 0.15, 0.15) + class ZoeBot(BrawlerBot): character = 'Zoe' - color=(0.6,0.6,0.6) - highlight=(0,1,0) + color = (0.6, 0.6, 0.6) + highlight = (0, 1, 0) + class SnakeBot(BrawlerBot): character = 'Snake Shadow' - color=(1,1,1) - highlight=(0.55,0.8,0.55) + color = (1, 1, 1) + highlight = (0.55, 0.8, 0.55) + class MelBot(BrawlerBot): character = 'Mel' - color=(1,1,1) - highlight=(0.1,0.6,0.1) + color = (1, 1, 1) + highlight = (0.1, 0.6, 0.1) + class JackBot(BrawlerBot): character = 'Jack Morgan' - color=(1,0.2,0.1) - highlight=(1,1,0) + color = (1, 0.2, 0.1) + highlight = (1, 1, 0) + class SantaBot(BrawlerBot): character = 'Santa Claus' - color=(1,0,0) - highlight=(1,1,1) + color = (1, 0, 0) + highlight = (1, 1, 1) + class FrostyBot(BrawlerBot): character = 'Frosty' - color=(0.5,0.5,1) - highlight=(1,0.5,0) + color = (0.5, 0.5, 1) + highlight = (1, 0.5, 0) + class BonesBot(BrawlerBot): character = 'Bones' - color=(0.6,0.9,1) - highlight=(0.6,0.9,1) + color = (0.6, 0.9, 1) + highlight = (0.6, 0.9, 1) + class BernardBot(BrawlerBot): character = 'Bernard' - color=(0.7,0.5,0.0) - highlight=(0.6,0.5,0.8) + color = (0.7, 0.5, 0.0) + highlight = (0.6, 0.5, 0.8) + class PascalBot(BrawlerBot): character = 'Pascal' - color=(0.3,0.5,0.8) - highlight=(1,0,0) + color = (0.3, 0.5, 0.8) + highlight = (1, 0, 0) + class TaobaoBot(BrawlerBot): character = 'Taobao Mascot' - color=(1,0.5,0) - highlight=(1,1,1) + color = (1, 0.5, 0) + highlight = (1, 1, 1) + class BBot(BrawlerBot): character = 'B-9000' - color=(0.5,0.5,0.5) - highlight=(1,0,0) + color = (0.5, 0.5, 0.5) + highlight = (1, 0, 0) + class AgentBot(BrawlerBot): character = 'Agent Johnson' - color=(0.3,0.3,0.33) - highlight=(1,0.5,0.3) + color = (0.3, 0.3, 0.33) + highlight = (1, 0.5, 0.3) + class GrumbledorfBot(BrawlerBot): character = 'Grumbledorf' - color=(0.2,0.4,1.0) - highlight=(0.06,0.15,0.4) + color = (0.2, 0.4, 1.0) + highlight = (0.06, 0.15, 0.4) + class PixelBot(BrawlerBot): character = 'Pixel' - color=(0,1,0.7) - highlight=(0.65,0.35,0.75) + color = (0, 1, 0.7) + highlight = (0.65, 0.35, 0.75) + class BunnyBot(BrawlerBot): character = 'Easter Bunny' - color=(1,1,1) - highlight=(1,0.5,0.5) + color = (1, 1, 1) + highlight = (1, 0.5, 0.5) + class Player(bs.Player['Team']): """Our player type for this game.""" @@ -299,108 +318,108 @@ def on_begin(self) -> None: for i in range(len(self._spaz_easy)): self._spawn_bots(4.0, SpazBot, - self._spaz_easy[i][0], self._spaz_easy[i][1]) + self._spaz_easy[i][0], self._spaz_easy[i][1]) for i in range(len(self._zoe_easy)): self._spawn_bots(4.0, ZoeBot, - self._zoe_easy[i][0], self._zoe_easy[i][1]) + self._zoe_easy[i][0], self._zoe_easy[i][1]) for i in range(len(self._snake_easy)): self._spawn_bots(4.0, SnakeBot, - self._snake_easy[i][0], self._snake_easy[i][1]) + self._snake_easy[i][0], self._snake_easy[i][1]) for i in range(len(self._kronk_easy)): self._spawn_bots(4.0, BrawlerBot, - self._kronk_easy[i][0], self._kronk_easy[i][1]) + self._kronk_easy[i][0], self._kronk_easy[i][1]) for i in range(len(self._mel_easy)): self._spawn_bots(4.0, MelBot, - self._mel_easy[i][0], self._mel_easy[i][1]) + self._mel_easy[i][0], self._mel_easy[i][1]) for i in range(len(self._jack_easy)): self._spawn_bots(4.0, JackBot, - self._jack_easy[i][0], self._jack_easy[i][1]) + self._jack_easy[i][0], self._jack_easy[i][1]) for i in range(len(self._santa_easy)): self._spawn_bots(4.0, SantaBot, - self._santa_easy[i][0], self._santa_easy[i][1]) + self._santa_easy[i][0], self._santa_easy[i][1]) for i in range(len(self._frosty_easy)): self._spawn_bots(4.0, FrostyBot, - self._frosty_easy[i][0], self._frosty_easy[i][1]) + self._frosty_easy[i][0], self._frosty_easy[i][1]) for i in range(len(self._bunny_easy)): self._spawn_bots(4.0, BunnyBot, - self._bunny_easy[i][0], self._bunny_easy[i][1]) + self._bunny_easy[i][0], self._bunny_easy[i][1]) for i in range(len(self._bones_easy)): self._spawn_bots(4.0, BonesBot, - self._bones_easy[i][0], self._bones_easy[i][1]) + self._bones_easy[i][0], self._bones_easy[i][1]) for i in range(len(self._bernard_easy)): self._spawn_bots(4.0, BernardBot, - self._bernard_easy[i][0], self._bernard_easy[i][1]) + self._bernard_easy[i][0], self._bernard_easy[i][1]) for i in range(len(self._pascal_easy)): self._spawn_bots(4.0, PascalBot, - self._pascal_easy[i][0], self._pascal_easy[i][1]) + self._pascal_easy[i][0], self._pascal_easy[i][1]) for i in range(len(self._taobao_easy)): self._spawn_bots(4.0, TaobaoBot, - self._taobao_easy[i][0], self._taobao_easy[i][1]) + self._taobao_easy[i][0], self._taobao_easy[i][1]) for i in range(len(self._bbot_easy)): self._spawn_bots(4.0, BBot, - self._bbot_easy[i][0], self._bbot_easy[i][1]) + self._bbot_easy[i][0], self._bbot_easy[i][1]) for i in range(len(self._agent_easy)): self._spawn_bots(4.0, AgentBot, - self._agent_easy[i][0], self._agent_easy[i][1]) + self._agent_easy[i][0], self._agent_easy[i][1]) for i in range(len(self._wizard_easy)): self._spawn_bots(4.0, GrumbledorfBot, - self._wizard_easy[i][0], self._wizard_easy[i][1]) + self._wizard_easy[i][0], self._wizard_easy[i][1]) for i in range(len(self._pixel_easy)): self._spawn_bots(4.0, PixelBot, - self._pixel_easy[i][0], self._pixel_easy[i][1]) + self._pixel_easy[i][0], self._pixel_easy[i][1]) if self._hard_mode: for i in range(len(self._spaz_hard)): self._spawn_bots(4.0, SpazBot, - self._spaz_hard[i][0], self._spaz_hard[i][1]) + self._spaz_hard[i][0], self._spaz_hard[i][1]) for i in range(len(self._zoe_hard)): self._spawn_bots(4.0, ZoeBot, - self._zoe_hard[i][0], self._zoe_hard[i][1]) + self._zoe_hard[i][0], self._zoe_hard[i][1]) for i in range(len(self._snake_hard)): self._spawn_bots(4.0, SnakeBot, - self._snake_hard[i][0], self._snake_hard[i][1]) + self._snake_hard[i][0], self._snake_hard[i][1]) for i in range(len(self._kronk_hard)): self._spawn_bots(4.0, BrawlerBot, - self._kronk_hard[i][0], self._kronk_hard[i][1]) + self._kronk_hard[i][0], self._kronk_hard[i][1]) for i in range(len(self._mel_hard)): self._spawn_bots(4.0, MelBot, - self._mel_hard[i][0], self._mel_hard[i][1]) + self._mel_hard[i][0], self._mel_hard[i][1]) for i in range(len(self._jack_hard)): self._spawn_bots(4.0, JackBot, - self._jack_hard[i][0], self._jack_hard[i][1]) + self._jack_hard[i][0], self._jack_hard[i][1]) for i in range(len(self._santa_hard)): self._spawn_bots(4.0, SantaBot, - self._santa_hard[i][0], self._santa_hard[i][1]) + self._santa_hard[i][0], self._santa_hard[i][1]) for i in range(len(self._frosty_hard)): self._spawn_bots(4.0, FrostyBot, - self._frosty_hard[i][0], self._frosty_hard[i][1]) + self._frosty_hard[i][0], self._frosty_hard[i][1]) for i in range(len(self._bunny_hard)): self._spawn_bots(4.0, BunnyBot, - self._bunny_hard[i][0], self._bunny_hard[i][1]) + self._bunny_hard[i][0], self._bunny_hard[i][1]) for i in range(len(self._bones_hard)): self._spawn_bots(4.0, BonesBot, - self._bones_hard[i][0], self._bones_hard[i][1]) + self._bones_hard[i][0], self._bones_hard[i][1]) for i in range(len(self._bernard_hard)): self._spawn_bots(4.0, BernardBot, - self._bernard_hard[i][0], self._bernard_hard[i][1]) + self._bernard_hard[i][0], self._bernard_hard[i][1]) for i in range(len(self._pascal_hard)): self._spawn_bots(4.0, PascalBot, - self._pascal_hard[i][0], self._pascal_hard[i][1]) + self._pascal_hard[i][0], self._pascal_hard[i][1]) for i in range(len(self._taobao_hard)): self._spawn_bots(4.0, TaobaoBot, - self._taobao_hard[i][0], self._taobao_hard[i][1]) + self._taobao_hard[i][0], self._taobao_hard[i][1]) for i in range(len(self._bbot_hard)): self._spawn_bots(4.0, BBot, - self._bbot_hard[i][0], self._bbot_hard[i][1]) + self._bbot_hard[i][0], self._bbot_hard[i][1]) for i in range(len(self._agent_hard)): self._spawn_bots(4.0, AgentBot, - self._agent_hard[i][0], self._agent_hard[i][1]) + self._agent_hard[i][0], self._agent_hard[i][1]) for i in range(len(self._wizard_hard)): self._spawn_bots(4.0, GrumbledorfBot, - self._wizard_hard[i][0], self._wizard_hard[i][1]) + self._wizard_hard[i][0], self._wizard_hard[i][1]) for i in range(len(self._pixel_hard)): self._spawn_bots(4.0, PixelBot, - self._pixel_hard[i][0], self._pixel_hard[i][1]) + self._pixel_hard[i][0], self._pixel_hard[i][1]) def _spawn_bots(self, time: float, bot: Any, pos: float, spawn_time: float) -> None: @@ -411,7 +430,7 @@ def on_player_join(self, player: Player) -> None: if self.has_begun(): bs.broadcastmessage( babase.Lstr(resource='playerDelayedJoinText', - subs=[('${PLAYER}', player.getname(full=True))]), + subs=[('${PLAYER}', player.getname(full=True))]), color=(0, 1, 0), ) return From 1c15e5b59dfa77023089773679c3b09ebb5344aa Mon Sep 17 00:00:00 2001 From: brostosjoined Date: Wed, 24 Jan 2024 21:18:36 +0300 Subject: [PATCH 0830/1464] O -> o --- plugins/utilities.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/utilities.json b/plugins/utilities.json index 743c3724..2f17edfc 100644 --- a/plugins/utilities.json +++ b/plugins/utilities.json @@ -1105,7 +1105,7 @@ "1.0.0": null } }, - "0nly_night": { + "only_night": { "description": "Night Mode", "external_url": "", "authors": [ From c31f77a882efedcee1ce6ac1e334d103235679eb Mon Sep 17 00:00:00 2001 From: brostos <67740566+brostosjoined@users.noreply.github.com> Date: Wed, 24 Jan 2024 21:25:53 +0300 Subject: [PATCH 0831/1464] Rename Avalanche.py to avalanche.py --- plugins/minigames/{Avalanche.py => avalanche.py} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename plugins/minigames/{Avalanche.py => avalanche.py} (100%) diff --git a/plugins/minigames/Avalanche.py b/plugins/minigames/avalanche.py similarity index 100% rename from plugins/minigames/Avalanche.py rename to plugins/minigames/avalanche.py From 7b765e759501a37c9462389b3f7a178c9335a896 Mon Sep 17 00:00:00 2001 From: brostos <67740566+brostosjoined@users.noreply.github.com> Date: Wed, 24 Jan 2024 21:26:15 +0300 Subject: [PATCH 0832/1464] Rename HYPER_RACE.py to hyper_race.py --- plugins/minigames/{HYPER_RACE.py => hyper_race.py} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename plugins/minigames/{HYPER_RACE.py => hyper_race.py} (100%) diff --git a/plugins/minigames/HYPER_RACE.py b/plugins/minigames/hyper_race.py similarity index 100% rename from plugins/minigames/HYPER_RACE.py rename to plugins/minigames/hyper_race.py From 718039bf67f969b6b2957bf9bbb6f20475bf3479 Mon Sep 17 00:00:00 2001 From: brostos <67740566+brostosjoined@users.noreply.github.com> Date: Wed, 24 Jan 2024 21:27:20 +0300 Subject: [PATCH 0833/1464] Rename Tag.py to tag.py --- plugins/utilities/{Tag.py => tag.py} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename plugins/utilities/{Tag.py => tag.py} (100%) diff --git a/plugins/utilities/Tag.py b/plugins/utilities/tag.py similarity index 100% rename from plugins/utilities/Tag.py rename to plugins/utilities/tag.py From 4c25646aed2f1136498fad8be3a2e3fbc05401a7 Mon Sep 17 00:00:00 2001 From: brostosjoined Date: Wed, 24 Jan 2024 18:27:47 +0000 Subject: [PATCH 0834/1464] [ci] apply-version-metadata --- plugins/minigames.json | 56 ++++++++++++++++++++++++++++++++++++------ plugins/utilities.json | 21 +++++++++++++--- 2 files changed, 66 insertions(+), 11 deletions(-) diff --git a/plugins/minigames.json b/plugins/minigames.json index 44e1e93a..4e7d0e21 100644 --- a/plugins/minigames.json +++ b/plugins/minigames.json @@ -979,7 +979,12 @@ } ], "versions": { - "1.0.0": null + "1.0.0": { + "api_version": 8, + "commit_sha": "718039b", + "released_on": "24-01-2024", + "md5sum": "c1c96450fbdb6e5b2f0d26bb4e797236" + } } }, "hyper_race": { @@ -993,7 +998,12 @@ } ], "versions": { - "1.0.0": null + "1.0.0": { + "api_version": 8, + "commit_sha": "718039b", + "released_on": "24-01-2024", + "md5sum": "8b423bdae256bd411489528b550b8bd9" + } } }, "meteor_shower_deluxe": { @@ -1007,7 +1017,12 @@ } ], "versions": { - "1.0.0": null + "1.0.0": { + "api_version": 8, + "commit_sha": "718039b", + "released_on": "24-01-2024", + "md5sum": "7e86bbc8e3ebb26a66602068950adfbf" + } } }, "ofuuu_attack": { @@ -1021,7 +1036,12 @@ } ], "versions": { - "1.0.0": null + "1.0.0": { + "api_version": 8, + "commit_sha": "718039b", + "released_on": "24-01-2024", + "md5sum": "982c72f2d2cb3d50280f50b022e7865f" + } } }, "safe_zone": { @@ -1035,7 +1055,12 @@ } ], "versions": { - "1.0.0": null + "1.0.0": { + "api_version": 8, + "commit_sha": "718039b", + "released_on": "24-01-2024", + "md5sum": "862fab0c26947c70397542742fb82635" + } } }, "snow_ball_fight": { @@ -1049,7 +1074,12 @@ } ], "versions": { - "1.0.0": null + "1.0.0": { + "api_version": 8, + "commit_sha": "718039b", + "released_on": "24-01-2024", + "md5sum": "ef6bd7cd0404674f65e8f8d4da3ab8c8" + } } }, "egg_game": { @@ -1063,7 +1093,12 @@ } ], "versions": { - "1.0.0": null + "1.0.0": { + "api_version": 8, + "commit_sha": "718039b", + "released_on": "24-01-2024", + "md5sum": "e1d401ec8f2d06dec741d713d6602710" + } } }, "you_vs_bombsquad": { @@ -1077,7 +1112,12 @@ } ], "versions": { - "1.0.0": null + "1.0.0": { + "api_version": 8, + "commit_sha": "718039b", + "released_on": "24-01-2024", + "md5sum": "451daeabbd628ec70fa31b80a0999f35" + } } } } diff --git a/plugins/utilities.json b/plugins/utilities.json index 2f17edfc..fa71aa4c 100644 --- a/plugins/utilities.json +++ b/plugins/utilities.json @@ -1102,7 +1102,12 @@ } ], "versions": { - "1.0.0": null + "1.0.0": { + "api_version": 8, + "commit_sha": "718039b", + "released_on": "24-01-2024", + "md5sum": "eb917ca19d206dfd19667181dacc1df5" + } } }, "only_night": { @@ -1116,7 +1121,12 @@ } ], "versions": { - "1.0.0": null + "1.0.0": { + "api_version": 8, + "commit_sha": "718039b", + "released_on": "24-01-2024", + "md5sum": "255d3d6694008cc2f73d115182100b52" + } } }, "tag": { @@ -1130,7 +1140,12 @@ } ], "versions": { - "2.0.1": null + "2.0.1": { + "api_version": 8, + "commit_sha": "718039b", + "released_on": "24-01-2024", + "md5sum": "01cf9e10ab0e1bf51c07d80ff842c632" + } } } } From 177b8ea93f73f074dca927d1a8db4435efb52d63 Mon Sep 17 00:00:00 2001 From: brostosjoined Date: Wed, 24 Jan 2024 21:28:29 +0300 Subject: [PATCH 0835/1464] Some bug --- plugins/minigames/egg_game.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/minigames/egg_game.py b/plugins/minigames/egg_game.py index 4c0ffc13..09ef244f 100644 --- a/plugins/minigames/egg_game.py +++ b/plugins/minigames/egg_game.py @@ -113,7 +113,7 @@ class Player(bs.Player['Team']): class Team(bs.Team[Player]): """Our team type for this game.""" - def on_app_running(self) -> None: + def __init__(self) -> None: self.score = 0 From ef7d79e93bad8bece36301055669abeaa2573128 Mon Sep 17 00:00:00 2001 From: brostosjoined Date: Fri, 26 Jan 2024 05:00:06 +0300 Subject: [PATCH 0836/1464] More --- .vscode/settings.json | 5 + plugins/minigames.json | 70 ++ plugins/minigames/ba_dark_fields.py | 291 +++++++ plugins/minigames/gravity_falls.py | 34 + plugins/minigames/infinite_ninjas.py | 134 +++ plugins/minigames/lame_fight.py | 158 ++++ plugins/minigames/onslaught_football.py | 1023 +++++++++++++++++++++++ 7 files changed, 1715 insertions(+) create mode 100644 .vscode/settings.json create mode 100644 plugins/minigames/ba_dark_fields.py create mode 100644 plugins/minigames/gravity_falls.py create mode 100644 plugins/minigames/infinite_ninjas.py create mode 100644 plugins/minigames/lame_fight.py create mode 100644 plugins/minigames/onslaught_football.py diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 00000000..b242572e --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,5 @@ +{ + "githubPullRequests.ignoredPullRequestBranches": [ + "main" + ] +} \ No newline at end of file diff --git a/plugins/minigames.json b/plugins/minigames.json index 44e1e93a..52ea0682 100644 --- a/plugins/minigames.json +++ b/plugins/minigames.json @@ -1079,6 +1079,76 @@ "versions": { "1.0.0": null } + }, + "ba_dark_fileds": { + "description": "Get to the other side and watch your step", + "external_url": "", + "authors": [ + { + "name": "Froshlee24", + "email": "", + "discord": "froshlee24" + } + ], + "versions": { + "1.0.0": null + } + }, + "onslaught_football": { + "description": "Onslaught but in football map", + "external_url": "", + "authors": [ + { + "name": "", + "email": "", + "discord": "" + } + ], + "versions": { + "1.0.0": null + } + }, + "lame_fight": { + "description": "Save World With Super Powers", + "external_url": "", + "authors": [ + { + "name": "", + "email": "", + "discord": "" + } + ], + "versions": { + "1.0.0": null + } + }, + "infinite_ninjas": { + "description": "How long can you survive from Ninjas??", + "external_url": "", + "authors": [ + { + "name": "", + "email": "", + "discord": "" + } + ], + "versions": { + "1.0.0": null + } + }, + "gravity_falls": { + "description": "Trip to the moon", + "external_url": "", + "authors": [ + { + "name": "", + "email": "", + "discord": "" + } + ], + "versions": { + "1.0.0": null + } } } } \ No newline at end of file diff --git a/plugins/minigames/ba_dark_fields.py b/plugins/minigames/ba_dark_fields.py new file mode 100644 index 00000000..2a820054 --- /dev/null +++ b/plugins/minigames/ba_dark_fields.py @@ -0,0 +1,291 @@ +# Ported to api 8 by brostos using baport.(https://github.com/bombsquad-community/baport) +"""Dark fields mini-game.""" + +# Minigame by Froshlee24 +# ba_meta require api 8 +# (see https://ballistica.net/wiki/meta-tag-system) + +from __future__ import annotations +import random +from typing import TYPE_CHECKING + +import _babase +import babase +import bauiv1 as bui +import bascenev1 as bs +from bascenev1lib.actor import bomb +from bascenev1._music import setmusic +from bascenev1lib.actor.scoreboard import Scoreboard +from bascenev1._gameutils import animate_array +from bascenev1lib.gameutils import SharedObjects +from bascenev1lib.actor.playerspaz import PlayerSpaz + +if TYPE_CHECKING: + from typing import Any, Sequence, Optional, List, Dict, Type, Type + +class Player(bs.Player['Team']): + """Our player type for this game.""" + + +class Team(bs.Team[Player]): + """Our team type for this game.""" + + def __init__(self) -> None: + self.score = 0 + +# ba_meta export bascenev1.GameActivity +class DarkFieldsGame(bs.TeamGameActivity[Player, Team]): + + name = 'Dark Fields' + description = 'Get to the other side.' + available_settings = [ + bs.IntSetting('Score to Win', + min_value=1, + default=3, + ), + bs.IntChoiceSetting('Time Limit', + choices=[ + ('None', 0), + ('1 Minute', 60), + ('2 Minutes', 120), + ('5 Minutes', 300), + ('10 Minutes', 600), + ('20 Minutes', 1200), + ], + default=0, + ), + bs.FloatChoiceSetting('Respawn Times', + choices=[ + ('Shorter', 0.25), + ('Short', 0.5), + ('Normal', 1.0), + ('Long', 2.0), + ('Longer', 4.0), + ], + default=1.0, + ), + bs.BoolSetting('Epic Mode', default=False), + bs.BoolSetting('Players as center of interest', default=True), + ] + + @classmethod + def get_supported_maps(cls, sessiontype: Type[bs.Session]) -> List[str]: + return bs.app.classic.getmaps('football') + + @classmethod + def supports_session_type(cls, sessiontype: Type[bs.Session]) -> bool: + return (issubclass(sessiontype, bs.DualTeamSession) + or issubclass(sessiontype, bs.FreeForAllSession)) + + def __init__(self, settings: dict): + super().__init__(settings) + self._epic_mode = bool(settings['Epic Mode']) + self._center_of_interest = bool(settings['Players as center of interest']) + self._score_to_win_per_player = int(settings['Score to Win']) + self._time_limit = float(settings['Time Limit']) + + self._scoreboard = Scoreboard() + + shared = SharedObjects.get() + + self._scoreRegionMaterial = bs.Material() + self._scoreRegionMaterial.add_actions( + conditions=("they_have_material",shared.player_material), + actions=(("modify_part_collision","collide",True), + ("modify_part_collision","physical",False), + ("call","at_connect", self._onPlayerScores))) + + self.slow_motion = self._epic_mode + self.default_music = (bs.MusicType.EPIC if self._epic_mode else None) + + + def on_transition_in(self) -> None: + super().on_transition_in() + gnode = bs.getactivity().globalsnode + gnode.tint = (0.5,0.5,0.5) + + a = bs.newnode('locator',attrs={'shape':'box','position':(12.2,0,.1087926362), + 'color':(5,0,0),'opacity':1,'draw_beauty':True,'additive':False,'size':[2.5,0.1,12.8]}) + + b = bs.newnode('locator',attrs={'shape':'box','position':(-12.1,0,.1087926362), + 'color':(0,0,5),'opacity':1,'draw_beauty':True,'additive':False,'size':[2.5,0.1,12.8]}) + + def on_begin(self) -> None: + # self._has_begun = False + super().on_begin() + + self.setup_standard_time_limit(self._time_limit) + self._score_to_win = (self._score_to_win_per_player * + max(1, max(len(t.players) for t in self.teams))) + self._update_scoreboard() + + self.isUpdatingMines = False + self._scoreSound = bs.getsound('dingSmall') + + for p in self.players: + if p.actor is not None: + try: + p.actor.disconnect_controls_from_player() + except Exception: + print('Can\'t connect to player') + + self._scoreRegions = [] + defs = bs.getactivity().map.defs + self._scoreRegions.append(bs.NodeActor(bs.newnode('region', + attrs={'position':defs.boxes['goal1'][0:3], + 'scale':defs.boxes['goal1'][6:9], + 'type': 'box', + 'materials':(self._scoreRegionMaterial,)}))) + self.mines = [] + self.spawnMines() + bs.timer(0.8 if self.slow_motion else 1.7,self.start) + + def start(self): + # self._has_begun = True + self._show_info() + bs.timer(random.randrange(3,7),self.doRandomLighting) + if not self._epic_mode: + setmusic(bs.MusicType.SCARY) + animate_array(bs.getactivity().globalsnode,'tint',3,{0:(0.5,0.5,0.5),2:(0.2,0.2,0.2)}) + + for p in self.players: + self.doPlayer(p) + + def spawn_player(self, player): + if not self.has_begun(): + return + else: + self.doPlayer(player) + + def doPlayer(self,player): + pos = (-12.4,1,random.randrange(-5,5)) + player = self.spawn_player_spaz(player,pos) + player.connect_controls_to_player(enable_punch=False,enable_bomb=False) + player.node.is_area_of_interest = self._center_of_interest + + def _show_info(self) -> None: + if self.has_begun(): + super()._show_info() + + def on_team_join(self, team: Team) -> None: + if self.has_begun(): + self._update_scoreboard() + + def _update_scoreboard(self) -> None: + for team in self.teams: + self._scoreboard.set_team_value(team, team.score, self._score_to_win) + + def doRandomLighting(self): + bs.timer(random.randrange(3,7),self.doRandomLighting) + if self.isUpdatingMines: return + + delay = 0 + for mine in self.mines: + if mine.node.exists(): + pos = mine.node.position + bs.timer(delay,babase.Call(self.do_light,pos)) + delay += 0.005 if self._epic_mode else 0.01 + + def do_light(self,pos): + light = bs.newnode('light',attrs={ + 'position': pos, + 'volume_intensity_scale': 1.0, + 'radius':0.1, + 'color': (1,0,0) + }) + bs.animate(light, 'intensity', { 0: 2.0, 3.0: 0.0}) + bs.timer(3.0, light.delete) + + def spawnMines(self): + delay = 0 + h_range = [10,8,6,4,2,0,-2,-4,-6,-8,-10] + for h in h_range: + for i in range(random.randint(3,4)): + x = h+random.random() + y = random.randrange(-5,6)+(random.random()) + pos = (x,1,y) + bs.timer(delay,babase.Call(self.doMine,pos)) + delay += 0.015 if self._epic_mode else 0.04 + bs.timer(5.0,self.stopUpdateMines) + + def stopUpdateMines(self): + self.isUpdatingMines = False + + def updateMines(self): + if self.isUpdatingMines: return + self.isUpdatingMines = True + for m in self.mines: + m.node.delete() + self.mines = [] + self.spawnMines() + + + def doMine(self,pos): + b = bomb.Bomb(position=pos,bomb_type='land_mine').autoretain() + b.add_explode_callback(self._on_bomb_exploded) + b.arm() + self.mines.append(b) + + def _on_bomb_exploded(self, bomb: Bomb, blast: Blast) -> None: + assert blast.node + p = blast.node.position + pos = (p[0],p[1]+1,p[2]) + bs.timer(0.5,babase.Call(self.doMine,pos)) + + def _onPlayerScores(self): + player: Optional[Player] + try: + spaz = bs.getcollision().opposingnode.getdelegate(PlayerSpaz, True) + except bs.NotFoundError: + return + + if not spaz.is_alive(): + return + + try: + player = spaz.getplayer(Player, True) + except bs.NotFoundError: + return + + if player.exists() and player.is_alive(): + player.team.score += 1 + self._scoreSound.play() + pos = player.actor.node.position + + animate_array(bs.getactivity().globalsnode,'tint',3,{0:(0.5,0.5,0.5),2.8:(0.2,0.2,0.2)}) + self._update_scoreboard() + + light = bs.newnode('light', + attrs={ + 'position': pos, + 'radius': 0.5, + 'color': (1, 0, 0) + }) + bs.animate(light, 'intensity', {0.0: 0, 0.1: 1, 0.5: 0}, loop=False) + bs.timer(1.0, light.delete) + + player.actor.handlemessage(bs.DieMessage( how=bs.DeathType.REACHED_GOAL)) + self.updateMines() + + if any(team.score >= self._score_to_win for team in self.teams): + bs.timer(0.5, self.end_game) + + def handlemessage(self, msg: Any) -> Any: + + if isinstance(msg, bs.PlayerDiedMessage): + + # Augment standard behavior. + super().handlemessage(msg) + + player = msg.getplayer(Player) + self.respawn_player(player) + + else: + return super().handlemessage(msg) + return None + + def end_game(self) -> None: + results = bs.GameResults() + for team in self.teams: + results.set_team_score(team, team.score) + self.end(results=results) \ No newline at end of file diff --git a/plugins/minigames/gravity_falls.py b/plugins/minigames/gravity_falls.py new file mode 100644 index 00000000..f24b5918 --- /dev/null +++ b/plugins/minigames/gravity_falls.py @@ -0,0 +1,34 @@ +# Ported to api 8 by brostos using baport.(https://github.com/bombsquad-community/baport) +## Made by MattZ45986 on GitHub +## Ported by: Freaku / @[Just] Freak#4999 + + +import babase +import bauiv1 as bui +import bascenev1 as bs +from bascenev1lib.game.elimination import EliminationGame + + + +# ba_meta require api 8 +# ba_meta export bascenev1.GameActivity +class GFGame(EliminationGame): + name = 'Gravity Falls' + + def spawn_player(self, player): + actor = self.spawn_player_spaz(player, (0,5,0)) + if not self._solo_mode: + bs.timer(0.3, babase.Call(self._print_lives, player)) + + # If we have any icons, update their state. + for icon in player.icons: + icon.handle_player_spawned() + bs.timer(1,babase.Call(self.raise_player, player)) + return actor + + def raise_player(self, player): + if player.is_alive(): + try: + player.actor.node.handlemessage("impulse",player.actor.node.position[0],player.actor.node.position[1]+.5,player.actor.node.position[2],0,5,0, 3,10,0,0, 0,5,0) + except: pass + bs.timer(0.05,babase.Call(self.raise_player,player)) \ No newline at end of file diff --git a/plugins/minigames/infinite_ninjas.py b/plugins/minigames/infinite_ninjas.py new file mode 100644 index 00000000..c43cb65e --- /dev/null +++ b/plugins/minigames/infinite_ninjas.py @@ -0,0 +1,134 @@ +# Ported to api 8 by brostos using baport.(https://github.com/bombsquad-community/baport) +# ba_meta require api 8 + +#Copy pasted from ExplodoRun by Blitz,just edited Bots and map 😝 + + +from __future__ import annotations + +import random +from typing import TYPE_CHECKING + +import babase +import bauiv1 as bui +import bascenev1 as bs +from bascenev1lib.actor.spazbot import SpazBotSet, ChargerBot, SpazBotDiedMessage +from bascenev1lib.actor.onscreentimer import OnScreenTimer + +if TYPE_CHECKING: + from typing import Any, Type, Dict, List, Optional + +## MoreMinigames.py support ## +def ba_get_api_version(): + return 6 + +def ba_get_levels(): + return [babase._level.Level( + 'Infinite Ninjas',gametype=InfiniteNinjasGame, + settings={}, + preview_texture_name = 'footballStadiumPreview'), + babase._level.Level( + 'Epic Infinite Ninjas',gametype=InfiniteNinjasGame, + settings={'Epic Mode':True}, + preview_texture_name = 'footballStadiumPreview')] +## MoreMinigames.py support ## + +class Player(bs.Player['Team']): + """Our player type for this game.""" + + +class Team(bs.Team[Player]): + """Our team type for this game.""" + +# ba_meta export bascenev1.GameActivity +class InfiniteNinjasGame(bs.TeamGameActivity[Player, Team]): + name = "Infinite Ninjas" + description = "How long can you survive from Ninjas??" + available_settings = [bs.BoolSetting('Epic Mode', default=False)] + scoreconfig = bs.ScoreConfig(label='Time', + scoretype=bs.ScoreType.MILLISECONDS, + lower_is_better=False) + default_music = bs.MusicType.TO_THE_DEATH + + def __init__(self, settings:dict): + settings['map'] = "Football Stadium" + self._epic_mode = settings.get('Epic Mode', False) + if self._epic_mode: + self.slow_motion = True + super().__init__(settings) + self._timer: Optional[OnScreenTimer] = None + self._winsound = bs.getsound('score') + self._won = False + self._bots = SpazBotSet() + self.wave = 1 + + def on_begin(self) -> None: + super().on_begin() + + self._timer = OnScreenTimer() + bs.timer(2.5, self._timer.start) + + #Bots Hehe + bs.timer(2.5,self.street) + + def street(self): + for a in range(self.wave): + p1 = random.choice([-5,-2.5,0,2.5,5]) + p3 = random.choice([-4.5,-4.14,-5,-3]) + time = random.choice([1,1.5,2.5,2]) + self._bots.spawn_bot(ChargerBot, pos=(p1,0.4,p3),spawn_time = time) + self.wave += 1 + + def botrespawn(self): + if not self._bots.have_living_bots(): + self.street() + def handlemessage(self, msg: Any) -> Any: + + # A player has died. + if isinstance(msg, bs.PlayerDiedMessage): + super().handlemessage(msg) # Augment standard behavior. + self._won = True + self.end_game() + + # A spaz-bot has died. + elif isinstance(msg, SpazBotDiedMessage): + # Unfortunately the bot-set will always tell us there are living + # bots if we ask here (the currently-dying bot isn't officially + # marked dead yet) ..so lets push a call into the event loop to + # check once this guy has finished dying. + babase.pushcall(self.botrespawn) + + # Let the base class handle anything we don't. + else: + return super().handlemessage(msg) + return None + + # When this is called, we should fill out results and end the game + # *regardless* of whether is has been won. (this may be called due + # to a tournament ending or other external reason). + def end_game(self) -> None: + + # Stop our on-screen timer so players can see what they got. + assert self._timer is not None + self._timer.stop() + + results = bs.GameResults() + + # If we won, set our score to the elapsed time in milliseconds. + # (there should just be 1 team here since this is co-op). + # ..if we didn't win, leave scores as default (None) which means + # we lost. + if self._won: + elapsed_time_ms = int((bs.time() - self._timer.starttime) * 1000.0) + bs.cameraflash() + self._winsound.play() + for team in self.teams: + for player in team.players: + if player.actor: + player.actor.handlemessage(bs.CelebrateMessage()) + results.set_team_score(team, elapsed_time_ms) + + # Ends the activity. + self.end(results) + + \ No newline at end of file diff --git a/plugins/minigames/lame_fight.py b/plugins/minigames/lame_fight.py new file mode 100644 index 00000000..e997a72a --- /dev/null +++ b/plugins/minigames/lame_fight.py @@ -0,0 +1,158 @@ +# Ported to api 8 by brostos using baport.(https://github.com/bombsquad-community/baport) + +# ba_meta require api 8 +# (see https://ballistica.net/wiki/meta-tag-system) + +from __future__ import annotations + +import random +from typing import TYPE_CHECKING + +import babase +import bauiv1 as bui +import bascenev1 as bs +from bascenev1lib.actor.spazbot import SpazBotSet, ChargerBot, BrawlerBotProShielded, TriggerBotProShielded, ExplodeyBot, BomberBotProShielded, SpazBotDiedMessage +from bascenev1lib.actor.onscreentimer import OnScreenTimer + +if TYPE_CHECKING: + from typing import Any, Type, Dict, List, Optional + +def ba_get_api_version(): + return 6 + +def ba_get_levels(): + return [babase._level.Level( + 'Lame Fight', + gametype=LameFightGame, + settings={}, + preview_texture_name='courtyardPreview')] + +class Player(bs.Player['Team']): + """Our player type for this game.""" + + +class Team(bs.Team[Player]): + """Our team type for this game.""" + +# ba_meta export bascenev1.GameActivity +class LameFightGame(bs.TeamGameActivity[Player, Team]): + name = "Lame Fight" + description = "Save World With Super Powers" + slow_motion = True + scoreconfig = bs.ScoreConfig(label='Time', + scoretype=bs.ScoreType.MILLISECONDS, + lower_is_better=True) + default_music = bs.MusicType.TO_THE_DEATH + + def __init__(self, settings:dict): + settings['map'] = "Courtyard" + super().__init__(settings) + self._timer: Optional[OnScreenTimer] = None + self._winsound = bs.getsound('score') + self._won = False + self._bots = SpazBotSet() + + def on_begin(self) -> None: + super().on_begin() + + self._timer = OnScreenTimer() + bs.timer(4.0, self._timer.start) + + #Bots Hehe + bs.timer(1.0, lambda: self._bots.spawn_bot(ChargerBot, pos=(3,3,-2),spawn_time = 3.0)) + bs.timer(1.0, lambda: self._bots.spawn_bot(ChargerBot, pos=(-3,3,-2),spawn_time = 3.0)) + bs.timer(1.0, lambda: self._bots.spawn_bot(ChargerBot, pos=(5,3,-2),spawn_time = 3.0)) + bs.timer(1.0, lambda: self._bots.spawn_bot(ChargerBot, pos=(-5,3,-2),spawn_time = 3.0)) + bs.timer(1.0, lambda: self._bots.spawn_bot(ChargerBot, pos=(0,3,1),spawn_time = 3.0)) + bs.timer(1.0, lambda: self._bots.spawn_bot(ChargerBot, pos=(0,3,-5),spawn_time = 3.0)) + bs.timer(9.0, lambda: self._bots.spawn_bot(BomberBotProShielded, pos=(-7,5,-7.5),spawn_time = 3.0)) + bs.timer(9.0, lambda: self._bots.spawn_bot(BomberBotProShielded, pos=(7,5,-7.5),spawn_time = 3.0)) + bs.timer(9.0, lambda: self._bots.spawn_bot(BomberBotProShielded, pos=(7,5,1.5),spawn_time = 3.0)) + bs.timer(9.0, lambda: self._bots.spawn_bot(BomberBotProShielded, pos=(-7,5,1.5),spawn_time = 3.0)) + bs.timer(12.0, lambda: self._bots.spawn_bot(TriggerBotProShielded, pos=(-1,7,-8),spawn_time = 3.0)) + bs.timer(12.0, lambda: self._bots.spawn_bot(TriggerBotProShielded, pos=(1,7,-8),spawn_time = 3.0)) + bs.timer(15.0, lambda: self._bots.spawn_bot(ExplodeyBot, pos=(0,3,-5),spawn_time = 3.0)) + bs.timer(20.0, lambda: self._bots.spawn_bot(ExplodeyBot, pos=(0,3,1),spawn_time = 3.0)) + bs.timer(20.0, lambda: self._bots.spawn_bot(ExplodeyBot, pos=(-5,3,-2),spawn_time = 3.0)) + bs.timer(20.0, lambda: self._bots.spawn_bot(ExplodeyBot, pos=(5,3,-2),spawn_time = 3.0)) + bs.timer(30,self.street) + + def street(self): + bs.broadcastmessage("Lame Guys Are Here!",color = (1,0,0)) + for a in range(-1,2): + for b in range(-3,0): + self._bots.spawn_bot(BrawlerBotProShielded, pos=(a,3,b),spawn_time = 3.0) + + def spawn_player(self, player: Player) -> bs.Actor: + spawn_center = (0, 3, -2) + pos = (spawn_center[0] + random.uniform(-1.5, 1.5), spawn_center[1], + spawn_center[2] + random.uniform(-1.5, 1.5)) + spaz = self.spawn_player_spaz(player,position = pos) + p = ["Bigger Blast","Stronger Punch","Shield","Speed"] + Power = random.choice(p) + spaz.bomb_type = random.choice(["normal","sticky","ice","impact","normal","ice","sticky"]) + bs.broadcastmessage(f"Now You Have {Power}") + if Power == p[0]: + spaz.bomb_count = 3 + spaz.blast_radius = 2.5 + if Power == p[1]: + spaz._punch_cooldown = 350 + spaz._punch_power_scale = 2.0 + if Power == p[2]: + spaz.equip_shields() + if Power == p[3]: + spaz.node.hockey = True + return spaz + def _check_if_won(self) -> None: + if not self._bots.have_living_bots(): + self._won = True + self.end_game() + def handlemessage(self, msg: Any) -> Any: + + # A player has died. + if isinstance(msg, bs.PlayerDiedMessage): + super().handlemessage(msg) # Augment standard behavior. + self.respawn_player(msg.getplayer(Player)) + + # A spaz-bot has died. + elif isinstance(msg, SpazBotDiedMessage): + # Unfortunately the bot-set will always tell us there are living + # bots if we ask here (the currently-dying bot isn't officially + # marked dead yet) ..so lets push a call into the event loop to + # check once this guy has finished dying. + babase.pushcall(self._check_if_won) + + # Let the base class handle anything we don't. + else: + return super().handlemessage(msg) + return None + + # When this is called, we should fill out results and end the game + # *regardless* of whether is has been won. (this may be called due + # to a tournament ending or other external reason). + def end_game(self) -> None: + + # Stop our on-screen timer so players can see what they got. + assert self._timer is not None + self._timer.stop() + + results = bs.GameResults() + + # If we won, set our score to the elapsed time in milliseconds. + # (there should just be 1 team here since this is co-op). + # ..if we didn't win, leave scores as default (None) which means + # we lost. + if self._won: + elapsed_time_ms = int((bs.time() - self._timer.starttime) * 1000.0) + bs.cameraflash() + self._winsound.play() + for team in self.teams: + for player in team.players: + if player.actor: + player.actor.handlemessage(bs.CelebrateMessage()) + results.set_team_score(team, elapsed_time_ms) + + # Ends the activity. + self.end(results) + + \ No newline at end of file diff --git a/plugins/minigames/onslaught_football.py b/plugins/minigames/onslaught_football.py new file mode 100644 index 00000000..06a5c5c2 --- /dev/null +++ b/plugins/minigames/onslaught_football.py @@ -0,0 +1,1023 @@ +# Ported to api 8 by brostos using baport.(https://github.com/bombsquad-community/baport) +# ba_meta require api 8 +# (see https://ballistica.net/wiki/meta-tag-system) + +from __future__ import annotations +from asyncio import base_subprocess + +import math +import random +from enum import Enum, unique +from dataclasses import dataclass +from typing import TYPE_CHECKING + +import babase +import bauiv1 as bui +import bascenev1 as bs +from bascenev1lib.actor.popuptext import PopupText +from bascenev1lib.actor.bomb import TNTSpawner +from bascenev1lib.actor.playerspaz import PlayerSpazHurtMessage +from bascenev1lib.actor.scoreboard import Scoreboard +from bascenev1lib.actor.controlsguide import ControlsGuide +from bascenev1lib.actor.powerupbox import PowerupBox, PowerupBoxFactory +from bascenev1lib.actor.spazbot import ( + SpazBotDiedMessage, + SpazBotSet, + ChargerBot, + StickyBot, + BomberBot, + BomberBotLite, + BrawlerBot, + BrawlerBotLite, + TriggerBot, + BomberBotStaticLite, + TriggerBotStatic, + BomberBotProStatic, + TriggerBotPro, + ExplodeyBot, + BrawlerBotProShielded, + ChargerBotProShielded, + BomberBotPro, + TriggerBotProShielded, + BrawlerBotPro, + BomberBotProShielded, +) + +if TYPE_CHECKING: + from typing import Any, Sequence + from bascenev1lib.actor.spazbot import SpazBot + + +@dataclass +class Wave: + """A wave of enemies.""" + + entries: list[Spawn | Spacing | Delay | None] + base_angle: float = 0.0 + + +@dataclass +class Spawn: + """A bot spawn event in a wave.""" + + bottype: type[SpazBot] | str + point: Point | None = None + spacing: float = 5.0 + + +@dataclass +class Spacing: + """Empty space in a wave.""" + + spacing: float = 5.0 + + +@dataclass +class Delay: + """A delay between events in a wave.""" + + duration: float + + +class Player(bs.Player['Team']): + """Our player type for this game.""" + + def __init__(self) -> None: + self.has_been_hurt = False + self.respawn_wave = 0 + + +class Team(bs.Team[Player]): + """Our team type for this game.""" + + +class OnslaughtFootballGame(bs.CoopGameActivity[Player, Team]): + """Co-op game where players try to survive attacking waves of enemies.""" + + name = 'Onslaught' + description = 'Defeat all enemies.' + + tips: list[str | babase.GameTip] = [ + 'Hold any button to run.' + ' (Trigger buttons work well if you have them)', + 'Try tricking enemies into killing eachother or running off cliffs.', + 'Try \'Cooking off\' bombs for a second or two before throwing them.', + 'It\'s easier to win with a friend or two helping.', + 'If you stay in one place, you\'re toast. Run and dodge to survive..', + 'Practice using your momentum to throw bombs more accurately.', + 'Your punches do much more damage if you are running or spinning.', + ] + + # Show messages when players die since it matters here. + announce_player_deaths = True + + def __init__(self, settings: dict): + super().__init__(settings) + self._new_wave_sound = bs.getsound('scoreHit01') + self._winsound = bs.getsound('score') + self._cashregistersound = bs.getsound('cashRegister') + self._a_player_has_been_hurt = False + self._player_has_dropped_bomb = False + self._spawn_center = (0, 0.2, 0) + self._tntspawnpos = (0, 0.95, -0.77) + self._powerup_center = (0, 1.5, 0) + self._powerup_spread = (6.0, 4.0) + self._scoreboard: Scoreboard | None = None + self._game_over = False + self._wavenum = 0 + self._can_end_wave = True + self._score = 0 + self._time_bonus = 0 + self._spawn_info_text: bs.NodeActor | None = None + self._dingsound = bs.getsound('dingSmall') + self._dingsoundhigh = bs.getsound('dingSmallHigh') + self._have_tnt = False + self._excluded_powerups: list[str] | None = None + self._waves: list[Wave] = [] + self._tntspawner: TNTSpawner | None = None + self._bots: SpazBotSet | None = None + self._powerup_drop_timer: bs.Timer | None = None + self._time_bonus_timer: bs.Timer | None = None + self._time_bonus_text: bs.NodeActor | None = None + self._flawless_bonus: int | None = None + self._wave_text: bs.NodeActor | None = None + self._wave_update_timer: bs.Timer | None = None + self._throw_off_kills = 0 + self._land_mine_kills = 0 + self._tnt_kills = 0 + + self._epic_mode = bool(settings['Epic Mode']) + # Base class overrides. + self.slow_motion = self._epic_mode + self.default_music = ( + bs.MusicType.EPIC if self._epic_mode else bs.MusicType.ONSLAUGHT + ) + + def on_transition_in(self) -> None: + super().on_transition_in() + self._spawn_info_text = bs.NodeActor( + bs.newnode( + 'text', + attrs={ + 'position': (15, -130), + 'h_attach': 'left', + 'v_attach': 'top', + 'scale': 0.55, + 'color': (0.3, 0.8, 0.3, 1.0), + 'text': '', + }, + ) + ) + self._scoreboard = Scoreboard( + label=babase.Lstr(resource='scoreText'), score_split=0.5 + ) + + def on_begin(self) -> None: + super().on_begin() + self._have_tnt = True + self._excluded_powerups = [] + self._waves = [] + bs.timer(4.0, self._start_powerup_drops) + + # Our TNT spawner (if applicable). + if self._have_tnt: + self._tntspawner = TNTSpawner(position=self._tntspawnpos) + + self.setup_low_life_warning_sound() + self._update_scores() + self._bots = SpazBotSet() + bs.timer(4.0, self._start_updating_waves) + self._next_ffa_start_index = random.randrange( + len(self.map.get_def_points('ffa_spawn')) + ) + + def _get_dist_grp_totals(self, grps: list[Any]) -> tuple[int, int]: + totalpts = 0 + totaldudes = 0 + for grp in grps: + for grpentry in grp: + dudes = grpentry[1] + totalpts += grpentry[0] * dudes + totaldudes += dudes + return totalpts, totaldudes + + def _get_distribution( + self, + target_points: int, + min_dudes: int, + max_dudes: int, + group_count: int, + max_level: int, + ) -> list[list[tuple[int, int]]]: + """Calculate a distribution of bad guys given some params.""" + max_iterations = 10 + max_dudes * 2 + + groups: list[list[tuple[int, int]]] = [] + for _g in range(group_count): + groups.append([]) + types = [1] + if max_level > 1: + types.append(2) + if max_level > 2: + types.append(3) + if max_level > 3: + types.append(4) + for iteration in range(max_iterations): + diff = self._add_dist_entry_if_possible( + groups, max_dudes, target_points, types + ) + + total_points, total_dudes = self._get_dist_grp_totals(groups) + full = total_points >= target_points + + if full: + # Every so often, delete a random entry just to + # shake up our distribution. + if random.random() < 0.2 and iteration != max_iterations - 1: + self._delete_random_dist_entry(groups) + + # If we don't have enough dudes, kill the group with + # the biggest point value. + elif ( + total_dudes < min_dudes and iteration != max_iterations - 1 + ): + self._delete_biggest_dist_entry(groups) + + # If we've got too many dudes, kill the group with the + # smallest point value. + elif ( + total_dudes > max_dudes and iteration != max_iterations - 1 + ): + self._delete_smallest_dist_entry(groups) + + # Close enough.. we're done. + else: + if diff == 0: + break + + return groups + + def _add_dist_entry_if_possible( + self, + groups: list[list[tuple[int, int]]], + max_dudes: int, + target_points: int, + types: list[int], + ) -> int: + # See how much we're off our target by. + total_points, total_dudes = self._get_dist_grp_totals(groups) + diff = target_points - total_points + dudes_diff = max_dudes - total_dudes + + # Add an entry if one will fit. + value = types[random.randrange(len(types))] + group = groups[random.randrange(len(groups))] + if not group: + max_count = random.randint(1, 6) + else: + max_count = 2 * random.randint(1, 3) + max_count = min(max_count, dudes_diff) + count = min(max_count, diff // value) + if count > 0: + group.append((value, count)) + total_points += value * count + total_dudes += count + diff = target_points - total_points + return diff + + def _delete_smallest_dist_entry( + self, groups: list[list[tuple[int, int]]] + ) -> None: + smallest_value = 9999 + smallest_entry = None + smallest_entry_group = None + for group in groups: + for entry in group: + if entry[0] < smallest_value or smallest_entry is None: + smallest_value = entry[0] + smallest_entry = entry + smallest_entry_group = group + assert smallest_entry is not None + assert smallest_entry_group is not None + smallest_entry_group.remove(smallest_entry) + + def _delete_biggest_dist_entry( + self, groups: list[list[tuple[int, int]]] + ) -> None: + biggest_value = 9999 + biggest_entry = None + biggest_entry_group = None + for group in groups: + for entry in group: + if entry[0] > biggest_value or biggest_entry is None: + biggest_value = entry[0] + biggest_entry = entry + biggest_entry_group = group + if biggest_entry is not None: + assert biggest_entry_group is not None + biggest_entry_group.remove(biggest_entry) + + def _delete_random_dist_entry( + self, groups: list[list[tuple[int, int]]] + ) -> None: + entry_count = 0 + for group in groups: + for _ in group: + entry_count += 1 + if entry_count > 1: + del_entry = random.randrange(entry_count) + entry_count = 0 + for group in groups: + for entry in group: + if entry_count == del_entry: + group.remove(entry) + break + entry_count += 1 + + def spawn_player(self, player: Player) -> bs.Actor: + + # We keep track of who got hurt each wave for score purposes. + player.has_been_hurt = False + pos = ( + self._spawn_center[0] + random.uniform(-1.5, 1.5), + self._spawn_center[1], + self._spawn_center[2] + random.uniform(-1.5, 1.5), + ) + spaz = self.spawn_player_spaz(player, position=pos) + spaz.add_dropped_bomb_callback(self._handle_player_dropped_bomb) + return spaz + + def _handle_player_dropped_bomb( + self, player: bs.Actor, bomb: bs.Actor + ) -> None: + del player, bomb # Unused. + self._player_has_dropped_bomb = True + + def _drop_powerup(self, index: int, poweruptype: str | None = None) -> None: + poweruptype = PowerupBoxFactory.get().get_random_powerup_type( + forcetype=poweruptype, excludetypes=self._excluded_powerups + ) + PowerupBox( + position=self.map.powerup_spawn_points[index], + poweruptype=poweruptype, + ).autoretain() + + def _start_powerup_drops(self) -> None: + self._powerup_drop_timer = bs.Timer( + 3.0, bs.WeakCall(self._drop_powerups), repeat=True + ) + + def _drop_powerups( + self, standard_points: bool = False, poweruptype: str | None = None + ) -> None: + """Generic powerup drop.""" + if standard_points: + points = self.map.powerup_spawn_points + for i in range(len(points)): + bs.timer( + 1.0 + i * 0.5, + bs.WeakCall( + self._drop_powerup, i, poweruptype if i == 0 else None + ), + ) + else: + point = ( + self._powerup_center[0] + + random.uniform( + -1.0 * self._powerup_spread[0], + 1.0 * self._powerup_spread[0], + ), + self._powerup_center[1], + self._powerup_center[2] + + random.uniform( + -self._powerup_spread[1], self._powerup_spread[1] + ), + ) + + # Drop one random one somewhere. + PowerupBox( + position=point, + poweruptype=PowerupBoxFactory.get().get_random_powerup_type( + excludetypes=self._excluded_powerups + ), + ).autoretain() + + def do_end(self, outcome: str, delay: float = 0.0) -> None: + """End the game with the specified outcome.""" + if outcome == 'defeat': + self.fade_to_red() + score: int | None + if self._wavenum >= 2: + score = self._score + fail_message = None + else: + score = None + fail_message = babase.Lstr(resource='reachWave2Text') + self.end( + { + 'outcome': outcome, + 'score': score, + 'fail_message': fail_message, + 'playerinfos': self.initialplayerinfos, + }, + delay=delay, + ) + + def _update_waves(self) -> None: + + # If we have no living bots, go to the next wave. + assert self._bots is not None + if ( + self._can_end_wave + and not self._bots.have_living_bots() + and not self._game_over + ): + self._can_end_wave = False + self._time_bonus_timer = None + self._time_bonus_text = None + base_delay = 0.0 + + # Reward time bonus. + if self._time_bonus > 0: + bs.timer(0, babase.Call(self._cashregistersound.play)) + bs.timer( + base_delay, + bs.WeakCall(self._award_time_bonus, self._time_bonus), + ) + base_delay += 1.0 + + # Reward flawless bonus. + if self._wavenum > 0: + have_flawless = False + for player in self.players: + if player.is_alive() and not player.has_been_hurt: + have_flawless = True + bs.timer( + base_delay, + bs.WeakCall(self._award_flawless_bonus, player), + ) + player.has_been_hurt = False # reset + if have_flawless: + base_delay += 1.0 + + self._wavenum += 1 + + # Short celebration after waves. + if self._wavenum > 1: + self.celebrate(0.5) + bs.timer(base_delay, bs.WeakCall(self._start_next_wave)) + + def _award_completion_bonus(self) -> None: + self._cashregistersound.play() + for player in self.players: + try: + if player.is_alive(): + assert self.initialplayerinfos is not None + self.stats.player_scored( + player, + int(100 / len(self.initialplayerinfos)), + scale=1.4, + color=(0.6, 0.6, 1.0, 1.0), + title=babase.Lstr(resource='completionBonusText'), + screenmessage=False, + ) + except Exception: + babase.print_exception() + + def _award_time_bonus(self, bonus: int) -> None: + self._cashregistersound.play() + PopupText( + babase.Lstr( + value='+${A} ${B}', + subs=[ + ('${A}', str(bonus)), + ('${B}', babase.Lstr(resource='timeBonusText')), + ], + ), + color=(1, 1, 0.5, 1), + scale=1.0, + position=(0, 3, -1), + ).autoretain() + self._score += self._time_bonus + self._update_scores() + + def _award_flawless_bonus(self, player: Player) -> None: + self._cashregistersound.play() + try: + if player.is_alive(): + assert self._flawless_bonus is not None + self.stats.player_scored( + player, + self._flawless_bonus, + scale=1.2, + color=(0.6, 1.0, 0.6, 1.0), + title=babase.Lstr(resource='flawlessWaveText'), + screenmessage=False, + ) + except Exception: + babase.print_exception() + + def _start_time_bonus_timer(self) -> None: + self._time_bonus_timer = bs.Timer( + 1.0, bs.WeakCall(self._update_time_bonus), repeat=True + ) + + def _update_player_spawn_info(self) -> None: + + # If we have no living players lets just blank this. + assert self._spawn_info_text is not None + assert self._spawn_info_text.node + if not any(player.is_alive() for player in self.teams[0].players): + self._spawn_info_text.node.text = '' + else: + text: str | babase.Lstr = '' + for player in self.players: + if not player.is_alive(): + rtxt = babase.Lstr( + resource='onslaughtRespawnText', + subs=[ + ('${PLAYER}', player.getname()), + ('${WAVE}', str(player.respawn_wave)), + ], + ) + text = babase.Lstr( + value='${A}${B}\n', + subs=[ + ('${A}', text), + ('${B}', rtxt), + ], + ) + self._spawn_info_text.node.text = text + + def _respawn_players_for_wave(self) -> None: + # Respawn applicable players. + if self._wavenum > 1 and not self.is_waiting_for_continue(): + for player in self.players: + if ( + not player.is_alive() + and player.respawn_wave == self._wavenum + ): + self.spawn_player(player) + self._update_player_spawn_info() + + def _setup_wave_spawns(self, wave: Wave) -> None: + tval = 0.0 + dtime = 0.2 + if self._wavenum == 1: + spawn_time = 3.973 + tval += 0.5 + else: + spawn_time = 2.648 + + bot_angle = wave.base_angle + self._time_bonus = 0 + self._flawless_bonus = 0 + for info in wave.entries: + if info is None: + continue + if isinstance(info, Delay): + spawn_time += info.duration + continue + if isinstance(info, Spacing): + bot_angle += info.spacing + continue + bot_type_2 = info.bottype + if bot_type_2 is not None: + assert not isinstance(bot_type_2, str) + self._time_bonus += bot_type_2.points_mult * 20 + self._flawless_bonus += bot_type_2.points_mult * 5 + + if self.map.name == 'Doom Shroom': + tval += dtime + spacing = info.spacing + bot_angle += spacing * 0.5 + if bot_type_2 is not None: + tcall = bs.WeakCall( + self.add_bot_at_angle, bot_angle, bot_type_2, spawn_time + ) + bs.timer(tval, tcall) + tval += dtime + bot_angle += spacing * 0.5 + else: + assert bot_type_2 is not None + spcall = bs.WeakCall( + self.add_bot_at_point, bot_type_2, spawn_time + ) + bs.timer(tval, spcall) + + # We can end the wave after all the spawning happens. + bs.timer( + tval + spawn_time - dtime + 0.01, + bs.WeakCall(self._set_can_end_wave), + ) + + def _start_next_wave(self) -> None: + + # This can happen if we beat a wave as we die. + # We don't wanna respawn players and whatnot if this happens. + if self._game_over: + return + + self._respawn_players_for_wave() + wave = self._generate_random_wave() + self._setup_wave_spawns(wave) + self._update_wave_ui_and_bonuses() + bs.timer(0.4, babase.Call(self._new_wave_sound.play)) + + def _update_wave_ui_and_bonuses(self) -> None: + self.show_zoom_message( + babase.Lstr( + value='${A} ${B}', + subs=[ + ('${A}', babase.Lstr(resource='waveText')), + ('${B}', str(self._wavenum)), + ], + ), + scale=1.0, + duration=1.0, + trail=True, + ) + + # Reset our time bonus. + tbtcolor = (1, 1, 0, 1) + tbttxt = babase.Lstr( + value='${A}: ${B}', + subs=[ + ('${A}', babase.Lstr(resource='timeBonusText')), + ('${B}', str(self._time_bonus)), + ], + ) + self._time_bonus_text = bs.NodeActor( + bs.newnode( + 'text', + attrs={ + 'v_attach': 'top', + 'h_attach': 'center', + 'h_align': 'center', + 'vr_depth': -30, + 'color': tbtcolor, + 'shadow': 1.0, + 'flatness': 1.0, + 'position': (0, -60), + 'scale': 0.8, + 'text': tbttxt, + }, + ) + ) + + bs.timer(5.0, bs.WeakCall(self._start_time_bonus_timer)) + wtcolor = (1, 1, 1, 1) + wttxt = babase.Lstr( + value='${A} ${B}', + subs=[ + ('${A}', babase.Lstr(resource='waveText')), + ('${B}', str(self._wavenum) + ('')), + ], + ) + self._wave_text = bs.NodeActor( + bs.newnode( + 'text', + attrs={ + 'v_attach': 'top', + 'h_attach': 'center', + 'h_align': 'center', + 'vr_depth': -10, + 'color': wtcolor, + 'shadow': 1.0, + 'flatness': 1.0, + 'position': (0, -40), + 'scale': 1.3, + 'text': wttxt, + }, + ) + ) + + def _bot_levels_for_wave(self) -> list[list[type[SpazBot]]]: + level = self._wavenum + bot_types = [ + BomberBot, + BrawlerBot, + TriggerBot, + ChargerBot, + BomberBotPro, + BrawlerBotPro, + TriggerBotPro, + BomberBotProShielded, + ExplodeyBot, + ChargerBotProShielded, + StickyBot, + BrawlerBotProShielded, + TriggerBotProShielded, + ] + if level > 5: + bot_types += [ + ExplodeyBot, + TriggerBotProShielded, + BrawlerBotProShielded, + ChargerBotProShielded, + ] + if level > 7: + bot_types += [ + ExplodeyBot, + TriggerBotProShielded, + BrawlerBotProShielded, + ChargerBotProShielded, + ] + if level > 10: + bot_types += [ + TriggerBotProShielded, + TriggerBotProShielded, + TriggerBotProShielded, + TriggerBotProShielded, + ] + if level > 13: + bot_types += [ + TriggerBotProShielded, + TriggerBotProShielded, + TriggerBotProShielded, + TriggerBotProShielded, + ] + bot_levels = [ + [b for b in bot_types if b.points_mult == 1], + [b for b in bot_types if b.points_mult == 2], + [b for b in bot_types if b.points_mult == 3], + [b for b in bot_types if b.points_mult == 4], + ] + + # Make sure all lists have something in them + if not all(bot_levels): + raise RuntimeError('Got empty bot level') + return bot_levels + + def _add_entries_for_distribution_group( + self, + group: list[tuple[int, int]], + bot_levels: list[list[type[SpazBot]]], + all_entries: list[Spawn | Spacing | Delay | None], + ) -> None: + entries: list[Spawn | Spacing | Delay | None] = [] + for entry in group: + bot_level = bot_levels[entry[0] - 1] + bot_type = bot_level[random.randrange(len(bot_level))] + rval = random.random() + if rval < 0.5: + spacing = 10.0 + elif rval < 0.9: + spacing = 20.0 + else: + spacing = 40.0 + split = random.random() > 0.3 + for i in range(entry[1]): + if split and i % 2 == 0: + entries.insert(0, Spawn(bot_type, spacing=spacing)) + else: + entries.append(Spawn(bot_type, spacing=spacing)) + if entries: + all_entries += entries + all_entries.append(Spacing(40.0 if random.random() < 0.5 else 80.0)) + + def _generate_random_wave(self) -> Wave: + level = self._wavenum + bot_levels = self._bot_levels_for_wave() + + target_points = level * 3 - 2 + min_dudes = min(1 + level // 3, 10) + max_dudes = min(10, level + 1) + max_level = ( + 4 if level > 6 else (3 if level > 3 else (2 if level > 2 else 1)) + ) + group_count = 3 + distribution = self._get_distribution( + target_points, min_dudes, max_dudes, group_count, max_level + ) + all_entries: list[Spawn | Spacing | Delay | None] = [] + for group in distribution: + self._add_entries_for_distribution_group( + group, bot_levels, all_entries + ) + angle_rand = random.random() + if angle_rand > 0.75: + base_angle = 130.0 + elif angle_rand > 0.5: + base_angle = 210.0 + elif angle_rand > 0.25: + base_angle = 20.0 + else: + base_angle = -30.0 + base_angle += (0.5 - random.random()) * 20.0 + wave = Wave(base_angle=base_angle, entries=all_entries) + return wave + + def add_bot_at_point( + self, spaz_type: type[SpazBot], spawn_time: float = 1.0 + ) -> None: + """Add a new bot at a specified named point.""" + if self._game_over: + return + def _getpt() -> Sequence[float]: + point = self.map.get_def_points( + 'ffa_spawn')[self._next_ffa_start_index] + self._next_ffa_start_index = ( + self._next_ffa_start_index + 1) % len( + self.map.get_def_points('ffa_spawn') + ) + x_range = (-0.5, 0.5) if point[3] == 0.0 else (-point[3], point[3]) + z_range = (-0.5, 0.5) if point[5] == 0.0 else (-point[5], point[5]) + point = ( + point[0] + random.uniform(*x_range), + point[1], + point[2] + random.uniform(*z_range), + ) + return point + pointpos = _getpt() + + assert self._bots is not None + self._bots.spawn_bot(spaz_type, pos=pointpos, spawn_time=spawn_time) + + def add_bot_at_angle( + self, angle: float, spaz_type: type[SpazBot], spawn_time: float = 1.0 + ) -> None: + """Add a new bot at a specified angle (for circular maps).""" + if self._game_over: + return + angle_radians = angle / 57.2957795 + xval = math.sin(angle_radians) * 1.06 + zval = math.cos(angle_radians) * 1.06 + point = (xval / 0.125, 2.3, (zval / 0.2) - 3.7) + assert self._bots is not None + self._bots.spawn_bot(spaz_type, pos=point, spawn_time=spawn_time) + + def _update_time_bonus(self) -> None: + self._time_bonus = int(self._time_bonus * 0.93) + if self._time_bonus > 0 and self._time_bonus_text is not None: + assert self._time_bonus_text.node + self._time_bonus_text.node.text = babase.Lstr( + value='${A}: ${B}', + subs=[ + ('${A}', babase.Lstr(resource='timeBonusText')), + ('${B}', str(self._time_bonus)), + ], + ) + else: + self._time_bonus_text = None + + def _start_updating_waves(self) -> None: + self._wave_update_timer = bs.Timer( + 2.0, bs.WeakCall(self._update_waves), repeat=True + ) + + def _update_scores(self) -> None: + score = self._score + assert self._scoreboard is not None + self._scoreboard.set_team_value(self.teams[0], score, max_score=None) + + def handlemessage(self, msg: Any) -> Any: + + if isinstance(msg, PlayerSpazHurtMessage): + msg.spaz.getplayer(Player, True).has_been_hurt = True + self._a_player_has_been_hurt = True + + elif isinstance(msg, bs.PlayerScoredMessage): + self._score += msg.score + self._update_scores() + + elif isinstance(msg, bs.PlayerDiedMessage): + super().handlemessage(msg) # Augment standard behavior. + player = msg.getplayer(Player) + self._a_player_has_been_hurt = True + + # Make note with the player when they can respawn: + if self._wavenum < 10: + player.respawn_wave = max(2, self._wavenum + 1) + elif self._wavenum < 15: + player.respawn_wave = max(2, self._wavenum + 2) + else: + player.respawn_wave = max(2, self._wavenum + 3) + bs.timer(0.1, self._update_player_spawn_info) + bs.timer(0.1, self._checkroundover) + + elif isinstance(msg, SpazBotDiedMessage): + pts, importance = msg.spazbot.get_death_points(msg.how) + if msg.killerplayer is not None: + target: Sequence[float] | None + if msg.spazbot.node: + target = msg.spazbot.node.position + else: + target = None + + killerplayer = msg.killerplayer + self.stats.player_scored( + killerplayer, + pts, + target=target, + kill=True, + screenmessage=False, + importance=importance, + ) + self._dingsound.play(volume=0.6) if importance == 1 else self._dingsoundhigh.play(volume=0.6) + + # Normally we pull scores from the score-set, but if there's + # no player lets be explicit. + else: + self._score += pts + self._update_scores() + else: + super().handlemessage(msg) + + def _handle_uber_kill_achievements(self, msg: SpazBotDiedMessage) -> None: + + # Uber mine achievement: + if msg.spazbot.last_attacked_type == ('explosion', 'land_mine'): + self._land_mine_kills += 1 + if self._land_mine_kills >= 6: + self._award_achievement('Gold Miner') + + # Uber tnt achievement: + if msg.spazbot.last_attacked_type == ('explosion', 'tnt'): + self._tnt_kills += 1 + if self._tnt_kills >= 6: + bs.timer( + 0.5, bs.WeakCall(self._award_achievement, 'TNT Terror') + ) + + def _handle_pro_kill_achievements(self, msg: SpazBotDiedMessage) -> None: + + # TNT achievement: + if msg.spazbot.last_attacked_type == ('explosion', 'tnt'): + self._tnt_kills += 1 + if self._tnt_kills >= 3: + bs.timer( + 0.5, + bs.WeakCall( + self._award_achievement, 'Boom Goes the Dynamite' + ), + ) + + def _handle_rookie_kill_achievements(self, msg: SpazBotDiedMessage) -> None: + # Land-mine achievement: + if msg.spazbot.last_attacked_type == ('explosion', 'land_mine'): + self._land_mine_kills += 1 + if self._land_mine_kills >= 3: + self._award_achievement('Mine Games') + + def _handle_training_kill_achievements( + self, msg: SpazBotDiedMessage + ) -> None: + # Toss-off-map achievement: + if msg.spazbot.last_attacked_type == ('picked_up', 'default'): + self._throw_off_kills += 1 + if self._throw_off_kills >= 3: + self._award_achievement('Off You Go Then') + + def _set_can_end_wave(self) -> None: + self._can_end_wave = True + + def end_game(self) -> None: + # Tell our bots to celebrate just to rub it in. + assert self._bots is not None + self._bots.final_celebrate() + self._game_over = True + self.do_end('defeat', delay=2.0) + bs.setmusic(None) + + def on_continue(self) -> None: + for player in self.players: + if not player.is_alive(): + self.spawn_player(player) + + def _checkroundover(self) -> None: + """Potentially end the round based on the state of the game.""" + if self.has_ended(): + return + if not any(player.is_alive() for player in self.teams[0].players): + # Allow continuing after wave 1. + if self._wavenum > 1: + self.continue_or_end_game() + else: + self.end_game() + +# ba_meta export plugin +class CustomOnslaughtLevel(babase.Plugin): + def on_app_running(self) -> None: + babase.app.classic.add_coop_practice_level( + bs._level.Level( + 'Onslaught Football', + gametype=OnslaughtFootballGame, + settings={ + 'map': 'Football Stadium', + 'Epic Mode': False, + }, + preview_texture_name='footballStadiumPreview', + ) + ) + babase.app.classic.add_coop_practice_level( + bs._level.Level( + 'Onslaught Football Epic', + gametype=OnslaughtFootballGame, + settings={ + 'map': 'Football Stadium', + 'Epic Mode': True, + }, + preview_texture_name='footballStadiumPreview', + ) + ) From 546a8d0a4a6ce2863b801c71ebeba6a1b5caedca Mon Sep 17 00:00:00 2001 From: brostosjoined Date: Fri, 26 Jan 2024 02:02:31 +0000 Subject: [PATCH 0837/1464] [ci] auto-format --- plugins/minigames/ba_dark_fields.py | 167 +- plugins/minigames/gravity_falls.py | 17 +- plugins/minigames/infinite_ninjas.py | 47 +- plugins/minigames/lame_fight.py | 88 +- plugins/minigames/onslaught_football.py | 1932 ++++++++++++----------- 5 files changed, 1139 insertions(+), 1112 deletions(-) diff --git a/plugins/minigames/ba_dark_fields.py b/plugins/minigames/ba_dark_fields.py index 2a820054..03302eea 100644 --- a/plugins/minigames/ba_dark_fields.py +++ b/plugins/minigames/ba_dark_fields.py @@ -23,6 +23,7 @@ if TYPE_CHECKING: from typing import Any, Sequence, Optional, List, Dict, Type, Type + class Player(bs.Player['Team']): """Our player type for this game.""" @@ -34,36 +35,38 @@ def __init__(self) -> None: self.score = 0 # ba_meta export bascenev1.GameActivity + + class DarkFieldsGame(bs.TeamGameActivity[Player, Team]): name = 'Dark Fields' description = 'Get to the other side.' available_settings = [ bs.IntSetting('Score to Win', - min_value=1, - default=3, - ), + min_value=1, + default=3, + ), bs.IntChoiceSetting('Time Limit', - choices=[ - ('None', 0), - ('1 Minute', 60), - ('2 Minutes', 120), - ('5 Minutes', 300), - ('10 Minutes', 600), - ('20 Minutes', 1200), - ], - default=0, - ), + choices=[ + ('None', 0), + ('1 Minute', 60), + ('2 Minutes', 120), + ('5 Minutes', 300), + ('10 Minutes', 600), + ('20 Minutes', 1200), + ], + default=0, + ), bs.FloatChoiceSetting('Respawn Times', - choices=[ - ('Shorter', 0.25), - ('Short', 0.5), - ('Normal', 1.0), - ('Long', 2.0), - ('Longer', 4.0), - ], - default=1.0, - ), + choices=[ + ('Shorter', 0.25), + ('Short', 0.5), + ('Normal', 1.0), + ('Long', 2.0), + ('Longer', 4.0), + ], + default=1.0, + ), bs.BoolSetting('Epic Mode', default=False), bs.BoolSetting('Players as center of interest', default=True), ] @@ -90,26 +93,25 @@ def __init__(self, settings: dict): self._scoreRegionMaterial = bs.Material() self._scoreRegionMaterial.add_actions( - conditions=("they_have_material",shared.player_material), - actions=(("modify_part_collision","collide",True), - ("modify_part_collision","physical",False), - ("call","at_connect", self._onPlayerScores))) + conditions=("they_have_material", shared.player_material), + actions=(("modify_part_collision", "collide", True), + ("modify_part_collision", "physical", False), + ("call", "at_connect", self._onPlayerScores))) self.slow_motion = self._epic_mode self.default_music = (bs.MusicType.EPIC if self._epic_mode else None) - def on_transition_in(self) -> None: super().on_transition_in() gnode = bs.getactivity().globalsnode - gnode.tint = (0.5,0.5,0.5) - - a = bs.newnode('locator',attrs={'shape':'box','position':(12.2,0,.1087926362), - 'color':(5,0,0),'opacity':1,'draw_beauty':True,'additive':False,'size':[2.5,0.1,12.8]}) - - b = bs.newnode('locator',attrs={'shape':'box','position':(-12.1,0,.1087926362), - 'color':(0,0,5),'opacity':1,'draw_beauty':True,'additive':False,'size':[2.5,0.1,12.8]}) - + gnode.tint = (0.5, 0.5, 0.5) + + a = bs.newnode('locator', attrs={'shape': 'box', 'position': (12.2, 0, .1087926362), + 'color': (5, 0, 0), 'opacity': 1, 'draw_beauty': True, 'additive': False, 'size': [2.5, 0.1, 12.8]}) + + b = bs.newnode('locator', attrs={'shape': 'box', 'position': (-12.1, 0, .1087926362), + 'color': (0, 0, 5), 'opacity': 1, 'draw_beauty': True, 'additive': False, 'size': [2.5, 0.1, 12.8]}) + def on_begin(self) -> None: # self._has_begun = False super().on_begin() @@ -132,21 +134,22 @@ def on_begin(self) -> None: self._scoreRegions = [] defs = bs.getactivity().map.defs self._scoreRegions.append(bs.NodeActor(bs.newnode('region', - attrs={'position':defs.boxes['goal1'][0:3], - 'scale':defs.boxes['goal1'][6:9], - 'type': 'box', - 'materials':(self._scoreRegionMaterial,)}))) + attrs={'position': defs.boxes['goal1'][0:3], + 'scale': defs.boxes['goal1'][6:9], + 'type': 'box', + 'materials': (self._scoreRegionMaterial,)}))) self.mines = [] self.spawnMines() - bs.timer(0.8 if self.slow_motion else 1.7,self.start) + bs.timer(0.8 if self.slow_motion else 1.7, self.start) def start(self): # self._has_begun = True self._show_info() - bs.timer(random.randrange(3,7),self.doRandomLighting) + bs.timer(random.randrange(3, 7), self.doRandomLighting) if not self._epic_mode: setmusic(bs.MusicType.SCARY) - animate_array(bs.getactivity().globalsnode,'tint',3,{0:(0.5,0.5,0.5),2:(0.2,0.2,0.2)}) + animate_array(bs.getactivity().globalsnode, 'tint', 3, + {0: (0.5, 0.5, 0.5), 2: (0.2, 0.2, 0.2)}) for p in self.players: self.doPlayer(p) @@ -157,10 +160,10 @@ def spawn_player(self, player): else: self.doPlayer(player) - def doPlayer(self,player): - pos = (-12.4,1,random.randrange(-5,5)) - player = self.spawn_player_spaz(player,pos) - player.connect_controls_to_player(enable_punch=False,enable_bomb=False) + def doPlayer(self, player): + pos = (-12.4, 1, random.randrange(-5, 5)) + player = self.spawn_player_spaz(player, pos) + player.connect_controls_to_player(enable_punch=False, enable_bomb=False) player.node.is_area_of_interest = self._center_of_interest def _show_info(self) -> None: @@ -176,52 +179,53 @@ def _update_scoreboard(self) -> None: self._scoreboard.set_team_value(team, team.score, self._score_to_win) def doRandomLighting(self): - bs.timer(random.randrange(3,7),self.doRandomLighting) - if self.isUpdatingMines: return + bs.timer(random.randrange(3, 7), self.doRandomLighting) + if self.isUpdatingMines: + return delay = 0 for mine in self.mines: if mine.node.exists(): pos = mine.node.position - bs.timer(delay,babase.Call(self.do_light,pos)) + bs.timer(delay, babase.Call(self.do_light, pos)) delay += 0.005 if self._epic_mode else 0.01 - def do_light(self,pos): - light = bs.newnode('light',attrs={ - 'position': pos, - 'volume_intensity_scale': 1.0, - 'radius':0.1, - 'color': (1,0,0) - }) - bs.animate(light, 'intensity', { 0: 2.0, 3.0: 0.0}) + def do_light(self, pos): + light = bs.newnode('light', attrs={ + 'position': pos, + 'volume_intensity_scale': 1.0, + 'radius': 0.1, + 'color': (1, 0, 0) + }) + bs.animate(light, 'intensity', {0: 2.0, 3.0: 0.0}) bs.timer(3.0, light.delete) def spawnMines(self): delay = 0 - h_range = [10,8,6,4,2,0,-2,-4,-6,-8,-10] + h_range = [10, 8, 6, 4, 2, 0, -2, -4, -6, -8, -10] for h in h_range: - for i in range(random.randint(3,4)): + for i in range(random.randint(3, 4)): x = h+random.random() - y = random.randrange(-5,6)+(random.random()) - pos = (x,1,y) - bs.timer(delay,babase.Call(self.doMine,pos)) + y = random.randrange(-5, 6)+(random.random()) + pos = (x, 1, y) + bs.timer(delay, babase.Call(self.doMine, pos)) delay += 0.015 if self._epic_mode else 0.04 - bs.timer(5.0,self.stopUpdateMines) + bs.timer(5.0, self.stopUpdateMines) def stopUpdateMines(self): self.isUpdatingMines = False def updateMines(self): - if self.isUpdatingMines: return + if self.isUpdatingMines: + return self.isUpdatingMines = True for m in self.mines: m.node.delete() self.mines = [] self.spawnMines() - - - def doMine(self,pos): - b = bomb.Bomb(position=pos,bomb_type='land_mine').autoretain() + + def doMine(self, pos): + b = bomb.Bomb(position=pos, bomb_type='land_mine').autoretain() b.add_explode_callback(self._on_bomb_exploded) b.arm() self.mines.append(b) @@ -229,8 +233,8 @@ def doMine(self,pos): def _on_bomb_exploded(self, bomb: Bomb, blast: Blast) -> None: assert blast.node p = blast.node.position - pos = (p[0],p[1]+1,p[2]) - bs.timer(0.5,babase.Call(self.doMine,pos)) + pos = (p[0], p[1]+1, p[2]) + bs.timer(0.5, babase.Call(self.doMine, pos)) def _onPlayerScores(self): player: Optional[Player] @@ -238,7 +242,7 @@ def _onPlayerScores(self): spaz = bs.getcollision().opposingnode.getdelegate(PlayerSpaz, True) except bs.NotFoundError: return - + if not spaz.is_alive(): return @@ -246,25 +250,26 @@ def _onPlayerScores(self): player = spaz.getplayer(Player, True) except bs.NotFoundError: return - + if player.exists() and player.is_alive(): player.team.score += 1 - self._scoreSound.play() + self._scoreSound.play() pos = player.actor.node.position - animate_array(bs.getactivity().globalsnode,'tint',3,{0:(0.5,0.5,0.5),2.8:(0.2,0.2,0.2)}) + animate_array(bs.getactivity().globalsnode, 'tint', 3, { + 0: (0.5, 0.5, 0.5), 2.8: (0.2, 0.2, 0.2)}) self._update_scoreboard() light = bs.newnode('light', - attrs={ - 'position': pos, - 'radius': 0.5, - 'color': (1, 0, 0) - }) + attrs={ + 'position': pos, + 'radius': 0.5, + 'color': (1, 0, 0) + }) bs.animate(light, 'intensity', {0.0: 0, 0.1: 1, 0.5: 0}, loop=False) bs.timer(1.0, light.delete) - player.actor.handlemessage(bs.DieMessage( how=bs.DeathType.REACHED_GOAL)) + player.actor.handlemessage(bs.DieMessage(how=bs.DeathType.REACHED_GOAL)) self.updateMines() if any(team.score >= self._score_to_win for team in self.teams): @@ -288,4 +293,4 @@ def end_game(self) -> None: results = bs.GameResults() for team in self.teams: results.set_team_score(team, team.score) - self.end(results=results) \ No newline at end of file + self.end(results=results) diff --git a/plugins/minigames/gravity_falls.py b/plugins/minigames/gravity_falls.py index f24b5918..e4c7e44a 100644 --- a/plugins/minigames/gravity_falls.py +++ b/plugins/minigames/gravity_falls.py @@ -1,6 +1,6 @@ # Ported to api 8 by brostos using baport.(https://github.com/bombsquad-community/baport) -## Made by MattZ45986 on GitHub -## Ported by: Freaku / @[Just] Freak#4999 +# Made by MattZ45986 on GitHub +# Ported by: Freaku / @[Just] Freak#4999 import babase @@ -9,26 +9,27 @@ from bascenev1lib.game.elimination import EliminationGame - # ba_meta require api 8 # ba_meta export bascenev1.GameActivity class GFGame(EliminationGame): name = 'Gravity Falls' def spawn_player(self, player): - actor = self.spawn_player_spaz(player, (0,5,0)) + actor = self.spawn_player_spaz(player, (0, 5, 0)) if not self._solo_mode: bs.timer(0.3, babase.Call(self._print_lives, player)) # If we have any icons, update their state. for icon in player.icons: icon.handle_player_spawned() - bs.timer(1,babase.Call(self.raise_player, player)) + bs.timer(1, babase.Call(self.raise_player, player)) return actor def raise_player(self, player): if player.is_alive(): try: - player.actor.node.handlemessage("impulse",player.actor.node.position[0],player.actor.node.position[1]+.5,player.actor.node.position[2],0,5,0, 3,10,0,0, 0,5,0) - except: pass - bs.timer(0.05,babase.Call(self.raise_player,player)) \ No newline at end of file + player.actor.node.handlemessage( + "impulse", player.actor.node.position[0], player.actor.node.position[1]+.5, player.actor.node.position[2], 0, 5, 0, 3, 10, 0, 0, 0, 5, 0) + except: + pass + bs.timer(0.05, babase.Call(self.raise_player, player)) diff --git a/plugins/minigames/infinite_ninjas.py b/plugins/minigames/infinite_ninjas.py index c43cb65e..de2784f6 100644 --- a/plugins/minigames/infinite_ninjas.py +++ b/plugins/minigames/infinite_ninjas.py @@ -1,7 +1,7 @@ # Ported to api 8 by brostos using baport.(https://github.com/bombsquad-community/baport) # ba_meta require api 8 -#Copy pasted from ExplodoRun by Blitz,just edited Bots and map 😝 +# Copy pasted from ExplodoRun by Blitz,just edited Bots and map 😝 from __future__ import annotations @@ -19,20 +19,24 @@ from typing import Any, Type, Dict, List, Optional ## MoreMinigames.py support ## + + def ba_get_api_version(): return 6 + def ba_get_levels(): return [babase._level.Level( - 'Infinite Ninjas',gametype=InfiniteNinjasGame, + 'Infinite Ninjas', gametype=InfiniteNinjasGame, settings={}, - preview_texture_name = 'footballStadiumPreview'), + preview_texture_name='footballStadiumPreview'), babase._level.Level( - 'Epic Infinite Ninjas',gametype=InfiniteNinjasGame, - settings={'Epic Mode':True}, - preview_texture_name = 'footballStadiumPreview')] + 'Epic Infinite Ninjas', gametype=InfiniteNinjasGame, + settings={'Epic Mode': True}, + preview_texture_name='footballStadiumPreview')] ## MoreMinigames.py support ## + class Player(bs.Player['Team']): """Our player type for this game.""" @@ -41,6 +45,8 @@ class Team(bs.Team[Player]): """Our team type for this game.""" # ba_meta export bascenev1.GameActivity + + class InfiniteNinjasGame(bs.TeamGameActivity[Player, Team]): name = "Infinite Ninjas" description = "How long can you survive from Ninjas??" @@ -49,8 +55,8 @@ class InfiniteNinjasGame(bs.TeamGameActivity[Player, Team]): scoretype=bs.ScoreType.MILLISECONDS, lower_is_better=False) default_music = bs.MusicType.TO_THE_DEATH - - def __init__(self, settings:dict): + + def __init__(self, settings: dict): settings['map'] = "Football Stadium" self._epic_mode = settings.get('Epic Mode', False) if self._epic_mode: @@ -61,27 +67,28 @@ def __init__(self, settings:dict): self._won = False self._bots = SpazBotSet() self.wave = 1 - + def on_begin(self) -> None: super().on_begin() - + self._timer = OnScreenTimer() bs.timer(2.5, self._timer.start) - - #Bots Hehe - bs.timer(2.5,self.street) + + # Bots Hehe + bs.timer(2.5, self.street) def street(self): for a in range(self.wave): - p1 = random.choice([-5,-2.5,0,2.5,5]) - p3 = random.choice([-4.5,-4.14,-5,-3]) - time = random.choice([1,1.5,2.5,2]) - self._bots.spawn_bot(ChargerBot, pos=(p1,0.4,p3),spawn_time = time) + p1 = random.choice([-5, -2.5, 0, 2.5, 5]) + p3 = random.choice([-4.5, -4.14, -5, -3]) + time = random.choice([1, 1.5, 2.5, 2]) + self._bots.spawn_bot(ChargerBot, pos=(p1, 0.4, p3), spawn_time=time) self.wave += 1 - + def botrespawn(self): if not self._bots.have_living_bots(): self.street() + def handlemessage(self, msg: Any) -> Any: # A player has died. @@ -89,7 +96,7 @@ def handlemessage(self, msg: Any) -> Any: super().handlemessage(msg) # Augment standard behavior. self._won = True self.end_game() - + # A spaz-bot has died. elif isinstance(msg, SpazBotDiedMessage): # Unfortunately the bot-set will always tell us there are living @@ -130,5 +137,3 @@ def end_game(self) -> None: # Ends the activity. self.end(results) - - \ No newline at end of file diff --git a/plugins/minigames/lame_fight.py b/plugins/minigames/lame_fight.py index e997a72a..6b69d137 100644 --- a/plugins/minigames/lame_fight.py +++ b/plugins/minigames/lame_fight.py @@ -17,15 +17,18 @@ if TYPE_CHECKING: from typing import Any, Type, Dict, List, Optional + def ba_get_api_version(): return 6 + def ba_get_levels(): - return [babase._level.Level( - 'Lame Fight', - gametype=LameFightGame, - settings={}, - preview_texture_name='courtyardPreview')] + return [babase._level.Level( + 'Lame Fight', + gametype=LameFightGame, + settings={}, + preview_texture_name='courtyardPreview')] + class Player(bs.Player['Team']): """Our player type for this game.""" @@ -35,6 +38,8 @@ class Team(bs.Team[Player]): """Our team type for this game.""" # ba_meta export bascenev1.GameActivity + + class LameFightGame(bs.TeamGameActivity[Player, Team]): name = "Lame Fight" description = "Save World With Super Powers" @@ -43,54 +48,61 @@ class LameFightGame(bs.TeamGameActivity[Player, Team]): scoretype=bs.ScoreType.MILLISECONDS, lower_is_better=True) default_music = bs.MusicType.TO_THE_DEATH - - def __init__(self, settings:dict): + + def __init__(self, settings: dict): settings['map'] = "Courtyard" super().__init__(settings) self._timer: Optional[OnScreenTimer] = None self._winsound = bs.getsound('score') self._won = False self._bots = SpazBotSet() - + def on_begin(self) -> None: super().on_begin() - + self._timer = OnScreenTimer() bs.timer(4.0, self._timer.start) - - #Bots Hehe - bs.timer(1.0, lambda: self._bots.spawn_bot(ChargerBot, pos=(3,3,-2),spawn_time = 3.0)) - bs.timer(1.0, lambda: self._bots.spawn_bot(ChargerBot, pos=(-3,3,-2),spawn_time = 3.0)) - bs.timer(1.0, lambda: self._bots.spawn_bot(ChargerBot, pos=(5,3,-2),spawn_time = 3.0)) - bs.timer(1.0, lambda: self._bots.spawn_bot(ChargerBot, pos=(-5,3,-2),spawn_time = 3.0)) - bs.timer(1.0, lambda: self._bots.spawn_bot(ChargerBot, pos=(0,3,1),spawn_time = 3.0)) - bs.timer(1.0, lambda: self._bots.spawn_bot(ChargerBot, pos=(0,3,-5),spawn_time = 3.0)) - bs.timer(9.0, lambda: self._bots.spawn_bot(BomberBotProShielded, pos=(-7,5,-7.5),spawn_time = 3.0)) - bs.timer(9.0, lambda: self._bots.spawn_bot(BomberBotProShielded, pos=(7,5,-7.5),spawn_time = 3.0)) - bs.timer(9.0, lambda: self._bots.spawn_bot(BomberBotProShielded, pos=(7,5,1.5),spawn_time = 3.0)) - bs.timer(9.0, lambda: self._bots.spawn_bot(BomberBotProShielded, pos=(-7,5,1.5),spawn_time = 3.0)) - bs.timer(12.0, lambda: self._bots.spawn_bot(TriggerBotProShielded, pos=(-1,7,-8),spawn_time = 3.0)) - bs.timer(12.0, lambda: self._bots.spawn_bot(TriggerBotProShielded, pos=(1,7,-8),spawn_time = 3.0)) - bs.timer(15.0, lambda: self._bots.spawn_bot(ExplodeyBot, pos=(0,3,-5),spawn_time = 3.0)) - bs.timer(20.0, lambda: self._bots.spawn_bot(ExplodeyBot, pos=(0,3,1),spawn_time = 3.0)) - bs.timer(20.0, lambda: self._bots.spawn_bot(ExplodeyBot, pos=(-5,3,-2),spawn_time = 3.0)) - bs.timer(20.0, lambda: self._bots.spawn_bot(ExplodeyBot, pos=(5,3,-2),spawn_time = 3.0)) - bs.timer(30,self.street) + + # Bots Hehe + bs.timer(1.0, lambda: self._bots.spawn_bot(ChargerBot, pos=(3, 3, -2), spawn_time=3.0)) + bs.timer(1.0, lambda: self._bots.spawn_bot(ChargerBot, pos=(-3, 3, -2), spawn_time=3.0)) + bs.timer(1.0, lambda: self._bots.spawn_bot(ChargerBot, pos=(5, 3, -2), spawn_time=3.0)) + bs.timer(1.0, lambda: self._bots.spawn_bot(ChargerBot, pos=(-5, 3, -2), spawn_time=3.0)) + bs.timer(1.0, lambda: self._bots.spawn_bot(ChargerBot, pos=(0, 3, 1), spawn_time=3.0)) + bs.timer(1.0, lambda: self._bots.spawn_bot(ChargerBot, pos=(0, 3, -5), spawn_time=3.0)) + bs.timer(9.0, lambda: self._bots.spawn_bot( + BomberBotProShielded, pos=(-7, 5, -7.5), spawn_time=3.0)) + bs.timer(9.0, lambda: self._bots.spawn_bot( + BomberBotProShielded, pos=(7, 5, -7.5), spawn_time=3.0)) + bs.timer(9.0, lambda: self._bots.spawn_bot( + BomberBotProShielded, pos=(7, 5, 1.5), spawn_time=3.0)) + bs.timer(9.0, lambda: self._bots.spawn_bot( + BomberBotProShielded, pos=(-7, 5, 1.5), spawn_time=3.0)) + bs.timer(12.0, lambda: self._bots.spawn_bot( + TriggerBotProShielded, pos=(-1, 7, -8), spawn_time=3.0)) + bs.timer(12.0, lambda: self._bots.spawn_bot( + TriggerBotProShielded, pos=(1, 7, -8), spawn_time=3.0)) + bs.timer(15.0, lambda: self._bots.spawn_bot(ExplodeyBot, pos=(0, 3, -5), spawn_time=3.0)) + bs.timer(20.0, lambda: self._bots.spawn_bot(ExplodeyBot, pos=(0, 3, 1), spawn_time=3.0)) + bs.timer(20.0, lambda: self._bots.spawn_bot(ExplodeyBot, pos=(-5, 3, -2), spawn_time=3.0)) + bs.timer(20.0, lambda: self._bots.spawn_bot(ExplodeyBot, pos=(5, 3, -2), spawn_time=3.0)) + bs.timer(30, self.street) def street(self): - bs.broadcastmessage("Lame Guys Are Here!",color = (1,0,0)) - for a in range(-1,2): - for b in range(-3,0): - self._bots.spawn_bot(BrawlerBotProShielded, pos=(a,3,b),spawn_time = 3.0) - + bs.broadcastmessage("Lame Guys Are Here!", color=(1, 0, 0)) + for a in range(-1, 2): + for b in range(-3, 0): + self._bots.spawn_bot(BrawlerBotProShielded, pos=(a, 3, b), spawn_time=3.0) + def spawn_player(self, player: Player) -> bs.Actor: spawn_center = (0, 3, -2) pos = (spawn_center[0] + random.uniform(-1.5, 1.5), spawn_center[1], spawn_center[2] + random.uniform(-1.5, 1.5)) - spaz = self.spawn_player_spaz(player,position = pos) - p = ["Bigger Blast","Stronger Punch","Shield","Speed"] + spaz = self.spawn_player_spaz(player, position=pos) + p = ["Bigger Blast", "Stronger Punch", "Shield", "Speed"] Power = random.choice(p) - spaz.bomb_type = random.choice(["normal","sticky","ice","impact","normal","ice","sticky"]) + spaz.bomb_type = random.choice( + ["normal", "sticky", "ice", "impact", "normal", "ice", "sticky"]) bs.broadcastmessage(f"Now You Have {Power}") if Power == p[0]: spaz.bomb_count = 3 @@ -103,10 +115,12 @@ def spawn_player(self, player: Player) -> bs.Actor: if Power == p[3]: spaz.node.hockey = True return spaz + def _check_if_won(self) -> None: if not self._bots.have_living_bots(): self._won = True self.end_game() + def handlemessage(self, msg: Any) -> Any: # A player has died. @@ -154,5 +168,3 @@ def end_game(self) -> None: # Ends the activity. self.end(results) - - \ No newline at end of file diff --git a/plugins/minigames/onslaught_football.py b/plugins/minigames/onslaught_football.py index 06a5c5c2..b585581a 100644 --- a/plugins/minigames/onslaught_football.py +++ b/plugins/minigames/onslaught_football.py @@ -21,1003 +21,1007 @@ from bascenev1lib.actor.controlsguide import ControlsGuide from bascenev1lib.actor.powerupbox import PowerupBox, PowerupBoxFactory from bascenev1lib.actor.spazbot import ( - SpazBotDiedMessage, - SpazBotSet, - ChargerBot, - StickyBot, - BomberBot, - BomberBotLite, - BrawlerBot, - BrawlerBotLite, - TriggerBot, - BomberBotStaticLite, - TriggerBotStatic, - BomberBotProStatic, - TriggerBotPro, - ExplodeyBot, - BrawlerBotProShielded, - ChargerBotProShielded, - BomberBotPro, - TriggerBotProShielded, - BrawlerBotPro, - BomberBotProShielded, + SpazBotDiedMessage, + SpazBotSet, + ChargerBot, + StickyBot, + BomberBot, + BomberBotLite, + BrawlerBot, + BrawlerBotLite, + TriggerBot, + BomberBotStaticLite, + TriggerBotStatic, + BomberBotProStatic, + TriggerBotPro, + ExplodeyBot, + BrawlerBotProShielded, + ChargerBotProShielded, + BomberBotPro, + TriggerBotProShielded, + BrawlerBotPro, + BomberBotProShielded, ) if TYPE_CHECKING: - from typing import Any, Sequence - from bascenev1lib.actor.spazbot import SpazBot + from typing import Any, Sequence + from bascenev1lib.actor.spazbot import SpazBot @dataclass class Wave: - """A wave of enemies.""" + """A wave of enemies.""" - entries: list[Spawn | Spacing | Delay | None] - base_angle: float = 0.0 + entries: list[Spawn | Spacing | Delay | None] + base_angle: float = 0.0 @dataclass class Spawn: - """A bot spawn event in a wave.""" + """A bot spawn event in a wave.""" - bottype: type[SpazBot] | str - point: Point | None = None - spacing: float = 5.0 + bottype: type[SpazBot] | str + point: Point | None = None + spacing: float = 5.0 @dataclass class Spacing: - """Empty space in a wave.""" + """Empty space in a wave.""" - spacing: float = 5.0 + spacing: float = 5.0 @dataclass class Delay: - """A delay between events in a wave.""" + """A delay between events in a wave.""" - duration: float + duration: float class Player(bs.Player['Team']): - """Our player type for this game.""" + """Our player type for this game.""" - def __init__(self) -> None: - self.has_been_hurt = False - self.respawn_wave = 0 + def __init__(self) -> None: + self.has_been_hurt = False + self.respawn_wave = 0 class Team(bs.Team[Player]): - """Our team type for this game.""" + """Our team type for this game.""" class OnslaughtFootballGame(bs.CoopGameActivity[Player, Team]): - """Co-op game where players try to survive attacking waves of enemies.""" - - name = 'Onslaught' - description = 'Defeat all enemies.' - - tips: list[str | babase.GameTip] = [ - 'Hold any button to run.' - ' (Trigger buttons work well if you have them)', - 'Try tricking enemies into killing eachother or running off cliffs.', - 'Try \'Cooking off\' bombs for a second or two before throwing them.', - 'It\'s easier to win with a friend or two helping.', - 'If you stay in one place, you\'re toast. Run and dodge to survive..', - 'Practice using your momentum to throw bombs more accurately.', - 'Your punches do much more damage if you are running or spinning.', - ] - - # Show messages when players die since it matters here. - announce_player_deaths = True - - def __init__(self, settings: dict): - super().__init__(settings) - self._new_wave_sound = bs.getsound('scoreHit01') - self._winsound = bs.getsound('score') - self._cashregistersound = bs.getsound('cashRegister') - self._a_player_has_been_hurt = False - self._player_has_dropped_bomb = False - self._spawn_center = (0, 0.2, 0) - self._tntspawnpos = (0, 0.95, -0.77) - self._powerup_center = (0, 1.5, 0) - self._powerup_spread = (6.0, 4.0) - self._scoreboard: Scoreboard | None = None - self._game_over = False - self._wavenum = 0 - self._can_end_wave = True - self._score = 0 - self._time_bonus = 0 - self._spawn_info_text: bs.NodeActor | None = None - self._dingsound = bs.getsound('dingSmall') - self._dingsoundhigh = bs.getsound('dingSmallHigh') - self._have_tnt = False - self._excluded_powerups: list[str] | None = None - self._waves: list[Wave] = [] - self._tntspawner: TNTSpawner | None = None - self._bots: SpazBotSet | None = None - self._powerup_drop_timer: bs.Timer | None = None - self._time_bonus_timer: bs.Timer | None = None - self._time_bonus_text: bs.NodeActor | None = None - self._flawless_bonus: int | None = None - self._wave_text: bs.NodeActor | None = None - self._wave_update_timer: bs.Timer | None = None - self._throw_off_kills = 0 - self._land_mine_kills = 0 - self._tnt_kills = 0 - - self._epic_mode = bool(settings['Epic Mode']) - # Base class overrides. - self.slow_motion = self._epic_mode - self.default_music = ( - bs.MusicType.EPIC if self._epic_mode else bs.MusicType.ONSLAUGHT - ) - - def on_transition_in(self) -> None: - super().on_transition_in() - self._spawn_info_text = bs.NodeActor( - bs.newnode( - 'text', - attrs={ - 'position': (15, -130), - 'h_attach': 'left', - 'v_attach': 'top', - 'scale': 0.55, - 'color': (0.3, 0.8, 0.3, 1.0), - 'text': '', - }, - ) - ) - self._scoreboard = Scoreboard( - label=babase.Lstr(resource='scoreText'), score_split=0.5 - ) - - def on_begin(self) -> None: - super().on_begin() - self._have_tnt = True - self._excluded_powerups = [] - self._waves = [] - bs.timer(4.0, self._start_powerup_drops) - - # Our TNT spawner (if applicable). - if self._have_tnt: - self._tntspawner = TNTSpawner(position=self._tntspawnpos) - - self.setup_low_life_warning_sound() - self._update_scores() - self._bots = SpazBotSet() - bs.timer(4.0, self._start_updating_waves) - self._next_ffa_start_index = random.randrange( - len(self.map.get_def_points('ffa_spawn')) - ) - - def _get_dist_grp_totals(self, grps: list[Any]) -> tuple[int, int]: - totalpts = 0 - totaldudes = 0 - for grp in grps: - for grpentry in grp: - dudes = grpentry[1] - totalpts += grpentry[0] * dudes - totaldudes += dudes - return totalpts, totaldudes - - def _get_distribution( - self, - target_points: int, - min_dudes: int, - max_dudes: int, - group_count: int, - max_level: int, - ) -> list[list[tuple[int, int]]]: - """Calculate a distribution of bad guys given some params.""" - max_iterations = 10 + max_dudes * 2 - - groups: list[list[tuple[int, int]]] = [] - for _g in range(group_count): - groups.append([]) - types = [1] - if max_level > 1: - types.append(2) - if max_level > 2: - types.append(3) - if max_level > 3: - types.append(4) - for iteration in range(max_iterations): - diff = self._add_dist_entry_if_possible( - groups, max_dudes, target_points, types - ) - - total_points, total_dudes = self._get_dist_grp_totals(groups) - full = total_points >= target_points - - if full: - # Every so often, delete a random entry just to - # shake up our distribution. - if random.random() < 0.2 and iteration != max_iterations - 1: - self._delete_random_dist_entry(groups) - - # If we don't have enough dudes, kill the group with - # the biggest point value. - elif ( - total_dudes < min_dudes and iteration != max_iterations - 1 - ): - self._delete_biggest_dist_entry(groups) - - # If we've got too many dudes, kill the group with the - # smallest point value. - elif ( - total_dudes > max_dudes and iteration != max_iterations - 1 - ): - self._delete_smallest_dist_entry(groups) - - # Close enough.. we're done. - else: - if diff == 0: - break - - return groups - - def _add_dist_entry_if_possible( - self, - groups: list[list[tuple[int, int]]], - max_dudes: int, - target_points: int, - types: list[int], - ) -> int: - # See how much we're off our target by. - total_points, total_dudes = self._get_dist_grp_totals(groups) - diff = target_points - total_points - dudes_diff = max_dudes - total_dudes - - # Add an entry if one will fit. - value = types[random.randrange(len(types))] - group = groups[random.randrange(len(groups))] - if not group: - max_count = random.randint(1, 6) - else: - max_count = 2 * random.randint(1, 3) - max_count = min(max_count, dudes_diff) - count = min(max_count, diff // value) - if count > 0: - group.append((value, count)) - total_points += value * count - total_dudes += count - diff = target_points - total_points - return diff - - def _delete_smallest_dist_entry( - self, groups: list[list[tuple[int, int]]] - ) -> None: - smallest_value = 9999 - smallest_entry = None - smallest_entry_group = None - for group in groups: - for entry in group: - if entry[0] < smallest_value or smallest_entry is None: - smallest_value = entry[0] - smallest_entry = entry - smallest_entry_group = group - assert smallest_entry is not None - assert smallest_entry_group is not None - smallest_entry_group.remove(smallest_entry) - - def _delete_biggest_dist_entry( - self, groups: list[list[tuple[int, int]]] - ) -> None: - biggest_value = 9999 - biggest_entry = None - biggest_entry_group = None - for group in groups: - for entry in group: - if entry[0] > biggest_value or biggest_entry is None: - biggest_value = entry[0] - biggest_entry = entry - biggest_entry_group = group - if biggest_entry is not None: - assert biggest_entry_group is not None - biggest_entry_group.remove(biggest_entry) - - def _delete_random_dist_entry( - self, groups: list[list[tuple[int, int]]] - ) -> None: - entry_count = 0 - for group in groups: - for _ in group: - entry_count += 1 - if entry_count > 1: - del_entry = random.randrange(entry_count) - entry_count = 0 - for group in groups: - for entry in group: - if entry_count == del_entry: - group.remove(entry) - break - entry_count += 1 - - def spawn_player(self, player: Player) -> bs.Actor: - - # We keep track of who got hurt each wave for score purposes. - player.has_been_hurt = False - pos = ( - self._spawn_center[0] + random.uniform(-1.5, 1.5), - self._spawn_center[1], - self._spawn_center[2] + random.uniform(-1.5, 1.5), - ) - spaz = self.spawn_player_spaz(player, position=pos) - spaz.add_dropped_bomb_callback(self._handle_player_dropped_bomb) - return spaz - - def _handle_player_dropped_bomb( - self, player: bs.Actor, bomb: bs.Actor - ) -> None: - del player, bomb # Unused. - self._player_has_dropped_bomb = True - - def _drop_powerup(self, index: int, poweruptype: str | None = None) -> None: - poweruptype = PowerupBoxFactory.get().get_random_powerup_type( - forcetype=poweruptype, excludetypes=self._excluded_powerups - ) - PowerupBox( - position=self.map.powerup_spawn_points[index], - poweruptype=poweruptype, - ).autoretain() - - def _start_powerup_drops(self) -> None: - self._powerup_drop_timer = bs.Timer( - 3.0, bs.WeakCall(self._drop_powerups), repeat=True - ) - - def _drop_powerups( - self, standard_points: bool = False, poweruptype: str | None = None - ) -> None: - """Generic powerup drop.""" - if standard_points: - points = self.map.powerup_spawn_points - for i in range(len(points)): - bs.timer( - 1.0 + i * 0.5, - bs.WeakCall( - self._drop_powerup, i, poweruptype if i == 0 else None - ), - ) - else: - point = ( - self._powerup_center[0] - + random.uniform( - -1.0 * self._powerup_spread[0], - 1.0 * self._powerup_spread[0], - ), - self._powerup_center[1], - self._powerup_center[2] - + random.uniform( - -self._powerup_spread[1], self._powerup_spread[1] - ), - ) - - # Drop one random one somewhere. - PowerupBox( - position=point, - poweruptype=PowerupBoxFactory.get().get_random_powerup_type( - excludetypes=self._excluded_powerups - ), - ).autoretain() - - def do_end(self, outcome: str, delay: float = 0.0) -> None: - """End the game with the specified outcome.""" - if outcome == 'defeat': - self.fade_to_red() - score: int | None - if self._wavenum >= 2: - score = self._score - fail_message = None - else: - score = None - fail_message = babase.Lstr(resource='reachWave2Text') - self.end( - { - 'outcome': outcome, - 'score': score, - 'fail_message': fail_message, - 'playerinfos': self.initialplayerinfos, - }, - delay=delay, - ) - - def _update_waves(self) -> None: - - # If we have no living bots, go to the next wave. - assert self._bots is not None - if ( - self._can_end_wave - and not self._bots.have_living_bots() - and not self._game_over - ): - self._can_end_wave = False - self._time_bonus_timer = None - self._time_bonus_text = None - base_delay = 0.0 - - # Reward time bonus. - if self._time_bonus > 0: - bs.timer(0, babase.Call(self._cashregistersound.play)) - bs.timer( - base_delay, - bs.WeakCall(self._award_time_bonus, self._time_bonus), - ) - base_delay += 1.0 - - # Reward flawless bonus. - if self._wavenum > 0: - have_flawless = False - for player in self.players: - if player.is_alive() and not player.has_been_hurt: - have_flawless = True - bs.timer( - base_delay, - bs.WeakCall(self._award_flawless_bonus, player), - ) - player.has_been_hurt = False # reset - if have_flawless: - base_delay += 1.0 - - self._wavenum += 1 - - # Short celebration after waves. - if self._wavenum > 1: - self.celebrate(0.5) - bs.timer(base_delay, bs.WeakCall(self._start_next_wave)) - - def _award_completion_bonus(self) -> None: - self._cashregistersound.play() - for player in self.players: - try: - if player.is_alive(): - assert self.initialplayerinfos is not None - self.stats.player_scored( - player, - int(100 / len(self.initialplayerinfos)), - scale=1.4, - color=(0.6, 0.6, 1.0, 1.0), - title=babase.Lstr(resource='completionBonusText'), - screenmessage=False, - ) - except Exception: - babase.print_exception() - - def _award_time_bonus(self, bonus: int) -> None: - self._cashregistersound.play() - PopupText( - babase.Lstr( - value='+${A} ${B}', - subs=[ - ('${A}', str(bonus)), - ('${B}', babase.Lstr(resource='timeBonusText')), - ], - ), - color=(1, 1, 0.5, 1), - scale=1.0, - position=(0, 3, -1), - ).autoretain() - self._score += self._time_bonus - self._update_scores() - - def _award_flawless_bonus(self, player: Player) -> None: - self._cashregistersound.play() - try: - if player.is_alive(): - assert self._flawless_bonus is not None - self.stats.player_scored( - player, - self._flawless_bonus, - scale=1.2, - color=(0.6, 1.0, 0.6, 1.0), - title=babase.Lstr(resource='flawlessWaveText'), - screenmessage=False, - ) - except Exception: - babase.print_exception() - - def _start_time_bonus_timer(self) -> None: - self._time_bonus_timer = bs.Timer( - 1.0, bs.WeakCall(self._update_time_bonus), repeat=True - ) - - def _update_player_spawn_info(self) -> None: - - # If we have no living players lets just blank this. - assert self._spawn_info_text is not None - assert self._spawn_info_text.node - if not any(player.is_alive() for player in self.teams[0].players): - self._spawn_info_text.node.text = '' - else: - text: str | babase.Lstr = '' - for player in self.players: - if not player.is_alive(): - rtxt = babase.Lstr( - resource='onslaughtRespawnText', - subs=[ - ('${PLAYER}', player.getname()), - ('${WAVE}', str(player.respawn_wave)), - ], - ) - text = babase.Lstr( - value='${A}${B}\n', - subs=[ - ('${A}', text), - ('${B}', rtxt), - ], - ) - self._spawn_info_text.node.text = text - - def _respawn_players_for_wave(self) -> None: - # Respawn applicable players. - if self._wavenum > 1 and not self.is_waiting_for_continue(): - for player in self.players: - if ( - not player.is_alive() - and player.respawn_wave == self._wavenum - ): - self.spawn_player(player) - self._update_player_spawn_info() - - def _setup_wave_spawns(self, wave: Wave) -> None: - tval = 0.0 - dtime = 0.2 - if self._wavenum == 1: - spawn_time = 3.973 - tval += 0.5 - else: - spawn_time = 2.648 - - bot_angle = wave.base_angle - self._time_bonus = 0 - self._flawless_bonus = 0 - for info in wave.entries: - if info is None: - continue - if isinstance(info, Delay): - spawn_time += info.duration - continue - if isinstance(info, Spacing): - bot_angle += info.spacing - continue - bot_type_2 = info.bottype - if bot_type_2 is not None: - assert not isinstance(bot_type_2, str) - self._time_bonus += bot_type_2.points_mult * 20 - self._flawless_bonus += bot_type_2.points_mult * 5 - - if self.map.name == 'Doom Shroom': - tval += dtime - spacing = info.spacing - bot_angle += spacing * 0.5 - if bot_type_2 is not None: - tcall = bs.WeakCall( - self.add_bot_at_angle, bot_angle, bot_type_2, spawn_time - ) - bs.timer(tval, tcall) - tval += dtime - bot_angle += spacing * 0.5 - else: - assert bot_type_2 is not None - spcall = bs.WeakCall( - self.add_bot_at_point, bot_type_2, spawn_time - ) - bs.timer(tval, spcall) - - # We can end the wave after all the spawning happens. - bs.timer( - tval + spawn_time - dtime + 0.01, - bs.WeakCall(self._set_can_end_wave), - ) - - def _start_next_wave(self) -> None: - - # This can happen if we beat a wave as we die. - # We don't wanna respawn players and whatnot if this happens. - if self._game_over: - return - - self._respawn_players_for_wave() - wave = self._generate_random_wave() - self._setup_wave_spawns(wave) - self._update_wave_ui_and_bonuses() - bs.timer(0.4, babase.Call(self._new_wave_sound.play)) - - def _update_wave_ui_and_bonuses(self) -> None: - self.show_zoom_message( - babase.Lstr( - value='${A} ${B}', - subs=[ - ('${A}', babase.Lstr(resource='waveText')), - ('${B}', str(self._wavenum)), - ], - ), - scale=1.0, - duration=1.0, - trail=True, - ) - - # Reset our time bonus. - tbtcolor = (1, 1, 0, 1) - tbttxt = babase.Lstr( - value='${A}: ${B}', - subs=[ - ('${A}', babase.Lstr(resource='timeBonusText')), - ('${B}', str(self._time_bonus)), - ], - ) - self._time_bonus_text = bs.NodeActor( - bs.newnode( - 'text', - attrs={ - 'v_attach': 'top', - 'h_attach': 'center', - 'h_align': 'center', - 'vr_depth': -30, - 'color': tbtcolor, - 'shadow': 1.0, - 'flatness': 1.0, - 'position': (0, -60), - 'scale': 0.8, - 'text': tbttxt, - }, - ) - ) - - bs.timer(5.0, bs.WeakCall(self._start_time_bonus_timer)) - wtcolor = (1, 1, 1, 1) - wttxt = babase.Lstr( - value='${A} ${B}', - subs=[ - ('${A}', babase.Lstr(resource='waveText')), - ('${B}', str(self._wavenum) + ('')), - ], - ) - self._wave_text = bs.NodeActor( - bs.newnode( - 'text', - attrs={ - 'v_attach': 'top', - 'h_attach': 'center', - 'h_align': 'center', - 'vr_depth': -10, - 'color': wtcolor, - 'shadow': 1.0, - 'flatness': 1.0, - 'position': (0, -40), - 'scale': 1.3, - 'text': wttxt, - }, - ) - ) - - def _bot_levels_for_wave(self) -> list[list[type[SpazBot]]]: - level = self._wavenum - bot_types = [ - BomberBot, - BrawlerBot, - TriggerBot, - ChargerBot, - BomberBotPro, - BrawlerBotPro, - TriggerBotPro, - BomberBotProShielded, - ExplodeyBot, - ChargerBotProShielded, - StickyBot, - BrawlerBotProShielded, - TriggerBotProShielded, - ] - if level > 5: - bot_types += [ - ExplodeyBot, - TriggerBotProShielded, - BrawlerBotProShielded, - ChargerBotProShielded, - ] - if level > 7: - bot_types += [ - ExplodeyBot, - TriggerBotProShielded, - BrawlerBotProShielded, - ChargerBotProShielded, - ] - if level > 10: - bot_types += [ - TriggerBotProShielded, - TriggerBotProShielded, - TriggerBotProShielded, - TriggerBotProShielded, - ] - if level > 13: - bot_types += [ - TriggerBotProShielded, - TriggerBotProShielded, - TriggerBotProShielded, - TriggerBotProShielded, - ] - bot_levels = [ - [b for b in bot_types if b.points_mult == 1], - [b for b in bot_types if b.points_mult == 2], - [b for b in bot_types if b.points_mult == 3], - [b for b in bot_types if b.points_mult == 4], - ] - - # Make sure all lists have something in them - if not all(bot_levels): - raise RuntimeError('Got empty bot level') - return bot_levels - - def _add_entries_for_distribution_group( - self, - group: list[tuple[int, int]], - bot_levels: list[list[type[SpazBot]]], - all_entries: list[Spawn | Spacing | Delay | None], - ) -> None: - entries: list[Spawn | Spacing | Delay | None] = [] - for entry in group: - bot_level = bot_levels[entry[0] - 1] - bot_type = bot_level[random.randrange(len(bot_level))] - rval = random.random() - if rval < 0.5: - spacing = 10.0 - elif rval < 0.9: - spacing = 20.0 - else: - spacing = 40.0 - split = random.random() > 0.3 - for i in range(entry[1]): - if split and i % 2 == 0: - entries.insert(0, Spawn(bot_type, spacing=spacing)) - else: - entries.append(Spawn(bot_type, spacing=spacing)) - if entries: - all_entries += entries - all_entries.append(Spacing(40.0 if random.random() < 0.5 else 80.0)) - - def _generate_random_wave(self) -> Wave: - level = self._wavenum - bot_levels = self._bot_levels_for_wave() - - target_points = level * 3 - 2 - min_dudes = min(1 + level // 3, 10) - max_dudes = min(10, level + 1) - max_level = ( - 4 if level > 6 else (3 if level > 3 else (2 if level > 2 else 1)) - ) - group_count = 3 - distribution = self._get_distribution( - target_points, min_dudes, max_dudes, group_count, max_level - ) - all_entries: list[Spawn | Spacing | Delay | None] = [] - for group in distribution: - self._add_entries_for_distribution_group( - group, bot_levels, all_entries - ) - angle_rand = random.random() - if angle_rand > 0.75: - base_angle = 130.0 - elif angle_rand > 0.5: - base_angle = 210.0 - elif angle_rand > 0.25: - base_angle = 20.0 - else: - base_angle = -30.0 - base_angle += (0.5 - random.random()) * 20.0 - wave = Wave(base_angle=base_angle, entries=all_entries) - return wave - - def add_bot_at_point( - self, spaz_type: type[SpazBot], spawn_time: float = 1.0 - ) -> None: - """Add a new bot at a specified named point.""" - if self._game_over: - return - def _getpt() -> Sequence[float]: - point = self.map.get_def_points( - 'ffa_spawn')[self._next_ffa_start_index] - self._next_ffa_start_index = ( - self._next_ffa_start_index + 1) % len( - self.map.get_def_points('ffa_spawn') - ) - x_range = (-0.5, 0.5) if point[3] == 0.0 else (-point[3], point[3]) - z_range = (-0.5, 0.5) if point[5] == 0.0 else (-point[5], point[5]) - point = ( - point[0] + random.uniform(*x_range), - point[1], - point[2] + random.uniform(*z_range), - ) - return point - pointpos = _getpt() - - assert self._bots is not None - self._bots.spawn_bot(spaz_type, pos=pointpos, spawn_time=spawn_time) - - def add_bot_at_angle( - self, angle: float, spaz_type: type[SpazBot], spawn_time: float = 1.0 - ) -> None: - """Add a new bot at a specified angle (for circular maps).""" - if self._game_over: - return - angle_radians = angle / 57.2957795 - xval = math.sin(angle_radians) * 1.06 - zval = math.cos(angle_radians) * 1.06 - point = (xval / 0.125, 2.3, (zval / 0.2) - 3.7) - assert self._bots is not None - self._bots.spawn_bot(spaz_type, pos=point, spawn_time=spawn_time) - - def _update_time_bonus(self) -> None: - self._time_bonus = int(self._time_bonus * 0.93) - if self._time_bonus > 0 and self._time_bonus_text is not None: - assert self._time_bonus_text.node - self._time_bonus_text.node.text = babase.Lstr( - value='${A}: ${B}', - subs=[ - ('${A}', babase.Lstr(resource='timeBonusText')), - ('${B}', str(self._time_bonus)), - ], - ) - else: - self._time_bonus_text = None - - def _start_updating_waves(self) -> None: - self._wave_update_timer = bs.Timer( - 2.0, bs.WeakCall(self._update_waves), repeat=True - ) - - def _update_scores(self) -> None: - score = self._score - assert self._scoreboard is not None - self._scoreboard.set_team_value(self.teams[0], score, max_score=None) - - def handlemessage(self, msg: Any) -> Any: - - if isinstance(msg, PlayerSpazHurtMessage): - msg.spaz.getplayer(Player, True).has_been_hurt = True - self._a_player_has_been_hurt = True - - elif isinstance(msg, bs.PlayerScoredMessage): - self._score += msg.score - self._update_scores() - - elif isinstance(msg, bs.PlayerDiedMessage): - super().handlemessage(msg) # Augment standard behavior. - player = msg.getplayer(Player) - self._a_player_has_been_hurt = True - - # Make note with the player when they can respawn: - if self._wavenum < 10: - player.respawn_wave = max(2, self._wavenum + 1) - elif self._wavenum < 15: - player.respawn_wave = max(2, self._wavenum + 2) - else: - player.respawn_wave = max(2, self._wavenum + 3) - bs.timer(0.1, self._update_player_spawn_info) - bs.timer(0.1, self._checkroundover) - - elif isinstance(msg, SpazBotDiedMessage): - pts, importance = msg.spazbot.get_death_points(msg.how) - if msg.killerplayer is not None: - target: Sequence[float] | None - if msg.spazbot.node: - target = msg.spazbot.node.position - else: - target = None - - killerplayer = msg.killerplayer - self.stats.player_scored( - killerplayer, - pts, - target=target, - kill=True, - screenmessage=False, - importance=importance, - ) - self._dingsound.play(volume=0.6) if importance == 1 else self._dingsoundhigh.play(volume=0.6) - - # Normally we pull scores from the score-set, but if there's - # no player lets be explicit. - else: - self._score += pts - self._update_scores() - else: - super().handlemessage(msg) - - def _handle_uber_kill_achievements(self, msg: SpazBotDiedMessage) -> None: - - # Uber mine achievement: - if msg.spazbot.last_attacked_type == ('explosion', 'land_mine'): - self._land_mine_kills += 1 - if self._land_mine_kills >= 6: - self._award_achievement('Gold Miner') - - # Uber tnt achievement: - if msg.spazbot.last_attacked_type == ('explosion', 'tnt'): - self._tnt_kills += 1 - if self._tnt_kills >= 6: - bs.timer( - 0.5, bs.WeakCall(self._award_achievement, 'TNT Terror') - ) - - def _handle_pro_kill_achievements(self, msg: SpazBotDiedMessage) -> None: - - # TNT achievement: - if msg.spazbot.last_attacked_type == ('explosion', 'tnt'): - self._tnt_kills += 1 - if self._tnt_kills >= 3: - bs.timer( - 0.5, - bs.WeakCall( - self._award_achievement, 'Boom Goes the Dynamite' - ), - ) - - def _handle_rookie_kill_achievements(self, msg: SpazBotDiedMessage) -> None: - # Land-mine achievement: - if msg.spazbot.last_attacked_type == ('explosion', 'land_mine'): - self._land_mine_kills += 1 - if self._land_mine_kills >= 3: - self._award_achievement('Mine Games') - - def _handle_training_kill_achievements( - self, msg: SpazBotDiedMessage - ) -> None: - # Toss-off-map achievement: - if msg.spazbot.last_attacked_type == ('picked_up', 'default'): - self._throw_off_kills += 1 - if self._throw_off_kills >= 3: - self._award_achievement('Off You Go Then') - - def _set_can_end_wave(self) -> None: - self._can_end_wave = True - - def end_game(self) -> None: - # Tell our bots to celebrate just to rub it in. - assert self._bots is not None - self._bots.final_celebrate() - self._game_over = True - self.do_end('defeat', delay=2.0) - bs.setmusic(None) - - def on_continue(self) -> None: - for player in self.players: - if not player.is_alive(): - self.spawn_player(player) - - def _checkroundover(self) -> None: - """Potentially end the round based on the state of the game.""" - if self.has_ended(): - return - if not any(player.is_alive() for player in self.teams[0].players): - # Allow continuing after wave 1. - if self._wavenum > 1: - self.continue_or_end_game() - else: - self.end_game() + """Co-op game where players try to survive attacking waves of enemies.""" + + name = 'Onslaught' + description = 'Defeat all enemies.' + + tips: list[str | babase.GameTip] = [ + 'Hold any button to run.' + ' (Trigger buttons work well if you have them)', + 'Try tricking enemies into killing eachother or running off cliffs.', + 'Try \'Cooking off\' bombs for a second or two before throwing them.', + 'It\'s easier to win with a friend or two helping.', + 'If you stay in one place, you\'re toast. Run and dodge to survive..', + 'Practice using your momentum to throw bombs more accurately.', + 'Your punches do much more damage if you are running or spinning.', + ] + + # Show messages when players die since it matters here. + announce_player_deaths = True + + def __init__(self, settings: dict): + super().__init__(settings) + self._new_wave_sound = bs.getsound('scoreHit01') + self._winsound = bs.getsound('score') + self._cashregistersound = bs.getsound('cashRegister') + self._a_player_has_been_hurt = False + self._player_has_dropped_bomb = False + self._spawn_center = (0, 0.2, 0) + self._tntspawnpos = (0, 0.95, -0.77) + self._powerup_center = (0, 1.5, 0) + self._powerup_spread = (6.0, 4.0) + self._scoreboard: Scoreboard | None = None + self._game_over = False + self._wavenum = 0 + self._can_end_wave = True + self._score = 0 + self._time_bonus = 0 + self._spawn_info_text: bs.NodeActor | None = None + self._dingsound = bs.getsound('dingSmall') + self._dingsoundhigh = bs.getsound('dingSmallHigh') + self._have_tnt = False + self._excluded_powerups: list[str] | None = None + self._waves: list[Wave] = [] + self._tntspawner: TNTSpawner | None = None + self._bots: SpazBotSet | None = None + self._powerup_drop_timer: bs.Timer | None = None + self._time_bonus_timer: bs.Timer | None = None + self._time_bonus_text: bs.NodeActor | None = None + self._flawless_bonus: int | None = None + self._wave_text: bs.NodeActor | None = None + self._wave_update_timer: bs.Timer | None = None + self._throw_off_kills = 0 + self._land_mine_kills = 0 + self._tnt_kills = 0 + + self._epic_mode = bool(settings['Epic Mode']) + # Base class overrides. + self.slow_motion = self._epic_mode + self.default_music = ( + bs.MusicType.EPIC if self._epic_mode else bs.MusicType.ONSLAUGHT + ) + + def on_transition_in(self) -> None: + super().on_transition_in() + self._spawn_info_text = bs.NodeActor( + bs.newnode( + 'text', + attrs={ + 'position': (15, -130), + 'h_attach': 'left', + 'v_attach': 'top', + 'scale': 0.55, + 'color': (0.3, 0.8, 0.3, 1.0), + 'text': '', + }, + ) + ) + self._scoreboard = Scoreboard( + label=babase.Lstr(resource='scoreText'), score_split=0.5 + ) + + def on_begin(self) -> None: + super().on_begin() + self._have_tnt = True + self._excluded_powerups = [] + self._waves = [] + bs.timer(4.0, self._start_powerup_drops) + + # Our TNT spawner (if applicable). + if self._have_tnt: + self._tntspawner = TNTSpawner(position=self._tntspawnpos) + + self.setup_low_life_warning_sound() + self._update_scores() + self._bots = SpazBotSet() + bs.timer(4.0, self._start_updating_waves) + self._next_ffa_start_index = random.randrange( + len(self.map.get_def_points('ffa_spawn')) + ) + + def _get_dist_grp_totals(self, grps: list[Any]) -> tuple[int, int]: + totalpts = 0 + totaldudes = 0 + for grp in grps: + for grpentry in grp: + dudes = grpentry[1] + totalpts += grpentry[0] * dudes + totaldudes += dudes + return totalpts, totaldudes + + def _get_distribution( + self, + target_points: int, + min_dudes: int, + max_dudes: int, + group_count: int, + max_level: int, + ) -> list[list[tuple[int, int]]]: + """Calculate a distribution of bad guys given some params.""" + max_iterations = 10 + max_dudes * 2 + + groups: list[list[tuple[int, int]]] = [] + for _g in range(group_count): + groups.append([]) + types = [1] + if max_level > 1: + types.append(2) + if max_level > 2: + types.append(3) + if max_level > 3: + types.append(4) + for iteration in range(max_iterations): + diff = self._add_dist_entry_if_possible( + groups, max_dudes, target_points, types + ) + + total_points, total_dudes = self._get_dist_grp_totals(groups) + full = total_points >= target_points + + if full: + # Every so often, delete a random entry just to + # shake up our distribution. + if random.random() < 0.2 and iteration != max_iterations - 1: + self._delete_random_dist_entry(groups) + + # If we don't have enough dudes, kill the group with + # the biggest point value. + elif ( + total_dudes < min_dudes and iteration != max_iterations - 1 + ): + self._delete_biggest_dist_entry(groups) + + # If we've got too many dudes, kill the group with the + # smallest point value. + elif ( + total_dudes > max_dudes and iteration != max_iterations - 1 + ): + self._delete_smallest_dist_entry(groups) + + # Close enough.. we're done. + else: + if diff == 0: + break + + return groups + + def _add_dist_entry_if_possible( + self, + groups: list[list[tuple[int, int]]], + max_dudes: int, + target_points: int, + types: list[int], + ) -> int: + # See how much we're off our target by. + total_points, total_dudes = self._get_dist_grp_totals(groups) + diff = target_points - total_points + dudes_diff = max_dudes - total_dudes + + # Add an entry if one will fit. + value = types[random.randrange(len(types))] + group = groups[random.randrange(len(groups))] + if not group: + max_count = random.randint(1, 6) + else: + max_count = 2 * random.randint(1, 3) + max_count = min(max_count, dudes_diff) + count = min(max_count, diff // value) + if count > 0: + group.append((value, count)) + total_points += value * count + total_dudes += count + diff = target_points - total_points + return diff + + def _delete_smallest_dist_entry( + self, groups: list[list[tuple[int, int]]] + ) -> None: + smallest_value = 9999 + smallest_entry = None + smallest_entry_group = None + for group in groups: + for entry in group: + if entry[0] < smallest_value or smallest_entry is None: + smallest_value = entry[0] + smallest_entry = entry + smallest_entry_group = group + assert smallest_entry is not None + assert smallest_entry_group is not None + smallest_entry_group.remove(smallest_entry) + + def _delete_biggest_dist_entry( + self, groups: list[list[tuple[int, int]]] + ) -> None: + biggest_value = 9999 + biggest_entry = None + biggest_entry_group = None + for group in groups: + for entry in group: + if entry[0] > biggest_value or biggest_entry is None: + biggest_value = entry[0] + biggest_entry = entry + biggest_entry_group = group + if biggest_entry is not None: + assert biggest_entry_group is not None + biggest_entry_group.remove(biggest_entry) + + def _delete_random_dist_entry( + self, groups: list[list[tuple[int, int]]] + ) -> None: + entry_count = 0 + for group in groups: + for _ in group: + entry_count += 1 + if entry_count > 1: + del_entry = random.randrange(entry_count) + entry_count = 0 + for group in groups: + for entry in group: + if entry_count == del_entry: + group.remove(entry) + break + entry_count += 1 + + def spawn_player(self, player: Player) -> bs.Actor: + + # We keep track of who got hurt each wave for score purposes. + player.has_been_hurt = False + pos = ( + self._spawn_center[0] + random.uniform(-1.5, 1.5), + self._spawn_center[1], + self._spawn_center[2] + random.uniform(-1.5, 1.5), + ) + spaz = self.spawn_player_spaz(player, position=pos) + spaz.add_dropped_bomb_callback(self._handle_player_dropped_bomb) + return spaz + + def _handle_player_dropped_bomb( + self, player: bs.Actor, bomb: bs.Actor + ) -> None: + del player, bomb # Unused. + self._player_has_dropped_bomb = True + + def _drop_powerup(self, index: int, poweruptype: str | None = None) -> None: + poweruptype = PowerupBoxFactory.get().get_random_powerup_type( + forcetype=poweruptype, excludetypes=self._excluded_powerups + ) + PowerupBox( + position=self.map.powerup_spawn_points[index], + poweruptype=poweruptype, + ).autoretain() + + def _start_powerup_drops(self) -> None: + self._powerup_drop_timer = bs.Timer( + 3.0, bs.WeakCall(self._drop_powerups), repeat=True + ) + + def _drop_powerups( + self, standard_points: bool = False, poweruptype: str | None = None + ) -> None: + """Generic powerup drop.""" + if standard_points: + points = self.map.powerup_spawn_points + for i in range(len(points)): + bs.timer( + 1.0 + i * 0.5, + bs.WeakCall( + self._drop_powerup, i, poweruptype if i == 0 else None + ), + ) + else: + point = ( + self._powerup_center[0] + + random.uniform( + -1.0 * self._powerup_spread[0], + 1.0 * self._powerup_spread[0], + ), + self._powerup_center[1], + self._powerup_center[2] + + random.uniform( + -self._powerup_spread[1], self._powerup_spread[1] + ), + ) + + # Drop one random one somewhere. + PowerupBox( + position=point, + poweruptype=PowerupBoxFactory.get().get_random_powerup_type( + excludetypes=self._excluded_powerups + ), + ).autoretain() + + def do_end(self, outcome: str, delay: float = 0.0) -> None: + """End the game with the specified outcome.""" + if outcome == 'defeat': + self.fade_to_red() + score: int | None + if self._wavenum >= 2: + score = self._score + fail_message = None + else: + score = None + fail_message = babase.Lstr(resource='reachWave2Text') + self.end( + { + 'outcome': outcome, + 'score': score, + 'fail_message': fail_message, + 'playerinfos': self.initialplayerinfos, + }, + delay=delay, + ) + + def _update_waves(self) -> None: + + # If we have no living bots, go to the next wave. + assert self._bots is not None + if ( + self._can_end_wave + and not self._bots.have_living_bots() + and not self._game_over + ): + self._can_end_wave = False + self._time_bonus_timer = None + self._time_bonus_text = None + base_delay = 0.0 + + # Reward time bonus. + if self._time_bonus > 0: + bs.timer(0, babase.Call(self._cashregistersound.play)) + bs.timer( + base_delay, + bs.WeakCall(self._award_time_bonus, self._time_bonus), + ) + base_delay += 1.0 + + # Reward flawless bonus. + if self._wavenum > 0: + have_flawless = False + for player in self.players: + if player.is_alive() and not player.has_been_hurt: + have_flawless = True + bs.timer( + base_delay, + bs.WeakCall(self._award_flawless_bonus, player), + ) + player.has_been_hurt = False # reset + if have_flawless: + base_delay += 1.0 + + self._wavenum += 1 + + # Short celebration after waves. + if self._wavenum > 1: + self.celebrate(0.5) + bs.timer(base_delay, bs.WeakCall(self._start_next_wave)) + + def _award_completion_bonus(self) -> None: + self._cashregistersound.play() + for player in self.players: + try: + if player.is_alive(): + assert self.initialplayerinfos is not None + self.stats.player_scored( + player, + int(100 / len(self.initialplayerinfos)), + scale=1.4, + color=(0.6, 0.6, 1.0, 1.0), + title=babase.Lstr(resource='completionBonusText'), + screenmessage=False, + ) + except Exception: + babase.print_exception() + + def _award_time_bonus(self, bonus: int) -> None: + self._cashregistersound.play() + PopupText( + babase.Lstr( + value='+${A} ${B}', + subs=[ + ('${A}', str(bonus)), + ('${B}', babase.Lstr(resource='timeBonusText')), + ], + ), + color=(1, 1, 0.5, 1), + scale=1.0, + position=(0, 3, -1), + ).autoretain() + self._score += self._time_bonus + self._update_scores() + + def _award_flawless_bonus(self, player: Player) -> None: + self._cashregistersound.play() + try: + if player.is_alive(): + assert self._flawless_bonus is not None + self.stats.player_scored( + player, + self._flawless_bonus, + scale=1.2, + color=(0.6, 1.0, 0.6, 1.0), + title=babase.Lstr(resource='flawlessWaveText'), + screenmessage=False, + ) + except Exception: + babase.print_exception() + + def _start_time_bonus_timer(self) -> None: + self._time_bonus_timer = bs.Timer( + 1.0, bs.WeakCall(self._update_time_bonus), repeat=True + ) + + def _update_player_spawn_info(self) -> None: + + # If we have no living players lets just blank this. + assert self._spawn_info_text is not None + assert self._spawn_info_text.node + if not any(player.is_alive() for player in self.teams[0].players): + self._spawn_info_text.node.text = '' + else: + text: str | babase.Lstr = '' + for player in self.players: + if not player.is_alive(): + rtxt = babase.Lstr( + resource='onslaughtRespawnText', + subs=[ + ('${PLAYER}', player.getname()), + ('${WAVE}', str(player.respawn_wave)), + ], + ) + text = babase.Lstr( + value='${A}${B}\n', + subs=[ + ('${A}', text), + ('${B}', rtxt), + ], + ) + self._spawn_info_text.node.text = text + + def _respawn_players_for_wave(self) -> None: + # Respawn applicable players. + if self._wavenum > 1 and not self.is_waiting_for_continue(): + for player in self.players: + if ( + not player.is_alive() + and player.respawn_wave == self._wavenum + ): + self.spawn_player(player) + self._update_player_spawn_info() + + def _setup_wave_spawns(self, wave: Wave) -> None: + tval = 0.0 + dtime = 0.2 + if self._wavenum == 1: + spawn_time = 3.973 + tval += 0.5 + else: + spawn_time = 2.648 + + bot_angle = wave.base_angle + self._time_bonus = 0 + self._flawless_bonus = 0 + for info in wave.entries: + if info is None: + continue + if isinstance(info, Delay): + spawn_time += info.duration + continue + if isinstance(info, Spacing): + bot_angle += info.spacing + continue + bot_type_2 = info.bottype + if bot_type_2 is not None: + assert not isinstance(bot_type_2, str) + self._time_bonus += bot_type_2.points_mult * 20 + self._flawless_bonus += bot_type_2.points_mult * 5 + + if self.map.name == 'Doom Shroom': + tval += dtime + spacing = info.spacing + bot_angle += spacing * 0.5 + if bot_type_2 is not None: + tcall = bs.WeakCall( + self.add_bot_at_angle, bot_angle, bot_type_2, spawn_time + ) + bs.timer(tval, tcall) + tval += dtime + bot_angle += spacing * 0.5 + else: + assert bot_type_2 is not None + spcall = bs.WeakCall( + self.add_bot_at_point, bot_type_2, spawn_time + ) + bs.timer(tval, spcall) + + # We can end the wave after all the spawning happens. + bs.timer( + tval + spawn_time - dtime + 0.01, + bs.WeakCall(self._set_can_end_wave), + ) + + def _start_next_wave(self) -> None: + + # This can happen if we beat a wave as we die. + # We don't wanna respawn players and whatnot if this happens. + if self._game_over: + return + + self._respawn_players_for_wave() + wave = self._generate_random_wave() + self._setup_wave_spawns(wave) + self._update_wave_ui_and_bonuses() + bs.timer(0.4, babase.Call(self._new_wave_sound.play)) + + def _update_wave_ui_and_bonuses(self) -> None: + self.show_zoom_message( + babase.Lstr( + value='${A} ${B}', + subs=[ + ('${A}', babase.Lstr(resource='waveText')), + ('${B}', str(self._wavenum)), + ], + ), + scale=1.0, + duration=1.0, + trail=True, + ) + + # Reset our time bonus. + tbtcolor = (1, 1, 0, 1) + tbttxt = babase.Lstr( + value='${A}: ${B}', + subs=[ + ('${A}', babase.Lstr(resource='timeBonusText')), + ('${B}', str(self._time_bonus)), + ], + ) + self._time_bonus_text = bs.NodeActor( + bs.newnode( + 'text', + attrs={ + 'v_attach': 'top', + 'h_attach': 'center', + 'h_align': 'center', + 'vr_depth': -30, + 'color': tbtcolor, + 'shadow': 1.0, + 'flatness': 1.0, + 'position': (0, -60), + 'scale': 0.8, + 'text': tbttxt, + }, + ) + ) + + bs.timer(5.0, bs.WeakCall(self._start_time_bonus_timer)) + wtcolor = (1, 1, 1, 1) + wttxt = babase.Lstr( + value='${A} ${B}', + subs=[ + ('${A}', babase.Lstr(resource='waveText')), + ('${B}', str(self._wavenum) + ('')), + ], + ) + self._wave_text = bs.NodeActor( + bs.newnode( + 'text', + attrs={ + 'v_attach': 'top', + 'h_attach': 'center', + 'h_align': 'center', + 'vr_depth': -10, + 'color': wtcolor, + 'shadow': 1.0, + 'flatness': 1.0, + 'position': (0, -40), + 'scale': 1.3, + 'text': wttxt, + }, + ) + ) + + def _bot_levels_for_wave(self) -> list[list[type[SpazBot]]]: + level = self._wavenum + bot_types = [ + BomberBot, + BrawlerBot, + TriggerBot, + ChargerBot, + BomberBotPro, + BrawlerBotPro, + TriggerBotPro, + BomberBotProShielded, + ExplodeyBot, + ChargerBotProShielded, + StickyBot, + BrawlerBotProShielded, + TriggerBotProShielded, + ] + if level > 5: + bot_types += [ + ExplodeyBot, + TriggerBotProShielded, + BrawlerBotProShielded, + ChargerBotProShielded, + ] + if level > 7: + bot_types += [ + ExplodeyBot, + TriggerBotProShielded, + BrawlerBotProShielded, + ChargerBotProShielded, + ] + if level > 10: + bot_types += [ + TriggerBotProShielded, + TriggerBotProShielded, + TriggerBotProShielded, + TriggerBotProShielded, + ] + if level > 13: + bot_types += [ + TriggerBotProShielded, + TriggerBotProShielded, + TriggerBotProShielded, + TriggerBotProShielded, + ] + bot_levels = [ + [b for b in bot_types if b.points_mult == 1], + [b for b in bot_types if b.points_mult == 2], + [b for b in bot_types if b.points_mult == 3], + [b for b in bot_types if b.points_mult == 4], + ] + + # Make sure all lists have something in them + if not all(bot_levels): + raise RuntimeError('Got empty bot level') + return bot_levels + + def _add_entries_for_distribution_group( + self, + group: list[tuple[int, int]], + bot_levels: list[list[type[SpazBot]]], + all_entries: list[Spawn | Spacing | Delay | None], + ) -> None: + entries: list[Spawn | Spacing | Delay | None] = [] + for entry in group: + bot_level = bot_levels[entry[0] - 1] + bot_type = bot_level[random.randrange(len(bot_level))] + rval = random.random() + if rval < 0.5: + spacing = 10.0 + elif rval < 0.9: + spacing = 20.0 + else: + spacing = 40.0 + split = random.random() > 0.3 + for i in range(entry[1]): + if split and i % 2 == 0: + entries.insert(0, Spawn(bot_type, spacing=spacing)) + else: + entries.append(Spawn(bot_type, spacing=spacing)) + if entries: + all_entries += entries + all_entries.append(Spacing(40.0 if random.random() < 0.5 else 80.0)) + + def _generate_random_wave(self) -> Wave: + level = self._wavenum + bot_levels = self._bot_levels_for_wave() + + target_points = level * 3 - 2 + min_dudes = min(1 + level // 3, 10) + max_dudes = min(10, level + 1) + max_level = ( + 4 if level > 6 else (3 if level > 3 else (2 if level > 2 else 1)) + ) + group_count = 3 + distribution = self._get_distribution( + target_points, min_dudes, max_dudes, group_count, max_level + ) + all_entries: list[Spawn | Spacing | Delay | None] = [] + for group in distribution: + self._add_entries_for_distribution_group( + group, bot_levels, all_entries + ) + angle_rand = random.random() + if angle_rand > 0.75: + base_angle = 130.0 + elif angle_rand > 0.5: + base_angle = 210.0 + elif angle_rand > 0.25: + base_angle = 20.0 + else: + base_angle = -30.0 + base_angle += (0.5 - random.random()) * 20.0 + wave = Wave(base_angle=base_angle, entries=all_entries) + return wave + + def add_bot_at_point( + self, spaz_type: type[SpazBot], spawn_time: float = 1.0 + ) -> None: + """Add a new bot at a specified named point.""" + if self._game_over: + return + + def _getpt() -> Sequence[float]: + point = self.map.get_def_points( + 'ffa_spawn')[self._next_ffa_start_index] + self._next_ffa_start_index = ( + self._next_ffa_start_index + 1) % len( + self.map.get_def_points('ffa_spawn') + ) + x_range = (-0.5, 0.5) if point[3] == 0.0 else (-point[3], point[3]) + z_range = (-0.5, 0.5) if point[5] == 0.0 else (-point[5], point[5]) + point = ( + point[0] + random.uniform(*x_range), + point[1], + point[2] + random.uniform(*z_range), + ) + return point + pointpos = _getpt() + + assert self._bots is not None + self._bots.spawn_bot(spaz_type, pos=pointpos, spawn_time=spawn_time) + + def add_bot_at_angle( + self, angle: float, spaz_type: type[SpazBot], spawn_time: float = 1.0 + ) -> None: + """Add a new bot at a specified angle (for circular maps).""" + if self._game_over: + return + angle_radians = angle / 57.2957795 + xval = math.sin(angle_radians) * 1.06 + zval = math.cos(angle_radians) * 1.06 + point = (xval / 0.125, 2.3, (zval / 0.2) - 3.7) + assert self._bots is not None + self._bots.spawn_bot(spaz_type, pos=point, spawn_time=spawn_time) + + def _update_time_bonus(self) -> None: + self._time_bonus = int(self._time_bonus * 0.93) + if self._time_bonus > 0 and self._time_bonus_text is not None: + assert self._time_bonus_text.node + self._time_bonus_text.node.text = babase.Lstr( + value='${A}: ${B}', + subs=[ + ('${A}', babase.Lstr(resource='timeBonusText')), + ('${B}', str(self._time_bonus)), + ], + ) + else: + self._time_bonus_text = None + + def _start_updating_waves(self) -> None: + self._wave_update_timer = bs.Timer( + 2.0, bs.WeakCall(self._update_waves), repeat=True + ) + + def _update_scores(self) -> None: + score = self._score + assert self._scoreboard is not None + self._scoreboard.set_team_value(self.teams[0], score, max_score=None) + + def handlemessage(self, msg: Any) -> Any: + + if isinstance(msg, PlayerSpazHurtMessage): + msg.spaz.getplayer(Player, True).has_been_hurt = True + self._a_player_has_been_hurt = True + + elif isinstance(msg, bs.PlayerScoredMessage): + self._score += msg.score + self._update_scores() + + elif isinstance(msg, bs.PlayerDiedMessage): + super().handlemessage(msg) # Augment standard behavior. + player = msg.getplayer(Player) + self._a_player_has_been_hurt = True + + # Make note with the player when they can respawn: + if self._wavenum < 10: + player.respawn_wave = max(2, self._wavenum + 1) + elif self._wavenum < 15: + player.respawn_wave = max(2, self._wavenum + 2) + else: + player.respawn_wave = max(2, self._wavenum + 3) + bs.timer(0.1, self._update_player_spawn_info) + bs.timer(0.1, self._checkroundover) + + elif isinstance(msg, SpazBotDiedMessage): + pts, importance = msg.spazbot.get_death_points(msg.how) + if msg.killerplayer is not None: + target: Sequence[float] | None + if msg.spazbot.node: + target = msg.spazbot.node.position + else: + target = None + + killerplayer = msg.killerplayer + self.stats.player_scored( + killerplayer, + pts, + target=target, + kill=True, + screenmessage=False, + importance=importance, + ) + self._dingsound.play( + volume=0.6) if importance == 1 else self._dingsoundhigh.play(volume=0.6) + + # Normally we pull scores from the score-set, but if there's + # no player lets be explicit. + else: + self._score += pts + self._update_scores() + else: + super().handlemessage(msg) + + def _handle_uber_kill_achievements(self, msg: SpazBotDiedMessage) -> None: + + # Uber mine achievement: + if msg.spazbot.last_attacked_type == ('explosion', 'land_mine'): + self._land_mine_kills += 1 + if self._land_mine_kills >= 6: + self._award_achievement('Gold Miner') + + # Uber tnt achievement: + if msg.spazbot.last_attacked_type == ('explosion', 'tnt'): + self._tnt_kills += 1 + if self._tnt_kills >= 6: + bs.timer( + 0.5, bs.WeakCall(self._award_achievement, 'TNT Terror') + ) + + def _handle_pro_kill_achievements(self, msg: SpazBotDiedMessage) -> None: + + # TNT achievement: + if msg.spazbot.last_attacked_type == ('explosion', 'tnt'): + self._tnt_kills += 1 + if self._tnt_kills >= 3: + bs.timer( + 0.5, + bs.WeakCall( + self._award_achievement, 'Boom Goes the Dynamite' + ), + ) + + def _handle_rookie_kill_achievements(self, msg: SpazBotDiedMessage) -> None: + # Land-mine achievement: + if msg.spazbot.last_attacked_type == ('explosion', 'land_mine'): + self._land_mine_kills += 1 + if self._land_mine_kills >= 3: + self._award_achievement('Mine Games') + + def _handle_training_kill_achievements( + self, msg: SpazBotDiedMessage + ) -> None: + # Toss-off-map achievement: + if msg.spazbot.last_attacked_type == ('picked_up', 'default'): + self._throw_off_kills += 1 + if self._throw_off_kills >= 3: + self._award_achievement('Off You Go Then') + + def _set_can_end_wave(self) -> None: + self._can_end_wave = True + + def end_game(self) -> None: + # Tell our bots to celebrate just to rub it in. + assert self._bots is not None + self._bots.final_celebrate() + self._game_over = True + self.do_end('defeat', delay=2.0) + bs.setmusic(None) + + def on_continue(self) -> None: + for player in self.players: + if not player.is_alive(): + self.spawn_player(player) + + def _checkroundover(self) -> None: + """Potentially end the round based on the state of the game.""" + if self.has_ended(): + return + if not any(player.is_alive() for player in self.teams[0].players): + # Allow continuing after wave 1. + if self._wavenum > 1: + self.continue_or_end_game() + else: + self.end_game() # ba_meta export plugin + + class CustomOnslaughtLevel(babase.Plugin): - def on_app_running(self) -> None: - babase.app.classic.add_coop_practice_level( - bs._level.Level( - 'Onslaught Football', - gametype=OnslaughtFootballGame, - settings={ - 'map': 'Football Stadium', - 'Epic Mode': False, - }, - preview_texture_name='footballStadiumPreview', - ) - ) - babase.app.classic.add_coop_practice_level( - bs._level.Level( - 'Onslaught Football Epic', - gametype=OnslaughtFootballGame, - settings={ - 'map': 'Football Stadium', - 'Epic Mode': True, - }, - preview_texture_name='footballStadiumPreview', - ) - ) + def on_app_running(self) -> None: + babase.app.classic.add_coop_practice_level( + bs._level.Level( + 'Onslaught Football', + gametype=OnslaughtFootballGame, + settings={ + 'map': 'Football Stadium', + 'Epic Mode': False, + }, + preview_texture_name='footballStadiumPreview', + ) + ) + babase.app.classic.add_coop_practice_level( + bs._level.Level( + 'Onslaught Football Epic', + gametype=OnslaughtFootballGame, + settings={ + 'map': 'Football Stadium', + 'Epic Mode': True, + }, + preview_texture_name='footballStadiumPreview', + ) + ) From 6c2125eaee4d511669aa143c3c56356aa173f9d2 Mon Sep 17 00:00:00 2001 From: brostosjoined Date: Fri, 26 Jan 2024 16:07:34 +0300 Subject: [PATCH 0838/1464] more --- plugins/minigames.json | 14 + plugins/minigames/bot_chase.py | 218 +++++++ plugins/utilities.json | 14 + plugins/utilities/ba_colors.py | 1018 ++++++++++++++++++++++++++++++++ 4 files changed, 1264 insertions(+) create mode 100644 plugins/minigames/bot_chase.py create mode 100644 plugins/utilities/ba_colors.py diff --git a/plugins/minigames.json b/plugins/minigames.json index 83855abc..65479f7c 100644 --- a/plugins/minigames.json +++ b/plugins/minigames.json @@ -1189,6 +1189,20 @@ "versions": { "1.0.0": null } + }, + "bot_chase": { + "description": "Try to survive from bots!", + "external_url": "", + "authors": [ + { + "name": "", + "email": "", + "discord": "" + } + ], + "versions": { + "1.0.0": null + } } } } \ No newline at end of file diff --git a/plugins/minigames/bot_chase.py b/plugins/minigames/bot_chase.py new file mode 100644 index 00000000..b9d2fe49 --- /dev/null +++ b/plugins/minigames/bot_chase.py @@ -0,0 +1,218 @@ +# Ported to api 8 by brostos using baport.(https://github.com/bombsquad-community/baport) +# ba_meta require api 8 +from __future__ import annotations +from typing import TYPE_CHECKING + +import babase +import bauiv1 as bui +import bascenev1 as bs +import random +from bascenev1lib.actor.spazbot import BrawlerBot, SpazBotSet, SpazBot, SpazBotDiedMessage +from bascenev1lib.actor.bomb import Bomb +from bascenev1lib.actor.spaz import Spaz +from bascenev1lib.actor.onscreentimer import OnScreenTimer + +if TYPE_CHECKING: + from typing import Any, List, Type, Optional + + +# def ba_get_api_version(): +# return 6 + +def ba_get_levels(): + return [babase._level.Level( + 'Bot Chase',gametype=BotChaseGame, + settings={}, + preview_texture_name = 'footballStadiumPreview')] + + +class Player(bs.Player['Team']): + """Our player type for this game""" + + def __init__(self) -> None: + super().__init__() + self.death_time: Optional[float] = None + + +class MrSpazBot(SpazBot): + """Our bot type for this game""" + character = 'Spaz' + run = True + charge_dist_min = 10.0 + charge_dist_max = 9999.0 + charge_speed_min = 1.0 + charge_speed_max = 1.0 + throw_dist_min = 9999 + throw_dist_max = 9999 + + +class Team(bs.Team[Player]): + """Our team type for this minigame""" + + +# ba_meta export bascenev1.GameActivity +class BotChaseGame(bs.TeamGameActivity[Player, Team]): + """Our goal is to survive from spawning bots""" + name = 'Bot Chase' + description = 'Try to survive from bots!' + available_settings = [ + bs.BoolSetting( + 'Epic Mode', + default=False + ), + ] + + announce_player_deaths = True + + @classmethod + def get_supported_maps(cls, sessiontype: Type[bs.Session]) -> List[str]: + return ['Football Stadium'] + + @classmethod + def supports_session_type(cls, sessiontype: Type[bs.Session]) -> bool: + return (issubclass(sessiontype, bs.FreeForAllSession) or issubclass(sessiontype, bs.DualTeamSession) or issubclass(sessiontype, bs.CoopSession)) # Coop session unused + + def __init__(self, settings: dict): + super().__init__(settings) + self._bots = SpazBotSet() + self._epic_mode = bool(settings['Epic Mode']) + self._timer: Optional[OnScreenTimer] = None + self._last_player_death_time: Optional[float] = None + + if self._epic_mode: + self.slow_motion = True + self.default_music = (bs.MusicType.EPIC if self._epic_mode else bs.MusicType.FORWARD_MARCH) + + def on_player_join(self, player: Player) -> None: + if self.has_begun(): + bs.broadcastmessage( + babase.Lstr(resource='playerDelayedJoinText', + subs=[('${PLAYER}', player.getname(full=True))]), + color=(0, 1, 0), + ) + assert self._timer is not None + player.death_time = self._timer.getstarttime() + return + self.spawn_player(player) + + def on_player_leave(self, player: Player) -> None: + super().on_player_leave(player) + self._check_end_game() + + def spawn_player(self, player: Player) -> bs.Actor: + spaz = self.spawn_player_spaz(player) + spaz.connect_controls_to_player(enable_punch=True, + enable_bomb=True, + enable_pickup=True) + + spaz.bomb_count = 3 + spaz.bomb_type = 'normal' + + #cerdo gordo + spaz.node.color_mask_texture = bs.gettexture('melColorMask') + spaz.node.color_texture = bs.gettexture('melColor') + spaz.node.head_mesh = bs.getmesh('melHead') + spaz.node.hand_mesh = bs.getmesh('melHand') + spaz.node.torso_mesh = bs.getmesh('melTorso') + spaz.node.pelvis_mesh = bs.getmesh('kronkPelvis') + spaz.node.upper_arm_mesh = bs.getmesh('melUpperArm') + spaz.node.forearm_mesh = bs.getmesh('melForeArm') + spaz.node.upper_leg_mesh = bs.getmesh('melUpperLeg') + spaz.node.lower_leg_mesh = bs.getmesh('melLowerLeg') + spaz.node.toes_mesh = bs.getmesh('melToes') + spaz.node.style = 'mel' + # Sounds cerdo gordo + mel_sounds = [bs.getsound('mel01'), bs.getsound('mel02'),bs.getsound('mel03'),bs.getsound('mel04'),bs.getsound('mel05'), + bs.getsound('mel06'),bs.getsound('mel07'),bs.getsound('mel08'),bs.getsound('mel09'),bs.getsound('mel10')] + spaz.node.jump_sounds = mel_sounds + spaz.node.attack_sounds = mel_sounds + spaz.node.impact_sounds = mel_sounds + spaz.node.pickup_sounds = mel_sounds + spaz.node.death_sounds = [bs.getsound('melDeath01')] + spaz.node.fall_sounds = [bs.getsound('melFall01')] + + spaz.play_big_death_sound = True + return spaz + + def on_begin(self) -> None: + super().on_begin() + self._bots.spawn_bot(MrSpazBot, pos=(random.choice([1, -1, 2, -2]), 1.34, random.choice([1, -1, 2, -2])), spawn_time=2.0) + self._bots.spawn_bot(MrSpazBot, pos=(random.choice([1, -1, 2, -2]), 1.34, random.choice([1, -1, 2, -2])), spawn_time=2.0) + + self._timer = OnScreenTimer() + self._timer.start() + + bs.timer(10.0, self._spawn_this_bot, repeat=True) + bs.timer(5.0, self._check_end_game) + + def handlemessage(self, msg: Any) -> Any: + if isinstance(msg, bs.PlayerDiedMessage): + + super().handlemessage(msg) + + curtime = bs.time() + + msg.getplayer(Player).death_time = curtime + + if isinstance(self.session, bs.CoopSession): + babase.pushcall(self._check_end_game) + + self._last_player_death_time = curtime + else: + bs.timer(1.0, self._check_end_game) + elif isinstance(msg, SpazBotDiedMessage): + self._spawn_this_bot() + else: + return super().handlemessage(msg) + return None + + def _spawn_this_bot(self) -> None: + self._bots.spawn_bot(MrSpazBot, pos=(random.choice([1, -1, 2, -2]), 1.34, random.choice([1, -1, 2, -2])), spawn_time=2.0) + + def _check_end_game(self) -> None: + living_team_count = 0 + for team in self.teams: + for player in team.players: + if player.is_alive(): + living_team_count += 1 + break + + if isinstance(self.session, bs.CoopSession): + if living_team_count <= 0: + self.end_game() + else: + if living_team_count <= 1: + self.end_game() + + def end_game(self) -> None: + cur_time = bs.time() + assert self._timer is not None + start_time = self._timer.getstarttime() + + for team in self.teams: + for player in team.players: + survived = False + + if player.death_time is None: + survived = True + player.death_time = cur_time + 1 + + score = int(player.death_time - self._timer.getstarttime()) + if survived: + score += 50 + self.stats.player_scored(player, score, screenmessage=False) + + self._timer.stop(endtime=self._last_player_death_time) + + results = bs.GameResults() + + for team in self.teams: + longest_life = 0.0 + for player in team.players: + assert player.death_time is not None + longest_life = max(longest_life, + player.death_time - start_time) + + results.set_team_score(team, int(1000.0 * longest_life)) + + self.end(results=results) \ No newline at end of file diff --git a/plugins/utilities.json b/plugins/utilities.json index fa71aa4c..db809c69 100644 --- a/plugins/utilities.json +++ b/plugins/utilities.json @@ -1147,6 +1147,20 @@ "md5sum": "01cf9e10ab0e1bf51c07d80ff842c632" } } + }, + "ba_colours": { + "description": "Try to survive from bots!", + "external_url": "", + "authors": [ + { + "name": "Froshlee", + "email": "", + "discord": "froshlee24" + } + ], + "versions": { + "1.0.0": null + } } } } \ No newline at end of file diff --git a/plugins/utilities/ba_colors.py b/plugins/utilities/ba_colors.py new file mode 100644 index 00000000..8480f8b3 --- /dev/null +++ b/plugins/utilities/ba_colors.py @@ -0,0 +1,1018 @@ +# Ported to api 8 by brostos using baport.(https://github.com/bombsquad-community/baport) +"""Colors Mod.""" +#Mod by Froshlee14 +# ba_meta require api 8 + +from __future__ import annotations +from typing import TYPE_CHECKING + +import _babase +import babase +import bauiv1 as bui +import bascenev1 as bs + +if TYPE_CHECKING: + pass + +from bascenev1lib.actor.spazfactory import SpazFactory +from bascenev1lib.actor.scoreboard import Scoreboard +from bascenev1lib.game.elimination import EliminationGame, Icon, Player, Team +from bascenev1lib.gameutils import SharedObjects + +from bascenev1 import get_player_colors, get_player_profile_colors, get_player_profile_icon +from bauiv1lib.popup import PopupWindow +from bascenev1lib.actor import bomb, spaz +from bauiv1lib import tabs, confirm, mainmenu, popup +from bauiv1lib.colorpicker import ColorPicker +from bauiv1lib.mainmenu import MainMenuWindow +from bauiv1lib.profile.browser import * +from bascenev1lib.actor.playerspaz import * +from bascenev1lib.actor.flag import * +from bascenev1lib.actor.spazbot import * +from bascenev1lib.actor.spazfactory import SpazFactory +#from bascenev1lib.mainmenu import MainMenuActivity +import random + + +def getData(data): + return babase.app.config["colorsMod"][data] + +def getRandomColor(): + c = random.choice(getData("colors")) + return c + +def doColorMenu(self): + bui.containerwidget(edit=self._root_widget,transition='out_left') + openWindow() + +def updateButton(self): + color = (random.random(),random.random(),random.random()) + try: + bui.buttonwidget(edit=self._colorsModButton,color=color) + except Exception: + self._timer = None + +newConfig = {"colorPlayer":True, + "higlightPlayer":False, + "namePlayer":False, + "glowColor":False, + "glowHighlight":False, + "glowName":False, + "actab":1, + "shieldColor":False, + "xplotionColor":True, + "delScorch":True, + "colorBots":False, + "glowBots":False, + "flag":True, + #"test":True, + "glowScale":1, + "timeDelay":500, + "activeProfiles":['__account__'], + "colors":[color for color in get_player_colors()], + } + +def getDefaultSettings(): + return newConfig + +def getTranslation(text): + actLan = bs.app.lang.language + colorsModsLan = { + "title":{ + "Spanish":'Colors Mod', + "English":'Colors Mod' + }, + "player_tab":{ + "Spanish":'Ajustes de Jugador', + "English":'Player settings' + }, + "extras_tab":{ + "Spanish":'Ajustes Adicionales', + "English":'Adittional settings' + }, + "general_tab":{ + "Spanish":'Ajustes Generales', + "English":'General settings' + }, + "info_tab":{ + "Spanish":'Creditos', + "English":'Credits' + }, + "profiles":{ + "Spanish":'Perfiles', + "English":'Profiles' + }, + "palette":{ + "Spanish":'Paleta de Colores', + "English":'Pallete' + }, + "change":{ + "Spanish":'Cambiar', + "English":'Change' + }, + "glow":{ + "Spanish":'Brillar', + "English":'Glow' + }, + "glow_scale":{ + "Spanish":'Escala de Brillo', + "English":'Glow Scale' + }, + "time_delay":{ + "Spanish":'Intervalo de Tiempo', + "English":'Time Delay' + }, + "reset_values":{ + "Spanish":'Reiniciar Valores', + "English":'Reset Values' + }, + "players":{ + "Spanish":'Jugadores', + "English":'Players' + }, + "apply_to_color":{ + "Spanish":'Color Principal', + "English":'Main Color' + }, + "apply_to_highlight":{ + "Spanish":'Color de Resalte', + "English":'Highlight Color' + }, + "apply_to_name":{ + "Spanish":'Color del Nombre', + "English":'Name Color' + }, + "additional_features":{ + "Spanish":'Ajustes Adicionales', + "English":'Additional Features' + }, + "apply_to_bots":{ + "Spanish":'Color Principal de Bots', + "English":'Bots Main Color' + }, + "apply_to_shields":{ + "Spanish":'Escudos de Colores', + "English":'Apply to Shields' + }, + "apply_to_explotions":{ + "Spanish":'Explosiones de Colores', + "English":'Apply to Explotions' + }, + "apply_to_flags":{ + "Spanish":'Banderas de Colores', + "English":'Apply to Flags' + }, + "pick_color":{ + "Spanish":'Selecciona un Color', + "English":'Pick a Color' + }, + "add_color":{ + "Spanish":'Agregar Color', + "English":'Add Color' + }, + "remove_color":{ + "Spanish":'Quitar Color', + "English":'Remove Color' + }, + "clean_explotions":{ + "Spanish":'Limpiar Explosiones', + "English":'Remove Scorch' + }, + "restore_default_settings":{ + "Spanish":'Restaurar Ajustes Por Defecto', + "English":'Restore Default Settings' + }, + "settings_restored":{ + "Spanish":'Ajustes Restaurados', + "English":'Settings Restored' + }, + "restore_settings":{ + "Spanish":'¿Restaurar Ajustes Por Defecto?', + "English":'Restore Default Settings?' + }, + "nothing_selected":{ + "Spanish":'Nada Seleccionado', + "English":'Nothing Selected' + }, + "color_already":{ + "Spanish":'Este Color Ya Existe En La Paleta', + "English":'Color Already In The Palette' + }, + "tap_color":{ + "Spanish":'Toca un color para quitarlo.', + "English":'Tap to remove a color.' + }, + } + lans = ["Spanish","English"] + if actLan not in lans: + actLan = "English" + return colorsModsLan[text][actLan] + + +# ba_meta export plugin +class ColorsMod(babase.Plugin): + + #PLUGINS PLUS COMPATIBILITY + version = "1.7.2" + logo = 'gameCenterIcon' + logo_color = (1,1,1) + plugin_type = 'mod' + + def has_settings_ui (self): + return True + + def show_settings_ui(self, button): + ColorsMenu() + + if bs.app.lang.language == "Spanish": + information = ("Modifica y aplica efectos\n" + "a los colores de tu personaje,\n" + "explosiones, bots, escudos,\n" + "entre otras cosas...\n\n" + "Programado por Froshlee14\nTraducido por CerdoGordo\n\n" + "ADVERTENCIA\nEste mod puede ocacionar\n" + "efectos de epilepsia\na personas sensibles.") + else: + information = ("Modify and add effects\n" + "to your character colours.\n" + "And other stuff...\n\n" + "Coded by Froshlee14\nTranslated by CerdoGordo\n\n" + "WARNING\nThis mod can cause epileptic\n" + "seizures especially\nwith sensitive people") + + def on_app_running(self) -> None: + + if "colorsMod" in babase.app.config: + oldConfig = babase.app.config["colorsMod"] + for setting in newConfig: + if setting not in oldConfig: + babase.app.config["colorsMod"].update({setting:newConfig[setting]}) + bs.broadcastmessage(('Colors Mod: config updated'),color=(1,1,0)) + + removeList = [] + for setting in oldConfig: + if setting not in newConfig: + removeList.append(setting) + for element in removeList : + babase.app.config["colorsMod"].pop(element) + bs.broadcastmessage(('Colors Mod: old config deleted'),color=(1,1,0)) + else: + babase.app.config["colorsMod"] = newConfig + babase.app.config.apply_and_commit() + + + #MainMenuActivity.oldMakeWord = MainMenuActivity._make_word + #def newMakeWord(self, word: str, + # x: float, + # y: float, + # scale: float = 1.0, + # delay: float = 0.0, + # vr_depth_offset: float = 0.0, + # shadow: bool = False): + # self.oldMakeWord(word,x,y,scale,delay,vr_depth_offset,shadow) + # word = self._word_actors[-1] + # if word.node.getnodetype(): + # if word.node.color[3] == 1.0: + # word.node.color = getRandomColor() + #MainMenuActivity._make_word = newMakeWord + + #### GAME MODIFICATIONS #### + + #ESCUDO DE COLORES + def new_equip_shields(self, decay: bool = False) -> None: + if not self.node: + babase.print_error('Can\'t equip shields; no node.') + return + + factory = SpazFactory.get() + if self.shield is None: + self.shield = bs.newnode('shield',owner=self.node,attrs={ + 'color': (0.3, 0.2, 2.0),'radius': 1.3 }) + self.node.connectattr('position_center', self.shield, 'position') + self.shield_hitpoints = self.shield_hitpoints_max = 650 + self.shield_decay_rate = factory.shield_decay_rate if decay else 0 + self.shield.hurt = 0 + factory.shield_up_sound.play(1.0, position=self.node.position) + + if self.shield_decay_rate > 0: + self.shield_decay_timer = bs.Timer(0.5,bs.WeakCall(self.shield_decay),repeat=True) + self.shield.always_show_health_bar = True + def changeColor(): + if self.shield is None: return + if getData("shieldColor"): + self.shield.color = c = getRandomColor() + self._shieldTimer = bs.Timer(getData("timeDelay") / 1000,changeColor,repeat=True) + PlayerSpaz.equip_shields = new_equip_shields + + #BOTS DE COLORES + SpazBot.oldBotInit = SpazBot.__init__ + def newBotInit(self, *args, **kwargs): + self.oldBotInit(*args, **kwargs) + s = 1 + if getData("glowBots"): + s = getData("glowScale") + + self.node.highlight = (self.node.highlight[0]*s,self.node.highlight[1]*s,self.node.highlight[2]*s) + + def changeColor(): + if self.is_alive(): + if getData("colorBots"): + c = getRandomColor() + self.node.highlight = (c[0]*s,c[1]*s,c[2]*s) + self._timer = bs.Timer(getData("timeDelay") / 1000 ,changeColor,repeat=True) + SpazBot.__init__ = newBotInit + + #BANDERA DE COLORES + Flag.oldFlagInit = Flag.__init__ + def newFlaginit(self,position: Sequence[float] = (0.0, 1.0, 0.0), + color: Sequence[float] = (1.0, 1.0, 1.0), + materials: Sequence[bs.Material] = None, + touchable: bool = True, + dropped_timeout: int = None): + self.oldFlagInit(position, color,materials,touchable,dropped_timeout) + + def cC(): + if self.node.exists(): + if getData("flag"): + c = getRandomColor() + self.node.color = (c[0]*1.2,c[1]*1.2,c[2]*1.2) + else: return + if touchable : + self._timer = bs.Timer(getData("timeDelay") / 1000 ,cC,repeat=True) + + Flag.__init__ = newFlaginit + + #JUGADORES DE COLORES + PlayerSpaz.oldInit = PlayerSpaz.__init__ + def newInit(self,player: bs.Player, + color: Sequence[float] = (1.0, 1.0, 1.0), + highlight: Sequence[float] = (0.5, 0.5, 0.5), + character: str = 'Spaz', + powerups_expire: bool = True): + self.oldInit(player,color,highlight,character,powerups_expire) + + players = [] + for p in getData("activeProfiles"): + players.append(p) + + for x in range(len(players)): + if players[x] == "__account__" : + players[x] = bui.app.plus.get_v1_account_name()#_babase.get_v1_account_name() + + if player.getname() in players: + s = s2 = s3 = 1 + if getData("glowColor"): + s = getData("glowScale") + if getData("glowHighlight"): + s2 = getData("glowScale") + if getData("glowName"): + s3 = getData("glowScale") + + self.node.color = (self.node.color[0]*s,self.node.color[1]*s,self.node.color[2]*s) + self.node.highlight = (self.node.highlight[0]*s2,self.node.highlight[1]*s2,self.node.highlight[2]*s2) + self.node.name_color = (self.node.name_color[0]*s3,self.node.name_color[1]*s3,self.node.name_color[2]*s3) + + def changeColor(): + if self.is_alive(): + if getData("colorPlayer"): + c = getRandomColor() + self.node.color = (c[0]*s,c[1]*s,c[2]*s) + if getData("higlightPlayer"): + c = getRandomColor() + self.node.highlight = (c[0]*s2,c[1]*s2,c[2]*s2) + if getData("namePlayer"): + c = getRandomColor() + self.node.name_color = (c[0]*s3,c[1]*s3,c[2]*s3) + self._timer = bs.Timer(getData("timeDelay") / 1000 ,changeColor,repeat=True) + PlayerSpaz.__init__ = newInit + + #EXPLOSIONES DE COLORES + bomb.Blast.oldBlastInit = bomb.Blast.__init__ + def newBlastInit(self, position: Sequence[float] = (0.0, 1.0, 0.0), velocity: Sequence[float] = (0.0, 0.0, 0.0), + blast_radius: float = 2.0, blast_type: str = 'normal', source_player: bs.Player = None, + hit_type: str = 'explosion', hit_subtype: str = 'normal'): + + self.oldBlastInit(position, velocity, blast_radius, blast_type, source_player, hit_type, hit_subtype) + + if getData("xplotionColor"): + c = getRandomColor() + + scl = random.uniform(0.6, 0.9) + scorch_radius = light_radius = self.radius + if self.blast_type == 'tnt': + light_radius *= 1.4 + scorch_radius *= 1.15 + scl *= 3.0 + + for i in range(2): + scorch = bs.newnode('scorch',attrs={'position':self.node.position, 'size':scorch_radius*0.5,'big':(self.blast_type == 'tnt')}) + if self.blast_type == 'ice': scorch.color =(1,1,1.5) + else: scorch.color = c + if getData("xplotionColor"): + if getData("delScorch"): + bs.animate(scorch,"presence",{3:1, 13:0}) + bs.Timer(13,scorch.delete) + + if self.blast_type == 'ice': return + light = bs.newnode('light', attrs={ 'position': position,'volume_intensity_scale': 10.0,'color': c}) + + iscale = 1.6 + bs.animate(light, 'intensity', { + 0: 2.0 * iscale, + scl * 0.02: 0.1 * iscale, + scl * 0.025: 0.2 * iscale, + scl * 0.05: 17.0 * iscale, + scl * 0.06: 5.0 * iscale, + scl * 0.08: 4.0 * iscale, + scl * 0.2: 0.6 * iscale, + scl * 2.0: 0.00 * iscale, + scl * 3.0: 0.0}) + bs.animate(light, 'radius', { + 0: light_radius * 0.2, + scl * 0.05: light_radius * 0.55, + scl * 0.1: light_radius * 0.3, + scl * 0.3: light_radius * 0.15, + scl * 1.0: light_radius * 0.05}) + bs.timer(scl * 3.0, light.delete) + bomb.Blast.__init__ = newBlastInit + + +class ProfilesWindow(popup.PopupWindow): + """Popup window to view achievements.""" + + def __init__(self): + uiscale = bui.app.ui_v1.uiscale + scale = (1.8 if uiscale is babase.UIScale.SMALL else + 1.65 if uiscale is babase.UIScale.MEDIUM else 1.23) + self._transitioning_out = False + self._width = 300 + self._height = (300 if uiscale is babase.UIScale.SMALL else 350) + bg_color = (0.5, 0.4, 0.6) + + self._selected = None + self._activeProfiles = getData("activeProfiles") + + self._profiles = babase.app.config.get('Player Profiles', {}) + assert self._profiles is not None + items = list(self._profiles.items()) + items.sort(key=lambda x: x[0].lower()) + + accountName: Optional[str] + if bui.app.plus.get_v1_account_state() == 'signed_in': + accountName = bui.app.plus.get_v1_account_display_string() + else: accountName = None + #subHeight += (len(items)*45) + + # creates our _root_widget + popup.PopupWindow.__init__(self, + position=(0,0), + size=(self._width, self._height), + scale=scale, + bg_color=bg_color) + + self._cancel_button = bui.buttonwidget( parent=self.root_widget, + position=(50, self._height - 30), size=(50, 50), + scale=0.5, label='', + color=bg_color, + on_activate_call=self._on_cancel_press, + autoselect=True, + icon=bui.gettexture('crossOut'), + iconscale=1.2) + bui.containerwidget(edit=self.root_widget,cancel_button=self._cancel_button) + + + self._title_text = bui.textwidget(parent=self.root_widget, + position=(self._width * 0.5,self._height - 20), + size=(0, 0), + h_align='center', + v_align='center', + scale=01.0, + text=getTranslation('profiles'), + maxwidth=200, + color=(1, 1, 1, 0.4)) + + self._scrollwidget = bui.scrollwidget(parent=self.root_widget, + size=(self._width - 60, + self._height - 70), + position=(30, 30), + capture_arrows=True, + simple_culling_v=10) + bui.widget(edit=self._scrollwidget, autoselect=True) + + #incr = 36 + sub_width = self._width - 90 + sub_height = (len(items)*50) + + eq_rsrc = 'coopSelectWindow.powerRankingPointsEqualsText' + pts_rsrc = 'coopSelectWindow.powerRankingPointsText' + + self._subcontainer = box = bui.containerwidget(parent=self._scrollwidget, + size=(sub_width, sub_height), + background=False) + h = 20 + v = sub_height - 60 + for pName, p in items: + if pName == '__account__' and accountName is None: + continue + color, highlight = get_player_profile_colors(pName) + tval = (accountName if pName == '__account__' else + get_player_profile_icon(pName) + pName) + assert isinstance(tval, str) + #print(tval) + value = True if pName in self._activeProfiles else False + + w = bui.checkboxwidget(parent=box,position=(10,v), value=value, + on_value_change_call=bs.WeakCall(self.select, pName), + maxwidth=sub_width,size=(sub_width,50), + textcolor = color, + text=babase.Lstr(value=tval),autoselect=True) + v -= 45 + + def addProfile(self): + if self._selected is not None: + if self._selected not in self._activeProfiles: + self._activeProfiles.append(self._selected) + babase.app.config["colorsMod"]["activeProfiles"] = self._activeProfiles + babase.app.config.apply_and_commit() + else: bs.broadcastmessage(getTranslation('nothing_selected')) + + def removeProfile(self): + if self._selected is not None: + if self._selected in self._activeProfiles: + self._activeProfiles.remove(self._selected) + babase.app.config["colorsMod"]["activeProfiles"] = self._activeProfiles + babase.app.config.apply_and_commit() + else: print('not found') + else: bs.broadcastmessage(getTranslation('nothing_selected')) + + def select(self,name,m): + self._selected = name + if m == 0: self.removeProfile() + else: self.addProfile() + + def _on_cancel_press(self) -> None: + self._transition_out() + + def _transition_out(self) -> None: + if not self._transitioning_out: + self._transitioning_out = True + bui.containerwidget(edit=self.root_widget, transition='out_scale') + + def on_popup_cancel(self) -> None: + bui.getsound('swish').play() + self._transition_out() + + +class ColorsMenu(PopupWindow): + + def __init__(self,transition='in_right'): + #self._width = width = 650 + self._width = width = 800 + self._height = height = 450 + + self._scrollWidth = self._width*0.85 + self._scrollHeight = self._height - 120 + self._subWidth = self._scrollWidth*0.95; + self._subHeight = 200 + + self._current_tab = getData('actab') + self._timeDelay = getData("timeDelay") + self._glowScale = getData("glowScale") + + self.midwidth = self._scrollWidth*0.45 + self.qwidth = self.midwidth*0.4 + + app = bui.app.ui_v1 + uiscale = app.uiscale + + from bascenev1lib.mainmenu import MainMenuSession + self._in_game = not isinstance(bs.get_foreground_host_session(), + MainMenuSession) + + self._root_widget = bui.containerwidget(size=(width,height),transition=transition, + scale=1.5 if uiscale is babase.UIScale.SMALL else 1.0, + stack_offset=(0,-5) if uiscale is babase.UIScale.SMALL else (0,0)) + + self._title = bui.textwidget(parent=self._root_widget,position=(50,height-40),text='', + maxwidth=self._scrollWidth,size=(self._scrollWidth,20), + color=(0.8,0.8,0.8,1.0),h_align="center",scale=1.1) + + self._backButton = b = bui.buttonwidget(parent=self._root_widget,autoselect=True, + position=(50,height-60),size=(120,50), + scale=0.8,text_scale=1.2,label=babase.Lstr(resource='backText'), + button_type='back',on_activate_call=self._back) + bui.buttonwidget(edit=self._backButton, button_type='backSmall',size=(50, 50),label=babase.charstr(babase.SpecialChar.BACK)) + bui.containerwidget(edit=self._root_widget,cancel_button=b) + + self._nextButton = bui.buttonwidget(parent=self._root_widget,autoselect=True, + position=(width-60,height*0.5-20),size=(50,50), + scale=1.0,label=babase.charstr(babase.SpecialChar.RIGHT_ARROW), + color=(0.2,1,0.2),button_type='square', + on_activate_call=self.nextTabContainer) + + self._prevButton = bui.buttonwidget(parent=self._root_widget,autoselect=True, + position=(10,height*0.5-20),size=(50,50), + scale=1.0,label=babase.charstr(babase.SpecialChar.LEFT_ARROW), + color=(0.2,1,0.2),button_type='square', + on_activate_call=self.prevTabContainer) + + v = self._subHeight - 55 + v0 = height - 90 + + self.tabs = [ + [0,getTranslation('general_tab')], + [1,getTranslation('player_tab')], + [2,getTranslation('extras_tab')], + [3,getTranslation('info_tab')], + ] + + self._scrollwidget = sc = bui.scrollwidget(parent=self._root_widget,size=(self._subWidth,self._scrollHeight),border_opacity=0.3, highlight=False, position=((width*0.5)-(self._scrollWidth*0.47),50),capture_arrows=True,) + + bui.widget(edit=sc, left_widget=self._prevButton) + bui.widget(edit=sc, right_widget=self._nextButton) + bui.widget(edit=self._backButton, down_widget=sc) + + self.tabButtons = [] + h = 330 + for i in range(3): + tabButton = bui.buttonwidget(parent=self._root_widget,autoselect=True, + position=(h,20),size=(20,20), + scale=1.2,label='', + color=(0.3,0.9,0.3), + on_activate_call=babase.Call(self._setTab,self.tabs[i][0]), + texture=bui.gettexture('nub')) + self.tabButtons.append(tabButton) + h += 50 + self._tabContainer = None + self._setTab(self._current_tab) + + def nextTabContainer(self): + tab = babase.app.config['colorsMod']['actab'] + if tab == 2: self._setTab(0) + else: self._setTab(tab+1) + + def prevTabContainer(self): + tab = babase.app.config['colorsMod']['actab'] + if tab == 0: self._setTab(2) + else: self._setTab(tab-1) + + def _setTab(self,tab): + + self._colorTimer = None + self._current_tab = tab + + babase.app.config['colorsMod']['actab'] = tab + babase.app.config.apply_and_commit() + + if self._tabContainer is not None and self._tabContainer.exists(): + self._tabContainer.delete() + self._tabData = {} + + if tab == 0: #general + subHeight = 0 + + self._tabContainer = c = bui.containerwidget(parent=self._scrollwidget,size=(self._subWidth,subHeight), + background=False,selection_loops_to_parent=True) + + bui.textwidget(edit=self._title,text=getTranslation('general_tab')) + v0 = subHeight - 30 + v = v0 - 10 + + h = self._scrollWidth*0.12 + cSpacing = self._scrollWidth*0.15 + t = bui.textwidget(parent=c,position=(0,v), + text=getTranslation('glow_scale'), + maxwidth=self.midwidth ,size=(self.midwidth ,20),color=(0.8,0.8,0.8,1.0),h_align="center") + v -= 45 + b = bui.buttonwidget(parent=c,position=(h-20,v-12),size=(40,40),label="-", + autoselect=True,on_activate_call=babase.Call(self._glowScaleDecrement),repeat=True,enable_sound=True,button_type='square') + + self._glowScaleText = bui.textwidget(parent=c,position=(h+20,v),maxwidth=cSpacing, + size=(cSpacing,20),editable=False,color=(0.3,1.0,0.3),h_align="center",text=str(self._glowScale)) + + b2 = bui.buttonwidget(parent=c,position=(h+cSpacing+20,v-12),size=(40,40),label="+", + autoselect=True,on_activate_call=babase.Call(self._glowScaleIncrement),repeat=True,enable_sound=True,button_type='square') + + v -= 70 + t = bui.textwidget(parent=c,position=(0,v), + text=getTranslation('time_delay'), + maxwidth=self.midwidth ,size=(self.midwidth ,20),color=(0.8,0.8,0.8,1.0),h_align="center") + v -= 45 + a = bui.buttonwidget(parent=c,position=(h-20,v-12),size=(40,40),label="-", + autoselect=True,on_activate_call=babase.Call(self._timeDelayDecrement),repeat=True,enable_sound=True,button_type='square') + + self._timeDelayText = bui.textwidget(parent=c,position=(h+20,v),maxwidth=self._scrollWidth*0.9, + size=(cSpacing,20),editable=False,color=(0.3,1.0,0.3,1.0),h_align="center",text=str(self._timeDelay)) + + a2 = bui.buttonwidget(parent=c,position=(h+cSpacing+20,v-12),size=(40,40),label="+", + autoselect=True,on_activate_call=babase.Call(self._timeDelayIncrement),repeat=True,enable_sound=True,button_type='square') + + v -= 70 + reset = bui.buttonwidget(parent=c, autoselect=True, + position=((self._scrollWidth*0.22)-80, v-25), size=(160,50),scale=1.0, text_scale=1.2,textcolor=(1,1,1), + label=getTranslation('reset_values'),on_activate_call=self._resetValues) + self._updateColorTimer() + + v = v0 + h = self._scrollWidth*0.44 + + t = bui.textwidget(parent=c,position=(h,v), + text=getTranslation('palette'), + maxwidth=self.midwidth ,size=(self.midwidth ,20), + color=(0.8,0.8,0.8,1.0),h_align="center") + v -= 30 + t2 = bui.textwidget(parent=c,position=(h,v), + text=getTranslation('tap_color'), scale=0.9, + maxwidth=self.midwidth ,size=(self.midwidth ,20), + color=(0.6,0.6,0.6,1.0),h_align="center") + v -= 20 + sp = h+45 + self.updatePalette(v,sp) + + elif tab == 1: + subHeight = self._subHeight + + self._tabContainer = c = bui.containerwidget(parent=self._scrollwidget,size=(self._subWidth,subHeight), + background=False,selection_loops_to_parent=True) + v2 = v = v0 = subHeight + bui.textwidget(edit=self._title,text=getTranslation('player_tab')) + + t = babase.app.classic.spaz_appearances['Spaz'] + tex = bui.gettexture(t.icon_texture) + tintTex = bui.gettexture(t.icon_mask_texture) + gs = getData("glowScale") + tc = (1,1,1) + t2c = (1,1,1) + + v2 -= (50+180) + self._previewImage = bui.imagewidget(parent=c,position=(self._subWidth*0.72-100,v2),size=(200,200), + mask_texture=bui.gettexture('characterIconMask'),tint_texture=tintTex, + texture=tex, mesh_transparent=bui.getmesh('image1x1'), + tint_color=(tc[0]*gs,tc[1]*gs,tc[2]*gs),tint2_color=(t2c[0]*gs,t2c[1]*gs,t2c[2]*gs)) + + self._colorTimer = bui.AppTimer(getData("timeDelay") / 1000, + babase.Call(self._updatePreview),repeat=True) + v2 -= 70 + + def doProfileWindow(): + ProfilesWindow() + + reset = bui.buttonwidget(parent=c, autoselect=True,on_activate_call=doProfileWindow, + position=(self._subWidth*0.72-100,v2), size=(200,60),scale=1.0, text_scale=1.2,textcolor=(1,1,1), + label=getTranslation('profiles')) + miniBoxWidth = self.midwidth - 30 + miniBoxHeight = 80 + + v -= 18 + #Color + h = 50 + box1 = bui.containerwidget(parent=c,position=(h,v-miniBoxHeight), + size=(miniBoxWidth,miniBoxHeight),background=True) + vbox1 = miniBoxHeight -25 + t = bui.textwidget(parent=box1,position=(10,vbox1), + text=getTranslation('apply_to_color'), + maxwidth=miniBoxWidth-20,size=(miniBoxWidth,20),color=(0.8,0.8,0.8,1.0),h_align="left") + vbox1 -= 45 + self.bw = bui.checkboxwidget(parent=box1,position=(10,vbox1), value=getData("colorPlayer"), + on_value_change_call=babase.Call(self._setSetting,'colorPlayer'), maxwidth=self.qwidth, + text=getTranslation('change'),autoselect=True,size=(self.qwidth,25)) + #vbox1 -= 35 + self.bw = bui.checkboxwidget(parent=box1,position=(25+self.qwidth,vbox1), value=getData("glowColor"), + on_value_change_call=babase.Call(self._setSetting,'glowColor'), maxwidth=self.qwidth, + text=getTranslation('glow'),autoselect=True,size=(self.qwidth,25)) + v -= (miniBoxHeight+20) + + #Highlight + box1 = bui.containerwidget(parent=c,position=(h,v-miniBoxHeight), + size=(miniBoxWidth,miniBoxHeight),background=True) + vbox1 = miniBoxHeight -20 + t = bui.textwidget(parent=box1,position=(10,vbox1), + text=getTranslation('apply_to_highlight'), + maxwidth=miniBoxWidth-20,size=(miniBoxWidth,20),color=(0.8,0.8,0.8,1.0),h_align="left") + vbox1 -= 45 + self.bw = bui.checkboxwidget(parent=box1,position=(10,vbox1), value=getData("higlightPlayer"), + on_value_change_call=babase.Call(self._setSetting,'higlightPlayer'), maxwidth=self.qwidth, + text=getTranslation('change'),autoselect=True,size=(self.qwidth,25)) + #vbox1 -= 35 + self.bw = bui.checkboxwidget(parent=box1,position=(25+self.qwidth,vbox1), value=getData("glowHighlight"), + on_value_change_call=babase.Call(self._setSetting,'glowHighlight'), maxwidth=self.qwidth, + text=getTranslation('glow'),autoselect=True,size=(self.qwidth,25)) + v -= (miniBoxHeight+20) + #Name + box1 = bui.containerwidget(parent=c,position=(h,v-miniBoxHeight), + size=(miniBoxWidth,miniBoxHeight),background=True) + vbox1 = miniBoxHeight -20 + t = bui.textwidget(parent=box1,position=(10,vbox1), + text=getTranslation('apply_to_name'), + maxwidth=miniBoxWidth-20,size=(miniBoxWidth,20),color=(0.8,0.8,0.8,1.0),h_align="left") + vbox1 -= 40 + self.bw = bui.checkboxwidget(parent=box1,position=(10,vbox1), value=getData("namePlayer"), + on_value_change_call=babase.Call(self._setSetting,'namePlayer'), maxwidth=self.qwidth, + text=getTranslation('change'),autoselect=True,size=(self.qwidth,25)) + #vbox1 -= 35 + self.bw = bui.checkboxwidget(parent=box1,position=(25+self.qwidth,vbox1), value=getData("glowName"), + on_value_change_call=babase.Call(self._setSetting,'glowName'), maxwidth=self.qwidth, + text=getTranslation('glow'),autoselect=True,size=(self.qwidth,25)) + v -= (miniBoxHeight+50) + + elif tab == 2: + subHeight = 0 + self._tabContainer = c = bui.containerwidget(parent=self._scrollwidget,size=(self._subWidth,subHeight), + background=False,selection_loops_to_parent=True) + v0 = subHeight - 50 + + v = v0 + h = 30 + bui.textwidget(edit=self._title,text=getTranslation('extras_tab')) + self.bw = bui.checkboxwidget(parent=c,position=(h,v), value=getData("shieldColor"), + on_value_change_call=babase.Call(self._setSetting,'shieldColor'), maxwidth=self.midwidth, + text=getTranslation('apply_to_shields'),autoselect=True,size=(self.midwidth,30)) + v -= 50 + self.bw = bui.checkboxwidget(parent=c,position=(h,v), value=getData("flag"), + on_value_change_call=babase.Call(self._setSetting,'flag'), maxwidth=self.midwidth, + text=getTranslation('apply_to_flags'),autoselect=True,size=(self.midwidth,30)) + v = v0 + h = self.midwidth + self.bw = bui.checkboxwidget(parent=c,position=(h,v), value=getData("xplotionColor"), + on_value_change_call=babase.Call(self._setSetting,'xplotionColor'), maxwidth=self.midwidth, + text=getTranslation('apply_to_explotions'),autoselect=True,size=(self.midwidth,30)) + v -= 50 + self.bw = bui.checkboxwidget(parent=c,position=(h,v), value=getData("delScorch"), + on_value_change_call=babase.Call(self._setSetting,'delScorch'), maxwidth=self.midwidth, + text=getTranslation('clean_explotions'),autoselect=True,size=(self.midwidth,30)) + v -= 35 + miniBoxWidth = self.midwidth + miniBoxHeight = 80 + + #Bots Color + box1 = bui.containerwidget(parent=c,position=((self._scrollWidth*0.45) -(miniBoxWidth/2),v-miniBoxHeight), + size=(miniBoxWidth,miniBoxHeight),background=True) + vbox1 = miniBoxHeight -20 + t = bui.textwidget(parent=box1,position=(10,vbox1), + text=getTranslation('apply_to_bots'), + maxwidth=miniBoxWidth-20,size=(miniBoxWidth,20),color=(0.8,0.8,0.8,1.0),h_align="left") + vbox1 -= 45 + self.bw = bui.checkboxwidget(parent=box1,position=(10,vbox1),value=getData("colorBots"), + on_value_change_call=babase.Call(self._setSetting,'colorBots'), maxwidth=self.qwidth, + text=getTranslation('change'),autoselect=True,size=(self.qwidth,25)) + + self.bw = bui.checkboxwidget(parent=box1,position=(30+self.qwidth,vbox1), value=getData("glowBots"), + on_value_change_call=babase.Call(self._setSetting,'glowBots'), maxwidth=self.qwidth, + text=getTranslation('glow'),autoselect=True,size=(self.qwidth,25)) + + v -= 130 + reset = bui.buttonwidget(parent=c, autoselect=True,on_activate_call=self.restoreSettings, + position=((self._scrollWidth*0.45)-150, v-25), size=(300,50),scale=1.0, text_scale=1.2,textcolor=(1,1,1), + label=getTranslation('restore_default_settings')) + + for bttn in self.tabButtons: + bui.buttonwidget(edit=bttn,color = (0.1,0.5,0.1)) + bui.buttonwidget(edit=self.tabButtons[tab],color = (0.1,1,0.1)) + + def _setSetting(self,setting,m): + babase.app.config["colorsMod"][setting] = False if m==0 else True + babase.app.config.apply_and_commit() + + def _timeDelayDecrement(self): + self._timeDelay = max(50,self._timeDelay - 50) + bui.textwidget(edit=self._timeDelayText,text=str(self._timeDelay)) + babase.app.config["colorsMod"]["timeDelay"] = self._timeDelay + babase.app.config.apply_and_commit() + self._updateColorTimer() + + def _timeDelayIncrement(self): + self._timeDelay = self._timeDelay + 50 + bui.textwidget(edit=self._timeDelayText,text=str(self._timeDelay)) + babase.app.config["colorsMod"]["timeDelay"] = self._timeDelay + babase.app.config.apply_and_commit() + self._updateColorTimer() + + def _resetValues(self): + babase.app.config["colorsMod"]["glowScale"] = self._glowScale = 1 + babase.app.config["colorsMod"]["timeDelay"] = self._timeDelay = 500 + bui.textwidget(edit=self._glowScaleText,text=str(self._glowScale)) + bui.textwidget(edit=self._timeDelayText,text=str(self._timeDelay)) + babase.app.config.apply_and_commit() + self._updateColorTimer() + + def updatePalette(self,h,sp): + colours = getData("colors") + x = sp + y = h - 50 + cont = 1 + bttnSize = (45,45) + l = len(colours) + + for i in range(16): + if i < l: + w = bui.buttonwidget( + parent= self._tabContainer, position=(x,y), size=bttnSize, + autoselect=False, label="",button_type="square",color=colours[i], + on_activate_call=bs.WeakCall(self.removeColor,colours[i])) + else: + w = bui.buttonwidget( + parent= self._tabContainer, position=(x,y), size=bttnSize,color=(0.5, 0.4, 0.6), + autoselect=False, label="",texture=bui.gettexture('frameInset')) + if i == l: + bui.buttonwidget(edit=w,on_activate_call=bs.WeakCall(self._makePicker,w),label="+") + if cont % 4 == 0: + x = sp + y -= ((bttnSize[0]) + 10) + else: x += (bttnSize[0]) + 13 + cont += 1 + + def addColor(self,color): + if not self.colorIn(color): + babase.app.config["colorsMod"]["colors"].append(color) + babase.app.config.apply_and_commit() + self._setTab(0) + else: bs.broadcastmessage(getTranslation('color_already')) + + def removeColor(self,color): + if color is not None: + if len(getData("colors")) >= 3: + if color in getData("colors"): + babase.app.config["colorsMod"]["colors"].remove(color) + babase.app.config.apply_and_commit() + self._setTab(0) + else: print('not found') + else: bs.broadcastmessage("Min. 2 colors", color=(0, 1, 0)) + else: bs.broadcastmessage(getTranslation('nothing_selected')) + + def _makePicker(self, origin): + baseScale = 2.05 if babase.UIScale.SMALL else 1.6 if babase.UIScale.MEDIUM else 1.0 + initial_color = (0, 0.8, 0) + ColorPicker( parent=self._tabContainer, position=origin.get_screen_space_center(), + offset=(baseScale * (-100), 0),initial_color=initial_color, delegate=self, tag='color') + + def color_picker_closing(self, picker): + if not self._root_widget.exists(): return + tag = picker.get_tag() + + def color_picker_selected_color(self, picker, color): + self.addColor(color) + + def colorIn(self,c): + sColors = getData("colors") + for sC in sColors: + if c[0] == sC[0] and c[1] == sC[1] and c[2] == sC[2]: + return True + return False + + def setColor(self,c): + self._selected = c + bui.buttonwidget(edit=self._moveOut,color = (0.8, 0, 0)) + + def _updateColorTimer(self): + self._colorTimer = bui.AppTimer(getData("timeDelay") / 1000 , self._update, repeat=True) + + def _update(self): + color = (random.random(),random.random(),random.random()) + bui.textwidget(edit=self._timeDelayText,color=color) + + def _updatePreview(self): + gs = gs2 = getData("glowScale") + if not getData("glowColor"): gs =1 + if not getData("glowHighlight"): gs2 =1 + + c = (1,1,1) + if getData("colorPlayer"): + c = getRandomColor() + + c2 = (1,1,1) + if getData("higlightPlayer"): + c2 = getRandomColor() + + bui.imagewidget(edit=self._previewImage,tint_color=(c[0]*gs,c[1]*gs,c[2]*gs)) + bui.imagewidget(edit=self._previewImage,tint2_color=(c2[0]*gs2,c2[1]*gs2,c2[2]*gs2)) + + def _glowScaleDecrement(self): + self._glowScale = max(1,self._glowScale - 1) + bui.textwidget(edit=self._glowScaleText,text=str(self._glowScale)) + babase.app.config["colorsMod"]["glowScale"] = self._glowScale + babase.app.config.apply_and_commit() + + def _glowScaleIncrement(self): + self._glowScale = min(5,self._glowScale + 1) + bui.textwidget(edit=self._glowScaleText,text=str(self._glowScale)) + babase.app.config["colorsMod"]["glowScale"] = self._glowScale + babase.app.config.apply_and_commit() + + def restoreSettings(self): + def doIt(): + babase.app.config["colorsMod"] = getDefaultSettings() + babase.app.config.apply_and_commit() + self._setTab(2) + bs.broadcastmessage(getTranslation('settings_restored')) + confirm.ConfirmWindow(getTranslation('restore_settings'), + width=400, height=120, action=doIt, ok_text=babase.Lstr(resource='okText')) + + def _back(self): + bui.containerwidget(edit=self._root_widget,transition='out_right') + self._colorTimer = None + self._colorPreviewTimer = None + #if self._in_game: + # babase.app.main_menu_window = (mainmenu.MainMenuWindow(transition='in_left').get_root_widget()) + #else: + # babase.app.main_menu_window = ProfileBrowserWindow(transition='in_left').get_root_widget() + #babase.app.main_menu_window = (mainmenu.MainMenuWindow(transition='in_left').get_root_widget()) \ No newline at end of file From 472ac8022890be2354a97e9a60b41ce3f3707a61 Mon Sep 17 00:00:00 2001 From: brostosjoined Date: Fri, 26 Jan 2024 16:10:05 +0300 Subject: [PATCH 0839/1464] Spelling error fix --- plugins/minigames.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/minigames.json b/plugins/minigames.json index 65479f7c..9513a6d9 100644 --- a/plugins/minigames.json +++ b/plugins/minigames.json @@ -1120,7 +1120,7 @@ } } }, - "ba_dark_fileds": { + "ba_dark_fields": { "description": "Get to the other side and watch your step", "external_url": "", "authors": [ From 1664b4724953a05f470a6afa2d6f3cb653b0f59b Mon Sep 17 00:00:00 2001 From: brostosjoined Date: Fri, 26 Jan 2024 13:12:06 +0000 Subject: [PATCH 0840/1464] [ci] auto-format --- plugins/minigames/bot_chase.py | 30 +- plugins/utilities/ba_colors.py | 1005 +++++++++++++++++--------------- 2 files changed, 542 insertions(+), 493 deletions(-) diff --git a/plugins/minigames/bot_chase.py b/plugins/minigames/bot_chase.py index b9d2fe49..6495ee46 100644 --- a/plugins/minigames/bot_chase.py +++ b/plugins/minigames/bot_chase.py @@ -21,9 +21,9 @@ def ba_get_levels(): return [babase._level.Level( - 'Bot Chase',gametype=BotChaseGame, + 'Bot Chase', gametype=BotChaseGame, settings={}, - preview_texture_name = 'footballStadiumPreview')] + preview_texture_name='footballStadiumPreview')] class Player(bs.Player['Team']): @@ -70,7 +70,8 @@ def get_supported_maps(cls, sessiontype: Type[bs.Session]) -> List[str]: @classmethod def supports_session_type(cls, sessiontype: Type[bs.Session]) -> bool: - return (issubclass(sessiontype, bs.FreeForAllSession) or issubclass(sessiontype, bs.DualTeamSession) or issubclass(sessiontype, bs.CoopSession)) # Coop session unused + # Coop session unused + return (issubclass(sessiontype, bs.FreeForAllSession) or issubclass(sessiontype, bs.DualTeamSession) or issubclass(sessiontype, bs.CoopSession)) def __init__(self, settings: dict): super().__init__(settings) @@ -87,7 +88,7 @@ def on_player_join(self, player: Player) -> None: if self.has_begun(): bs.broadcastmessage( babase.Lstr(resource='playerDelayedJoinText', - subs=[('${PLAYER}', player.getname(full=True))]), + subs=[('${PLAYER}', player.getname(full=True))]), color=(0, 1, 0), ) assert self._timer is not None @@ -104,11 +105,11 @@ def spawn_player(self, player: Player) -> bs.Actor: spaz.connect_controls_to_player(enable_punch=True, enable_bomb=True, enable_pickup=True) - + spaz.bomb_count = 3 spaz.bomb_type = 'normal' - #cerdo gordo + # cerdo gordo spaz.node.color_mask_texture = bs.gettexture('melColorMask') spaz.node.color_texture = bs.gettexture('melColor') spaz.node.head_mesh = bs.getmesh('melHead') @@ -122,8 +123,8 @@ def spawn_player(self, player: Player) -> bs.Actor: spaz.node.toes_mesh = bs.getmesh('melToes') spaz.node.style = 'mel' # Sounds cerdo gordo - mel_sounds = [bs.getsound('mel01'), bs.getsound('mel02'),bs.getsound('mel03'),bs.getsound('mel04'),bs.getsound('mel05'), - bs.getsound('mel06'),bs.getsound('mel07'),bs.getsound('mel08'),bs.getsound('mel09'),bs.getsound('mel10')] + mel_sounds = [bs.getsound('mel01'), bs.getsound('mel02'), bs.getsound('mel03'), bs.getsound('mel04'), bs.getsound('mel05'), + bs.getsound('mel06'), bs.getsound('mel07'), bs.getsound('mel08'), bs.getsound('mel09'), bs.getsound('mel10')] spaz.node.jump_sounds = mel_sounds spaz.node.attack_sounds = mel_sounds spaz.node.impact_sounds = mel_sounds @@ -136,9 +137,11 @@ def spawn_player(self, player: Player) -> bs.Actor: def on_begin(self) -> None: super().on_begin() - self._bots.spawn_bot(MrSpazBot, pos=(random.choice([1, -1, 2, -2]), 1.34, random.choice([1, -1, 2, -2])), spawn_time=2.0) - self._bots.spawn_bot(MrSpazBot, pos=(random.choice([1, -1, 2, -2]), 1.34, random.choice([1, -1, 2, -2])), spawn_time=2.0) - + self._bots.spawn_bot(MrSpazBot, pos=(random.choice( + [1, -1, 2, -2]), 1.34, random.choice([1, -1, 2, -2])), spawn_time=2.0) + self._bots.spawn_bot(MrSpazBot, pos=(random.choice( + [1, -1, 2, -2]), 1.34, random.choice([1, -1, 2, -2])), spawn_time=2.0) + self._timer = OnScreenTimer() self._timer.start() @@ -167,7 +170,8 @@ def handlemessage(self, msg: Any) -> Any: return None def _spawn_this_bot(self) -> None: - self._bots.spawn_bot(MrSpazBot, pos=(random.choice([1, -1, 2, -2]), 1.34, random.choice([1, -1, 2, -2])), spawn_time=2.0) + self._bots.spawn_bot(MrSpazBot, pos=(random.choice( + [1, -1, 2, -2]), 1.34, random.choice([1, -1, 2, -2])), spawn_time=2.0) def _check_end_game(self) -> None: living_team_count = 0 @@ -215,4 +219,4 @@ def end_game(self) -> None: results.set_team_score(team, int(1000.0 * longest_life)) - self.end(results=results) \ No newline at end of file + self.end(results=results) diff --git a/plugins/utilities/ba_colors.py b/plugins/utilities/ba_colors.py index 8480f8b3..e5225293 100644 --- a/plugins/utilities/ba_colors.py +++ b/plugins/utilities/ba_colors.py @@ -1,6 +1,6 @@ # Ported to api 8 by brostos using baport.(https://github.com/bombsquad-community/baport) """Colors Mod.""" -#Mod by Froshlee14 +# Mod by Froshlee14 # ba_meta require api 8 from __future__ import annotations @@ -30,215 +30,221 @@ from bascenev1lib.actor.flag import * from bascenev1lib.actor.spazbot import * from bascenev1lib.actor.spazfactory import SpazFactory -#from bascenev1lib.mainmenu import MainMenuActivity +# from bascenev1lib.mainmenu import MainMenuActivity import random def getData(data): return babase.app.config["colorsMod"][data] + def getRandomColor(): c = random.choice(getData("colors")) return c + def doColorMenu(self): - bui.containerwidget(edit=self._root_widget,transition='out_left') + bui.containerwidget(edit=self._root_widget, transition='out_left') openWindow() + def updateButton(self): - color = (random.random(),random.random(),random.random()) + color = (random.random(), random.random(), random.random()) try: - bui.buttonwidget(edit=self._colorsModButton,color=color) + bui.buttonwidget(edit=self._colorsModButton, color=color) except Exception: self._timer = None -newConfig = {"colorPlayer":True, - "higlightPlayer":False, - "namePlayer":False, - "glowColor":False, - "glowHighlight":False, - "glowName":False, - "actab":1, - "shieldColor":False, - "xplotionColor":True, - "delScorch":True, - "colorBots":False, - "glowBots":False, - "flag":True, - #"test":True, - "glowScale":1, - "timeDelay":500, - "activeProfiles":['__account__'], - "colors":[color for color in get_player_colors()], - } + +newConfig = {"colorPlayer": True, + "higlightPlayer": False, + "namePlayer": False, + "glowColor": False, + "glowHighlight": False, + "glowName": False, + "actab": 1, + "shieldColor": False, + "xplotionColor": True, + "delScorch": True, + "colorBots": False, + "glowBots": False, + "flag": True, + # "test":True, + "glowScale": 1, + "timeDelay": 500, + "activeProfiles": ['__account__'], + "colors": [color for color in get_player_colors()], + } + def getDefaultSettings(): return newConfig + def getTranslation(text): actLan = bs.app.lang.language colorsModsLan = { - "title":{ - "Spanish":'Colors Mod', - "English":'Colors Mod' + "title": { + "Spanish": 'Colors Mod', + "English": 'Colors Mod' }, - "player_tab":{ - "Spanish":'Ajustes de Jugador', - "English":'Player settings' + "player_tab": { + "Spanish": 'Ajustes de Jugador', + "English": 'Player settings' }, - "extras_tab":{ - "Spanish":'Ajustes Adicionales', - "English":'Adittional settings' + "extras_tab": { + "Spanish": 'Ajustes Adicionales', + "English": 'Adittional settings' }, - "general_tab":{ - "Spanish":'Ajustes Generales', - "English":'General settings' + "general_tab": { + "Spanish": 'Ajustes Generales', + "English": 'General settings' }, - "info_tab":{ - "Spanish":'Creditos', - "English":'Credits' + "info_tab": { + "Spanish": 'Creditos', + "English": 'Credits' }, - "profiles":{ - "Spanish":'Perfiles', - "English":'Profiles' + "profiles": { + "Spanish": 'Perfiles', + "English": 'Profiles' }, - "palette":{ - "Spanish":'Paleta de Colores', - "English":'Pallete' + "palette": { + "Spanish": 'Paleta de Colores', + "English": 'Pallete' }, - "change":{ - "Spanish":'Cambiar', - "English":'Change' + "change": { + "Spanish": 'Cambiar', + "English": 'Change' }, - "glow":{ - "Spanish":'Brillar', - "English":'Glow' + "glow": { + "Spanish": 'Brillar', + "English": 'Glow' }, - "glow_scale":{ - "Spanish":'Escala de Brillo', - "English":'Glow Scale' + "glow_scale": { + "Spanish": 'Escala de Brillo', + "English": 'Glow Scale' }, - "time_delay":{ - "Spanish":'Intervalo de Tiempo', - "English":'Time Delay' + "time_delay": { + "Spanish": 'Intervalo de Tiempo', + "English": 'Time Delay' }, - "reset_values":{ - "Spanish":'Reiniciar Valores', - "English":'Reset Values' + "reset_values": { + "Spanish": 'Reiniciar Valores', + "English": 'Reset Values' }, - "players":{ - "Spanish":'Jugadores', - "English":'Players' + "players": { + "Spanish": 'Jugadores', + "English": 'Players' }, - "apply_to_color":{ - "Spanish":'Color Principal', - "English":'Main Color' + "apply_to_color": { + "Spanish": 'Color Principal', + "English": 'Main Color' }, - "apply_to_highlight":{ - "Spanish":'Color de Resalte', - "English":'Highlight Color' + "apply_to_highlight": { + "Spanish": 'Color de Resalte', + "English": 'Highlight Color' }, - "apply_to_name":{ - "Spanish":'Color del Nombre', - "English":'Name Color' + "apply_to_name": { + "Spanish": 'Color del Nombre', + "English": 'Name Color' }, - "additional_features":{ - "Spanish":'Ajustes Adicionales', - "English":'Additional Features' + "additional_features": { + "Spanish": 'Ajustes Adicionales', + "English": 'Additional Features' }, - "apply_to_bots":{ - "Spanish":'Color Principal de Bots', - "English":'Bots Main Color' + "apply_to_bots": { + "Spanish": 'Color Principal de Bots', + "English": 'Bots Main Color' }, - "apply_to_shields":{ - "Spanish":'Escudos de Colores', - "English":'Apply to Shields' + "apply_to_shields": { + "Spanish": 'Escudos de Colores', + "English": 'Apply to Shields' }, - "apply_to_explotions":{ - "Spanish":'Explosiones de Colores', - "English":'Apply to Explotions' + "apply_to_explotions": { + "Spanish": 'Explosiones de Colores', + "English": 'Apply to Explotions' }, - "apply_to_flags":{ - "Spanish":'Banderas de Colores', - "English":'Apply to Flags' + "apply_to_flags": { + "Spanish": 'Banderas de Colores', + "English": 'Apply to Flags' }, - "pick_color":{ - "Spanish":'Selecciona un Color', - "English":'Pick a Color' + "pick_color": { + "Spanish": 'Selecciona un Color', + "English": 'Pick a Color' }, - "add_color":{ - "Spanish":'Agregar Color', - "English":'Add Color' + "add_color": { + "Spanish": 'Agregar Color', + "English": 'Add Color' }, - "remove_color":{ - "Spanish":'Quitar Color', - "English":'Remove Color' + "remove_color": { + "Spanish": 'Quitar Color', + "English": 'Remove Color' }, - "clean_explotions":{ - "Spanish":'Limpiar Explosiones', - "English":'Remove Scorch' + "clean_explotions": { + "Spanish": 'Limpiar Explosiones', + "English": 'Remove Scorch' }, - "restore_default_settings":{ - "Spanish":'Restaurar Ajustes Por Defecto', - "English":'Restore Default Settings' + "restore_default_settings": { + "Spanish": 'Restaurar Ajustes Por Defecto', + "English": 'Restore Default Settings' }, - "settings_restored":{ - "Spanish":'Ajustes Restaurados', - "English":'Settings Restored' + "settings_restored": { + "Spanish": 'Ajustes Restaurados', + "English": 'Settings Restored' }, - "restore_settings":{ - "Spanish":'¿Restaurar Ajustes Por Defecto?', - "English":'Restore Default Settings?' + "restore_settings": { + "Spanish": '¿Restaurar Ajustes Por Defecto?', + "English": 'Restore Default Settings?' }, - "nothing_selected":{ - "Spanish":'Nada Seleccionado', - "English":'Nothing Selected' + "nothing_selected": { + "Spanish": 'Nada Seleccionado', + "English": 'Nothing Selected' }, - "color_already":{ - "Spanish":'Este Color Ya Existe En La Paleta', - "English":'Color Already In The Palette' + "color_already": { + "Spanish": 'Este Color Ya Existe En La Paleta', + "English": 'Color Already In The Palette' }, - "tap_color":{ - "Spanish":'Toca un color para quitarlo.', - "English":'Tap to remove a color.' + "tap_color": { + "Spanish": 'Toca un color para quitarlo.', + "English": 'Tap to remove a color.' }, } - lans = ["Spanish","English"] + lans = ["Spanish", "English"] if actLan not in lans: actLan = "English" return colorsModsLan[text][actLan] - + # ba_meta export plugin class ColorsMod(babase.Plugin): - #PLUGINS PLUS COMPATIBILITY + # PLUGINS PLUS COMPATIBILITY version = "1.7.2" logo = 'gameCenterIcon' - logo_color = (1,1,1) + logo_color = (1, 1, 1) plugin_type = 'mod' - def has_settings_ui (self): + def has_settings_ui(self): return True def show_settings_ui(self, button): ColorsMenu() if bs.app.lang.language == "Spanish": - information = ("Modifica y aplica efectos\n" - "a los colores de tu personaje,\n" - "explosiones, bots, escudos,\n" - "entre otras cosas...\n\n" - "Programado por Froshlee14\nTraducido por CerdoGordo\n\n" - "ADVERTENCIA\nEste mod puede ocacionar\n" - "efectos de epilepsia\na personas sensibles.") + information = ("Modifica y aplica efectos\n" + "a los colores de tu personaje,\n" + "explosiones, bots, escudos,\n" + "entre otras cosas...\n\n" + "Programado por Froshlee14\nTraducido por CerdoGordo\n\n" + "ADVERTENCIA\nEste mod puede ocacionar\n" + "efectos de epilepsia\na personas sensibles.") else: - information = ("Modify and add effects\n" - "to your character colours.\n" - "And other stuff...\n\n" - "Coded by Froshlee14\nTranslated by CerdoGordo\n\n" - "WARNING\nThis mod can cause epileptic\n" - "seizures especially\nwith sensitive people") + information = ("Modify and add effects\n" + "to your character colours.\n" + "And other stuff...\n\n" + "Coded by Froshlee14\nTranslated by CerdoGordo\n\n" + "WARNING\nThis mod can cause epileptic\n" + "seizures especially\nwith sensitive people") def on_app_running(self) -> None: @@ -246,23 +252,22 @@ def on_app_running(self) -> None: oldConfig = babase.app.config["colorsMod"] for setting in newConfig: if setting not in oldConfig: - babase.app.config["colorsMod"].update({setting:newConfig[setting]}) - bs.broadcastmessage(('Colors Mod: config updated'),color=(1,1,0)) + babase.app.config["colorsMod"].update({setting: newConfig[setting]}) + bs.broadcastmessage(('Colors Mod: config updated'), color=(1, 1, 0)) removeList = [] for setting in oldConfig: if setting not in newConfig: removeList.append(setting) - for element in removeList : + for element in removeList: babase.app.config["colorsMod"].pop(element) - bs.broadcastmessage(('Colors Mod: old config deleted'),color=(1,1,0)) + bs.broadcastmessage(('Colors Mod: old config deleted'), color=(1, 1, 0)) else: babase.app.config["colorsMod"] = newConfig babase.app.config.apply_and_commit() - - #MainMenuActivity.oldMakeWord = MainMenuActivity._make_word - #def newMakeWord(self, word: str, + # MainMenuActivity.oldMakeWord = MainMenuActivity._make_word + # def newMakeWord(self, word: str, # x: float, # y: float, # scale: float = 1.0, @@ -274,11 +279,12 @@ def on_app_running(self) -> None: # if word.node.getnodetype(): # if word.node.color[3] == 1.0: # word.node.color = getRandomColor() - #MainMenuActivity._make_word = newMakeWord + # MainMenuActivity._make_word = newMakeWord #### GAME MODIFICATIONS #### - #ESCUDO DE COLORES + # ESCUDO DE COLORES + def new_equip_shields(self, decay: bool = False) -> None: if not self.node: babase.print_error('Can\'t equip shields; no node.') @@ -286,8 +292,8 @@ def new_equip_shields(self, decay: bool = False) -> None: factory = SpazFactory.get() if self.shield is None: - self.shield = bs.newnode('shield',owner=self.node,attrs={ - 'color': (0.3, 0.2, 2.0),'radius': 1.3 }) + self.shield = bs.newnode('shield', owner=self.node, attrs={ + 'color': (0.3, 0.2, 2.0), 'radius': 1.3}) self.node.connectattr('position_center', self.shield, 'position') self.shield_hitpoints = self.shield_hitpoints_max = 650 self.shield_decay_rate = factory.shield_decay_rate if decay else 0 @@ -295,69 +301,76 @@ def new_equip_shields(self, decay: bool = False) -> None: factory.shield_up_sound.play(1.0, position=self.node.position) if self.shield_decay_rate > 0: - self.shield_decay_timer = bs.Timer(0.5,bs.WeakCall(self.shield_decay),repeat=True) + self.shield_decay_timer = bs.Timer(0.5, bs.WeakCall(self.shield_decay), repeat=True) self.shield.always_show_health_bar = True + def changeColor(): - if self.shield is None: return + if self.shield is None: + return if getData("shieldColor"): self.shield.color = c = getRandomColor() - self._shieldTimer = bs.Timer(getData("timeDelay") / 1000,changeColor,repeat=True) + self._shieldTimer = bs.Timer(getData("timeDelay") / 1000, changeColor, repeat=True) PlayerSpaz.equip_shields = new_equip_shields - #BOTS DE COLORES + # BOTS DE COLORES SpazBot.oldBotInit = SpazBot.__init__ + def newBotInit(self, *args, **kwargs): self.oldBotInit(*args, **kwargs) s = 1 if getData("glowBots"): s = getData("glowScale") - - self.node.highlight = (self.node.highlight[0]*s,self.node.highlight[1]*s,self.node.highlight[2]*s) + + self.node.highlight = (self.node.highlight[0]*s, + self.node.highlight[1]*s, self.node.highlight[2]*s) def changeColor(): if self.is_alive(): if getData("colorBots"): c = getRandomColor() - self.node.highlight = (c[0]*s,c[1]*s,c[2]*s) - self._timer = bs.Timer(getData("timeDelay") / 1000 ,changeColor,repeat=True) + self.node.highlight = (c[0]*s, c[1]*s, c[2]*s) + self._timer = bs.Timer(getData("timeDelay") / 1000, changeColor, repeat=True) SpazBot.__init__ = newBotInit - #BANDERA DE COLORES + # BANDERA DE COLORES Flag.oldFlagInit = Flag.__init__ - def newFlaginit(self,position: Sequence[float] = (0.0, 1.0, 0.0), - color: Sequence[float] = (1.0, 1.0, 1.0), - materials: Sequence[bs.Material] = None, - touchable: bool = True, - dropped_timeout: int = None): - self.oldFlagInit(position, color,materials,touchable,dropped_timeout) - + + def newFlaginit(self, position: Sequence[float] = (0.0, 1.0, 0.0), + color: Sequence[float] = (1.0, 1.0, 1.0), + materials: Sequence[bs.Material] = None, + touchable: bool = True, + dropped_timeout: int = None): + self.oldFlagInit(position, color, materials, touchable, dropped_timeout) + def cC(): if self.node.exists(): if getData("flag"): c = getRandomColor() - self.node.color = (c[0]*1.2,c[1]*1.2,c[2]*1.2) - else: return - if touchable : - self._timer = bs.Timer(getData("timeDelay") / 1000 ,cC,repeat=True) - + self.node.color = (c[0]*1.2, c[1]*1.2, c[2]*1.2) + else: + return + if touchable: + self._timer = bs.Timer(getData("timeDelay") / 1000, cC, repeat=True) + Flag.__init__ = newFlaginit - #JUGADORES DE COLORES + # JUGADORES DE COLORES PlayerSpaz.oldInit = PlayerSpaz.__init__ - def newInit(self,player: bs.Player, - color: Sequence[float] = (1.0, 1.0, 1.0), - highlight: Sequence[float] = (0.5, 0.5, 0.5), - character: str = 'Spaz', - powerups_expire: bool = True): - self.oldInit(player,color,highlight,character,powerups_expire) + + def newInit(self, player: bs.Player, + color: Sequence[float] = (1.0, 1.0, 1.0), + highlight: Sequence[float] = (0.5, 0.5, 0.5), + character: str = 'Spaz', + powerups_expire: bool = True): + self.oldInit(player, color, highlight, character, powerups_expire) players = [] for p in getData("activeProfiles"): players.append(p) for x in range(len(players)): - if players[x] == "__account__" : - players[x] = bui.app.plus.get_v1_account_name()#_babase.get_v1_account_name() + if players[x] == "__account__": + players[x] = bui.app.plus.get_v1_account_name() # _babase.get_v1_account_name() if player.getname() in players: s = s2 = s3 = 1 @@ -368,31 +381,35 @@ def newInit(self,player: bs.Player, if getData("glowName"): s3 = getData("glowScale") - self.node.color = (self.node.color[0]*s,self.node.color[1]*s,self.node.color[2]*s) - self.node.highlight = (self.node.highlight[0]*s2,self.node.highlight[1]*s2,self.node.highlight[2]*s2) - self.node.name_color = (self.node.name_color[0]*s3,self.node.name_color[1]*s3,self.node.name_color[2]*s3) + self.node.color = (self.node.color[0]*s, self.node.color[1]*s, self.node.color[2]*s) + self.node.highlight = ( + self.node.highlight[0]*s2, self.node.highlight[1]*s2, self.node.highlight[2]*s2) + self.node.name_color = ( + self.node.name_color[0]*s3, self.node.name_color[1]*s3, self.node.name_color[2]*s3) def changeColor(): if self.is_alive(): if getData("colorPlayer"): c = getRandomColor() - self.node.color = (c[0]*s,c[1]*s,c[2]*s) + self.node.color = (c[0]*s, c[1]*s, c[2]*s) if getData("higlightPlayer"): c = getRandomColor() - self.node.highlight = (c[0]*s2,c[1]*s2,c[2]*s2) + self.node.highlight = (c[0]*s2, c[1]*s2, c[2]*s2) if getData("namePlayer"): c = getRandomColor() - self.node.name_color = (c[0]*s3,c[1]*s3,c[2]*s3) - self._timer = bs.Timer(getData("timeDelay") / 1000 ,changeColor,repeat=True) + self.node.name_color = (c[0]*s3, c[1]*s3, c[2]*s3) + self._timer = bs.Timer(getData("timeDelay") / 1000, changeColor, repeat=True) PlayerSpaz.__init__ = newInit - #EXPLOSIONES DE COLORES + # EXPLOSIONES DE COLORES bomb.Blast.oldBlastInit = bomb.Blast.__init__ + def newBlastInit(self, position: Sequence[float] = (0.0, 1.0, 0.0), velocity: Sequence[float] = (0.0, 0.0, 0.0), - blast_radius: float = 2.0, blast_type: str = 'normal', source_player: bs.Player = None, - hit_type: str = 'explosion', hit_subtype: str = 'normal'): + blast_radius: float = 2.0, blast_type: str = 'normal', source_player: bs.Player = None, + hit_type: str = 'explosion', hit_subtype: str = 'normal'): - self.oldBlastInit(position, velocity, blast_radius, blast_type, source_player, hit_type, hit_subtype) + self.oldBlastInit(position, velocity, blast_radius, blast_type, + source_player, hit_type, hit_subtype) if getData("xplotionColor"): c = getRandomColor() @@ -405,16 +422,21 @@ def newBlastInit(self, position: Sequence[float] = (0.0, 1.0, 0.0), velocity: S scl *= 3.0 for i in range(2): - scorch = bs.newnode('scorch',attrs={'position':self.node.position, 'size':scorch_radius*0.5,'big':(self.blast_type == 'tnt')}) - if self.blast_type == 'ice': scorch.color =(1,1,1.5) - else: scorch.color = c + scorch = bs.newnode('scorch', attrs={ + 'position': self.node.position, 'size': scorch_radius*0.5, 'big': (self.blast_type == 'tnt')}) + if self.blast_type == 'ice': + scorch.color = (1, 1, 1.5) + else: + scorch.color = c if getData("xplotionColor"): if getData("delScorch"): - bs.animate(scorch,"presence",{3:1, 13:0}) - bs.Timer(13,scorch.delete) + bs.animate(scorch, "presence", {3: 1, 13: 0}) + bs.Timer(13, scorch.delete) - if self.blast_type == 'ice': return - light = bs.newnode('light', attrs={ 'position': position,'volume_intensity_scale': 10.0,'color': c}) + if self.blast_type == 'ice': + return + light = bs.newnode('light', attrs={'position': position, + 'volume_intensity_scale': 10.0, 'color': c}) iscale = 1.6 bs.animate(light, 'intensity', { @@ -458,48 +480,48 @@ def __init__(self): items.sort(key=lambda x: x[0].lower()) accountName: Optional[str] - if bui.app.plus.get_v1_account_state() == 'signed_in': + if bui.app.plus.get_v1_account_state() == 'signed_in': accountName = bui.app.plus.get_v1_account_display_string() - else: accountName = None - #subHeight += (len(items)*45) + else: + accountName = None + # subHeight += (len(items)*45) # creates our _root_widget popup.PopupWindow.__init__(self, - position=(0,0), + position=(0, 0), size=(self._width, self._height), scale=scale, bg_color=bg_color) - self._cancel_button = bui.buttonwidget( parent=self.root_widget, - position=(50, self._height - 30), size=(50, 50), - scale=0.5, label='', - color=bg_color, - on_activate_call=self._on_cancel_press, - autoselect=True, - icon=bui.gettexture('crossOut'), - iconscale=1.2) - bui.containerwidget(edit=self.root_widget,cancel_button=self._cancel_button) - + self._cancel_button = bui.buttonwidget(parent=self.root_widget, + position=(50, self._height - 30), size=(50, 50), + scale=0.5, label='', + color=bg_color, + on_activate_call=self._on_cancel_press, + autoselect=True, + icon=bui.gettexture('crossOut'), + iconscale=1.2) + bui.containerwidget(edit=self.root_widget, cancel_button=self._cancel_button) self._title_text = bui.textwidget(parent=self.root_widget, - position=(self._width * 0.5,self._height - 20), - size=(0, 0), - h_align='center', - v_align='center', - scale=01.0, - text=getTranslation('profiles'), - maxwidth=200, - color=(1, 1, 1, 0.4)) + position=(self._width * 0.5, self._height - 20), + size=(0, 0), + h_align='center', + v_align='center', + scale=01.0, + text=getTranslation('profiles'), + maxwidth=200, + color=(1, 1, 1, 0.4)) self._scrollwidget = bui.scrollwidget(parent=self.root_widget, - size=(self._width - 60, - self._height - 70), - position=(30, 30), - capture_arrows=True, - simple_culling_v=10) + size=(self._width - 60, + self._height - 70), + position=(30, 30), + capture_arrows=True, + simple_culling_v=10) bui.widget(edit=self._scrollwidget, autoselect=True) - #incr = 36 + # incr = 36 sub_width = self._width - 90 sub_height = (len(items)*50) @@ -507,8 +529,8 @@ def __init__(self): pts_rsrc = 'coopSelectWindow.powerRankingPointsText' self._subcontainer = box = bui.containerwidget(parent=self._scrollwidget, - size=(sub_width, sub_height), - background=False) + size=(sub_width, sub_height), + background=False) h = 20 v = sub_height - 60 for pName, p in items: @@ -518,14 +540,14 @@ def __init__(self): tval = (accountName if pName == '__account__' else get_player_profile_icon(pName) + pName) assert isinstance(tval, str) - #print(tval) + # print(tval) value = True if pName in self._activeProfiles else False - w = bui.checkboxwidget(parent=box,position=(10,v), value=value, - on_value_change_call=bs.WeakCall(self.select, pName), - maxwidth=sub_width,size=(sub_width,50), - textcolor = color, - text=babase.Lstr(value=tval),autoselect=True) + w = bui.checkboxwidget(parent=box, position=(10, v), value=value, + on_value_change_call=bs.WeakCall(self.select, pName), + maxwidth=sub_width, size=(sub_width, 50), + textcolor=color, + text=babase.Lstr(value=tval), autoselect=True) v -= 45 def addProfile(self): @@ -534,7 +556,8 @@ def addProfile(self): self._activeProfiles.append(self._selected) babase.app.config["colorsMod"]["activeProfiles"] = self._activeProfiles babase.app.config.apply_and_commit() - else: bs.broadcastmessage(getTranslation('nothing_selected')) + else: + bs.broadcastmessage(getTranslation('nothing_selected')) def removeProfile(self): if self._selected is not None: @@ -542,13 +565,17 @@ def removeProfile(self): self._activeProfiles.remove(self._selected) babase.app.config["colorsMod"]["activeProfiles"] = self._activeProfiles babase.app.config.apply_and_commit() - else: print('not found') - else: bs.broadcastmessage(getTranslation('nothing_selected')) + else: + print('not found') + else: + bs.broadcastmessage(getTranslation('nothing_selected')) - def select(self,name,m): + def select(self, name, m): self._selected = name - if m == 0: self.removeProfile() - else: self.addProfile() + if m == 0: + self.removeProfile() + else: + self.addProfile() def _on_cancel_press(self) -> None: self._transition_out() @@ -565,19 +592,19 @@ def on_popup_cancel(self) -> None: class ColorsMenu(PopupWindow): - def __init__(self,transition='in_right'): - #self._width = width = 650 + def __init__(self, transition='in_right'): + # self._width = width = 650 self._width = width = 800 self._height = height = 450 self._scrollWidth = self._width*0.85 self._scrollHeight = self._height - 120 - self._subWidth = self._scrollWidth*0.95; + self._subWidth = self._scrollWidth*0.95 self._subHeight = 200 - + self._current_tab = getData('actab') - self._timeDelay = getData("timeDelay") - self._glowScale = getData("glowScale") + self._timeDelay = getData("timeDelay") + self._glowScale = getData("glowScale") self.midwidth = self._scrollWidth*0.45 self.qwidth = self.midwidth*0.4 @@ -589,58 +616,61 @@ def __init__(self,transition='in_right'): self._in_game = not isinstance(bs.get_foreground_host_session(), MainMenuSession) - self._root_widget = bui.containerwidget(size=(width,height),transition=transition, - scale=1.5 if uiscale is babase.UIScale.SMALL else 1.0, - stack_offset=(0,-5) if uiscale is babase.UIScale.SMALL else (0,0)) - - self._title = bui.textwidget(parent=self._root_widget,position=(50,height-40),text='', - maxwidth=self._scrollWidth,size=(self._scrollWidth,20), - color=(0.8,0.8,0.8,1.0),h_align="center",scale=1.1) - - self._backButton = b = bui.buttonwidget(parent=self._root_widget,autoselect=True, - position=(50,height-60),size=(120,50), - scale=0.8,text_scale=1.2,label=babase.Lstr(resource='backText'), - button_type='back',on_activate_call=self._back) - bui.buttonwidget(edit=self._backButton, button_type='backSmall',size=(50, 50),label=babase.charstr(babase.SpecialChar.BACK)) - bui.containerwidget(edit=self._root_widget,cancel_button=b) - - self._nextButton = bui.buttonwidget(parent=self._root_widget,autoselect=True, - position=(width-60,height*0.5-20),size=(50,50), - scale=1.0,label=babase.charstr(babase.SpecialChar.RIGHT_ARROW), - color=(0.2,1,0.2),button_type='square', - on_activate_call=self.nextTabContainer) - - self._prevButton = bui.buttonwidget(parent=self._root_widget,autoselect=True, - position=(10,height*0.5-20),size=(50,50), - scale=1.0,label=babase.charstr(babase.SpecialChar.LEFT_ARROW), - color=(0.2,1,0.2),button_type='square', - on_activate_call=self.prevTabContainer) - + self._root_widget = bui.containerwidget(size=(width, height), transition=transition, + scale=1.5 if uiscale is babase.UIScale.SMALL else 1.0, + stack_offset=(0, -5) if uiscale is babase.UIScale.SMALL else (0, 0)) + + self._title = bui.textwidget(parent=self._root_widget, position=(50, height-40), text='', + maxwidth=self._scrollWidth, size=(self._scrollWidth, 20), + color=(0.8, 0.8, 0.8, 1.0), h_align="center", scale=1.1) + + self._backButton = b = bui.buttonwidget(parent=self._root_widget, autoselect=True, + position=(50, height-60), size=(120, 50), + scale=0.8, text_scale=1.2, label=babase.Lstr(resource='backText'), + button_type='back', on_activate_call=self._back) + bui.buttonwidget(edit=self._backButton, button_type='backSmall', size=( + 50, 50), label=babase.charstr(babase.SpecialChar.BACK)) + bui.containerwidget(edit=self._root_widget, cancel_button=b) + + self._nextButton = bui.buttonwidget(parent=self._root_widget, autoselect=True, + position=(width-60, height*0.5-20), size=(50, 50), + scale=1.0, label=babase.charstr(babase.SpecialChar.RIGHT_ARROW), + color=(0.2, 1, 0.2), button_type='square', + on_activate_call=self.nextTabContainer) + + self._prevButton = bui.buttonwidget(parent=self._root_widget, autoselect=True, + position=(10, height*0.5-20), size=(50, 50), + scale=1.0, label=babase.charstr(babase.SpecialChar.LEFT_ARROW), + color=(0.2, 1, 0.2), button_type='square', + on_activate_call=self.prevTabContainer) + v = self._subHeight - 55 v0 = height - 90 self.tabs = [ - [0,getTranslation('general_tab')], - [1,getTranslation('player_tab')], - [2,getTranslation('extras_tab')], - [3,getTranslation('info_tab')], - ] - - self._scrollwidget = sc = bui.scrollwidget(parent=self._root_widget,size=(self._subWidth,self._scrollHeight),border_opacity=0.3, highlight=False, position=((width*0.5)-(self._scrollWidth*0.47),50),capture_arrows=True,) + [0, getTranslation('general_tab')], + [1, getTranslation('player_tab')], + [2, getTranslation('extras_tab')], + [3, getTranslation('info_tab')], + ] + + self._scrollwidget = sc = bui.scrollwidget(parent=self._root_widget, size=( + self._subWidth, self._scrollHeight), border_opacity=0.3, highlight=False, position=((width*0.5)-(self._scrollWidth*0.47), 50), capture_arrows=True,) bui.widget(edit=sc, left_widget=self._prevButton) bui.widget(edit=sc, right_widget=self._nextButton) bui.widget(edit=self._backButton, down_widget=sc) self.tabButtons = [] - h = 330 + h = 330 for i in range(3): - tabButton = bui.buttonwidget(parent=self._root_widget,autoselect=True, - position=(h,20),size=(20,20), - scale=1.2,label='', - color=(0.3,0.9,0.3), - on_activate_call=babase.Call(self._setTab,self.tabs[i][0]), - texture=bui.gettexture('nub')) + tabButton = bui.buttonwidget(parent=self._root_widget, autoselect=True, + position=(h, 20), size=(20, 20), + scale=1.2, label='', + color=(0.3, 0.9, 0.3), + on_activate_call=babase.Call( + self._setTab, self.tabs[i][0]), + texture=bui.gettexture('nub')) self.tabButtons.append(tabButton) h += 50 self._tabContainer = None @@ -648,15 +678,19 @@ def __init__(self,transition='in_right'): def nextTabContainer(self): tab = babase.app.config['colorsMod']['actab'] - if tab == 2: self._setTab(0) - else: self._setTab(tab+1) + if tab == 2: + self._setTab(0) + else: + self._setTab(tab+1) def prevTabContainer(self): tab = babase.app.config['colorsMod']['actab'] - if tab == 0: self._setTab(2) - else: self._setTab(tab-1) - - def _setTab(self,tab): + if tab == 0: + self._setTab(2) + else: + self._setTab(tab-1) + + def _setTab(self, tab): self._colorTimer = None self._current_tab = tab @@ -668,334 +702,345 @@ def _setTab(self,tab): self._tabContainer.delete() self._tabData = {} - if tab == 0: #general + if tab == 0: # general subHeight = 0 - self._tabContainer = c = bui.containerwidget(parent=self._scrollwidget,size=(self._subWidth,subHeight), - background=False,selection_loops_to_parent=True) - - bui.textwidget(edit=self._title,text=getTranslation('general_tab')) + self._tabContainer = c = bui.containerwidget(parent=self._scrollwidget, size=(self._subWidth, subHeight), + background=False, selection_loops_to_parent=True) + + bui.textwidget(edit=self._title, text=getTranslation('general_tab')) v0 = subHeight - 30 v = v0 - 10 - + h = self._scrollWidth*0.12 cSpacing = self._scrollWidth*0.15 - t = bui.textwidget(parent=c,position=(0,v), - text=getTranslation('glow_scale'), - maxwidth=self.midwidth ,size=(self.midwidth ,20),color=(0.8,0.8,0.8,1.0),h_align="center") - v -= 45 - b = bui.buttonwidget(parent=c,position=(h-20,v-12),size=(40,40),label="-", - autoselect=True,on_activate_call=babase.Call(self._glowScaleDecrement),repeat=True,enable_sound=True,button_type='square') + t = bui.textwidget(parent=c, position=(0, v), + text=getTranslation('glow_scale'), + maxwidth=self.midwidth, size=(self.midwidth, 20), color=(0.8, 0.8, 0.8, 1.0), h_align="center") + v -= 45 + b = bui.buttonwidget(parent=c, position=(h-20, v-12), size=(40, 40), label="-", + autoselect=True, on_activate_call=babase.Call(self._glowScaleDecrement), repeat=True, enable_sound=True, button_type='square') - self._glowScaleText = bui.textwidget(parent=c,position=(h+20,v),maxwidth=cSpacing, - size=(cSpacing,20),editable=False,color=(0.3,1.0,0.3),h_align="center",text=str(self._glowScale)) + self._glowScaleText = bui.textwidget(parent=c, position=(h+20, v), maxwidth=cSpacing, + size=(cSpacing, 20), editable=False, color=(0.3, 1.0, 0.3), h_align="center", text=str(self._glowScale)) - b2 = bui.buttonwidget(parent=c,position=(h+cSpacing+20,v-12),size=(40,40),label="+", - autoselect=True,on_activate_call=babase.Call(self._glowScaleIncrement),repeat=True,enable_sound=True,button_type='square') + b2 = bui.buttonwidget(parent=c, position=(h+cSpacing+20, v-12), size=(40, 40), label="+", + autoselect=True, on_activate_call=babase.Call(self._glowScaleIncrement), repeat=True, enable_sound=True, button_type='square') v -= 70 - t = bui.textwidget(parent=c,position=(0,v), - text=getTranslation('time_delay'), - maxwidth=self.midwidth ,size=(self.midwidth ,20),color=(0.8,0.8,0.8,1.0),h_align="center") - v -= 45 - a = bui.buttonwidget(parent=c,position=(h-20,v-12),size=(40,40),label="-", - autoselect=True,on_activate_call=babase.Call(self._timeDelayDecrement),repeat=True,enable_sound=True,button_type='square') - - self._timeDelayText = bui.textwidget(parent=c,position=(h+20,v),maxwidth=self._scrollWidth*0.9, - size=(cSpacing,20),editable=False,color=(0.3,1.0,0.3,1.0),h_align="center",text=str(self._timeDelay)) - - a2 = bui.buttonwidget(parent=c,position=(h+cSpacing+20,v-12),size=(40,40),label="+", - autoselect=True,on_activate_call=babase.Call(self._timeDelayIncrement),repeat=True,enable_sound=True,button_type='square') - + t = bui.textwidget(parent=c, position=(0, v), + text=getTranslation('time_delay'), + maxwidth=self.midwidth, size=(self.midwidth, 20), color=(0.8, 0.8, 0.8, 1.0), h_align="center") + v -= 45 + a = bui.buttonwidget(parent=c, position=(h-20, v-12), size=(40, 40), label="-", + autoselect=True, on_activate_call=babase.Call(self._timeDelayDecrement), repeat=True, enable_sound=True, button_type='square') + + self._timeDelayText = bui.textwidget(parent=c, position=(h+20, v), maxwidth=self._scrollWidth*0.9, + size=(cSpacing, 20), editable=False, color=(0.3, 1.0, 0.3, 1.0), h_align="center", text=str(self._timeDelay)) + + a2 = bui.buttonwidget(parent=c, position=(h+cSpacing+20, v-12), size=(40, 40), label="+", + autoselect=True, on_activate_call=babase.Call(self._timeDelayIncrement), repeat=True, enable_sound=True, button_type='square') + v -= 70 reset = bui.buttonwidget(parent=c, autoselect=True, - position=((self._scrollWidth*0.22)-80, v-25), size=(160,50),scale=1.0, text_scale=1.2,textcolor=(1,1,1), - label=getTranslation('reset_values'),on_activate_call=self._resetValues) + position=((self._scrollWidth*0.22)-80, v-25), size=(160, 50), scale=1.0, text_scale=1.2, textcolor=(1, 1, 1), + label=getTranslation('reset_values'), on_activate_call=self._resetValues) self._updateColorTimer() v = v0 h = self._scrollWidth*0.44 - t = bui.textwidget(parent=c,position=(h,v), - text=getTranslation('palette'), - maxwidth=self.midwidth ,size=(self.midwidth ,20), - color=(0.8,0.8,0.8,1.0),h_align="center") + t = bui.textwidget(parent=c, position=(h, v), + text=getTranslation('palette'), + maxwidth=self.midwidth, size=(self.midwidth, 20), + color=(0.8, 0.8, 0.8, 1.0), h_align="center") v -= 30 - t2 = bui.textwidget(parent=c,position=(h,v), - text=getTranslation('tap_color'), scale=0.9, - maxwidth=self.midwidth ,size=(self.midwidth ,20), - color=(0.6,0.6,0.6,1.0),h_align="center") + t2 = bui.textwidget(parent=c, position=(h, v), + text=getTranslation('tap_color'), scale=0.9, + maxwidth=self.midwidth, size=(self.midwidth, 20), + color=(0.6, 0.6, 0.6, 1.0), h_align="center") v -= 20 sp = h+45 - self.updatePalette(v,sp) + self.updatePalette(v, sp) elif tab == 1: subHeight = self._subHeight - self._tabContainer = c = bui.containerwidget(parent=self._scrollwidget,size=(self._subWidth,subHeight), - background=False,selection_loops_to_parent=True) + self._tabContainer = c = bui.containerwidget(parent=self._scrollwidget, size=(self._subWidth, subHeight), + background=False, selection_loops_to_parent=True) v2 = v = v0 = subHeight - bui.textwidget(edit=self._title,text=getTranslation('player_tab')) + bui.textwidget(edit=self._title, text=getTranslation('player_tab')) t = babase.app.classic.spaz_appearances['Spaz'] tex = bui.gettexture(t.icon_texture) tintTex = bui.gettexture(t.icon_mask_texture) gs = getData("glowScale") - tc = (1,1,1) - t2c = (1,1,1) + tc = (1, 1, 1) + t2c = (1, 1, 1) - v2 -= (50+180) - self._previewImage = bui.imagewidget(parent=c,position=(self._subWidth*0.72-100,v2),size=(200,200), - mask_texture=bui.gettexture('characterIconMask'),tint_texture=tintTex, - texture=tex, mesh_transparent=bui.getmesh('image1x1'), - tint_color=(tc[0]*gs,tc[1]*gs,tc[2]*gs),tint2_color=(t2c[0]*gs,t2c[1]*gs,t2c[2]*gs)) + v2 -= (50+180) + self._previewImage = bui.imagewidget(parent=c, position=(self._subWidth*0.72-100, v2), size=(200, 200), + mask_texture=bui.gettexture('characterIconMask'), tint_texture=tintTex, + texture=tex, mesh_transparent=bui.getmesh( + 'image1x1'), + tint_color=(tc[0]*gs, tc[1]*gs, tc[2]*gs), tint2_color=(t2c[0]*gs, t2c[1]*gs, t2c[2]*gs)) self._colorTimer = bui.AppTimer(getData("timeDelay") / 1000, - babase.Call(self._updatePreview),repeat=True) + babase.Call(self._updatePreview), repeat=True) v2 -= 70 def doProfileWindow(): ProfilesWindow() - reset = bui.buttonwidget(parent=c, autoselect=True,on_activate_call=doProfileWindow, - position=(self._subWidth*0.72-100,v2), size=(200,60),scale=1.0, text_scale=1.2,textcolor=(1,1,1), - label=getTranslation('profiles')) + reset = bui.buttonwidget(parent=c, autoselect=True, on_activate_call=doProfileWindow, + position=(self._subWidth*0.72-100, v2), size=(200, 60), scale=1.0, text_scale=1.2, textcolor=(1, 1, 1), + label=getTranslation('profiles')) miniBoxWidth = self.midwidth - 30 miniBoxHeight = 80 v -= 18 - #Color + # Color h = 50 - box1 = bui.containerwidget(parent=c,position=(h,v-miniBoxHeight), - size=(miniBoxWidth,miniBoxHeight),background=True) - vbox1 = miniBoxHeight -25 - t = bui.textwidget(parent=box1,position=(10,vbox1), - text=getTranslation('apply_to_color'), - maxwidth=miniBoxWidth-20,size=(miniBoxWidth,20),color=(0.8,0.8,0.8,1.0),h_align="left") + box1 = bui.containerwidget(parent=c, position=(h, v-miniBoxHeight), + size=(miniBoxWidth, miniBoxHeight), background=True) + vbox1 = miniBoxHeight - 25 + t = bui.textwidget(parent=box1, position=(10, vbox1), + text=getTranslation('apply_to_color'), + maxwidth=miniBoxWidth-20, size=(miniBoxWidth, 20), color=(0.8, 0.8, 0.8, 1.0), h_align="left") vbox1 -= 45 - self.bw = bui.checkboxwidget(parent=box1,position=(10,vbox1), value=getData("colorPlayer"), - on_value_change_call=babase.Call(self._setSetting,'colorPlayer'), maxwidth=self.qwidth, - text=getTranslation('change'),autoselect=True,size=(self.qwidth,25)) - #vbox1 -= 35 - self.bw = bui.checkboxwidget(parent=box1,position=(25+self.qwidth,vbox1), value=getData("glowColor"), - on_value_change_call=babase.Call(self._setSetting,'glowColor'), maxwidth=self.qwidth, - text=getTranslation('glow'),autoselect=True,size=(self.qwidth,25)) + self.bw = bui.checkboxwidget(parent=box1, position=(10, vbox1), value=getData("colorPlayer"), + on_value_change_call=babase.Call(self._setSetting, 'colorPlayer'), maxwidth=self.qwidth, + text=getTranslation('change'), autoselect=True, size=(self.qwidth, 25)) + # vbox1 -= 35 + self.bw = bui.checkboxwidget(parent=box1, position=(25+self.qwidth, vbox1), value=getData("glowColor"), + on_value_change_call=babase.Call(self._setSetting, 'glowColor'), maxwidth=self.qwidth, + text=getTranslation('glow'), autoselect=True, size=(self.qwidth, 25)) v -= (miniBoxHeight+20) - #Highlight - box1 = bui.containerwidget(parent=c,position=(h,v-miniBoxHeight), - size=(miniBoxWidth,miniBoxHeight),background=True) - vbox1 = miniBoxHeight -20 - t = bui.textwidget(parent=box1,position=(10,vbox1), - text=getTranslation('apply_to_highlight'), - maxwidth=miniBoxWidth-20,size=(miniBoxWidth,20),color=(0.8,0.8,0.8,1.0),h_align="left") + # Highlight + box1 = bui.containerwidget(parent=c, position=(h, v-miniBoxHeight), + size=(miniBoxWidth, miniBoxHeight), background=True) + vbox1 = miniBoxHeight - 20 + t = bui.textwidget(parent=box1, position=(10, vbox1), + text=getTranslation('apply_to_highlight'), + maxwidth=miniBoxWidth-20, size=(miniBoxWidth, 20), color=(0.8, 0.8, 0.8, 1.0), h_align="left") vbox1 -= 45 - self.bw = bui.checkboxwidget(parent=box1,position=(10,vbox1), value=getData("higlightPlayer"), - on_value_change_call=babase.Call(self._setSetting,'higlightPlayer'), maxwidth=self.qwidth, - text=getTranslation('change'),autoselect=True,size=(self.qwidth,25)) - #vbox1 -= 35 - self.bw = bui.checkboxwidget(parent=box1,position=(25+self.qwidth,vbox1), value=getData("glowHighlight"), - on_value_change_call=babase.Call(self._setSetting,'glowHighlight'), maxwidth=self.qwidth, - text=getTranslation('glow'),autoselect=True,size=(self.qwidth,25)) + self.bw = bui.checkboxwidget(parent=box1, position=(10, vbox1), value=getData("higlightPlayer"), + on_value_change_call=babase.Call(self._setSetting, 'higlightPlayer'), maxwidth=self.qwidth, + text=getTranslation('change'), autoselect=True, size=(self.qwidth, 25)) + # vbox1 -= 35 + self.bw = bui.checkboxwidget(parent=box1, position=(25+self.qwidth, vbox1), value=getData("glowHighlight"), + on_value_change_call=babase.Call(self._setSetting, 'glowHighlight'), maxwidth=self.qwidth, + text=getTranslation('glow'), autoselect=True, size=(self.qwidth, 25)) v -= (miniBoxHeight+20) - #Name - box1 = bui.containerwidget(parent=c,position=(h,v-miniBoxHeight), - size=(miniBoxWidth,miniBoxHeight),background=True) - vbox1 = miniBoxHeight -20 - t = bui.textwidget(parent=box1,position=(10,vbox1), - text=getTranslation('apply_to_name'), - maxwidth=miniBoxWidth-20,size=(miniBoxWidth,20),color=(0.8,0.8,0.8,1.0),h_align="left") + # Name + box1 = bui.containerwidget(parent=c, position=(h, v-miniBoxHeight), + size=(miniBoxWidth, miniBoxHeight), background=True) + vbox1 = miniBoxHeight - 20 + t = bui.textwidget(parent=box1, position=(10, vbox1), + text=getTranslation('apply_to_name'), + maxwidth=miniBoxWidth-20, size=(miniBoxWidth, 20), color=(0.8, 0.8, 0.8, 1.0), h_align="left") vbox1 -= 40 - self.bw = bui.checkboxwidget(parent=box1,position=(10,vbox1), value=getData("namePlayer"), - on_value_change_call=babase.Call(self._setSetting,'namePlayer'), maxwidth=self.qwidth, - text=getTranslation('change'),autoselect=True,size=(self.qwidth,25)) - #vbox1 -= 35 - self.bw = bui.checkboxwidget(parent=box1,position=(25+self.qwidth,vbox1), value=getData("glowName"), - on_value_change_call=babase.Call(self._setSetting,'glowName'), maxwidth=self.qwidth, - text=getTranslation('glow'),autoselect=True,size=(self.qwidth,25)) + self.bw = bui.checkboxwidget(parent=box1, position=(10, vbox1), value=getData("namePlayer"), + on_value_change_call=babase.Call(self._setSetting, 'namePlayer'), maxwidth=self.qwidth, + text=getTranslation('change'), autoselect=True, size=(self.qwidth, 25)) + # vbox1 -= 35 + self.bw = bui.checkboxwidget(parent=box1, position=(25+self.qwidth, vbox1), value=getData("glowName"), + on_value_change_call=babase.Call(self._setSetting, 'glowName'), maxwidth=self.qwidth, + text=getTranslation('glow'), autoselect=True, size=(self.qwidth, 25)) v -= (miniBoxHeight+50) elif tab == 2: subHeight = 0 - self._tabContainer = c = bui.containerwidget(parent=self._scrollwidget,size=(self._subWidth,subHeight), - background=False,selection_loops_to_parent=True) + self._tabContainer = c = bui.containerwidget(parent=self._scrollwidget, size=(self._subWidth, subHeight), + background=False, selection_loops_to_parent=True) v0 = subHeight - 50 v = v0 h = 30 - bui.textwidget(edit=self._title,text=getTranslation('extras_tab')) - self.bw = bui.checkboxwidget(parent=c,position=(h,v), value=getData("shieldColor"), - on_value_change_call=babase.Call(self._setSetting,'shieldColor'), maxwidth=self.midwidth, - text=getTranslation('apply_to_shields'),autoselect=True,size=(self.midwidth,30)) + bui.textwidget(edit=self._title, text=getTranslation('extras_tab')) + self.bw = bui.checkboxwidget(parent=c, position=(h, v), value=getData("shieldColor"), + on_value_change_call=babase.Call(self._setSetting, 'shieldColor'), maxwidth=self.midwidth, + text=getTranslation('apply_to_shields'), autoselect=True, size=(self.midwidth, 30)) v -= 50 - self.bw = bui.checkboxwidget(parent=c,position=(h,v), value=getData("flag"), - on_value_change_call=babase.Call(self._setSetting,'flag'), maxwidth=self.midwidth, - text=getTranslation('apply_to_flags'),autoselect=True,size=(self.midwidth,30)) + self.bw = bui.checkboxwidget(parent=c, position=(h, v), value=getData("flag"), + on_value_change_call=babase.Call(self._setSetting, 'flag'), maxwidth=self.midwidth, + text=getTranslation('apply_to_flags'), autoselect=True, size=(self.midwidth, 30)) v = v0 h = self.midwidth - self.bw = bui.checkboxwidget(parent=c,position=(h,v), value=getData("xplotionColor"), - on_value_change_call=babase.Call(self._setSetting,'xplotionColor'), maxwidth=self.midwidth, - text=getTranslation('apply_to_explotions'),autoselect=True,size=(self.midwidth,30)) + self.bw = bui.checkboxwidget(parent=c, position=(h, v), value=getData("xplotionColor"), + on_value_change_call=babase.Call(self._setSetting, 'xplotionColor'), maxwidth=self.midwidth, + text=getTranslation('apply_to_explotions'), autoselect=True, size=(self.midwidth, 30)) v -= 50 - self.bw = bui.checkboxwidget(parent=c,position=(h,v), value=getData("delScorch"), - on_value_change_call=babase.Call(self._setSetting,'delScorch'), maxwidth=self.midwidth, - text=getTranslation('clean_explotions'),autoselect=True,size=(self.midwidth,30)) + self.bw = bui.checkboxwidget(parent=c, position=(h, v), value=getData("delScorch"), + on_value_change_call=babase.Call(self._setSetting, 'delScorch'), maxwidth=self.midwidth, + text=getTranslation('clean_explotions'), autoselect=True, size=(self.midwidth, 30)) v -= 35 miniBoxWidth = self.midwidth miniBoxHeight = 80 - #Bots Color - box1 = bui.containerwidget(parent=c,position=((self._scrollWidth*0.45) -(miniBoxWidth/2),v-miniBoxHeight), - size=(miniBoxWidth,miniBoxHeight),background=True) - vbox1 = miniBoxHeight -20 - t = bui.textwidget(parent=box1,position=(10,vbox1), - text=getTranslation('apply_to_bots'), - maxwidth=miniBoxWidth-20,size=(miniBoxWidth,20),color=(0.8,0.8,0.8,1.0),h_align="left") + # Bots Color + box1 = bui.containerwidget(parent=c, position=((self._scrollWidth*0.45) - (miniBoxWidth/2), v-miniBoxHeight), + size=(miniBoxWidth, miniBoxHeight), background=True) + vbox1 = miniBoxHeight - 20 + t = bui.textwidget(parent=box1, position=(10, vbox1), + text=getTranslation('apply_to_bots'), + maxwidth=miniBoxWidth-20, size=(miniBoxWidth, 20), color=(0.8, 0.8, 0.8, 1.0), h_align="left") vbox1 -= 45 - self.bw = bui.checkboxwidget(parent=box1,position=(10,vbox1),value=getData("colorBots"), - on_value_change_call=babase.Call(self._setSetting,'colorBots'), maxwidth=self.qwidth, - text=getTranslation('change'),autoselect=True,size=(self.qwidth,25)) + self.bw = bui.checkboxwidget(parent=box1, position=(10, vbox1), value=getData("colorBots"), + on_value_change_call=babase.Call(self._setSetting, 'colorBots'), maxwidth=self.qwidth, + text=getTranslation('change'), autoselect=True, size=(self.qwidth, 25)) - self.bw = bui.checkboxwidget(parent=box1,position=(30+self.qwidth,vbox1), value=getData("glowBots"), - on_value_change_call=babase.Call(self._setSetting,'glowBots'), maxwidth=self.qwidth, - text=getTranslation('glow'),autoselect=True,size=(self.qwidth,25)) + self.bw = bui.checkboxwidget(parent=box1, position=(30+self.qwidth, vbox1), value=getData("glowBots"), + on_value_change_call=babase.Call(self._setSetting, 'glowBots'), maxwidth=self.qwidth, + text=getTranslation('glow'), autoselect=True, size=(self.qwidth, 25)) v -= 130 - reset = bui.buttonwidget(parent=c, autoselect=True,on_activate_call=self.restoreSettings, - position=((self._scrollWidth*0.45)-150, v-25), size=(300,50),scale=1.0, text_scale=1.2,textcolor=(1,1,1), - label=getTranslation('restore_default_settings')) - + reset = bui.buttonwidget(parent=c, autoselect=True, on_activate_call=self.restoreSettings, + position=((self._scrollWidth*0.45)-150, v-25), size=(300, 50), scale=1.0, text_scale=1.2, textcolor=(1, 1, 1), + label=getTranslation('restore_default_settings')) + for bttn in self.tabButtons: - bui.buttonwidget(edit=bttn,color = (0.1,0.5,0.1)) - bui.buttonwidget(edit=self.tabButtons[tab],color = (0.1,1,0.1)) + bui.buttonwidget(edit=bttn, color=(0.1, 0.5, 0.1)) + bui.buttonwidget(edit=self.tabButtons[tab], color=(0.1, 1, 0.1)) - def _setSetting(self,setting,m): - babase.app.config["colorsMod"][setting] = False if m==0 else True + def _setSetting(self, setting, m): + babase.app.config["colorsMod"][setting] = False if m == 0 else True babase.app.config.apply_and_commit() - + def _timeDelayDecrement(self): - self._timeDelay = max(50,self._timeDelay - 50) - bui.textwidget(edit=self._timeDelayText,text=str(self._timeDelay)) - babase.app.config["colorsMod"]["timeDelay"] = self._timeDelay + self._timeDelay = max(50, self._timeDelay - 50) + bui.textwidget(edit=self._timeDelayText, text=str(self._timeDelay)) + babase.app.config["colorsMod"]["timeDelay"] = self._timeDelay babase.app.config.apply_and_commit() self._updateColorTimer() - + def _timeDelayIncrement(self): self._timeDelay = self._timeDelay + 50 - bui.textwidget(edit=self._timeDelayText,text=str(self._timeDelay)) - babase.app.config["colorsMod"]["timeDelay"] = self._timeDelay + bui.textwidget(edit=self._timeDelayText, text=str(self._timeDelay)) + babase.app.config["colorsMod"]["timeDelay"] = self._timeDelay babase.app.config.apply_and_commit() self._updateColorTimer() - + def _resetValues(self): - babase.app.config["colorsMod"]["glowScale"] = self._glowScale = 1 - babase.app.config["colorsMod"]["timeDelay"] = self._timeDelay = 500 - bui.textwidget(edit=self._glowScaleText,text=str(self._glowScale)) - bui.textwidget(edit=self._timeDelayText,text=str(self._timeDelay)) + babase.app.config["colorsMod"]["glowScale"] = self._glowScale = 1 + babase.app.config["colorsMod"]["timeDelay"] = self._timeDelay = 500 + bui.textwidget(edit=self._glowScaleText, text=str(self._glowScale)) + bui.textwidget(edit=self._timeDelayText, text=str(self._timeDelay)) babase.app.config.apply_and_commit() self._updateColorTimer() - def updatePalette(self,h,sp): + def updatePalette(self, h, sp): colours = getData("colors") x = sp y = h - 50 cont = 1 - bttnSize = (45,45) + bttnSize = (45, 45) l = len(colours) for i in range(16): if i < l: w = bui.buttonwidget( - parent= self._tabContainer, position=(x,y), size=bttnSize, - autoselect=False, label="",button_type="square",color=colours[i], - on_activate_call=bs.WeakCall(self.removeColor,colours[i])) + parent=self._tabContainer, position=(x, y), size=bttnSize, + autoselect=False, label="", button_type="square", color=colours[i], + on_activate_call=bs.WeakCall(self.removeColor, colours[i])) else: w = bui.buttonwidget( - parent= self._tabContainer, position=(x,y), size=bttnSize,color=(0.5, 0.4, 0.6), - autoselect=False, label="",texture=bui.gettexture('frameInset')) + parent=self._tabContainer, position=( + x, y), size=bttnSize, color=(0.5, 0.4, 0.6), + autoselect=False, label="", texture=bui.gettexture('frameInset')) if i == l: - bui.buttonwidget(edit=w,on_activate_call=bs.WeakCall(self._makePicker,w),label="+") + bui.buttonwidget(edit=w, on_activate_call=bs.WeakCall( + self._makePicker, w), label="+") if cont % 4 == 0: x = sp y -= ((bttnSize[0]) + 10) - else: x += (bttnSize[0]) + 13 + else: + x += (bttnSize[0]) + 13 cont += 1 - def addColor(self,color): - if not self.colorIn(color): + def addColor(self, color): + if not self.colorIn(color): babase.app.config["colorsMod"]["colors"].append(color) babase.app.config.apply_and_commit() self._setTab(0) - else: bs.broadcastmessage(getTranslation('color_already')) + else: + bs.broadcastmessage(getTranslation('color_already')) - def removeColor(self,color): + def removeColor(self, color): if color is not None: if len(getData("colors")) >= 3: if color in getData("colors"): babase.app.config["colorsMod"]["colors"].remove(color) babase.app.config.apply_and_commit() self._setTab(0) - else: print('not found') - else: bs.broadcastmessage("Min. 2 colors", color=(0, 1, 0)) - else: bs.broadcastmessage(getTranslation('nothing_selected')) + else: + print('not found') + else: + bs.broadcastmessage("Min. 2 colors", color=(0, 1, 0)) + else: + bs.broadcastmessage(getTranslation('nothing_selected')) def _makePicker(self, origin): baseScale = 2.05 if babase.UIScale.SMALL else 1.6 if babase.UIScale.MEDIUM else 1.0 initial_color = (0, 0.8, 0) - ColorPicker( parent=self._tabContainer, position=origin.get_screen_space_center(), - offset=(baseScale * (-100), 0),initial_color=initial_color, delegate=self, tag='color') + ColorPicker(parent=self._tabContainer, position=origin.get_screen_space_center(), + offset=(baseScale * (-100), 0), initial_color=initial_color, delegate=self, tag='color') def color_picker_closing(self, picker): - if not self._root_widget.exists(): return + if not self._root_widget.exists(): + return tag = picker.get_tag() def color_picker_selected_color(self, picker, color): self.addColor(color) - def colorIn(self,c): + def colorIn(self, c): sColors = getData("colors") for sC in sColors: - if c[0] == sC[0] and c[1] == sC[1] and c[2] == sC[2]: - return True + if c[0] == sC[0] and c[1] == sC[1] and c[2] == sC[2]: + return True return False - def setColor(self,c): + def setColor(self, c): self._selected = c - bui.buttonwidget(edit=self._moveOut,color = (0.8, 0, 0)) + bui.buttonwidget(edit=self._moveOut, color=(0.8, 0, 0)) def _updateColorTimer(self): - self._colorTimer = bui.AppTimer(getData("timeDelay") / 1000 , self._update, repeat=True) - + self._colorTimer = bui.AppTimer(getData("timeDelay") / 1000, self._update, repeat=True) + def _update(self): - color = (random.random(),random.random(),random.random()) - bui.textwidget(edit=self._timeDelayText,color=color) + color = (random.random(), random.random(), random.random()) + bui.textwidget(edit=self._timeDelayText, color=color) def _updatePreview(self): gs = gs2 = getData("glowScale") - if not getData("glowColor"): gs =1 - if not getData("glowHighlight"): gs2 =1 + if not getData("glowColor"): + gs = 1 + if not getData("glowHighlight"): + gs2 = 1 - c = (1,1,1) + c = (1, 1, 1) if getData("colorPlayer"): c = getRandomColor() - c2 = (1,1,1) + c2 = (1, 1, 1) if getData("higlightPlayer"): c2 = getRandomColor() - bui.imagewidget(edit=self._previewImage,tint_color=(c[0]*gs,c[1]*gs,c[2]*gs)) - bui.imagewidget(edit=self._previewImage,tint2_color=(c2[0]*gs2,c2[1]*gs2,c2[2]*gs2)) - + bui.imagewidget(edit=self._previewImage, tint_color=(c[0]*gs, c[1]*gs, c[2]*gs)) + bui.imagewidget(edit=self._previewImage, tint2_color=(c2[0]*gs2, c2[1]*gs2, c2[2]*gs2)) + def _glowScaleDecrement(self): - self._glowScale = max(1,self._glowScale - 1) - bui.textwidget(edit=self._glowScaleText,text=str(self._glowScale)) - babase.app.config["colorsMod"]["glowScale"] = self._glowScale + self._glowScale = max(1, self._glowScale - 1) + bui.textwidget(edit=self._glowScaleText, text=str(self._glowScale)) + babase.app.config["colorsMod"]["glowScale"] = self._glowScale babase.app.config.apply_and_commit() - + def _glowScaleIncrement(self): - self._glowScale = min(5,self._glowScale + 1) - bui.textwidget(edit=self._glowScaleText,text=str(self._glowScale)) - babase.app.config["colorsMod"]["glowScale"] = self._glowScale + self._glowScale = min(5, self._glowScale + 1) + bui.textwidget(edit=self._glowScaleText, text=str(self._glowScale)) + babase.app.config["colorsMod"]["glowScale"] = self._glowScale babase.app.config.apply_and_commit() def restoreSettings(self): @@ -1005,14 +1050,14 @@ def doIt(): self._setTab(2) bs.broadcastmessage(getTranslation('settings_restored')) confirm.ConfirmWindow(getTranslation('restore_settings'), - width=400, height=120, action=doIt, ok_text=babase.Lstr(resource='okText')) + width=400, height=120, action=doIt, ok_text=babase.Lstr(resource='okText')) def _back(self): - bui.containerwidget(edit=self._root_widget,transition='out_right') + bui.containerwidget(edit=self._root_widget, transition='out_right') self._colorTimer = None self._colorPreviewTimer = None - #if self._in_game: + # if self._in_game: # babase.app.main_menu_window = (mainmenu.MainMenuWindow(transition='in_left').get_root_widget()) - #else: + # else: # babase.app.main_menu_window = ProfileBrowserWindow(transition='in_left').get_root_widget() - #babase.app.main_menu_window = (mainmenu.MainMenuWindow(transition='in_left').get_root_widget()) \ No newline at end of file + # babase.app.main_menu_window = (mainmenu.MainMenuWindow(transition='in_left').get_root_widget()) From 0d5f03d62b557c1c56d81454ef87c329375e095c Mon Sep 17 00:00:00 2001 From: brostosjoined Date: Fri, 26 Jan 2024 16:14:42 +0300 Subject: [PATCH 0841/1464] ... --- plugins/utilities/{ba_colors.py => ba_colours.py} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename plugins/utilities/{ba_colors.py => ba_colours.py} (100%) diff --git a/plugins/utilities/ba_colors.py b/plugins/utilities/ba_colours.py similarity index 100% rename from plugins/utilities/ba_colors.py rename to plugins/utilities/ba_colours.py From d99d0cad72740d86924f0c62ad48b15089d5001e Mon Sep 17 00:00:00 2001 From: brostosjoined Date: Thu, 1 Feb 2024 11:57:50 +0300 Subject: [PATCH 0842/1464] more --- plugins/minigames.json | 98 +++ plugins/minigames/better_deathmatch.py | 271 ++++++++ plugins/minigames/better_elimination.py | 660 +++++++++++++++++++ plugins/minigames/bot_shower.py | 195 ++++++ plugins/minigames/down_into_the_abyss.py | 789 +++++++++++++++++++++++ plugins/minigames/explodo_run.py | 132 ++++ plugins/minigames/extinction.py | 254 ++++++++ plugins/minigames/fat_pigs.py | 340 ++++++++++ plugins/utilities.json | 16 +- plugins/utilities/xyz_tool.py | 85 +++ 10 files changed, 2839 insertions(+), 1 deletion(-) create mode 100644 plugins/minigames/better_deathmatch.py create mode 100644 plugins/minigames/better_elimination.py create mode 100644 plugins/minigames/bot_shower.py create mode 100644 plugins/minigames/down_into_the_abyss.py create mode 100644 plugins/minigames/explodo_run.py create mode 100644 plugins/minigames/extinction.py create mode 100644 plugins/minigames/fat_pigs.py create mode 100644 plugins/utilities/xyz_tool.py diff --git a/plugins/minigames.json b/plugins/minigames.json index 9513a6d9..4cdc9ce6 100644 --- a/plugins/minigames.json +++ b/plugins/minigames.json @@ -1203,6 +1203,104 @@ "versions": { "1.0.0": null } + }, + "down_into_the_abyss": { + "description": "Survive as long as you can but dont miss a step", + "external_url": "", + "authors": [ + { + "name": "", + "email": "", + "discord": "" + } + ], + "versions": { + "1.0.0": null + } + }, + "better_deathmatch": { + "description": "A very-customisable DeathMatch mini-game", + "external_url": "", + "authors": [ + { + "name": "Freaku", + "email": "", + "discord": "freakyyyy" + } + ], + "versions": { + "1.0.0": null + } + }, + "better_elimination": { + "description": "A very-customisable Elimination mini-game", + "external_url": "", + "authors": [ + { + "name": "Freaku", + "email": "", + "discord": "freakyyyy" + } + ], + "versions": { + "1.0.0": null + } + }, + "bot_shower": { + "description": "Survive from the bots.", + "external_url": "", + "authors": [ + { + "name": "", + "email": "", + "discord": "" + } + ], + "versions": { + "1.0.0": null + } + }, + "explodo_run": { + "description": "Run For Your Life :))", + "external_url": "", + "authors": [ + { + "name": "", + "email": "", + "discord": "" + } + ], + "versions": { + "1.0.0": null + } + }, + "extinction_run": { + "description": "Survive the Extinction.", + "external_url": "", + "authors": [ + { + "name": "", + "email": "", + "discord": "" + } + ], + "versions": { + "1.0.0": null + } + }, + "fat_pigs": { + "description": "Survive the Extinction.", + "external_url": "Survive the pigs...", + "authors": [ + { + "name": "Zacker Tz", + "email": "", + "discord": "zacker_tz" + } + ], + "versions": { + "1.0.0": null + } } } } \ No newline at end of file diff --git a/plugins/minigames/better_deathmatch.py b/plugins/minigames/better_deathmatch.py new file mode 100644 index 00000000..34116a59 --- /dev/null +++ b/plugins/minigames/better_deathmatch.py @@ -0,0 +1,271 @@ +# Ported to api 8 by brostos using baport.(https://github.com/bombsquad-community/baport) +#BetterDeathMatch +#Made by your friend: @[Just] Freak#4999 + +"""Defines a very-customisable DeathMatch mini-game""" + +# ba_meta require api 8 + +from __future__ import annotations + +from typing import TYPE_CHECKING + +import babase +import bauiv1 as bui +import bascenev1 as bs +from bascenev1lib.actor.playerspaz import PlayerSpaz +from bascenev1lib.actor.scoreboard import Scoreboard + +if TYPE_CHECKING: + from typing import Any, Type, List, Dict, Tuple, Union, Sequence, Optional + + +class Player(bs.Player['Team']): + """Our player type for this game.""" + + +class Team(bs.Team[Player]): + """Our team type for this game.""" + + def __init__(self) -> None: + self.score = 0 + + +# ba_meta export bascenev1.GameActivity +class BetterDeathMatchGame(bs.TeamGameActivity[Player, Team]): + """A game type based on acquiring kills.""" + + name = 'Btrr Death Match' + description = 'Kill a set number of enemies to win.\nbyFREAK' + + # Print messages when players die since it matters here. + announce_player_deaths = True + + @classmethod + def get_available_settings( + cls, sessiontype: Type[bs.Session]) -> List[babase.Setting]: + settings = [ + bs.IntSetting( + 'Kills to Win Per Player', + min_value=1, + default=5, + increment=1, + ), + bs.IntChoiceSetting( + 'Time Limit', + choices=[ + ('None', 0), + ('1 Minute', 60), + ('2 Minutes', 120), + ('5 Minutes', 300), + ('10 Minutes', 600), + ('20 Minutes', 1200), + ], + default=0, + ), + bs.FloatChoiceSetting( + 'Respawn Times', + choices=[ + ('Shorter', 0.25), + ('Short', 0.5), + ('Normal', 1.0), + ('Long', 2.0), + ('Longer', 4.0), + ], + default=1.0, + ), + bs.BoolSetting('Epic Mode', default=False), + + +## Add settings ## + bs.BoolSetting('Enable Gloves', False), + bs.BoolSetting('Enable Powerups', True), + bs.BoolSetting('Night Mode', False), + bs.BoolSetting('Icy Floor', False), + bs.BoolSetting('One Punch Kill', False), + bs.BoolSetting('Spawn with Shield', False), + bs.BoolSetting('Punching Only', False), +## Add settings ## + ] + + + # In teams mode, a suicide gives a point to the other team, but in + # free-for-all it subtracts from your own score. By default we clamp + # this at zero to benefit new players, but pro players might like to + # be able to go negative. (to avoid a strategy of just + # suiciding until you get a good drop) + if issubclass(sessiontype, bs.FreeForAllSession): + settings.append( + bs.BoolSetting('Allow Negative Scores', default=False)) + + return settings + + @classmethod + def supports_session_type(cls, sessiontype: Type[bs.Session]) -> bool: + return (issubclass(sessiontype, bs.DualTeamSession) + or issubclass(sessiontype, bs.FreeForAllSession)) + + @classmethod + def get_supported_maps(cls, sessiontype: Type[bs.Session]) -> List[str]: + return bs.app.classic.getmaps('melee') + + def __init__(self, settings: dict): + super().__init__(settings) + self._scoreboard = Scoreboard() + self._score_to_win: Optional[int] = None + self._dingsound = bui.getsound('dingSmall') + + +## Take applied settings ## + self._boxing_gloves = bool(settings['Enable Gloves']) + self._enable_powerups = bool(settings['Enable Powerups']) + self._night_mode = bool(settings['Night Mode']) + self._icy_floor = bool(settings['Icy Floor']) + self._one_punch_kill = bool(settings['One Punch Kill']) + self._shield_ = bool(settings['Spawn with Shield']) + self._only_punch = bool(settings['Punching Only']) +## Take applied settings ## + + + self._epic_mode = bool(settings['Epic Mode']) + self._kills_to_win_per_player = int( + settings['Kills to Win Per Player']) + self._time_limit = float(settings['Time Limit']) + self._allow_negative_scores = bool( + settings.get('Allow Negative Scores', False)) + + # Base class overrides. + self.slow_motion = self._epic_mode + self.default_music = (bs.MusicType.EPIC if self._epic_mode else + bs.MusicType.TO_THE_DEATH) + + def get_instance_description(self) -> Union[str, Sequence]: + return 'Crush ${ARG1} of your enemies. byFREAK', self._score_to_win + + def get_instance_description_short(self) -> Union[str, Sequence]: + return 'kill ${ARG1} enemies. byFREAK', self._score_to_win + + def on_team_join(self, team: Team) -> None: + if self.has_begun(): + self._update_scoreboard() + + +## Run settings related: IcyFloor ## + def on_transition_in(self) -> None: + super().on_transition_in() + activity = bs.getactivity() + if self._icy_floor: + activity.map.is_hockey = True + else: + return +## Run settings related: IcyFloor ## + + + + def on_begin(self) -> None: + super().on_begin() + self.setup_standard_time_limit(self._time_limit) + + +## Run settings related: NightMode,Powerups ## + if self._night_mode: + bs.getactivity().globalsnode.tint = (0.5, 0.7, 1) + else: + pass +#-# Tried return here, pfft. Took me 30mins to figure out why pwps spawning only on NightMode +#-# Now its fixed :) + if self._enable_powerups: + self.setup_standard_powerup_drops() + else: + pass +## Run settings related: NightMode,Powerups ## + + + # Base kills needed to win on the size of the largest team. + self._score_to_win = (self._kills_to_win_per_player * + max(1, max(len(t.players) for t in self.teams))) + self._update_scoreboard() + + def handlemessage(self, msg: Any) -> Any: + + if isinstance(msg, bs.PlayerDiedMessage): + + # Augment standard behavior. + super().handlemessage(msg) + + player = msg.getplayer(Player) + self.respawn_player(player) + + killer = msg.getkillerplayer(Player) + if killer is None: + return None + + # Handle team-kills. + if killer.team is player.team: + + # In free-for-all, killing yourself loses you a point. + if isinstance(self.session, bs.FreeForAllSession): + new_score = player.team.score - 1 + if not self._allow_negative_scores: + new_score = max(0, new_score) + player.team.score = new_score + + # In teams-mode it gives a point to the other team. + else: + self._dingsound.play() + for team in self.teams: + if team is not killer.team: + team.score += 1 + + # Killing someone on another team nets a kill. + else: + killer.team.score += 1 + self._dingsound.play() + + # In FFA show scores since its hard to find on the scoreboard. + if isinstance(killer.actor, PlayerSpaz) and killer.actor: + killer.actor.set_score_text(str(killer.team.score) + '/' + + str(self._score_to_win), + color=killer.team.color, + flash=True) + + self._update_scoreboard() + + # If someone has won, set a timer to end shortly. + # (allows the dust to clear and draws to occur if deaths are + # close enough) + assert self._score_to_win is not None + if any(team.score >= self._score_to_win for team in self.teams): + bs.timer(0.5, self.end_game) + + else: + return super().handlemessage(msg) + return None + + +## Run settings related: Spaz ## + def spawn_player(self, player: Player) -> bs.Actor: + spaz = self.spawn_player_spaz(player) + if self._boxing_gloves: + spaz.equip_boxing_gloves() + if self._one_punch_kill: + spaz._punch_power_scale = 15 + if self._shield_: + spaz.equip_shields() + if self._only_punch: + spaz.connect_controls_to_player(enable_bomb=False, enable_pickup=False) + + return spaz +## Run settings related: Spaz ## + + + def _update_scoreboard(self) -> None: + for team in self.teams: + self._scoreboard.set_team_value(team, team.score, + self._score_to_win) + + def end_game(self) -> None: + results = bs.GameResults() + for team in self.teams: + results.set_team_score(team, team.score) + self.end(results=results) diff --git a/plugins/minigames/better_elimination.py b/plugins/minigames/better_elimination.py new file mode 100644 index 00000000..6ff29100 --- /dev/null +++ b/plugins/minigames/better_elimination.py @@ -0,0 +1,660 @@ +# Ported to api 8 by brostos using baport.(https://github.com/bombsquad-community/baport) +#BetterElimination +#Made by your friend: @[Just] Freak#4999 + +#Huge Thx to Nippy for "Live Team Balance" + + +"""Defines a very-customisable Elimination mini-game""" + +# ba_meta require api 8 + +from __future__ import annotations + +from typing import TYPE_CHECKING + +import babase +import bauiv1 as bui +import bascenev1 as bs +from bascenev1lib.actor.spazfactory import SpazFactory +from bascenev1lib.actor.scoreboard import Scoreboard + +if TYPE_CHECKING: + from typing import (Any, Tuple, Dict, Type, List, Sequence, Optional, + Union) + + +class Icon(bs.Actor): + """Creates in in-game icon on screen.""" + + def __init__(self, + player: Player, + position: Tuple[float, float], + scale: float, + show_lives: bool = True, + show_death: bool = True, + name_scale: float = 1.0, + name_maxwidth: float = 115.0, + flatness: float = 1.0, + shadow: float = 1.0): + super().__init__() + + self._player = player + self._show_lives = show_lives + self._show_death = show_death + self._name_scale = name_scale + self._outline_tex = bs.gettexture('characterIconMask') + + icon = player.get_icon() + self.node = bs.newnode('image', + delegate=self, + attrs={ + 'texture': icon['texture'], + 'tint_texture': icon['tint_texture'], + 'tint_color': icon['tint_color'], + 'vr_depth': 400, + 'tint2_color': icon['tint2_color'], + 'mask_texture': self._outline_tex, + 'opacity': 1.0, + 'absolute_scale': True, + 'attach': 'bottomCenter' + }) + self._name_text = bs.newnode( + 'text', + owner=self.node, + attrs={ + 'text': babase.Lstr(value=player.getname()), + 'color': babase.safecolor(player.team.color), + 'h_align': 'center', + 'v_align': 'center', + 'vr_depth': 410, + 'maxwidth': name_maxwidth, + 'shadow': shadow, + 'flatness': flatness, + 'h_attach': 'center', + 'v_attach': 'bottom' + }) + if self._show_lives: + self._lives_text = bs.newnode('text', + owner=self.node, + attrs={ + 'text': 'x0', + 'color': (1, 1, 0.5), + 'h_align': 'left', + 'vr_depth': 430, + 'shadow': 1.0, + 'flatness': 1.0, + 'h_attach': 'center', + 'v_attach': 'bottom' + }) + self.set_position_and_scale(position, scale) + + def set_position_and_scale(self, position: Tuple[float, float], + scale: float) -> None: + """(Re)position the icon.""" + assert self.node + self.node.position = position + self.node.scale = [70.0 * scale] + self._name_text.position = (position[0], position[1] + scale * 52.0) + self._name_text.scale = 1.0 * scale * self._name_scale + if self._show_lives: + self._lives_text.position = (position[0] + scale * 10.0, + position[1] - scale * 43.0) + self._lives_text.scale = 1.0 * scale + + def update_for_lives(self) -> None: + """Update for the target player's current lives.""" + if self._player: + lives = self._player.lives + else: + lives = 0 + if self._show_lives: + if lives > 0: + self._lives_text.text = 'x' + str(lives - 1) + else: + self._lives_text.text = '' + if lives == 0: + self._name_text.opacity = 0.2 + assert self.node + self.node.color = (0.7, 0.3, 0.3) + self.node.opacity = 0.2 + + def handle_player_spawned(self) -> None: + """Our player spawned; hooray!""" + if not self.node: + return + self.node.opacity = 1.0 + self.update_for_lives() + + def handle_player_died(self) -> None: + """Well poo; our player died.""" + if not self.node: + return + if self._show_death: + bs.animate( + self.node, 'opacity', { + 0.00: 1.0, + 0.05: 0.0, + 0.10: 1.0, + 0.15: 0.0, + 0.20: 1.0, + 0.25: 0.0, + 0.30: 1.0, + 0.35: 0.0, + 0.40: 1.0, + 0.45: 0.0, + 0.50: 1.0, + 0.55: 0.2 + }) + lives = self._player.lives + if lives == 0: + bs.timer(0.6, self.update_for_lives) + + def handlemessage(self, msg: Any) -> Any: + if isinstance(msg, bs.DieMessage): + self.node.delete() + return None + return super().handlemessage(msg) + + +class Player(bs.Player['Team']): + """Our player type for this game.""" + + def __init__(self) -> None: + self.lives = 0 + self.icons: List[Icon] = [] + + +class Team(bs.Team[Player]): + """Our team type for this game.""" + + def __init__(self) -> None: + self.survival_seconds: Optional[int] = None + self.spawn_order: List[Player] = [] + + +# ba_meta export bascenev1.GameActivity +class BetterEliminationGame(bs.TeamGameActivity[Player, Team]): + """Game type where last player(s) left alive win.""" + + name = 'Bttr Elimination' + description = 'Last remaining alive wins.\nbyFREAK' + scoreconfig = bs.ScoreConfig(label='Survived', + scoretype=bs.ScoreType.SECONDS, + none_is_winner=True) + # Show messages when players die since it's meaningful here. + announce_player_deaths = True + + @classmethod + def get_available_settings( + cls, sessiontype: Type[bs.Session]) -> List[babase.Setting]: + settings = [ + bs.IntSetting( + 'Life\'s Per Player', + default=1, + min_value=1, + max_value=10, + increment=1, + ), + bs.IntChoiceSetting( + 'Time Limit', + choices=[ + ('None', 0), + ('1 Minute', 60), + ('2 Minutes', 120), + ('5 Minutes', 300), + ('10 Minutes', 600), + ('20 Minutes', 1200), + ], + default=0, + ), + bs.FloatChoiceSetting( + 'Respawn Times', + choices=[ + ('Shorter', 0.25), + ('Short', 0.5), + ('Normal', 1.0), + ('Long', 2.0), + ('Longer', 4.0), + ], + default=1.0, + ), + bs.BoolSetting('Epic Mode', default=False), + + +## Add settings ## + bs.BoolSetting('Live Team Balance (by Nippy#2677)', True), + bs.BoolSetting('Enable Gloves', False), + bs.BoolSetting('Enable Powerups', True), + bs.BoolSetting('Night Mode', False), + bs.BoolSetting('Icy Floor', False), + bs.BoolSetting('One Punch Kill', False), + bs.BoolSetting('Spawn with Shield', False), + bs.BoolSetting('Punching Only', False), +## Add settings ## + ] + if issubclass(sessiontype, bs.DualTeamSession): + settings.append(bs.BoolSetting('Solo Mode', default=False)) + settings.append( + bs.BoolSetting('Balance Total Life\'s (on spawn only)', default=False)) + return settings + + @classmethod + def supports_session_type(cls, sessiontype: Type[bs.Session]) -> bool: + return (issubclass(sessiontype, bs.DualTeamSession) + or issubclass(sessiontype, bs.FreeForAllSession)) + + @classmethod + def get_supported_maps(cls, sessiontype: Type[bs.Session]) -> List[str]: + return bs.app.classic.getmaps('melee') + + def __init__(self, settings: dict): + super().__init__(settings) + self._scoreboard = Scoreboard() + self._start_time: Optional[float] = None + self._vs_text: Optional[bs.Actor] = None + self._round_end_timer: Optional[bs.Timer] = None + +## Take applied settings ## + self._live_team_balance = bool(settings['Live Team Balance (by Nippy#2677)']) + self._boxing_gloves = bool(settings['Enable Gloves']) + self._enable_powerups = bool(settings['Enable Powerups']) + self._night_mode = bool(settings['Night Mode']) + self._icy_floor = bool(settings['Icy Floor']) + self._one_punch_kill = bool(settings['One Punch Kill']) + self._shield_ = bool(settings['Spawn with Shield']) + self._only_punch = bool(settings['Punching Only']) +## Take applied settings ## + + self._epic_mode = bool(settings['Epic Mode']) + self._lives_per_player = int(settings['Life\'s Per Player']) + self._time_limit = float(settings['Time Limit']) + self._balance_total_lives = bool( + settings.get('Balance Total Life\'s (on spawn only)', False)) + self._solo_mode = bool(settings.get('Solo Mode', False)) + + # Base class overrides: + self.slow_motion = self._epic_mode + self.default_music = (bs.MusicType.EPIC + if self._epic_mode else bs.MusicType.SURVIVAL) + + def get_instance_description(self) -> Union[str, Sequence]: + return 'Last team standing wins. byFREAK' if isinstance( + self.session, bs.DualTeamSession) else 'Last one standing wins.' + + def get_instance_description_short(self) -> Union[str, Sequence]: + return 'last team standing wins. byFREAK' if isinstance( + self.session, bs.DualTeamSession) else 'last one standing wins' + + def on_player_join(self, player: Player) -> None: + + # No longer allowing mid-game joiners here; too easy to exploit. + if self.has_begun(): + + # Make sure their team has survival seconds set if they're all dead + # (otherwise blocked new ffa players are considered 'still alive' + # in score tallying). + if (self._get_total_team_lives(player.team) == 0 + and player.team.survival_seconds is None): + player.team.survival_seconds = 0 + bui.screenmessage( + babase.Lstr(resource='playerDelayedJoinText', + subs=[('${PLAYER}', player.getname(full=True))]), + color=(0, 1, 0), + ) + return + + player.lives = self._lives_per_player + + if self._solo_mode: + player.team.spawn_order.append(player) + self._update_solo_mode() + else: + # Create our icon and spawn. + player.icons = [Icon(player, position=(0, 50), scale=0.8)] + if player.lives > 0: + self.spawn_player(player) + + # Don't waste time doing this until begin. + if self.has_begun(): + self._update_icons() + + +## Run settings related: IcyFloor ## + def on_transition_in(self) -> None: + super().on_transition_in() + activity = bs.getactivity() + if self._icy_floor: + activity.map.is_hockey = True + else: + return +## Run settings related: IcyFloor ## + + + + def on_begin(self) -> None: + super().on_begin() + self._start_time = bs.time() + self.setup_standard_time_limit(self._time_limit) + + +## Run settings related: NightMode,Powerups ## + if self._night_mode: + bs.getactivity().globalsnode.tint = (0.5, 0.7, 1) + else: + pass +#-# Tried return here, pfft. Took me 30mins to figure out why pwps spawning only on NightMode +#-# Now its fixed :) + if self._enable_powerups: + self.setup_standard_powerup_drops() + else: + pass +## Run settings related: NightMode,Powerups ## + + + if self._solo_mode: + self._vs_text = bs.NodeActor( + bs.newnode('text', + attrs={ + 'position': (0, 105), + 'h_attach': 'center', + 'h_align': 'center', + 'maxwidth': 200, + 'shadow': 0.5, + 'vr_depth': 390, + 'scale': 0.6, + 'v_attach': 'bottom', + 'color': (0.8, 0.8, 0.3, 1.0), + 'text': babase.Lstr(resource='vsText') + })) + + # If balance-team-lives is on, add lives to the smaller team until + # total lives match. + if (isinstance(self.session, bs.DualTeamSession) + and self._balance_total_lives and self.teams[0].players + and self.teams[1].players): + if self._get_total_team_lives( + self.teams[0]) < self._get_total_team_lives(self.teams[1]): + lesser_team = self.teams[0] + greater_team = self.teams[1] + else: + lesser_team = self.teams[1] + greater_team = self.teams[0] + add_index = 0 + while (self._get_total_team_lives(lesser_team) < + self._get_total_team_lives(greater_team)): + lesser_team.players[add_index].lives += 1 + add_index = (add_index + 1) % len(lesser_team.players) + + self._update_icons() + + # We could check game-over conditions at explicit trigger points, + # but lets just do the simple thing and poll it. + bs.timer(1.0, self._update, repeat=True) + + def _update_solo_mode(self) -> None: + # For both teams, find the first player on the spawn order list with + # lives remaining and spawn them if they're not alive. + for team in self.teams: + # Prune dead players from the spawn order. + team.spawn_order = [p for p in team.spawn_order if p] + for player in team.spawn_order: + assert isinstance(player, Player) + if player.lives > 0: + if not player.is_alive(): + self.spawn_player(player) + break + + def _update_icons(self) -> None: + # pylint: disable=too-many-branches + + # In free-for-all mode, everyone is just lined up along the bottom. + if isinstance(self.session, bs.FreeForAllSession): + count = len(self.teams) + x_offs = 85 + xval = x_offs * (count - 1) * -0.5 + for team in self.teams: + if len(team.players) == 1: + player = team.players[0] + for icon in player.icons: + icon.set_position_and_scale((xval, 30), 0.7) + icon.update_for_lives() + xval += x_offs + + # In teams mode we split up teams. + else: + if self._solo_mode: + # First off, clear out all icons. + for player in self.players: + player.icons = [] + + # Now for each team, cycle through our available players + # adding icons. + for team in self.teams: + if team.id == 0: + xval = -60 + x_offs = -78 + else: + xval = 60 + x_offs = 78 + is_first = True + test_lives = 1 + while True: + players_with_lives = [ + p for p in team.spawn_order + if p and p.lives >= test_lives + ] + if not players_with_lives: + break + for player in players_with_lives: + player.icons.append( + Icon(player, + position=(xval, (40 if is_first else 25)), + scale=1.0 if is_first else 0.5, + name_maxwidth=130 if is_first else 75, + name_scale=0.8 if is_first else 1.0, + flatness=0.0 if is_first else 1.0, + shadow=0.5 if is_first else 1.0, + show_death=is_first, + show_lives=False)) + xval += x_offs * (0.8 if is_first else 0.56) + is_first = False + test_lives += 1 + # Non-solo mode. + else: + for team in self.teams: + if team.id == 0: + xval = -50 + x_offs = -85 + else: + xval = 50 + x_offs = 85 + for player in team.players: + for icon in player.icons: + icon.set_position_and_scale((xval, 30), 0.7) + icon.update_for_lives() + xval += x_offs + + def _get_spawn_point(self, player: Player) -> Optional[babase.Vec3]: + del player # Unused. + + # In solo-mode, if there's an existing live player on the map, spawn at + # whichever spot is farthest from them (keeps the action spread out). + if self._solo_mode: + living_player = None + living_player_pos = None + for team in self.teams: + for tplayer in team.players: + if tplayer.is_alive(): + assert tplayer.node + ppos = tplayer.node.position + living_player = tplayer + living_player_pos = ppos + break + if living_player: + assert living_player_pos is not None + player_pos = babase.Vec3(living_player_pos) + points: List[Tuple[float, babase.Vec3]] = [] + for team in self.teams: + start_pos = babase.Vec3(self.map.get_start_position(team.id)) + points.append( + ((start_pos - player_pos).length(), start_pos)) + # Hmm.. we need to sorting vectors too? + points.sort(key=lambda x: x[0]) + return points[-1][1] + return None + + def spawn_player(self, player: Player) -> bs.Actor: + actor = self.spawn_player_spaz(player, self._get_spawn_point(player)) + if not self._solo_mode: + bs.timer(0.3, babase.Call(self._print_lives, player)) + + # If we have any icons, update their state. + for icon in player.icons: + icon.handle_player_spawned() + +## Run settings related: Spaz ## + if self._boxing_gloves: + actor.equip_boxing_gloves() + if self._one_punch_kill: + actor._punch_power_scale = 15 + if self._shield_: + actor.equip_shields() + if self._only_punch: + actor.connect_controls_to_player(enable_bomb=False, enable_pickup=False) + + return actor +## Run settings related: Spaz ## + + + def _print_lives(self, player: Player) -> None: + from bascenev1lib.actor import popuptext + + # We get called in a timer so it's possible our player has left/etc. + if not player or not player.is_alive() or not player.node: + return + + popuptext.PopupText('x' + str(player.lives - 1), + color=(1, 1, 0, 1), + offset=(0, -0.8, 0), + random_offset=0.0, + scale=1.8, + position=player.node.position).autoretain() + + def on_player_leave(self, player: Player) -> None: + ########################################################Nippy#2677 + team_count=1 #Just initiating + if player.lives>0 and self._live_team_balance: + team_mem=[] + for teamer in player.team.players: + if player!=teamer: + team_mem.append(teamer) #Got Dead players Team + live=player.lives + team_count=len(team_mem) + for i in range(int((live if live%2==0 else live+1)/2)): #Extending Player List for Sorted Players + team_mem.extend(team_mem) + if team_count>0: + for i in range(live): + team_mem[i].lives+=1 + + if team_count<=0 : #Draw if Player Leaves + self.end_game() + ########################################################Nippy#2677 + super().on_player_leave(player) + player.icons = [] + + # Remove us from spawn-order. + if self._solo_mode: + if player in player.team.spawn_order: + player.team.spawn_order.remove(player) + + # Update icons in a moment since our team will be gone from the + # list then. + bs.timer(0, self._update_icons) + + # If the player to leave was the last in spawn order and had + # their final turn currently in-progress, mark the survival time + # for their team. + if self._get_total_team_lives(player.team) == 0: + assert self._start_time is not None + player.team.survival_seconds = int(bs.time() - self._start_time) + + def _get_total_team_lives(self, team: Team) -> int: + return sum(player.lives for player in team.players) + + def handlemessage(self, msg: Any) -> Any: + if isinstance(msg, bs.PlayerDiedMessage): + + # Augment standard behavior. + super().handlemessage(msg) + player: Player = msg.getplayer(Player) + + player.lives -= 1 + if player.lives < 0: + babase.print_error( + "Got lives < 0 in Elim; this shouldn't happen. solo:" + + str(self._solo_mode)) + player.lives = 0 + + # If we have any icons, update their state. + for icon in player.icons: + icon.handle_player_died() + + # Play big death sound on our last death + # or for every one in solo mode. + if self._solo_mode or player.lives == 0: + SpazFactory.get().single_player_death_sound.play() + + # If we hit zero lives, we're dead (and our team might be too). + if player.lives == 0: + # If the whole team is now dead, mark their survival time. + if self._get_total_team_lives(player.team) == 0: + assert self._start_time is not None + player.team.survival_seconds = int(bs.time() - + self._start_time) + else: + # Otherwise, in regular mode, respawn. + if not self._solo_mode: + self.respawn_player(player) + + # In solo, put ourself at the back of the spawn order. + if self._solo_mode: + player.team.spawn_order.remove(player) + player.team.spawn_order.append(player) + + def _update(self) -> None: + if self._solo_mode: + # For both teams, find the first player on the spawn order + # list with lives remaining and spawn them if they're not alive. + for team in self.teams: + # Prune dead players from the spawn order. + team.spawn_order = [p for p in team.spawn_order if p] + for player in team.spawn_order: + assert isinstance(player, Player) + if player.lives > 0: + if not player.is_alive(): + self.spawn_player(player) + self._update_icons() + break + + # If we're down to 1 or fewer living teams, start a timer to end + # the game (allows the dust to settle and draws to occur if deaths + # are close enough). + if len(self._get_living_teams()) < 2: + self._round_end_timer = bs.Timer(0.5, self.end_game) + + def _get_living_teams(self) -> List[Team]: + return [ + team for team in self.teams + if len(team.players) > 0 and any(player.lives > 0 + for player in team.players) + ] + + def end_game(self) -> None: + if self.has_ended(): + return + results = bs.GameResults() + self._vs_text = None # Kill our 'vs' if its there. + for team in self.teams: + results.set_team_score(team, team.survival_seconds) + self.end(results=results) diff --git a/plugins/minigames/bot_shower.py b/plugins/minigames/bot_shower.py new file mode 100644 index 00000000..ebbd14bf --- /dev/null +++ b/plugins/minigames/bot_shower.py @@ -0,0 +1,195 @@ +# Ported to api 8 by brostos using baport.(https://github.com/bombsquad-community/baport) + +# ba_meta require api 8 + +from __future__ import annotations +from typing import TYPE_CHECKING + +import babase +import bauiv1 as bui +import bascenev1 as bs +import random +from bascenev1lib.actor.onscreentimer import OnScreenTimer +from bascenev1lib.actor.spazbot import ( + SpazBot, SpazBotSet, + BomberBot, BrawlerBot, BouncyBot, + ChargerBot, StickyBot, TriggerBot, + ExplodeyBot) + +if TYPE_CHECKING: + from typing import Any, List, Type, Optional + + +class Player(bs.Player['Team']): + """Our player type for this game.""" + + def __init__(self) -> None: + super().__init__() + self.death_time: Optional[float] = None + + +class Team(bs.Team[Player]): + """Our team type for this game.""" + + +# ba_meta export bascenev1.GameActivity +class BotShowerGame(bs.TeamGameActivity[Player, Team]): + """A babase.MeteorShowerGame but replaced with bots.""" + + name = 'Bot Shower' + description = 'Survive from the bots.' + available_settings = [ + bs.BoolSetting('Spaz', default=True), + bs.BoolSetting('Zoe', default=True), + bs.BoolSetting('Kronk', default=True), + bs.BoolSetting('Snake Shadow', default=True), + bs.BoolSetting('Mel', default=True), + bs.BoolSetting('Jack Morgan', default=True), + bs.BoolSetting('Easter Bunny', default=True), + bs.BoolSetting('Epic Mode', default=False), + ] + + announce_player_deaths = True + + @classmethod + def get_supported_maps(cls, sessiontype: Type[bs.Session]) -> List[str]: + return ['Football Stadium', 'Hockey Stadium'] + + def __init__(self, settings: dict) -> None: + super().__init__(settings) + self._epic_mode = settings['Epic Mode'] + self._last_player_death_time: Optional[float] = None + self._timer: Optional[OnScreenTimer] = None + self._bots: Optional[SpazBotSet] = None + self._bot_type: List[SpazBot] = [] + + if bool(settings['Spaz']) == True: + self._bot_type.append(BomberBot) + else: + if BomberBot in self._bot_type: + self._bot_type.remove(BomberBot) + if bool(settings['Zoe']) == True: + self._bot_type.append(TriggerBot) + else: + if TriggerBot in self._bot_type: + self._bot_type.remove(TriggerBot) + if bool(settings['Kronk']) == True: + self._bot_type.append(BrawlerBot) + else: + if BrawlerBot in self._bot_type: + self._bot_type.remove(BrawlerBot) + if bool(settings['Snake Shadow']) == True: + self._bot_type.append(ChargerBot) + else: + if ChargerBot in self._bot_type: + self._bot_type.remove(ChargerBot) + if bool(settings['Jack Morgan']) == True: + self._bot_type.append(ExplodeyBot) + else: + if ExplodeyBot in self._bot_type: + self._bot_type.remove(ExplodeyBot) + if bool(settings['Easter Bunny']) == True: + self._bot_type.append(BouncyBot) + else: + if BouncyBot in self._bot_type: + self._bot_type.remove(BouncyBot) + + self.slow_motion = self._epic_mode + self.default_music = (bs.MusicType.EPIC + if self._epic_mode else bs.MusicType.SURVIVAL) + + def on_begin(self) -> None: + super().on_begin() + self._bots = SpazBotSet() + self._timer = OnScreenTimer() + self._timer.start() + + if self._epic_mode: + bs.timer(1.0, self._start_spawning_bots) + else: + bs.timer(5.0, self._start_spawning_bots) + + bs.timer(5.0, self._check_end_game) + + def spawn_player(self, player: Player) -> None: + spaz = self.spawn_player_spaz(player) + spaz.connect_controls_to_player( + enable_punch=False, + enable_bomb=False, + enable_pickup=False) + return spaz + + def on_player_join(self, player: Player) -> None: + if self.has_begun(): + bui.screenmessage( + babase.Lstr(resource='playerDelayedJoinText', + subs=[('${PLAYER}', player.getname(full=True))]), + color=(1, 1, 0), + ) + + assert self._timer is not None + player.death_time = self._timer.getstarttime() + return + self.spawn_player(player) + + def handlemessage(self, msg: Any) -> Any: + if isinstance(msg, bs.PlayerDiedMessage): + curtime = bs.time() + msg.getplayer(Player).death_time = curtime + + bs.timer(1.0, self._check_end_game) + else: + super().handlemessage(msg) + + def _start_spawning_bots(self) -> None: + bs.timer(1.2, self._spawn_bot, repeat=True) + bs.timer(2.2, self._spawn_bot, repeat=True) + + def _spawn_bot(self) -> None: + assert self._bots is not None + self._bots.spawn_bot(random.choice(self._bot_type), pos=(random.uniform(-11, 11), (9.8 if self.map.getname() == 'Football Stadium' else 5.0), random.uniform(-5, 5))) + + def _check_end_game(self) -> None: + living_team_count = 0 + for team in self.teams: + for player in team.players: + if player.is_alive(): + living_team_count += 1 + break + + if living_team_count <= 1: + self.end_game() + + def end_game(self) -> None: + cur_time = bs.time() + assert self._timer is not None + start_time = self._timer.getstarttime() + + for team in self.teams: + for player in team.players: + survived = False + + if player.death_time is None: + survived = True + player.death_time = cur_time + 1 + + score = int(player.death_time - self._timer.getstarttime()) + if survived: + score += 50 + self.stats.player_scored(player, score, screenmessage=False) + + self._timer.stop(endtime=self._last_player_death_time) + + results = bs.GameResults() + + for team in self.teams: + + longest_life = 0.0 + for player in team.players: + assert player.death_time is not None + longest_life = max(longest_life, + player.death_time - start_time) + + results.set_team_score(team, int(1000.0 * longest_life)) + + self.end(results=results) \ No newline at end of file diff --git a/plugins/minigames/down_into_the_abyss.py b/plugins/minigames/down_into_the_abyss.py new file mode 100644 index 00000000..2ecac4e7 --- /dev/null +++ b/plugins/minigames/down_into_the_abyss.py @@ -0,0 +1,789 @@ +# Ported to api 8 by brostos using baport.(https://github.com/bombsquad-community/baport) +# ba_meta require api 8 +# (see https://ballistica.net/wiki/meta-tag-system) + +from __future__ import annotations + +from typing import TYPE_CHECKING + +import babase +import bauiv1 as bui +import bascenev1 as bs +import _babase +import random +from bascenev1._map import register_map +from bascenev1lib.actor.spaz import PickupMessage +from bascenev1lib.actor.playerspaz import PlayerSpaz +from bascenev1lib.actor.spazfactory import SpazFactory +from bascenev1lib.gameutils import SharedObjects +from bascenev1lib.actor.spazbot import SpazBotSet, ChargerBotPro, TriggerBotPro +from bascenev1lib.actor.bomb import Blast +from bascenev1lib.actor.powerupbox import PowerupBoxFactory +from bascenev1lib.actor.onscreentimer import OnScreenTimer + +if TYPE_CHECKING: + from typing import Any, Sequence + + +lang = bs.app.lang.language + +if lang == 'Spanish': + name = 'Abajo en el Abismo' + description = 'Sobrevive tanto como puedas' + help = 'El mapa es 3D, ¡ten cuidado!' + author = 'Autor: Deva' + github = 'GitHub: spdv123' + blog = 'Blog: superdeva.info' + peaceTime = 'Tiempo de Paz' + npcDensity = 'Densidad de Enemigos' + hint_use_punch = '¡Ahora puedes golpear a los enemigos!' +elif lang == 'Chinese': + name = '无尽深渊' + description = '在无穷尽的坠落中存活更长时间' + help = '' + author = '作者: Deva' + github = 'GitHub: spdv123' + blog = '博客: superdeva.info' + peaceTime = '和平时间' + npcDensity = 'NPC密度' + hint_use_punch = u'现在可以使用拳头痛扁你的敌人了' +else: + name = 'Down Into The Abyss' + description = 'Survive as long as you can' + help = 'The map is 3D, be careful!' + author = 'Author: Deva' + github = 'GitHub: spdv123' + blog = 'Blog: superdeva.info' + peaceTime = 'Peace Time' + npcDensity = 'NPC Density' + hint_use_punch = 'You can punch your enemies now!' + + +class AbyssMap(bs.Map): + from bascenev1lib.mapdata import happy_thoughts as defs + # Add the y-dimension space for players + defs.boxes['map_bounds'] = (-0.8748348681, 9.212941713, -9.729538885) \ + + (0.0, 0.0, 0.0) \ + + (36.09666006, 26.19950145, 20.89541168) + name = 'Abyss Unhappy' + + @classmethod + def get_play_types(cls) -> list[str]: + """Return valid play types for this map.""" + return ['abyss'] + + @classmethod + def get_preview_texture_name(cls) -> str: + return 'alwaysLandPreview' + + @classmethod + def on_preload(cls) -> Any: + data: dict[str, Any] = { + 'mesh': bs.getmesh('alwaysLandLevel'), + 'bottom_mesh': bs.getmesh('alwaysLandLevelBottom'), + 'bgmesh': bs.getmesh('alwaysLandBG'), + 'collision_mesh': bs.getcollisionmesh('alwaysLandLevelCollide'), + 'tex': bs.gettexture('alwaysLandLevelColor'), + 'bgtex': bs.gettexture('alwaysLandBGColor'), + 'vr_fill_mound_mesh': bs.getmesh('alwaysLandVRFillMound'), + 'vr_fill_mound_tex': bs.gettexture('vrFillMound') + } + return data + + @classmethod + def get_music_type(cls) -> bs.MusicType: + return bs.MusicType.FLYING + + def __init__(self) -> None: + super().__init__(vr_overlay_offset=(0, -3.7, 2.5)) + self.background = bs.newnode( + 'terrain', + attrs={ + 'mesh': self.preloaddata['bgmesh'], + 'lighting': False, + 'background': True, + 'color_texture': self.preloaddata['bgtex'] + }) + bs.newnode('terrain', + attrs={ + 'mesh': self.preloaddata['vr_fill_mound_mesh'], + 'lighting': False, + 'vr_only': True, + 'color': (0.2, 0.25, 0.2), + 'background': True, + 'color_texture': self.preloaddata['vr_fill_mound_tex'] + }) + gnode = bs.getactivity().globalsnode + gnode.happy_thoughts_mode = True + gnode.shadow_offset = (0.0, 8.0, 5.0) + gnode.tint = (1.3, 1.23, 1.0) + gnode.ambient_color = (1.3, 1.23, 1.0) + gnode.vignette_outer = (0.64, 0.59, 0.69) + gnode.vignette_inner = (0.95, 0.95, 0.93) + gnode.vr_near_clip = 1.0 + self.is_flying = True + +register_map(AbyssMap) + + +class SpazTouchFoothold: + pass + +class BombToDieMessage: + pass + + +class Foothold(bs.Actor): + + def __init__(self, + position: Sequence[float] = (0.0, 1.0, 0.0), + power: str = 'random', + size: float = 6.0, + breakable: bool = True, + moving: bool = False): + super().__init__() + shared = SharedObjects.get() + powerup = PowerupBoxFactory.get() + + fmesh = bs.getmesh('landMine') + fmeshs = bs.getmesh('powerupSimple') + self.died = False + self.breakable = breakable + self.moving = moving # move right and left + self.lrSig = 1 # left or right signal + self.lrSpeedPlus = random.uniform(1 / 2.0, 1 / 0.7) + self._npcBots = SpazBotSet() + + self.foothold_material = bs.Material() + self.impact_sound = bui.getsound('impactMedium') + + self.foothold_material.add_actions( + conditions=(('they_dont_have_material', shared.player_material), + 'and', + ('they_have_material', shared.object_material), + 'or', + ('they_have_material', shared.footing_material)), + actions=(('modify_node_collision', 'collide', True), + )) + + self.foothold_material.add_actions( + conditions=('they_have_material', shared.player_material), + actions=(('modify_part_collision', 'physical', True), + ('modify_part_collision', 'stiffness', 0.05), + ('message', 'our_node', 'at_connect', SpazTouchFoothold()), + )) + + self.foothold_material.add_actions( + conditions=('they_have_material', self.foothold_material), + actions=('modify_node_collision', 'collide', False), + ) + + tex = { + 'punch': powerup.tex_punch, + 'sticky_bombs': powerup.tex_sticky_bombs, + 'ice_bombs': powerup.tex_ice_bombs, + 'impact_bombs': powerup.tex_impact_bombs, + 'health': powerup.tex_health, + 'curse': powerup.tex_curse, + 'shield': powerup.tex_shield, + 'land_mines': powerup.tex_land_mines, + 'tnt': bs.gettexture('tnt'), + }.get(power, bs.gettexture('tnt')) + + powerupdist = { + powerup.tex_bomb: 3, + powerup.tex_ice_bombs: 2, + powerup.tex_punch: 3, + powerup.tex_impact_bombs: 3, + powerup.tex_land_mines: 3, + powerup.tex_sticky_bombs: 4, + powerup.tex_shield: 4, + powerup.tex_health: 3, + powerup.tex_curse: 1, + bs.gettexture('tnt'): 2 + } + + self.randtex = [] + + for keyTex in powerupdist: + for i in range(powerupdist[keyTex]): + self.randtex.append(keyTex) + + if power == 'random': + random.seed() + tex = random.choice(self.randtex) + + self.tex = tex + self.powerup_type = { + powerup.tex_punch: 'punch', + powerup.tex_bomb: 'triple_bombs', + powerup.tex_ice_bombs: 'ice_bombs', + powerup.tex_impact_bombs: 'impact_bombs', + powerup.tex_land_mines: 'land_mines', + powerup.tex_sticky_bombs: 'sticky_bombs', + powerup.tex_shield: 'shield', + powerup.tex_health: 'health', + powerup.tex_curse: 'curse', + bs.gettexture('tnt'): 'tnt' + }.get(self.tex, '') + + self._spawn_pos = (position[0], position[1], position[2]) + + self.node = bs.newnode( + 'prop', + delegate=self, + attrs={ + 'body': 'landMine', + 'position': self._spawn_pos, + 'mesh': fmesh, + 'light_mesh': fmeshs, + 'shadow_size': 0.5, + 'velocity': (0, 0, 0), + 'density': 90000000000, + 'sticky': False, + 'body_scale': size, + 'mesh_scale': size, + 'color_texture': tex, + 'reflection': 'powerup', + 'is_area_of_interest': True, + 'gravity_scale': 0.0, + 'reflection_scale': [0], + 'materials': [self.foothold_material, + shared.object_material, + shared.footing_material] + }) + self.touchedSpazs = set() + self.keep_vel() + + def keep_vel(self) -> None: + if self.node and not self.died: + speed = bs.getactivity().cur_speed + if self.moving: + if abs(self.node.position[0]) > 10: + self.lrSig *= -1 + self.node.velocity = ( + self.lrSig * speed * self.lrSpeedPlus,speed, 0) + bs.timer(0.1, bs.WeakCall(self.keep_vel)) + else: + self.node.velocity = (0, speed, 0) + # self.node.extraacceleration = (0, self.speed, 0) + bs.timer(0.1, bs.WeakCall(self.keep_vel)) + + def tnt_explode(self) -> None: + pos = self.node.position + Blast(position=pos, + blast_radius=6.0, + blast_type='tnt', + source_player=None).autoretain() + + def spawn_npc(self) -> None: + if not self.breakable: + return + if self._npcBots.have_living_bots(): + return + if random.randint(0, 3) >= bs.getactivity().npc_density: + return + pos = self.node.position + pos = (pos[0], pos[1] + 1, pos[2]) + self._npcBots.spawn_bot( + bot_type=random.choice([ChargerBotPro, TriggerBotPro]), + pos=pos, + spawn_time=10) + + def handlemessage(self, msg: Any) -> Any: + if isinstance(msg, bs.DieMessage): + if self.node: + self.node.delete() + self.died = True + elif isinstance(msg, bs.OutOfBoundsMessage): + self.handlemessage(bs.DieMessage()) + elif isinstance(msg, BombToDieMessage): + if self.powerup_type == 'tnt': + self.tnt_explode() + self.handlemessage(bs.DieMessage()) + elif isinstance(msg, bs.HitMessage): + ispunched = (msg.srcnode and msg.srcnode.getnodetype() == 'spaz') + if not ispunched: + if self.breakable: + self.handlemessage(BombToDieMessage()) + elif isinstance(msg, SpazTouchFoothold): + node = bs.getcollision().opposingnode + if node is not None and node: + try: + spaz = node.getdelegate(object) + if not isinstance(spaz, AbyssPlayerSpaz): + return + if spaz in self.touchedSpazs: + return + self.touchedSpazs.add(spaz) + self.spawn_npc() + spaz.fix_2D_position() + if self.powerup_type not in ['', 'tnt']: + node.handlemessage( + bs.PowerupMessage(self.powerup_type)) + except Exception as e: + print(e) + pass + + +class AbyssPlayerSpaz(PlayerSpaz): + + def __init__(self, + player: bs.Player, + color: Sequence[float] = (1.0, 1.0, 1.0), + highlight: Sequence[float] = (0.5, 0.5, 0.5), + character: str = 'Spaz', + powerups_expire: bool = True): + super().__init__(player=player, + color=color, + highlight=highlight, + character=character, + powerups_expire=powerups_expire) + self.node.fly = False + self.node.hockey = True + self.hitpoints_max = self.hitpoints = 1500 # more HP to handle drop + bs.timer(bs.getactivity().peace_time, + bs.WeakCall(self.safe_connect_controls_to_player)) + + def safe_connect_controls_to_player(self) -> None: + try: + self.connect_controls_to_player() + except: + pass + + def on_move_up_down(self, value: float) -> None: + """ + Called to set the up/down joystick amount on this spaz; + used for player or AI connections. + value will be between -32768 to 32767 + WARNING: deprecated; use on_move instead. + """ + if not self.node: + return + if self.node.run > 0.1: + self.node.move_up_down = value + else: + self.node.move_up_down = value / 3. + + def on_move_left_right(self, value: float) -> None: + """ + Called to set the left/right joystick amount on this spaz; + used for player or AI connections. + value will be between -32768 to 32767 + WARNING: deprecated; use on_move instead. + """ + if not self.node: + return + if self.node.run > 0.1: + self.node.move_left_right = value + else: + self.node.move_left_right = value / 1.5 + + def fix_2D_position(self) -> None: + self.node.fly = True + bs.timer(0.02, bs.WeakCall(self.disable_fly)) + + def disable_fly(self) -> None: + if self.node: + self.node.fly = False + + def curse(self) -> None: + """ + Give this poor spaz a curse; + he will explode in 5 seconds. + """ + if not self._cursed: + factory = SpazFactory.get() + self._cursed = True + + # Add the curse material. + for attr in ['materials', 'roller_materials']: + materials = getattr(self.node, attr) + if factory.curse_material not in materials: + setattr(self.node, attr, + materials + (factory.curse_material, )) + + # None specifies no time limit + assert self.node + if self.curse_time == -1: + self.node.curse_death_time = -1 + else: + # Note: curse-death-time takes milliseconds. + tval = bs.time() + assert isinstance(tval, (float, int)) + self.node.curse_death_time = bs.time() + 15 + bs.timer(15, bs.WeakCall(self.curse_explode)) + + def handlemessage(self, msg: Any) -> Any: + dontUp = False + + if isinstance(msg, PickupMessage): + dontUp = True + collision = bs.getcollision() + opposingnode = collision.opposingnode + opposingbody = collision.opposingbody + + if opposingnode is None or not opposingnode: + return True + opposingdelegate = opposingnode.getdelegate(object) + # Don't pick up the foothold + if isinstance(opposingdelegate, Foothold): + return True + + # dont allow picking up of invincible dudes + try: + if opposingnode.invincible: + return True + except Exception: + pass + + # if we're grabbing the pelvis of a non-shattered spaz, + # we wanna grab the torso instead + if (opposingnode.getnodetype() == 'spaz' + and not opposingnode.shattered and opposingbody == 4): + opposingbody = 1 + + + # Special case - if we're holding a flag, don't replace it + # (hmm - should make this customizable or more low level). + held = self.node.hold_node + if held and held.getnodetype() == 'flag': + return True + + # Note: hold_body needs to be set before hold_node. + self.node.hold_body = opposingbody + self.node.hold_node = opposingnode + + if not dontUp: + PlayerSpaz.handlemessage(self, msg) + + +class Player(bs.Player['Team']): + """Our player type for this game.""" + + def __init__(self) -> None: + super().__init__() + self.death_time: float | None = None + self.notIn: bool = None + + +class Team(bs.Team[Player]): + """Our team type for this game.""" + + +# ba_meta export bascenev1.GameActivity +class AbyssGame(bs.TeamGameActivity[Player, Team]): + + name = name + description = description + scoreconfig = bs.ScoreConfig(label='Survived', + scoretype=bs.ScoreType.MILLISECONDS, + version='B') + + # Print messages when players die (since its meaningful in this game). + announce_player_deaths = True + + # We're currently hard-coded for one map. + @classmethod + def get_supported_maps(cls, sessiontype: type[bs.Session]) -> list[str]: + return ['Abyss Unhappy'] + + @classmethod + def get_available_settings( + cls, sessiontype: type[bs.Session]) -> list[babase.Setting]: + settings = [ + bs.FloatChoiceSetting( + peaceTime, + choices=[ + ('None', 0.0), + ('Shorter', 2.5), + ('Short', 5.0), + ('Normal', 10.0), + ('Long', 15.0), + ('Longer', 20.0), + ], + default=10.0, + ), + bs.FloatChoiceSetting( + npcDensity, + choices=[ + ('0%', 0), + ('25%', 1), + ('50%', 2), + ('75%', 3), + ('100%', 4), + ], + default=2, + ), + bs.BoolSetting('Epic Mode', default=False), + ] + return settings + + # We support teams, free-for-all, and co-op sessions. + @classmethod + def supports_session_type(cls, sessiontype: type[bs.Session]) -> bool: + return (issubclass(sessiontype, bs.DualTeamSession) + or issubclass(sessiontype, bs.FreeForAllSession) + or issubclass(sessiontype, bs.CoopSession)) + + def __init__(self, settings: dict): + super().__init__(settings) + self._epic_mode = settings.get('Epic Mode', False) + self._last_player_death_time: float | None = None + self._timer: OnScreenTimer | None = None + self.fix_y = -5.614479365 + self.start_z = 0 + self.init_position = (0, self.start_z, self.fix_y) + self.team_init_positions = [(-5, self.start_z, self.fix_y), + (5, self.start_z, self.fix_y)] + self.cur_speed = 2.5 + # TODO: The variable below should be set in settings + self.peace_time = float(settings[peaceTime]) + self.npc_density = float(settings[npcDensity]) + + # Some base class overrides: + self.default_music = (bs.MusicType.EPIC + if self._epic_mode else bs.MusicType.SURVIVAL) + if self._epic_mode: + self.slow_motion = True + + self._game_credit = bs.NodeActor( + bs.newnode( + 'text', + attrs={ + 'v_attach': 'bottom', + 'h_align': 'center', + 'vr_depth': 0, + 'color': (0.0, 0.7, 1.0), + 'shadow': 1.0 if True else 0.5, + 'flatness': 1.0 if True else 0.5, + 'position': (0, 0), + 'scale': 0.8, + 'text': ' | '.join([author, github, blog]) + })) + + def get_instance_description(self) -> str | Sequence: + return description + + def get_instance_description_short(self) -> str | Sequence: + return self.get_instance_description() + '\n' + help + + def on_player_join(self, player: Player) -> None: + if self.has_begun(): + player.notIn = True + bs.broadcastmessage(babase.Lstr( + resource='playerDelayedJoinText', + subs=[('${PLAYER}', player.getname(full=True))]), + color=(0, 1, 0)) + self.spawn_player(player) + + def on_begin(self) -> None: + super().on_begin() + self._timer = OnScreenTimer() + self._timer.start() + + self.level_cnt = 1 + + if self.teams_or_ffa() == 'teams': + ip0 = self.team_init_positions[0] + ip1 = self.team_init_positions[1] + Foothold( + (ip0[0], ip0[1] - 2, ip0[2]), + power='shield', breakable=False).autoretain() + Foothold( + (ip1[0], ip1[1] - 2, ip1[2]), + power='shield', breakable=False).autoretain() + else: + ip = self.init_position + Foothold( + (ip[0], ip[1] - 2, ip[2]), + power='shield', breakable=False).autoretain() + + bs.timer(int(5.0 / self.cur_speed), + bs.WeakCall(self.add_foothold), repeat=True) + + # Repeat check game end + bs.timer(1.0, self._check_end_game, repeat=True) + bs.timer(self.peace_time + 0.1, + bs.WeakCall(self.tip_hint, hint_use_punch)) + bs.timer(6.0, bs.WeakCall(self.faster_speed), repeat=True) + + def tip_hint(self, text: str) -> None: + bs.broadcastmessage(text, color=(0.2, 0.2, 1)) + + def faster_speed(self) -> None: + self.cur_speed *= 1.15 + + def add_foothold(self) -> None: + ip = self.init_position + ip_1 = (ip[0] - 7, ip[1], ip[2]) + ip_2 = (ip[0] + 7, ip[1], ip[2]) + ru = random.uniform + self.level_cnt += 1 + if self.level_cnt % 3: + Foothold(( + ip_1[0] + ru(-5, 5), + ip[1] - 2, + ip[2] + ru(-0.0, 0.0))).autoretain() + Foothold(( + ip_2[0] + ru(-5, 5), + ip[1] - 2, + ip[2] + ru(-0.0, 0.0))).autoretain() + else: + Foothold(( + ip[0] + ru(-8, 8), + ip[1] - 2, + ip[2]), moving=True).autoretain() + + def teams_or_ffa(self) -> None: + if isinstance(self.session, bs.DualTeamSession): + return 'teams' + return 'ffa' + + def spawn_player_spaz(self, + player: Player, + position: Sequence[float] = (0, 0, 0), + angle: float | None = None) -> PlayerSpaz: + # pylint: disable=too-many-locals + # pylint: disable=cyclic-import + from babase import _math + from bascenev1._gameutils import animate + + position = self.init_position + if self.teams_or_ffa() == 'teams': + position = self.team_init_positions[player.team.id % 2] + angle = None + + name = player.getname() + color = player.color + highlight = player.highlight + + light_color = _math.normalized_color(color) + display_color = _babase.safecolor(color, target_intensity=0.75) + spaz = AbyssPlayerSpaz(color=color, + highlight=highlight, + character=player.character, + player=player) + + player.actor = spaz + assert spaz.node + + spaz.node.name = name + spaz.node.name_color = display_color + spaz.connect_controls_to_player(enable_punch=False, + enable_bomb=True, + enable_pickup=False) + + # Move to the stand position and add a flash of light. + spaz.handlemessage( + bs.StandMessage( + position, + angle if angle is not None else random.uniform(0, 360))) + self._spawn_sound.play(1, position=spaz.node.position) + light = bs.newnode('light', attrs={'color': light_color}) + spaz.node.connectattr('position', light, 'position') + animate(light, 'intensity', {0: 0, 0.25: 1, 0.5: 0}) + bs.timer(0.5, light.delete) + return spaz + + def handlemessage(self, msg: Any) -> Any: + if isinstance(msg, bs.PlayerDiedMessage): + + # Augment standard behavior. + super().handlemessage(msg) + + curtime = bs.time() + + # Record the player's moment of death. + # assert isinstance(msg.spaz.player + msg.getplayer(Player).death_time = curtime + + # In co-op mode, end the game the instant everyone dies + # (more accurate looking). + # In teams/ffa, allow a one-second fudge-factor so we can + # get more draws if players die basically at the same time. + if isinstance(self.session, bs.CoopSession): + # Teams will still show up if we check now.. check in + # the next cycle. + babase.pushcall(self._check_end_game) + + # Also record this for a final setting of the clock. + self._last_player_death_time = curtime + else: + bs.timer(1.0, self._check_end_game) + + else: + # Default handler: + return super().handlemessage(msg) + return None + + def _check_end_game(self) -> None: + living_team_count = 0 + for team in self.teams: + for player in team.players: + if player.is_alive(): + living_team_count += 1 + break + + # In co-op, we go till everyone is dead.. otherwise we go + # until one team remains. + if isinstance(self.session, bs.CoopSession): + if living_team_count <= 0: + self.end_game() + else: + if living_team_count <= 0: + self.end_game() + + def end_game(self) -> None: + cur_time = bs.time() + assert self._timer is not None + start_time = self._timer.getstarttime() + + # Mark death-time as now for any still-living players + # and award players points for how long they lasted. + # (these per-player scores are only meaningful in team-games) + for team in self.teams: + for player in team.players: + survived = False + if player.notIn: + player.death_time = 0 + + # Throw an extra fudge factor in so teams that + # didn't die come out ahead of teams that did. + if player.death_time is None: + survived = True + player.death_time = cur_time + 1 + + # Award a per-player score depending on how many seconds + # they lasted (per-player scores only affect teams mode; + # everywhere else just looks at the per-team score). + score = int(player.death_time - self._timer.getstarttime()) + if survived: + score += 50 # A bit extra for survivors. + self.stats.player_scored(player, score, screenmessage=False) + + # Stop updating our time text, and set the final time to match + # exactly when our last guy died. + self._timer.stop(endtime=self._last_player_death_time) + + # Ok now calc game results: set a score for each team and then tell + # the game to end. + results = bs.GameResults() + + # Remember that 'free-for-all' mode is simply a special form + # of 'teams' mode where each player gets their own team, so we can + # just always deal in teams and have all cases covered. + for team in self.teams: + + # Set the team score to the max time survived by any player on + # that team. + longest_life = 0.0 + for player in team.players: + assert player.death_time is not None + longest_life = max(longest_life, + player.death_time - start_time) + + # Submit the score value in milliseconds. + results.set_team_score(team, int(1000.0 * longest_life)) + + self.end(results=results) diff --git a/plugins/minigames/explodo_run.py b/plugins/minigames/explodo_run.py new file mode 100644 index 00000000..be013c71 --- /dev/null +++ b/plugins/minigames/explodo_run.py @@ -0,0 +1,132 @@ +# Ported to api 8 by brostos using baport.(https://github.com/bombsquad-community/baport) + +# ba_meta require api 8 +# (see https://ballistica.net/wiki/meta-tag-system) + +from __future__ import annotations + +import random +from typing import TYPE_CHECKING + +import babase +import bauiv1 as bui +import bascenev1 as bs +from bascenev1lib.actor.spazbot import SpazBotSet, ExplodeyBot, SpazBotDiedMessage +from bascenev1lib.actor.onscreentimer import OnScreenTimer + +if TYPE_CHECKING: + from typing import Any, Type, Dict, List, Optional + +def ba_get_api_version(): + return 8 + +def ba_get_levels(): + return [bs._level.Level( + 'Explodo Run', + gametype=ExplodoRunGame, + settings={}, + preview_texture_name='rampagePreview'),bs._level.Level( + 'Epic Explodo Run', + gametype=ExplodoRunGame, + settings={'Epic Mode':True}, + preview_texture_name='rampagePreview')] + +class Player(bs.Player['Team']): + """Our player type for this game.""" + + +class Team(bs.Team[Player]): + """Our team type for this game.""" + +# ba_meta export bascenev1.GameActivity +class ExplodoRunGame(bs.TeamGameActivity[Player, Team]): + name = "Explodo Run" + description = "Run For Your Life :))" + available_settings = [bs.BoolSetting('Epic Mode', default=False)] + scoreconfig = bs.ScoreConfig(label='Time', + scoretype=bs.ScoreType.MILLISECONDS, + lower_is_better=False) + default_music = bs.MusicType.TO_THE_DEATH + + def __init__(self, settings:dict): + settings['map'] = "Rampage" + self._epic_mode = settings.get('Epic Mode', False) + if self._epic_mode: + self.slow_motion = True + super().__init__(settings) + self._timer: Optional[OnScreenTimer] = None + self._winsound = bs.getsound('score') + self._won = False + self._bots = SpazBotSet() + self.wave = 1 + + def on_begin(self) -> None: + super().on_begin() + + self._timer = OnScreenTimer() + bs.timer(2.5, self._timer.start) + + #Bots Hehe + bs.timer(2.5,self.street) + + def street(self): + for a in range(self.wave): + p1 = random.choice([-5,-2.5,0,2.5,5]) + p3 = random.choice([-4.5,-4.14,-5,-3]) + time = random.choice([1,1.5,2.5,2]) + self._bots.spawn_bot(ExplodeyBot, pos=(p1,5.5,p3),spawn_time = time) + self.wave += 1 + + def botrespawn(self): + if not self._bots.have_living_bots(): + self.street() + def handlemessage(self, msg: Any) -> Any: + + # A player has died. + if isinstance(msg, bs.PlayerDiedMessage): + super().handlemessage(msg) # Augment standard behavior. + self._won = True + self.end_game() + + # A spaz-bot has died. + elif isinstance(msg, SpazBotDiedMessage): + # Unfortunately the bot-set will always tell us there are living + # bots if we ask here (the currently-dying bot isn't officially + # marked dead yet) ..so lets push a call into the event loop to + # check once this guy has finished dying. + babase.pushcall(self.botrespawn) + + # Let the base class handle anything we don't. + else: + return super().handlemessage(msg) + return None + + # When this is called, we should fill out results and end the game + # *regardless* of whether is has been won. (this may be called due + # to a tournament ending or other external reason). + def end_game(self) -> None: + + # Stop our on-screen timer so players can see what they got. + assert self._timer is not None + self._timer.stop() + + results = bs.GameResults() + + # If we won, set our score to the elapsed time in milliseconds. + # (there should just be 1 team here since this is co-op). + # ..if we didn't win, leave scores as default (None) which means + # we lost. + if self._won: + elapsed_time_ms = int((bs.time() - self._timer.starttime) * 1000.0) + bs.cameraflash() + self._winsound.play() + for team in self.teams: + for player in team.players: + if player.actor: + player.actor.handlemessage(bs.CelebrateMessage()) + results.set_team_score(team, elapsed_time_ms) + + # Ends the activity. + self.end(results) + + \ No newline at end of file diff --git a/plugins/minigames/extinction.py b/plugins/minigames/extinction.py new file mode 100644 index 00000000..39266e56 --- /dev/null +++ b/plugins/minigames/extinction.py @@ -0,0 +1,254 @@ +# Ported to api 8 by brostos using baport.(https://github.com/bombsquad-community/baport) +"""For 1.7.33""" + +# ba_meta require api 8 + +from __future__ import annotations +from typing import TYPE_CHECKING + +import babase +import bauiv1 as bui +import bascenev1 as bs +import random +from bascenev1lib.actor.bomb import BombFactory, Blast, ImpactMessage +from bascenev1lib.actor.onscreentimer import OnScreenTimer +from bascenev1lib.gameutils import SharedObjects + +if TYPE_CHECKING: + from typing import Any, Sequence, Optional, Type + + +def ba_get_api_version(): + return 8 + +def ba_get_levels(): + return [babase._level.Level( + 'Extinction', + gametype=NewMeteorShowerGame, + settings={'Epic Mode': False}, + preview_texture_name='footballStadiumPreview'), + babase._level.Level( + 'Epic Extinction', + gametype=NewMeteorShowerGame, + settings={'Epic Mode': True}, + preview_texture_name='footballStadiumPreview')] + +class Meteor(bs.Actor): + """A giant meteor instead of bombs.""" + + def __init__(self, + pos: Sequence[float] = (0.0, 1.0, 0.0), + velocity: Sequence[float] = (0.0, 0.0, 0.0)): + super().__init__() + + shared = SharedObjects.get() + factory = BombFactory.get() + + materials = (shared.object_material, + factory.impact_blast_material) + + self.pos = (pos[0], pos[1], pos[2]) + self.velocity = (velocity[0], velocity[1], velocity[2]) + + self.node = bs.newnode( + 'prop', + delegate=self, + attrs={ + 'position': self.pos, + 'velocity': self.velocity, + 'mesh': factory.sticky_bomb_mesh, + 'color_texture': factory.tnt_tex, + 'mesh_scale': 3.0, + 'body_scale': 2.99, + 'body': 'sphere', + 'shadow_size': 0.5, + 'reflection': 'soft', + 'reflection_scale': [0.45], + 'materials': materials + }) + + def explode(self) -> None: + Blast(position=self.node.position, + velocity=self.node.velocity, + blast_type='tnt', + blast_radius=2.0) + + def handlemessage(self, msg: Any) -> Any: + if isinstance(msg, bs.DieMessage): + if self.node: + self.node.delete() + elif isinstance(msg, ImpactMessage): + self.explode() + self.handlemessage(bs.DieMessage()) + else: + super().handlemessage(msg) + + +class Player(bs.Player['Team']): + """Our player type for this game.""" + + def __init__(self): + super().__init__() + self.death_time: Optional[float] = None + +class Team(bs.Team[Player]): + """Our team type for this game.""" + + +# ba_meta export bascenev1.GameActivity +class NewMeteorShowerGame(bs.TeamGameActivity[Player, Team]): + """Minigame by Jetz.""" + + name = 'Extinction' + description = 'Survive the Extinction.' + available_settings = [ + bs.BoolSetting('Epic Mode', default=False)] + + announce_player_deaths = True + + @classmethod + def get_supported_maps(cls, sessiontype: Type[bs.Session]) -> List[str]: + return ['Football Stadium'] + + @classmethod + def supports_session_type(cls, sessiontype: Type[bs.Session]) -> bool: + return (issubclass(sessiontype, bs.FreeForAllSession) + or issubclass(sessiontype, bs.DualTeamSession)) + + def __init__(self, settings: dict): + super().__init__(settings) + + self._epic_mode = bool(settings['Epic Mode']) + self._last_player_death_time: Optiobal[float] = None + self._meteor_time = 2.0 + self._timer: Optional[OnScreenTimer] = None + + self.default_music = (bs.MusicType.EPIC + if self._epic_mode else bs.MusicType.SURVIVAL) + + if self._epic_mode: + self.slow_motion = True + + def on_begin(self) -> None: + super().on_begin() + + delay = 5.0 if len(self.players) > 2 else 2.5 + if self._epic_mode: + delay *= 0.25 + bs.timer(delay, self._decrement_meteor_time, repeat=True) + + delay = 3.0 + if self._epic_mode: + delay *= 0.25 + bs.timer(delay, self._set_meteor_timer) + + self._timer = OnScreenTimer() + self._timer.start() + self._check_end_game() + + def on_player_join(self, player: Player) -> None: + if self.has_begun(): + bs.broadcastmessage( + babase.Lstr(resource='playerDelayedJoinText', + subs=[('${PLAYER}', player.getname(full=True))]), + color=(0, 1, 0), + ) + assert self._timer is not None + player.death_time = self._timer.getstarttime() + return + self.spawn_player(player) + + def spawn_player(self, player: Player) -> None: + spaz = self.spawn_player_spaz(player) + + spaz.connect_controls_to_player(enable_punch=False, + enable_pickup=False, + enable_bomb=False, + enable_jump=False) + spaz.play_big_death_sound = True + + return spaz + + def on_player_leave(self, player: Player) -> None: + super().on_player_leave(player) + + self._check_end_game() + + def handlemessage(self, msg: Any) -> Any: + if isinstance(msg, bs.PlayerDiedMessage): + curtime = bs.time() + + msg.getplayer(Player).death_time = curtime + bs.timer(1.0, self._check_end_game) + else: + return super().handlemessage(msg) + + def _spawn_meteors(self) -> None: + pos = (random.randint(-6, 7), 12, + random.uniform(-2, 1)) + velocity = (random.randint(-11, 11), 0, + random.uniform(-5, 5)) + Meteor(pos=pos, velocity=velocity).autoretain() + + def _spawn_meteors_cluster(self) -> None: + delay = 0.0 + for _i in range(random.randrange(1, 3)): + bs.timer(delay, self._spawn_meteors) + delay += 1 + self._set_meteor_timer() + + def _decrement_meteor_time(self) -> None: + self._meteor_time = max(0.01, self._meteor_time * 0.9) + + def _set_meteor_timer(self) -> None: + bs.timer((1.0 + 0.2 * random.random()) * self._meteor_time, + self._spawn_meteors_cluster) + + def _check_end_game(self) -> None: + living_team_count = 0 + for team in self.teams: + for player in team.players: + if player.is_alive(): + living_team_count += 1 + break + + if isinstance(self.session, bs.CoopSession): + if living_team_count <= 0: + self.end_game() + else: + if living_team_count <= 1: + self.end_game() + + def end_game(self) -> None: + cur_time = bs.time() + assert self._timer is not None + start_time = self._timer.getstarttime() + + for team in self.teams: + for player in team.players: + survived = False + + if player.death_time is None: + survived = True + player.death_time = cur_time + 1 + + score = int(player.death_time - self._timer.getstarttime()) + if survived: + score += 50 + self.stats.player_scored(player, score, screenmessage=False) + + self._timer.stop(endtime=self._last_player_death_time) + + results = bs.GameResults() + + for team in self.teams: + + longest_life = 0.0 + for player in team.players: + assert player.death_time is not None + longest_life = max(longest_life, + player.death_time - start_time) + + results.set_team_score(team, int(1000.0 * longest_life)) + + self.end(results=results) \ No newline at end of file diff --git a/plugins/minigames/fat_pigs.py b/plugins/minigames/fat_pigs.py new file mode 100644 index 00000000..aed1a690 --- /dev/null +++ b/plugins/minigames/fat_pigs.py @@ -0,0 +1,340 @@ +# Ported to api 8 by brostos using baport.(https://github.com/bombsquad-community/baport) +# ba_meta require api 8 + +# - - - - - - - - - - - - - - - - - - - - - +# - Fat-Pigs! by Zacker Tz || Zacker#5505 - +# - Version 0.01 :v - +# - - - - - - - - - - - - - - - - - - - - - + +from __future__ import annotations + +from typing import TYPE_CHECKING + +import random +import babase +import bauiv1 as bui +import bascenev1 as bs +from bascenev1lib.actor.bomb import Bomb +from bascenev1lib.actor.onscreentimer import OnScreenTimer +from bascenev1lib.actor.playerspaz import PlayerSpaz +from bascenev1lib.actor.scoreboard import Scoreboard + +if TYPE_CHECKING: + from typing import Any, Union, Sequence, Optional + +# - - - - - - - Mini - Settings - - - - - - - - - - - - - - - - # + +zkBombs_limit = 3 # Number of bombs you can use | Default = 3 +zkPunch = False # Enable/Disable punchs | Default = False +zkPickup = False # Enable/Disable pickup | Default = False + +# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - # + +class Player(bs.Player['Team']): + """Our player type for this game.""" + + +class Team(bs.Team[Player]): + """Our team type for this game.""" + + def __init__(self) -> None: + self.score = 0 + +# ba_meta export bascenev1.GameActivity +class FatPigs(bs.TeamGameActivity[Player, Team]): + """A game type based on acquiring kills.""" + + name = 'Fat-Pigs!' + description = 'Survive...' + + # Print messages when players die since it matters here. + announce_player_deaths = True + + @classmethod + def get_available_settings( + cls, sessiontype: type[bs.Session]) -> list[babase.Setting]: + settings = [ + bs.IntSetting( + 'Kills to Win Per Player', + min_value=1, + default=5, + increment=1, + ), + bs.IntChoiceSetting( + 'Time Limit', + choices=[ + ('None', 0), + ('1 Minute', 60), + ('2 Minutes', 120), + ('5 Minutes', 300), + ('10 Minutes', 600), + ('20 Minutes', 1200), + ], + default=0, + ), + bs.FloatChoiceSetting( + 'Respawn Times', + choices=[ + ('Shorter', 0.25), + ('Short', 0.5), + ('Normal', 1.0), + ('Long', 2.0), + ('Longer', 4.0), + ], + default=0.25, + ), + bs.BoolSetting('Epic Mode', default=False), + ] + + # In teams mode, a suicide gives a point to the other team, but in + # free-for-all it subtracts from your own score. By default we clamp + # this at zero to benefit new players, but pro players might like to + # be able to go negative. (to avoid a strategy of just + # suiciding until you get a good drop) + if issubclass(sessiontype, bs.FreeForAllSession): + settings.append( + bs.BoolSetting('Allow Negative Scores', default=False)) + + return settings + + @classmethod + def supports_session_type(cls, sessiontype: type[bs.Session]) -> bool: + return (issubclass(sessiontype, bs.DualTeamSession) + or issubclass(sessiontype, bs.FreeForAllSession)) + + @classmethod + def get_supported_maps(cls, sessiontype: type[bs.Session]) -> list[str]: + return ['Courtyard', 'Rampage', 'Monkey Face', 'Lake Frigid', 'Step Right Up'] + + def __init__(self, settings: dict): + super().__init__(settings) + self._scoreboard = Scoreboard() + self._meteor_time = 2.0 + self._score_to_win: Optional[int] = None + self._dingsound = bs.getsound('dingSmall') + self._epic_mode = bool(settings['Epic Mode']) + # self._text_credit = bool(settings['Credits']) + self._kills_to_win_per_player = int( + settings['Kills to Win Per Player']) + self._time_limit = float(settings['Time Limit']) + self._allow_negative_scores = bool( + settings.get('Allow Negative Scores', False)) + + # Base class overrides. + self.slow_motion = self._epic_mode + self.default_music = (bs.MusicType.EPIC if self._epic_mode else + bs.MusicType.TO_THE_DEATH) + + def get_instance_description(self) -> Union[str, Sequence]: + return 'Crush ${ARG1} of your enemies.', self._score_to_win + + def get_instance_description_short(self) -> Union[str, Sequence]: + return 'kill ${ARG1} enemies', self._score_to_win + + def on_team_join(self, team: Team) -> None: + if self.has_begun(): + self._update_scoreboard() + + def on_begin(self) -> None: + super().on_begin() + self.setup_standard_time_limit(self._time_limit) + # self.setup_standard_powerup_drops() + #Ambiente + gnode = bs.getactivity().globalsnode + gnode.tint = (0.8, 1.2, 0.8) + gnode.ambient_color = (0.7, 1.0, 0.6) + gnode.vignette_outer = (0.4, 0.6, 0.4) #C + # gnode.vignette_inner = (0.9, 0.9, 0.9) + + + + # Base kills needed to win on the size of the largest team. + self._score_to_win = (self._kills_to_win_per_player * + max(1, max(len(t.players) for t in self.teams))) + self._update_scoreboard() + + delay = 5.0 if len(self.players) > 2 else 2.5 + if self._epic_mode: + delay *= 0.25 + bs.timer(delay, self._decrement_meteor_time, repeat=False) + + # Kick off the first wave in a few seconds. + delay = 3.0 + if self._epic_mode: + delay *= 0.25 + bs.timer(delay, self._set_meteor_timer) + + # self._timer = OnScreenTimer() + # self._timer.start() + + # Check for immediate end (if we've only got 1 player, etc). + bs.timer(5.0, self._check_end_game) + + t = bs.newnode('text', + attrs={ 'text':"Minigame by Zacker Tz", + 'scale':0.7, + 'position':(0.001,625), + 'shadow':0.5, + 'opacity':0.7, + 'flatness':1.2, + 'color':(0.6, 1, 0.6), + 'h_align':'center', + 'v_attach':'bottom'}) + + + def spawn_player(self, player: Player) -> bs.Actor: + spaz = self.spawn_player_spaz(player) + + # Let's reconnect this player's controls to this + # spaz but *without* the ability to attack or pick stuff up. + spaz.connect_controls_to_player(enable_punch=zkPunch, + enable_bomb=True, + enable_pickup=zkPickup) + + spaz.bomb_count = zkBombs_limit + spaz._max_bomb_count = zkBombs_limit + spaz.bomb_type_default = 'sticky' + spaz.bomb_type = 'sticky' + + #cerdo gordo + spaz.node.color_mask_texture = bs.gettexture('melColorMask') + spaz.node.color_texture = bs.gettexture('melColor') + spaz.node.head_mesh = bs.getmesh('melHead') + spaz.node.hand_mesh = bs.getmesh('melHand') + spaz.node.torso_mesh = bs.getmesh('melTorso') + spaz.node.pelvis_mesh = bs.getmesh('kronkPelvis') + spaz.node.upper_arm_mesh = bs.getmesh('melUpperArm') + spaz.node.forearm_mesh = bs.getmesh('melForeArm') + spaz.node.upper_leg_mesh = bs.getmesh('melUpperLeg') + spaz.node.lower_leg_mesh = bs.getmesh('melLowerLeg') + spaz.node.toes_mesh = bs.getmesh('melToes') + spaz.node.style = 'mel' + # Sounds cerdo gordo + mel_sounds = [bs.getsound('mel01'), bs.getsound('mel02'),bs.getsound('mel03'),bs.getsound('mel04'),bs.getsound('mel05'), + bs.getsound('mel06'),bs.getsound('mel07'),bs.getsound('mel08'),bs.getsound('mel09'),bs.getsound('mel10')] + spaz.node.jump_sounds = mel_sounds + spaz.node.attack_sounds = mel_sounds + spaz.node.impact_sounds = mel_sounds + spaz.node.pickup_sounds = mel_sounds + spaz.node.death_sounds = [bs.getsound('melDeath01')] + spaz.node.fall_sounds = [bs.getsound('melFall01')] + + def _set_meteor_timer(self) -> None: + bs.timer((1.0 + 0.2 * random.random()) * self._meteor_time, + self._drop_bomb_cluster) + + def _drop_bomb_cluster(self) -> None: + + # Random note: code like this is a handy way to plot out extents + # and debug things. + loc_test = False + if loc_test: + bs.newnode('locator', attrs={'position': (8, 6, -5.5)}) + bs.newnode('locator', attrs={'position': (8, 6, -2.3)}) + bs.newnode('locator', attrs={'position': (-7.3, 6, -5.5)}) + bs.newnode('locator', attrs={'position': (-7.3, 6, -2.3)}) + + # Drop several bombs in series. + delay = 0.0 + for _i in range(random.randrange(1, 3)): + # Drop them somewhere within our bounds with velocity pointing + # toward the opposite side. + pos = (-7.3 + 15.3 * random.random(), 11, + -5.5 + 2.1 * random.random()) + dropdir = (-1.0 if pos[0] > 0 else 1.0) + vel = ((-5.0 + random.random() * 30.0) * dropdir, -4.0, 0) + bs.timer(delay, babase.Call(self._drop_bomb, pos, vel)) + delay += 0.1 + self._set_meteor_timer() + + def _drop_bomb(self, position: Sequence[float], + velocity: Sequence[float]) -> None: + Bomb(position=position, velocity=velocity,bomb_type='sticky').autoretain() + + def _decrement_meteor_time(self) -> None: + self._meteor_time = max(0.01, self._meteor_time * 0.9) + + + def handlemessage(self, msg: Any) -> Any: + + if isinstance(msg, bs.PlayerDiedMessage): + + # Augment standard behavior. + super().handlemessage(msg) + + player = msg.getplayer(Player) + self.respawn_player(player) + + killer = msg.getkillerplayer(Player) + if killer is None: + return None + + # Handle team-kills. + if killer.team is player.team: + + # In free-for-all, killing yourself loses you a point. + if isinstance(self.session, bs.FreeForAllSession): + new_score = player.team.score - 1 + if not self._allow_negative_scores: + new_score = max(0, new_score) + player.team.score = new_score + + # In teams-mode it gives a point to the other team. + else: + self._dingsound.play() + for team in self.teams: + if team is not killer.team: + team.score += 1 + + # Killing someone on another team nets a kill. + else: + killer.team.score += 1 + self._dingsound.play() + + # In FFA show scores since its hard to find on the scoreboard. + if isinstance(killer.actor, PlayerSpaz) and killer.actor: + killer.actor.set_score_text(str(killer.team.score) + '/' + + str(self._score_to_win), + color=killer.team.color, + flash=True) + + self._update_scoreboard() + + # If someone has won, set a timer to end shortly. + # (allows the dust to clear and draws to occur if deaths are + # close enough) + assert self._score_to_win is not None + if any(team.score >= self._score_to_win for team in self.teams): + bs.timer(0.5, self.end_game) + + else: + return super().handlemessage(msg) + return None + + def _check_end_game(self) -> None: + living_team_count = 0 + for team in self.teams: + for player in team.players: + if player.is_alive(): + living_team_count += 1 + break + + # In co-op, we go till everyone is dead.. otherwise we go + # until one team remains. + if isinstance(self.session, bs.CoopSession): + if living_team_count <= 0: + self.end_game() + else: + if living_team_count <= 1: + self.end_game() + + def _update_scoreboard(self) -> None: + for team in self.teams: + self._scoreboard.set_team_value(team, team.score, + self._score_to_win) + + def end_game(self) -> None: + results = bs.GameResults() + for team in self.teams: + results.set_team_score(team, team.score) + self.end(results=results) diff --git a/plugins/utilities.json b/plugins/utilities.json index db809c69..0a5c0940 100644 --- a/plugins/utilities.json +++ b/plugins/utilities.json @@ -1149,7 +1149,7 @@ } }, "ba_colours": { - "description": "Try to survive from bots!", + "description": "Colourful bots and more", "external_url": "", "authors": [ { @@ -1161,6 +1161,20 @@ "versions": { "1.0.0": null } + }, + "xyz_tool": { + "description": "Punch to save the co-ordinates", + "external_url": "", + "authors": [ + { + "name": "", + "email": "", + "discord": "" + } + ], + "versions": { + "1.0.0": null + } } } } \ No newline at end of file diff --git a/plugins/utilities/xyz_tool.py b/plugins/utilities/xyz_tool.py new file mode 100644 index 00000000..2ad1efda --- /dev/null +++ b/plugins/utilities/xyz_tool.py @@ -0,0 +1,85 @@ +# Ported to api 8 by brostos using baport.(https://github.com/bombsquad-community/baport) +# Released under the MIT License. See LICENSE for details. +# ba_meta require api 8 + +from __future__ import annotations +from typing import TYPE_CHECKING +from bascenev1lib.actor.playerspaz import PlayerSpaz +from bascenev1lib.actor.spazfactory import SpazFactory +import babase +import bauiv1 as bui +import bascenev1 as bs +import math +import os +import _babase +import shutil +if TYPE_CHECKING: + pass + +DECIMAL_LIMIT = 7 + + +PlayerSpaz.supershit = PlayerSpaz.__init__ +def ShitInit(self, + player: bs.Player, + color: Sequence[float] = (1.0, 1.0, 1.0), + highlight: Sequence[float] = (0.5, 0.5, 0.5), + character: str = 'Spaz', + powerups_expire: bool = True) -> None: + self.supershit(player, color, highlight, character, powerups_expire) + self.offt = bs.newnode('math', owner=self.node, attrs={'input1': (1.2, 1.8, -0.7),'operation': 'add'}) + self.node.connectattr('torso_position', self.offt, 'input2') + self.txt = bs.newnode('text', owner=self.node, attrs={'text': '3.0','in_world': True,'text':'0','shadow': 1.0,'color': (1,0,0),'flatness': 0.5,'scale': 0.01,'h_align': 'right'}) + p = self.node.position + self.xyz = 0 + self.txt.text = "X: " + str(p[0]) + "\nY: " + str(p[1]) + "\nZ: " + str(p[2]) + self.offt.connectattr('output', self.txt, 'position') + def update(): + p = self.node.position + is_moving = abs(self.node.move_up_down) >= 0.01 or abs(self.node.move_left_right) >= 0.01 + if is_moving: + self.xyz = (p[0],p[1],p[2]) + self.txt.text = "X: " + str(round(self.xyz[0],DECIMAL_LIMIT)) + "\nY: " + str(round(self.xyz[1],DECIMAL_LIMIT)) + "\nZ: " + str(round(self.xyz[2],DECIMAL_LIMIT)) + bs.timer(0.1,update,repeat=True) + +def replaceable_punch(self) -> None: + """ + Called to 'press punch' on this spaz; + used for player or AI connections. + """ + if not self.node or self.frozen or self.node.knockout > 0.0: + return + index = 0 + path_aid = _babase.env()['python_directory_user'] + '/Saved XYZ' + path, dirs, files = next(os.walk(path_aid)) + index += len(files) + c27 = str(index + 1) + with open(path_aid + '/coords' + c27 + '.txt', 'w') as gg: + gg.write("X: " + str(round(self.xyz[0],DECIMAL_LIMIT)) + "\nY: " + str(round(self.xyz[1],DECIMAL_LIMIT)) + "\nZ: " + str(round(self.xyz[2],DECIMAL_LIMIT)) + '\n\n' + '(' + str(round(self.xyz[0],DECIMAL_LIMIT)) + ', ' + str(round(self.xyz[1],DECIMAL_LIMIT)) + ', ' + str(round(self.xyz[2],DECIMAL_LIMIT)) + ')') + bui.screenmessage("Coordinates saved in: " + "BombSquad/Saved XYZ/" + "coords" + c27) + if _babase.app.classic.platform == 'android': + _babase.android_media_scan_file(path_aid) + t_ms = bs.time() * 1000 + assert isinstance(t_ms, int) + if t_ms - self.last_punch_time_ms >= self._punch_cooldown: + if self.punch_callback is not None: + self.punch_callback(self) + self._punched_nodes = set() # Reset this. + self.last_punch_time_ms = t_ms + self.node.punch_pressed = True + if not self.node.hold_node: + bs.timer( + 0.1, + bs.WeakCall(self._safe_play_sound, + SpazFactory.get().swish_sound, 0.8)) + self._turbo_filter_add_press('punch') + +# ba_meta export plugin +class ragingspeedhorn(babase.Plugin): + try: + oath = _babase.env()['python_directory_user'] + '/Saved XYZ' + os.makedirs(oath,exist_ok=False) + except: pass + PlayerSpaz.on_punch_press = replaceable_punch + PlayerSpaz.__init__ = ShitInit + PlayerSpaz.xyz = 0 \ No newline at end of file From e7158a0878c9a184eb8b39b8fbe6c9dbdf6a564d Mon Sep 17 00:00:00 2001 From: brostosjoined Date: Thu, 1 Feb 2024 08:58:54 +0000 Subject: [PATCH 0843/1464] [ci] auto-format --- plugins/minigames/better_deathmatch.py | 22 +- plugins/minigames/better_elimination.py | 49 +- plugins/minigames/bot_shower.py | 7 +- plugins/minigames/down_into_the_abyss.py | 1457 +++++++++++----------- plugins/minigames/explodo_run.py | 52 +- plugins/minigames/extinction.py | 95 +- plugins/minigames/fat_pigs.py | 65 +- plugins/utilities/xyz_tool.py | 51 +- 8 files changed, 907 insertions(+), 891 deletions(-) diff --git a/plugins/minigames/better_deathmatch.py b/plugins/minigames/better_deathmatch.py index 34116a59..6882c8ad 100644 --- a/plugins/minigames/better_deathmatch.py +++ b/plugins/minigames/better_deathmatch.py @@ -1,6 +1,6 @@ # Ported to api 8 by brostos using baport.(https://github.com/bombsquad-community/baport) -#BetterDeathMatch -#Made by your friend: @[Just] Freak#4999 +# BetterDeathMatch +# Made by your friend: @[Just] Freak#4999 """Defines a very-customisable DeathMatch mini-game""" @@ -77,7 +77,7 @@ def get_available_settings( bs.BoolSetting('Epic Mode', default=False), -## Add settings ## + ## Add settings ## bs.BoolSetting('Enable Gloves', False), bs.BoolSetting('Enable Powerups', True), bs.BoolSetting('Night Mode', False), @@ -85,10 +85,9 @@ def get_available_settings( bs.BoolSetting('One Punch Kill', False), bs.BoolSetting('Spawn with Shield', False), bs.BoolSetting('Punching Only', False), -## Add settings ## + ## Add settings ## ] - # In teams mode, a suicide gives a point to the other team, but in # free-for-all it subtracts from your own score. By default we clamp # this at zero to benefit new players, but pro players might like to @@ -126,7 +125,6 @@ def __init__(self, settings: dict): self._only_punch = bool(settings['Punching Only']) ## Take applied settings ## - self._epic_mode = bool(settings['Epic Mode']) self._kills_to_win_per_player = int( settings['Kills to Win Per Player']) @@ -151,6 +149,8 @@ def on_team_join(self, team: Team) -> None: ## Run settings related: IcyFloor ## + + def on_transition_in(self) -> None: super().on_transition_in() activity = bs.getactivity() @@ -160,8 +160,6 @@ def on_transition_in(self) -> None: return ## Run settings related: IcyFloor ## - - def on_begin(self) -> None: super().on_begin() self.setup_standard_time_limit(self._time_limit) @@ -172,15 +170,14 @@ def on_begin(self) -> None: bs.getactivity().globalsnode.tint = (0.5, 0.7, 1) else: pass -#-# Tried return here, pfft. Took me 30mins to figure out why pwps spawning only on NightMode -#-# Now its fixed :) +# -# Tried return here, pfft. Took me 30mins to figure out why pwps spawning only on NightMode +# -# Now its fixed :) if self._enable_powerups: self.setup_standard_powerup_drops() else: pass ## Run settings related: NightMode,Powerups ## - # Base kills needed to win on the size of the largest team. self._score_to_win = (self._kills_to_win_per_player * max(1, max(len(t.players) for t in self.teams))) @@ -244,6 +241,8 @@ def handlemessage(self, msg: Any) -> Any: ## Run settings related: Spaz ## + + def spawn_player(self, player: Player) -> bs.Actor: spaz = self.spawn_player_spaz(player) if self._boxing_gloves: @@ -258,7 +257,6 @@ def spawn_player(self, player: Player) -> bs.Actor: return spaz ## Run settings related: Spaz ## - def _update_scoreboard(self) -> None: for team in self.teams: self._scoreboard.set_team_value(team, team.score, diff --git a/plugins/minigames/better_elimination.py b/plugins/minigames/better_elimination.py index 6ff29100..8edd4c10 100644 --- a/plugins/minigames/better_elimination.py +++ b/plugins/minigames/better_elimination.py @@ -1,8 +1,8 @@ # Ported to api 8 by brostos using baport.(https://github.com/bombsquad-community/baport) -#BetterElimination -#Made by your friend: @[Just] Freak#4999 +# BetterElimination +# Made by your friend: @[Just] Freak#4999 -#Huge Thx to Nippy for "Live Team Balance" +# Huge Thx to Nippy for "Live Team Balance" """Defines a very-customisable Elimination mini-game""" @@ -222,7 +222,7 @@ def get_available_settings( bs.BoolSetting('Epic Mode', default=False), -## Add settings ## + ## Add settings ## bs.BoolSetting('Live Team Balance (by Nippy#2677)', True), bs.BoolSetting('Enable Gloves', False), bs.BoolSetting('Enable Powerups', True), @@ -231,7 +231,7 @@ def get_available_settings( bs.BoolSetting('One Punch Kill', False), bs.BoolSetting('Spawn with Shield', False), bs.BoolSetting('Punching Only', False), -## Add settings ## + ## Add settings ## ] if issubclass(sessiontype, bs.DualTeamSession): settings.append(bs.BoolSetting('Solo Mode', default=False)) @@ -299,7 +299,7 @@ def on_player_join(self, player: Player) -> None: player.team.survival_seconds = 0 bui.screenmessage( babase.Lstr(resource='playerDelayedJoinText', - subs=[('${PLAYER}', player.getname(full=True))]), + subs=[('${PLAYER}', player.getname(full=True))]), color=(0, 1, 0), ) return @@ -321,6 +321,8 @@ def on_player_join(self, player: Player) -> None: ## Run settings related: IcyFloor ## + + def on_transition_in(self) -> None: super().on_transition_in() activity = bs.getactivity() @@ -330,8 +332,6 @@ def on_transition_in(self) -> None: return ## Run settings related: IcyFloor ## - - def on_begin(self) -> None: super().on_begin() self._start_time = bs.time() @@ -343,15 +343,14 @@ def on_begin(self) -> None: bs.getactivity().globalsnode.tint = (0.5, 0.7, 1) else: pass -#-# Tried return here, pfft. Took me 30mins to figure out why pwps spawning only on NightMode -#-# Now its fixed :) +# -# Tried return here, pfft. Took me 30mins to figure out why pwps spawning only on NightMode +# -# Now its fixed :) if self._enable_powerups: self.setup_standard_powerup_drops() else: pass ## Run settings related: NightMode,Powerups ## - if self._solo_mode: self._vs_text = bs.NodeActor( bs.newnode('text', @@ -526,7 +525,6 @@ def spawn_player(self, player: Player) -> bs.Actor: return actor ## Run settings related: Spaz ## - def _print_lives(self, player: Player) -> None: from bascenev1lib.actor import popuptext @@ -542,24 +540,25 @@ def _print_lives(self, player: Player) -> None: position=player.node.position).autoretain() def on_player_leave(self, player: Player) -> None: - ########################################################Nippy#2677 - team_count=1 #Just initiating - if player.lives>0 and self._live_team_balance: - team_mem=[] + # Nippy#2677 + team_count = 1 # Just initiating + if player.lives > 0 and self._live_team_balance: + team_mem = [] for teamer in player.team.players: - if player!=teamer: - team_mem.append(teamer) #Got Dead players Team - live=player.lives - team_count=len(team_mem) - for i in range(int((live if live%2==0 else live+1)/2)): #Extending Player List for Sorted Players + if player != teamer: + team_mem.append(teamer) # Got Dead players Team + live = player.lives + team_count = len(team_mem) + # Extending Player List for Sorted Players + for i in range(int((live if live % 2 == 0 else live+1)/2)): team_mem.extend(team_mem) - if team_count>0: + if team_count > 0: for i in range(live): - team_mem[i].lives+=1 + team_mem[i].lives += 1 - if team_count<=0 : #Draw if Player Leaves + if team_count <= 0: # Draw if Player Leaves self.end_game() - ########################################################Nippy#2677 + # Nippy#2677 super().on_player_leave(player) player.icons = [] diff --git a/plugins/minigames/bot_shower.py b/plugins/minigames/bot_shower.py index ebbd14bf..bbc6da93 100644 --- a/plugins/minigames/bot_shower.py +++ b/plugins/minigames/bot_shower.py @@ -123,7 +123,7 @@ def on_player_join(self, player: Player) -> None: if self.has_begun(): bui.screenmessage( babase.Lstr(resource='playerDelayedJoinText', - subs=[('${PLAYER}', player.getname(full=True))]), + subs=[('${PLAYER}', player.getname(full=True))]), color=(1, 1, 0), ) @@ -147,7 +147,8 @@ def _start_spawning_bots(self) -> None: def _spawn_bot(self) -> None: assert self._bots is not None - self._bots.spawn_bot(random.choice(self._bot_type), pos=(random.uniform(-11, 11), (9.8 if self.map.getname() == 'Football Stadium' else 5.0), random.uniform(-5, 5))) + self._bots.spawn_bot(random.choice(self._bot_type), pos=( + random.uniform(-11, 11), (9.8 if self.map.getname() == 'Football Stadium' else 5.0), random.uniform(-5, 5))) def _check_end_game(self) -> None: living_team_count = 0 @@ -192,4 +193,4 @@ def end_game(self) -> None: results.set_team_score(team, int(1000.0 * longest_life)) - self.end(results=results) \ No newline at end of file + self.end(results=results) diff --git a/plugins/minigames/down_into_the_abyss.py b/plugins/minigames/down_into_the_abyss.py index 2ecac4e7..ab26ef58 100644 --- a/plugins/minigames/down_into_the_abyss.py +++ b/plugins/minigames/down_into_the_abyss.py @@ -22,768 +22,769 @@ from bascenev1lib.actor.onscreentimer import OnScreenTimer if TYPE_CHECKING: - from typing import Any, Sequence + from typing import Any, Sequence lang = bs.app.lang.language if lang == 'Spanish': - name = 'Abajo en el Abismo' - description = 'Sobrevive tanto como puedas' - help = 'El mapa es 3D, ¡ten cuidado!' - author = 'Autor: Deva' - github = 'GitHub: spdv123' - blog = 'Blog: superdeva.info' - peaceTime = 'Tiempo de Paz' - npcDensity = 'Densidad de Enemigos' - hint_use_punch = '¡Ahora puedes golpear a los enemigos!' + name = 'Abajo en el Abismo' + description = 'Sobrevive tanto como puedas' + help = 'El mapa es 3D, ¡ten cuidado!' + author = 'Autor: Deva' + github = 'GitHub: spdv123' + blog = 'Blog: superdeva.info' + peaceTime = 'Tiempo de Paz' + npcDensity = 'Densidad de Enemigos' + hint_use_punch = '¡Ahora puedes golpear a los enemigos!' elif lang == 'Chinese': - name = '无尽深渊' - description = '在无穷尽的坠落中存活更长时间' - help = '' - author = '作者: Deva' - github = 'GitHub: spdv123' - blog = '博客: superdeva.info' - peaceTime = '和平时间' - npcDensity = 'NPC密度' - hint_use_punch = u'现在可以使用拳头痛扁你的敌人了' + name = '无尽深渊' + description = '在无穷尽的坠落中存活更长时间' + help = '' + author = '作者: Deva' + github = 'GitHub: spdv123' + blog = '博客: superdeva.info' + peaceTime = '和平时间' + npcDensity = 'NPC密度' + hint_use_punch = u'现在可以使用拳头痛扁你的敌人了' else: - name = 'Down Into The Abyss' - description = 'Survive as long as you can' - help = 'The map is 3D, be careful!' - author = 'Author: Deva' - github = 'GitHub: spdv123' - blog = 'Blog: superdeva.info' - peaceTime = 'Peace Time' - npcDensity = 'NPC Density' - hint_use_punch = 'You can punch your enemies now!' + name = 'Down Into The Abyss' + description = 'Survive as long as you can' + help = 'The map is 3D, be careful!' + author = 'Author: Deva' + github = 'GitHub: spdv123' + blog = 'Blog: superdeva.info' + peaceTime = 'Peace Time' + npcDensity = 'NPC Density' + hint_use_punch = 'You can punch your enemies now!' class AbyssMap(bs.Map): - from bascenev1lib.mapdata import happy_thoughts as defs - # Add the y-dimension space for players - defs.boxes['map_bounds'] = (-0.8748348681, 9.212941713, -9.729538885) \ - + (0.0, 0.0, 0.0) \ - + (36.09666006, 26.19950145, 20.89541168) - name = 'Abyss Unhappy' - - @classmethod - def get_play_types(cls) -> list[str]: - """Return valid play types for this map.""" - return ['abyss'] - - @classmethod - def get_preview_texture_name(cls) -> str: - return 'alwaysLandPreview' - - @classmethod - def on_preload(cls) -> Any: - data: dict[str, Any] = { - 'mesh': bs.getmesh('alwaysLandLevel'), - 'bottom_mesh': bs.getmesh('alwaysLandLevelBottom'), - 'bgmesh': bs.getmesh('alwaysLandBG'), - 'collision_mesh': bs.getcollisionmesh('alwaysLandLevelCollide'), - 'tex': bs.gettexture('alwaysLandLevelColor'), - 'bgtex': bs.gettexture('alwaysLandBGColor'), - 'vr_fill_mound_mesh': bs.getmesh('alwaysLandVRFillMound'), - 'vr_fill_mound_tex': bs.gettexture('vrFillMound') - } - return data - - @classmethod - def get_music_type(cls) -> bs.MusicType: - return bs.MusicType.FLYING - - def __init__(self) -> None: - super().__init__(vr_overlay_offset=(0, -3.7, 2.5)) - self.background = bs.newnode( - 'terrain', - attrs={ - 'mesh': self.preloaddata['bgmesh'], - 'lighting': False, - 'background': True, - 'color_texture': self.preloaddata['bgtex'] - }) - bs.newnode('terrain', - attrs={ - 'mesh': self.preloaddata['vr_fill_mound_mesh'], - 'lighting': False, - 'vr_only': True, - 'color': (0.2, 0.25, 0.2), - 'background': True, - 'color_texture': self.preloaddata['vr_fill_mound_tex'] - }) - gnode = bs.getactivity().globalsnode - gnode.happy_thoughts_mode = True - gnode.shadow_offset = (0.0, 8.0, 5.0) - gnode.tint = (1.3, 1.23, 1.0) - gnode.ambient_color = (1.3, 1.23, 1.0) - gnode.vignette_outer = (0.64, 0.59, 0.69) - gnode.vignette_inner = (0.95, 0.95, 0.93) - gnode.vr_near_clip = 1.0 - self.is_flying = True + from bascenev1lib.mapdata import happy_thoughts as defs + # Add the y-dimension space for players + defs.boxes['map_bounds'] = (-0.8748348681, 9.212941713, -9.729538885) \ + + (0.0, 0.0, 0.0) \ + + (36.09666006, 26.19950145, 20.89541168) + name = 'Abyss Unhappy' + + @classmethod + def get_play_types(cls) -> list[str]: + """Return valid play types for this map.""" + return ['abyss'] + + @classmethod + def get_preview_texture_name(cls) -> str: + return 'alwaysLandPreview' + + @classmethod + def on_preload(cls) -> Any: + data: dict[str, Any] = { + 'mesh': bs.getmesh('alwaysLandLevel'), + 'bottom_mesh': bs.getmesh('alwaysLandLevelBottom'), + 'bgmesh': bs.getmesh('alwaysLandBG'), + 'collision_mesh': bs.getcollisionmesh('alwaysLandLevelCollide'), + 'tex': bs.gettexture('alwaysLandLevelColor'), + 'bgtex': bs.gettexture('alwaysLandBGColor'), + 'vr_fill_mound_mesh': bs.getmesh('alwaysLandVRFillMound'), + 'vr_fill_mound_tex': bs.gettexture('vrFillMound') + } + return data + + @classmethod + def get_music_type(cls) -> bs.MusicType: + return bs.MusicType.FLYING + + def __init__(self) -> None: + super().__init__(vr_overlay_offset=(0, -3.7, 2.5)) + self.background = bs.newnode( + 'terrain', + attrs={ + 'mesh': self.preloaddata['bgmesh'], + 'lighting': False, + 'background': True, + 'color_texture': self.preloaddata['bgtex'] + }) + bs.newnode('terrain', + attrs={ + 'mesh': self.preloaddata['vr_fill_mound_mesh'], + 'lighting': False, + 'vr_only': True, + 'color': (0.2, 0.25, 0.2), + 'background': True, + 'color_texture': self.preloaddata['vr_fill_mound_tex'] + }) + gnode = bs.getactivity().globalsnode + gnode.happy_thoughts_mode = True + gnode.shadow_offset = (0.0, 8.0, 5.0) + gnode.tint = (1.3, 1.23, 1.0) + gnode.ambient_color = (1.3, 1.23, 1.0) + gnode.vignette_outer = (0.64, 0.59, 0.69) + gnode.vignette_inner = (0.95, 0.95, 0.93) + gnode.vr_near_clip = 1.0 + self.is_flying = True + register_map(AbyssMap) class SpazTouchFoothold: - pass + pass + class BombToDieMessage: - pass + pass class Foothold(bs.Actor): - def __init__(self, - position: Sequence[float] = (0.0, 1.0, 0.0), - power: str = 'random', - size: float = 6.0, - breakable: bool = True, - moving: bool = False): - super().__init__() - shared = SharedObjects.get() - powerup = PowerupBoxFactory.get() - - fmesh = bs.getmesh('landMine') - fmeshs = bs.getmesh('powerupSimple') - self.died = False - self.breakable = breakable - self.moving = moving # move right and left - self.lrSig = 1 # left or right signal - self.lrSpeedPlus = random.uniform(1 / 2.0, 1 / 0.7) - self._npcBots = SpazBotSet() - - self.foothold_material = bs.Material() - self.impact_sound = bui.getsound('impactMedium') - - self.foothold_material.add_actions( - conditions=(('they_dont_have_material', shared.player_material), - 'and', - ('they_have_material', shared.object_material), - 'or', - ('they_have_material', shared.footing_material)), - actions=(('modify_node_collision', 'collide', True), - )) - - self.foothold_material.add_actions( - conditions=('they_have_material', shared.player_material), - actions=(('modify_part_collision', 'physical', True), - ('modify_part_collision', 'stiffness', 0.05), - ('message', 'our_node', 'at_connect', SpazTouchFoothold()), - )) - - self.foothold_material.add_actions( - conditions=('they_have_material', self.foothold_material), - actions=('modify_node_collision', 'collide', False), - ) - - tex = { - 'punch': powerup.tex_punch, - 'sticky_bombs': powerup.tex_sticky_bombs, - 'ice_bombs': powerup.tex_ice_bombs, - 'impact_bombs': powerup.tex_impact_bombs, - 'health': powerup.tex_health, - 'curse': powerup.tex_curse, - 'shield': powerup.tex_shield, - 'land_mines': powerup.tex_land_mines, - 'tnt': bs.gettexture('tnt'), - }.get(power, bs.gettexture('tnt')) - - powerupdist = { - powerup.tex_bomb: 3, - powerup.tex_ice_bombs: 2, - powerup.tex_punch: 3, - powerup.tex_impact_bombs: 3, - powerup.tex_land_mines: 3, - powerup.tex_sticky_bombs: 4, - powerup.tex_shield: 4, - powerup.tex_health: 3, - powerup.tex_curse: 1, - bs.gettexture('tnt'): 2 - } - - self.randtex = [] - - for keyTex in powerupdist: - for i in range(powerupdist[keyTex]): - self.randtex.append(keyTex) - - if power == 'random': - random.seed() - tex = random.choice(self.randtex) - - self.tex = tex - self.powerup_type = { - powerup.tex_punch: 'punch', - powerup.tex_bomb: 'triple_bombs', - powerup.tex_ice_bombs: 'ice_bombs', - powerup.tex_impact_bombs: 'impact_bombs', - powerup.tex_land_mines: 'land_mines', - powerup.tex_sticky_bombs: 'sticky_bombs', - powerup.tex_shield: 'shield', - powerup.tex_health: 'health', - powerup.tex_curse: 'curse', - bs.gettexture('tnt'): 'tnt' - }.get(self.tex, '') - - self._spawn_pos = (position[0], position[1], position[2]) - - self.node = bs.newnode( - 'prop', - delegate=self, - attrs={ - 'body': 'landMine', - 'position': self._spawn_pos, - 'mesh': fmesh, - 'light_mesh': fmeshs, - 'shadow_size': 0.5, - 'velocity': (0, 0, 0), - 'density': 90000000000, - 'sticky': False, - 'body_scale': size, - 'mesh_scale': size, - 'color_texture': tex, - 'reflection': 'powerup', - 'is_area_of_interest': True, - 'gravity_scale': 0.0, - 'reflection_scale': [0], - 'materials': [self.foothold_material, - shared.object_material, - shared.footing_material] - }) - self.touchedSpazs = set() - self.keep_vel() - - def keep_vel(self) -> None: - if self.node and not self.died: - speed = bs.getactivity().cur_speed - if self.moving: - if abs(self.node.position[0]) > 10: - self.lrSig *= -1 - self.node.velocity = ( - self.lrSig * speed * self.lrSpeedPlus,speed, 0) - bs.timer(0.1, bs.WeakCall(self.keep_vel)) - else: - self.node.velocity = (0, speed, 0) - # self.node.extraacceleration = (0, self.speed, 0) - bs.timer(0.1, bs.WeakCall(self.keep_vel)) - - def tnt_explode(self) -> None: - pos = self.node.position - Blast(position=pos, - blast_radius=6.0, - blast_type='tnt', - source_player=None).autoretain() - - def spawn_npc(self) -> None: - if not self.breakable: - return - if self._npcBots.have_living_bots(): - return - if random.randint(0, 3) >= bs.getactivity().npc_density: - return - pos = self.node.position - pos = (pos[0], pos[1] + 1, pos[2]) - self._npcBots.spawn_bot( - bot_type=random.choice([ChargerBotPro, TriggerBotPro]), - pos=pos, - spawn_time=10) - - def handlemessage(self, msg: Any) -> Any: - if isinstance(msg, bs.DieMessage): - if self.node: - self.node.delete() - self.died = True - elif isinstance(msg, bs.OutOfBoundsMessage): - self.handlemessage(bs.DieMessage()) - elif isinstance(msg, BombToDieMessage): - if self.powerup_type == 'tnt': - self.tnt_explode() - self.handlemessage(bs.DieMessage()) - elif isinstance(msg, bs.HitMessage): - ispunched = (msg.srcnode and msg.srcnode.getnodetype() == 'spaz') - if not ispunched: - if self.breakable: - self.handlemessage(BombToDieMessage()) - elif isinstance(msg, SpazTouchFoothold): - node = bs.getcollision().opposingnode - if node is not None and node: - try: - spaz = node.getdelegate(object) - if not isinstance(spaz, AbyssPlayerSpaz): - return - if spaz in self.touchedSpazs: - return - self.touchedSpazs.add(spaz) - self.spawn_npc() - spaz.fix_2D_position() - if self.powerup_type not in ['', 'tnt']: - node.handlemessage( - bs.PowerupMessage(self.powerup_type)) - except Exception as e: - print(e) - pass + def __init__(self, + position: Sequence[float] = (0.0, 1.0, 0.0), + power: str = 'random', + size: float = 6.0, + breakable: bool = True, + moving: bool = False): + super().__init__() + shared = SharedObjects.get() + powerup = PowerupBoxFactory.get() + + fmesh = bs.getmesh('landMine') + fmeshs = bs.getmesh('powerupSimple') + self.died = False + self.breakable = breakable + self.moving = moving # move right and left + self.lrSig = 1 # left or right signal + self.lrSpeedPlus = random.uniform(1 / 2.0, 1 / 0.7) + self._npcBots = SpazBotSet() + + self.foothold_material = bs.Material() + self.impact_sound = bui.getsound('impactMedium') + + self.foothold_material.add_actions( + conditions=(('they_dont_have_material', shared.player_material), + 'and', + ('they_have_material', shared.object_material), + 'or', + ('they_have_material', shared.footing_material)), + actions=(('modify_node_collision', 'collide', True), + )) + + self.foothold_material.add_actions( + conditions=('they_have_material', shared.player_material), + actions=(('modify_part_collision', 'physical', True), + ('modify_part_collision', 'stiffness', 0.05), + ('message', 'our_node', 'at_connect', SpazTouchFoothold()), + )) + + self.foothold_material.add_actions( + conditions=('they_have_material', self.foothold_material), + actions=('modify_node_collision', 'collide', False), + ) + + tex = { + 'punch': powerup.tex_punch, + 'sticky_bombs': powerup.tex_sticky_bombs, + 'ice_bombs': powerup.tex_ice_bombs, + 'impact_bombs': powerup.tex_impact_bombs, + 'health': powerup.tex_health, + 'curse': powerup.tex_curse, + 'shield': powerup.tex_shield, + 'land_mines': powerup.tex_land_mines, + 'tnt': bs.gettexture('tnt'), + }.get(power, bs.gettexture('tnt')) + + powerupdist = { + powerup.tex_bomb: 3, + powerup.tex_ice_bombs: 2, + powerup.tex_punch: 3, + powerup.tex_impact_bombs: 3, + powerup.tex_land_mines: 3, + powerup.tex_sticky_bombs: 4, + powerup.tex_shield: 4, + powerup.tex_health: 3, + powerup.tex_curse: 1, + bs.gettexture('tnt'): 2 + } + + self.randtex = [] + + for keyTex in powerupdist: + for i in range(powerupdist[keyTex]): + self.randtex.append(keyTex) + + if power == 'random': + random.seed() + tex = random.choice(self.randtex) + + self.tex = tex + self.powerup_type = { + powerup.tex_punch: 'punch', + powerup.tex_bomb: 'triple_bombs', + powerup.tex_ice_bombs: 'ice_bombs', + powerup.tex_impact_bombs: 'impact_bombs', + powerup.tex_land_mines: 'land_mines', + powerup.tex_sticky_bombs: 'sticky_bombs', + powerup.tex_shield: 'shield', + powerup.tex_health: 'health', + powerup.tex_curse: 'curse', + bs.gettexture('tnt'): 'tnt' + }.get(self.tex, '') + + self._spawn_pos = (position[0], position[1], position[2]) + + self.node = bs.newnode( + 'prop', + delegate=self, + attrs={ + 'body': 'landMine', + 'position': self._spawn_pos, + 'mesh': fmesh, + 'light_mesh': fmeshs, + 'shadow_size': 0.5, + 'velocity': (0, 0, 0), + 'density': 90000000000, + 'sticky': False, + 'body_scale': size, + 'mesh_scale': size, + 'color_texture': tex, + 'reflection': 'powerup', + 'is_area_of_interest': True, + 'gravity_scale': 0.0, + 'reflection_scale': [0], + 'materials': [self.foothold_material, + shared.object_material, + shared.footing_material] + }) + self.touchedSpazs = set() + self.keep_vel() + + def keep_vel(self) -> None: + if self.node and not self.died: + speed = bs.getactivity().cur_speed + if self.moving: + if abs(self.node.position[0]) > 10: + self.lrSig *= -1 + self.node.velocity = ( + self.lrSig * speed * self.lrSpeedPlus, speed, 0) + bs.timer(0.1, bs.WeakCall(self.keep_vel)) + else: + self.node.velocity = (0, speed, 0) + # self.node.extraacceleration = (0, self.speed, 0) + bs.timer(0.1, bs.WeakCall(self.keep_vel)) + + def tnt_explode(self) -> None: + pos = self.node.position + Blast(position=pos, + blast_radius=6.0, + blast_type='tnt', + source_player=None).autoretain() + + def spawn_npc(self) -> None: + if not self.breakable: + return + if self._npcBots.have_living_bots(): + return + if random.randint(0, 3) >= bs.getactivity().npc_density: + return + pos = self.node.position + pos = (pos[0], pos[1] + 1, pos[2]) + self._npcBots.spawn_bot( + bot_type=random.choice([ChargerBotPro, TriggerBotPro]), + pos=pos, + spawn_time=10) + + def handlemessage(self, msg: Any) -> Any: + if isinstance(msg, bs.DieMessage): + if self.node: + self.node.delete() + self.died = True + elif isinstance(msg, bs.OutOfBoundsMessage): + self.handlemessage(bs.DieMessage()) + elif isinstance(msg, BombToDieMessage): + if self.powerup_type == 'tnt': + self.tnt_explode() + self.handlemessage(bs.DieMessage()) + elif isinstance(msg, bs.HitMessage): + ispunched = (msg.srcnode and msg.srcnode.getnodetype() == 'spaz') + if not ispunched: + if self.breakable: + self.handlemessage(BombToDieMessage()) + elif isinstance(msg, SpazTouchFoothold): + node = bs.getcollision().opposingnode + if node is not None and node: + try: + spaz = node.getdelegate(object) + if not isinstance(spaz, AbyssPlayerSpaz): + return + if spaz in self.touchedSpazs: + return + self.touchedSpazs.add(spaz) + self.spawn_npc() + spaz.fix_2D_position() + if self.powerup_type not in ['', 'tnt']: + node.handlemessage( + bs.PowerupMessage(self.powerup_type)) + except Exception as e: + print(e) + pass class AbyssPlayerSpaz(PlayerSpaz): - def __init__(self, - player: bs.Player, - color: Sequence[float] = (1.0, 1.0, 1.0), - highlight: Sequence[float] = (0.5, 0.5, 0.5), - character: str = 'Spaz', - powerups_expire: bool = True): - super().__init__(player=player, - color=color, - highlight=highlight, - character=character, - powerups_expire=powerups_expire) - self.node.fly = False - self.node.hockey = True - self.hitpoints_max = self.hitpoints = 1500 # more HP to handle drop - bs.timer(bs.getactivity().peace_time, - bs.WeakCall(self.safe_connect_controls_to_player)) - - def safe_connect_controls_to_player(self) -> None: - try: - self.connect_controls_to_player() - except: - pass - - def on_move_up_down(self, value: float) -> None: - """ - Called to set the up/down joystick amount on this spaz; - used for player or AI connections. - value will be between -32768 to 32767 - WARNING: deprecated; use on_move instead. - """ - if not self.node: - return - if self.node.run > 0.1: - self.node.move_up_down = value - else: - self.node.move_up_down = value / 3. - - def on_move_left_right(self, value: float) -> None: - """ - Called to set the left/right joystick amount on this spaz; - used for player or AI connections. - value will be between -32768 to 32767 - WARNING: deprecated; use on_move instead. - """ - if not self.node: - return - if self.node.run > 0.1: - self.node.move_left_right = value - else: - self.node.move_left_right = value / 1.5 - - def fix_2D_position(self) -> None: - self.node.fly = True - bs.timer(0.02, bs.WeakCall(self.disable_fly)) - - def disable_fly(self) -> None: - if self.node: - self.node.fly = False - - def curse(self) -> None: - """ - Give this poor spaz a curse; - he will explode in 5 seconds. - """ - if not self._cursed: - factory = SpazFactory.get() - self._cursed = True - - # Add the curse material. - for attr in ['materials', 'roller_materials']: - materials = getattr(self.node, attr) - if factory.curse_material not in materials: - setattr(self.node, attr, - materials + (factory.curse_material, )) - - # None specifies no time limit - assert self.node - if self.curse_time == -1: - self.node.curse_death_time = -1 - else: - # Note: curse-death-time takes milliseconds. - tval = bs.time() - assert isinstance(tval, (float, int)) - self.node.curse_death_time = bs.time() + 15 - bs.timer(15, bs.WeakCall(self.curse_explode)) - - def handlemessage(self, msg: Any) -> Any: - dontUp = False - - if isinstance(msg, PickupMessage): - dontUp = True - collision = bs.getcollision() - opposingnode = collision.opposingnode - opposingbody = collision.opposingbody - - if opposingnode is None or not opposingnode: - return True - opposingdelegate = opposingnode.getdelegate(object) - # Don't pick up the foothold - if isinstance(opposingdelegate, Foothold): - return True - - # dont allow picking up of invincible dudes - try: - if opposingnode.invincible: - return True - except Exception: - pass - - # if we're grabbing the pelvis of a non-shattered spaz, - # we wanna grab the torso instead - if (opposingnode.getnodetype() == 'spaz' - and not opposingnode.shattered and opposingbody == 4): - opposingbody = 1 - - - # Special case - if we're holding a flag, don't replace it - # (hmm - should make this customizable or more low level). - held = self.node.hold_node - if held and held.getnodetype() == 'flag': - return True - - # Note: hold_body needs to be set before hold_node. - self.node.hold_body = opposingbody - self.node.hold_node = opposingnode - - if not dontUp: - PlayerSpaz.handlemessage(self, msg) + def __init__(self, + player: bs.Player, + color: Sequence[float] = (1.0, 1.0, 1.0), + highlight: Sequence[float] = (0.5, 0.5, 0.5), + character: str = 'Spaz', + powerups_expire: bool = True): + super().__init__(player=player, + color=color, + highlight=highlight, + character=character, + powerups_expire=powerups_expire) + self.node.fly = False + self.node.hockey = True + self.hitpoints_max = self.hitpoints = 1500 # more HP to handle drop + bs.timer(bs.getactivity().peace_time, + bs.WeakCall(self.safe_connect_controls_to_player)) + + def safe_connect_controls_to_player(self) -> None: + try: + self.connect_controls_to_player() + except: + pass + + def on_move_up_down(self, value: float) -> None: + """ + Called to set the up/down joystick amount on this spaz; + used for player or AI connections. + value will be between -32768 to 32767 + WARNING: deprecated; use on_move instead. + """ + if not self.node: + return + if self.node.run > 0.1: + self.node.move_up_down = value + else: + self.node.move_up_down = value / 3. + + def on_move_left_right(self, value: float) -> None: + """ + Called to set the left/right joystick amount on this spaz; + used for player or AI connections. + value will be between -32768 to 32767 + WARNING: deprecated; use on_move instead. + """ + if not self.node: + return + if self.node.run > 0.1: + self.node.move_left_right = value + else: + self.node.move_left_right = value / 1.5 + + def fix_2D_position(self) -> None: + self.node.fly = True + bs.timer(0.02, bs.WeakCall(self.disable_fly)) + + def disable_fly(self) -> None: + if self.node: + self.node.fly = False + + def curse(self) -> None: + """ + Give this poor spaz a curse; + he will explode in 5 seconds. + """ + if not self._cursed: + factory = SpazFactory.get() + self._cursed = True + + # Add the curse material. + for attr in ['materials', 'roller_materials']: + materials = getattr(self.node, attr) + if factory.curse_material not in materials: + setattr(self.node, attr, + materials + (factory.curse_material, )) + + # None specifies no time limit + assert self.node + if self.curse_time == -1: + self.node.curse_death_time = -1 + else: + # Note: curse-death-time takes milliseconds. + tval = bs.time() + assert isinstance(tval, (float, int)) + self.node.curse_death_time = bs.time() + 15 + bs.timer(15, bs.WeakCall(self.curse_explode)) + + def handlemessage(self, msg: Any) -> Any: + dontUp = False + + if isinstance(msg, PickupMessage): + dontUp = True + collision = bs.getcollision() + opposingnode = collision.opposingnode + opposingbody = collision.opposingbody + + if opposingnode is None or not opposingnode: + return True + opposingdelegate = opposingnode.getdelegate(object) + # Don't pick up the foothold + if isinstance(opposingdelegate, Foothold): + return True + + # dont allow picking up of invincible dudes + try: + if opposingnode.invincible: + return True + except Exception: + pass + + # if we're grabbing the pelvis of a non-shattered spaz, + # we wanna grab the torso instead + if (opposingnode.getnodetype() == 'spaz' + and not opposingnode.shattered and opposingbody == 4): + opposingbody = 1 + + # Special case - if we're holding a flag, don't replace it + # (hmm - should make this customizable or more low level). + held = self.node.hold_node + if held and held.getnodetype() == 'flag': + return True + + # Note: hold_body needs to be set before hold_node. + self.node.hold_body = opposingbody + self.node.hold_node = opposingnode + + if not dontUp: + PlayerSpaz.handlemessage(self, msg) class Player(bs.Player['Team']): - """Our player type for this game.""" + """Our player type for this game.""" - def __init__(self) -> None: - super().__init__() - self.death_time: float | None = None - self.notIn: bool = None + def __init__(self) -> None: + super().__init__() + self.death_time: float | None = None + self.notIn: bool = None class Team(bs.Team[Player]): - """Our team type for this game.""" + """Our team type for this game.""" # ba_meta export bascenev1.GameActivity class AbyssGame(bs.TeamGameActivity[Player, Team]): - name = name - description = description - scoreconfig = bs.ScoreConfig(label='Survived', - scoretype=bs.ScoreType.MILLISECONDS, - version='B') - - # Print messages when players die (since its meaningful in this game). - announce_player_deaths = True - - # We're currently hard-coded for one map. - @classmethod - def get_supported_maps(cls, sessiontype: type[bs.Session]) -> list[str]: - return ['Abyss Unhappy'] - - @classmethod - def get_available_settings( - cls, sessiontype: type[bs.Session]) -> list[babase.Setting]: - settings = [ - bs.FloatChoiceSetting( - peaceTime, - choices=[ - ('None', 0.0), - ('Shorter', 2.5), - ('Short', 5.0), - ('Normal', 10.0), - ('Long', 15.0), - ('Longer', 20.0), - ], - default=10.0, - ), - bs.FloatChoiceSetting( - npcDensity, - choices=[ - ('0%', 0), - ('25%', 1), - ('50%', 2), - ('75%', 3), - ('100%', 4), - ], - default=2, - ), - bs.BoolSetting('Epic Mode', default=False), - ] - return settings - - # We support teams, free-for-all, and co-op sessions. - @classmethod - def supports_session_type(cls, sessiontype: type[bs.Session]) -> bool: - return (issubclass(sessiontype, bs.DualTeamSession) - or issubclass(sessiontype, bs.FreeForAllSession) - or issubclass(sessiontype, bs.CoopSession)) - - def __init__(self, settings: dict): - super().__init__(settings) - self._epic_mode = settings.get('Epic Mode', False) - self._last_player_death_time: float | None = None - self._timer: OnScreenTimer | None = None - self.fix_y = -5.614479365 - self.start_z = 0 - self.init_position = (0, self.start_z, self.fix_y) - self.team_init_positions = [(-5, self.start_z, self.fix_y), - (5, self.start_z, self.fix_y)] - self.cur_speed = 2.5 - # TODO: The variable below should be set in settings - self.peace_time = float(settings[peaceTime]) - self.npc_density = float(settings[npcDensity]) - - # Some base class overrides: - self.default_music = (bs.MusicType.EPIC - if self._epic_mode else bs.MusicType.SURVIVAL) - if self._epic_mode: - self.slow_motion = True - - self._game_credit = bs.NodeActor( - bs.newnode( - 'text', - attrs={ - 'v_attach': 'bottom', - 'h_align': 'center', - 'vr_depth': 0, - 'color': (0.0, 0.7, 1.0), - 'shadow': 1.0 if True else 0.5, - 'flatness': 1.0 if True else 0.5, - 'position': (0, 0), - 'scale': 0.8, - 'text': ' | '.join([author, github, blog]) - })) - - def get_instance_description(self) -> str | Sequence: - return description - - def get_instance_description_short(self) -> str | Sequence: - return self.get_instance_description() + '\n' + help - - def on_player_join(self, player: Player) -> None: - if self.has_begun(): - player.notIn = True - bs.broadcastmessage(babase.Lstr( - resource='playerDelayedJoinText', - subs=[('${PLAYER}', player.getname(full=True))]), - color=(0, 1, 0)) - self.spawn_player(player) - - def on_begin(self) -> None: - super().on_begin() - self._timer = OnScreenTimer() - self._timer.start() - - self.level_cnt = 1 - - if self.teams_or_ffa() == 'teams': - ip0 = self.team_init_positions[0] - ip1 = self.team_init_positions[1] - Foothold( - (ip0[0], ip0[1] - 2, ip0[2]), - power='shield', breakable=False).autoretain() - Foothold( - (ip1[0], ip1[1] - 2, ip1[2]), - power='shield', breakable=False).autoretain() - else: - ip = self.init_position - Foothold( - (ip[0], ip[1] - 2, ip[2]), - power='shield', breakable=False).autoretain() - - bs.timer(int(5.0 / self.cur_speed), - bs.WeakCall(self.add_foothold), repeat=True) - - # Repeat check game end - bs.timer(1.0, self._check_end_game, repeat=True) - bs.timer(self.peace_time + 0.1, - bs.WeakCall(self.tip_hint, hint_use_punch)) - bs.timer(6.0, bs.WeakCall(self.faster_speed), repeat=True) - - def tip_hint(self, text: str) -> None: - bs.broadcastmessage(text, color=(0.2, 0.2, 1)) - - def faster_speed(self) -> None: - self.cur_speed *= 1.15 - - def add_foothold(self) -> None: - ip = self.init_position - ip_1 = (ip[0] - 7, ip[1], ip[2]) - ip_2 = (ip[0] + 7, ip[1], ip[2]) - ru = random.uniform - self.level_cnt += 1 - if self.level_cnt % 3: - Foothold(( - ip_1[0] + ru(-5, 5), - ip[1] - 2, - ip[2] + ru(-0.0, 0.0))).autoretain() - Foothold(( - ip_2[0] + ru(-5, 5), - ip[1] - 2, - ip[2] + ru(-0.0, 0.0))).autoretain() - else: - Foothold(( - ip[0] + ru(-8, 8), - ip[1] - 2, - ip[2]), moving=True).autoretain() - - def teams_or_ffa(self) -> None: - if isinstance(self.session, bs.DualTeamSession): - return 'teams' - return 'ffa' - - def spawn_player_spaz(self, - player: Player, - position: Sequence[float] = (0, 0, 0), - angle: float | None = None) -> PlayerSpaz: - # pylint: disable=too-many-locals - # pylint: disable=cyclic-import - from babase import _math - from bascenev1._gameutils import animate - - position = self.init_position - if self.teams_or_ffa() == 'teams': - position = self.team_init_positions[player.team.id % 2] - angle = None - - name = player.getname() - color = player.color - highlight = player.highlight - - light_color = _math.normalized_color(color) - display_color = _babase.safecolor(color, target_intensity=0.75) - spaz = AbyssPlayerSpaz(color=color, - highlight=highlight, - character=player.character, - player=player) - - player.actor = spaz - assert spaz.node - - spaz.node.name = name - spaz.node.name_color = display_color - spaz.connect_controls_to_player(enable_punch=False, - enable_bomb=True, - enable_pickup=False) - - # Move to the stand position and add a flash of light. - spaz.handlemessage( - bs.StandMessage( - position, - angle if angle is not None else random.uniform(0, 360))) - self._spawn_sound.play(1, position=spaz.node.position) - light = bs.newnode('light', attrs={'color': light_color}) - spaz.node.connectattr('position', light, 'position') - animate(light, 'intensity', {0: 0, 0.25: 1, 0.5: 0}) - bs.timer(0.5, light.delete) - return spaz - - def handlemessage(self, msg: Any) -> Any: - if isinstance(msg, bs.PlayerDiedMessage): - - # Augment standard behavior. - super().handlemessage(msg) - - curtime = bs.time() - - # Record the player's moment of death. - # assert isinstance(msg.spaz.player - msg.getplayer(Player).death_time = curtime - - # In co-op mode, end the game the instant everyone dies - # (more accurate looking). - # In teams/ffa, allow a one-second fudge-factor so we can - # get more draws if players die basically at the same time. - if isinstance(self.session, bs.CoopSession): - # Teams will still show up if we check now.. check in - # the next cycle. - babase.pushcall(self._check_end_game) - - # Also record this for a final setting of the clock. - self._last_player_death_time = curtime - else: - bs.timer(1.0, self._check_end_game) - - else: - # Default handler: - return super().handlemessage(msg) - return None - - def _check_end_game(self) -> None: - living_team_count = 0 - for team in self.teams: - for player in team.players: - if player.is_alive(): - living_team_count += 1 - break - - # In co-op, we go till everyone is dead.. otherwise we go - # until one team remains. - if isinstance(self.session, bs.CoopSession): - if living_team_count <= 0: - self.end_game() - else: - if living_team_count <= 0: - self.end_game() - - def end_game(self) -> None: - cur_time = bs.time() - assert self._timer is not None - start_time = self._timer.getstarttime() - - # Mark death-time as now for any still-living players - # and award players points for how long they lasted. - # (these per-player scores are only meaningful in team-games) - for team in self.teams: - for player in team.players: - survived = False - if player.notIn: - player.death_time = 0 - - # Throw an extra fudge factor in so teams that - # didn't die come out ahead of teams that did. - if player.death_time is None: - survived = True - player.death_time = cur_time + 1 - - # Award a per-player score depending on how many seconds - # they lasted (per-player scores only affect teams mode; - # everywhere else just looks at the per-team score). - score = int(player.death_time - self._timer.getstarttime()) - if survived: - score += 50 # A bit extra for survivors. - self.stats.player_scored(player, score, screenmessage=False) - - # Stop updating our time text, and set the final time to match - # exactly when our last guy died. - self._timer.stop(endtime=self._last_player_death_time) - - # Ok now calc game results: set a score for each team and then tell - # the game to end. - results = bs.GameResults() - - # Remember that 'free-for-all' mode is simply a special form - # of 'teams' mode where each player gets their own team, so we can - # just always deal in teams and have all cases covered. - for team in self.teams: - - # Set the team score to the max time survived by any player on - # that team. - longest_life = 0.0 - for player in team.players: - assert player.death_time is not None - longest_life = max(longest_life, - player.death_time - start_time) - - # Submit the score value in milliseconds. - results.set_team_score(team, int(1000.0 * longest_life)) - - self.end(results=results) + name = name + description = description + scoreconfig = bs.ScoreConfig(label='Survived', + scoretype=bs.ScoreType.MILLISECONDS, + version='B') + + # Print messages when players die (since its meaningful in this game). + announce_player_deaths = True + + # We're currently hard-coded for one map. + @classmethod + def get_supported_maps(cls, sessiontype: type[bs.Session]) -> list[str]: + return ['Abyss Unhappy'] + + @classmethod + def get_available_settings( + cls, sessiontype: type[bs.Session]) -> list[babase.Setting]: + settings = [ + bs.FloatChoiceSetting( + peaceTime, + choices=[ + ('None', 0.0), + ('Shorter', 2.5), + ('Short', 5.0), + ('Normal', 10.0), + ('Long', 15.0), + ('Longer', 20.0), + ], + default=10.0, + ), + bs.FloatChoiceSetting( + npcDensity, + choices=[ + ('0%', 0), + ('25%', 1), + ('50%', 2), + ('75%', 3), + ('100%', 4), + ], + default=2, + ), + bs.BoolSetting('Epic Mode', default=False), + ] + return settings + + # We support teams, free-for-all, and co-op sessions. + @classmethod + def supports_session_type(cls, sessiontype: type[bs.Session]) -> bool: + return (issubclass(sessiontype, bs.DualTeamSession) + or issubclass(sessiontype, bs.FreeForAllSession) + or issubclass(sessiontype, bs.CoopSession)) + + def __init__(self, settings: dict): + super().__init__(settings) + self._epic_mode = settings.get('Epic Mode', False) + self._last_player_death_time: float | None = None + self._timer: OnScreenTimer | None = None + self.fix_y = -5.614479365 + self.start_z = 0 + self.init_position = (0, self.start_z, self.fix_y) + self.team_init_positions = [(-5, self.start_z, self.fix_y), + (5, self.start_z, self.fix_y)] + self.cur_speed = 2.5 + # TODO: The variable below should be set in settings + self.peace_time = float(settings[peaceTime]) + self.npc_density = float(settings[npcDensity]) + + # Some base class overrides: + self.default_music = (bs.MusicType.EPIC + if self._epic_mode else bs.MusicType.SURVIVAL) + if self._epic_mode: + self.slow_motion = True + + self._game_credit = bs.NodeActor( + bs.newnode( + 'text', + attrs={ + 'v_attach': 'bottom', + 'h_align': 'center', + 'vr_depth': 0, + 'color': (0.0, 0.7, 1.0), + 'shadow': 1.0 if True else 0.5, + 'flatness': 1.0 if True else 0.5, + 'position': (0, 0), + 'scale': 0.8, + 'text': ' | '.join([author, github, blog]) + })) + + def get_instance_description(self) -> str | Sequence: + return description + + def get_instance_description_short(self) -> str | Sequence: + return self.get_instance_description() + '\n' + help + + def on_player_join(self, player: Player) -> None: + if self.has_begun(): + player.notIn = True + bs.broadcastmessage(babase.Lstr( + resource='playerDelayedJoinText', + subs=[('${PLAYER}', player.getname(full=True))]), + color=(0, 1, 0)) + self.spawn_player(player) + + def on_begin(self) -> None: + super().on_begin() + self._timer = OnScreenTimer() + self._timer.start() + + self.level_cnt = 1 + + if self.teams_or_ffa() == 'teams': + ip0 = self.team_init_positions[0] + ip1 = self.team_init_positions[1] + Foothold( + (ip0[0], ip0[1] - 2, ip0[2]), + power='shield', breakable=False).autoretain() + Foothold( + (ip1[0], ip1[1] - 2, ip1[2]), + power='shield', breakable=False).autoretain() + else: + ip = self.init_position + Foothold( + (ip[0], ip[1] - 2, ip[2]), + power='shield', breakable=False).autoretain() + + bs.timer(int(5.0 / self.cur_speed), + bs.WeakCall(self.add_foothold), repeat=True) + + # Repeat check game end + bs.timer(1.0, self._check_end_game, repeat=True) + bs.timer(self.peace_time + 0.1, + bs.WeakCall(self.tip_hint, hint_use_punch)) + bs.timer(6.0, bs.WeakCall(self.faster_speed), repeat=True) + + def tip_hint(self, text: str) -> None: + bs.broadcastmessage(text, color=(0.2, 0.2, 1)) + + def faster_speed(self) -> None: + self.cur_speed *= 1.15 + + def add_foothold(self) -> None: + ip = self.init_position + ip_1 = (ip[0] - 7, ip[1], ip[2]) + ip_2 = (ip[0] + 7, ip[1], ip[2]) + ru = random.uniform + self.level_cnt += 1 + if self.level_cnt % 3: + Foothold(( + ip_1[0] + ru(-5, 5), + ip[1] - 2, + ip[2] + ru(-0.0, 0.0))).autoretain() + Foothold(( + ip_2[0] + ru(-5, 5), + ip[1] - 2, + ip[2] + ru(-0.0, 0.0))).autoretain() + else: + Foothold(( + ip[0] + ru(-8, 8), + ip[1] - 2, + ip[2]), moving=True).autoretain() + + def teams_or_ffa(self) -> None: + if isinstance(self.session, bs.DualTeamSession): + return 'teams' + return 'ffa' + + def spawn_player_spaz(self, + player: Player, + position: Sequence[float] = (0, 0, 0), + angle: float | None = None) -> PlayerSpaz: + # pylint: disable=too-many-locals + # pylint: disable=cyclic-import + from babase import _math + from bascenev1._gameutils import animate + + position = self.init_position + if self.teams_or_ffa() == 'teams': + position = self.team_init_positions[player.team.id % 2] + angle = None + + name = player.getname() + color = player.color + highlight = player.highlight + + light_color = _math.normalized_color(color) + display_color = _babase.safecolor(color, target_intensity=0.75) + spaz = AbyssPlayerSpaz(color=color, + highlight=highlight, + character=player.character, + player=player) + + player.actor = spaz + assert spaz.node + + spaz.node.name = name + spaz.node.name_color = display_color + spaz.connect_controls_to_player(enable_punch=False, + enable_bomb=True, + enable_pickup=False) + + # Move to the stand position and add a flash of light. + spaz.handlemessage( + bs.StandMessage( + position, + angle if angle is not None else random.uniform(0, 360))) + self._spawn_sound.play(1, position=spaz.node.position) + light = bs.newnode('light', attrs={'color': light_color}) + spaz.node.connectattr('position', light, 'position') + animate(light, 'intensity', {0: 0, 0.25: 1, 0.5: 0}) + bs.timer(0.5, light.delete) + return spaz + + def handlemessage(self, msg: Any) -> Any: + if isinstance(msg, bs.PlayerDiedMessage): + + # Augment standard behavior. + super().handlemessage(msg) + + curtime = bs.time() + + # Record the player's moment of death. + # assert isinstance(msg.spaz.player + msg.getplayer(Player).death_time = curtime + + # In co-op mode, end the game the instant everyone dies + # (more accurate looking). + # In teams/ffa, allow a one-second fudge-factor so we can + # get more draws if players die basically at the same time. + if isinstance(self.session, bs.CoopSession): + # Teams will still show up if we check now.. check in + # the next cycle. + babase.pushcall(self._check_end_game) + + # Also record this for a final setting of the clock. + self._last_player_death_time = curtime + else: + bs.timer(1.0, self._check_end_game) + + else: + # Default handler: + return super().handlemessage(msg) + return None + + def _check_end_game(self) -> None: + living_team_count = 0 + for team in self.teams: + for player in team.players: + if player.is_alive(): + living_team_count += 1 + break + + # In co-op, we go till everyone is dead.. otherwise we go + # until one team remains. + if isinstance(self.session, bs.CoopSession): + if living_team_count <= 0: + self.end_game() + else: + if living_team_count <= 0: + self.end_game() + + def end_game(self) -> None: + cur_time = bs.time() + assert self._timer is not None + start_time = self._timer.getstarttime() + + # Mark death-time as now for any still-living players + # and award players points for how long they lasted. + # (these per-player scores are only meaningful in team-games) + for team in self.teams: + for player in team.players: + survived = False + if player.notIn: + player.death_time = 0 + + # Throw an extra fudge factor in so teams that + # didn't die come out ahead of teams that did. + if player.death_time is None: + survived = True + player.death_time = cur_time + 1 + + # Award a per-player score depending on how many seconds + # they lasted (per-player scores only affect teams mode; + # everywhere else just looks at the per-team score). + score = int(player.death_time - self._timer.getstarttime()) + if survived: + score += 50 # A bit extra for survivors. + self.stats.player_scored(player, score, screenmessage=False) + + # Stop updating our time text, and set the final time to match + # exactly when our last guy died. + self._timer.stop(endtime=self._last_player_death_time) + + # Ok now calc game results: set a score for each team and then tell + # the game to end. + results = bs.GameResults() + + # Remember that 'free-for-all' mode is simply a special form + # of 'teams' mode where each player gets their own team, so we can + # just always deal in teams and have all cases covered. + for team in self.teams: + + # Set the team score to the max time survived by any player on + # that team. + longest_life = 0.0 + for player in team.players: + assert player.death_time is not None + longest_life = max(longest_life, + player.death_time - start_time) + + # Submit the score value in milliseconds. + results.set_team_score(team, int(1000.0 * longest_life)) + + self.end(results=results) diff --git a/plugins/minigames/explodo_run.py b/plugins/minigames/explodo_run.py index be013c71..cac6a65f 100644 --- a/plugins/minigames/explodo_run.py +++ b/plugins/minigames/explodo_run.py @@ -17,19 +17,22 @@ if TYPE_CHECKING: from typing import Any, Type, Dict, List, Optional + def ba_get_api_version(): return 8 + def ba_get_levels(): - return [bs._level.Level( - 'Explodo Run', - gametype=ExplodoRunGame, - settings={}, - preview_texture_name='rampagePreview'),bs._level.Level( - 'Epic Explodo Run', - gametype=ExplodoRunGame, - settings={'Epic Mode':True}, - preview_texture_name='rampagePreview')] + return [bs._level.Level( + 'Explodo Run', + gametype=ExplodoRunGame, + settings={}, + preview_texture_name='rampagePreview'), bs._level.Level( + 'Epic Explodo Run', + gametype=ExplodoRunGame, + settings={'Epic Mode': True}, + preview_texture_name='rampagePreview')] + class Player(bs.Player['Team']): """Our player type for this game.""" @@ -39,6 +42,8 @@ class Team(bs.Team[Player]): """Our team type for this game.""" # ba_meta export bascenev1.GameActivity + + class ExplodoRunGame(bs.TeamGameActivity[Player, Team]): name = "Explodo Run" description = "Run For Your Life :))" @@ -47,8 +52,8 @@ class ExplodoRunGame(bs.TeamGameActivity[Player, Team]): scoretype=bs.ScoreType.MILLISECONDS, lower_is_better=False) default_music = bs.MusicType.TO_THE_DEATH - - def __init__(self, settings:dict): + + def __init__(self, settings: dict): settings['map'] = "Rampage" self._epic_mode = settings.get('Epic Mode', False) if self._epic_mode: @@ -59,27 +64,28 @@ def __init__(self, settings:dict): self._won = False self._bots = SpazBotSet() self.wave = 1 - + def on_begin(self) -> None: super().on_begin() - + self._timer = OnScreenTimer() bs.timer(2.5, self._timer.start) - - #Bots Hehe - bs.timer(2.5,self.street) + + # Bots Hehe + bs.timer(2.5, self.street) def street(self): for a in range(self.wave): - p1 = random.choice([-5,-2.5,0,2.5,5]) - p3 = random.choice([-4.5,-4.14,-5,-3]) - time = random.choice([1,1.5,2.5,2]) - self._bots.spawn_bot(ExplodeyBot, pos=(p1,5.5,p3),spawn_time = time) + p1 = random.choice([-5, -2.5, 0, 2.5, 5]) + p3 = random.choice([-4.5, -4.14, -5, -3]) + time = random.choice([1, 1.5, 2.5, 2]) + self._bots.spawn_bot(ExplodeyBot, pos=(p1, 5.5, p3), spawn_time=time) self.wave += 1 - + def botrespawn(self): if not self._bots.have_living_bots(): self.street() + def handlemessage(self, msg: Any) -> Any: # A player has died. @@ -87,7 +93,7 @@ def handlemessage(self, msg: Any) -> Any: super().handlemessage(msg) # Augment standard behavior. self._won = True self.end_game() - + # A spaz-bot has died. elif isinstance(msg, SpazBotDiedMessage): # Unfortunately the bot-set will always tell us there are living @@ -128,5 +134,3 @@ def end_game(self) -> None: # Ends the activity. self.end(results) - - \ No newline at end of file diff --git a/plugins/minigames/extinction.py b/plugins/minigames/extinction.py index 39266e56..22ca2fcd 100644 --- a/plugins/minigames/extinction.py +++ b/plugins/minigames/extinction.py @@ -21,6 +21,7 @@ def ba_get_api_version(): return 8 + def ba_get_levels(): return [babase._level.Level( 'Extinction', @@ -33,23 +34,24 @@ def ba_get_levels(): settings={'Epic Mode': True}, preview_texture_name='footballStadiumPreview')] + class Meteor(bs.Actor): """A giant meteor instead of bombs.""" - + def __init__(self, pos: Sequence[float] = (0.0, 1.0, 0.0), velocity: Sequence[float] = (0.0, 0.0, 0.0)): super().__init__() - + shared = SharedObjects.get() factory = BombFactory.get() - + materials = (shared.object_material, factory.impact_blast_material) - + self.pos = (pos[0], pos[1], pos[2]) self.velocity = (velocity[0], velocity[1], velocity[2]) - + self.node = bs.newnode( 'prop', delegate=self, @@ -66,13 +68,13 @@ def __init__(self, 'reflection_scale': [0.45], 'materials': materials }) - + def explode(self) -> None: Blast(position=self.node.position, velocity=self.node.velocity, blast_type='tnt', blast_radius=2.0) - + def handlemessage(self, msg: Any) -> Any: if isinstance(msg, bs.DieMessage): if self.node: @@ -86,11 +88,12 @@ def handlemessage(self, msg: Any) -> Any: class Player(bs.Player['Team']): """Our player type for this game.""" - + def __init__(self): super().__init__() self.death_time: Optional[float] = None + class Team(bs.Team[Player]): """Our team type for this game.""" @@ -98,112 +101,112 @@ class Team(bs.Team[Player]): # ba_meta export bascenev1.GameActivity class NewMeteorShowerGame(bs.TeamGameActivity[Player, Team]): """Minigame by Jetz.""" - + name = 'Extinction' description = 'Survive the Extinction.' available_settings = [ bs.BoolSetting('Epic Mode', default=False)] - + announce_player_deaths = True - + @classmethod def get_supported_maps(cls, sessiontype: Type[bs.Session]) -> List[str]: return ['Football Stadium'] - + @classmethod def supports_session_type(cls, sessiontype: Type[bs.Session]) -> bool: return (issubclass(sessiontype, bs.FreeForAllSession) or issubclass(sessiontype, bs.DualTeamSession)) - + def __init__(self, settings: dict): super().__init__(settings) - + self._epic_mode = bool(settings['Epic Mode']) self._last_player_death_time: Optiobal[float] = None self._meteor_time = 2.0 self._timer: Optional[OnScreenTimer] = None - + self.default_music = (bs.MusicType.EPIC if self._epic_mode else bs.MusicType.SURVIVAL) - + if self._epic_mode: self.slow_motion = True - + def on_begin(self) -> None: super().on_begin() - + delay = 5.0 if len(self.players) > 2 else 2.5 if self._epic_mode: delay *= 0.25 bs.timer(delay, self._decrement_meteor_time, repeat=True) - + delay = 3.0 if self._epic_mode: delay *= 0.25 bs.timer(delay, self._set_meteor_timer) - + self._timer = OnScreenTimer() self._timer.start() self._check_end_game() - + def on_player_join(self, player: Player) -> None: if self.has_begun(): bs.broadcastmessage( babase.Lstr(resource='playerDelayedJoinText', - subs=[('${PLAYER}', player.getname(full=True))]), + subs=[('${PLAYER}', player.getname(full=True))]), color=(0, 1, 0), ) assert self._timer is not None player.death_time = self._timer.getstarttime() return self.spawn_player(player) - + def spawn_player(self, player: Player) -> None: spaz = self.spawn_player_spaz(player) - + spaz.connect_controls_to_player(enable_punch=False, enable_pickup=False, enable_bomb=False, enable_jump=False) spaz.play_big_death_sound = True - + return spaz - + def on_player_leave(self, player: Player) -> None: super().on_player_leave(player) - + self._check_end_game() - + def handlemessage(self, msg: Any) -> Any: if isinstance(msg, bs.PlayerDiedMessage): curtime = bs.time() - + msg.getplayer(Player).death_time = curtime bs.timer(1.0, self._check_end_game) else: return super().handlemessage(msg) - + def _spawn_meteors(self) -> None: pos = (random.randint(-6, 7), 12, random.uniform(-2, 1)) velocity = (random.randint(-11, 11), 0, random.uniform(-5, 5)) Meteor(pos=pos, velocity=velocity).autoretain() - + def _spawn_meteors_cluster(self) -> None: delay = 0.0 for _i in range(random.randrange(1, 3)): bs.timer(delay, self._spawn_meteors) delay += 1 self._set_meteor_timer() - + def _decrement_meteor_time(self) -> None: self._meteor_time = max(0.01, self._meteor_time * 0.9) - + def _set_meteor_timer(self) -> None: bs.timer((1.0 + 0.2 * random.random()) * self._meteor_time, self._spawn_meteors_cluster) - + def _check_end_game(self) -> None: living_team_count = 0 for team in self.teams: @@ -211,44 +214,44 @@ def _check_end_game(self) -> None: if player.is_alive(): living_team_count += 1 break - + if isinstance(self.session, bs.CoopSession): if living_team_count <= 0: self.end_game() else: if living_team_count <= 1: self.end_game() - + def end_game(self) -> None: cur_time = bs.time() assert self._timer is not None start_time = self._timer.getstarttime() - + for team in self.teams: for player in team.players: survived = False - + if player.death_time is None: survived = True player.death_time = cur_time + 1 - + score = int(player.death_time - self._timer.getstarttime()) if survived: score += 50 self.stats.player_scored(player, score, screenmessage=False) - + self._timer.stop(endtime=self._last_player_death_time) - + results = bs.GameResults() - + for team in self.teams: - + longest_life = 0.0 for player in team.players: assert player.death_time is not None longest_life = max(longest_life, player.death_time - start_time) - + results.set_team_score(team, int(1000.0 * longest_life)) - - self.end(results=results) \ No newline at end of file + + self.end(results=results) diff --git a/plugins/minigames/fat_pigs.py b/plugins/minigames/fat_pigs.py index aed1a690..78c56c37 100644 --- a/plugins/minigames/fat_pigs.py +++ b/plugins/minigames/fat_pigs.py @@ -3,7 +3,7 @@ # - - - - - - - - - - - - - - - - - - - - - # - Fat-Pigs! by Zacker Tz || Zacker#5505 - -# - Version 0.01 :v - +# - Version 0.01 :v - # - - - - - - - - - - - - - - - - - - - - - from __future__ import annotations @@ -24,12 +24,13 @@ # - - - - - - - Mini - Settings - - - - - - - - - - - - - - - - # -zkBombs_limit = 3 # Number of bombs you can use | Default = 3 -zkPunch = False # Enable/Disable punchs | Default = False -zkPickup = False # Enable/Disable pickup | Default = False +zkBombs_limit = 3 # Number of bombs you can use | Default = 3 +zkPunch = False # Enable/Disable punchs | Default = False +zkPickup = False # Enable/Disable pickup | Default = False # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - # + class Player(bs.Player['Team']): """Our player type for this game.""" @@ -40,7 +41,9 @@ class Team(bs.Team[Player]): def __init__(self) -> None: self.score = 0 -# ba_meta export bascenev1.GameActivity +# ba_meta export bascenev1.GameActivity + + class FatPigs(bs.TeamGameActivity[Player, Team]): """A game type based on acquiring kills.""" @@ -139,20 +142,18 @@ def on_begin(self) -> None: super().on_begin() self.setup_standard_time_limit(self._time_limit) # self.setup_standard_powerup_drops() - #Ambiente + # Ambiente gnode = bs.getactivity().globalsnode gnode.tint = (0.8, 1.2, 0.8) gnode.ambient_color = (0.7, 1.0, 0.6) - gnode.vignette_outer = (0.4, 0.6, 0.4) #C + gnode.vignette_outer = (0.4, 0.6, 0.4) # C # gnode.vignette_inner = (0.9, 0.9, 0.9) - - # Base kills needed to win on the size of the largest team. self._score_to_win = (self._kills_to_win_per_player * max(1, max(len(t.players) for t in self.teams))) self._update_scoreboard() - + delay = 5.0 if len(self.players) > 2 else 2.5 if self._epic_mode: delay *= 0.25 @@ -169,18 +170,17 @@ def on_begin(self) -> None: # Check for immediate end (if we've only got 1 player, etc). bs.timer(5.0, self._check_end_game) - + t = bs.newnode('text', - attrs={ 'text':"Minigame by Zacker Tz", - 'scale':0.7, - 'position':(0.001,625), - 'shadow':0.5, - 'opacity':0.7, - 'flatness':1.2, - 'color':(0.6, 1, 0.6), - 'h_align':'center', - 'v_attach':'bottom'}) - + attrs={'text': "Minigame by Zacker Tz", + 'scale': 0.7, + 'position': (0.001, 625), + 'shadow': 0.5, + 'opacity': 0.7, + 'flatness': 1.2, + 'color': (0.6, 1, 0.6), + 'h_align': 'center', + 'v_attach': 'bottom'}) def spawn_player(self, player: Player) -> bs.Actor: spaz = self.spawn_player_spaz(player) @@ -190,13 +190,13 @@ def spawn_player(self, player: Player) -> bs.Actor: spaz.connect_controls_to_player(enable_punch=zkPunch, enable_bomb=True, enable_pickup=zkPickup) - + spaz.bomb_count = zkBombs_limit spaz._max_bomb_count = zkBombs_limit spaz.bomb_type_default = 'sticky' spaz.bomb_type = 'sticky' - #cerdo gordo + # cerdo gordo spaz.node.color_mask_texture = bs.gettexture('melColorMask') spaz.node.color_texture = bs.gettexture('melColor') spaz.node.head_mesh = bs.getmesh('melHead') @@ -210,19 +210,19 @@ def spawn_player(self, player: Player) -> bs.Actor: spaz.node.toes_mesh = bs.getmesh('melToes') spaz.node.style = 'mel' # Sounds cerdo gordo - mel_sounds = [bs.getsound('mel01'), bs.getsound('mel02'),bs.getsound('mel03'),bs.getsound('mel04'),bs.getsound('mel05'), - bs.getsound('mel06'),bs.getsound('mel07'),bs.getsound('mel08'),bs.getsound('mel09'),bs.getsound('mel10')] + mel_sounds = [bs.getsound('mel01'), bs.getsound('mel02'), bs.getsound('mel03'), bs.getsound('mel04'), bs.getsound('mel05'), + bs.getsound('mel06'), bs.getsound('mel07'), bs.getsound('mel08'), bs.getsound('mel09'), bs.getsound('mel10')] spaz.node.jump_sounds = mel_sounds spaz.node.attack_sounds = mel_sounds spaz.node.impact_sounds = mel_sounds spaz.node.pickup_sounds = mel_sounds spaz.node.death_sounds = [bs.getsound('melDeath01')] spaz.node.fall_sounds = [bs.getsound('melFall01')] - + def _set_meteor_timer(self) -> None: bs.timer((1.0 + 0.2 * random.random()) * self._meteor_time, - self._drop_bomb_cluster) - + self._drop_bomb_cluster) + def _drop_bomb_cluster(self) -> None: # Random note: code like this is a handy way to plot out extents @@ -245,15 +245,14 @@ def _drop_bomb_cluster(self) -> None: vel = ((-5.0 + random.random() * 30.0) * dropdir, -4.0, 0) bs.timer(delay, babase.Call(self._drop_bomb, pos, vel)) delay += 0.1 - self._set_meteor_timer() - + self._set_meteor_timer() + def _drop_bomb(self, position: Sequence[float], velocity: Sequence[float]) -> None: - Bomb(position=position, velocity=velocity,bomb_type='sticky').autoretain() + Bomb(position=position, velocity=velocity, bomb_type='sticky').autoretain() def _decrement_meteor_time(self) -> None: self._meteor_time = max(0.01, self._meteor_time * 0.9) - def handlemessage(self, msg: Any) -> Any: @@ -326,7 +325,7 @@ def _check_end_game(self) -> None: self.end_game() else: if living_team_count <= 1: - self.end_game() + self.end_game() def _update_scoreboard(self) -> None: for team in self.teams: diff --git a/plugins/utilities/xyz_tool.py b/plugins/utilities/xyz_tool.py index 2ad1efda..c3cf5670 100644 --- a/plugins/utilities/xyz_tool.py +++ b/plugins/utilities/xyz_tool.py @@ -20,28 +20,35 @@ PlayerSpaz.supershit = PlayerSpaz.__init__ + + def ShitInit(self, - player: bs.Player, - color: Sequence[float] = (1.0, 1.0, 1.0), - highlight: Sequence[float] = (0.5, 0.5, 0.5), - character: str = 'Spaz', - powerups_expire: bool = True) -> None: + player: bs.Player, + color: Sequence[float] = (1.0, 1.0, 1.0), + highlight: Sequence[float] = (0.5, 0.5, 0.5), + character: str = 'Spaz', + powerups_expire: bool = True) -> None: self.supershit(player, color, highlight, character, powerups_expire) - self.offt = bs.newnode('math', owner=self.node, attrs={'input1': (1.2, 1.8, -0.7),'operation': 'add'}) + self.offt = bs.newnode('math', owner=self.node, attrs={ + 'input1': (1.2, 1.8, -0.7), 'operation': 'add'}) self.node.connectattr('torso_position', self.offt, 'input2') - self.txt = bs.newnode('text', owner=self.node, attrs={'text': '3.0','in_world': True,'text':'0','shadow': 1.0,'color': (1,0,0),'flatness': 0.5,'scale': 0.01,'h_align': 'right'}) + self.txt = bs.newnode('text', owner=self.node, attrs={'text': '3.0', 'in_world': True, 'text': '0', 'shadow': 1.0, 'color': ( + 1, 0, 0), 'flatness': 0.5, 'scale': 0.01, 'h_align': 'right'}) p = self.node.position self.xyz = 0 self.txt.text = "X: " + str(p[0]) + "\nY: " + str(p[1]) + "\nZ: " + str(p[2]) self.offt.connectattr('output', self.txt, 'position') + def update(): p = self.node.position is_moving = abs(self.node.move_up_down) >= 0.01 or abs(self.node.move_left_right) >= 0.01 if is_moving: - self.xyz = (p[0],p[1],p[2]) - self.txt.text = "X: " + str(round(self.xyz[0],DECIMAL_LIMIT)) + "\nY: " + str(round(self.xyz[1],DECIMAL_LIMIT)) + "\nZ: " + str(round(self.xyz[2],DECIMAL_LIMIT)) - bs.timer(0.1,update,repeat=True) - + self.xyz = (p[0], p[1], p[2]) + self.txt.text = "X: " + str(round(self.xyz[0], DECIMAL_LIMIT)) + "\nY: " + str( + round(self.xyz[1], DECIMAL_LIMIT)) + "\nZ: " + str(round(self.xyz[2], DECIMAL_LIMIT)) + bs.timer(0.1, update, repeat=True) + + def replaceable_punch(self) -> None: """ Called to 'press punch' on this spaz; @@ -55,10 +62,11 @@ def replaceable_punch(self) -> None: index += len(files) c27 = str(index + 1) with open(path_aid + '/coords' + c27 + '.txt', 'w') as gg: - gg.write("X: " + str(round(self.xyz[0],DECIMAL_LIMIT)) + "\nY: " + str(round(self.xyz[1],DECIMAL_LIMIT)) + "\nZ: " + str(round(self.xyz[2],DECIMAL_LIMIT)) + '\n\n' + '(' + str(round(self.xyz[0],DECIMAL_LIMIT)) + ', ' + str(round(self.xyz[1],DECIMAL_LIMIT)) + ', ' + str(round(self.xyz[2],DECIMAL_LIMIT)) + ')') + gg.write("X: " + str(round(self.xyz[0], DECIMAL_LIMIT)) + "\nY: " + str(round(self.xyz[1], DECIMAL_LIMIT)) + "\nZ: " + str(round(self.xyz[2], DECIMAL_LIMIT)) + + '\n\n' + '(' + str(round(self.xyz[0], DECIMAL_LIMIT)) + ', ' + str(round(self.xyz[1], DECIMAL_LIMIT)) + ', ' + str(round(self.xyz[2], DECIMAL_LIMIT)) + ')') bui.screenmessage("Coordinates saved in: " + "BombSquad/Saved XYZ/" + "coords" + c27) if _babase.app.classic.platform == 'android': - _babase.android_media_scan_file(path_aid) + _babase.android_media_scan_file(path_aid) t_ms = bs.time() * 1000 assert isinstance(t_ms, int) if t_ms - self.last_punch_time_ms >= self._punch_cooldown: @@ -69,17 +77,20 @@ def replaceable_punch(self) -> None: self.node.punch_pressed = True if not self.node.hold_node: bs.timer( - 0.1, - bs.WeakCall(self._safe_play_sound, - SpazFactory.get().swish_sound, 0.8)) + 0.1, + bs.WeakCall(self._safe_play_sound, + SpazFactory.get().swish_sound, 0.8)) self._turbo_filter_add_press('punch') # ba_meta export plugin + + class ragingspeedhorn(babase.Plugin): try: - oath = _babase.env()['python_directory_user'] + '/Saved XYZ' - os.makedirs(oath,exist_ok=False) - except: pass + oath = _babase.env()['python_directory_user'] + '/Saved XYZ' + os.makedirs(oath, exist_ok=False) + except: + pass PlayerSpaz.on_punch_press = replaceable_punch PlayerSpaz.__init__ = ShitInit - PlayerSpaz.xyz = 0 \ No newline at end of file + PlayerSpaz.xyz = 0 From 0fd7c5bed18919410c1aad103a69680fc2c08dee Mon Sep 17 00:00:00 2001 From: brostosjoined Date: Thu, 1 Feb 2024 13:07:51 +0300 Subject: [PATCH 0844/1464] More --- plugins/minigames.json | 20 +- plugins/minigames/flag_day.py | 614 ++++++++++++++++++ plugins/utilities.json | 28 + plugins/utilities/bots_can_accept_powerups.py | 41 ++ plugins/utilities/cheat_menu.py | 355 ++++++++++ 5 files changed, 1055 insertions(+), 3 deletions(-) create mode 100644 plugins/minigames/flag_day.py create mode 100644 plugins/utilities/bots_can_accept_powerups.py create mode 100644 plugins/utilities/cheat_menu.py diff --git a/plugins/minigames.json b/plugins/minigames.json index 4cdc9ce6..db4143e4 100644 --- a/plugins/minigames.json +++ b/plugins/minigames.json @@ -1274,7 +1274,7 @@ "1.0.0": null } }, - "extinction_run": { + "extinction": { "description": "Survive the Extinction.", "external_url": "", "authors": [ @@ -1289,8 +1289,8 @@ } }, "fat_pigs": { - "description": "Survive the Extinction.", - "external_url": "Survive the pigs...", + "description": "Survive...", + "external_url": "", "authors": [ { "name": "Zacker Tz", @@ -1301,6 +1301,20 @@ "versions": { "1.0.0": null } + }, + "flag_day": { + "description": "Pick up flags to receive a prize.\nBut beware...", + "external_url": "https://youtu.be/ANDzdBicjA4?si=h8S_TPUAxSaG7nls", + "authors": [ + { + "name": "MattZ45986", + "email": "", + "discord": "" + } + ], + "versions": { + "1.0.0": null + } } } } \ No newline at end of file diff --git a/plugins/minigames/flag_day.py b/plugins/minigames/flag_day.py new file mode 100644 index 00000000..d5d473c5 --- /dev/null +++ b/plugins/minigames/flag_day.py @@ -0,0 +1,614 @@ + +#Ported by brostos to api 8 +# ba_meta require api 8 +# (see https://ballistica.net/wiki/meta-tag-system) + +from __future__ import annotations + +from typing import TYPE_CHECKING + +import babase +import bauiv1 as bui +import bascenev1 as bs +import _babase +import json +import math +import random +from bascenev1lib.game.elimination import Icon +from bascenev1lib.actor.bomb import Bomb, Blast +from bascenev1lib.actor.playerspaz import PlayerSpaz +from bascenev1lib.actor.scoreboard import Scoreboard +from bascenev1lib.actor.powerupbox import PowerupBox +from bascenev1lib.actor.flag import Flag, FlagPickedUpMessage +from bascenev1lib.actor.spazbot import SpazBotSet, BrawlerBotLite, SpazBotDiedMessage + +if TYPE_CHECKING: + from typing import Any, Sequence + + +lang = bs.app.lang.language +if lang == 'Spanish': + name = 'Día de la Bandera' + description = ('Recoge las banderas para recibir un premio.\n' + 'Pero ten cuidado...') + slow_motion_deaths = 'Muertes en Cámara Lenta' + credits = 'Creado por MattZ45986 en Github | Actualizado por byANG3L and brostos' + you_were = 'Estas' + cursed_text = 'MALDITO' + run = 'CORRE' + climb_top = 'Escala a la cima' + bomb_rain = '¡LLUVIA DE BOMBAS!' + lame_guys = 'Chicos Ligeros' + jackpot = '¡PREMIO MAYOR!' + diedtxt = '¡' + diedtxt2 = ' ha sido eliminado!' +else: + name = 'Flag Day' + description = 'Pick up flags to receive a prize.\nBut beware...' + slow_motion_deaths = 'Slow Motion Deaths' + credits = 'Created by MattZ45986 on Github | Updated by byANG3L and brostos' + you_were = 'You were' + cursed_text = 'CURSED' + run = 'RUN' + climb_top = 'Climb to the top' + bomb_rain = 'BOMB RAIN!' + lame_guys = 'Lame Guys' + jackpot = '!JACKPOT!' + diedtxt = '' + diedtxt2 = ' died!' + + +class Icon(Icon): + + def __init__( + self, + player: Player, + position: tuple[float, float], + scale: float, + show_lives: bool = True, + show_death: bool = True, + name_scale: float = 1.0, + name_maxwidth: float = 115.0, + flatness: float = 1.0, + shadow: float = 1.0, + dead: bool = False, + ): + super().__init__(player,position,scale,show_lives,show_death, + name_scale,name_maxwidth,flatness,shadow) + if dead: + self._name_text.opacity = 0.2 + self.node.color = (0.7, 0.3, 0.3) + self.node.opacity = 0.2 + + +class FlagBearer(PlayerSpaz): + def handlemessage(self, msg: Any) -> Any: + super().handlemessage(msg) + if isinstance(msg, bs.PowerupMessage): + activity = self.activity + player = self.getplayer(Player) + if not player.is_alive(): + return + if activity.last_prize == 'curse': + player.team.score += 25 + activity._update_scoreboard() + elif activity.last_prize == 'land_mines': + player.team.score += 15 + activity._update_scoreboard() + self.connect_controls_to_player() + elif activity.last_prize == 'climb': + player.team.score += 50 + activity._update_scoreboard() + if msg.poweruptype == 'health': + activity.round_timer = None + bs.timer(0.2, activity.setup_next_round) + + +class Player(bs.Player['Team']): + """Our player type for this game.""" + + def __init__(self) -> None: + self.dead = False + self.icons: list[Icon] = [] + +class Team(bs.Team[Player]): + """Our team type for this game.""" + + def __init__(self) -> None: + self.score = 0 + + +# ba_meta export bascenev1.GameActivity +class FlagDayGame(bs.TeamGameActivity[Player, Team]): + """A game type based on acquiring kills.""" + + name = name + description = description + + # Print messages when players die since it matters here. + announce_player_deaths = True + + allow_mid_activity_joins = False + + @classmethod + def get_available_settings( + cls, sessiontype: type[bs.Session] + ) -> list[babase.Setting]: + settings = [ + bs.BoolSetting(slow_motion_deaths, default=True), + bs.BoolSetting('Epic Mode', default=False), + ] + return settings + + @classmethod + def supports_session_type(cls, sessiontype: type[bs.Session]) -> bool: + return ( + issubclass(sessiontype, bs.CoopSession) + or issubclass(sessiontype, bs.DualTeamSession) + or issubclass(sessiontype, bs.FreeForAllSession) + ) + + @classmethod + def get_supported_maps(cls, sessiontype: type[bs.Session]) -> list[str]: + return ['Courtyard'] + + def __init__(self, settings: dict): + super().__init__(settings) + self.credits() + self._scoreboard = Scoreboard() + self._dingsound = bui.getsound('dingSmall') + self._epic_mode = bool(settings['Epic Mode']) + self._slow_motion_deaths = bool(settings[slow_motion_deaths]) + self.current_player: Player | None = None + self.prize_recipient: Player | None = None + self.bomb_survivor: Player | None = None + self.bad_guy_cost: int = 0 + self.player_index: int = 0 + self.bombs: list = [] + self.queue_line: list = [] + self._bots: SpazBotSet | None = None + self.light: bs.Node | None = None + self.last_prize = 'none' + self._flag: Flag | None = None + self._flag2: Flag | None = None + self._flag3: Flag | None = None + self._flag4: Flag | None = None + self._flag5: Flag | None = None + self._flag6: Flag | None = None + self._flag7: Flag | None = None + self._flag8: Flag | None = None + self.set = False + self.round_timer: bs.Timer | None = None + self.give_points_timer: bs.Timer | None = None + + self._jackpot_sound = bui.getsound('achievement') + self._round_sound = bui.getsound('powerup01') + self._dingsound = bui.getsound('dingSmall') + + # Base class overrides. + self.slow_motion = self._epic_mode + self.default_music = ( + bs.MusicType.EPIC if self._epic_mode else bs.MusicType.TO_THE_DEATH + ) + + def on_team_join(self, team: Team) -> None: + if self.has_begun(): + self._update_scoreboard() + + def on_player_leave(self, player: Player) -> None: + if player is self.current_player: + self.setup_next_round() + self._check_end_game() + super().on_player_leave(player) + self.queue_line.remove(player) + self._update_icons() + + def on_begin(self) -> None: + super().on_begin() + for player in self.players: + if player.actor: + player.actor.handlemessage(bs.DieMessage()) + player.actor.node.delete() + self.queue_line.append(player) + self.spawn_player_spaz( + self.queue_line[self.player_index % len(self.queue_line)], + (0.0, 3.0, -2.0)) + self.current_player = self.queue_line[0] + # Declare a set of bots (enemies) that we will use later + self._bots = SpazBotSet() + self.reset_flags() + self._update_icons() + self._update_scoreboard() + + def credits(self) -> None: + bs.newnode( + 'text', + attrs={ + 'v_attach': 'bottom', + 'h_align': 'center', + 'vr_depth': 0, + 'color': (0, 0.2, 0), + 'shadow': 1.0, + 'flatness': 1.0, + 'position': (0,0), + 'scale': 0.8, + 'text': credits + }) + + def _update_icons(self) -> None: + # pylint: disable=too-many-branches + for player in self.queue_line: + player.icons = [] + if player == self.current_player: + xval = 0 + x_offs = -78 + player.icons.append( + Icon(player, + position=(xval, 65), + scale=1.0, + name_maxwidth=130, + name_scale=0.8, + flatness=0.0, + shadow=0.5, + show_death=True, + show_lives=False)) + elif player.dead: + xval = 65 + x_offs = 78 + player.icons.append( + Icon(player, + position=(xval, 50), + scale=0.5, + name_maxwidth=75, + name_scale=1.0, + flatness=1.0, + shadow=1.0, + show_death=False, + show_lives=False, + dead=True)) + xval += x_offs * 0.56 + else: + xval = -65 + x_offs = 78 + player.icons.append( + Icon(player, + position=(xval, 50), + scale=0.5, + name_maxwidth=75, + name_scale=1.0, + flatness=1.0, + shadow=1.0, + show_death=False, + show_lives=False)) + xval -= x_offs * 0.56 + + def give_prize(self, prize: int) -> None: + if prize == 1: + # Curse him aka make him blow up in 5 seconds + # give them a nice message + bs.broadcastmessage(you_were, color=(0.1, 0.1, 0.1)) + bs.broadcastmessage(cursed_text, color=(1.0, 0.0, 0.0)) + self.make_health_box((0.0, 0.0, 0.0)) + self.last_prize = 'curse' + self.prize_recipient.actor.curse() + # bs.timer(5.5, self.setup_next_round) + if prize == 2: + self.setup_rof() + bs.broadcastmessage(run, color=(1.0, 0.2, 0.1)) + self.last_prize = 'ring_of_fire' + if prize == 3: + self.last_prize = 'climb' + self.light = bs.newnode( + 'locator', + attrs={ + 'shape': 'circle', + 'position': (0.0, 3.0, -9.0), + 'color': (1.0, 1.0, 1.0), + 'opacity': 1.0, + 'draw_beauty': True, + 'additive': True + }) + bs.broadcastmessage(climb_top, color=(0.5, 0.5, 0.5)) + bs.timer(3.0, babase.Call(self.make_health_box, (0.0, 6.0, -9.0))) + self.round_timer = bs.Timer(10.0, self.setup_next_round) + if prize == 4: + self.last_prize = 'land_mines' + self.make_health_box((6.0, 5.0, -2.0)) + self.make_land_mines() + self.prize_recipient.actor.connect_controls_to_player( + enable_bomb=False) + self.prize_recipient.actor.node.handlemessage( + bs.StandMessage(position=(-6.0, 3.0, -2.0))) + self.round_timer = bs.Timer(7.0, self.setup_next_round) + if prize == 5: + # Make it rain bombs + self.bomb_survivor = self.prize_recipient + bs.broadcastmessage(bomb_rain, color=(1.0, 0.5, 0.16)) + # Set positions for the bombs to drop + for bzz in range(-5,6): + for azz in range(-5,2): + # for each position make a bomb drop there + self.make_bomb(bzz, azz) + self.give_points_timer = bs.Timer(3.3, self.give_points) + self.last_prize = 'bombrain' + if prize == 6: + self.setup_br() + self.bomb_survivor = self.prize_recipient + self.give_points_timer = bs.Timer(7.0, self.give_points) + self.last_prize = 'bombroad' + if prize == 7: + # makes killing a bad guy worth ten points + self.bad_guy_cost = 2 + bs.broadcastmessage(lame_guys, color=(1.0, 0.5, 0.16)) + # makes a set of nine positions + for a in range(-1, 2): + for b in range(-3, 0): + # and spawns one in each position + self._bots.spawn_bot(BrawlerBotLite, pos=(a, 2.5, b)) + # and we give our player boxing gloves and a shield + self._player.equip_boxing_gloves() + self._player.equip_shields() + self.last_prize = 'lameguys' + if prize == 8: + self._jackpot_sound.play() + bs.broadcastmessage(jackpot, color=(1.0, 0.0, 0.0)) + bs.broadcastmessage(jackpot, color=(0.0, 1.0, 0.0)) + bs.broadcastmessage(jackpot, color=(0.0, 0.0, 1.0)) + team = self.prize_recipient.team + # GIVE THEM A WHOPPING 50 POINTS!!! + team.score += 50 + # and update the scores + self._update_scoreboard() + self.last_prize = 'jackpot' + bs.timer(2.0, self.setup_next_round) + + def setup_next_round(self) -> None: + if self._slow_motion_deaths: + bs.getactivity().globalsnode.slow_motion = False + if self.set: + return + if self.light: + self.light.delete() + for bomb in self.bombs: + bomb.handlemessage(bs.DieMessage()) + self.kill_flags() + self._bots.clear() + self.reset_flags() + self.current_player.actor.handlemessage( + bs.DieMessage(how='game')) + self.current_player.actor.node.delete() + c = 0 + self.player_index += 1 + self.player_index %= len(self.queue_line) + if len(self.queue_line) > 0: + while self.queue_line[self.player_index].dead: + if c > len(self.queue_line): + return + self.player_index += 1 + self.player_index %= len(self.queue_line) + c += 1 + self.spawn_player_spaz( + self.queue_line[self.player_index], (0.0, 3.0, -2.0)) + self.current_player = self.queue_line[self.player_index] + self.last_prize = 'none' + self._update_icons() + + def check_bots(self) -> None: + if not self._bots.have_living_bots(): + self.setup_next_round() + + def make_land_mines(self) -> None: + self.bombs = [] + for i in range(-11, 7): + self.bombs.append(Bomb( + position=(0.0, 6.0, i/2.0), + bomb_type='land_mine', + blast_radius=2.0)) + self.bombs[i+10].arm() + + def give_points(self) -> None: + if self.bomb_survivor is not None and self.bomb_survivor.is_alive(): + self.bomb_survivor.team.score += 20 + self._update_scoreboard() + self.round_timer = bs.Timer(1.0, self.setup_next_round) + + def make_health_box(self, position: Sequence[float]) -> None: + if position == (0.0, 3.0, 0.0): + position = (random.randint(-6, 6), 6, random.randint(-6, 4)) + elif position == (0,0,0): + position = random.choice( + ((-7, 6, -5), (7, 6, -5), (-7, 6, 1), (7, 6, 1))) + self.health_box = PowerupBox( + position=position, poweruptype='health').autoretain() + + # called in prize #5 + def make_bomb(self, xpos: float, zpos: float) -> None: + # makes a bomb at the given position then auto-retains it aka: + # makes sure it doesn't disappear because there is no reference to it + self.bombs.append(Bomb(position=(xpos, 12, zpos))) + + def setup_br(self) -> None: + self.make_bomb_row(6) + self.prize_recipient.actor.handlemessage( + bs.StandMessage(position=(6.0, 3.0, -2.0))) + + def make_bomb_row(self, num: int) -> None: + if not self.prize_recipient.is_alive(): + return + if num == 0: + self.round_timer = bs.Timer(1.0, self.setup_next_round) + return + for i in range(-11, 7): + self.bombs.append( + Bomb(position=(-3, 3, i/2.0), + velocity=(12, 0.0, 0.0), + bomb_type='normal', + blast_radius=1.2)) + bs.timer(1.0, babase.Call(self.make_bomb_row, num-1)) + + def setup_rof(self) -> None: + self.make_blast_ring(10) + self.prize_recipient.actor.handlemessage( + bs.StandMessage(position=(0.0, 3.0, -2.0))) + + def make_blast_ring(self, length: float) -> None: + if not self.prize_recipient.is_alive(): + return + if length == 0: + self.setup_next_round() + self.prize_recipient.team.score += 50 + self._update_scoreboard() + return + for angle in range(0, 360, 45): + angle += random.randint(0, 45) + angle %= 360 + x = length * math.cos(math.radians(angle)) + z = length * math.sin(math.radians(angle)) + blast = Blast(position=(x, 2.2, z-2), blast_radius=3.5) + bs.timer(0.75, babase.Call(self.make_blast_ring, length-1)) + + # a method to remake the flags + def reset_flags(self) -> None: + # remake the flags + self._flag = Flag( + position=(0.0, 3.0, 1.0), touchable=True, color=(0.0, 0.0, 1.0)) + self._flag2 = Flag( + position=(0.0, 3.0, -5.0), touchable=True, color=(1.0, 0.0, 0.0)) + self._flag3 = Flag( + position=(3.0, 3.0, -2.0), touchable=True, color=(0.0, 1.0, 0.0)) + self._flag4 = Flag( + position=(-3.0, 3.0, -2.0), touchable=True, color=(1.0, 1.0, 1.0)) + self._flag5 = Flag( + position=(1.8, 3.0, 0.2), touchable=True, color=(0.0, 1.0, 1.0)) + self._flag6 = Flag( + position=(-1.8, 3.0, 0.2), touchable=True, color=(1.0, 0.0, 1.0)) + self._flag7 = Flag( + position=(1.8, 3.0, -3.8), touchable=True, color=(1.0, 1.0, 0.0)) + self._flag8 = Flag( + position=(-1.8, 3.0, -3.8), touchable=True, color=(0.0, 0.0, 0.0)) + + # a method to kill the flags + def kill_flags(self) -> None: + # destroy all the flags by erasing all references to them, + # indicated by None similar to null + self._flag.node.delete() + self._flag2.node.delete() + self._flag3.node.delete() + self._flag4.node.delete() + self._flag5.node.delete() # 132, 210 ,12 + self._flag6.node.delete() + self._flag7.node.delete() + self._flag8.node.delete() + + def _check_end_game(self) -> None: + for player in self.queue_line: + if not player.dead: + return + self.end_game() + + def spawn_player_spaz( + self, + player: PlayerT, + position: Sequence[float] = (0, 0, 0), + angle: float | None = None, + ) -> PlayerSpaz: + from babase import _math + from bascenev1._gameutils import animate + from bascenev1._coopsession import CoopSession + + angle = None + name = player.getname() + color = player.color + highlight = player.highlight + + light_color = _math.normalized_color(color) + display_color = babase.safecolor(color, target_intensity=0.75) + + spaz = FlagBearer(color=color, + highlight=highlight, + character=player.character, + player=player) + + player.actor = spaz + assert spaz.node + + spaz.node.name = name + spaz.node.name_color = display_color + spaz.connect_controls_to_player() + + # Move to the stand position and add a flash of light. + spaz.handlemessage( + bs.StandMessage( + position, + angle if angle is not None else random.uniform(0, 360))) + self._spawn_sound.play(1, position=spaz.node.position) + light = bs.newnode('light', attrs={'color': light_color}) + spaz.node.connectattr('position', light, 'position') + animate(light, 'intensity', {0: 0, 0.25: 1, 0.5: 0}) + bs.timer(0.5, light.delete) + return spaz + + def handlemessage(self, msg: Any) -> Any: + if isinstance(msg, bs.PlayerDiedMessage): + # give them a nice farewell + if bs.time() < 0.5: + return + if msg.how == 'game': + return + player = msg.getplayer(Player) + bs.broadcastmessage( + diedtxt + str(player.getname()) + diedtxt2, color=player.color) + player.dead = True + if player is self.current_player: + self.round_timer = None + self.give_points_timer = None + if not msg.how is bs.DeathType.FALL: + if self._slow_motion_deaths: + bs.getactivity().globalsnode.slow_motion = True + time = 0.5 + else: + time = 0.01 + # check to see if we can end the game + self._check_end_game() + bs.timer(time, self.setup_next_round) + elif isinstance(msg, FlagPickedUpMessage): + msg.flag.last_player_to_hold = msg.node.getdelegate( + FlagBearer, True + ).getplayer(Player, True) + self._player = msg.node.getdelegate( + FlagBearer, True + ) + self.prize_recipient = msg.node.getdelegate( + FlagBearer, True + ).getplayer(Player, True) + self.kill_flags() + self.give_prize(random.randint(1, 8)) + self._round_sound.play() + self.current_player = self.prize_recipient + elif isinstance(msg, SpazBotDiedMessage): + # find out which team the last person to hold a flag was on + team = self.prize_recipient.team + # give them their points + team.score += self.bad_guy_cost + self._dingsound.play(0.5) + # update the scores + for team in self.teams: + self._scoreboard.set_team_value(team, team.score) + bs.timer(0.3, self.check_bots) + return None + + def _update_scoreboard(self) -> None: + for player in self.queue_line: + if not player.dead: + if player.team.score > 0: + self._dingsound.play() + self._scoreboard.set_team_value(player.team, player.team.score) + + def end_game(self) -> None: + if self.set: + return + self.set = True + results = bs.GameResults() + for team in self.teams: + results.set_team_score(team, team.score) + self.end(results=results) diff --git a/plugins/utilities.json b/plugins/utilities.json index 0a5c0940..b5f63eb0 100644 --- a/plugins/utilities.json +++ b/plugins/utilities.json @@ -1175,6 +1175,34 @@ "versions": { "1.0.0": null } + }, + "bots_can_accept_powerups": { + "description": "Bots can steal your powerups", + "external_url": "", + "authors": [ + { + "name": "", + "email": "", + "discord": "" + } + ], + "versions": { + "1.0.0": null + } + }, + "cheat_menu": { + "description": "Cheat menu on the settings window", + "external_url": "", + "authors": [ + { + "name": "pranav", + "email": "", + "discord": "" + } + ], + "versions": { + "1.0.0": null + } } } } \ No newline at end of file diff --git a/plugins/utilities/bots_can_accept_powerups.py b/plugins/utilities/bots_can_accept_powerups.py new file mode 100644 index 00000000..7c00f67e --- /dev/null +++ b/plugins/utilities/bots_can_accept_powerups.py @@ -0,0 +1,41 @@ +# Ported to api 8 by brostos using baport.(https://github.com/bombsquad-community/baport) +# ba_meta require api 8 +# (see https://ballistica.net/wiki/meta-tag-system) + +from __future__ import annotations + +from typing import TYPE_CHECKING + +import babase +import bauiv1 as bui +import bascenev1 as bs +from bascenev1lib.actor.spazbot import SpazBot +from bascenev1lib.actor.powerupbox import PowerupBoxFactory + +if TYPE_CHECKING: + pass + + +# ba_meta export plugin +class BotsCanAcceptPowerupsPlugin(babase.Plugin): + def on_app_running(self) -> None: + SpazBot.oldinit = SpazBot.__init__ + def __init__(self) -> None: + self.oldinit() + pam = PowerupBoxFactory.get().powerup_accept_material + materials = self.node.materials + materials = list(materials) + materials.append(pam) + materials = tuple(materials) + self.node.materials = materials + roller_materials = self.node.roller_materials + roller_materials = list(roller_materials) + roller_materials.append(pam) + roller_materials = tuple(roller_materials) + self.node.roller_materials = roller_materials + extras_material = self.node.extras_material + extras_material = list(extras_material) + extras_material.append(pam) + extras_material = tuple(extras_material) + self.node.extras_material = extras_material + SpazBot.__init__ = __init__ diff --git a/plugins/utilities/cheat_menu.py b/plugins/utilities/cheat_menu.py new file mode 100644 index 00000000..8648dea7 --- /dev/null +++ b/plugins/utilities/cheat_menu.py @@ -0,0 +1,355 @@ +# Ported by brostos to api 8 +# Tool used to make porting easier.(https://github.com/bombsquad-community/baport) +"""CheatMenu | now cheat much as you can haha!! please eric sir dont kill me + + +Credits To: +Pranav"Modder"= Creator of the mod. +Emily"Skin and Modder"= Code and Mod Ideas.(pls dont be angry) :"( +And Me(Edited): Well Litterally Nothing lol. + +Important Note From the Creator: "I apreciate any kind of modification. So feel free to use or edit code or change credit string.... no problem. +this mod uses activity loop cheacks if change in config and update it on our player node" + +Really Awesome servers: + Bombsquad Consultancy Service - https://discord.gg/2RKd9QQdQY. + bombspot - https://discord.gg/ucyaesh. + cyclones - https://discord.gg/pJXxkbQ7kH. +""" +from __future__ import annotations + +__author__ = 'egg' +__version__ = 1.0 + +import babase +import bauiv1 as bui +import bascenev1 as bs +import _babase + +from baenv import TARGET_BALLISTICA_BUILD as build_number +from bauiv1lib.settings.allsettings import AllSettingsWindow +from bascenev1lib.actor.spaz import Spaz + +from typing import ( + Text, + Tuple, + Optional, + Union, + get_args +) +type + +# Default Confings/Settings +CONFIG = "CheatMenu" +APPCONFIG = babase.app.config +Configs = { + "Unlimited Heath": False, + "SpeedBoots": False, + "Fly": False, + "SuperPunch": False, + "ImpactOnly": False, + "StickyOnly": False, + "IceOnly" : False, + "Infinite Bombs": False, + "More Are Coming": False, + "Credits": False, +} + + +def setconfigs() -> None: + """Set required defualt configs for mod""" + if CONFIG not in APPCONFIG: + APPCONFIG[str(CONFIG)] = Configs + + for c in Configs: + if c not in APPCONFIG[str(CONFIG)]: + APPCONFIG[str(CONFIG)][str(c)] = Configs[str(c)] + else: + pass + APPCONFIG.apply_and_commit() + + +def update_config(config: str, change: any): + """update's given value in json config file of pluguin""" + APPCONFIG[str(CONFIG)][str(config)] = change + APPCONFIG.apply_and_commit() + + +# ba_meta require api 8 +# ba_meta export plugin +class Plugin(babase.Plugin): + def on_app_running(self) -> None: + if babase.app.build_number if build_number < 21282 else babase.app.env.build_number: + setconfigs() + self.overwrite() + + else: + babase.screenmessage(f'{__name__} only works on api 8') + + def overwrite(self) -> None: + AllSettingsWindow.init = AllSettingsWindow.__init__ + AllSettingsWindow.__init__ = AllSettingsWindowInit + + +# creating Cheat button, start button +def AllSettingsWindowInit(self, transition: str = 'in_right', origin_widget: bui.Widget = None): + self.init(transition) + + uiscale = bui.app.ui_v1.uiscale + btn_width = 720 if uiscale is babase.UIScale.SMALL else 400 + btn_height = 380 + + self.cheat_menu_btn = bui.buttonwidget( + parent=self._root_widget, + autoselect=True, + position=(btn_width, btn_height), + size=(105, 50), + icon=bui.gettexture('settingsIcon'), + label='Cheats', + button_type='square', + text_scale=1.2, + on_activate_call=babase.Call( + on_cheat_menu_btn_press, self)) + + +# on cheat button press call Window +def on_cheat_menu_btn_press(self): + bui.containerwidget(edit=self._root_widget, + transition='out_scale') + bui.app.ui_v1.set_main_menu_window( + CheatMenuWindow( + transition='in_right').get_root_widget(), from_window=self._root_widget) + + +class CheatMenuWindow(bui.Window): + def __init__(self, + transition: Optional[str] = 'in_right') -> None: + + # background window, main widget parameters + uiscale = bui.app.ui_v1.uiscale + self._width = 870.0 if uiscale is babase.UIScale.SMALL else 670.0 + self._height = (390.0 if uiscale is babase.UIScale.SMALL else + 450.0 if uiscale is babase.UIScale.MEDIUM else 520.0) + extra_x = 100 if uiscale is babase.UIScale.SMALL else 0 + self.extra_x = extra_x + top_extra = 20 if uiscale is babase.UIScale.SMALL else 0 + + # scroll widget parameters + self._scroll_width = self._width - (100 + 2 * extra_x) + self._scroll_height = self._height - 115.0 + self._sub_width = self._scroll_width * 0.95 + self._sub_height = 640.0 + self._spacing = 32 + self._extra_button_spacing = self._spacing * 2.5 + + super().__init__( + root_widget=bui.containerwidget( + size=(self._width, self._height), + transition=transition, + scale=(2.06 if uiscale is babase.UIScale.SMALL else + 1.4 if uiscale is babase.UIScale.MEDIUM else 1.0))) + + # back button widget + self._back_button = bui.buttonwidget( + parent=self._root_widget, + autoselect=True, + position=(52 + self.extra_x, + self._height - 60 - top_extra), + size=(60, 60), + scale=0.8, + label=babase.charstr(babase.SpecialChar.BACK), + button_type='backSmall', + on_activate_call=self._back) + bui.containerwidget(edit=self._root_widget, + cancel_button=self._back_button) + + # window title, apears in top center of window + self._title_text = bui.textwidget( + parent=self._root_widget, + position=(0, self._height - 40 - top_extra), + size=(self._width, 25), + text='Cheat Menu', + color=bui.app.ui_v1.title_color, + scale=1.2, + h_align='center', + v_align='top') + + self._scrollwidget = bui.scrollwidget( + parent=self._root_widget, + position=(50 + extra_x, 50 - top_extra), + simple_culling_v=20.0, + highlight=False, + size=(self._scroll_width, + self._scroll_height), + selection_loops_to_parent=True) + bui.widget(edit=self._scrollwidget, + right_widget=self._scrollwidget) + + # subcontainer represents scroll widget and used as parent + self._subcontainer = bui.containerwidget( + parent=self._scrollwidget, + size=(self._sub_width, + self._sub_height), + background=False, + selection_loops_to_parent=True) + + v = self._sub_height - 35 + v -= self._spacing * 1.2 + conf = APPCONFIG[str(CONFIG)] + + for checkbox in Configs: + bui.checkboxwidget( + parent=self._subcontainer, + autoselect=True, + position=(25.0, v), + size=(40, 40), + text=checkbox, + textcolor=(0.8, 0.8, 0.8), + value=APPCONFIG[CONFIG][checkbox], + on_value_change_call=babase.Call( + self.update, checkbox), + scale=1.4, + maxwidth=430) + v -= 70 + + def update(self, config: str, change) -> None: + """Change config and get our sounds + + Args: + config: str + change: any + """ + try: + if change == True and config == "Fly": + bui.screenmessage("Some maps may not work good for flying", + color=(1, 0, 0)) + update_config(config, change) + bui.getsound('gunCocking').play() + except Exception: + bui.screenmessage("error", color=(1, 0, 0)) + bui.getsound('error').play() + + try: + if change == True and config == "SuperPunch": + bui.screenmessage("SuperPunch Activated", + color=(1, 0, 0)) + elif change == False and config == "SuperPunch": + bui.screenmessage("Super Punch Deactivated", + color=(0.5,0,0)) + update_config(config, change) + bui.getsound('gunCocking').play() + except Exception: + bui.screenmessage("error", color=(1, 0, 0)) + bui.getsound('spazOw').play() + + try: + if change == True and config == "IceOnly": + bui.screenmessage("Ice Bombs Activated", + color=(0.1, 1, 1)) + elif change == False and config == "IceOnly": + bui.screenmessage("Ice Bombs Deactivated", + color=(1, 0, 0)) + update_config(config, change) + bui.getsound('gunCocking').play() + except Exception: + bui.screenmessage("error", color=(1, 0, 0)) + bui.getsound('spazOw').play() + try: + if change == True and config == "StickyOnly": + bui.screenmessage("Sticky Bombs Activated", + color=(0, 1, 0)) + elif change == False and config == "StickyOnly": + bui.screenmessage("Sticky Bombs Deactivated", + color=(1, 0, 0)) + update_config(config, change) + bui.getsound('gunCocking').play() + except Exception: + bui.screenmessage("error", color=(1, 0, 0)) + bui.getsound('spazOw').play() + + try: + if change == True and config == "ImpactOnly": + bui.screenmessage("Impact Bombs Activated", + color=(0.5, 0.5, 0.5)) + elif change == False and config == "ImpactOnly": + bui.screenmessage("Impact Bombs Deactivated", + color=(1, 0, 0)) + update_config(config, change) + bui.getsound('gunCocking').play() + except Exception: + bui.screenmessage("error", color=(1, 0, 0)) + bui.getsound('spazOw').play() + + try: + if change == True and config == "More Are Coming": + bui.screenmessage("Check out https://discord.gg/2RKd9QQdQY For More Mods", + color=(4, 9, 2)) + update_config(config, change) + bui.getsound('gunCocking').play() + except Exception: + bui.screenmessage("error", color=(1, 0, 0)) + bui.getsound('cheer').play() + + try: + if change == True and config == "Credits": + bui.screenmessage("To Pranav Made The Mod and Emily For Ideas, Thx", + color=(4, 9, 2)) + update_config(config, change) + bui.getsound('gunCocking').play() + except Exception: + bui.screenmessage("error", color=(1, 0, 0)) + bui.getsound('cheer').play() + + def _back(self) -> None: + """Kill the window and get back to previous one + """ + bui.containerwidget(edit=self._root_widget, + transition='out_scale') + bui.app.ui_v1.set_main_menu_window( + AllSettingsWindow( + transition='in_left').get_root_widget(), from_window=self._root_widget) + + +def ishost(): + session = bs.get_foreground_host_session() + with session.context: + for player in session.sessionplayers: + if player.inputdevice.client_id == -1: + return True + +def activity_loop(): + if bs.get_foreground_host_activity() is not None: + activity = bs.get_foreground_host_activity() + with activity.context: + for player in activity.players: + if not ishost() or not player.actor: + return + config = APPCONFIG[CONFIG] + + player.actor.node.invincible = config["Unlimited Heath"] + player.actor.node.fly = config["Fly"] + player.actor.node.hockey = config["SpeedBoots"] + + if config["SuperPunch"]: + player.actor._punch_power_scale = 2 + + elif not config["SuperPunch"]: + player.actor._punch_power_scale = 1.2 + + if config["IceOnly"]: + player.actor.bomb_type = 'ice' + elif not config["IceOnly"]: + player.actor.bomb_type = 'normal' + player.actor.bomb_count= 1 + + if config["ImpactOnly"]: + player.actor.bomb_type = 'impact' + player.actor.bomb_count = 1 + + if config["StickyOnly"]: + player.actor.bomb_type = 'sticky' + player.actor.bomb_count = 1 + + if config["Infinite Bombs"]: + player.actor.bomb_count = 100 +timer = babase.AppTimer(2, activity_loop,repeat=True) \ No newline at end of file From 4941d0cb0e208fbf794f7ef47c2ba5caad41d058 Mon Sep 17 00:00:00 2001 From: brostosjoined Date: Thu, 1 Feb 2024 10:09:19 +0000 Subject: [PATCH 0845/1464] [ci] auto-format --- plugins/minigames/flag_day.py | 1135 +++++++++-------- plugins/utilities/bots_can_accept_powerups.py | 1 + plugins/utilities/cheat_menu.py | 67 +- 3 files changed, 604 insertions(+), 599 deletions(-) diff --git a/plugins/minigames/flag_day.py b/plugins/minigames/flag_day.py index d5d473c5..534ec6f2 100644 --- a/plugins/minigames/flag_day.py +++ b/plugins/minigames/flag_day.py @@ -1,5 +1,5 @@ -#Ported by brostos to api 8 +# Ported by brostos to api 8 # ba_meta require api 8 # (see https://ballistica.net/wiki/meta-tag-system) @@ -23,592 +23,593 @@ from bascenev1lib.actor.spazbot import SpazBotSet, BrawlerBotLite, SpazBotDiedMessage if TYPE_CHECKING: - from typing import Any, Sequence + from typing import Any, Sequence lang = bs.app.lang.language if lang == 'Spanish': - name = 'Día de la Bandera' - description = ('Recoge las banderas para recibir un premio.\n' - 'Pero ten cuidado...') - slow_motion_deaths = 'Muertes en Cámara Lenta' - credits = 'Creado por MattZ45986 en Github | Actualizado por byANG3L and brostos' - you_were = 'Estas' - cursed_text = 'MALDITO' - run = 'CORRE' - climb_top = 'Escala a la cima' - bomb_rain = '¡LLUVIA DE BOMBAS!' - lame_guys = 'Chicos Ligeros' - jackpot = '¡PREMIO MAYOR!' - diedtxt = '¡' - diedtxt2 = ' ha sido eliminado!' + name = 'Día de la Bandera' + description = ('Recoge las banderas para recibir un premio.\n' + 'Pero ten cuidado...') + slow_motion_deaths = 'Muertes en Cámara Lenta' + credits = 'Creado por MattZ45986 en Github | Actualizado por byANG3L and brostos' + you_were = 'Estas' + cursed_text = 'MALDITO' + run = 'CORRE' + climb_top = 'Escala a la cima' + bomb_rain = '¡LLUVIA DE BOMBAS!' + lame_guys = 'Chicos Ligeros' + jackpot = '¡PREMIO MAYOR!' + diedtxt = '¡' + diedtxt2 = ' ha sido eliminado!' else: - name = 'Flag Day' - description = 'Pick up flags to receive a prize.\nBut beware...' - slow_motion_deaths = 'Slow Motion Deaths' - credits = 'Created by MattZ45986 on Github | Updated by byANG3L and brostos' - you_were = 'You were' - cursed_text = 'CURSED' - run = 'RUN' - climb_top = 'Climb to the top' - bomb_rain = 'BOMB RAIN!' - lame_guys = 'Lame Guys' - jackpot = '!JACKPOT!' - diedtxt = '' - diedtxt2 = ' died!' + name = 'Flag Day' + description = 'Pick up flags to receive a prize.\nBut beware...' + slow_motion_deaths = 'Slow Motion Deaths' + credits = 'Created by MattZ45986 on Github | Updated by byANG3L and brostos' + you_were = 'You were' + cursed_text = 'CURSED' + run = 'RUN' + climb_top = 'Climb to the top' + bomb_rain = 'BOMB RAIN!' + lame_guys = 'Lame Guys' + jackpot = '!JACKPOT!' + diedtxt = '' + diedtxt2 = ' died!' class Icon(Icon): - def __init__( - self, - player: Player, - position: tuple[float, float], - scale: float, - show_lives: bool = True, - show_death: bool = True, - name_scale: float = 1.0, - name_maxwidth: float = 115.0, - flatness: float = 1.0, - shadow: float = 1.0, - dead: bool = False, - ): - super().__init__(player,position,scale,show_lives,show_death, - name_scale,name_maxwidth,flatness,shadow) - if dead: - self._name_text.opacity = 0.2 - self.node.color = (0.7, 0.3, 0.3) - self.node.opacity = 0.2 + def __init__( + self, + player: Player, + position: tuple[float, float], + scale: float, + show_lives: bool = True, + show_death: bool = True, + name_scale: float = 1.0, + name_maxwidth: float = 115.0, + flatness: float = 1.0, + shadow: float = 1.0, + dead: bool = False, + ): + super().__init__(player, position, scale, show_lives, show_death, + name_scale, name_maxwidth, flatness, shadow) + if dead: + self._name_text.opacity = 0.2 + self.node.color = (0.7, 0.3, 0.3) + self.node.opacity = 0.2 class FlagBearer(PlayerSpaz): - def handlemessage(self, msg: Any) -> Any: - super().handlemessage(msg) - if isinstance(msg, bs.PowerupMessage): - activity = self.activity - player = self.getplayer(Player) - if not player.is_alive(): - return - if activity.last_prize == 'curse': - player.team.score += 25 - activity._update_scoreboard() - elif activity.last_prize == 'land_mines': - player.team.score += 15 - activity._update_scoreboard() - self.connect_controls_to_player() - elif activity.last_prize == 'climb': - player.team.score += 50 - activity._update_scoreboard() - if msg.poweruptype == 'health': - activity.round_timer = None - bs.timer(0.2, activity.setup_next_round) + def handlemessage(self, msg: Any) -> Any: + super().handlemessage(msg) + if isinstance(msg, bs.PowerupMessage): + activity = self.activity + player = self.getplayer(Player) + if not player.is_alive(): + return + if activity.last_prize == 'curse': + player.team.score += 25 + activity._update_scoreboard() + elif activity.last_prize == 'land_mines': + player.team.score += 15 + activity._update_scoreboard() + self.connect_controls_to_player() + elif activity.last_prize == 'climb': + player.team.score += 50 + activity._update_scoreboard() + if msg.poweruptype == 'health': + activity.round_timer = None + bs.timer(0.2, activity.setup_next_round) class Player(bs.Player['Team']): - """Our player type for this game.""" + """Our player type for this game.""" + + def __init__(self) -> None: + self.dead = False + self.icons: list[Icon] = [] - def __init__(self) -> None: - self.dead = False - self.icons: list[Icon] = [] class Team(bs.Team[Player]): - """Our team type for this game.""" + """Our team type for this game.""" - def __init__(self) -> None: - self.score = 0 + def __init__(self) -> None: + self.score = 0 # ba_meta export bascenev1.GameActivity class FlagDayGame(bs.TeamGameActivity[Player, Team]): - """A game type based on acquiring kills.""" - - name = name - description = description - - # Print messages when players die since it matters here. - announce_player_deaths = True - - allow_mid_activity_joins = False - - @classmethod - def get_available_settings( - cls, sessiontype: type[bs.Session] - ) -> list[babase.Setting]: - settings = [ - bs.BoolSetting(slow_motion_deaths, default=True), - bs.BoolSetting('Epic Mode', default=False), - ] - return settings - - @classmethod - def supports_session_type(cls, sessiontype: type[bs.Session]) -> bool: - return ( - issubclass(sessiontype, bs.CoopSession) - or issubclass(sessiontype, bs.DualTeamSession) - or issubclass(sessiontype, bs.FreeForAllSession) - ) - - @classmethod - def get_supported_maps(cls, sessiontype: type[bs.Session]) -> list[str]: - return ['Courtyard'] - - def __init__(self, settings: dict): - super().__init__(settings) - self.credits() - self._scoreboard = Scoreboard() - self._dingsound = bui.getsound('dingSmall') - self._epic_mode = bool(settings['Epic Mode']) - self._slow_motion_deaths = bool(settings[slow_motion_deaths]) - self.current_player: Player | None = None - self.prize_recipient: Player | None = None - self.bomb_survivor: Player | None = None - self.bad_guy_cost: int = 0 - self.player_index: int = 0 - self.bombs: list = [] - self.queue_line: list = [] - self._bots: SpazBotSet | None = None - self.light: bs.Node | None = None - self.last_prize = 'none' - self._flag: Flag | None = None - self._flag2: Flag | None = None - self._flag3: Flag | None = None - self._flag4: Flag | None = None - self._flag5: Flag | None = None - self._flag6: Flag | None = None - self._flag7: Flag | None = None - self._flag8: Flag | None = None - self.set = False - self.round_timer: bs.Timer | None = None - self.give_points_timer: bs.Timer | None = None - - self._jackpot_sound = bui.getsound('achievement') - self._round_sound = bui.getsound('powerup01') - self._dingsound = bui.getsound('dingSmall') - - # Base class overrides. - self.slow_motion = self._epic_mode - self.default_music = ( - bs.MusicType.EPIC if self._epic_mode else bs.MusicType.TO_THE_DEATH - ) - - def on_team_join(self, team: Team) -> None: - if self.has_begun(): - self._update_scoreboard() - - def on_player_leave(self, player: Player) -> None: - if player is self.current_player: - self.setup_next_round() - self._check_end_game() - super().on_player_leave(player) - self.queue_line.remove(player) - self._update_icons() - - def on_begin(self) -> None: - super().on_begin() - for player in self.players: - if player.actor: - player.actor.handlemessage(bs.DieMessage()) - player.actor.node.delete() - self.queue_line.append(player) - self.spawn_player_spaz( - self.queue_line[self.player_index % len(self.queue_line)], - (0.0, 3.0, -2.0)) - self.current_player = self.queue_line[0] - # Declare a set of bots (enemies) that we will use later - self._bots = SpazBotSet() - self.reset_flags() - self._update_icons() - self._update_scoreboard() - - def credits(self) -> None: - bs.newnode( - 'text', - attrs={ - 'v_attach': 'bottom', - 'h_align': 'center', - 'vr_depth': 0, - 'color': (0, 0.2, 0), - 'shadow': 1.0, - 'flatness': 1.0, - 'position': (0,0), - 'scale': 0.8, - 'text': credits - }) - - def _update_icons(self) -> None: - # pylint: disable=too-many-branches - for player in self.queue_line: - player.icons = [] - if player == self.current_player: - xval = 0 - x_offs = -78 - player.icons.append( - Icon(player, - position=(xval, 65), - scale=1.0, - name_maxwidth=130, - name_scale=0.8, - flatness=0.0, - shadow=0.5, - show_death=True, - show_lives=False)) - elif player.dead: - xval = 65 - x_offs = 78 - player.icons.append( - Icon(player, - position=(xval, 50), - scale=0.5, - name_maxwidth=75, - name_scale=1.0, - flatness=1.0, - shadow=1.0, - show_death=False, - show_lives=False, - dead=True)) - xval += x_offs * 0.56 - else: - xval = -65 - x_offs = 78 - player.icons.append( - Icon(player, - position=(xval, 50), - scale=0.5, - name_maxwidth=75, - name_scale=1.0, - flatness=1.0, - shadow=1.0, - show_death=False, - show_lives=False)) - xval -= x_offs * 0.56 - - def give_prize(self, prize: int) -> None: - if prize == 1: - # Curse him aka make him blow up in 5 seconds - # give them a nice message - bs.broadcastmessage(you_were, color=(0.1, 0.1, 0.1)) - bs.broadcastmessage(cursed_text, color=(1.0, 0.0, 0.0)) - self.make_health_box((0.0, 0.0, 0.0)) - self.last_prize = 'curse' - self.prize_recipient.actor.curse() - # bs.timer(5.5, self.setup_next_round) - if prize == 2: - self.setup_rof() - bs.broadcastmessage(run, color=(1.0, 0.2, 0.1)) - self.last_prize = 'ring_of_fire' - if prize == 3: - self.last_prize = 'climb' - self.light = bs.newnode( - 'locator', - attrs={ - 'shape': 'circle', - 'position': (0.0, 3.0, -9.0), - 'color': (1.0, 1.0, 1.0), - 'opacity': 1.0, - 'draw_beauty': True, - 'additive': True - }) - bs.broadcastmessage(climb_top, color=(0.5, 0.5, 0.5)) - bs.timer(3.0, babase.Call(self.make_health_box, (0.0, 6.0, -9.0))) - self.round_timer = bs.Timer(10.0, self.setup_next_round) - if prize == 4: - self.last_prize = 'land_mines' - self.make_health_box((6.0, 5.0, -2.0)) - self.make_land_mines() - self.prize_recipient.actor.connect_controls_to_player( - enable_bomb=False) - self.prize_recipient.actor.node.handlemessage( - bs.StandMessage(position=(-6.0, 3.0, -2.0))) - self.round_timer = bs.Timer(7.0, self.setup_next_round) - if prize == 5: - # Make it rain bombs - self.bomb_survivor = self.prize_recipient - bs.broadcastmessage(bomb_rain, color=(1.0, 0.5, 0.16)) - # Set positions for the bombs to drop - for bzz in range(-5,6): - for azz in range(-5,2): - # for each position make a bomb drop there - self.make_bomb(bzz, azz) - self.give_points_timer = bs.Timer(3.3, self.give_points) - self.last_prize = 'bombrain' - if prize == 6: - self.setup_br() - self.bomb_survivor = self.prize_recipient - self.give_points_timer = bs.Timer(7.0, self.give_points) - self.last_prize = 'bombroad' - if prize == 7: - # makes killing a bad guy worth ten points - self.bad_guy_cost = 2 - bs.broadcastmessage(lame_guys, color=(1.0, 0.5, 0.16)) - # makes a set of nine positions - for a in range(-1, 2): - for b in range(-3, 0): - # and spawns one in each position - self._bots.spawn_bot(BrawlerBotLite, pos=(a, 2.5, b)) - # and we give our player boxing gloves and a shield - self._player.equip_boxing_gloves() - self._player.equip_shields() - self.last_prize = 'lameguys' - if prize == 8: - self._jackpot_sound.play() - bs.broadcastmessage(jackpot, color=(1.0, 0.0, 0.0)) - bs.broadcastmessage(jackpot, color=(0.0, 1.0, 0.0)) - bs.broadcastmessage(jackpot, color=(0.0, 0.0, 1.0)) - team = self.prize_recipient.team - # GIVE THEM A WHOPPING 50 POINTS!!! - team.score += 50 - # and update the scores - self._update_scoreboard() - self.last_prize = 'jackpot' - bs.timer(2.0, self.setup_next_round) - - def setup_next_round(self) -> None: - if self._slow_motion_deaths: - bs.getactivity().globalsnode.slow_motion = False - if self.set: - return - if self.light: - self.light.delete() - for bomb in self.bombs: - bomb.handlemessage(bs.DieMessage()) - self.kill_flags() - self._bots.clear() - self.reset_flags() - self.current_player.actor.handlemessage( - bs.DieMessage(how='game')) - self.current_player.actor.node.delete() - c = 0 - self.player_index += 1 - self.player_index %= len(self.queue_line) - if len(self.queue_line) > 0: - while self.queue_line[self.player_index].dead: - if c > len(self.queue_line): - return - self.player_index += 1 - self.player_index %= len(self.queue_line) - c += 1 - self.spawn_player_spaz( - self.queue_line[self.player_index], (0.0, 3.0, -2.0)) - self.current_player = self.queue_line[self.player_index] - self.last_prize = 'none' - self._update_icons() - - def check_bots(self) -> None: - if not self._bots.have_living_bots(): - self.setup_next_round() - - def make_land_mines(self) -> None: - self.bombs = [] - for i in range(-11, 7): - self.bombs.append(Bomb( - position=(0.0, 6.0, i/2.0), - bomb_type='land_mine', - blast_radius=2.0)) - self.bombs[i+10].arm() - - def give_points(self) -> None: - if self.bomb_survivor is not None and self.bomb_survivor.is_alive(): - self.bomb_survivor.team.score += 20 - self._update_scoreboard() - self.round_timer = bs.Timer(1.0, self.setup_next_round) - - def make_health_box(self, position: Sequence[float]) -> None: - if position == (0.0, 3.0, 0.0): - position = (random.randint(-6, 6), 6, random.randint(-6, 4)) - elif position == (0,0,0): - position = random.choice( - ((-7, 6, -5), (7, 6, -5), (-7, 6, 1), (7, 6, 1))) - self.health_box = PowerupBox( - position=position, poweruptype='health').autoretain() - - # called in prize #5 - def make_bomb(self, xpos: float, zpos: float) -> None: - # makes a bomb at the given position then auto-retains it aka: - # makes sure it doesn't disappear because there is no reference to it - self.bombs.append(Bomb(position=(xpos, 12, zpos))) - - def setup_br(self) -> None: - self.make_bomb_row(6) - self.prize_recipient.actor.handlemessage( - bs.StandMessage(position=(6.0, 3.0, -2.0))) - - def make_bomb_row(self, num: int) -> None: - if not self.prize_recipient.is_alive(): - return - if num == 0: - self.round_timer = bs.Timer(1.0, self.setup_next_round) - return - for i in range(-11, 7): - self.bombs.append( - Bomb(position=(-3, 3, i/2.0), - velocity=(12, 0.0, 0.0), - bomb_type='normal', - blast_radius=1.2)) - bs.timer(1.0, babase.Call(self.make_bomb_row, num-1)) - - def setup_rof(self) -> None: - self.make_blast_ring(10) - self.prize_recipient.actor.handlemessage( - bs.StandMessage(position=(0.0, 3.0, -2.0))) - - def make_blast_ring(self, length: float) -> None: - if not self.prize_recipient.is_alive(): - return - if length == 0: - self.setup_next_round() - self.prize_recipient.team.score += 50 - self._update_scoreboard() - return - for angle in range(0, 360, 45): - angle += random.randint(0, 45) - angle %= 360 - x = length * math.cos(math.radians(angle)) - z = length * math.sin(math.radians(angle)) - blast = Blast(position=(x, 2.2, z-2), blast_radius=3.5) - bs.timer(0.75, babase.Call(self.make_blast_ring, length-1)) - - # a method to remake the flags - def reset_flags(self) -> None: - # remake the flags - self._flag = Flag( - position=(0.0, 3.0, 1.0), touchable=True, color=(0.0, 0.0, 1.0)) - self._flag2 = Flag( - position=(0.0, 3.0, -5.0), touchable=True, color=(1.0, 0.0, 0.0)) - self._flag3 = Flag( - position=(3.0, 3.0, -2.0), touchable=True, color=(0.0, 1.0, 0.0)) - self._flag4 = Flag( - position=(-3.0, 3.0, -2.0), touchable=True, color=(1.0, 1.0, 1.0)) - self._flag5 = Flag( - position=(1.8, 3.0, 0.2), touchable=True, color=(0.0, 1.0, 1.0)) - self._flag6 = Flag( - position=(-1.8, 3.0, 0.2), touchable=True, color=(1.0, 0.0, 1.0)) - self._flag7 = Flag( - position=(1.8, 3.0, -3.8), touchable=True, color=(1.0, 1.0, 0.0)) - self._flag8 = Flag( - position=(-1.8, 3.0, -3.8), touchable=True, color=(0.0, 0.0, 0.0)) - - # a method to kill the flags - def kill_flags(self) -> None: - # destroy all the flags by erasing all references to them, - # indicated by None similar to null - self._flag.node.delete() - self._flag2.node.delete() - self._flag3.node.delete() - self._flag4.node.delete() - self._flag5.node.delete() # 132, 210 ,12 - self._flag6.node.delete() - self._flag7.node.delete() - self._flag8.node.delete() - - def _check_end_game(self) -> None: - for player in self.queue_line: - if not player.dead: - return - self.end_game() - - def spawn_player_spaz( - self, - player: PlayerT, - position: Sequence[float] = (0, 0, 0), - angle: float | None = None, - ) -> PlayerSpaz: - from babase import _math - from bascenev1._gameutils import animate - from bascenev1._coopsession import CoopSession - - angle = None - name = player.getname() - color = player.color - highlight = player.highlight - - light_color = _math.normalized_color(color) - display_color = babase.safecolor(color, target_intensity=0.75) - - spaz = FlagBearer(color=color, - highlight=highlight, - character=player.character, - player=player) - - player.actor = spaz - assert spaz.node - - spaz.node.name = name - spaz.node.name_color = display_color - spaz.connect_controls_to_player() - - # Move to the stand position and add a flash of light. - spaz.handlemessage( - bs.StandMessage( - position, - angle if angle is not None else random.uniform(0, 360))) - self._spawn_sound.play(1, position=spaz.node.position) - light = bs.newnode('light', attrs={'color': light_color}) - spaz.node.connectattr('position', light, 'position') - animate(light, 'intensity', {0: 0, 0.25: 1, 0.5: 0}) - bs.timer(0.5, light.delete) - return spaz - - def handlemessage(self, msg: Any) -> Any: - if isinstance(msg, bs.PlayerDiedMessage): - # give them a nice farewell - if bs.time() < 0.5: - return - if msg.how == 'game': - return - player = msg.getplayer(Player) - bs.broadcastmessage( - diedtxt + str(player.getname()) + diedtxt2, color=player.color) - player.dead = True - if player is self.current_player: - self.round_timer = None - self.give_points_timer = None - if not msg.how is bs.DeathType.FALL: - if self._slow_motion_deaths: - bs.getactivity().globalsnode.slow_motion = True - time = 0.5 - else: - time = 0.01 - # check to see if we can end the game - self._check_end_game() - bs.timer(time, self.setup_next_round) - elif isinstance(msg, FlagPickedUpMessage): - msg.flag.last_player_to_hold = msg.node.getdelegate( - FlagBearer, True - ).getplayer(Player, True) - self._player = msg.node.getdelegate( - FlagBearer, True - ) - self.prize_recipient = msg.node.getdelegate( - FlagBearer, True - ).getplayer(Player, True) - self.kill_flags() - self.give_prize(random.randint(1, 8)) - self._round_sound.play() - self.current_player = self.prize_recipient - elif isinstance(msg, SpazBotDiedMessage): - # find out which team the last person to hold a flag was on - team = self.prize_recipient.team - # give them their points - team.score += self.bad_guy_cost - self._dingsound.play(0.5) - # update the scores - for team in self.teams: - self._scoreboard.set_team_value(team, team.score) - bs.timer(0.3, self.check_bots) - return None - - def _update_scoreboard(self) -> None: - for player in self.queue_line: - if not player.dead: - if player.team.score > 0: - self._dingsound.play() - self._scoreboard.set_team_value(player.team, player.team.score) - - def end_game(self) -> None: - if self.set: - return - self.set = True - results = bs.GameResults() - for team in self.teams: - results.set_team_score(team, team.score) - self.end(results=results) + """A game type based on acquiring kills.""" + + name = name + description = description + + # Print messages when players die since it matters here. + announce_player_deaths = True + + allow_mid_activity_joins = False + + @classmethod + def get_available_settings( + cls, sessiontype: type[bs.Session] + ) -> list[babase.Setting]: + settings = [ + bs.BoolSetting(slow_motion_deaths, default=True), + bs.BoolSetting('Epic Mode', default=False), + ] + return settings + + @classmethod + def supports_session_type(cls, sessiontype: type[bs.Session]) -> bool: + return ( + issubclass(sessiontype, bs.CoopSession) + or issubclass(sessiontype, bs.DualTeamSession) + or issubclass(sessiontype, bs.FreeForAllSession) + ) + + @classmethod + def get_supported_maps(cls, sessiontype: type[bs.Session]) -> list[str]: + return ['Courtyard'] + + def __init__(self, settings: dict): + super().__init__(settings) + self.credits() + self._scoreboard = Scoreboard() + self._dingsound = bui.getsound('dingSmall') + self._epic_mode = bool(settings['Epic Mode']) + self._slow_motion_deaths = bool(settings[slow_motion_deaths]) + self.current_player: Player | None = None + self.prize_recipient: Player | None = None + self.bomb_survivor: Player | None = None + self.bad_guy_cost: int = 0 + self.player_index: int = 0 + self.bombs: list = [] + self.queue_line: list = [] + self._bots: SpazBotSet | None = None + self.light: bs.Node | None = None + self.last_prize = 'none' + self._flag: Flag | None = None + self._flag2: Flag | None = None + self._flag3: Flag | None = None + self._flag4: Flag | None = None + self._flag5: Flag | None = None + self._flag6: Flag | None = None + self._flag7: Flag | None = None + self._flag8: Flag | None = None + self.set = False + self.round_timer: bs.Timer | None = None + self.give_points_timer: bs.Timer | None = None + + self._jackpot_sound = bui.getsound('achievement') + self._round_sound = bui.getsound('powerup01') + self._dingsound = bui.getsound('dingSmall') + + # Base class overrides. + self.slow_motion = self._epic_mode + self.default_music = ( + bs.MusicType.EPIC if self._epic_mode else bs.MusicType.TO_THE_DEATH + ) + + def on_team_join(self, team: Team) -> None: + if self.has_begun(): + self._update_scoreboard() + + def on_player_leave(self, player: Player) -> None: + if player is self.current_player: + self.setup_next_round() + self._check_end_game() + super().on_player_leave(player) + self.queue_line.remove(player) + self._update_icons() + + def on_begin(self) -> None: + super().on_begin() + for player in self.players: + if player.actor: + player.actor.handlemessage(bs.DieMessage()) + player.actor.node.delete() + self.queue_line.append(player) + self.spawn_player_spaz( + self.queue_line[self.player_index % len(self.queue_line)], + (0.0, 3.0, -2.0)) + self.current_player = self.queue_line[0] + # Declare a set of bots (enemies) that we will use later + self._bots = SpazBotSet() + self.reset_flags() + self._update_icons() + self._update_scoreboard() + + def credits(self) -> None: + bs.newnode( + 'text', + attrs={ + 'v_attach': 'bottom', + 'h_align': 'center', + 'vr_depth': 0, + 'color': (0, 0.2, 0), + 'shadow': 1.0, + 'flatness': 1.0, + 'position': (0, 0), + 'scale': 0.8, + 'text': credits + }) + + def _update_icons(self) -> None: + # pylint: disable=too-many-branches + for player in self.queue_line: + player.icons = [] + if player == self.current_player: + xval = 0 + x_offs = -78 + player.icons.append( + Icon(player, + position=(xval, 65), + scale=1.0, + name_maxwidth=130, + name_scale=0.8, + flatness=0.0, + shadow=0.5, + show_death=True, + show_lives=False)) + elif player.dead: + xval = 65 + x_offs = 78 + player.icons.append( + Icon(player, + position=(xval, 50), + scale=0.5, + name_maxwidth=75, + name_scale=1.0, + flatness=1.0, + shadow=1.0, + show_death=False, + show_lives=False, + dead=True)) + xval += x_offs * 0.56 + else: + xval = -65 + x_offs = 78 + player.icons.append( + Icon(player, + position=(xval, 50), + scale=0.5, + name_maxwidth=75, + name_scale=1.0, + flatness=1.0, + shadow=1.0, + show_death=False, + show_lives=False)) + xval -= x_offs * 0.56 + + def give_prize(self, prize: int) -> None: + if prize == 1: + # Curse him aka make him blow up in 5 seconds + # give them a nice message + bs.broadcastmessage(you_were, color=(0.1, 0.1, 0.1)) + bs.broadcastmessage(cursed_text, color=(1.0, 0.0, 0.0)) + self.make_health_box((0.0, 0.0, 0.0)) + self.last_prize = 'curse' + self.prize_recipient.actor.curse() + # bs.timer(5.5, self.setup_next_round) + if prize == 2: + self.setup_rof() + bs.broadcastmessage(run, color=(1.0, 0.2, 0.1)) + self.last_prize = 'ring_of_fire' + if prize == 3: + self.last_prize = 'climb' + self.light = bs.newnode( + 'locator', + attrs={ + 'shape': 'circle', + 'position': (0.0, 3.0, -9.0), + 'color': (1.0, 1.0, 1.0), + 'opacity': 1.0, + 'draw_beauty': True, + 'additive': True + }) + bs.broadcastmessage(climb_top, color=(0.5, 0.5, 0.5)) + bs.timer(3.0, babase.Call(self.make_health_box, (0.0, 6.0, -9.0))) + self.round_timer = bs.Timer(10.0, self.setup_next_round) + if prize == 4: + self.last_prize = 'land_mines' + self.make_health_box((6.0, 5.0, -2.0)) + self.make_land_mines() + self.prize_recipient.actor.connect_controls_to_player( + enable_bomb=False) + self.prize_recipient.actor.node.handlemessage( + bs.StandMessage(position=(-6.0, 3.0, -2.0))) + self.round_timer = bs.Timer(7.0, self.setup_next_round) + if prize == 5: + # Make it rain bombs + self.bomb_survivor = self.prize_recipient + bs.broadcastmessage(bomb_rain, color=(1.0, 0.5, 0.16)) + # Set positions for the bombs to drop + for bzz in range(-5, 6): + for azz in range(-5, 2): + # for each position make a bomb drop there + self.make_bomb(bzz, azz) + self.give_points_timer = bs.Timer(3.3, self.give_points) + self.last_prize = 'bombrain' + if prize == 6: + self.setup_br() + self.bomb_survivor = self.prize_recipient + self.give_points_timer = bs.Timer(7.0, self.give_points) + self.last_prize = 'bombroad' + if prize == 7: + # makes killing a bad guy worth ten points + self.bad_guy_cost = 2 + bs.broadcastmessage(lame_guys, color=(1.0, 0.5, 0.16)) + # makes a set of nine positions + for a in range(-1, 2): + for b in range(-3, 0): + # and spawns one in each position + self._bots.spawn_bot(BrawlerBotLite, pos=(a, 2.5, b)) + # and we give our player boxing gloves and a shield + self._player.equip_boxing_gloves() + self._player.equip_shields() + self.last_prize = 'lameguys' + if prize == 8: + self._jackpot_sound.play() + bs.broadcastmessage(jackpot, color=(1.0, 0.0, 0.0)) + bs.broadcastmessage(jackpot, color=(0.0, 1.0, 0.0)) + bs.broadcastmessage(jackpot, color=(0.0, 0.0, 1.0)) + team = self.prize_recipient.team + # GIVE THEM A WHOPPING 50 POINTS!!! + team.score += 50 + # and update the scores + self._update_scoreboard() + self.last_prize = 'jackpot' + bs.timer(2.0, self.setup_next_round) + + def setup_next_round(self) -> None: + if self._slow_motion_deaths: + bs.getactivity().globalsnode.slow_motion = False + if self.set: + return + if self.light: + self.light.delete() + for bomb in self.bombs: + bomb.handlemessage(bs.DieMessage()) + self.kill_flags() + self._bots.clear() + self.reset_flags() + self.current_player.actor.handlemessage( + bs.DieMessage(how='game')) + self.current_player.actor.node.delete() + c = 0 + self.player_index += 1 + self.player_index %= len(self.queue_line) + if len(self.queue_line) > 0: + while self.queue_line[self.player_index].dead: + if c > len(self.queue_line): + return + self.player_index += 1 + self.player_index %= len(self.queue_line) + c += 1 + self.spawn_player_spaz( + self.queue_line[self.player_index], (0.0, 3.0, -2.0)) + self.current_player = self.queue_line[self.player_index] + self.last_prize = 'none' + self._update_icons() + + def check_bots(self) -> None: + if not self._bots.have_living_bots(): + self.setup_next_round() + + def make_land_mines(self) -> None: + self.bombs = [] + for i in range(-11, 7): + self.bombs.append(Bomb( + position=(0.0, 6.0, i/2.0), + bomb_type='land_mine', + blast_radius=2.0)) + self.bombs[i+10].arm() + + def give_points(self) -> None: + if self.bomb_survivor is not None and self.bomb_survivor.is_alive(): + self.bomb_survivor.team.score += 20 + self._update_scoreboard() + self.round_timer = bs.Timer(1.0, self.setup_next_round) + + def make_health_box(self, position: Sequence[float]) -> None: + if position == (0.0, 3.0, 0.0): + position = (random.randint(-6, 6), 6, random.randint(-6, 4)) + elif position == (0, 0, 0): + position = random.choice( + ((-7, 6, -5), (7, 6, -5), (-7, 6, 1), (7, 6, 1))) + self.health_box = PowerupBox( + position=position, poweruptype='health').autoretain() + + # called in prize #5 + def make_bomb(self, xpos: float, zpos: float) -> None: + # makes a bomb at the given position then auto-retains it aka: + # makes sure it doesn't disappear because there is no reference to it + self.bombs.append(Bomb(position=(xpos, 12, zpos))) + + def setup_br(self) -> None: + self.make_bomb_row(6) + self.prize_recipient.actor.handlemessage( + bs.StandMessage(position=(6.0, 3.0, -2.0))) + + def make_bomb_row(self, num: int) -> None: + if not self.prize_recipient.is_alive(): + return + if num == 0: + self.round_timer = bs.Timer(1.0, self.setup_next_round) + return + for i in range(-11, 7): + self.bombs.append( + Bomb(position=(-3, 3, i/2.0), + velocity=(12, 0.0, 0.0), + bomb_type='normal', + blast_radius=1.2)) + bs.timer(1.0, babase.Call(self.make_bomb_row, num-1)) + + def setup_rof(self) -> None: + self.make_blast_ring(10) + self.prize_recipient.actor.handlemessage( + bs.StandMessage(position=(0.0, 3.0, -2.0))) + + def make_blast_ring(self, length: float) -> None: + if not self.prize_recipient.is_alive(): + return + if length == 0: + self.setup_next_round() + self.prize_recipient.team.score += 50 + self._update_scoreboard() + return + for angle in range(0, 360, 45): + angle += random.randint(0, 45) + angle %= 360 + x = length * math.cos(math.radians(angle)) + z = length * math.sin(math.radians(angle)) + blast = Blast(position=(x, 2.2, z-2), blast_radius=3.5) + bs.timer(0.75, babase.Call(self.make_blast_ring, length-1)) + + # a method to remake the flags + def reset_flags(self) -> None: + # remake the flags + self._flag = Flag( + position=(0.0, 3.0, 1.0), touchable=True, color=(0.0, 0.0, 1.0)) + self._flag2 = Flag( + position=(0.0, 3.0, -5.0), touchable=True, color=(1.0, 0.0, 0.0)) + self._flag3 = Flag( + position=(3.0, 3.0, -2.0), touchable=True, color=(0.0, 1.0, 0.0)) + self._flag4 = Flag( + position=(-3.0, 3.0, -2.0), touchable=True, color=(1.0, 1.0, 1.0)) + self._flag5 = Flag( + position=(1.8, 3.0, 0.2), touchable=True, color=(0.0, 1.0, 1.0)) + self._flag6 = Flag( + position=(-1.8, 3.0, 0.2), touchable=True, color=(1.0, 0.0, 1.0)) + self._flag7 = Flag( + position=(1.8, 3.0, -3.8), touchable=True, color=(1.0, 1.0, 0.0)) + self._flag8 = Flag( + position=(-1.8, 3.0, -3.8), touchable=True, color=(0.0, 0.0, 0.0)) + + # a method to kill the flags + def kill_flags(self) -> None: + # destroy all the flags by erasing all references to them, + # indicated by None similar to null + self._flag.node.delete() + self._flag2.node.delete() + self._flag3.node.delete() + self._flag4.node.delete() + self._flag5.node.delete() # 132, 210 ,12 + self._flag6.node.delete() + self._flag7.node.delete() + self._flag8.node.delete() + + def _check_end_game(self) -> None: + for player in self.queue_line: + if not player.dead: + return + self.end_game() + + def spawn_player_spaz( + self, + player: PlayerT, + position: Sequence[float] = (0, 0, 0), + angle: float | None = None, + ) -> PlayerSpaz: + from babase import _math + from bascenev1._gameutils import animate + from bascenev1._coopsession import CoopSession + + angle = None + name = player.getname() + color = player.color + highlight = player.highlight + + light_color = _math.normalized_color(color) + display_color = babase.safecolor(color, target_intensity=0.75) + + spaz = FlagBearer(color=color, + highlight=highlight, + character=player.character, + player=player) + + player.actor = spaz + assert spaz.node + + spaz.node.name = name + spaz.node.name_color = display_color + spaz.connect_controls_to_player() + + # Move to the stand position and add a flash of light. + spaz.handlemessage( + bs.StandMessage( + position, + angle if angle is not None else random.uniform(0, 360))) + self._spawn_sound.play(1, position=spaz.node.position) + light = bs.newnode('light', attrs={'color': light_color}) + spaz.node.connectattr('position', light, 'position') + animate(light, 'intensity', {0: 0, 0.25: 1, 0.5: 0}) + bs.timer(0.5, light.delete) + return spaz + + def handlemessage(self, msg: Any) -> Any: + if isinstance(msg, bs.PlayerDiedMessage): + # give them a nice farewell + if bs.time() < 0.5: + return + if msg.how == 'game': + return + player = msg.getplayer(Player) + bs.broadcastmessage( + diedtxt + str(player.getname()) + diedtxt2, color=player.color) + player.dead = True + if player is self.current_player: + self.round_timer = None + self.give_points_timer = None + if not msg.how is bs.DeathType.FALL: + if self._slow_motion_deaths: + bs.getactivity().globalsnode.slow_motion = True + time = 0.5 + else: + time = 0.01 + # check to see if we can end the game + self._check_end_game() + bs.timer(time, self.setup_next_round) + elif isinstance(msg, FlagPickedUpMessage): + msg.flag.last_player_to_hold = msg.node.getdelegate( + FlagBearer, True + ).getplayer(Player, True) + self._player = msg.node.getdelegate( + FlagBearer, True + ) + self.prize_recipient = msg.node.getdelegate( + FlagBearer, True + ).getplayer(Player, True) + self.kill_flags() + self.give_prize(random.randint(1, 8)) + self._round_sound.play() + self.current_player = self.prize_recipient + elif isinstance(msg, SpazBotDiedMessage): + # find out which team the last person to hold a flag was on + team = self.prize_recipient.team + # give them their points + team.score += self.bad_guy_cost + self._dingsound.play(0.5) + # update the scores + for team in self.teams: + self._scoreboard.set_team_value(team, team.score) + bs.timer(0.3, self.check_bots) + return None + + def _update_scoreboard(self) -> None: + for player in self.queue_line: + if not player.dead: + if player.team.score > 0: + self._dingsound.play() + self._scoreboard.set_team_value(player.team, player.team.score) + + def end_game(self) -> None: + if self.set: + return + self.set = True + results = bs.GameResults() + for team in self.teams: + results.set_team_score(team, team.score) + self.end(results=results) diff --git a/plugins/utilities/bots_can_accept_powerups.py b/plugins/utilities/bots_can_accept_powerups.py index 7c00f67e..ca7d8428 100644 --- a/plugins/utilities/bots_can_accept_powerups.py +++ b/plugins/utilities/bots_can_accept_powerups.py @@ -20,6 +20,7 @@ class BotsCanAcceptPowerupsPlugin(babase.Plugin): def on_app_running(self) -> None: SpazBot.oldinit = SpazBot.__init__ + def __init__(self) -> None: self.oldinit() pam = PowerupBoxFactory.get().powerup_accept_material diff --git a/plugins/utilities/cheat_menu.py b/plugins/utilities/cheat_menu.py index 8648dea7..4e1b0036 100644 --- a/plugins/utilities/cheat_menu.py +++ b/plugins/utilities/cheat_menu.py @@ -49,7 +49,7 @@ "SuperPunch": False, "ImpactOnly": False, "StickyOnly": False, - "IceOnly" : False, + "IceOnly": False, "Infinite Bombs": False, "More Are Coming": False, "Credits": False, @@ -82,7 +82,7 @@ def on_app_running(self) -> None: if babase.app.build_number if build_number < 21282 else babase.app.env.build_number: setconfigs() self.overwrite() - + else: babase.screenmessage(f'{__name__} only works on api 8') @@ -115,7 +115,7 @@ def AllSettingsWindowInit(self, transition: str = 'in_right', origin_widget: bui # on cheat button press call Window def on_cheat_menu_btn_press(self): bui.containerwidget(edit=self._root_widget, - transition='out_scale') + transition='out_scale') bui.app.ui_v1.set_main_menu_window( CheatMenuWindow( transition='in_right').get_root_widget(), from_window=self._root_widget) @@ -161,7 +161,7 @@ def __init__(self, button_type='backSmall', on_activate_call=self._back) bui.containerwidget(edit=self._root_widget, - cancel_button=self._back_button) + cancel_button=self._back_button) # window title, apears in top center of window self._title_text = bui.textwidget( @@ -183,7 +183,7 @@ def __init__(self, self._scroll_height), selection_loops_to_parent=True) bui.widget(edit=self._scrollwidget, - right_widget=self._scrollwidget) + right_widget=self._scrollwidget) # subcontainer represents scroll widget and used as parent self._subcontainer = bui.containerwidget( @@ -222,20 +222,20 @@ def update(self, config: str, change) -> None: try: if change == True and config == "Fly": bui.screenmessage("Some maps may not work good for flying", - color=(1, 0, 0)) + color=(1, 0, 0)) update_config(config, change) bui.getsound('gunCocking').play() except Exception: bui.screenmessage("error", color=(1, 0, 0)) bui.getsound('error').play() - + try: if change == True and config == "SuperPunch": bui.screenmessage("SuperPunch Activated", - color=(1, 0, 0)) + color=(1, 0, 0)) elif change == False and config == "SuperPunch": - bui.screenmessage("Super Punch Deactivated", - color=(0.5,0,0)) + bui.screenmessage("Super Punch Deactivated", + color=(0.5, 0, 0)) update_config(config, change) bui.getsound('gunCocking').play() except Exception: @@ -245,10 +245,10 @@ def update(self, config: str, change) -> None: try: if change == True and config == "IceOnly": bui.screenmessage("Ice Bombs Activated", - color=(0.1, 1, 1)) + color=(0.1, 1, 1)) elif change == False and config == "IceOnly": bui.screenmessage("Ice Bombs Deactivated", - color=(1, 0, 0)) + color=(1, 0, 0)) update_config(config, change) bui.getsound('gunCocking').play() except Exception: @@ -257,23 +257,23 @@ def update(self, config: str, change) -> None: try: if change == True and config == "StickyOnly": bui.screenmessage("Sticky Bombs Activated", - color=(0, 1, 0)) + color=(0, 1, 0)) elif change == False and config == "StickyOnly": bui.screenmessage("Sticky Bombs Deactivated", - color=(1, 0, 0)) + color=(1, 0, 0)) update_config(config, change) bui.getsound('gunCocking').play() except Exception: bui.screenmessage("error", color=(1, 0, 0)) bui.getsound('spazOw').play() - + try: if change == True and config == "ImpactOnly": bui.screenmessage("Impact Bombs Activated", - color=(0.5, 0.5, 0.5)) + color=(0.5, 0.5, 0.5)) elif change == False and config == "ImpactOnly": bui.screenmessage("Impact Bombs Deactivated", - color=(1, 0, 0)) + color=(1, 0, 0)) update_config(config, change) bui.getsound('gunCocking').play() except Exception: @@ -283,17 +283,17 @@ def update(self, config: str, change) -> None: try: if change == True and config == "More Are Coming": bui.screenmessage("Check out https://discord.gg/2RKd9QQdQY For More Mods", - color=(4, 9, 2)) + color=(4, 9, 2)) update_config(config, change) bui.getsound('gunCocking').play() except Exception: bui.screenmessage("error", color=(1, 0, 0)) bui.getsound('cheer').play() - + try: if change == True and config == "Credits": bui.screenmessage("To Pranav Made The Mod and Emily For Ideas, Thx", - color=(4, 9, 2)) + color=(4, 9, 2)) update_config(config, change) bui.getsound('gunCocking').play() except Exception: @@ -304,7 +304,7 @@ def _back(self) -> None: """Kill the window and get back to previous one """ bui.containerwidget(edit=self._root_widget, - transition='out_scale') + transition='out_scale') bui.app.ui_v1.set_main_menu_window( AllSettingsWindow( transition='in_left').get_root_widget(), from_window=self._root_widget) @@ -317,6 +317,7 @@ def ishost(): if player.inputdevice.client_id == -1: return True + def activity_loop(): if bs.get_foreground_host_activity() is not None: activity = bs.get_foreground_host_activity() @@ -337,19 +338,21 @@ def activity_loop(): player.actor._punch_power_scale = 1.2 if config["IceOnly"]: - player.actor.bomb_type = 'ice' + player.actor.bomb_type = 'ice' elif not config["IceOnly"]: - player.actor.bomb_type = 'normal' - player.actor.bomb_count= 1 - + player.actor.bomb_type = 'normal' + player.actor.bomb_count = 1 + if config["ImpactOnly"]: - player.actor.bomb_type = 'impact' - player.actor.bomb_count = 1 - + player.actor.bomb_type = 'impact' + player.actor.bomb_count = 1 + if config["StickyOnly"]: - player.actor.bomb_type = 'sticky' - player.actor.bomb_count = 1 + player.actor.bomb_type = 'sticky' + player.actor.bomb_count = 1 if config["Infinite Bombs"]: - player.actor.bomb_count = 100 -timer = babase.AppTimer(2, activity_loop,repeat=True) \ No newline at end of file + player.actor.bomb_count = 100 + + +timer = babase.AppTimer(2, activity_loop, repeat=True) From a5e88115ab01a3ba8c62a9f31f40cee433ed7339 Mon Sep 17 00:00:00 2001 From: brostosjoined Date: Thu, 1 Feb 2024 10:09:20 +0000 Subject: [PATCH 0846/1464] [ci] apply-version-metadata --- plugins/minigames.json | 98 ++++++++++++++++++++++++++++++++++++------ plugins/utilities.json | 28 ++++++++++-- 2 files changed, 108 insertions(+), 18 deletions(-) diff --git a/plugins/minigames.json b/plugins/minigames.json index db4143e4..ecc1d212 100644 --- a/plugins/minigames.json +++ b/plugins/minigames.json @@ -1131,7 +1131,12 @@ } ], "versions": { - "1.0.0": null + "1.0.0": { + "api_version": 8, + "commit_sha": "4941d0c", + "released_on": "01-02-2024", + "md5sum": "335d7191f26ba21ad10a5755d7741ce0" + } } }, "onslaught_football": { @@ -1145,7 +1150,12 @@ } ], "versions": { - "1.0.0": null + "1.0.0": { + "api_version": 8, + "commit_sha": "4941d0c", + "released_on": "01-02-2024", + "md5sum": "e6267fec4dc7f874b1f8065863aae1cb" + } } }, "lame_fight": { @@ -1159,7 +1169,12 @@ } ], "versions": { - "1.0.0": null + "1.0.0": { + "api_version": 8, + "commit_sha": "4941d0c", + "released_on": "01-02-2024", + "md5sum": "eb0e5a8658e82b3aac6b04b68c1c0f60" + } } }, "infinite_ninjas": { @@ -1173,7 +1188,12 @@ } ], "versions": { - "1.0.0": null + "1.0.0": { + "api_version": 8, + "commit_sha": "4941d0c", + "released_on": "01-02-2024", + "md5sum": "1b6e28bed97bf78430135c64a1fca2c2" + } } }, "gravity_falls": { @@ -1187,7 +1207,12 @@ } ], "versions": { - "1.0.0": null + "1.0.0": { + "api_version": 8, + "commit_sha": "4941d0c", + "released_on": "01-02-2024", + "md5sum": "6d0b06b283ef702f41837f09e457d3b8" + } } }, "bot_chase": { @@ -1201,7 +1226,12 @@ } ], "versions": { - "1.0.0": null + "1.0.0": { + "api_version": 8, + "commit_sha": "4941d0c", + "released_on": "01-02-2024", + "md5sum": "c26e6aee6f545d911106431f3c2d8f0f" + } } }, "down_into_the_abyss": { @@ -1215,7 +1245,12 @@ } ], "versions": { - "1.0.0": null + "1.0.0": { + "api_version": 8, + "commit_sha": "4941d0c", + "released_on": "01-02-2024", + "md5sum": "d3c488671dd35c488e22002ddeb80aef" + } } }, "better_deathmatch": { @@ -1229,7 +1264,12 @@ } ], "versions": { - "1.0.0": null + "1.0.0": { + "api_version": 8, + "commit_sha": "4941d0c", + "released_on": "01-02-2024", + "md5sum": "0b607db2dbe3ab40aa05bd4bfd5b4afa" + } } }, "better_elimination": { @@ -1243,7 +1283,12 @@ } ], "versions": { - "1.0.0": null + "1.0.0": { + "api_version": 8, + "commit_sha": "4941d0c", + "released_on": "01-02-2024", + "md5sum": "18bbb7f6ddc4206c7039ad3b5f5facae" + } } }, "bot_shower": { @@ -1257,7 +1302,12 @@ } ], "versions": { - "1.0.0": null + "1.0.0": { + "api_version": 8, + "commit_sha": "4941d0c", + "released_on": "01-02-2024", + "md5sum": "1259e09ccd9b10ae82e4a6623572a4d2" + } } }, "explodo_run": { @@ -1271,7 +1321,12 @@ } ], "versions": { - "1.0.0": null + "1.0.0": { + "api_version": 8, + "commit_sha": "4941d0c", + "released_on": "01-02-2024", + "md5sum": "af5022d1f78887e0ac2b0cfc37f4f04a" + } } }, "extinction": { @@ -1285,7 +1340,12 @@ } ], "versions": { - "1.0.0": null + "1.0.0": { + "api_version": 8, + "commit_sha": "4941d0c", + "released_on": "01-02-2024", + "md5sum": "daf6c3e3d8663fa6d99c9e3f75033f36" + } } }, "fat_pigs": { @@ -1299,7 +1359,12 @@ } ], "versions": { - "1.0.0": null + "1.0.0": { + "api_version": 8, + "commit_sha": "4941d0c", + "released_on": "01-02-2024", + "md5sum": "fe0d82c322ce01d8956af3131e135ad2" + } } }, "flag_day": { @@ -1313,7 +1378,12 @@ } ], "versions": { - "1.0.0": null + "1.0.0": { + "api_version": 8, + "commit_sha": "4941d0c", + "released_on": "01-02-2024", + "md5sum": "e11fbf742e6556939ac8d986e2dd430b" + } } } } diff --git a/plugins/utilities.json b/plugins/utilities.json index b5f63eb0..6cd3c8af 100644 --- a/plugins/utilities.json +++ b/plugins/utilities.json @@ -1159,7 +1159,12 @@ } ], "versions": { - "1.0.0": null + "1.0.0": { + "api_version": 8, + "commit_sha": "4941d0c", + "released_on": "01-02-2024", + "md5sum": "4b5479f51356b0c9c80c4b9968fea910" + } } }, "xyz_tool": { @@ -1173,7 +1178,12 @@ } ], "versions": { - "1.0.0": null + "1.0.0": { + "api_version": 8, + "commit_sha": "4941d0c", + "released_on": "01-02-2024", + "md5sum": "3f301456128f422b7277c667f6c5c47e" + } } }, "bots_can_accept_powerups": { @@ -1187,7 +1197,12 @@ } ], "versions": { - "1.0.0": null + "1.0.0": { + "api_version": 8, + "commit_sha": "4941d0c", + "released_on": "01-02-2024", + "md5sum": "71eae7c5d0e05821809d348ea0c64837" + } } }, "cheat_menu": { @@ -1201,7 +1216,12 @@ } ], "versions": { - "1.0.0": null + "1.0.0": { + "api_version": 8, + "commit_sha": "4941d0c", + "released_on": "01-02-2024", + "md5sum": "079e857197979aabf53f232b3cce56ba" + } } } } From eb51abd6d425d6e5964103cb85a79e13d07b60b8 Mon Sep 17 00:00:00 2001 From: brostosjoined Date: Thu, 1 Feb 2024 13:10:08 +0300 Subject: [PATCH 0847/1464] ... --- plugins/utilities.json | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/plugins/utilities.json b/plugins/utilities.json index b5f63eb0..12d3190a 100644 --- a/plugins/utilities.json +++ b/plugins/utilities.json @@ -1178,12 +1178,12 @@ }, "bots_can_accept_powerups": { "description": "Bots can steal your powerups", - "external_url": "", + "external_url": "https://youtu.be/Jrk5JfveYEI?si=wYXWVxdC-3XMpuCg", "authors": [ { - "name": "", + "name": "JoseAng3l", "email": "", - "discord": "" + "discord": "joseang3l" } ], "versions": { From a1efdd0e7006ffa5c21482367a6005535e2e2473 Mon Sep 17 00:00:00 2001 From: brostosjoined Date: Thu, 1 Feb 2024 13:12:23 +0300 Subject: [PATCH 0848/1464] ... --- plugins/minigames.json | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/plugins/minigames.json b/plugins/minigames.json index ecc1d212..48048c74 100644 --- a/plugins/minigames.json +++ b/plugins/minigames.json @@ -1093,13 +1093,7 @@ } ], "versions": { - "1.0.0": { - "api_version": 8, - "commit_sha": "718039b", - "released_on": "24-01-2024", - "md5sum": "e1d401ec8f2d06dec741d713d6602710" - } - } + "1.0.0": null }, "you_vs_bombsquad": { "description": "You against bombsquad solo or with friends", From 388e58a577933e36c7e2bdc66fb7ec579ae5ed98 Mon Sep 17 00:00:00 2001 From: brostosjoined Date: Thu, 1 Feb 2024 13:14:44 +0300 Subject: [PATCH 0849/1464] work --- plugins/minigames.json | 1 + 1 file changed, 1 insertion(+) diff --git a/plugins/minigames.json b/plugins/minigames.json index 48048c74..7731067d 100644 --- a/plugins/minigames.json +++ b/plugins/minigames.json @@ -1094,6 +1094,7 @@ ], "versions": { "1.0.0": null + } }, "you_vs_bombsquad": { "description": "You against bombsquad solo or with friends", From 6baf0428283c99873726c26186484f68b19c0f82 Mon Sep 17 00:00:00 2001 From: brostosjoined Date: Thu, 1 Feb 2024 10:15:25 +0000 Subject: [PATCH 0850/1464] [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 7731067d..9b90f8d3 100644 --- a/plugins/minigames.json +++ b/plugins/minigames.json @@ -1093,7 +1093,12 @@ } ], "versions": { - "1.0.0": null + "1.0.0": { + "api_version": 8, + "commit_sha": "388e58a", + "released_on": "01-02-2024", + "md5sum": "8fc1f9c984f9e77b0125cbeaba5c13bf" + } } }, "you_vs_bombsquad": { From 157a956e0c620f8576e642bbe4b2384838dc2604 Mon Sep 17 00:00:00 2001 From: brostosjoined Date: Thu, 1 Feb 2024 13:16:46 +0300 Subject: [PATCH 0851/1464] ... --- .vscode/settings.json | 5 ----- 1 file changed, 5 deletions(-) delete mode 100644 .vscode/settings.json diff --git a/.vscode/settings.json b/.vscode/settings.json deleted file mode 100644 index b242572e..00000000 --- a/.vscode/settings.json +++ /dev/null @@ -1,5 +0,0 @@ -{ - "githubPullRequests.ignoredPullRequestBranches": [ - "main" - ] -} \ No newline at end of file From 9ec7242e93ab99592a92d539796bd81b1aedd073 Mon Sep 17 00:00:00 2001 From: brostosjoined Date: Thu, 1 Feb 2024 20:46:32 +0300 Subject: [PATCH 0852/1464] \n --- plugins/minigames.json | 27 ++++++--------------------- plugins/minigames/explodo_run.py | 10 +++++++++- 2 files changed, 15 insertions(+), 22 deletions(-) diff --git a/plugins/minigames.json b/plugins/minigames.json index 9b90f8d3..5b958225 100644 --- a/plugins/minigames.json +++ b/plugins/minigames.json @@ -1311,7 +1311,7 @@ } }, "explodo_run": { - "description": "Run For Your Life :))", + "description": "Cursed meteor shower of crazy Captain Jack trying take your soul", "external_url": "", "authors": [ { @@ -1321,12 +1321,7 @@ } ], "versions": { - "1.0.0": { - "api_version": 8, - "commit_sha": "4941d0c", - "released_on": "01-02-2024", - "md5sum": "af5022d1f78887e0ac2b0cfc37f4f04a" - } + "1.0.0": null } }, "extinction": { @@ -1349,7 +1344,7 @@ } }, "fat_pigs": { - "description": "Survive...", + "description": "Eliminate other Mels' while dodging falling stickies.", "external_url": "", "authors": [ { @@ -1359,16 +1354,11 @@ } ], "versions": { - "1.0.0": { - "api_version": 8, - "commit_sha": "4941d0c", - "released_on": "01-02-2024", - "md5sum": "fe0d82c322ce01d8956af3131e135ad2" - } + "1.0.0": null } }, "flag_day": { - "description": "Pick up flags to receive a prize.\nBut beware...", + "description": "Pick up flags to receive a prize.But beware...", "external_url": "https://youtu.be/ANDzdBicjA4?si=h8S_TPUAxSaG7nls", "authors": [ { @@ -1378,12 +1368,7 @@ } ], "versions": { - "1.0.0": { - "api_version": 8, - "commit_sha": "4941d0c", - "released_on": "01-02-2024", - "md5sum": "e11fbf742e6556939ac8d986e2dd430b" - } + "1.0.0": null } } } diff --git a/plugins/minigames/explodo_run.py b/plugins/minigames/explodo_run.py index cac6a65f..f11cb343 100644 --- a/plugins/minigames/explodo_run.py +++ b/plugins/minigames/explodo_run.py @@ -51,8 +51,15 @@ class ExplodoRunGame(bs.TeamGameActivity[Player, Team]): scoreconfig = bs.ScoreConfig(label='Time', scoretype=bs.ScoreType.MILLISECONDS, lower_is_better=False) - default_music = bs.MusicType.TO_THE_DEATH + @classmethod + def get_preview_texture_name(cls) -> str: + return 'rampagePreview' + + @classmethod + def get_supported_maps(cls, sessiontype: type[bs.Session]) -> list[str]: + return ['Rampage'] + def __init__(self, settings: dict): settings['map'] = "Rampage" self._epic_mode = settings.get('Epic Mode', False) @@ -64,6 +71,7 @@ def __init__(self, settings: dict): self._won = False self._bots = SpazBotSet() self.wave = 1 + self.default_music = bs.MusicType.TO_THE_DEATH def on_begin(self) -> None: super().on_begin() From ec6286e84226e6905b4a7877ecd5ffaeed4c2296 Mon Sep 17 00:00:00 2001 From: brostosjoined Date: Thu, 1 Feb 2024 17:47:30 +0000 Subject: [PATCH 0853/1464] [ci] auto-format --- plugins/minigames/explodo_run.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/plugins/minigames/explodo_run.py b/plugins/minigames/explodo_run.py index f11cb343..b6bd60d9 100644 --- a/plugins/minigames/explodo_run.py +++ b/plugins/minigames/explodo_run.py @@ -55,11 +55,11 @@ class ExplodoRunGame(bs.TeamGameActivity[Player, Team]): @classmethod def get_preview_texture_name(cls) -> str: return 'rampagePreview' - + @classmethod def get_supported_maps(cls, sessiontype: type[bs.Session]) -> list[str]: return ['Rampage'] - + def __init__(self, settings: dict): settings['map'] = "Rampage" self._epic_mode = settings.get('Epic Mode', False) From becfccc107d4fe8ca29443f960549f7d5abfb657 Mon Sep 17 00:00:00 2001 From: brostosjoined Date: Thu, 1 Feb 2024 17:47:31 +0000 Subject: [PATCH 0854/1464] [ci] apply-version-metadata --- plugins/minigames.json | 21 ++++++++++++++++++--- 1 file changed, 18 insertions(+), 3 deletions(-) diff --git a/plugins/minigames.json b/plugins/minigames.json index 5b958225..f55df6f3 100644 --- a/plugins/minigames.json +++ b/plugins/minigames.json @@ -1321,7 +1321,12 @@ } ], "versions": { - "1.0.0": null + "1.0.0": { + "api_version": 8, + "commit_sha": "ec6286e", + "released_on": "01-02-2024", + "md5sum": "e3cd927316b9c3bcac714b4dc8d0d73c" + } } }, "extinction": { @@ -1354,7 +1359,12 @@ } ], "versions": { - "1.0.0": null + "1.0.0": { + "api_version": 8, + "commit_sha": "ec6286e", + "released_on": "01-02-2024", + "md5sum": "fe0d82c322ce01d8956af3131e135ad2" + } } }, "flag_day": { @@ -1368,7 +1378,12 @@ } ], "versions": { - "1.0.0": null + "1.0.0": { + "api_version": 8, + "commit_sha": "ec6286e", + "released_on": "01-02-2024", + "md5sum": "e11fbf742e6556939ac8d986e2dd430b" + } } } } From 6e7940753caca603767ed553a03381e30c6ea800 Mon Sep 17 00:00:00 2001 From: brostosjoined Date: Sat, 3 Feb 2024 23:33:52 +0300 Subject: [PATCH 0855/1464] Used IDK cause there is a modder named unkown --- plugins/minigames.json | 76 +++++++++------------------- plugins/minigames/avalanche.py | 4 +- plugins/minigames/bot_chase.py | 6 +-- plugins/minigames/extinction.py | 4 +- plugins/minigames/infection.py | 4 +- plugins/minigames/infinite_ninjas.py | 6 +-- plugins/utilities.json | 13 ++--- 7 files changed, 39 insertions(+), 74 deletions(-) diff --git a/plugins/minigames.json b/plugins/minigames.json index 5b958225..6e747918 100644 --- a/plugins/minigames.json +++ b/plugins/minigames.json @@ -254,7 +254,7 @@ { "name": "Rikko", "email": "rikkolovescats@proton.me", - "discord": "Rikko#7383" + "discord": "rikkolovescats" } ], "versions": { @@ -360,7 +360,7 @@ { "name": "TheMikirog", "email": "", - "discord": "TheMikirog#1984" + "discord": "themikirog" } ], "versions": { @@ -601,7 +601,7 @@ { "name": "TheMikirog", "email": "", - "discord": "TheMikirog#1984" + "discord": "themikirog" }, { "name": "JoseAng3l", @@ -911,12 +911,7 @@ } ], "versions": { - "1.0.0": { - "api_version": 8, - "commit_sha": "47a1ca8", - "released_on": "22-08-2023", - "md5sum": "398cf911195c4904b281ed05767e25f4" - } + "1.0.0": null } }, "super_duel": { @@ -979,16 +974,11 @@ } ], "versions": { - "1.0.0": { - "api_version": 8, - "commit_sha": "718039b", - "released_on": "24-01-2024", - "md5sum": "c1c96450fbdb6e5b2f0d26bb4e797236" - } + "1.0.0": null } }, "hyper_race": { - "description": "Race and avoid the obsatacles", + "description": "Race and avoid the obstacles", "external_url": "", "authors": [ { @@ -998,12 +988,7 @@ } ], "versions": { - "1.0.0": { - "api_version": 8, - "commit_sha": "718039b", - "released_on": "24-01-2024", - "md5sum": "8b423bdae256bd411489528b550b8bd9" - } + "1.0.0": null } }, "meteor_shower_deluxe": { @@ -1144,7 +1129,7 @@ "external_url": "", "authors": [ { - "name": "", + "name": "IDK", "email": "", "discord": "" } @@ -1163,9 +1148,9 @@ "external_url": "", "authors": [ { - "name": "", + "name": "Blitz", "email": "", - "discord": "" + "discord": "itsmeblitz" } ], "versions": { @@ -1182,18 +1167,13 @@ "external_url": "", "authors": [ { - "name": "", + "name": "IDK", "email": "", "discord": "" } ], "versions": { - "1.0.0": { - "api_version": 8, - "commit_sha": "4941d0c", - "released_on": "01-02-2024", - "md5sum": "1b6e28bed97bf78430135c64a1fca2c2" - } + "1.0.0": null } }, "gravity_falls": { @@ -1201,7 +1181,7 @@ "external_url": "", "authors": [ { - "name": "", + "name": "IDK", "email": "", "discord": "" } @@ -1220,18 +1200,13 @@ "external_url": "", "authors": [ { - "name": "", + "name": "! JETZ", "email": "", - "discord": "" + "discord": "! JETZ#5313" } ], "versions": { - "1.0.0": { - "api_version": 8, - "commit_sha": "4941d0c", - "released_on": "01-02-2024", - "md5sum": "c26e6aee6f545d911106431f3c2d8f0f" - } + "1.0.0": null } }, "down_into_the_abyss": { @@ -1239,7 +1214,7 @@ "external_url": "", "authors": [ { - "name": "", + "name": "IDK", "email": "", "discord": "" } @@ -1296,9 +1271,9 @@ "external_url": "", "authors": [ { - "name": "", + "name": "! JETZ", "email": "", - "discord": "" + "discord": "! JETZ#5313" } ], "versions": { @@ -1315,9 +1290,9 @@ "external_url": "", "authors": [ { - "name": "", + "name": "Blitz", "email": "", - "discord": "" + "discord": "itsmeblitz" } ], "versions": { @@ -1329,18 +1304,13 @@ "external_url": "", "authors": [ { - "name": "", + "name": "IDK", "email": "", "discord": "" } ], "versions": { - "1.0.0": { - "api_version": 8, - "commit_sha": "4941d0c", - "released_on": "01-02-2024", - "md5sum": "daf6c3e3d8663fa6d99c9e3f75033f36" - } + "1.0.0": null } }, "fat_pigs": { diff --git a/plugins/minigames/avalanche.py b/plugins/minigames/avalanche.py index 1e362080..43eed2fb 100644 --- a/plugins/minigames/avalanche.py +++ b/plugins/minigames/avalanche.py @@ -26,12 +26,12 @@ def ba_get_api_version(): - return 6 + return 8 def ba_get_levels(): return [ - babase._level.Level( + bs._level.Level( "Icy Emits", gametype=IcyEmitsGame, settings={}, diff --git a/plugins/minigames/bot_chase.py b/plugins/minigames/bot_chase.py index 6495ee46..deab742f 100644 --- a/plugins/minigames/bot_chase.py +++ b/plugins/minigames/bot_chase.py @@ -16,11 +16,11 @@ from typing import Any, List, Type, Optional -# def ba_get_api_version(): -# return 6 +def ba_get_api_version(): + return 8 def ba_get_levels(): - return [babase._level.Level( + return [bs._level.Level( 'Bot Chase', gametype=BotChaseGame, settings={}, preview_texture_name='footballStadiumPreview')] diff --git a/plugins/minigames/extinction.py b/plugins/minigames/extinction.py index 22ca2fcd..436a6313 100644 --- a/plugins/minigames/extinction.py +++ b/plugins/minigames/extinction.py @@ -23,12 +23,12 @@ def ba_get_api_version(): def ba_get_levels(): - return [babase._level.Level( + return [bs._level.Level( 'Extinction', gametype=NewMeteorShowerGame, settings={'Epic Mode': False}, preview_texture_name='footballStadiumPreview'), - babase._level.Level( + bs._level.Level( 'Epic Extinction', gametype=NewMeteorShowerGame, settings={'Epic Mode': True}, diff --git a/plugins/minigames/infection.py b/plugins/minigames/infection.py index a509ec89..b46b1e23 100644 --- a/plugins/minigames/infection.py +++ b/plugins/minigames/infection.py @@ -55,11 +55,11 @@ def ba_get_api_version(): - return 6 + return 8 def ba_get_levels(): - return [babase._level.Level( + return [bs._level.Level( name, gametype=Infection, settings={}, diff --git a/plugins/minigames/infinite_ninjas.py b/plugins/minigames/infinite_ninjas.py index de2784f6..6ff1b0a2 100644 --- a/plugins/minigames/infinite_ninjas.py +++ b/plugins/minigames/infinite_ninjas.py @@ -22,15 +22,15 @@ def ba_get_api_version(): - return 6 + return 8 def ba_get_levels(): - return [babase._level.Level( + return [bs._level.Level( 'Infinite Ninjas', gametype=InfiniteNinjasGame, settings={}, preview_texture_name='footballStadiumPreview'), - babase._level.Level( + bs._level.Level( 'Epic Infinite Ninjas', gametype=InfiniteNinjasGame, settings={'Epic Mode': True}, preview_texture_name='footballStadiumPreview')] diff --git a/plugins/utilities.json b/plugins/utilities.json index 16a9ecfe..c586f677 100644 --- a/plugins/utilities.json +++ b/plugins/utilities.json @@ -1115,7 +1115,7 @@ "external_url": "", "authors": [ { - "name": "", + "name": "IDK", "email": "", "discord": "" } @@ -1172,18 +1172,13 @@ "external_url": "", "authors": [ { - "name": "", + "name": "Yann", "email": "", - "discord": "" + "discord": "riyukiiyan" } ], "versions": { - "1.0.0": { - "api_version": 8, - "commit_sha": "4941d0c", - "released_on": "01-02-2024", - "md5sum": "3f301456128f422b7277c667f6c5c47e" - } + "1.0.0": null } }, "bots_can_accept_powerups": { From 50636908520eb71bdb4e485bb6de7b13e77c8b25 Mon Sep 17 00:00:00 2001 From: brostosjoined Date: Sat, 3 Feb 2024 20:35:33 +0000 Subject: [PATCH 0856/1464] [ci] auto-format --- plugins/minigames/bot_chase.py | 1 + 1 file changed, 1 insertion(+) diff --git a/plugins/minigames/bot_chase.py b/plugins/minigames/bot_chase.py index deab742f..7ef9e80d 100644 --- a/plugins/minigames/bot_chase.py +++ b/plugins/minigames/bot_chase.py @@ -19,6 +19,7 @@ def ba_get_api_version(): return 8 + def ba_get_levels(): return [bs._level.Level( 'Bot Chase', gametype=BotChaseGame, From 3277f85f3b609e860a4489897cfbfac955d67636 Mon Sep 17 00:00:00 2001 From: brostosjoined Date: Sat, 3 Feb 2024 20:35:34 +0000 Subject: [PATCH 0857/1464] [ci] apply-version-metadata --- plugins/minigames.json | 42 ++++++++++++++++++++++++++++++++++++------ plugins/utilities.json | 7 ++++++- 2 files changed, 42 insertions(+), 7 deletions(-) diff --git a/plugins/minigames.json b/plugins/minigames.json index 73e2c237..30ac1d3d 100644 --- a/plugins/minigames.json +++ b/plugins/minigames.json @@ -911,7 +911,12 @@ } ], "versions": { - "1.0.0": null + "1.0.0": { + "api_version": 8, + "commit_sha": "5063690", + "released_on": "03-02-2024", + "md5sum": "4a9cdcd798454e5034a5ea9ce58fe586" + } } }, "super_duel": { @@ -974,7 +979,12 @@ } ], "versions": { - "1.0.0": null + "1.0.0": { + "api_version": 8, + "commit_sha": "5063690", + "released_on": "03-02-2024", + "md5sum": "a07a171c29417056bb69ed1cf0f2864b" + } } }, "hyper_race": { @@ -988,7 +998,12 @@ } ], "versions": { - "1.0.0": null + "1.0.0": { + "api_version": 8, + "commit_sha": "5063690", + "released_on": "03-02-2024", + "md5sum": "8b423bdae256bd411489528b550b8bd9" + } } }, "meteor_shower_deluxe": { @@ -1173,7 +1188,12 @@ } ], "versions": { - "1.0.0": null + "1.0.0": { + "api_version": 8, + "commit_sha": "5063690", + "released_on": "03-02-2024", + "md5sum": "15e303e02e3da4636fd002c43a579180" + } } }, "gravity_falls": { @@ -1206,7 +1226,12 @@ } ], "versions": { - "1.0.0": null + "1.0.0": { + "api_version": 8, + "commit_sha": "5063690", + "released_on": "03-02-2024", + "md5sum": "b0519f41146eb2f8b9c2d6c747376a9b" + } } }, "down_into_the_abyss": { @@ -1315,7 +1340,12 @@ } ], "versions": { - "1.0.0": null + "1.0.0": { + "api_version": 8, + "commit_sha": "5063690", + "released_on": "03-02-2024", + "md5sum": "9fb61df79a50d010864964a7cb1de76e" + } } }, "fat_pigs": { diff --git a/plugins/utilities.json b/plugins/utilities.json index c586f677..7ed32f9d 100644 --- a/plugins/utilities.json +++ b/plugins/utilities.json @@ -1178,7 +1178,12 @@ } ], "versions": { - "1.0.0": null + "1.0.0": { + "api_version": 8, + "commit_sha": "5063690", + "released_on": "03-02-2024", + "md5sum": "3f301456128f422b7277c667f6c5c47e" + } } }, "bots_can_accept_powerups": { From 4d454d6e28ccdd56aeab2c3821673ac688035ca5 Mon Sep 17 00:00:00 2001 From: brostosjoined Date: Sun, 4 Feb 2024 10:59:44 +0300 Subject: [PATCH 0858/1464] =?UTF-8?q?=F0=9F=98=94?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- plugins/minigames.json | 19 - plugins/minigames/ba_dark_fields.py | 296 -------- plugins/utilities.json | 19 - plugins/utilities/ba_colours.py | 1063 --------------------------- 4 files changed, 1397 deletions(-) delete mode 100644 plugins/minigames/ba_dark_fields.py delete mode 100644 plugins/utilities/ba_colours.py diff --git a/plugins/minigames.json b/plugins/minigames.json index 73e2c237..ff0e3fb4 100644 --- a/plugins/minigames.json +++ b/plugins/minigames.json @@ -1105,25 +1105,6 @@ } } }, - "ba_dark_fields": { - "description": "Get to the other side and watch your step", - "external_url": "", - "authors": [ - { - "name": "Froshlee24", - "email": "", - "discord": "froshlee24" - } - ], - "versions": { - "1.0.0": { - "api_version": 8, - "commit_sha": "4941d0c", - "released_on": "01-02-2024", - "md5sum": "335d7191f26ba21ad10a5755d7741ce0" - } - } - }, "onslaught_football": { "description": "Onslaught but in football map", "external_url": "", diff --git a/plugins/minigames/ba_dark_fields.py b/plugins/minigames/ba_dark_fields.py deleted file mode 100644 index 03302eea..00000000 --- a/plugins/minigames/ba_dark_fields.py +++ /dev/null @@ -1,296 +0,0 @@ -# Ported to api 8 by brostos using baport.(https://github.com/bombsquad-community/baport) -"""Dark fields mini-game.""" - -# Minigame by Froshlee24 -# ba_meta require api 8 -# (see https://ballistica.net/wiki/meta-tag-system) - -from __future__ import annotations -import random -from typing import TYPE_CHECKING - -import _babase -import babase -import bauiv1 as bui -import bascenev1 as bs -from bascenev1lib.actor import bomb -from bascenev1._music import setmusic -from bascenev1lib.actor.scoreboard import Scoreboard -from bascenev1._gameutils import animate_array -from bascenev1lib.gameutils import SharedObjects -from bascenev1lib.actor.playerspaz import PlayerSpaz - -if TYPE_CHECKING: - from typing import Any, Sequence, Optional, List, Dict, Type, Type - - -class Player(bs.Player['Team']): - """Our player type for this game.""" - - -class Team(bs.Team[Player]): - """Our team type for this game.""" - - def __init__(self) -> None: - self.score = 0 - -# ba_meta export bascenev1.GameActivity - - -class DarkFieldsGame(bs.TeamGameActivity[Player, Team]): - - name = 'Dark Fields' - description = 'Get to the other side.' - available_settings = [ - bs.IntSetting('Score to Win', - min_value=1, - default=3, - ), - bs.IntChoiceSetting('Time Limit', - choices=[ - ('None', 0), - ('1 Minute', 60), - ('2 Minutes', 120), - ('5 Minutes', 300), - ('10 Minutes', 600), - ('20 Minutes', 1200), - ], - default=0, - ), - bs.FloatChoiceSetting('Respawn Times', - choices=[ - ('Shorter', 0.25), - ('Short', 0.5), - ('Normal', 1.0), - ('Long', 2.0), - ('Longer', 4.0), - ], - default=1.0, - ), - bs.BoolSetting('Epic Mode', default=False), - bs.BoolSetting('Players as center of interest', default=True), - ] - - @classmethod - def get_supported_maps(cls, sessiontype: Type[bs.Session]) -> List[str]: - return bs.app.classic.getmaps('football') - - @classmethod - def supports_session_type(cls, sessiontype: Type[bs.Session]) -> bool: - return (issubclass(sessiontype, bs.DualTeamSession) - or issubclass(sessiontype, bs.FreeForAllSession)) - - def __init__(self, settings: dict): - super().__init__(settings) - self._epic_mode = bool(settings['Epic Mode']) - self._center_of_interest = bool(settings['Players as center of interest']) - self._score_to_win_per_player = int(settings['Score to Win']) - self._time_limit = float(settings['Time Limit']) - - self._scoreboard = Scoreboard() - - shared = SharedObjects.get() - - self._scoreRegionMaterial = bs.Material() - self._scoreRegionMaterial.add_actions( - conditions=("they_have_material", shared.player_material), - actions=(("modify_part_collision", "collide", True), - ("modify_part_collision", "physical", False), - ("call", "at_connect", self._onPlayerScores))) - - self.slow_motion = self._epic_mode - self.default_music = (bs.MusicType.EPIC if self._epic_mode else None) - - def on_transition_in(self) -> None: - super().on_transition_in() - gnode = bs.getactivity().globalsnode - gnode.tint = (0.5, 0.5, 0.5) - - a = bs.newnode('locator', attrs={'shape': 'box', 'position': (12.2, 0, .1087926362), - 'color': (5, 0, 0), 'opacity': 1, 'draw_beauty': True, 'additive': False, 'size': [2.5, 0.1, 12.8]}) - - b = bs.newnode('locator', attrs={'shape': 'box', 'position': (-12.1, 0, .1087926362), - 'color': (0, 0, 5), 'opacity': 1, 'draw_beauty': True, 'additive': False, 'size': [2.5, 0.1, 12.8]}) - - def on_begin(self) -> None: - # self._has_begun = False - super().on_begin() - - self.setup_standard_time_limit(self._time_limit) - self._score_to_win = (self._score_to_win_per_player * - max(1, max(len(t.players) for t in self.teams))) - self._update_scoreboard() - - self.isUpdatingMines = False - self._scoreSound = bs.getsound('dingSmall') - - for p in self.players: - if p.actor is not None: - try: - p.actor.disconnect_controls_from_player() - except Exception: - print('Can\'t connect to player') - - self._scoreRegions = [] - defs = bs.getactivity().map.defs - self._scoreRegions.append(bs.NodeActor(bs.newnode('region', - attrs={'position': defs.boxes['goal1'][0:3], - 'scale': defs.boxes['goal1'][6:9], - 'type': 'box', - 'materials': (self._scoreRegionMaterial,)}))) - self.mines = [] - self.spawnMines() - bs.timer(0.8 if self.slow_motion else 1.7, self.start) - - def start(self): - # self._has_begun = True - self._show_info() - bs.timer(random.randrange(3, 7), self.doRandomLighting) - if not self._epic_mode: - setmusic(bs.MusicType.SCARY) - animate_array(bs.getactivity().globalsnode, 'tint', 3, - {0: (0.5, 0.5, 0.5), 2: (0.2, 0.2, 0.2)}) - - for p in self.players: - self.doPlayer(p) - - def spawn_player(self, player): - if not self.has_begun(): - return - else: - self.doPlayer(player) - - def doPlayer(self, player): - pos = (-12.4, 1, random.randrange(-5, 5)) - player = self.spawn_player_spaz(player, pos) - player.connect_controls_to_player(enable_punch=False, enable_bomb=False) - player.node.is_area_of_interest = self._center_of_interest - - def _show_info(self) -> None: - if self.has_begun(): - super()._show_info() - - def on_team_join(self, team: Team) -> None: - if self.has_begun(): - self._update_scoreboard() - - def _update_scoreboard(self) -> None: - for team in self.teams: - self._scoreboard.set_team_value(team, team.score, self._score_to_win) - - def doRandomLighting(self): - bs.timer(random.randrange(3, 7), self.doRandomLighting) - if self.isUpdatingMines: - return - - delay = 0 - for mine in self.mines: - if mine.node.exists(): - pos = mine.node.position - bs.timer(delay, babase.Call(self.do_light, pos)) - delay += 0.005 if self._epic_mode else 0.01 - - def do_light(self, pos): - light = bs.newnode('light', attrs={ - 'position': pos, - 'volume_intensity_scale': 1.0, - 'radius': 0.1, - 'color': (1, 0, 0) - }) - bs.animate(light, 'intensity', {0: 2.0, 3.0: 0.0}) - bs.timer(3.0, light.delete) - - def spawnMines(self): - delay = 0 - h_range = [10, 8, 6, 4, 2, 0, -2, -4, -6, -8, -10] - for h in h_range: - for i in range(random.randint(3, 4)): - x = h+random.random() - y = random.randrange(-5, 6)+(random.random()) - pos = (x, 1, y) - bs.timer(delay, babase.Call(self.doMine, pos)) - delay += 0.015 if self._epic_mode else 0.04 - bs.timer(5.0, self.stopUpdateMines) - - def stopUpdateMines(self): - self.isUpdatingMines = False - - def updateMines(self): - if self.isUpdatingMines: - return - self.isUpdatingMines = True - for m in self.mines: - m.node.delete() - self.mines = [] - self.spawnMines() - - def doMine(self, pos): - b = bomb.Bomb(position=pos, bomb_type='land_mine').autoretain() - b.add_explode_callback(self._on_bomb_exploded) - b.arm() - self.mines.append(b) - - def _on_bomb_exploded(self, bomb: Bomb, blast: Blast) -> None: - assert blast.node - p = blast.node.position - pos = (p[0], p[1]+1, p[2]) - bs.timer(0.5, babase.Call(self.doMine, pos)) - - def _onPlayerScores(self): - player: Optional[Player] - try: - spaz = bs.getcollision().opposingnode.getdelegate(PlayerSpaz, True) - except bs.NotFoundError: - return - - if not spaz.is_alive(): - return - - try: - player = spaz.getplayer(Player, True) - except bs.NotFoundError: - return - - if player.exists() and player.is_alive(): - player.team.score += 1 - self._scoreSound.play() - pos = player.actor.node.position - - animate_array(bs.getactivity().globalsnode, 'tint', 3, { - 0: (0.5, 0.5, 0.5), 2.8: (0.2, 0.2, 0.2)}) - self._update_scoreboard() - - light = bs.newnode('light', - attrs={ - 'position': pos, - 'radius': 0.5, - 'color': (1, 0, 0) - }) - bs.animate(light, 'intensity', {0.0: 0, 0.1: 1, 0.5: 0}, loop=False) - bs.timer(1.0, light.delete) - - player.actor.handlemessage(bs.DieMessage(how=bs.DeathType.REACHED_GOAL)) - self.updateMines() - - if any(team.score >= self._score_to_win for team in self.teams): - bs.timer(0.5, self.end_game) - - def handlemessage(self, msg: Any) -> Any: - - if isinstance(msg, bs.PlayerDiedMessage): - - # Augment standard behavior. - super().handlemessage(msg) - - player = msg.getplayer(Player) - self.respawn_player(player) - - else: - return super().handlemessage(msg) - return None - - def end_game(self) -> None: - results = bs.GameResults() - for team in self.teams: - results.set_team_score(team, team.score) - self.end(results=results) diff --git a/plugins/utilities.json b/plugins/utilities.json index c586f677..fc48240f 100644 --- a/plugins/utilities.json +++ b/plugins/utilities.json @@ -1148,25 +1148,6 @@ } } }, - "ba_colours": { - "description": "Colourful bots and more", - "external_url": "", - "authors": [ - { - "name": "Froshlee", - "email": "", - "discord": "froshlee24" - } - ], - "versions": { - "1.0.0": { - "api_version": 8, - "commit_sha": "4941d0c", - "released_on": "01-02-2024", - "md5sum": "4b5479f51356b0c9c80c4b9968fea910" - } - } - }, "xyz_tool": { "description": "Punch to save the co-ordinates", "external_url": "", diff --git a/plugins/utilities/ba_colours.py b/plugins/utilities/ba_colours.py deleted file mode 100644 index e5225293..00000000 --- a/plugins/utilities/ba_colours.py +++ /dev/null @@ -1,1063 +0,0 @@ -# Ported to api 8 by brostos using baport.(https://github.com/bombsquad-community/baport) -"""Colors Mod.""" -# Mod by Froshlee14 -# ba_meta require api 8 - -from __future__ import annotations -from typing import TYPE_CHECKING - -import _babase -import babase -import bauiv1 as bui -import bascenev1 as bs - -if TYPE_CHECKING: - pass - -from bascenev1lib.actor.spazfactory import SpazFactory -from bascenev1lib.actor.scoreboard import Scoreboard -from bascenev1lib.game.elimination import EliminationGame, Icon, Player, Team -from bascenev1lib.gameutils import SharedObjects - -from bascenev1 import get_player_colors, get_player_profile_colors, get_player_profile_icon -from bauiv1lib.popup import PopupWindow -from bascenev1lib.actor import bomb, spaz -from bauiv1lib import tabs, confirm, mainmenu, popup -from bauiv1lib.colorpicker import ColorPicker -from bauiv1lib.mainmenu import MainMenuWindow -from bauiv1lib.profile.browser import * -from bascenev1lib.actor.playerspaz import * -from bascenev1lib.actor.flag import * -from bascenev1lib.actor.spazbot import * -from bascenev1lib.actor.spazfactory import SpazFactory -# from bascenev1lib.mainmenu import MainMenuActivity -import random - - -def getData(data): - return babase.app.config["colorsMod"][data] - - -def getRandomColor(): - c = random.choice(getData("colors")) - return c - - -def doColorMenu(self): - bui.containerwidget(edit=self._root_widget, transition='out_left') - openWindow() - - -def updateButton(self): - color = (random.random(), random.random(), random.random()) - try: - bui.buttonwidget(edit=self._colorsModButton, color=color) - except Exception: - self._timer = None - - -newConfig = {"colorPlayer": True, - "higlightPlayer": False, - "namePlayer": False, - "glowColor": False, - "glowHighlight": False, - "glowName": False, - "actab": 1, - "shieldColor": False, - "xplotionColor": True, - "delScorch": True, - "colorBots": False, - "glowBots": False, - "flag": True, - # "test":True, - "glowScale": 1, - "timeDelay": 500, - "activeProfiles": ['__account__'], - "colors": [color for color in get_player_colors()], - } - - -def getDefaultSettings(): - return newConfig - - -def getTranslation(text): - actLan = bs.app.lang.language - colorsModsLan = { - "title": { - "Spanish": 'Colors Mod', - "English": 'Colors Mod' - }, - "player_tab": { - "Spanish": 'Ajustes de Jugador', - "English": 'Player settings' - }, - "extras_tab": { - "Spanish": 'Ajustes Adicionales', - "English": 'Adittional settings' - }, - "general_tab": { - "Spanish": 'Ajustes Generales', - "English": 'General settings' - }, - "info_tab": { - "Spanish": 'Creditos', - "English": 'Credits' - }, - "profiles": { - "Spanish": 'Perfiles', - "English": 'Profiles' - }, - "palette": { - "Spanish": 'Paleta de Colores', - "English": 'Pallete' - }, - "change": { - "Spanish": 'Cambiar', - "English": 'Change' - }, - "glow": { - "Spanish": 'Brillar', - "English": 'Glow' - }, - "glow_scale": { - "Spanish": 'Escala de Brillo', - "English": 'Glow Scale' - }, - "time_delay": { - "Spanish": 'Intervalo de Tiempo', - "English": 'Time Delay' - }, - "reset_values": { - "Spanish": 'Reiniciar Valores', - "English": 'Reset Values' - }, - "players": { - "Spanish": 'Jugadores', - "English": 'Players' - }, - "apply_to_color": { - "Spanish": 'Color Principal', - "English": 'Main Color' - }, - "apply_to_highlight": { - "Spanish": 'Color de Resalte', - "English": 'Highlight Color' - }, - "apply_to_name": { - "Spanish": 'Color del Nombre', - "English": 'Name Color' - }, - "additional_features": { - "Spanish": 'Ajustes Adicionales', - "English": 'Additional Features' - }, - "apply_to_bots": { - "Spanish": 'Color Principal de Bots', - "English": 'Bots Main Color' - }, - "apply_to_shields": { - "Spanish": 'Escudos de Colores', - "English": 'Apply to Shields' - }, - "apply_to_explotions": { - "Spanish": 'Explosiones de Colores', - "English": 'Apply to Explotions' - }, - "apply_to_flags": { - "Spanish": 'Banderas de Colores', - "English": 'Apply to Flags' - }, - "pick_color": { - "Spanish": 'Selecciona un Color', - "English": 'Pick a Color' - }, - "add_color": { - "Spanish": 'Agregar Color', - "English": 'Add Color' - }, - "remove_color": { - "Spanish": 'Quitar Color', - "English": 'Remove Color' - }, - "clean_explotions": { - "Spanish": 'Limpiar Explosiones', - "English": 'Remove Scorch' - }, - "restore_default_settings": { - "Spanish": 'Restaurar Ajustes Por Defecto', - "English": 'Restore Default Settings' - }, - "settings_restored": { - "Spanish": 'Ajustes Restaurados', - "English": 'Settings Restored' - }, - "restore_settings": { - "Spanish": '¿Restaurar Ajustes Por Defecto?', - "English": 'Restore Default Settings?' - }, - "nothing_selected": { - "Spanish": 'Nada Seleccionado', - "English": 'Nothing Selected' - }, - "color_already": { - "Spanish": 'Este Color Ya Existe En La Paleta', - "English": 'Color Already In The Palette' - }, - "tap_color": { - "Spanish": 'Toca un color para quitarlo.', - "English": 'Tap to remove a color.' - }, - } - lans = ["Spanish", "English"] - if actLan not in lans: - actLan = "English" - return colorsModsLan[text][actLan] - - -# ba_meta export plugin -class ColorsMod(babase.Plugin): - - # PLUGINS PLUS COMPATIBILITY - version = "1.7.2" - logo = 'gameCenterIcon' - logo_color = (1, 1, 1) - plugin_type = 'mod' - - def has_settings_ui(self): - return True - - def show_settings_ui(self, button): - ColorsMenu() - - if bs.app.lang.language == "Spanish": - information = ("Modifica y aplica efectos\n" - "a los colores de tu personaje,\n" - "explosiones, bots, escudos,\n" - "entre otras cosas...\n\n" - "Programado por Froshlee14\nTraducido por CerdoGordo\n\n" - "ADVERTENCIA\nEste mod puede ocacionar\n" - "efectos de epilepsia\na personas sensibles.") - else: - information = ("Modify and add effects\n" - "to your character colours.\n" - "And other stuff...\n\n" - "Coded by Froshlee14\nTranslated by CerdoGordo\n\n" - "WARNING\nThis mod can cause epileptic\n" - "seizures especially\nwith sensitive people") - - def on_app_running(self) -> None: - - if "colorsMod" in babase.app.config: - oldConfig = babase.app.config["colorsMod"] - for setting in newConfig: - if setting not in oldConfig: - babase.app.config["colorsMod"].update({setting: newConfig[setting]}) - bs.broadcastmessage(('Colors Mod: config updated'), color=(1, 1, 0)) - - removeList = [] - for setting in oldConfig: - if setting not in newConfig: - removeList.append(setting) - for element in removeList: - babase.app.config["colorsMod"].pop(element) - bs.broadcastmessage(('Colors Mod: old config deleted'), color=(1, 1, 0)) - else: - babase.app.config["colorsMod"] = newConfig - babase.app.config.apply_and_commit() - - # MainMenuActivity.oldMakeWord = MainMenuActivity._make_word - # def newMakeWord(self, word: str, - # x: float, - # y: float, - # scale: float = 1.0, - # delay: float = 0.0, - # vr_depth_offset: float = 0.0, - # shadow: bool = False): - # self.oldMakeWord(word,x,y,scale,delay,vr_depth_offset,shadow) - # word = self._word_actors[-1] - # if word.node.getnodetype(): - # if word.node.color[3] == 1.0: - # word.node.color = getRandomColor() - # MainMenuActivity._make_word = newMakeWord - - #### GAME MODIFICATIONS #### - - # ESCUDO DE COLORES - - def new_equip_shields(self, decay: bool = False) -> None: - if not self.node: - babase.print_error('Can\'t equip shields; no node.') - return - - factory = SpazFactory.get() - if self.shield is None: - self.shield = bs.newnode('shield', owner=self.node, attrs={ - 'color': (0.3, 0.2, 2.0), 'radius': 1.3}) - self.node.connectattr('position_center', self.shield, 'position') - self.shield_hitpoints = self.shield_hitpoints_max = 650 - self.shield_decay_rate = factory.shield_decay_rate if decay else 0 - self.shield.hurt = 0 - factory.shield_up_sound.play(1.0, position=self.node.position) - - if self.shield_decay_rate > 0: - self.shield_decay_timer = bs.Timer(0.5, bs.WeakCall(self.shield_decay), repeat=True) - self.shield.always_show_health_bar = True - - def changeColor(): - if self.shield is None: - return - if getData("shieldColor"): - self.shield.color = c = getRandomColor() - self._shieldTimer = bs.Timer(getData("timeDelay") / 1000, changeColor, repeat=True) - PlayerSpaz.equip_shields = new_equip_shields - - # BOTS DE COLORES - SpazBot.oldBotInit = SpazBot.__init__ - - def newBotInit(self, *args, **kwargs): - self.oldBotInit(*args, **kwargs) - s = 1 - if getData("glowBots"): - s = getData("glowScale") - - self.node.highlight = (self.node.highlight[0]*s, - self.node.highlight[1]*s, self.node.highlight[2]*s) - - def changeColor(): - if self.is_alive(): - if getData("colorBots"): - c = getRandomColor() - self.node.highlight = (c[0]*s, c[1]*s, c[2]*s) - self._timer = bs.Timer(getData("timeDelay") / 1000, changeColor, repeat=True) - SpazBot.__init__ = newBotInit - - # BANDERA DE COLORES - Flag.oldFlagInit = Flag.__init__ - - def newFlaginit(self, position: Sequence[float] = (0.0, 1.0, 0.0), - color: Sequence[float] = (1.0, 1.0, 1.0), - materials: Sequence[bs.Material] = None, - touchable: bool = True, - dropped_timeout: int = None): - self.oldFlagInit(position, color, materials, touchable, dropped_timeout) - - def cC(): - if self.node.exists(): - if getData("flag"): - c = getRandomColor() - self.node.color = (c[0]*1.2, c[1]*1.2, c[2]*1.2) - else: - return - if touchable: - self._timer = bs.Timer(getData("timeDelay") / 1000, cC, repeat=True) - - Flag.__init__ = newFlaginit - - # JUGADORES DE COLORES - PlayerSpaz.oldInit = PlayerSpaz.__init__ - - def newInit(self, player: bs.Player, - color: Sequence[float] = (1.0, 1.0, 1.0), - highlight: Sequence[float] = (0.5, 0.5, 0.5), - character: str = 'Spaz', - powerups_expire: bool = True): - self.oldInit(player, color, highlight, character, powerups_expire) - - players = [] - for p in getData("activeProfiles"): - players.append(p) - - for x in range(len(players)): - if players[x] == "__account__": - players[x] = bui.app.plus.get_v1_account_name() # _babase.get_v1_account_name() - - if player.getname() in players: - s = s2 = s3 = 1 - if getData("glowColor"): - s = getData("glowScale") - if getData("glowHighlight"): - s2 = getData("glowScale") - if getData("glowName"): - s3 = getData("glowScale") - - self.node.color = (self.node.color[0]*s, self.node.color[1]*s, self.node.color[2]*s) - self.node.highlight = ( - self.node.highlight[0]*s2, self.node.highlight[1]*s2, self.node.highlight[2]*s2) - self.node.name_color = ( - self.node.name_color[0]*s3, self.node.name_color[1]*s3, self.node.name_color[2]*s3) - - def changeColor(): - if self.is_alive(): - if getData("colorPlayer"): - c = getRandomColor() - self.node.color = (c[0]*s, c[1]*s, c[2]*s) - if getData("higlightPlayer"): - c = getRandomColor() - self.node.highlight = (c[0]*s2, c[1]*s2, c[2]*s2) - if getData("namePlayer"): - c = getRandomColor() - self.node.name_color = (c[0]*s3, c[1]*s3, c[2]*s3) - self._timer = bs.Timer(getData("timeDelay") / 1000, changeColor, repeat=True) - PlayerSpaz.__init__ = newInit - - # EXPLOSIONES DE COLORES - bomb.Blast.oldBlastInit = bomb.Blast.__init__ - - def newBlastInit(self, position: Sequence[float] = (0.0, 1.0, 0.0), velocity: Sequence[float] = (0.0, 0.0, 0.0), - blast_radius: float = 2.0, blast_type: str = 'normal', source_player: bs.Player = None, - hit_type: str = 'explosion', hit_subtype: str = 'normal'): - - self.oldBlastInit(position, velocity, blast_radius, blast_type, - source_player, hit_type, hit_subtype) - - if getData("xplotionColor"): - c = getRandomColor() - - scl = random.uniform(0.6, 0.9) - scorch_radius = light_radius = self.radius - if self.blast_type == 'tnt': - light_radius *= 1.4 - scorch_radius *= 1.15 - scl *= 3.0 - - for i in range(2): - scorch = bs.newnode('scorch', attrs={ - 'position': self.node.position, 'size': scorch_radius*0.5, 'big': (self.blast_type == 'tnt')}) - if self.blast_type == 'ice': - scorch.color = (1, 1, 1.5) - else: - scorch.color = c - if getData("xplotionColor"): - if getData("delScorch"): - bs.animate(scorch, "presence", {3: 1, 13: 0}) - bs.Timer(13, scorch.delete) - - if self.blast_type == 'ice': - return - light = bs.newnode('light', attrs={'position': position, - 'volume_intensity_scale': 10.0, 'color': c}) - - iscale = 1.6 - bs.animate(light, 'intensity', { - 0: 2.0 * iscale, - scl * 0.02: 0.1 * iscale, - scl * 0.025: 0.2 * iscale, - scl * 0.05: 17.0 * iscale, - scl * 0.06: 5.0 * iscale, - scl * 0.08: 4.0 * iscale, - scl * 0.2: 0.6 * iscale, - scl * 2.0: 0.00 * iscale, - scl * 3.0: 0.0}) - bs.animate(light, 'radius', { - 0: light_radius * 0.2, - scl * 0.05: light_radius * 0.55, - scl * 0.1: light_radius * 0.3, - scl * 0.3: light_radius * 0.15, - scl * 1.0: light_radius * 0.05}) - bs.timer(scl * 3.0, light.delete) - bomb.Blast.__init__ = newBlastInit - - -class ProfilesWindow(popup.PopupWindow): - """Popup window to view achievements.""" - - def __init__(self): - uiscale = bui.app.ui_v1.uiscale - scale = (1.8 if uiscale is babase.UIScale.SMALL else - 1.65 if uiscale is babase.UIScale.MEDIUM else 1.23) - self._transitioning_out = False - self._width = 300 - self._height = (300 if uiscale is babase.UIScale.SMALL else 350) - bg_color = (0.5, 0.4, 0.6) - - self._selected = None - self._activeProfiles = getData("activeProfiles") - - self._profiles = babase.app.config.get('Player Profiles', {}) - assert self._profiles is not None - items = list(self._profiles.items()) - items.sort(key=lambda x: x[0].lower()) - - accountName: Optional[str] - if bui.app.plus.get_v1_account_state() == 'signed_in': - accountName = bui.app.plus.get_v1_account_display_string() - else: - accountName = None - # subHeight += (len(items)*45) - - # creates our _root_widget - popup.PopupWindow.__init__(self, - position=(0, 0), - size=(self._width, self._height), - scale=scale, - bg_color=bg_color) - - self._cancel_button = bui.buttonwidget(parent=self.root_widget, - position=(50, self._height - 30), size=(50, 50), - scale=0.5, label='', - color=bg_color, - on_activate_call=self._on_cancel_press, - autoselect=True, - icon=bui.gettexture('crossOut'), - iconscale=1.2) - bui.containerwidget(edit=self.root_widget, cancel_button=self._cancel_button) - - self._title_text = bui.textwidget(parent=self.root_widget, - position=(self._width * 0.5, self._height - 20), - size=(0, 0), - h_align='center', - v_align='center', - scale=01.0, - text=getTranslation('profiles'), - maxwidth=200, - color=(1, 1, 1, 0.4)) - - self._scrollwidget = bui.scrollwidget(parent=self.root_widget, - size=(self._width - 60, - self._height - 70), - position=(30, 30), - capture_arrows=True, - simple_culling_v=10) - bui.widget(edit=self._scrollwidget, autoselect=True) - - # incr = 36 - sub_width = self._width - 90 - sub_height = (len(items)*50) - - eq_rsrc = 'coopSelectWindow.powerRankingPointsEqualsText' - pts_rsrc = 'coopSelectWindow.powerRankingPointsText' - - self._subcontainer = box = bui.containerwidget(parent=self._scrollwidget, - size=(sub_width, sub_height), - background=False) - h = 20 - v = sub_height - 60 - for pName, p in items: - if pName == '__account__' and accountName is None: - continue - color, highlight = get_player_profile_colors(pName) - tval = (accountName if pName == '__account__' else - get_player_profile_icon(pName) + pName) - assert isinstance(tval, str) - # print(tval) - value = True if pName in self._activeProfiles else False - - w = bui.checkboxwidget(parent=box, position=(10, v), value=value, - on_value_change_call=bs.WeakCall(self.select, pName), - maxwidth=sub_width, size=(sub_width, 50), - textcolor=color, - text=babase.Lstr(value=tval), autoselect=True) - v -= 45 - - def addProfile(self): - if self._selected is not None: - if self._selected not in self._activeProfiles: - self._activeProfiles.append(self._selected) - babase.app.config["colorsMod"]["activeProfiles"] = self._activeProfiles - babase.app.config.apply_and_commit() - else: - bs.broadcastmessage(getTranslation('nothing_selected')) - - def removeProfile(self): - if self._selected is not None: - if self._selected in self._activeProfiles: - self._activeProfiles.remove(self._selected) - babase.app.config["colorsMod"]["activeProfiles"] = self._activeProfiles - babase.app.config.apply_and_commit() - else: - print('not found') - else: - bs.broadcastmessage(getTranslation('nothing_selected')) - - def select(self, name, m): - self._selected = name - if m == 0: - self.removeProfile() - else: - self.addProfile() - - def _on_cancel_press(self) -> None: - self._transition_out() - - def _transition_out(self) -> None: - if not self._transitioning_out: - self._transitioning_out = True - bui.containerwidget(edit=self.root_widget, transition='out_scale') - - def on_popup_cancel(self) -> None: - bui.getsound('swish').play() - self._transition_out() - - -class ColorsMenu(PopupWindow): - - def __init__(self, transition='in_right'): - # self._width = width = 650 - self._width = width = 800 - self._height = height = 450 - - self._scrollWidth = self._width*0.85 - self._scrollHeight = self._height - 120 - self._subWidth = self._scrollWidth*0.95 - self._subHeight = 200 - - self._current_tab = getData('actab') - self._timeDelay = getData("timeDelay") - self._glowScale = getData("glowScale") - - self.midwidth = self._scrollWidth*0.45 - self.qwidth = self.midwidth*0.4 - - app = bui.app.ui_v1 - uiscale = app.uiscale - - from bascenev1lib.mainmenu import MainMenuSession - self._in_game = not isinstance(bs.get_foreground_host_session(), - MainMenuSession) - - self._root_widget = bui.containerwidget(size=(width, height), transition=transition, - scale=1.5 if uiscale is babase.UIScale.SMALL else 1.0, - stack_offset=(0, -5) if uiscale is babase.UIScale.SMALL else (0, 0)) - - self._title = bui.textwidget(parent=self._root_widget, position=(50, height-40), text='', - maxwidth=self._scrollWidth, size=(self._scrollWidth, 20), - color=(0.8, 0.8, 0.8, 1.0), h_align="center", scale=1.1) - - self._backButton = b = bui.buttonwidget(parent=self._root_widget, autoselect=True, - position=(50, height-60), size=(120, 50), - scale=0.8, text_scale=1.2, label=babase.Lstr(resource='backText'), - button_type='back', on_activate_call=self._back) - bui.buttonwidget(edit=self._backButton, button_type='backSmall', size=( - 50, 50), label=babase.charstr(babase.SpecialChar.BACK)) - bui.containerwidget(edit=self._root_widget, cancel_button=b) - - self._nextButton = bui.buttonwidget(parent=self._root_widget, autoselect=True, - position=(width-60, height*0.5-20), size=(50, 50), - scale=1.0, label=babase.charstr(babase.SpecialChar.RIGHT_ARROW), - color=(0.2, 1, 0.2), button_type='square', - on_activate_call=self.nextTabContainer) - - self._prevButton = bui.buttonwidget(parent=self._root_widget, autoselect=True, - position=(10, height*0.5-20), size=(50, 50), - scale=1.0, label=babase.charstr(babase.SpecialChar.LEFT_ARROW), - color=(0.2, 1, 0.2), button_type='square', - on_activate_call=self.prevTabContainer) - - v = self._subHeight - 55 - v0 = height - 90 - - self.tabs = [ - [0, getTranslation('general_tab')], - [1, getTranslation('player_tab')], - [2, getTranslation('extras_tab')], - [3, getTranslation('info_tab')], - ] - - self._scrollwidget = sc = bui.scrollwidget(parent=self._root_widget, size=( - self._subWidth, self._scrollHeight), border_opacity=0.3, highlight=False, position=((width*0.5)-(self._scrollWidth*0.47), 50), capture_arrows=True,) - - bui.widget(edit=sc, left_widget=self._prevButton) - bui.widget(edit=sc, right_widget=self._nextButton) - bui.widget(edit=self._backButton, down_widget=sc) - - self.tabButtons = [] - h = 330 - for i in range(3): - tabButton = bui.buttonwidget(parent=self._root_widget, autoselect=True, - position=(h, 20), size=(20, 20), - scale=1.2, label='', - color=(0.3, 0.9, 0.3), - on_activate_call=babase.Call( - self._setTab, self.tabs[i][0]), - texture=bui.gettexture('nub')) - self.tabButtons.append(tabButton) - h += 50 - self._tabContainer = None - self._setTab(self._current_tab) - - def nextTabContainer(self): - tab = babase.app.config['colorsMod']['actab'] - if tab == 2: - self._setTab(0) - else: - self._setTab(tab+1) - - def prevTabContainer(self): - tab = babase.app.config['colorsMod']['actab'] - if tab == 0: - self._setTab(2) - else: - self._setTab(tab-1) - - def _setTab(self, tab): - - self._colorTimer = None - self._current_tab = tab - - babase.app.config['colorsMod']['actab'] = tab - babase.app.config.apply_and_commit() - - if self._tabContainer is not None and self._tabContainer.exists(): - self._tabContainer.delete() - self._tabData = {} - - if tab == 0: # general - subHeight = 0 - - self._tabContainer = c = bui.containerwidget(parent=self._scrollwidget, size=(self._subWidth, subHeight), - background=False, selection_loops_to_parent=True) - - bui.textwidget(edit=self._title, text=getTranslation('general_tab')) - v0 = subHeight - 30 - v = v0 - 10 - - h = self._scrollWidth*0.12 - cSpacing = self._scrollWidth*0.15 - t = bui.textwidget(parent=c, position=(0, v), - text=getTranslation('glow_scale'), - maxwidth=self.midwidth, size=(self.midwidth, 20), color=(0.8, 0.8, 0.8, 1.0), h_align="center") - v -= 45 - b = bui.buttonwidget(parent=c, position=(h-20, v-12), size=(40, 40), label="-", - autoselect=True, on_activate_call=babase.Call(self._glowScaleDecrement), repeat=True, enable_sound=True, button_type='square') - - self._glowScaleText = bui.textwidget(parent=c, position=(h+20, v), maxwidth=cSpacing, - size=(cSpacing, 20), editable=False, color=(0.3, 1.0, 0.3), h_align="center", text=str(self._glowScale)) - - b2 = bui.buttonwidget(parent=c, position=(h+cSpacing+20, v-12), size=(40, 40), label="+", - autoselect=True, on_activate_call=babase.Call(self._glowScaleIncrement), repeat=True, enable_sound=True, button_type='square') - - v -= 70 - t = bui.textwidget(parent=c, position=(0, v), - text=getTranslation('time_delay'), - maxwidth=self.midwidth, size=(self.midwidth, 20), color=(0.8, 0.8, 0.8, 1.0), h_align="center") - v -= 45 - a = bui.buttonwidget(parent=c, position=(h-20, v-12), size=(40, 40), label="-", - autoselect=True, on_activate_call=babase.Call(self._timeDelayDecrement), repeat=True, enable_sound=True, button_type='square') - - self._timeDelayText = bui.textwidget(parent=c, position=(h+20, v), maxwidth=self._scrollWidth*0.9, - size=(cSpacing, 20), editable=False, color=(0.3, 1.0, 0.3, 1.0), h_align="center", text=str(self._timeDelay)) - - a2 = bui.buttonwidget(parent=c, position=(h+cSpacing+20, v-12), size=(40, 40), label="+", - autoselect=True, on_activate_call=babase.Call(self._timeDelayIncrement), repeat=True, enable_sound=True, button_type='square') - - v -= 70 - reset = bui.buttonwidget(parent=c, autoselect=True, - position=((self._scrollWidth*0.22)-80, v-25), size=(160, 50), scale=1.0, text_scale=1.2, textcolor=(1, 1, 1), - label=getTranslation('reset_values'), on_activate_call=self._resetValues) - self._updateColorTimer() - - v = v0 - h = self._scrollWidth*0.44 - - t = bui.textwidget(parent=c, position=(h, v), - text=getTranslation('palette'), - maxwidth=self.midwidth, size=(self.midwidth, 20), - color=(0.8, 0.8, 0.8, 1.0), h_align="center") - v -= 30 - t2 = bui.textwidget(parent=c, position=(h, v), - text=getTranslation('tap_color'), scale=0.9, - maxwidth=self.midwidth, size=(self.midwidth, 20), - color=(0.6, 0.6, 0.6, 1.0), h_align="center") - v -= 20 - sp = h+45 - self.updatePalette(v, sp) - - elif tab == 1: - subHeight = self._subHeight - - self._tabContainer = c = bui.containerwidget(parent=self._scrollwidget, size=(self._subWidth, subHeight), - background=False, selection_loops_to_parent=True) - v2 = v = v0 = subHeight - bui.textwidget(edit=self._title, text=getTranslation('player_tab')) - - t = babase.app.classic.spaz_appearances['Spaz'] - tex = bui.gettexture(t.icon_texture) - tintTex = bui.gettexture(t.icon_mask_texture) - gs = getData("glowScale") - tc = (1, 1, 1) - t2c = (1, 1, 1) - - v2 -= (50+180) - self._previewImage = bui.imagewidget(parent=c, position=(self._subWidth*0.72-100, v2), size=(200, 200), - mask_texture=bui.gettexture('characterIconMask'), tint_texture=tintTex, - texture=tex, mesh_transparent=bui.getmesh( - 'image1x1'), - tint_color=(tc[0]*gs, tc[1]*gs, tc[2]*gs), tint2_color=(t2c[0]*gs, t2c[1]*gs, t2c[2]*gs)) - - self._colorTimer = bui.AppTimer(getData("timeDelay") / 1000, - babase.Call(self._updatePreview), repeat=True) - v2 -= 70 - - def doProfileWindow(): - ProfilesWindow() - - reset = bui.buttonwidget(parent=c, autoselect=True, on_activate_call=doProfileWindow, - position=(self._subWidth*0.72-100, v2), size=(200, 60), scale=1.0, text_scale=1.2, textcolor=(1, 1, 1), - label=getTranslation('profiles')) - miniBoxWidth = self.midwidth - 30 - miniBoxHeight = 80 - - v -= 18 - # Color - h = 50 - box1 = bui.containerwidget(parent=c, position=(h, v-miniBoxHeight), - size=(miniBoxWidth, miniBoxHeight), background=True) - vbox1 = miniBoxHeight - 25 - t = bui.textwidget(parent=box1, position=(10, vbox1), - text=getTranslation('apply_to_color'), - maxwidth=miniBoxWidth-20, size=(miniBoxWidth, 20), color=(0.8, 0.8, 0.8, 1.0), h_align="left") - vbox1 -= 45 - self.bw = bui.checkboxwidget(parent=box1, position=(10, vbox1), value=getData("colorPlayer"), - on_value_change_call=babase.Call(self._setSetting, 'colorPlayer'), maxwidth=self.qwidth, - text=getTranslation('change'), autoselect=True, size=(self.qwidth, 25)) - # vbox1 -= 35 - self.bw = bui.checkboxwidget(parent=box1, position=(25+self.qwidth, vbox1), value=getData("glowColor"), - on_value_change_call=babase.Call(self._setSetting, 'glowColor'), maxwidth=self.qwidth, - text=getTranslation('glow'), autoselect=True, size=(self.qwidth, 25)) - v -= (miniBoxHeight+20) - - # Highlight - box1 = bui.containerwidget(parent=c, position=(h, v-miniBoxHeight), - size=(miniBoxWidth, miniBoxHeight), background=True) - vbox1 = miniBoxHeight - 20 - t = bui.textwidget(parent=box1, position=(10, vbox1), - text=getTranslation('apply_to_highlight'), - maxwidth=miniBoxWidth-20, size=(miniBoxWidth, 20), color=(0.8, 0.8, 0.8, 1.0), h_align="left") - vbox1 -= 45 - self.bw = bui.checkboxwidget(parent=box1, position=(10, vbox1), value=getData("higlightPlayer"), - on_value_change_call=babase.Call(self._setSetting, 'higlightPlayer'), maxwidth=self.qwidth, - text=getTranslation('change'), autoselect=True, size=(self.qwidth, 25)) - # vbox1 -= 35 - self.bw = bui.checkboxwidget(parent=box1, position=(25+self.qwidth, vbox1), value=getData("glowHighlight"), - on_value_change_call=babase.Call(self._setSetting, 'glowHighlight'), maxwidth=self.qwidth, - text=getTranslation('glow'), autoselect=True, size=(self.qwidth, 25)) - v -= (miniBoxHeight+20) - # Name - box1 = bui.containerwidget(parent=c, position=(h, v-miniBoxHeight), - size=(miniBoxWidth, miniBoxHeight), background=True) - vbox1 = miniBoxHeight - 20 - t = bui.textwidget(parent=box1, position=(10, vbox1), - text=getTranslation('apply_to_name'), - maxwidth=miniBoxWidth-20, size=(miniBoxWidth, 20), color=(0.8, 0.8, 0.8, 1.0), h_align="left") - vbox1 -= 40 - self.bw = bui.checkboxwidget(parent=box1, position=(10, vbox1), value=getData("namePlayer"), - on_value_change_call=babase.Call(self._setSetting, 'namePlayer'), maxwidth=self.qwidth, - text=getTranslation('change'), autoselect=True, size=(self.qwidth, 25)) - # vbox1 -= 35 - self.bw = bui.checkboxwidget(parent=box1, position=(25+self.qwidth, vbox1), value=getData("glowName"), - on_value_change_call=babase.Call(self._setSetting, 'glowName'), maxwidth=self.qwidth, - text=getTranslation('glow'), autoselect=True, size=(self.qwidth, 25)) - v -= (miniBoxHeight+50) - - elif tab == 2: - subHeight = 0 - self._tabContainer = c = bui.containerwidget(parent=self._scrollwidget, size=(self._subWidth, subHeight), - background=False, selection_loops_to_parent=True) - v0 = subHeight - 50 - - v = v0 - h = 30 - bui.textwidget(edit=self._title, text=getTranslation('extras_tab')) - self.bw = bui.checkboxwidget(parent=c, position=(h, v), value=getData("shieldColor"), - on_value_change_call=babase.Call(self._setSetting, 'shieldColor'), maxwidth=self.midwidth, - text=getTranslation('apply_to_shields'), autoselect=True, size=(self.midwidth, 30)) - v -= 50 - self.bw = bui.checkboxwidget(parent=c, position=(h, v), value=getData("flag"), - on_value_change_call=babase.Call(self._setSetting, 'flag'), maxwidth=self.midwidth, - text=getTranslation('apply_to_flags'), autoselect=True, size=(self.midwidth, 30)) - v = v0 - h = self.midwidth - self.bw = bui.checkboxwidget(parent=c, position=(h, v), value=getData("xplotionColor"), - on_value_change_call=babase.Call(self._setSetting, 'xplotionColor'), maxwidth=self.midwidth, - text=getTranslation('apply_to_explotions'), autoselect=True, size=(self.midwidth, 30)) - v -= 50 - self.bw = bui.checkboxwidget(parent=c, position=(h, v), value=getData("delScorch"), - on_value_change_call=babase.Call(self._setSetting, 'delScorch'), maxwidth=self.midwidth, - text=getTranslation('clean_explotions'), autoselect=True, size=(self.midwidth, 30)) - v -= 35 - miniBoxWidth = self.midwidth - miniBoxHeight = 80 - - # Bots Color - box1 = bui.containerwidget(parent=c, position=((self._scrollWidth*0.45) - (miniBoxWidth/2), v-miniBoxHeight), - size=(miniBoxWidth, miniBoxHeight), background=True) - vbox1 = miniBoxHeight - 20 - t = bui.textwidget(parent=box1, position=(10, vbox1), - text=getTranslation('apply_to_bots'), - maxwidth=miniBoxWidth-20, size=(miniBoxWidth, 20), color=(0.8, 0.8, 0.8, 1.0), h_align="left") - vbox1 -= 45 - self.bw = bui.checkboxwidget(parent=box1, position=(10, vbox1), value=getData("colorBots"), - on_value_change_call=babase.Call(self._setSetting, 'colorBots'), maxwidth=self.qwidth, - text=getTranslation('change'), autoselect=True, size=(self.qwidth, 25)) - - self.bw = bui.checkboxwidget(parent=box1, position=(30+self.qwidth, vbox1), value=getData("glowBots"), - on_value_change_call=babase.Call(self._setSetting, 'glowBots'), maxwidth=self.qwidth, - text=getTranslation('glow'), autoselect=True, size=(self.qwidth, 25)) - - v -= 130 - reset = bui.buttonwidget(parent=c, autoselect=True, on_activate_call=self.restoreSettings, - position=((self._scrollWidth*0.45)-150, v-25), size=(300, 50), scale=1.0, text_scale=1.2, textcolor=(1, 1, 1), - label=getTranslation('restore_default_settings')) - - for bttn in self.tabButtons: - bui.buttonwidget(edit=bttn, color=(0.1, 0.5, 0.1)) - bui.buttonwidget(edit=self.tabButtons[tab], color=(0.1, 1, 0.1)) - - def _setSetting(self, setting, m): - babase.app.config["colorsMod"][setting] = False if m == 0 else True - babase.app.config.apply_and_commit() - - def _timeDelayDecrement(self): - self._timeDelay = max(50, self._timeDelay - 50) - bui.textwidget(edit=self._timeDelayText, text=str(self._timeDelay)) - babase.app.config["colorsMod"]["timeDelay"] = self._timeDelay - babase.app.config.apply_and_commit() - self._updateColorTimer() - - def _timeDelayIncrement(self): - self._timeDelay = self._timeDelay + 50 - bui.textwidget(edit=self._timeDelayText, text=str(self._timeDelay)) - babase.app.config["colorsMod"]["timeDelay"] = self._timeDelay - babase.app.config.apply_and_commit() - self._updateColorTimer() - - def _resetValues(self): - babase.app.config["colorsMod"]["glowScale"] = self._glowScale = 1 - babase.app.config["colorsMod"]["timeDelay"] = self._timeDelay = 500 - bui.textwidget(edit=self._glowScaleText, text=str(self._glowScale)) - bui.textwidget(edit=self._timeDelayText, text=str(self._timeDelay)) - babase.app.config.apply_and_commit() - self._updateColorTimer() - - def updatePalette(self, h, sp): - colours = getData("colors") - x = sp - y = h - 50 - cont = 1 - bttnSize = (45, 45) - l = len(colours) - - for i in range(16): - if i < l: - w = bui.buttonwidget( - parent=self._tabContainer, position=(x, y), size=bttnSize, - autoselect=False, label="", button_type="square", color=colours[i], - on_activate_call=bs.WeakCall(self.removeColor, colours[i])) - else: - w = bui.buttonwidget( - parent=self._tabContainer, position=( - x, y), size=bttnSize, color=(0.5, 0.4, 0.6), - autoselect=False, label="", texture=bui.gettexture('frameInset')) - if i == l: - bui.buttonwidget(edit=w, on_activate_call=bs.WeakCall( - self._makePicker, w), label="+") - if cont % 4 == 0: - x = sp - y -= ((bttnSize[0]) + 10) - else: - x += (bttnSize[0]) + 13 - cont += 1 - - def addColor(self, color): - if not self.colorIn(color): - babase.app.config["colorsMod"]["colors"].append(color) - babase.app.config.apply_and_commit() - self._setTab(0) - else: - bs.broadcastmessage(getTranslation('color_already')) - - def removeColor(self, color): - if color is not None: - if len(getData("colors")) >= 3: - if color in getData("colors"): - babase.app.config["colorsMod"]["colors"].remove(color) - babase.app.config.apply_and_commit() - self._setTab(0) - else: - print('not found') - else: - bs.broadcastmessage("Min. 2 colors", color=(0, 1, 0)) - else: - bs.broadcastmessage(getTranslation('nothing_selected')) - - def _makePicker(self, origin): - baseScale = 2.05 if babase.UIScale.SMALL else 1.6 if babase.UIScale.MEDIUM else 1.0 - initial_color = (0, 0.8, 0) - ColorPicker(parent=self._tabContainer, position=origin.get_screen_space_center(), - offset=(baseScale * (-100), 0), initial_color=initial_color, delegate=self, tag='color') - - def color_picker_closing(self, picker): - if not self._root_widget.exists(): - return - tag = picker.get_tag() - - def color_picker_selected_color(self, picker, color): - self.addColor(color) - - def colorIn(self, c): - sColors = getData("colors") - for sC in sColors: - if c[0] == sC[0] and c[1] == sC[1] and c[2] == sC[2]: - return True - return False - - def setColor(self, c): - self._selected = c - bui.buttonwidget(edit=self._moveOut, color=(0.8, 0, 0)) - - def _updateColorTimer(self): - self._colorTimer = bui.AppTimer(getData("timeDelay") / 1000, self._update, repeat=True) - - def _update(self): - color = (random.random(), random.random(), random.random()) - bui.textwidget(edit=self._timeDelayText, color=color) - - def _updatePreview(self): - gs = gs2 = getData("glowScale") - if not getData("glowColor"): - gs = 1 - if not getData("glowHighlight"): - gs2 = 1 - - c = (1, 1, 1) - if getData("colorPlayer"): - c = getRandomColor() - - c2 = (1, 1, 1) - if getData("higlightPlayer"): - c2 = getRandomColor() - - bui.imagewidget(edit=self._previewImage, tint_color=(c[0]*gs, c[1]*gs, c[2]*gs)) - bui.imagewidget(edit=self._previewImage, tint2_color=(c2[0]*gs2, c2[1]*gs2, c2[2]*gs2)) - - def _glowScaleDecrement(self): - self._glowScale = max(1, self._glowScale - 1) - bui.textwidget(edit=self._glowScaleText, text=str(self._glowScale)) - babase.app.config["colorsMod"]["glowScale"] = self._glowScale - babase.app.config.apply_and_commit() - - def _glowScaleIncrement(self): - self._glowScale = min(5, self._glowScale + 1) - bui.textwidget(edit=self._glowScaleText, text=str(self._glowScale)) - babase.app.config["colorsMod"]["glowScale"] = self._glowScale - babase.app.config.apply_and_commit() - - def restoreSettings(self): - def doIt(): - babase.app.config["colorsMod"] = getDefaultSettings() - babase.app.config.apply_and_commit() - self._setTab(2) - bs.broadcastmessage(getTranslation('settings_restored')) - confirm.ConfirmWindow(getTranslation('restore_settings'), - width=400, height=120, action=doIt, ok_text=babase.Lstr(resource='okText')) - - def _back(self): - bui.containerwidget(edit=self._root_widget, transition='out_right') - self._colorTimer = None - self._colorPreviewTimer = None - # if self._in_game: - # babase.app.main_menu_window = (mainmenu.MainMenuWindow(transition='in_left').get_root_widget()) - # else: - # babase.app.main_menu_window = ProfileBrowserWindow(transition='in_left').get_root_widget() - # babase.app.main_menu_window = (mainmenu.MainMenuWindow(transition='in_left').get_root_widget()) From f8b3cee591e3b2425dd94a6b798f35439d830c3d Mon Sep 17 00:00:00 2001 From: brostosjoined Date: Sun, 4 Feb 2024 11:47:47 +0300 Subject: [PATCH 0859/1464] Safe zone out --- plugins/minigames.json | 19 - plugins/minigames/safe_zone.py | 737 --------------------------------- 2 files changed, 756 deletions(-) delete mode 100644 plugins/minigames/safe_zone.py diff --git a/plugins/minigames.json b/plugins/minigames.json index f101bb18..11e9e23c 100644 --- a/plugins/minigames.json +++ b/plugins/minigames.json @@ -1044,25 +1044,6 @@ } } }, - "safe_zone": { - "description": "Stay in the safe zone", - "external_url": "", - "authors": [ - { - "name": "SEBASTIAN2059", - "email": "", - "discord": "sebastian2059" - } - ], - "versions": { - "1.0.0": { - "api_version": 8, - "commit_sha": "718039b", - "released_on": "24-01-2024", - "md5sum": "862fab0c26947c70397542742fb82635" - } - } - }, "snow_ball_fight": { "description": "Throw snoballs and dominate", "external_url": "https://youtu.be/uXyb_meBjGI?si=D_N_OXZT5BFh8R5C", diff --git a/plugins/minigames/safe_zone.py b/plugins/minigames/safe_zone.py deleted file mode 100644 index 56808770..00000000 --- a/plugins/minigames/safe_zone.py +++ /dev/null @@ -1,737 +0,0 @@ -# Porting to api 8 made easier by baport.(https://github.com/bombsquad-community/baport) -# Released under the MIT License. See LICENSE for details. -# -"""Elimination mini-game.""" - -# Maded by Froshlee14 -# Update by SEBASTIAN2059 - -# ba_meta require api 8 -# (see https://ballistica.net/wiki/meta-tag-system) - -from __future__ import annotations - -from typing import TYPE_CHECKING - -import babase -import bauiv1 as bui -import bascenev1 as bs -import _babase -import random -from bascenev1lib.actor.spazfactory import SpazFactory -from bascenev1lib.actor.scoreboard import Scoreboard -from bascenev1lib.actor import spazbot as stdbot -from bascenev1lib.gameutils import SharedObjects as so - -if TYPE_CHECKING: - from typing import (Any, Tuple, Dict, Type, List, Sequence, Optional, - Union) - - -class Icon(bs.Actor): - """Creates in in-game icon on screen.""" - - def __init__(self, - player: Player, - position: Tuple[float, float], - scale: float, - show_lives: bool = True, - show_death: bool = True, - name_scale: float = 1.0, - name_maxwidth: float = 115.0, - flatness: float = 1.0, - shadow: float = 1.0): - super().__init__() - - self._player = player - self._show_lives = show_lives - self._show_death = show_death - self._name_scale = name_scale - self._outline_tex = bs.gettexture('characterIconMask') - - icon = player.get_icon() - self.node = bs.newnode('image', - delegate=self, - attrs={ - 'texture': icon['texture'], - 'tint_texture': icon['tint_texture'], - 'tint_color': icon['tint_color'], - 'vr_depth': 400, - 'tint2_color': icon['tint2_color'], - 'mask_texture': self._outline_tex, - 'opacity': 1.0, - 'absolute_scale': True, - 'attach': 'bottomCenter' - }) - self._name_text = bs.newnode( - 'text', - owner=self.node, - attrs={ - 'text': babase.Lstr(value=player.getname()), - 'color': babase.safecolor(player.team.color), - 'h_align': 'center', - 'v_align': 'center', - 'vr_depth': 410, - 'maxwidth': name_maxwidth, - 'shadow': shadow, - 'flatness': flatness, - 'h_attach': 'center', - 'v_attach': 'bottom' - }) - if self._show_lives: - self._lives_text = bs.newnode('text', - owner=self.node, - attrs={ - 'text': 'x0', - 'color': (1, 1, 0.5), - 'h_align': 'left', - 'vr_depth': 430, - 'shadow': 1.0, - 'flatness': 1.0, - 'h_attach': 'center', - 'v_attach': 'bottom' - }) - self.set_position_and_scale(position, scale) - - def set_position_and_scale(self, position: Tuple[float, float], - scale: float) -> None: - """(Re)position the icon.""" - assert self.node - self.node.position = position - self.node.scale = [70.0 * scale] - self._name_text.position = (position[0], position[1] + scale * 52.0) - self._name_text.scale = 1.0 * scale * self._name_scale - if self._show_lives: - self._lives_text.position = (position[0] + scale * 10.0, - position[1] - scale * 43.0) - self._lives_text.scale = 1.0 * scale - - def update_for_lives(self) -> None: - """Update for the target player's current lives.""" - if self._player: - lives = self._player.lives - else: - lives = 0 - if self._show_lives: - if lives > 0: - self._lives_text.text = 'x' + str(lives - 1) - else: - self._lives_text.text = '' - if lives == 0: - self._name_text.opacity = 0.2 - assert self.node - self.node.color = (0.7, 0.3, 0.3) - self.node.opacity = 0.2 - - def handle_player_spawned(self) -> None: - """Our player spawned; hooray!""" - if not self.node: - return - self.node.opacity = 1.0 - self.update_for_lives() - - def handle_player_died(self) -> None: - """Well poo; our player died.""" - if not self.node: - return - if self._show_death: - bs.animate( - self.node, 'opacity', { - 0.00: 1.0, - 0.05: 0.0, - 0.10: 1.0, - 0.15: 0.0, - 0.20: 1.0, - 0.25: 0.0, - 0.30: 1.0, - 0.35: 0.0, - 0.40: 1.0, - 0.45: 0.0, - 0.50: 1.0, - 0.55: 0.2 - }) - lives = self._player.lives - if lives == 0: - bs.timer(0.6, self.update_for_lives) - - def handlemessage(self, msg: Any) -> Any: - if isinstance(msg, bs.DieMessage): - self.node.delete() - return None - return super().handlemessage(msg) - - -class Player(bs.Player['Team']): - """Our player type for this game.""" - - def __init__(self) -> None: - self.lives = 0 - self.icons: List[Icon] = [] - - -class Team(bs.Team[Player]): - """Our team type for this game.""" - - def __init__(self) -> None: - self.survival_seconds: Optional[int] = None - self.spawn_order: List[Player] = [] - - -lang = bs.app.lang.language -if lang == 'Spanish': - description = 'Mantente en la zona segura.' - join_description = 'Corre hacia la zona segura.' - kill_timer = 'Kill timer: ' -else: - description = 'Stay in the safe zone.' - join_description = 'Run into the safe zone' - kill_timer = 'Kill timer: ' - -# ba_meta export bascenev1.GameActivity - - -class SafeZoneGame(bs.TeamGameActivity[Player, Team]): - """Game type where last player(s) left alive win.""" - - name = 'Safe Zone' - description = description - scoreconfig = bs.ScoreConfig(label='Survived', - scoretype=bs.ScoreType.SECONDS, - none_is_winner=True) - # Show messages when players die since it's meaningful here. - announce_player_deaths = True - - @classmethod - def get_available_settings( - cls, sessiontype: Type[bs.Session]) -> List[babase.Setting]: - settings = [ - bs.IntSetting( - 'Lives Per Player', - default=2, - min_value=1, - max_value=10, - increment=1, - ), - bs.IntChoiceSetting( - 'Time Limit', - choices=[ - ('None', 0), - ('1 Minute', 60), - ('2 Minutes', 120), - ('5 Minutes', 300), - ('10 Minutes', 600), - ('20 Minutes', 1200), - ], - default=0, - ), - bs.FloatChoiceSetting( - 'Respawn Times', - choices=[ - ('Short', 0.25), - ('Normal', 0.5), - ], - default=0.5, - ), - bs.BoolSetting('Epic Mode', default=False), - ] - if issubclass(sessiontype, bs.DualTeamSession): - settings.append(bs.BoolSetting('Solo Mode', default=False)) - settings.append( - bs.BoolSetting('Balance Total Lives', default=False)) - return settings - - @classmethod - def supports_session_type(cls, sessiontype: Type[bs.Session]) -> bool: - return (issubclass(sessiontype, bs.DualTeamSession) - or issubclass(sessiontype, bs.FreeForAllSession)) - - @classmethod - def get_supported_maps(cls, sessiontype: Type[bs.Session]) -> List[str]: - return ['Football Stadium', 'Hockey Stadium'] - - def __init__(self, settings: dict): - super().__init__(settings) - self._scoreboard = Scoreboard() - self._start_time: Optional[float] = None - self._vs_text: Optional[bs.Actor] = None - self._round_end_timer: Optional[bs.Timer] = None - self._epic_mode = bool(settings['Epic Mode']) - self._lives_per_player = int(settings['Lives Per Player']) - self._time_limit = float(settings['Time Limit']) - self._balance_total_lives = bool( - settings.get('Balance Total Lives', False)) - self._solo_mode = bool(settings.get('Solo Mode', False)) - - # Base class overrides: - self.slow_motion = self._epic_mode - self.default_music = (bs.MusicType.EPIC - if self._epic_mode else bs.MusicType.SURVIVAL) - - self._tick_sound = bs.getsound('tick') - - def get_instance_description(self) -> Union[str, Sequence]: - return join_description - - def get_instance_description_short(self) -> Union[str, Sequence]: - return 'last team standing wins' if isinstance( - self.session, bs.DualTeamSession) else 'last one standing wins' - - def on_player_join(self, player: Player) -> None: - - # No longer allowing mid-game joiners here; too easy to exploit. - if self.has_begun(): - - # Make sure their team has survival seconds set if they're all dead - # (otherwise blocked new ffa players are considered 'still alive' - # in score tallying). - if (self._get_total_team_lives(player.team) == 0 - and player.team.survival_seconds is None): - player.team.survival_seconds = 0 - bs.broadcastmessage( - babase.Lstr(resource='playerDelayedJoinText', - subs=[('${PLAYER}', player.getname(full=True))]), - color=(0, 1, 0), - ) - return - - player.lives = self._lives_per_player - - if self._solo_mode: - player.team.spawn_order.append(player) - self._update_solo_mode() - else: - # Create our icon and spawn. - player.icons = [Icon(player, position=(0, 50), scale=0.8)] - if player.lives > 0: - self.spawn_player(player) - - # Don't waste time doing this until begin. - if self.has_begun(): - self._update_icons() - - def on_begin(self) -> None: - super().on_begin() - self._start_time = bs.time() - self.setup_standard_time_limit(self._time_limit) - # self.setup_standard_powerup_drops() - - bs.timer(5, self.spawn_zone) - self._bots = stdbot.SpazBotSet() - bs.timer(3, babase.Call(self.add_bot, 'left')) - bs.timer(3, babase.Call(self.add_bot, 'right')) - if len(self.initialplayerinfos) > 4: - bs.timer(5, babase.Call(self.add_bot, 'right')) - bs.timer(5, babase.Call(self.add_bot, 'left')) - - if self._solo_mode: - self._vs_text = bs.NodeActor( - bs.newnode('text', - attrs={ - 'position': (0, 105), - 'h_attach': 'center', - 'h_align': 'center', - 'maxwidth': 200, - 'shadow': 0.5, - 'vr_depth': 390, - 'scale': 0.6, - 'v_attach': 'bottom', - 'color': (0.8, 0.8, 0.3, 1.0), - 'text': babase.Lstr(resource='vsText') - })) - - # If balance-team-lives is on, add lives to the smaller team until - # total lives match. - if (isinstance(self.session, bs.DualTeamSession) - and self._balance_total_lives and self.teams[0].players - and self.teams[1].players): - if self._get_total_team_lives( - self.teams[0]) < self._get_total_team_lives(self.teams[1]): - lesser_team = self.teams[0] - greater_team = self.teams[1] - else: - lesser_team = self.teams[1] - greater_team = self.teams[0] - add_index = 0 - while (self._get_total_team_lives(lesser_team) < - self._get_total_team_lives(greater_team)): - lesser_team.players[add_index].lives += 1 - add_index = (add_index + 1) % len(lesser_team.players) - - self._update_icons() - - # We could check game-over conditions at explicit trigger points, - # but lets just do the simple thing and poll it. - bs.timer(1.0, self._update, repeat=True) - - def spawn_zone(self): - self.zone_pos = (random.randrange(-10, 10), 0.05, random.randrange(-5, 5)) - self.zone = bs.newnode('locator', attrs={'shape': 'circle', 'position': self.zone_pos, 'color': ( - 1, 1, 0), 'opacity': 0.8, 'draw_beauty': True, 'additive': False, 'drawShadow': False}) - self.zone_limit = bs.newnode('locator', attrs={'shape': 'circleOutline', 'position': self.zone_pos, 'color': ( - 1, 0.2, 0.2), 'opacity': 0.8, 'draw_beauty': True, 'additive': False, 'drawShadow': False}) - bs.animate_array(self.zone, 'size', 1, {0: [0], 0.3: [ - self.get_players_count()*0.85], 0.35: [self.get_players_count()*0.8]}) - bs.animate_array(self.zone_limit, 'size', 1, {0: [0], 0.3: [ - self.get_players_count()*1.2], 0.35: [self.get_players_count()*0.95]}) - self.last_players_count = self.get_players_count() - bs.getsound('laserReverse').play() - self.start_timer() - self.move_zone() - - def delete_zone(self): - self.zone.delete() - self.zone = None - self.zone_limit.delete() - self.zone_limit = None - bs.getsound('shieldDown').play() - bs.timer(1, self.spawn_zone) - - def move_zone(self): - if self.zone_pos[0] > 0: - x = random.randrange(0, 10) - else: - x = random.randrange(-10, 0) - - if self.zone_pos[2] > 0: - y = random.randrange(0, 5) - else: - y = random.randrange(-5, 0) - - new_pos = (x, 0.05, y) - bs.animate_array(self.zone, 'position', 3, {0: self.zone.position, 8: new_pos}) - bs.animate_array(self.zone_limit, 'position', 3, {0: self.zone_limit.position, 8: new_pos}) - - def start_timer(self): - count = self.get_players_count() - self._time_remaining = 10 if count > 9 else count-1 if count > 6 else count if count > 2 else count*2 - self._timer_x = bs.Timer(1.0, bs.WeakCall(self.tick), repeat=True) - # gnode = bs.getactivity().globalsnode - # tint = gnode.tint - # bs.animate_array(gnode,'tint',3,{0:tint,self._time_remaining*1.5:(1.0,0.5,0.5),self._time_remaining*1.55:tint}) - - def stop_timer(self): - self._time = None - self._timer_x = None - - def tick(self): - self.check_players() - self._time = bs.NodeActor(bs.newnode('text', - attrs={'v_attach': 'top', 'h_attach': 'center', - 'text': kill_timer+str(self._time_remaining)+'s', - 'opacity': 0.8, 'maxwidth': 100, 'h_align': 'center', - 'v_align': 'center', 'shadow': 1.0, 'flatness': 1.0, - 'color': (1, 1, 1), 'scale': 1.5, 'position': (0, -50)} - ) - ) - self._time_remaining -= 1 - self._tick_sound.play() - - def check_players(self): - if self._time_remaining <= 0: - self.stop_timer() - bs.animate_array(self.zone, 'size', 1, { - 0: [self.last_players_count*0.8], 1.4: [self.last_players_count*0.8], 1.5: [0]}) - bs.animate_array(self.zone_limit, 'size', 1, { - 0: [self.last_players_count*0.95], 1.45: [self.last_players_count*0.95], 1.5: [0]}) - bs.timer(1.5, self.delete_zone) - for player in self.players: - if not player.actor is None: - if player.actor.is_alive(): - p1 = player.actor.node.position - p2 = self.zone.position - diff = (babase.Vec3(p1[0]-p2[0], 0.0, p1[2]-p2[2])) - dist = (diff.length()) - if dist > (self.get_players_count()*0.7): - player.actor.handlemessage(bs.DieMessage()) - - def get_players_count(self): - count = 0 - for player in self.players: - if not player.actor is None: - if player.actor.is_alive(): - count += 1 - return count - - def _update_solo_mode(self) -> None: - # For both teams, find the first player on the spawn order list with - # lives remaining and spawn them if they're not alive. - for team in self.teams: - # Prune dead players from the spawn order. - team.spawn_order = [p for p in team.spawn_order if p] - for player in team.spawn_order: - assert isinstance(player, Player) - if player.lives > 0: - if not player.is_alive(): - self.spawn_player(player) - break - - def _update_icons(self) -> None: - # pylint: disable=too-many-branches - - # In free-for-all mode, everyone is just lined up along the bottom. - if isinstance(self.session, bs.FreeForAllSession): - count = len(self.teams) - x_offs = 85 - xval = x_offs * (count - 1) * -0.5 - for team in self.teams: - if len(team.players) == 1: - player = team.players[0] - for icon in player.icons: - icon.set_position_and_scale((xval, 30), 0.7) - icon.update_for_lives() - xval += x_offs - - # In teams mode we split up teams. - else: - if self._solo_mode: - # First off, clear out all icons. - for player in self.players: - player.icons = [] - - # Now for each team, cycle through our available players - # adding icons. - for team in self.teams: - if team.id == 0: - xval = -60 - x_offs = -78 - else: - xval = 60 - x_offs = 78 - is_first = True - test_lives = 1 - while True: - players_with_lives = [ - p for p in team.spawn_order - if p and p.lives >= test_lives - ] - if not players_with_lives: - break - for player in players_with_lives: - player.icons.append( - Icon(player, - position=(xval, (40 if is_first else 25)), - scale=1.0 if is_first else 0.5, - name_maxwidth=130 if is_first else 75, - name_scale=0.8 if is_first else 1.0, - flatness=0.0 if is_first else 1.0, - shadow=0.5 if is_first else 1.0, - show_death=is_first, - show_lives=False)) - xval += x_offs * (0.8 if is_first else 0.56) - is_first = False - test_lives += 1 - # Non-solo mode. - else: - for team in self.teams: - if team.id == 0: - xval = -50 - x_offs = -85 - else: - xval = 50 - x_offs = 85 - for player in team.players: - for icon in player.icons: - icon.set_position_and_scale((xval, 30), 0.7) - icon.update_for_lives() - xval += x_offs - - def _get_spawn_point(self, player: Player) -> Optional[babase.Vec3]: - del player # Unused. - - # In solo-mode, if there's an existing live player on the map, spawn at - # whichever spot is farthest from them (keeps the action spread out). - if self._solo_mode: - living_player = None - living_player_pos = None - for team in self.teams: - for tplayer in team.players: - if tplayer.is_alive(): - assert tplayer.node - ppos = tplayer.node.position - living_player = tplayer - living_player_pos = ppos - break - if living_player: - assert living_player_pos is not None - player_pos = babase.Vec3(living_player_pos) - points: List[Tuple[float, babase.Vec3]] = [] - for team in self.teams: - start_pos = babase.Vec3(self.map.get_start_position(team.id)) - points.append( - ((start_pos - player_pos).length(), start_pos)) - # Hmm.. we need to sorting vectors too? - points.sort(key=lambda x: x[0]) - return points[-1][1] - return None - - def spawn_player(self, player: Player) -> bs.Actor: - actor = self.spawn_player_spaz(player, self._get_spawn_point(player)) - if not self._solo_mode: - bs.timer(0.3, babase.Call(self._print_lives, player)) - - # spaz but *without* the ability to attack or pick stuff up. - actor.connect_controls_to_player(enable_punch=False, - enable_bomb=False, - enable_pickup=False) - - # If we have any icons, update their state. - for icon in player.icons: - icon.handle_player_spawned() - return actor - - def _print_lives(self, player: Player) -> None: - from bascenev1lib.actor import popuptext - - # We get called in a timer so it's possible our player has left/etc. - if not player or not player.is_alive() or not player.node: - return - - popuptext.PopupText('x' + str(player.lives - 1), - color=(1, 1, 0, 1), - offset=(0, -0.8, 0), - random_offset=0.0, - scale=1.8, - position=player.node.position).autoretain() - - def on_player_leave(self, player: Player) -> None: - super().on_player_leave(player) - player.icons = [] - - # Remove us from spawn-order. - if self._solo_mode: - if player in player.team.spawn_order: - player.team.spawn_order.remove(player) - - # Update icons in a moment since our team will be gone from the - # list then. - bs.timer(0, self._update_icons) - - # If the player to leave was the last in spawn order and had - # their final turn currently in-progress, mark the survival time - # for their team. - if self._get_total_team_lives(player.team) == 0: - assert self._start_time is not None - player.team.survival_seconds = int(bs.time() - self._start_time) - - def _get_total_team_lives(self, team: Team) -> int: - return sum(player.lives for player in team.players) - - def handlemessage(self, msg: Any) -> Any: - if isinstance(msg, bs.PlayerDiedMessage): - - # Augment standard behavior. - super().handlemessage(msg) - player: Player = msg.getplayer(Player) - - player.lives -= 1 - if player.lives < 0: - babase.print_error( - "Got lives < 0 in Elim; this shouldn't happen. solo:" + - str(self._solo_mode)) - player.lives = 0 - - # If we have any icons, update their state. - for icon in player.icons: - icon.handle_player_died() - - # Play big death sound on our last death - # or for every one in solo mode. - if self._solo_mode or player.lives == 0: - SpazFactory.get().single_player_death_sound.play() - - # If we hit zero lives, we're dead (and our team might be too). - if player.lives == 0: - # If the whole team is now dead, mark their survival time. - if self._get_total_team_lives(player.team) == 0: - assert self._start_time is not None - player.team.survival_seconds = int(bs.time() - - self._start_time) - else: - # Otherwise, in regular mode, respawn. - if not self._solo_mode: - self.respawn_player(player) - - # In solo, put ourself at the back of the spawn order. - if self._solo_mode: - player.team.spawn_order.remove(player) - player.team.spawn_order.append(player) - elif isinstance(msg, stdbot.SpazBotDiedMessage): - self._on_spaz_bot_died(msg) - - def _on_spaz_bot_died(self, die_msg): - bs.timer(1, babase.Call(self.add_bot, die_msg.spazbot.node.position)) - - def _on_bot_spawn(self, spaz): - spaz.update_callback = self.move_bot - spaz_type = type(spaz) - spaz._charge_speed = self._get_bot_speed(spaz_type) - - def add_bot(self, pos=None): - if pos == 'left': - position = (-11, 0, random.randrange(-5, 5)) - elif pos == 'right': - position = (11, 0, random.randrange(-5, 5)) - else: - position = pos - self._bots.spawn_bot(self.get_random_bot(), pos=position, spawn_time=1, - on_spawn_call=babase.Call(self._on_bot_spawn)) - - def move_bot(self, bot): - p = bot.node.position - speed = -bot._charge_speed if (p[0] >= -11 and p[0] < 0) else bot._charge_speed - - if (p[0] >= -11) and (p[0] <= 11): - bot.node.move_left_right = speed - bot.node.move_up_down = 0.0 - bot.node.run = 0.0 - return True - return False - - def get_random_bot(self): - bots = [stdbot.BomberBotStatic, stdbot.TriggerBotStatic] - return (random.choice(bots)) - - def _get_bot_speed(self, bot_type): - if bot_type == stdbot.BomberBotStatic: - return 0.48 - elif bot_type == stdbot.TriggerBotStatic: - return 0.73 - else: - raise Exception('Invalid bot type to _getBotSpeed(): '+str(bot_type)) - - def _update(self) -> None: - if self._solo_mode: - # For both teams, find the first player on the spawn order - # list with lives remaining and spawn them if they're not alive. - for team in self.teams: - # Prune dead players from the spawn order. - team.spawn_order = [p for p in team.spawn_order if p] - for player in team.spawn_order: - assert isinstance(player, Player) - if player.lives > 0: - if not player.is_alive(): - self.spawn_player(player) - self._update_icons() - break - - # If we're down to 1 or fewer living teams, start a timer to end - # the game (allows the dust to settle and draws to occur if deaths - # are close enough). - if len(self._get_living_teams()) < 2: - self._round_end_timer = bs.Timer(0.5, self.end_game) - - def _get_living_teams(self) -> List[Team]: - return [ - team for team in self.teams - if len(team.players) > 0 and any(player.lives > 0 - for player in team.players) - ] - - def end_game(self) -> None: - if self.has_ended(): - return - results = bs.GameResults() - self._vs_text = None # Kill our 'vs' if its there. - for team in self.teams: - results.set_team_score(team, team.survival_seconds) - self.end(results=results) From 79cd405ca10c6f20fea8b812357fa1ea714615ac Mon Sep 17 00:00:00 2001 From: ! Freaku <92618708+Freaku17@users.noreply.github.com> Date: Fri, 9 Feb 2024 23:06:06 +0530 Subject: [PATCH 0860/1464] Add new mod: translate --- plugins/utilities/translate.py | 237 +++++++++++++++++++++++++++++++++ 1 file changed, 237 insertions(+) create mode 100644 plugins/utilities/translate.py diff --git a/plugins/utilities/translate.py b/plugins/utilities/translate.py new file mode 100644 index 00000000..512dbdc2 --- /dev/null +++ b/plugins/utilities/translate.py @@ -0,0 +1,237 @@ +# Made by your friend: Freaku + +# Translate function through google webpage by: OnurV2 (from their BombsquadDetails.py mod) +# Github: https://github.com/OnurV2 +# YT: https://m.youtube.com/@OnurV2 + + +import babase +import bauiv1 as bui +from bauiv1lib.popup import PopupMenu +import bauiv1lib.party +import urllib +import threading +import random + +show_translate_result = True +config = babase.app.config +default_config = {'O Source Trans Lang': 'Auto Detect', 'O Target Trans Lang': babase.app.lang.default_language, 'Y Source Trans Lang': 'Auto Detect', 'Y Target Trans Lang': babase.app.lang.default_language} + +for key in default_config: + if not key in config: + config[key] = default_config[key] + +translate_languages = {'Auto Detect': 'auto', 'Arabic': 'ar', 'Chinese (simplified)': 'zh-CN', 'Chinese (traditional)': 'zh-TW', 'Croatian': 'hr', 'Czech': 'cs', + 'Danish': 'da', 'Dutch': 'nl', 'English': 'en', 'Esperanto': 'eo', + 'Finnish': 'fi', + 'Tagalog': 'tl', 'French': 'fr', 'German': 'de', 'Greek': 'el', + 'Hindi': 'hi', 'Hungarian': 'hu', 'Indonesian': 'id', 'Italian': 'it', + 'Japanese': 'ja', + 'Korean': 'ko', 'Malay': 'ms', 'Malayalam': 'ml', 'Marathi': 'mr', 'Persian': 'fa', 'Polish': 'pl', + 'Portuguese': 'pt', 'Romanian': 'ro', 'Russian': 'ru', 'Serbian': 'sr', + 'Slovak': 'sk', 'Spanish': 'es', 'Swedish': 'sv', 'Tamil': 'ta', + 'Telugu': 'te', + 'Thai': 'th', 'Turkish': 'tr', 'Ukrainian': 'uk', 'Vietnamese': 'vi'} +available_translate_languages = [] +for lang in translate_languages: + available_translate_languages.append(lang) +available_translate_languages.sort() +available_translate_languages.remove('Auto Detect') +available_translate_languages.insert(0, 'Auto Detect') + + + +def translate(text, _callback, source='auto', target='en'): + text = urllib.parse.quote(text) + url = f'https://translate.google.com/m?tl={target}&sl={source}&q={text}' + request = urllib.request.Request(url) + data = urllib.request.urlopen(request).read().decode('utf-8') + result = data[(data.find('"result-container">'))+len('"result-container">'):data.find('