Files
autopon/autopon.py
Jacob Babor c14f537a88 Tweaking, tuning, and cleanup
Apparently we need to be using keycodes for this for reliability. Also, the 100ms delay is required, otherwise Patapon (the game, not the emulator or the input layer) won't pick up on it
2025-01-30 04:00:14 -06:00

97 lines
3.2 KiB
Python
Executable File

#! /usr/bin/env python3
import argparse
import subprocess
import time
def ydotool(key):
subprocess.run([
"ydotool",
"key",
str(key) + ":1",
str(key) + ":0",
"--key-delay",
"100"
])
def main():
# A list of all possible songs, expressed as their cardinal directions
# We'll map these to keystrokes later
songs = [
# March of Mobility
"L-L-L-R-",
# Aria of Attack
"R-R-L-R-",
# Lament of Defense
"U-U-L-R-",
# Hold-Tight Hoe-Down/Concerto of Charge
"R-R-U-U-",
# Melody with a Bounce/Jingle of Jump
"D-D-U-U-",
# Ballad of 1999/Pizzicato of Party
"L-R-D-U-",
# Song of Miracles (Djinn)
"D-DD-DD-",
# Leisurely Lullaby
# Not sure why you'd want to cast this on repeat, but you can I guess
"L-R-L-R-",
# Step Back Strut
"U-L-U-L-"
]
# A mapping of characters in our encoded songs to keys to send to ydotool
# These should be the default bindings for PPSSPP
keymapping = {
"U": "31",
"D": "44",
"L": "30",
"R": "45"
}
drummapping = {
"U": '\033[32mCHAKA\033[0m',
"D": '\033[33mDON\033[0m',
"L": '\033[31mPATA\033[0m',
"R": '\033[34mPON\033[0m'
}
parser = argparse.ArgumentParser(
description="Play a sequence of Patapon commands on repeat"
)
parser.add_argument('song',default="R-R-L-R-",nargs="+",choices=songs,help="The song to play. Defaults to Aria of Attack. When expressing a song, use eighth notes, dashes, and cardinal directions to designate the drums. For example, party would be \"L-R-D-U-\", and djinn would be \"D-DD-DD-\"")
parser.add_argument('--bpm',type=float,default=1,help="Multiplier for the BPM. Change if you're running the game at a higher speed")
parser.add_argument('--iterations',type=int,default=10000,help="Number of iterations of the sequence to run. Defaults to 10,000")
args = parser.parse_args()
# Schedule out our beat interval
# 120 Naiive, does not work
# 119.905 Still fast
# 119.900 Still fast
# 119.890
bpm_constant = 119.890
beat_interval = 60 / (bpm_constsant * args.bpm * 2)
print(f"Beat interval: {beat_interval}")
# Set up the environment
sequence='--------' + '--------'.join(args.song)
print(f"Song sequence: {sequence}")
remaining_iterations = args.iterations
lastbeat = 0
# Wait for user confirmation
input("Press enter on-beat to sync up with Patapon...")
synctime = time.perf_counter()
# Play da notes
while remaining_iterations > 0:
for i, key in enumerate(sequence):
while time.perf_counter() < synctime + lastbeat:
pass
lastbeat += beat_interval
button = keymapping.get(key, '-')
if button != '-':
ydotool(button)
print(drummapping.get(key, '-'), end="", flush=True)
else:
print(" ", end="", flush=True)
remaining_iterations -= 1
print(f"~ ({remaining_iterations} remaining)")
main()