[ci] auto-format

This commit is contained in:
TheMikirog 2023-01-01 20:03:15 +00:00 committed by Rikko
parent 5e0280df5b
commit 23314581cc

View file

@ -26,7 +26,7 @@ from bastd.actor.spaz import Spaz
if TYPE_CHECKING:
pass
"""
This mod is much more "technical" than my other mods.
I highly recommend checking out the code of this mod once you have a good understanding of programming.
@ -70,6 +70,8 @@ if TYPE_CHECKING:
"""
# ba_meta export plugin
class AutoRun(ba.Plugin):
# During my research and prototyping I figured I'd have to do some linear algebgra.
@ -77,7 +79,7 @@ class AutoRun(ba.Plugin):
# Because of this I made certain functions from scratch that are easily accessible.
# If you are curious over the details, look these up on the Internet.
# I'll only briefly cover their purpose in the context of the mod.
# Here's the dot product function.
# To keep it short, it returns the difference in angle between two vectors.
# We're gonna use that knowledge to check how tight our turn is.
@ -90,11 +92,11 @@ class AutoRun(ba.Plugin):
def clamp(num, min_value, max_value):
num = max(min(num, max_value), min_value)
return num
# A vector can be of any length, but we need them to be of length 1.
# This vector normalization function changes the magnitude of a vector without changing its direction.
def normalize(vector):
length = math.hypot(vector[0], vector[1]) # Pythagoras says hi
length = math.hypot(vector[0], vector[1]) # Pythagoras says hi
# Sometimes we'll get a [0,0] vector and dividing by 0 is iffy.
# Let's leave the vector unchanged if that's the case.
if length > 0:
@ -107,29 +109,29 @@ class AutoRun(ba.Plugin):
# Here I'm defining a new spaz init function that'll be replaced.
def new_init(func):
def wrapper(*args, **kwargs):
# Here's where we execute the original game's code, so it's not lost.
# We want to add our code at the end of the existing code, so our code goes under that.
func(*args, **kwargs)
# We define some variables that we need to keep track of.
# For future reference, if you see args[0] anywhere, that is "self" in the original function.
args[0].autorun_timer: ba.Timer | None = None
args[0].autorun_override = False
# We wanna do our auto run calculations when the player moves their analog stick to make it responsive.
# However doing this ONLY tracks changes in analog stick position and some bugs come up because of that.
# For example moving via dpad on a gamepad can sometimes not execute the run at all.
# To keep the behavior predictable, we also want to update our auto run functionality with a periodic timer.
# We could ignore the update on analog stick movement, but then it feels terrible to play. We need both.
# Update on analog movement for responsive controls, timer to foolproof everything else.
# To make our timer, we want to have access to our function responsible for doing the auto run logic.
# The issue is that timers only work when a function is created within the context of the game.
# Timer throws a tantrum if it references the run_update function, but NOT if that function is an intermediary.
def spaz_autorun_update():
AutoRun.run_update(args[0])
# We don't want this logic to be ran on bots, only players.
# Check if we have a player assigned to that spaz. If we do, let's make our timer.
if args[0].source_player:
@ -138,8 +140,9 @@ class AutoRun(ba.Plugin):
# Notice how it's the capital T Timer instead of the small letter.
# That's important, because big T returns a timer object we can manipulate.
# We need it assigned to a variable, because we have to delete it once it stops being relevant.
args[0].autorun_timer = ba.Timer(0.1, spaz_autorun_update, timetype=TimeType.SIM, repeat=True)
args[0].autorun_timer = ba.Timer(
0.1, spaz_autorun_update, timetype=TimeType.SIM, repeat=True)
return wrapper
# Let's replace the original function with our modified version.
bastd.actor.spaz.Spaz.__init__ = new_init(bastd.actor.spaz.Spaz.__init__)
@ -151,31 +154,31 @@ class AutoRun(ba.Plugin):
# On mobile it's always 0 and 1, but on gamepad you can have values between them
# For example you can do a jog instead of a sprint.
# We activate this function periodically via a timer and every time the player moves their analog stick.
# The idea is to make it 1 when the player is running forward and make it 0
# The idea is to make it 1 when the player is running forward and make it 0
# when the player makes the tightest turn possible.
# We also want to account for how far the analog stick is pushed.
def run_update(self) -> None:
# Let's not run this code if our character does not exist or the player decides to run "manually".
if not self.node or self.autorun_override:
return
# Let's read our player's analog stick.
# Notice how the vertical direction is inverted (there's a minus in front of the variable).
# We want the directions to corespond to the game world.
vertical = -self.node.move_up_down
horizontal = self.node.move_left_right
movement_vector = [horizontal, vertical]
# Get our character's facing direction
facing_direction = (self.node.position[0] - self.node.position_forward[0],
facing_direction = (self.node.position[0] - self.node.position_forward[0],
self.node.position[2] - self.node.position_forward[2])
# We want our character's facing direction to be a normalized vector (magnitude of 1).
facing_direction = AutoRun.normalize(facing_direction)
# We don't want to run our code if the player has their analog stick in a neutral position.
if movement_vector == [0.0, 0.0]:
return
# Get the difference between our current facing direction and where we plan on moving towards.
# Check the dot function higher up in the script for details.
dot = AutoRun.dot(facing_direction, AutoRun.normalize(movement_vector))
@ -184,20 +187,21 @@ class AutoRun(ba.Plugin):
# We want it from 0 to 1.
# 0 being 180 degree turn, 1 being running exactly straight.
dot = (dot + 1) / 2
# Let's read how far our player pushed his stick. 1 being full tilt, 0 being neutral.
run_power = math.hypot(movement_vector[0], movement_vector[1]) # Heres our homie Pythagoras once again
# Heres our homie Pythagoras once again
run_power = math.hypot(movement_vector[0], movement_vector[1])
# I noticed the player starts running too fast if the stick is pushed half-way.
# I changed the linear scale to be exponential.
# easings.net is a great website that shows you different ways of converting a linear curve to some other kind.
# Here I used the EaseInQuad easing, which is just raising the value to the power of 2.
# This should make half-way pushes less severe.
run_power = pow(run_power, 2)
# Just in case let's clamp our value from 0 to 1.
run_power = AutoRun.clamp(run_power, 0.0, 1.0)
# Here we combine our dot result with how far we pushed our stick to get the final running value.
# Clamping from 0 to 1 for good measure.
self.node.run = AutoRun.clamp(run_power * dot, 0.0, 1.0)
@ -215,7 +219,7 @@ class AutoRun(ba.Plugin):
return wrapper
# We replace the character running function with our modified version.
bastd.actor.spaz.Spaz.on_run = new_onrun(bastd.actor.spaz.Spaz.on_run)
# There's two function that are called when our player pushes the analog stick - two for each axis.
# Here's for the vertical axis.
def new_updown(func):
@ -228,7 +232,7 @@ class AutoRun(ba.Plugin):
return wrapper
# You get the idea.
bastd.actor.spaz.Spaz.on_move_up_down = new_updown(bastd.actor.spaz.Spaz.on_move_up_down)
# Let's do the same for our horizontal axis.
# Second verse same as the first.
def new_leftright(func):
@ -237,8 +241,9 @@ class AutoRun(ba.Plugin):
if not args[0].autorun_override and args[0].source_player:
AutoRun.run_update(args[0])
return wrapper
bastd.actor.spaz.Spaz.on_move_left_right = new_leftright(bastd.actor.spaz.Spaz.on_move_left_right)
bastd.actor.spaz.Spaz.on_move_left_right = new_leftright(
bastd.actor.spaz.Spaz.on_move_left_right)
# There's one downside to the looping timer - it runs constantly even if the player is dead.
# We don't want to waste computational power on something like that.
# Let's kill our timer when the player dies.