# 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__)