mirror of https://github.com/pret/pokecrystal.git
programmatic speedrun of pokecrystal (vba)
This commit is contained in:
parent
6c5ccae807
commit
fe01fb510f
|
@ -0,0 +1,464 @@
|
|||
# -*- 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()
|
Loading…
Reference in New Issue