mirror of
https://github.com/bombsquad-community/plugin-manager.git
synced 2025-10-08 14:54:36 +00:00
[ci] auto-format
This commit is contained in:
parent
5e0280df5b
commit
23314581cc
1 changed files with 31 additions and 26 deletions
|
|
@ -26,7 +26,7 @@ from bastd.actor.spaz import Spaz
|
||||||
|
|
||||||
if TYPE_CHECKING:
|
if TYPE_CHECKING:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
"""
|
"""
|
||||||
This mod is much more "technical" than my other mods.
|
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.
|
I highly recommend checking out the code of this mod once you have a good understanding of programming.
|
||||||
|
|
@ -70,6 +70,8 @@ if TYPE_CHECKING:
|
||||||
"""
|
"""
|
||||||
|
|
||||||
# ba_meta export plugin
|
# ba_meta export plugin
|
||||||
|
|
||||||
|
|
||||||
class AutoRun(ba.Plugin):
|
class AutoRun(ba.Plugin):
|
||||||
|
|
||||||
# During my research and prototyping I figured I'd have to do some linear algebgra.
|
# 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.
|
# 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.
|
# 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.
|
# I'll only briefly cover their purpose in the context of the mod.
|
||||||
|
|
||||||
# Here's the dot product function.
|
# Here's the dot product function.
|
||||||
# To keep it short, it returns the difference in angle between two vectors.
|
# 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.
|
# We're gonna use that knowledge to check how tight our turn is.
|
||||||
|
|
@ -90,11 +92,11 @@ class AutoRun(ba.Plugin):
|
||||||
def clamp(num, min_value, max_value):
|
def clamp(num, min_value, max_value):
|
||||||
num = max(min(num, max_value), min_value)
|
num = max(min(num, max_value), min_value)
|
||||||
return num
|
return num
|
||||||
|
|
||||||
# A vector can be of any length, but we need them to be of length 1.
|
# 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.
|
# This vector normalization function changes the magnitude of a vector without changing its direction.
|
||||||
def normalize(vector):
|
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.
|
# 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.
|
# Let's leave the vector unchanged if that's the case.
|
||||||
if length > 0:
|
if length > 0:
|
||||||
|
|
@ -107,29 +109,29 @@ class AutoRun(ba.Plugin):
|
||||||
# Here I'm defining a new spaz init function that'll be replaced.
|
# Here I'm defining a new spaz init function that'll be replaced.
|
||||||
def new_init(func):
|
def new_init(func):
|
||||||
def wrapper(*args, **kwargs):
|
def wrapper(*args, **kwargs):
|
||||||
|
|
||||||
# Here's where we execute the original game's code, so it's not lost.
|
# 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.
|
# We want to add our code at the end of the existing code, so our code goes under that.
|
||||||
func(*args, **kwargs)
|
func(*args, **kwargs)
|
||||||
|
|
||||||
# We define some variables that we need to keep track of.
|
# 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.
|
# 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: ba.Timer | None = None
|
||||||
args[0].autorun_override = False
|
args[0].autorun_override = False
|
||||||
|
|
||||||
# We wanna do our auto run calculations when the player moves their analog stick to make it responsive.
|
# 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.
|
# 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.
|
# 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.
|
# 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.
|
# 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.
|
# 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.
|
# 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.
|
# 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.
|
# Timer throws a tantrum if it references the run_update function, but NOT if that function is an intermediary.
|
||||||
def spaz_autorun_update():
|
def spaz_autorun_update():
|
||||||
AutoRun.run_update(args[0])
|
AutoRun.run_update(args[0])
|
||||||
|
|
||||||
# We don't want this logic to be ran on bots, only players.
|
# 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.
|
# Check if we have a player assigned to that spaz. If we do, let's make our timer.
|
||||||
if args[0].source_player:
|
if args[0].source_player:
|
||||||
|
|
@ -138,8 +140,9 @@ class AutoRun(ba.Plugin):
|
||||||
# Notice how it's the capital T Timer instead of the small letter.
|
# 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.
|
# 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.
|
# 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
|
return wrapper
|
||||||
# Let's replace the original function with our modified version.
|
# Let's replace the original function with our modified version.
|
||||||
bastd.actor.spaz.Spaz.__init__ = new_init(bastd.actor.spaz.Spaz.__init__)
|
bastd.actor.spaz.Spaz.__init__ = new_init(bastd.actor.spaz.Spaz.__init__)
|
||||||
|
|
@ -151,31 +154,31 @@ class AutoRun(ba.Plugin):
|
||||||
# On mobile it's always 0 and 1, but on gamepad you can have values between them
|
# 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.
|
# 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.
|
# 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.
|
# when the player makes the tightest turn possible.
|
||||||
# We also want to account for how far the analog stick is pushed.
|
# We also want to account for how far the analog stick is pushed.
|
||||||
def run_update(self) -> None:
|
def run_update(self) -> None:
|
||||||
# Let's not run this code if our character does not exist or the player decides to run "manually".
|
# 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:
|
if not self.node or self.autorun_override:
|
||||||
return
|
return
|
||||||
|
|
||||||
# Let's read our player's analog stick.
|
# Let's read our player's analog stick.
|
||||||
# Notice how the vertical direction is inverted (there's a minus in front of the variable).
|
# 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.
|
# We want the directions to corespond to the game world.
|
||||||
vertical = -self.node.move_up_down
|
vertical = -self.node.move_up_down
|
||||||
horizontal = self.node.move_left_right
|
horizontal = self.node.move_left_right
|
||||||
movement_vector = [horizontal, vertical]
|
movement_vector = [horizontal, vertical]
|
||||||
|
|
||||||
# Get our character's facing direction
|
# 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])
|
self.node.position[2] - self.node.position_forward[2])
|
||||||
# We want our character's facing direction to be a normalized vector (magnitude of 1).
|
# We want our character's facing direction to be a normalized vector (magnitude of 1).
|
||||||
facing_direction = AutoRun.normalize(facing_direction)
|
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.
|
# 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]:
|
if movement_vector == [0.0, 0.0]:
|
||||||
return
|
return
|
||||||
|
|
||||||
# Get the difference between our current facing direction and where we plan on moving towards.
|
# 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.
|
# Check the dot function higher up in the script for details.
|
||||||
dot = AutoRun.dot(facing_direction, AutoRun.normalize(movement_vector))
|
dot = AutoRun.dot(facing_direction, AutoRun.normalize(movement_vector))
|
||||||
|
|
@ -184,20 +187,21 @@ class AutoRun(ba.Plugin):
|
||||||
# We want it from 0 to 1.
|
# We want it from 0 to 1.
|
||||||
# 0 being 180 degree turn, 1 being running exactly straight.
|
# 0 being 180 degree turn, 1 being running exactly straight.
|
||||||
dot = (dot + 1) / 2
|
dot = (dot + 1) / 2
|
||||||
|
|
||||||
# Let's read how far our player pushed his stick. 1 being full tilt, 0 being neutral.
|
# 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 noticed the player starts running too fast if the stick is pushed half-way.
|
||||||
# I changed the linear scale to be exponential.
|
# 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.
|
# 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.
|
# 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.
|
# This should make half-way pushes less severe.
|
||||||
run_power = pow(run_power, 2)
|
run_power = pow(run_power, 2)
|
||||||
|
|
||||||
# Just in case let's clamp our value from 0 to 1.
|
# Just in case let's clamp our value from 0 to 1.
|
||||||
run_power = AutoRun.clamp(run_power, 0.0, 1.0)
|
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.
|
# 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.
|
# Clamping from 0 to 1 for good measure.
|
||||||
self.node.run = AutoRun.clamp(run_power * dot, 0.0, 1.0)
|
self.node.run = AutoRun.clamp(run_power * dot, 0.0, 1.0)
|
||||||
|
|
@ -215,7 +219,7 @@ class AutoRun(ba.Plugin):
|
||||||
return wrapper
|
return wrapper
|
||||||
# We replace the character running function with our modified version.
|
# We replace the character running function with our modified version.
|
||||||
bastd.actor.spaz.Spaz.on_run = new_onrun(bastd.actor.spaz.Spaz.on_run)
|
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.
|
# There's two function that are called when our player pushes the analog stick - two for each axis.
|
||||||
# Here's for the vertical axis.
|
# Here's for the vertical axis.
|
||||||
def new_updown(func):
|
def new_updown(func):
|
||||||
|
|
@ -228,7 +232,7 @@ class AutoRun(ba.Plugin):
|
||||||
return wrapper
|
return wrapper
|
||||||
# You get the idea.
|
# You get the idea.
|
||||||
bastd.actor.spaz.Spaz.on_move_up_down = new_updown(bastd.actor.spaz.Spaz.on_move_up_down)
|
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.
|
# Let's do the same for our horizontal axis.
|
||||||
# Second verse same as the first.
|
# Second verse same as the first.
|
||||||
def new_leftright(func):
|
def new_leftright(func):
|
||||||
|
|
@ -237,8 +241,9 @@ class AutoRun(ba.Plugin):
|
||||||
if not args[0].autorun_override and args[0].source_player:
|
if not args[0].autorun_override and args[0].source_player:
|
||||||
AutoRun.run_update(args[0])
|
AutoRun.run_update(args[0])
|
||||||
return wrapper
|
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.
|
# 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.
|
# We don't want to waste computational power on something like that.
|
||||||
# Let's kill our timer when the player dies.
|
# Let's kill our timer when the player dies.
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue