diff options
Diffstat (limited to 'pokemontools')
| -rw-r--r-- | pokemontools/vba/autoplayer.py | 742 | 
1 files changed, 378 insertions, 364 deletions
| diff --git a/pokemontools/vba/autoplayer.py b/pokemontools/vba/autoplayer.py index 9aa8f4a..a63caa8 100644 --- a/pokemontools/vba/autoplayer.py +++ b/pokemontools/vba/autoplayer.py @@ -5,27 +5,7 @@ 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 outside into new bark town -    walk_into_new_bark_town() - -    # walk to elm and do whatever he wants -    handle_elm("totodile") - -    new_bark_level_grind(10, skip=False) +import vba as _vba  def skippable(func):      """ @@ -51,445 +31,479 @@ def skippable(func):          return_value = None          if not skip: -            vba.save_state(func.__name__ + "-start", override=True) +            _vba.save_state(func.__name__ + "-start", override=True)              return_value = func(*args, **kwargs) -            vba.save_state(func.__name__ + "-end", override=True) +            _vba.save_state(func.__name__ + "-end", override=True)          elif skip: -            vba.set_state(vba.load_state(func.__name__ + "-end")) +            _vba.set_state(vba.load_state(func.__name__ + "-end"))          return return_value      return wrapped_function -@skippable -def skip_intro(): +class Runner(object):      """ -    Skip the game boot intro sequence. +    ``Runner`` is used to represent a set of functions that control an instance +    of the emulator. This allows for automated runs of games.      """ +    pass -    # copyright sequence -    vba.nstep(400) +class SpeedRunner(Runner): +    def setup(self): +        self.cry = _vba.crystal() -    # skip the ditto sequence -    vba.press("a") -    vba.nstep(100) +    def main(self): +        """ +        Start the game. +        """ +        # get past the opening sequence +        self.skip_intro() -    # skip the start screen -    vba.press("start") -    vba.nstep(100) +        # walk to mom and handle her text +        self.handle_mom() -    # click "new game" -    vba.press("a", holdsteps=50, aftersteps=1) +        # walk outside into new bark town +        self.walk_into_new_bark_town() -    # skip text up to "Are you a boy? Or are you a girl?" -    vba.crystal.text_wait() +        # walk to elm and do whatever he wants +        self.handle_elm("totodile") -    # select "Boy" -    vba.press("a", holdsteps=50, aftersteps=1) +        self.new_bark_level_grind(10, skip=False) -    # text until "What time is it?" -    vba.crystal.text_wait() +    @skippable +    def skip_intro(self): +        """ +        Skip the game boot intro sequence. +        """ -    # select 10 o'clock -    vba.press("a", holdsteps=50, aftersteps=1) +        # copyright sequence +        self.cry.nstep(400) -    # yes i mean it -    vba.press("a", holdsteps=50, aftersteps=1) +        # skip the ditto sequence +        self.cry.press("a") +        self.cry.nstep(100) -    # "How many minutes?" 0 min. -    vba.press("a", holdsteps=50, aftersteps=1) +        # skip the start screen +        self.cry.press("start") +        self.cry.nstep(100) -    # "Who! 0 min.?" yes/no select yes -    vba.press("a", holdsteps=50, aftersteps=1) +        # click "new game" +        self.cry.press("a", holdsteps=50, aftersteps=1) -    # read text until name selection -    vba.crystal.text_wait() +        # skip text up to "Are you a boy? Or are you a girl?" +        self.cry.text_wait() -    # select "Chris" -    vba.press("d", holdsteps=10, aftersteps=1) -    vba.press("a", holdsteps=50, aftersteps=1) +        # select "Boy" +        self.cry.press("a", holdsteps=50, aftersteps=1) -    def overworldcheck(): -        """ -        A basic check for when the game starts. -        """ -        return vba.get_memory_at(0xcfb1) != 0 +        # text until "What time is it?" +        self.cry.text_wait() -    # go until the introduction is done -    vba.crystal.text_wait(callback=overworldcheck) +        # select 10 o'clock +        self.cry.press("a", holdsteps=50, aftersteps=1) -    return +        # yes i mean it +        self.cry.press("a", holdsteps=50, aftersteps=1) -@skippable -def handle_mom(): -    """ -    Walk to mom. Handle her speech and questions. -    """ +        # "How many minutes?" 0 min. +        self.cry.press("a", holdsteps=50, aftersteps=1) -    vba.crystal.move("r") -    vba.crystal.move("r") -    vba.crystal.move("r") -    vba.crystal.move("r") +        # "Who! 0 min.?" yes/no select yes +        self.cry.press("a", holdsteps=50, aftersteps=1) -    vba.crystal.move("u") -    vba.crystal.move("u") -    vba.crystal.move("u") +        # read text until name selection +        self.cry.text_wait() -    vba.crystal.move("d") -    vba.crystal.move("d") +        # select "Chris" +        self.cry.press("d", holdsteps=10, aftersteps=1) +        self.cry.press("a", holdsteps=50, aftersteps=1) -    # move into mom's line of sight -    vba.crystal.move("d") +        def overworldcheck(): +            """ +            A basic check for when the game starts. +            """ +            return self.cry.vba.memory[0xcfb1] != 0 -    # let mom talk until "What day is it?" -    vba.crystal.text_wait() +        # go until the introduction is done +        self.cry.text_wait(callback=overworldcheck) -    # "What day is it?" Sunday -    vba.press("a", holdsteps=10) # Sunday +        return -    vba.crystal.text_wait() +    @skippable +    def handle_mom(self): +        """ +        Walk to mom. Handle her speech and questions. +        """ -    # "SUNDAY, is it?" yes/no -    vba.press("a", holdsteps=10) # yes +        self.cry.move("r") +        self.cry.move("r") +        self.cry.move("r") +        self.cry.move("r") -    vba.crystal.text_wait() +        self.cry.move("u") +        self.cry.move("u") +        self.cry.move("u") -    # "Is it Daylight Saving Time now?" yes/no -    vba.press("a", holdsteps=10) # yes +        self.cry.move("d") +        self.cry.move("d") -    vba.crystal.text_wait() +        # move into mom's line of sight +        self.cry.move("d") -    # "AM DST, is that OK?" yes/no -    vba.press("a", holdsteps=10) # yes +        # let mom talk until "What day is it?" +        self.cry.text_wait() -    # text until "know how to use the PHONE?" yes/no -    vba.crystal.text_wait() +        # "What day is it?" Sunday +        self.cry.vba.press("a", holdsteps=10) # Sunday -    # press yes -    vba.press("a", holdsteps=10) +        self.cry.text_wait() -    # wait until mom is done talking -    vba.crystal.text_wait() +        # "SUNDAY, is it?" yes/no +        self.cry.vba.press("a", holdsteps=10) # yes -    # wait until the script is done running -    vba.crystal.wait_for_script_running() +        self.cry.text_wait() -    return +        # "Is it Daylight Saving Time now?" yes/no +        self.cry.vba.press("a", holdsteps=10) # yes -@skippable -def walk_into_new_bark_town(): -    """ -    Walk outside after talking with mom. -    """ +        self.cry.text_wait() -    vba.crystal.move("d") -    vba.crystal.move("d") -    vba.crystal.move("d") -    vba.crystal.move("l") -    vba.crystal.move("l") +        # "AM DST, is that OK?" yes/no +        self.cry.vba.press("a", holdsteps=10) # yes -    # walk outside -    vba.crystal.move("d") +        # text until "know how to use the PHONE?" yes/no +        self.cry.text_wait() -@skippable -def handle_elm(starter_choice): -    """ -    Walk to Elm's Lab and get a starter. -    """ +        # press yes +        self.cry.vba.press("a", holdsteps=10) -    # walk to the lab -    vba.crystal.move("l") -    vba.crystal.move("l") -    vba.crystal.move("l") -    vba.crystal.move("l") -    vba.crystal.move("l") -    vba.crystal.move("l") -    vba.crystal.move("l") -    vba.crystal.move("u") -    vba.crystal.move("u") +        # wait until mom is done talking +        self.cry.text_wait() -    # walk into the lab -    vba.crystal.move("u") +        # wait until the script is done running +        self.cry.wait_for_script_running() -    # talk to elm -    vba.crystal.text_wait() +        return -    # "that I recently caught." yes/no -    vba.press("a", holdsteps=10) # yes +    @skippable +    def walk_into_new_bark_town(self): +        """ +        Walk outside after talking with mom. +        """ -    # talk to elm some more -    vba.crystal.text_wait() +        self.cry.move("d") +        self.cry.move("d") +        self.cry.move("d") +        self.cry.move("l") +        self.cry.move("l") -    # talking isn't done yet.. -    vba.crystal.text_wait() -    vba.crystal.text_wait() -    vba.crystal.text_wait() +        # walk outside +        self.cry.move("d") -    # wait until the script is done running -    vba.crystal.wait_for_script_running() +    @skippable +    def handle_elm(self, starter_choice): +        """ +        Walk to Elm's Lab and get a starter. +        """ + +        # walk to the lab +        self.cry.move("l") +        self.cry.move("l") +        self.cry.move("l") +        self.cry.move("l") +        self.cry.move("l") +        self.cry.move("l") +        self.cry.move("l") +        self.cry.move("u") +        self.cry.move("u") + +        # walk into the lab +        self.cry.move("u") + +        # talk to elm +        self.cry.text_wait() + +        # "that I recently caught." yes/no +        self.cry.vba.press("a", holdsteps=10) # yes + +        # talk to elm some more +        self.cry.text_wait() + +        # talking isn't done yet.. +        self.cry.text_wait() +        self.cry.text_wait() +        self.cry.text_wait() -    # move toward the pokeballs -    vba.crystal.move("r") +        # wait until the script is done running +        self.cry.wait_for_script_running() -    # move to cyndaquil -    vba.crystal.move("r") +        # move toward the pokeballs +        self.cry.move("r") -    moves = 0 +        # move to cyndaquil +        self.cry.move("r") -    if starter_choice.lower() == "cyndaquil":          moves = 0 -    if starter_choice.lower() == "totodile": -        moves = 1 -    else: -        moves = 2 -    for each in range(0, moves): -        vba.crystal.move("r") +        if starter_choice.lower() == "cyndaquil": +            moves = 0 +        if starter_choice.lower() == "totodile": +            moves = 1 +        else: +            moves = 2 -    # face the pokeball -    vba.crystal.move("u") +        for each in range(0, moves): +            self.cry.move("r") -    # select it -    vba.press("a", holdsteps=10, aftersteps=0) +        # face the pokeball +        self.cry.move("u") -    # wait for the image to pop up -    vba.crystal.text_wait() +        # select it +        self.cry.vba.press("a", holdsteps=10, aftersteps=0) -    # wait for the image to close -    vba.crystal.text_wait() +        # wait for the image to pop up +        self.cry.text_wait() -    # wait for the yes/no box -    vba.crystal.text_wait() +        # wait for the image to close +        self.cry.text_wait() -    # press yes -    vba.press("a", holdsteps=10, aftersteps=0) +        # wait for the yes/no box +        self.cry.text_wait() -    # wait for elm to talk a bit -    vba.crystal.text_wait() +        # press yes +        self.cry.vba.press("a", holdsteps=10, aftersteps=0) -    # TODO: why didn't that finish his talking? -    vba.crystal.text_wait() +        # wait for elm to talk a bit +        self.cry.text_wait() -    # give a nickname? yes/no -    vba.press("d", holdsteps=10, aftersteps=0) # move to "no" -    vba.press("a", holdsteps=10, aftersteps=0) # no +        # TODO: why didn't that finish his talking? +        self.cry.text_wait() -    # TODO: why didn't this wait until he was completely done? -    vba.crystal.text_wait() -    vba.crystal.text_wait() +        # give a nickname? yes/no +        self.cry.vba.press("d", holdsteps=10, aftersteps=0) # move to "no" +        self.cry.vba.press("a", holdsteps=10, aftersteps=0) # no -    # get the phone number -    vba.crystal.text_wait() +        # TODO: why didn't this wait until he was completely done? +        self.cry.text_wait() +        self.cry.text_wait() -    # talk with elm a bit more -    vba.crystal.text_wait() +        # get the phone number +        self.cry.text_wait() -    # TODO: and again.. wtf? -    vba.crystal.text_wait() +        # talk with elm a bit more +        self.cry.text_wait() -    # wait until the script is done running -    vba.crystal.wait_for_script_running() +        # TODO: and again.. wtf? +        self.cry.text_wait() -    # move down -    vba.crystal.move("d") -    vba.crystal.move("d") -    vba.crystal.move("d") -    vba.crystal.move("d") +        # wait until the script is done running +        self.cry.wait_for_script_running() -    # move into the researcher's line of sight -    vba.crystal.move("d") +        # move down +        self.cry.move("d") +        self.cry.move("d") +        self.cry.move("d") +        self.cry.move("d") -    # get the potion from the person -    vba.crystal.text_wait() -    vba.crystal.text_wait() +        # move into the researcher's line of sight +        self.cry.move("d") -    # wait for the script to end -    vba.crystal.wait_for_script_running() +        # get the potion from the person +        self.cry.text_wait() +        self.cry.text_wait() -    vba.crystal.move("d") -    vba.crystal.move("d") -    vba.crystal.move("d") +        # wait for the script to end +        self.cry.wait_for_script_running() -    # go outside -    vba.crystal.move("d") +        self.cry.move("d") +        self.cry.move("d") +        self.cry.move("d") -    return +        # go outside +        self.cry.move("d") -@skippable -def new_bark_level_grind(level): -    """ -    Do level grinding in New Bark. +        return -    Starting just outside of Elm's Lab, do some level grinding until the first -    partymon level is equal to the given value.. -    """ +    @skippable +    def new_bark_level_grind(self, level): +        """ +        Do level grinding in New Bark. -    # walk to the grass area -    new_bark_level_grind_walk_to_grass(skip=False) +        Starting just outside of Elm's Lab, do some level grinding until the +        first partymon level is equal to the given value.. +        """ -    # TODO: walk around in grass, handle battles -    walk = ["d", "d", "u", "d", "u", "d"] -    for direction in walk: -        vba.crystal.move(direction) +        # walk to the grass area +        self.new_bark_level_grind_walk_to_grass(skip=False) -    # wait for wild battle to completely start -    vba.crystal.text_wait() +        # TODO: walk around in grass, handle battles +        walk = ["d", "d", "u", "d", "u", "d"] +        for direction in walk: +            self.cry.move(direction) -    attacks = 5 +        # wait for wild battle to completely start +        self.cry.text_wait() -    while attacks > 0: -        # FIGHT -        vba.press("a", holdsteps=10, aftersteps=1) +        attacks = 5 -        # wait to select a move -        vba.crystal.text_wait() +        while attacks > 0: +            # FIGHT +            self.cry.vba.press("a", holdsteps=10, aftersteps=1) -        # SCRATCH -        vba.press("a", holdsteps=10, aftersteps=1) +            # wait to select a move +            self.cry.text_wait() -        # wait for the move to be over -        vba.crystal.text_wait() +            # SCRATCH +            self.cry.vba.press("a", holdsteps=10, aftersteps=1) -        hp = ((vba.get_memory_at(0xd218) << 8) | vba.get_memory_at(0xd217)) -        print "enemy hp is: " + str(hp) +            # wait for the move to be over +            self.cry.text_wait() -        if hp == 0: -            print "enemy hp is zero, exiting" -            break -        else: +            hp = ((self.cry.vba.get_memory_at(0xd218) << 8) | self.cry.vba.get_memory_at(0xd217))              print "enemy hp is: " + str(hp) -        attacks = attacks - 1 - -    while vba.get_memory_at(0xd22d) != 0: -        vba.press("a", holdsteps=10, aftersteps=1) - -    # wait for the map to finish loading -    vba.nstep(50) - -    print "okay, back in the overworld" - -    # move up -    vba.crystal.move("u") -    vba.crystal.move("u") -    vba.crystal.move("u") -    vba.crystal.move("u") - -    # move into new bark town -    vba.crystal.move("r") -    vba.crystal.move("r") -    vba.crystal.move("r") -    vba.crystal.move("r") -    vba.crystal.move("r") -    vba.crystal.move("r") -    vba.crystal.move("r") -    vba.crystal.move("r") -    vba.crystal.move("r") -    vba.crystal.move("r") - -    # move up -    vba.crystal.move("u") -    vba.crystal.move("u") -    vba.crystal.move("u") -    vba.crystal.move("u") -    vba.crystal.move("u") - -    # move to the door -    vba.crystal.move("r") -    vba.crystal.move("r") -    vba.crystal.move("r") - -    # walk in -    vba.crystal.move("u") - -    # move up to the healing thing -    vba.crystal.move("u") -    vba.crystal.move("u") -    vba.crystal.move("u") -    vba.crystal.move("u") -    vba.crystal.move("u") -    vba.crystal.move("u") -    vba.crystal.move("u") -    vba.crystal.move("u") -    vba.crystal.move("u") -    vba.crystal.move("l") -    vba.crystal.move("l") - -    # face it -    vba.crystal.move("u") - -    # interact -    vba.press("a", holdsteps=10, aftersteps=1) - -    # wait for yes/no box -    vba.crystal.text_wait() - -    # press yes -    vba.press("a", holdsteps=10, aftersteps=1) - -    # TODO: when is healing done? - -    # wait until the script is done running -    vba.crystal.wait_for_script_running() - -    # wait for it to be really really done -    vba.nstep(50) - -    vba.crystal.move("r") -    vba.crystal.move("r") - -    # move to the door -    vba.crystal.move("d") -    vba.crystal.move("d") -    vba.crystal.move("d") -    vba.crystal.move("d") -    vba.crystal.move("d") -    vba.crystal.move("d") -    vba.crystal.move("d") -    vba.crystal.move("d") -    vba.crystal.move("d") - -    # walk out -    vba.crystal.move("d") - -    # check partymon1 level -    if vba.get_memory_at(0xdcfe) < level: -        new_bark_level_grind(level, skip=False) -    else: -        return +            if hp == 0: +                print "enemy hp is zero, exiting" +                break +            else: +                print "enemy hp is: " + str(hp) + +            attacks = attacks - 1 + +        while self.cry.vba.get_memory_at(0xd22d) != 0: +            self.cry.vba.press("a", holdsteps=10, aftersteps=1) + +        # wait for the map to finish loading +        self.cry.vba.nstep(50) + +        print "okay, back in the overworld" + +        # move up +        self.cry.move("u") +        self.cry.move("u") +        self.cry.move("u") +        self.cry.move("u") + +        # move into new bark town +        self.cry.move("r") +        self.cry.move("r") +        self.cry.move("r") +        self.cry.move("r") +        self.cry.move("r") +        self.cry.move("r") +        self.cry.move("r") +        self.cry.move("r") +        self.cry.move("r") +        self.cry.move("r") + +        # move up +        self.cry.move("u") +        self.cry.move("u") +        self.cry.move("u") +        self.cry.move("u") +        self.cry.move("u") + +        # move to the door +        self.cry.move("r") +        self.cry.move("r") +        self.cry.move("r") + +        # walk in +        self.cry.move("u") + +        # move up to the healing thing +        self.cry.move("u") +        self.cry.move("u") +        self.cry.move("u") +        self.cry.move("u") +        self.cry.move("u") +        self.cry.move("u") +        self.cry.move("u") +        self.cry.move("u") +        self.cry.move("u") +        self.cry.move("l") +        self.cry.move("l") + +        # face it +        self.cry.move("u") + +        # interact +        self.cry.vba.press("a", holdsteps=10, aftersteps=1) + +        # wait for yes/no box +        self.cry.text_wait() + +        # press yes +        self.cry.vba.press("a", holdsteps=10, aftersteps=1) + +        # TODO: when is healing done? + +        # wait until the script is done running +        self.cry.wait_for_script_running() + +        # wait for it to be really really done +        self.cry.vba.nstep(50) + +        self.cry.move("r") +        self.cry.move("r") + +        # move to the door +        self.cry.move("d") +        self.cry.move("d") +        self.cry.move("d") +        self.cry.move("d") +        self.cry.move("d") +        self.cry.move("d") +        self.cry.move("d") +        self.cry.move("d") +        self.cry.move("d") + +        # walk out +        self.cry.move("d") + +        # check partymon1 level +        if self.cry.vba.get_memory_at(0xdcfe) < level: +            self.new_bark_level_grind(level, skip=False) +        else: +            return -@skippable -def new_bark_level_grind_walk_to_grass(): -    """ -    Move to just above the grass from outside Elm's lab. -    """ +    @skippable +    def new_bark_level_grind_walk_to_grass(self): +        """ +        Move to just above the grass from outside Elm's lab. +        """ + +        self.cry.move("d") +        self.cry.move("d") -    vba.crystal.move("d") -    vba.crystal.move("d") - -    vba.crystal.move("l") -    vba.crystal.move("l") - -    vba.crystal.move("d") -    vba.crystal.move("d") - -    vba.crystal.move("l") -    vba.crystal.move("l") - -    # move to route 29 past the trees -    vba.crystal.move("l") -    vba.crystal.move("l") -    vba.crystal.move("l") -    vba.crystal.move("l") -    vba.crystal.move("l") -    vba.crystal.move("l") -    vba.crystal.move("l") -    vba.crystal.move("l") -    vba.crystal.move("l") - -    # move to just above the grass -    vba.crystal.move("d") -    vba.crystal.move("d") -    vba.crystal.move("d") +        self.cry.move("l") +        self.cry.move("l") + +        self.cry.move("d") +        self.cry.move("d") + +        self.cry.move("l") +        self.cry.move("l") + +        # move to route 29 past the trees +        self.cry.move("l") +        self.cry.move("l") +        self.cry.move("l") +        self.cry.move("l") +        self.cry.move("l") +        self.cry.move("l") +        self.cry.move("l") +        self.cry.move("l") +        self.cry.move("l") + +        # move to just above the grass +        self.cry.move("d") +        self.cry.move("d") +        self.cry.move("d") + +def main(): +    runner = SpeedRunner() +    runner.setup() +    return runner.main()  if __name__ == "__main__":      main() | 
