pokecrystal/extras/vba_autoplayer.py

465 lines
10 KiB
Python

# -*- coding: utf-8 -*-
"""
Programmatic speedrun of Pokémon Crystal
"""
import os
# bring in the emulator and basic tools
import vba
def main():
"""
Start the game.
"""
vba.load_rom()
# get past the opening sequence
skip_intro()
# walk to mom and handle her text
handle_mom()
# walk to elm and do whatever he wants
handle_elm("totodile")
new_bark_level_grind(10, skip=False)
def skippable(func):
"""
Makes a function skippable by saving the state before and after the
function runs. Pass "skip=True" to the function to load the previous save
state from when the function finished.
"""
def wrapped_function(*args, **kwargs):
skip = True
if "skip" in kwargs.keys():
skip = kwargs["skip"]
del kwargs["skip"]
# override skip if there's no save
if skip:
full_name = func.__name__ + "-end.sav"
if not os.path.exists(os.path.join(vba.save_state_path, full_name)):
skip = False
return_value = None
if not skip:
vba.save_state(func.__name__ + "-start", override=True)
return_value = func(*args, **kwargs)
vba.save_state(func.__name__ + "-end", override=True)
elif skip:
vba.set_state(vba.load_state(func.__name__ + "-end"))
return return_value
return wrapped_function
@skippable
def skip_intro():
"""
Skip the game boot intro sequence.
"""
# copyright sequence
vba.nstep(400)
# skip the ditto sequence
vba.press("a")
vba.nstep(100)
# skip the start screen
vba.press("start")
vba.nstep(100)
# click "new game"
vba.press("a", holdsteps=50, aftersteps=1)
# Are you a boy? Or are you a girl?
vba.nstep(145)
# pick "boy"
vba.press("a", holdsteps=50, aftersteps=1)
# ....
vba.crystal.text_wait()
vba.crystal.text_wait()
# What time is it?
vba.crystal.text_wait()
# DAY 10 o'clock
vba.press("a", holdsteps=50, aftersteps=1)
# WHAT? DAY 10 o'clock? YES/NO.
vba.press("a", holdsteps=50, aftersteps=1)
# How many minutes? 0 min.
vba.press("a", holdsteps=50, aftersteps=1)
# Whoa! 0 min.? YES/NO.
vba.press("a", holdsteps=50, aftersteps=1)
vba.crystal.text_wait()
vba.crystal.text_wait()
# People call me
vba.crystal.text_wait()
vba.crystal.text_wait()
# tures that we call
vba.crystal.text_wait()
vba.crystal.text_wait()
vba.crystal.text_wait()
vba.crystal.text_wait()
vba.crystal.text_wait()
vba.crystal.text_wait()
# everything about pokemon yet.
vba.crystal.text_wait()
vba.crystal.text_wait()
vba.crystal.text_wait()
vba.crystal.text_wait()
vba.crystal.text_wait()
vba.crystal.text_wait()
# Now, what did you say your name was?
vba.crystal.text_wait()
# move down to "CHRIS"
vba.press("d")
vba.nstep(50)
vba.press("a", holdsteps=50, aftersteps=1)
vba.crystal.text_wait()
vba.crystal.text_wait()
vba.crystal.text_wait()
vba.crystal.text_wait()
vba.crystal.text_wait()
vba.crystal.text_wait()
vba.crystal.text_wait()
# wait until playable
# could be 150, but it sometimes takes longer??
vba.nstep(200)
return
@skippable
def handle_mom():
"""
Walk to mom. Handle her speech and questions.
"""
vba.press("r"); vba.nstep(50)
vba.press("r"); vba.nstep(50)
vba.press("r"); vba.nstep(50)
vba.press("r"); vba.nstep(50)
vba.press("r"); vba.nstep(50)
vba.press("u"); vba.nstep(50)
vba.press("u"); vba.nstep(50)
vba.press("u"); vba.nstep(50)
vba.press("u"); vba.nstep(50)
# wait for next map to load
vba.nstep(50)
vba.press("d"); vba.nstep(50)
vba.press("d"); vba.nstep(50)
vba.press("d"); vba.nstep(50)
# walk into mom's line of sight
vba.press("d"); vba.nstep(50)
vba.nstep(50)
vba.crystal.text_wait()
vba.crystal.text_wait()
vba.crystal.text_wait()
vba.crystal.text_wait()
vba.crystal.text_wait()
vba.crystal.text_wait()
vba.crystal.text_wait()
vba.crystal.text_wait()
vba.crystal.text_wait()
vba.crystal.text_wait()
vba.crystal.text_wait()
vba.crystal.text_wait()
# What day is it? SUNDAY.
vba.press("a", holdsteps=50, aftersteps=1)
# SUNDAY, is it? YES/NO
vba.press("a", holdsteps=50, aftersteps=1)
vba.nstep(200)
# is it DST now? YES/NO.
vba.press("a", holdsteps=50, aftersteps=1)
# 10:06 AM DST, is that OK? YES/NO.
vba.press("a", holdsteps=50, aftersteps=1)
vba.crystal.text_wait()
vba.crystal.text_wait()
vba.crystal.text_wait()
# know how to use the PHONE? YES/NO.
vba.press("a", holdsteps=50, aftersteps=1)
vba.crystal.text_wait()
vba.crystal.text_wait()
vba.crystal.text_wait()
vba.crystal.text_wait()
vba.press("a", holdsteps=50, aftersteps=1)
# have to wait for her to move back :(
vba.nstep(50)
# face down
vba.press("d"); vba.nstep(50)
return
@skippable
def handle_elm(starter_choice):
"""
Walk to Elm's Lab and get a starter.
"""
# walk down
vba.press("d"); vba.nstep(50)
vba.press("d"); vba.nstep(50)
# face left
vba.press("l"); vba.nstep(50)
# walk left
vba.press("l"); vba.nstep(50)
vba.press("l"); vba.nstep(50)
# face down
vba.press("d"); vba.nstep(50)
# walk down
vba.press("d"); vba.nstep(50)
# walk down to warp to outside
vba.press("d"); vba.nstep(50)
vba.nstep(10)
vba.press("l", holdsteps=10, aftersteps=50)
vba.press("l", holdsteps=10, aftersteps=50)
vba.press("l", holdsteps=10, aftersteps=50)
vba.press("l", holdsteps=10, aftersteps=50)
vba.press("l", holdsteps=10, aftersteps=50)
vba.press("l", holdsteps=10, aftersteps=50)
vba.press("l", holdsteps=10, aftersteps=50)
vba.press("u", holdsteps=10, aftersteps=50)
vba.press("u", holdsteps=10, aftersteps=50)
# warp into elm's lab (bottom left warp)
vba.press("u", holdsteps=5, aftersteps=50)
# let the script play
vba.nstep(200)
vba.crystal.text_wait()
# I needed to ask you a fa
vba.crystal.text_wait()
vba.crystal.text_wait()
vba.crystal.text_wait()
vba.crystal.text_wait()
vba.crystal.text_wait()
vba.crystal.text_wait()
vba.crystal.text_wait()
vba.crystal.text_wait()
vba.crystal.text_wait()
vba.crystal.text_wait()
vba.crystal.text_wait()
vba.nstep(50)
# YES/NO.
vba.press("a")
vba.crystal.text_wait()
vba.crystal.text_wait()
vba.crystal.text_wait()
vba.crystal.text_wait()
vba.crystal.text_wait()
vba.press("a")
vba.crystal.text_wait()
vba.crystal.text_wait()
vba.press("a")
vba.crystal.text_wait()
vba.crystal.text_wait()
vba.crystal.text_wait()
for x in range(0, 8): # was 15
vba.crystal.text_wait()
vba.nstep(50)
vba.press("a")
vba.nstep(100)
vba.crystal.text_wait()
vba.crystal.text_wait()
vba.crystal.text_wait()
vba.crystal.text_wait()
# Go on! Pick one.
vba.nstep(100)
vba.press("a"); vba.nstep(50)
vba.press("r"); vba.nstep(50)
vba.press("r"); vba.nstep(50)
right = 0
if starter_choice in [1, "cyndaquil"]:
right = 0
elif starter_choice in [2, "totodile"]:
right = 1
elif starter_choice in [3, "chikorita"]:
right = 2
else:
raise Exception("bad starter")
for each in range(0, right):
vba.press("r"); vba.nstep(50)
# look up
vba.press("u", holdsteps=5, aftersteps=50)
# get menu
vba.press("a", holdsteps=5, aftersteps=50)
# let the image show
vba.nstep(100)
vba.crystal.text_wait()
vba.crystal.text_wait()
# YES/NO.
vba.press("a")
vba.crystal.text_wait()
vba.crystal.text_wait()
# received.. music is playing.
vba.press("a")
vba.crystal.text_wait()
# YES/NO (nickname)
vba.crystal.text_wait()
vba.press("b")
# get back to elm
vba.nstep(100)
vba.nstep(100)
vba.crystal.text_wait()
vba.crystal.text_wait()
vba.crystal.text_wait()
vba.crystal.text_wait()
vba.crystal.text_wait()
# phone number..
vba.press("a")
vba.crystal.text_wait()
vba.nstep(100)
vba.press("a")
vba.nstep(300)
vba.press("a")
vba.nstep(100)
vba.crystal.text_wait()
vba.crystal.text_wait()
vba.crystal.text_wait()
# I'm counting on you!
vba.nstep(200)
vba.press("a")
vba.nstep(50)
# look down
vba.press("d", holdsteps=5, aftersteps=50)
# walk down
vba.press("d", holdsteps=10, aftersteps=50)
vba.press("d", holdsteps=10, aftersteps=50)
vba.press("d", holdsteps=10, aftersteps=50)
vba.press("d", holdsteps=10, aftersteps=50)
vba.press("d", holdsteps=10, aftersteps=50)
vba.crystal.text_wait()
vba.crystal.text_wait()
vba.press("a")
vba.nstep(50)
vba.press("a")
vba.crystal.text_wait()
vba.crystal.text_wait()
vba.press("a")
vba.nstep(50)
vba.crystal.text_wait()
vba.press("a")
vba.nstep(100)
vba.press("d", holdsteps=10, aftersteps=50)
vba.press("d", holdsteps=10, aftersteps=50)
vba.press("d", holdsteps=10, aftersteps=50)
vba.press("d", holdsteps=10, aftersteps=50)
# step outside
vba.nstep(40)
@skippable
def new_bark_level_grind(level):
"""
Starting just outside of Elm's Lab, do some level grinding until the first
partymon level is equal to the given value..
"""
# walk to the grass area
new_bark_level_grind_walk_to_grass(skip=False)
# TODO: walk around in grass, handle battles
# TODO: heal at the lab, then repeat entire function
@skippable
def new_bark_level_grind_travel_to_grass():
"""
Move to just above the grass.
"""
vba.press("d", holdsteps=10, aftersteps=50)
vba.press("d", holdsteps=10, aftersteps=50)
vba.press("d", holdsteps=10, aftersteps=50)
vba.press("l", holdsteps=10, aftersteps=50)
vba.press("l", holdsteps=10, aftersteps=50)
vba.press("l", holdsteps=10, aftersteps=50)
vba.press("l", holdsteps=10, aftersteps=50)
vba.press("d", holdsteps=10, aftersteps=50)
vba.press("d", holdsteps=10, aftersteps=50)
if __name__ == "__main__":
main()