diff --git a/plugins/utilities.json b/plugins/utilities.json index 747eeb2..3b51fff 100644 --- a/plugins/utilities.json +++ b/plugins/utilities.json @@ -826,7 +826,7 @@ } }, "disco_light": { - "description": "Add disco light into the game.", + "description": "Add disco light into the game. Do '/disco' to turn on and '/disco off' to turn off", "external_url": "", "authors": [ { @@ -836,6 +836,12 @@ } ], "versions": { + "2.1.0": { + "api_version": 8, + "commit_sha": "41046ae", + "released_on": "14-02-2024", + "md5sum": "bfffb346d61958c02015dde0b1520ca3" + }, "1.0.1": { "api_version": 8, "commit_sha": "2b5c9ee", @@ -851,7 +857,7 @@ } }, "practice_tools": { - "description": "Powerful and comprehensive tools for practice purpose. Practice tabs can be access through party window.", + "description": "Powerful and comprehensive tools for practice purposes. Practice tabs can be accessed through party window.", "external_url": "https://www.youtube.com/watch?v=7BeCcIYSXd0&t=113s&ab_channel=BOMBsquadlife", "authors": [ { @@ -861,6 +867,12 @@ } ], "versions": { + "2.2.0": { + "api_version": 8, + "commit_sha": "41046ae", + "released_on": "14-02-2024", + "md5sum": "b02de60a80039b092ef4d826b3d61cc1" + }, "2.1.1": { "api_version": 8, "commit_sha": "5422dd6", @@ -905,6 +917,25 @@ } } }, + "health_indicator": { + "description": "Add a simple health indicator on every player and bot.", + "external_url": "", + "authors": [ + { + "name": "Cross Joy", + "email": "cross.joy.official@gmail.com", + "discord": "crossjoy" + } + ], + "versions": { + "1.2.0": { + "api_version": 8, + "commit_sha": "41046ae", + "released_on": "14-02-2024", + "md5sum": "e16123cf550f433c70e53b8ec41a4e46" + } + } + }, "autorun": { "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": "", diff --git a/plugins/utilities/disco_light.py b/plugins/utilities/disco_light.py index 68d4979..fc03d80 100644 --- a/plugins/utilities/disco_light.py +++ b/plugins/utilities/disco_light.py @@ -1,12 +1,11 @@ -# Porting to api 8 made easier by baport.(https://github.com/bombsquad-community/baport) -"""Disco Light Mod: V1.0 +"""Disco Light Mod: V2.1 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: crossjoy +# My Discord Id: Cross Joy#0721 # My BS Discord Server: https://discord.gg/JyBY6haARJ @@ -19,11 +18,16 @@ Made by Cross Joy""" # Coop and multiplayer compatible. -# Work on any 1.7 ver. +# Work on any 1.7.20+ ver. # Note: # The plugin commands only works on the host with the plugin activated. # Other clients/players can't use the commands. + +# v2.1 +# - Enhance compatibility with other mods +# - Tint change when /disco off will be more dynamic. + # ---------------------------------------------------------------------------- # ba_meta require api 8 @@ -33,255 +37,196 @@ from __future__ import annotations from typing import TYPE_CHECKING -from baenv import TARGET_BALLISTICA_BUILD as build_number -from bauiv1lib import mainmenu +import bascenev1 as bs import babase import bauiv1 as bui -import bascenev1 as bs -import _babase -from bascenev1 import _gameutils, animate +from bascenev1 import _gameutils import random +from bascenev1 import animate if TYPE_CHECKING: from typing import Sequence, Union -# Check game ver. +class DiscoLight: -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 if build_number < - 21282 else babase.app.env.split("."))) - version = tuple(map(int, version.split("."))) - return game_version < version + def __init__(self): + activity = bs.get_foreground_host_activity() + self.globalnodes = activity.globalsnode.tint + # Activate disco light. + def start(self): + activity = bs.get_foreground_host_activity() + with activity.context: + self.partyLight(True) + self.rainbow(activity) -# if is_game_version_lower_than("1.7.7"): -# ba_internal = _ba -# else: -# ba_internal = babase.internal + # Deactivate disco light. + def stop(self): + activity = bs.get_foreground_host_activity() + with activity.context: + self.partyLight(False) + self.stop_rainbow(activity) + # Create and animate colorful spotlight. + def partyLight(self, switch=True): + from bascenev1._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] -# Activate disco light. -def start(): - activity = bs.get_foreground_host_activity() + # Store this on the current activity, so we only have one at a time. + 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( + 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) + })) + 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] + }) + 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: + bs.timer(0.1, + light.node.delete) + activity.camera_flash_data.append(light) # type: ignore - with activity.context: - partyLight(True) - rainbow(activity) + # Create RGB tint. + def rainbow(self, activity) -> None: + """Create RGB tint.""" + cnode = bs.newnode('combine', + attrs={ + 'input0': self.globalnodes[0], + 'input1': self.globalnodes[1], + 'input2': self.globalnodes[2], + 'size': 3 + }) -# Deactivate disco light. -def stop(): - activity = bs.get_foreground_host_activity() + _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) - with activity.context: - partyLight(False) - stop_rainbow(activity) + _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) -# Create and animate colorful spotlight. -def partyLight(switch=True): - from bascenev1._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] + cnode.connectattr('output', activity.globalsnode, 'tint') - # Store this on the current activity, so we only have one at a time. - 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( - 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) - })) - 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] - }) - 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: - bs.timer(0.1, - light.node.delete) - activity.camera_flash_data.append(light) # type: ignore + # Revert to the original map tint. + def stop_rainbow(self, activity): + """Revert to the original map tint.""" + c_existing = activity.globalsnode.tint + # map_name = activity.map.getname() + tint = self.globalnodes + cnode = bs.newnode('combine', + attrs={ + 'input0': c_existing[0], + 'input1': c_existing[1], + 'input2': c_existing[2], + 'size': 3 + }) -# Create RGB tint. -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 - }) + _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]}) - _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.""" - try: - c_existing = self.globalsnode.tint - map_name = self.map.getname() - tint = check_map_tint(map_name) - except: - tint = (1, 1, 1) - - cnode = bs.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 = bs.chatmessage + cnode.connectattr('output', activity.globalsnode, 'tint') # New chat func to add some commands to activate/deactivate the disco light. -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': - start() - if msg == '/disco off': - stop() +def new_chat_message(func): + def wrapper(*args, **kwargs): + func(*args, **kwargs) + activity = bs.get_foreground_host_activity() + with activity.context: + try: + if not activity.disco_light: + activity.disco_light = DiscoLight() + except: + activity.disco_light = DiscoLight() + if args[0] == '/disco': + activity.disco_light.start() + elif args[0] == '/disco off': + activity.disco_light.stop() + + return wrapper -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 +def new_begin(func): + """Runs when game is began.""" + + def wrapper(*args, **kwargs): + func(*args, **kwargs) bui.set_party_icon_always_visible(True) - -# Replace new chat func to the original game codes. -bs.chatmessage = new_chat_message + return wrapper # ba_meta export plugin class ByCrossJoy(babase.Plugin): - def on_app_running(self): - mainmenu.MainMenuWindow = NewMainMenuWindow + def __init__(self): + # Replace new chat func to the original game codes. + bs.chatmessage = new_chat_message(bs.chatmessage) + bs._activity.Activity.on_begin = new_begin( + bs._activity.Activity.on_begin) diff --git a/plugins/utilities/health_indicator.py b/plugins/utilities/health_indicator.py new file mode 100644 index 0000000..52d8f8b --- /dev/null +++ b/plugins/utilities/health_indicator.py @@ -0,0 +1,79 @@ +"""Health Indicator mod v1.2 +Made by Cross Joy +For 1.7.20+""" + +# ---------------------- +# v1.2 update +# Enhance compatibility with other mods. +# Fixed the health is not displaying accurately. +# ---------------------- + +# You can contact me through discord: +# My Discord Id: Cross Joy#0721 +# My BS Discord Server: https://discord.gg/JyBY6haARJ + +# Add a simple health indicator on every player and bot. + +# ba_meta require api 8 + +from __future__ import annotations + +import babase +import bascenev1lib.actor.spaz +from bascenev1lib.actor.spaz import Spaz +import bascenev1 as bs +import bascenev1lib + + +def new_init_spaz_(func): + def wrapper(*args, **kwargs): + func(*args, **kwargs) + m = bs.newnode('math', + owner=args[0].node, + attrs={'input1': (0, 0.7, 0), + 'operation': 'add'}) + args[0].node.connectattr('position', m, 'input2') + args[0]._hitpoint_text = bs.newnode( + 'text', + owner=args[0].node, + attrs={'text': "\ue047" + str(args[0].hitpoints), + 'in_world': True, + 'shadow': 1.0, + 'flatness': 1.0, + 'color': (1, 1, 1), + 'scale': 0.0, + 'h_align': 'center'}) + m.connectattr('output', args[0]._hitpoint_text, 'position') + bs.animate(args[0]._hitpoint_text, 'scale', {0: 0.0, 1.0: 0.01}) + + return wrapper + + +def new_handlemessage_spaz_(func): + def wrapper(*args, **kwargs): + def update_hitpoint_text(spaz): + spaz._hitpoint_text.text = "\ue047" + str(spaz.hitpoints) + r = spaz.hitpoints / 1000 + spaz._hitpoint_text.color = (1, r, r, 1) + + func(*args, **kwargs) + if isinstance(args[1], bs.PowerupMessage): + if args[1].poweruptype == 'health': + update_hitpoint_text(args[0]) + if isinstance( + args[1], bs.HitMessage) or isinstance( + args[1], bs.ImpactDamageMessage): + update_hitpoint_text(args[0]) + + return wrapper + + +# ba_meta export plugin +class ByCrossJoy(babase.Plugin): + + def __init__(self): + pass + + def on_app_running(self) -> None: + Spaz.__init__ = new_init_spaz_(Spaz.__init__) + Spaz.handlemessage = new_handlemessage_spaz_(Spaz.handlemessage) diff --git a/plugins/utilities/practice_tools.py b/plugins/utilities/practice_tools.py index e4e928b..0cc009a 100644 --- a/plugins/utilities/practice_tools.py +++ b/plugins/utilities/practice_tools.py @@ -1,4 +1,4 @@ -"""Practice Tools Mod: V2.1 +"""Practice Tools Mod: V2.2 Made by Cross Joy""" # If anyone who want to help me on giving suggestion/ fix bugs/ creating PR, @@ -12,25 +12,12 @@ Made by Cross Joy""" # 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+) +# V2.2 update +# - Enhance computability with other mods. +# - Added setting for permanent powerups. +# - Codes Optimization. -# 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. @@ -72,7 +59,8 @@ import bascenev1lib import bauiv1 as bui from bauiv1lib import mainmenu from babase import app, Plugin -from bascenev1lib.actor.powerupbox import PowerupBox +from bascenev1lib.actor.powerupbox import PowerupBox, PowerupBoxFactory +from bascenev1lib.actor.bomb import Bomb from bascenev1lib.actor.spaz import Spaz from bascenev1lib.actor import spawner from bascenev1lib.actor.spazbot import (SpazBotSet, SpazBot, BrawlerBot, @@ -94,47 +82,35 @@ from bauiv1lib.tabs import TabRow if TYPE_CHECKING: from typing import Any, Sequence, Callable, Optional -version = '2.1' +version = '2.2' -try: - if babase.app.config.get("bombCountdown") is None: - babase.app.config["bombCountdown"] = False - else: - babase.app.config.get("bombCountdown") -except: - babase.app.config["bombCountdown"] = False -try: - if babase.app.config.get("bombRadiusVisual") is None: - babase.app.config["bombRadiusVisual"] = False - else: - babase.app.config.get("bombRadiusVisual") -except: - babase.app.config["bombRadiusVisual"] = False +class ConfigLoader: + def __init__(self): + self.config_data = { + "Practice Tab": False, + "bombCountdown": False, + "bombRadiusVisual": False, + "stopBots": False, + "immortalDummy": False, + "powerupsExpire": False, + "invincible": False + } + self.config_names = ["Practice Tab", "bombCountdown", + "bombRadiusVisual", "stopBots", + "immortalDummy", "powerupsExpire", "invincible"] -try: - if babase.app.config.get("stopBots") is None: - babase.app.config["stopBots"] = False - else: - babase.app.config.get("stopBots") -except: - babase.app.config["stopBots"] = False - -try: - if babase.app.config.get("immortalDummy") is None: - babase.app.config["immortalDummy"] = False - else: - babase.app.config.get("immortalDummy") -except: - babase.app.config["immortalDummy"] = False - -try: - if babase.app.config.get("invincible") is None: - babase.app.config["invincible"] = False - else: - babase.app.config.get("invincible") -except: - babase.app.config["invincible"] = False + def load_configs(self): + for config_name in self.config_names: + try: + existing_config = babase.app.config.get(config_name) + if existing_config is None: + babase.app.config[config_name] = self.config_data[ + config_name] + else: + babase.app.config.get(config_name) + except: + babase.app.config[config_name] = self.config_data[config_name] class PartyWindow(bui.Window): @@ -174,7 +150,7 @@ def redefine_class(original_cls: object, cls: object) -> None: def main(plugin: Plugin) -> None: - print(f'Plugins Tools v{plugin.__version__}') + print(f'Practice Tools v{plugin.__version__}') app.practice_tool = plugin redefine_class(OriginalPartyWindow, PartyWindow) @@ -185,10 +161,9 @@ class NewMainMenuWindow(mainmenu.MainMenuWindow): # 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__ = version @@ -202,334 +177,373 @@ class Practice(Plugin): raise RuntimeError( 'sad') mainmenu.MainMenuWindow = NewMainMenuWindow + config_loader = ConfigLoader() + config_loader.load_configs() 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') +def new_bomb_init(func): + def setting(*args, **kwargs): + func(*args, **kwargs) - 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={ - 'shape': 'circle', - 'color': (1, 0, 0), - 'opacity': 0.05, - 'draw_beauty': False, - 'additive': False - }) - args[0].node.connectattr('position', args[0].radius_visualizer, - 'position') + bomb_type = args[0].bomb_type + fuse_bomb = ('land_mine', 'tnt', 'impact') - 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] - }) + 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={ + 'shape': 'circle', + 'color': (1, 0, 0), + 'opacity': 0.05, + 'draw_beauty': False, + 'additive': False + }) + args[0].node.connectattr('position', args[0].radius_visualizer, + 'position') - args[0].radius_visualizer_circle = bs.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') - - bs.animate( - args[0].radius_visualizer_circle, 'opacity', { - 0: 0.0, - 0.4: 0.1 - }) - - if bomb_type == 'tnt': - args[0].fatal = bs.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') - - 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 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) - bs.timer(1, bs.Call(count_bomb, *args, count='2', color=color)) - color = (1.0, 0.15, 0.15) - bs.timer(2, bs.Call(count_bomb, *args, count='1', color=color)) - - return setting - - bascenev1lib.actor.bomb.Bomb.__init__ = new_bomb_init( - bascenev1lib.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 = bs.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 = bs.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 = bs.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 = bs.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 = bs.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 bs.get_foreground_host_activity().players: - try: - if i.node: - if babase.app.config.get("invincible"): - i.actor.node.invincible = True - else: - i.actor.node.invincible = False - except: - pass - - bs.timer(1.001, bs.Call(invincible)) - - -Spaz.__init__ = _init_spaz_ - -Spaz.super_curse = Spaz.curse - - -def new_cursed(self): - if self.node.invincible: - return - self.super_curse() - 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], - 5.0: [3 * 2.0], - 5.1: [0.0], - }) - - bs.animate( - self.curse_visualizer_circle, 'opacity', { - 0: 0.0, - 0.4: 0.1, - 5.0: 0.1, - 5.1: 0.0, + 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] }) - bs.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], - }) + args[0].radius_visualizer_circle = bs.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') + + bs.animate( + args[0].radius_visualizer_circle, 'opacity', { + 0: 0.0, + 0.4: 0.1 + }) + + if bomb_type == 'tnt': + args[0].fatal = bs.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') + + 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 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) + bs.timer(1, bs.Call(count_bomb, *args, count='2', color=color)) + color = (1.0, 0.15, 0.15) + bs.timer(2, bs.Call(count_bomb, *args, count='1', color=color)) + + return setting -Spaz.curse = new_cursed - -Spaz.super_handlemessage = Spaz.handlemessage +bascenev1lib.actor.bomb.Bomb.__init__ = new_bomb_init( + bascenev1lib.actor.bomb.Bomb.__init__) -def bot_handlemessage(self, msg: Any): - if isinstance(msg, bs.PowerupMessage): - if msg.poweruptype == 'health': - if babase.app.config.get("bombRadiusVisual"): - if self._cursed: - bs.animate_array(self.curse_visualizer, 'size', 1, { - 0.0: [3 * 2.0], - 0.2: [0.0], - }) +def _init_spaz_(func): + def wrapper(*args, **kwargs): + func(*args, **kwargs) + args[0].bot_radius = bs.newnode('locator', + owner=args[0].node, + attrs={ + 'shape': 'circle', + 'color': (0, 0, 1), + 'opacity': 0.0, + 'draw_beauty': False, + 'additive': False + }) + args[0].node.connectattr('position', + args[0].bot_radius, + 'position') - bs.animate( - self.curse_visualizer_circle, 'opacity', { - 0.0: 0.1, - 0.2: 0.0, + args[0].radius_visualizer_circle = bs.newnode( + 'locator', + owner=args[0].node, + attrs={ + 'shape': 'circleOutline', + 'size': [(args[0].hitpoints_max - args[0].hitpoints) * 0.0048], + 'color': (0, 1, 1), + 'draw_beauty': False, + 'additive': True + }) + + args[0].node.connectattr('position', args[0].radius_visualizer_circle, + 'position') + + args[0].curse_visualizer = bs.newnode('locator', + owner=args[0].node, + attrs={ + 'shape': 'circle', + 'color': (1, 0, 0), + 'size': (0.0, 0.0, 0.0), + 'opacity': 0.05, + 'draw_beauty': False, + 'additive': False + }) + args[0].node.connectattr('position', args[0].curse_visualizer, + 'position') + + args[0].curse_visualizer_circle = bs.newnode( + 'locator', + owner=args[0].node, + attrs={ + 'shape': 'circleOutline', + 'size': [3 * 2.0], + 'color': ( + 1, 1, 0), + 'opacity': 0.0, + 'draw_beauty': False, + 'additive': True + }) + args[0].node.connectattr('position', + args[0].curse_visualizer_circle, + 'position') + + args[0].curse_visualizer_fatal = bs.newnode('locator', + owner=args[0].node, + attrs={ + 'shape': 'circle', + 'color': ( + 0.7, 0, 0), + 'size': (0.0, 0.0, 0.0), + 'opacity': 0.10, + 'draw_beauty': False, + 'additive': False + }) + args[0].node.connectattr('position', + args[0].curse_visualizer_fatal, + 'position') + + def invincible() -> None: + for i in bs.get_foreground_host_activity().players: + try: + if i.node: + if babase.app.config.get("invincible"): + i.actor.node.invincible = True + else: + i.actor.node.invincible = False + except: + pass + + bs.timer(1.001, bs.Call(invincible)) + + return wrapper + + +Spaz.__init__ = _init_spaz_(Spaz.__init__) + + +def new_cursed(func): + def wrapper(*args, **kwargs): + if args[0].node.invincible: + return + func(*args, **kwargs) + if babase.app.config.get("bombRadiusVisual"): + bs.animate_array(args[0].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], + }) + + bs.animate( + args[0].curse_visualizer_circle, 'opacity', { + 0: 0.0, + 0.4: 0.1, + 5.0: 0.1, + 5.1: 0.0, + }) + + bs.animate_array(args[0].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], + }) + + return wrapper + + +Spaz.curse = new_cursed(Spaz.curse) + + +def bot_handlemessage(func): + def wrapper(*args, **kwargs): + + if isinstance(args[1], bs.PowerupMessage): + if args[1].poweruptype == 'health': + if babase.app.config.get("bombRadiusVisual"): + if args[0]._cursed: + bs.animate_array(args[0].curse_visualizer, 'size', 1, { + 0.0: [3 * 2.0], + 0.2: [0.0], }) - bs.animate_array(self.curse_visualizer_fatal, 'size', 1, { - 0.0: [2.0], - 0.2: [0.0], + bs.animate( + args[0].curse_visualizer_circle, 'opacity', { + 0.0: 0.1, + 0.2: 0.0, + }) + + bs.animate_array(args[0].curse_visualizer_fatal, 'size', + 1, + { + 0.0: [2.0], + 0.2: [0.0], + }) + + bs.animate_array(args[0].bot_radius, 'size', 1, { + 0.0: [0], + 0.25: [0] }) - - bs.animate_array(self.bot_radius, 'size', 1, { - 0.0: [0], - 0.25: [0] - }) - bs.animate(self.bot_radius, 'opacity', { - 0.0: 0.00, - 0.25: 0.0 - }) - - bs.animate_array(self.radius_visualizer_circle, 'size', 1, { - 0.0: [0], - 0.25: [0] - }) - - bs.animate( - self.radius_visualizer_circle, 'opacity', { + bs.animate(args[0].bot_radius, 'opacity', { 0.0: 0.00, 0.25: 0.0 }) - self.super_handlemessage(msg) + bs.animate_array(args[0].radius_visualizer_circle, 'size', + 1, { + 0.0: [0], + 0.25: [0] + }) - if isinstance(msg, bs.HitMessage): - if self.hitpoints <= 0: - bs.animate(self.bot_radius, 'opacity', { - 0.0: 0.00 - }) - bs.animate( - self.radius_visualizer_circle, 'opacity', { + bs.animate( + args[0].radius_visualizer_circle, 'opacity', { + 0.0: 0.00, + 0.25: 0.0 + }) + if not (babase.app.config.get("powerupsExpire") and + args[0].powerups_expire): + if args[1].poweruptype == 'triple_bombs': + tex = PowerupBoxFactory.get().tex_bomb + args[0]._flash_billboard(tex) + args[0].set_bomb_count(3) + + elif args[1].poweruptype == 'impact_bombs': + args[0].bomb_type = 'impact' + tex = args[0]._get_bomb_type_tex() + args[0]._flash_billboard(tex) + + elif args[1].poweruptype == 'sticky_bombs': + args[0].bomb_type = 'sticky' + tex = args[0]._get_bomb_type_tex() + args[0]._flash_billboard(tex) + + elif args[1].poweruptype == 'punch': + tex = PowerupBoxFactory.get().tex_punch + args[0]._flash_billboard(tex) + args[0].equip_boxing_gloves() + + elif args[1].poweruptype == 'ice_bombs': + args[0].bomb_type = 'ice' + tex = args[0]._get_bomb_type_tex() + args[0]._flash_billboard(tex) + + if args[1].poweruptype in ['triple_bombs', 'impact_bombs', + 'sticky_bombs', 'punch', + 'ice_bombs']: + args[0].node.handlemessage('flash') + if args[1].sourcenode: + args[1].sourcenode.handlemessage( + bs.PowerupAcceptMessage()) + return True + + func(*args, **kwargs) + + if isinstance(args[1], bs.HitMessage): + if args[0].hitpoints <= 0: + bs.animate(args[0].bot_radius, 'opacity', { 0.0: 0.00 }) - elif babase.app.config.get('bombRadiusVisual'): + bs.animate( + args[0].radius_visualizer_circle, 'opacity', { + 0.0: 0.00 + }) + elif babase.app.config.get('bombRadiusVisual'): - 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] - }) - bs.animate(self.bot_radius, 'opacity', { - 0.0: 0.00, - 0.25: 0.05 - }) - - 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] - }) - - bs.animate( - self.radius_visualizer_circle, 'opacity', { + bs.animate_array(args[0].bot_radius, 'size', 1, { + 0.0: [(args[0].hitpoints_max - args[0].hitpoints) * 0.0045], + 0.25: [(args[0].hitpoints_max - args[0].hitpoints) * 0.0045] + }) + bs.animate(args[0].bot_radius, 'opacity', { 0.0: 0.00, - 0.25: 0.1 + 0.25: 0.05 }) + bs.animate_array(args[0].radius_visualizer_circle, 'size', 1, { + 0.0: [(args[0].hitpoints_max - args[0].hitpoints) * 0.0045], + 0.25: [(args[0].hitpoints_max - args[0].hitpoints) * 0.0045] + }) -Spaz.handlemessage = bot_handlemessage + bs.animate( + args[0].radius_visualizer_circle, 'opacity', { + 0.0: 0.00, + 0.25: 0.1 + }) + + return wrapper + + +Spaz.handlemessage = bot_handlemessage(Spaz.handlemessage) def count_bomb(*args, count, color): - 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 = bs.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', - }) + if args[0].node.exists(): + 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 = bs.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') - bs.animate(args[0].spaztext, 'scale', - {0: 0, 0.3: 0.03, 0.5: 0.025, 0.8: 0.025, 1.0: 0.0}) + args[0].node.connectattr('position', args[0].spaztext, + 'position') + 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): @@ -1211,8 +1225,9 @@ class PowerUpPracticeTab(PracticeTab): 'shield', 'sticky_bombs']) self._icon_index = self.load_settings() - self.setting_name = (['Bomb Countdown', 'Bomb Radius Visualizer']) - self.config = (['bombCountdown', 'bombRadiusVisual']) + self.setting_name = ( + ['Bomb Countdown', 'Bomb Radius Visualizer', 'Powerups Expire']) + self.config = (['bombCountdown', 'bombRadiusVisual', 'powerupsExpire']) def on_activate( self, @@ -1238,7 +1253,7 @@ class PowerUpPracticeTab(PracticeTab): self._sub_width = self._scroll_width self._sub_height = 200 - self.container_h = 450 + self.container_h = 550 power_height = self.container_h - 50 self._subcontainer = bui.containerwidget( @@ -1426,6 +1441,11 @@ class PowerUpPracticeTab(PracticeTab): babase.app.config["bombRadiusVisual"] = True else: babase.app.config["bombRadiusVisual"] = False + elif setting == 2: + if value: + babase.app.config["powerupsExpire"] = True + else: + babase.app.config["powerupsExpire"] = False def load_settings(self): try: @@ -2204,9 +2224,9 @@ class InfoWindow(popup.PopupWindow): text = ('Practice Tools Mod\n' 'Made By Cross Joy\n' 'version v' + version + '\n' - '\n' - 'Thx to\n' - 'Mikirog for the Bomb radius visualizer mod.\n' + '\n' + 'Thx to\n' + 'Mikirog for the Bomb radius visualizer mod.\n' ) lines = text.splitlines()