shithub: pokecrystal

Download patch

ref: fe01fb510ff87310de1ecbce73f74d1a390d557c
parent: 6c5ccae8078fd753314b5c63ba7c4a4b9e2ae402
author: Bryan Bishop <[email protected]>
date: Sun Jun 16 13:17:37 EDT 2013

programmatic speedrun of pokecrystal (vba)

--- /dev/null
+++ b/extras/vba_autoplayer.py
@@ -1,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()