From d0c53213c416a1c77891fb10f11e6316817101e7 Mon Sep 17 00:00:00 2001 From: Bryan Bishop Date: Sat, 21 Sep 2013 23:54:55 -0500 Subject: make the vba autoplayer use the new methods --- pokemontools/vba/autoplayer.py | 742 +++++++++++++++++++++-------------------- 1 file changed, 378 insertions(+), 364 deletions(-) (limited to 'pokemontools/vba/autoplayer.py') 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() -- cgit v1.2.3 From c44ab9b5565a46004b17d87fdfefcd515b0adbf9 Mon Sep 17 00:00:00 2001 From: Bryan Bishop Date: Sun, 22 Sep 2013 00:28:43 -0500 Subject: make the skippable decorator use config Use the pokemontools configuration to determine where to save the save states. --- pokemontools/vba/autoplayer.py | 27 +++++++++++++++++++-------- 1 file changed, 19 insertions(+), 8 deletions(-) (limited to 'pokemontools/vba/autoplayer.py') diff --git a/pokemontools/vba/autoplayer.py b/pokemontools/vba/autoplayer.py index a63caa8..ee1a0c7 100644 --- a/pokemontools/vba/autoplayer.py +++ b/pokemontools/vba/autoplayer.py @@ -4,6 +4,8 @@ Programmatic speedrun of Pokémon Crystal """ import os +import pokemontools.configuration as configuration + # bring in the emulator and basic tools import vba as _vba @@ -11,11 +13,11 @@ def skippable(func): """ Makes a function skippable. - Saves 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. + Saves 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): + self = args[0] skip = True if "skip" in kwargs.keys(): @@ -25,17 +27,17 @@ def skippable(func): # 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)): + if not os.path.exists(os.path.join(self.config.save_state_path, full_name)): skip = False return_value = None if not skip: - _vba.save_state(func.__name__ + "-start", override=True) + self.cry.save_state(func.__name__ + "-start", override=True) return_value = func(*args, **kwargs) - _vba.save_state(func.__name__ + "-end", override=True) + self.cry.save_state(func.__name__ + "-end", override=True) elif skip: - _vba.set_state(vba.load_state(func.__name__ + "-end")) + self.cry.vba.set_state(self.cry.vba.load_state(func.__name__ + "-end")) return return_value return wrapped_function @@ -48,8 +50,17 @@ class Runner(object): pass class SpeedRunner(Runner): + def __init__(self, cry=None, config=None): + self.cry = cry + + if not config: + config = configuration.Config() + + self.config = config + def setup(self): - self.cry = _vba.crystal() + if not self.cry: + self.cry = _vba.crystal(config=config) def main(self): """ -- cgit v1.2.3 From 6568c299fd59b72bf6bcb66df23b3631e2e0a88e Mon Sep 17 00:00:00 2001 From: Bryan Bishop Date: Sun, 22 Sep 2013 00:59:19 -0500 Subject: fix how autoplayer calls hold/press on buttons --- pokemontools/vba/autoplayer.py | 50 +++++++++++++++++++++--------------------- 1 file changed, 25 insertions(+), 25 deletions(-) (limited to 'pokemontools/vba/autoplayer.py') diff --git a/pokemontools/vba/autoplayer.py b/pokemontools/vba/autoplayer.py index ee1a0c7..a143f1e 100644 --- a/pokemontools/vba/autoplayer.py +++ b/pokemontools/vba/autoplayer.py @@ -90,43 +90,43 @@ class SpeedRunner(Runner): self.cry.nstep(400) # skip the ditto sequence - self.cry.press("a") + self.cry.vba.press("a") self.cry.nstep(100) # skip the start screen - self.cry.press("start") + self.cry.vba.press("start") self.cry.nstep(100) # click "new game" - self.cry.press("a", holdsteps=50, aftersteps=1) + self.cry.vba.press("a", hold=50, after=1) # skip text up to "Are you a boy? Or are you a girl?" self.cry.text_wait() # select "Boy" - self.cry.press("a", holdsteps=50, aftersteps=1) + self.cry.vba.press("a", hold=50, after=1) # text until "What time is it?" self.cry.text_wait() # select 10 o'clock - self.cry.press("a", holdsteps=50, aftersteps=1) + self.cry.vba.press("a", hold=50, after=1) # yes i mean it - self.cry.press("a", holdsteps=50, aftersteps=1) + self.cry.vba.press("a", hold=50, after=1) # "How many minutes?" 0 min. - self.cry.press("a", holdsteps=50, aftersteps=1) + self.cry.vba.press("a", hold=50, after=1) # "Who! 0 min.?" yes/no select yes - self.cry.press("a", holdsteps=50, aftersteps=1) + self.cry.vba.press("a", hold=50, after=1) # read text until name selection self.cry.text_wait() # select "Chris" - self.cry.press("d", holdsteps=10, aftersteps=1) - self.cry.press("a", holdsteps=50, aftersteps=1) + self.cry.vba.press("d", hold=10, after=1) + self.cry.vba.press("a", hold=50, after=1) def overworldcheck(): """ @@ -164,28 +164,28 @@ class SpeedRunner(Runner): self.cry.text_wait() # "What day is it?" Sunday - self.cry.vba.press("a", holdsteps=10) # Sunday + self.cry.vba.press("a", hold=10) # Sunday self.cry.text_wait() # "SUNDAY, is it?" yes/no - self.cry.vba.press("a", holdsteps=10) # yes + self.cry.vba.press("a", hold=10) # yes self.cry.text_wait() # "Is it Daylight Saving Time now?" yes/no - self.cry.vba.press("a", holdsteps=10) # yes + self.cry.vba.press("a", hold=10) # yes self.cry.text_wait() # "AM DST, is that OK?" yes/no - self.cry.vba.press("a", holdsteps=10) # yes + self.cry.vba.press("a", hold=10) # yes # text until "know how to use the PHONE?" yes/no self.cry.text_wait() # press yes - self.cry.vba.press("a", holdsteps=10) + self.cry.vba.press("a", hold=10) # wait until mom is done talking self.cry.text_wait() @@ -234,7 +234,7 @@ class SpeedRunner(Runner): self.cry.text_wait() # "that I recently caught." yes/no - self.cry.vba.press("a", holdsteps=10) # yes + self.cry.vba.press("a", hold=10) # yes # talk to elm some more self.cry.text_wait() @@ -269,7 +269,7 @@ class SpeedRunner(Runner): self.cry.move("u") # select it - self.cry.vba.press("a", holdsteps=10, aftersteps=0) + self.cry.vba.press("a", hold=10, after=0) # wait for the image to pop up self.cry.text_wait() @@ -281,7 +281,7 @@ class SpeedRunner(Runner): self.cry.text_wait() # press yes - self.cry.vba.press("a", holdsteps=10, aftersteps=0) + self.cry.vba.press("a", hold=10, after=0) # wait for elm to talk a bit self.cry.text_wait() @@ -290,8 +290,8 @@ class SpeedRunner(Runner): self.cry.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 + self.cry.vba.press("d", hold=10, after=0) # move to "no" + self.cry.vba.press("a", hold=10, after=0) # no # TODO: why didn't this wait until he was completely done? self.cry.text_wait() @@ -358,13 +358,13 @@ class SpeedRunner(Runner): while attacks > 0: # FIGHT - self.cry.vba.press("a", holdsteps=10, aftersteps=1) + self.cry.vba.press("a", hold=10, after=1) # wait to select a move self.cry.text_wait() # SCRATCH - self.cry.vba.press("a", holdsteps=10, aftersteps=1) + self.cry.vba.press("a", hold=10, after=1) # wait for the move to be over self.cry.text_wait() @@ -381,7 +381,7 @@ class SpeedRunner(Runner): attacks = attacks - 1 while self.cry.vba.get_memory_at(0xd22d) != 0: - self.cry.vba.press("a", holdsteps=10, aftersteps=1) + self.cry.vba.press("a", hold=10, after=1) # wait for the map to finish loading self.cry.vba.nstep(50) @@ -438,13 +438,13 @@ class SpeedRunner(Runner): self.cry.move("u") # interact - self.cry.vba.press("a", holdsteps=10, aftersteps=1) + self.cry.vba.press("a", hold=10, after=1) # wait for yes/no box self.cry.text_wait() # press yes - self.cry.vba.press("a", holdsteps=10, aftersteps=1) + self.cry.vba.press("a", hold=10, after=1) # TODO: when is healing done? -- cgit v1.2.3 From f83fc26b499a55d5611e16726a356981b682dd63 Mon Sep 17 00:00:00 2001 From: Bryan Bishop Date: Sun, 22 Sep 2013 01:04:16 -0500 Subject: fix skippable decorator emulator state setter --- pokemontools/vba/autoplayer.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'pokemontools/vba/autoplayer.py') diff --git a/pokemontools/vba/autoplayer.py b/pokemontools/vba/autoplayer.py index a143f1e..13565d4 100644 --- a/pokemontools/vba/autoplayer.py +++ b/pokemontools/vba/autoplayer.py @@ -37,7 +37,7 @@ def skippable(func): return_value = func(*args, **kwargs) self.cry.save_state(func.__name__ + "-end", override=True) elif skip: - self.cry.vba.set_state(self.cry.vba.load_state(func.__name__ + "-end")) + self.cry.vba.state = self.cry.vba.load_state(func.__name__ + "-end") return return_value return wrapped_function -- cgit v1.2.3 From 81504f340187fe6e3fff7ed13d947216fe36030c Mon Sep 17 00:00:00 2001 From: Bryan Bishop Date: Sun, 22 Sep 2013 01:11:53 -0500 Subject: load_state was called on the wrong object --- pokemontools/vba/autoplayer.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'pokemontools/vba/autoplayer.py') diff --git a/pokemontools/vba/autoplayer.py b/pokemontools/vba/autoplayer.py index 13565d4..6755db9 100644 --- a/pokemontools/vba/autoplayer.py +++ b/pokemontools/vba/autoplayer.py @@ -37,7 +37,7 @@ def skippable(func): return_value = func(*args, **kwargs) self.cry.save_state(func.__name__ + "-end", override=True) elif skip: - self.cry.vba.state = self.cry.vba.load_state(func.__name__ + "-end") + self.cry.vba.state = self.cry.load_state(func.__name__ + "-end") return return_value return wrapped_function -- cgit v1.2.3 From 912efe7fd0127a0abd5c92c51990d732b18d32a6 Mon Sep 17 00:00:00 2001 From: Bryan Bishop Date: Sun, 22 Sep 2013 02:12:11 -0500 Subject: make SpeedRunner.setup use the right config ref --- pokemontools/vba/autoplayer.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'pokemontools/vba/autoplayer.py') diff --git a/pokemontools/vba/autoplayer.py b/pokemontools/vba/autoplayer.py index 6755db9..aa57825 100644 --- a/pokemontools/vba/autoplayer.py +++ b/pokemontools/vba/autoplayer.py @@ -60,7 +60,7 @@ class SpeedRunner(Runner): def setup(self): if not self.cry: - self.cry = _vba.crystal(config=config) + self.cry = _vba.crystal(config=self.config) def main(self): """ -- cgit v1.2.3 From a04f6ceb4b98d9b37390905b7ab60bd5e35fcc21 Mon Sep 17 00:00:00 2001 From: Bryan Bishop Date: Sun, 22 Sep 2013 02:46:40 -0500 Subject: fix cyndaquil selection in Elm's Lab --- pokemontools/vba/autoplayer.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'pokemontools/vba/autoplayer.py') diff --git a/pokemontools/vba/autoplayer.py b/pokemontools/vba/autoplayer.py index aa57825..5bbf91e 100644 --- a/pokemontools/vba/autoplayer.py +++ b/pokemontools/vba/autoplayer.py @@ -257,7 +257,7 @@ class SpeedRunner(Runner): if starter_choice.lower() == "cyndaquil": moves = 0 - if starter_choice.lower() == "totodile": + elif starter_choice.lower() == "totodile": moves = 1 else: moves = 2 -- cgit v1.2.3 From 50997c8b3849d70483266dce2661e3f076558cc6 Mon Sep 17 00:00:00 2001 From: Bryan Bishop Date: Sun, 22 Sep 2013 02:48:26 -0500 Subject: get rid of a text_wait when talking to Elm --- pokemontools/vba/autoplayer.py | 3 --- 1 file changed, 3 deletions(-) (limited to 'pokemontools/vba/autoplayer.py') diff --git a/pokemontools/vba/autoplayer.py b/pokemontools/vba/autoplayer.py index 5bbf91e..744b9e3 100644 --- a/pokemontools/vba/autoplayer.py +++ b/pokemontools/vba/autoplayer.py @@ -303,9 +303,6 @@ class SpeedRunner(Runner): # talk with elm a bit more self.cry.text_wait() - # TODO: and again.. wtf? - self.cry.text_wait() - # wait until the script is done running self.cry.wait_for_script_running() -- cgit v1.2.3 From a4c418bc7a2b99ad3da7f421bba8cf7415f9f021 Mon Sep 17 00:00:00 2001 From: Bryan Bishop Date: Sun, 22 Sep 2013 10:50:21 -0500 Subject: fix some func calls in the auto level grinder --- pokemontools/vba/autoplayer.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) (limited to 'pokemontools/vba/autoplayer.py') diff --git a/pokemontools/vba/autoplayer.py b/pokemontools/vba/autoplayer.py index 744b9e3..5ee2ac1 100644 --- a/pokemontools/vba/autoplayer.py +++ b/pokemontools/vba/autoplayer.py @@ -366,7 +366,7 @@ class SpeedRunner(Runner): # wait for the move to be over self.cry.text_wait() - hp = ((self.cry.vba.get_memory_at(0xd218) << 8) | self.cry.vba.get_memory_at(0xd217)) + hp = ((self.cry.vba.memory[0xd218] << 8) | self.cry.vba.memory[0xd217]) print "enemy hp is: " + str(hp) if hp == 0: @@ -377,11 +377,11 @@ class SpeedRunner(Runner): attacks = attacks - 1 - while self.cry.vba.get_memory_at(0xd22d) != 0: + while self.cry.vba.memory[0xd22d] != 0: self.cry.vba.press("a", hold=10, after=1) # wait for the map to finish loading - self.cry.vba.nstep(50) + self.cry.vba.step(count=50) print "okay, back in the overworld" @@ -449,7 +449,7 @@ class SpeedRunner(Runner): self.cry.wait_for_script_running() # wait for it to be really really done - self.cry.vba.nstep(50) + self.cry.vba.step(count=50) self.cry.move("r") self.cry.move("r") @@ -469,7 +469,7 @@ class SpeedRunner(Runner): self.cry.move("d") # check partymon1 level - if self.cry.vba.get_memory_at(0xdcfe) < level: + if self.cry.vba.memory[0xdcfe] < level: self.new_bark_level_grind(level, skip=False) else: return -- cgit v1.2.3 From 6a1fc607718e70a5e8c50309c51d6b2e4bfd54a1 Mon Sep 17 00:00:00 2001 From: Bryan Bishop Date: Sun, 22 Sep 2013 10:55:44 -0500 Subject: better IsInBattle detection for level grinding --- pokemontools/vba/autoplayer.py | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) (limited to 'pokemontools/vba/autoplayer.py') diff --git a/pokemontools/vba/autoplayer.py b/pokemontools/vba/autoplayer.py index 5ee2ac1..987395a 100644 --- a/pokemontools/vba/autoplayer.py +++ b/pokemontools/vba/autoplayer.py @@ -343,11 +343,19 @@ class SpeedRunner(Runner): # walk to the grass area self.new_bark_level_grind_walk_to_grass(skip=False) - # TODO: walk around in grass, handle battles - walk = ["d", "d", "u", "d", "u", "d"] - for direction in walk: + last_direction = "u" + + # walk around in the grass until a battle happens + while self.cry.vba.memory[0xd22d] == 0: + if last_direction == "u": + direction = "d" + else: + direction = "u" + self.cry.move(direction) + last_direction = direction + # wait for wild battle to completely start self.cry.text_wait() -- cgit v1.2.3 From d0b0b9c5f2e0d302b9150e6eeb5be9b2467fb792 Mon Sep 17 00:00:00 2001 From: Bryan Bishop Date: Sun, 22 Sep 2013 11:12:38 -0500 Subject: only heal if HP is low or move1 PP is low --- pokemontools/vba/autoplayer.py | 21 +++++++++++++++++++-- 1 file changed, 19 insertions(+), 2 deletions(-) (limited to 'pokemontools/vba/autoplayer.py') diff --git a/pokemontools/vba/autoplayer.py b/pokemontools/vba/autoplayer.py index 987395a..b47634e 100644 --- a/pokemontools/vba/autoplayer.py +++ b/pokemontools/vba/autoplayer.py @@ -332,7 +332,7 @@ class SpeedRunner(Runner): return @skippable - def new_bark_level_grind(self, level): + def new_bark_level_grind(self, level, walk_to_grass=True): """ Do level grinding in New Bark. @@ -341,7 +341,8 @@ class SpeedRunner(Runner): """ # walk to the grass area - self.new_bark_level_grind_walk_to_grass(skip=False) + if walk_to_grass: + self.new_bark_level_grind_walk_to_grass(skip=False) last_direction = "u" @@ -391,8 +392,24 @@ class SpeedRunner(Runner): # wait for the map to finish loading self.cry.vba.step(count=50) + # This is used to handle any additional textbox that might be up on the + # screen. The debug parameter is set to True so that max_wait is + # enabled. This might be a textbox that is still waiting around because + # of some faint during the battle. I am not completely sure why this + # happens. + self.cry.text_wait(max_wait=30, debug=True) + print "okay, back in the overworld" + cur_hp = ((self.cry.vba.memory[0xdd01] << 8) | self.cry.vba.memory[0xdd02]) + move_pp = self.cry.vba.memory[0xdcf6] # move 1 pp + + # if pokemon health is >20, just continue + # if move 1 PP is 0, just continue + if cur_hp > 20 and move_pp > 5: + self.cry.move("u") + return self.new_bark_level_grind(level, walk_to_grass=False, skip=False) + # move up self.cry.move("u") self.cry.move("u") -- cgit v1.2.3 From 54579ad69962d62a7af874635ff4e3e5fb4738b7 Mon Sep 17 00:00:00 2001 From: Bryan Bishop Date: Sun, 22 Sep 2013 11:38:35 -0500 Subject: make skippable decorator not always save state There are some runs where the "skippable" decorator should not save the state of the game before and after, like if the function is given different parameters and the after state should not be the canonical after state. --- pokemontools/vba/autoplayer.py | 18 +++++++++++++++--- 1 file changed, 15 insertions(+), 3 deletions(-) (limited to 'pokemontools/vba/autoplayer.py') diff --git a/pokemontools/vba/autoplayer.py b/pokemontools/vba/autoplayer.py index b47634e..c1e36bc 100644 --- a/pokemontools/vba/autoplayer.py +++ b/pokemontools/vba/autoplayer.py @@ -19,11 +19,16 @@ def skippable(func): def wrapped_function(*args, **kwargs): self = args[0] skip = True + override = True if "skip" in kwargs.keys(): skip = kwargs["skip"] del kwargs["skip"] + if "override" in kwargs.keys(): + override = kwargs["override"] + del kwargs["override"] + # override skip if there's no save if skip: full_name = func.__name__ + "-end.sav" @@ -33,9 +38,13 @@ def skippable(func): return_value = None if not skip: - self.cry.save_state(func.__name__ + "-start", override=True) + if override: + self.cry.save_state(func.__name__ + "-start", override=override) + return_value = func(*args, **kwargs) - self.cry.save_state(func.__name__ + "-end", override=True) + + if override: + self.cry.save_state(func.__name__ + "-end", override=override) elif skip: self.cry.vba.state = self.cry.load_state(func.__name__ + "-end") @@ -81,7 +90,7 @@ class SpeedRunner(Runner): self.new_bark_level_grind(10, skip=False) @skippable - def skip_intro(self): + def skip_intro(self, stop_at_name_selection=False): """ Skip the game boot intro sequence. """ @@ -124,6 +133,9 @@ class SpeedRunner(Runner): # read text until name selection self.cry.text_wait() + if stop_at_name_selection: + return + # select "Chris" self.cry.vba.press("d", hold=10, after=1) self.cry.vba.press("a", hold=50, after=1) -- cgit v1.2.3 From 0b7ed30a33fb9775b2b5e1f3245a2e28608c9fc6 Mon Sep 17 00:00:00 2001 From: Bryan Bishop Date: Sun, 22 Sep 2013 12:42:02 -0500 Subject: go heal if level reached the target --- pokemontools/vba/autoplayer.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'pokemontools/vba/autoplayer.py') diff --git a/pokemontools/vba/autoplayer.py b/pokemontools/vba/autoplayer.py index c1e36bc..0049021 100644 --- a/pokemontools/vba/autoplayer.py +++ b/pokemontools/vba/autoplayer.py @@ -418,7 +418,7 @@ class SpeedRunner(Runner): # if pokemon health is >20, just continue # if move 1 PP is 0, just continue - if cur_hp > 20 and move_pp > 5: + if cur_hp > 20 and move_pp > 5 and self.cry.vba.memory[0xdcfe] < level: self.cry.move("u") return self.new_bark_level_grind(level, walk_to_grass=False, skip=False) -- cgit v1.2.3 From 38ecfa8705fb6140a00988ef8fc88272974cbe36 Mon Sep 17 00:00:00 2001 From: Bryan Bishop Date: Sun, 22 Sep 2013 17:27:35 -0500 Subject: use explicit skips in vba autoplayer --- pokemontools/vba/autoplayer.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) (limited to 'pokemontools/vba/autoplayer.py') diff --git a/pokemontools/vba/autoplayer.py b/pokemontools/vba/autoplayer.py index 0049021..479924c 100644 --- a/pokemontools/vba/autoplayer.py +++ b/pokemontools/vba/autoplayer.py @@ -76,18 +76,18 @@ class SpeedRunner(Runner): Start the game. """ # get past the opening sequence - self.skip_intro() + self.skip_intro(skip=True) # walk to mom and handle her text - self.handle_mom() + self.handle_mom(skip=True) # walk outside into new bark town - self.walk_into_new_bark_town() + self.walk_into_new_bark_town(skip=True) # walk to elm and do whatever he wants - self.handle_elm("totodile") + self.handle_elm("totodile", skip=True) - self.new_bark_level_grind(10, skip=False) + self.new_bark_level_grind(6, skip=False) @skippable def skip_intro(self, stop_at_name_selection=False): -- cgit v1.2.3 From 27ea6f652796a177ea4b102dbea504a459e11cf5 Mon Sep 17 00:00:00 2001 From: Bryan Bishop Date: Thu, 26 Sep 2013 01:03:58 -0500 Subject: grind to a higher level --- pokemontools/vba/autoplayer.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'pokemontools/vba/autoplayer.py') diff --git a/pokemontools/vba/autoplayer.py b/pokemontools/vba/autoplayer.py index 479924c..6aa9494 100644 --- a/pokemontools/vba/autoplayer.py +++ b/pokemontools/vba/autoplayer.py @@ -87,7 +87,7 @@ class SpeedRunner(Runner): # walk to elm and do whatever he wants self.handle_elm("totodile", skip=True) - self.new_bark_level_grind(6, skip=False) + self.new_bark_level_grind(17, skip=False) @skippable def skip_intro(self, stop_at_name_selection=False): -- cgit v1.2.3 From 80fe5be90664faf03992c160055b9fa061eb74af Mon Sep 17 00:00:00 2001 From: Bryan Bishop Date: Sat, 12 Oct 2013 16:22:53 -0500 Subject: use get_enemy_hp instead of a custom check --- pokemontools/vba/autoplayer.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'pokemontools/vba/autoplayer.py') diff --git a/pokemontools/vba/autoplayer.py b/pokemontools/vba/autoplayer.py index 6aa9494..847ebbd 100644 --- a/pokemontools/vba/autoplayer.py +++ b/pokemontools/vba/autoplayer.py @@ -387,7 +387,7 @@ class SpeedRunner(Runner): # wait for the move to be over self.cry.text_wait() - hp = ((self.cry.vba.memory[0xd218] << 8) | self.cry.vba.memory[0xd217]) + hp = self.cry.get_enemy_hp() print "enemy hp is: " + str(hp) if hp == 0: -- cgit v1.2.3 From 2328b2bd3addc7034e2a7d14dc39e39b7627df82 Mon Sep 17 00:00:00 2001 From: Bryan Bishop Date: Sat, 12 Oct 2013 16:25:39 -0500 Subject: call super __init__() in SpeedRunner --- pokemontools/vba/autoplayer.py | 2 ++ 1 file changed, 2 insertions(+) (limited to 'pokemontools/vba/autoplayer.py') diff --git a/pokemontools/vba/autoplayer.py b/pokemontools/vba/autoplayer.py index 847ebbd..428b85d 100644 --- a/pokemontools/vba/autoplayer.py +++ b/pokemontools/vba/autoplayer.py @@ -60,6 +60,8 @@ class Runner(object): class SpeedRunner(Runner): def __init__(self, cry=None, config=None): + super(SpeedRunner, self).__init__() + self.cry = cry if not config: -- cgit v1.2.3 From 819d16726ec2e4cbe04c6803539b4c13014717b5 Mon Sep 17 00:00:00 2001 From: Bryan Bishop Date: Sat, 12 Oct 2013 16:29:03 -0500 Subject: improve some VBA-related docstrings --- pokemontools/vba/autoplayer.py | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) (limited to 'pokemontools/vba/autoplayer.py') diff --git a/pokemontools/vba/autoplayer.py b/pokemontools/vba/autoplayer.py index 428b85d..2d62433 100644 --- a/pokemontools/vba/autoplayer.py +++ b/pokemontools/vba/autoplayer.py @@ -70,12 +70,16 @@ class SpeedRunner(Runner): self.config = config def setup(self): + """ + Configure this ``Runner`` instance to contain a reference to an active + emulator session. + """ if not self.cry: self.cry = _vba.crystal(config=self.config) def main(self): """ - Start the game. + Main entry point for complete control of the game as the main player. """ # get past the opening sequence self.skip_intro(skip=True) @@ -548,6 +552,9 @@ class SpeedRunner(Runner): self.cry.move("d") def main(): + """ + Setup a basic ``SpeedRunner`` instance and then run the runner. + """ runner = SpeedRunner() runner.setup() return runner.main() -- cgit v1.2.3 From 1f185185ca15389417474f6becfddde56e8e80eb Mon Sep 17 00:00:00 2001 From: Bryan Bishop Date: Sat, 2 Nov 2013 14:00:04 -0500 Subject: autoplayer.bootstrap to call skip_intro There are situations other than just testing where making a bootstrapped game state is a useful ability. --- pokemontools/vba/autoplayer.py | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) (limited to 'pokemontools/vba/autoplayer.py') diff --git a/pokemontools/vba/autoplayer.py b/pokemontools/vba/autoplayer.py index 2d62433..a20744e 100644 --- a/pokemontools/vba/autoplayer.py +++ b/pokemontools/vba/autoplayer.py @@ -551,6 +551,26 @@ class SpeedRunner(Runner): self.cry.move("d") self.cry.move("d") +def bootstrap(runner=None, cry=None): + """ + Setup the initial game and return the state. This skips the intro and + performs some other actions to get the game to a reasonable starting state. + """ + if not runner: + runner = SpeedRunner(cry=cry) + runner.setup() + + # skip=False means always run the skip_intro function regardless of the + # presence of a saved after state. + runner.skip_intro(skip=True) + + # keep a reference of the current state + state = runner.cry.vba.state + + cry.vba.shutdown() + + return state + def main(): """ Setup a basic ``SpeedRunner`` instance and then run the runner. -- cgit v1.2.3 From 185856adb4a10c66a1fc206c13862ffa6958cec6 Mon Sep 17 00:00:00 2001 From: Bryan Bishop Date: Sat, 2 Nov 2013 14:01:01 -0500 Subject: fix a call to vba.shutdown in bootstrap() --- pokemontools/vba/autoplayer.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'pokemontools/vba/autoplayer.py') diff --git a/pokemontools/vba/autoplayer.py b/pokemontools/vba/autoplayer.py index a20744e..af14d47 100644 --- a/pokemontools/vba/autoplayer.py +++ b/pokemontools/vba/autoplayer.py @@ -567,7 +567,7 @@ def bootstrap(runner=None, cry=None): # keep a reference of the current state state = runner.cry.vba.state - cry.vba.shutdown() + runner.cry.vba.shutdown() return state -- cgit v1.2.3