diff options
Diffstat (limited to 'pokemontools/vba/autoplayer.py')
-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() |