diff options
Diffstat (limited to 'tests/test_vba.py')
| -rw-r--r-- | tests/test_vba.py | 303 | 
1 files changed, 269 insertions, 34 deletions
| diff --git a/tests/test_vba.py b/tests/test_vba.py index 56a71e3..9c12cc1 100644 --- a/tests/test_vba.py +++ b/tests/test_vba.py @@ -6,23 +6,37 @@ import unittest  import pokemontools.vba.vba as vba +from pokemontools.vba.battle import ( +    Battle, +    BattleException, +) +  try: -    import pokemontools.vba.vba_autoplayer +    import pokemontools.vba.vba_autoplayer as autoplayer  except ImportError: -    import pokemontools.vba.autoplayer as vba_autoplayer +    import pokemontools.vba.autoplayer as autoplayer +autoplayer.vba = vba -vba_autoplayer.vba = vba +import pokemontools.vba.keyboard as keyboard  def setup_wram():      """      Loads up some default addresses. Should eventually be replaced with the      actual wram parser.      """ +    # TODO: this should just be parsed straight out of wram.asm      wram = {}      wram["PlayerDirection"] = 0xd4de      wram["PlayerAction"] = 0xd4e1      wram["MapX"] = 0xd4e6      wram["MapY"] = 0xd4e7 + +    wram["WarpNumber"] = 0xdcb4 +    wram["MapGroup"] = 0xdcb5 +    wram["MapNumber"] = 0xdcb6 +    wram["YCoord"] = 0xdcb7 +    wram["XCoord"] = 0xdcb8 +      return wram  def bootstrap(): @@ -31,54 +45,102 @@ def bootstrap():      is constructed by this function.      """ -    # reset the rom -    vba.shutdown() -    vba.load_rom() +    cry = vba.crystal(config=None) +    runner = autoplayer.SpeedRunner(cry=cry)      # skip=False means run the skip_intro function instead of just skipping to      # a saved state. -    vba_autoplayer.skip_intro() +    runner.skip_intro(skip=True) -    state = vba.get_state() +    state = cry.vba.state      # clean everything up again -    vba.shutdown() +    cry.vba.shutdown()      return state +def bootstrap_trainer_battle(): +    """ +    Start a trainer battle. +    """ +    # setup +    cry = vba.crystal(config=None) +    runner = autoplayer.SpeedRunner(cry=cry) + +    runner.skip_intro(skip=True) +    runner.handle_mom(skip=True) +    runner.walk_into_new_bark_town(skip=True) +    runner.handle_elm("totodile", skip=True) + +    # levelgrind a pokemon +    # TODO: make new_bark_level_grind able to figure out how to construct its +    # initial state if none is provided. +    runner.new_bark_level_grind(17, skip=True) + +    # TODO: figure out a better way to start a trainer battle :( +    runner.cry.start_trainer_battle_lamely() + +    return runner.cry.vba.state + +class OtherVbaTests(unittest.TestCase): +    def test_keyboard_planner(self): +        button_sequence = keyboard.plan_typing("an") +        expected_result = ["select", "a", "d", "r", "r", "r", "r", "a"] + +        self.assertEqual(len(expected_result), len(button_sequence)) +        self.assertEqual(expected_result, button_sequence) +  class VbaTests(unittest.TestCase): -    # unittest in jython2.5 doesn't seem to have setUpClass ?? Man, why am I on -    # jython2.5? This is ancient. -    #@classmethod -    #def setUpClass(cls): -    #    # get a good game state -    #    cls.state = bootstrap() -    # -    #    # figure out addresses -    #    cls.wram = setup_wram() - -    # FIXME: work around jython2.5 unittest -    state = bootstrap() -    wram = setup_wram() +    cry = None +    wram = None -    def get_wram_value(self, name): -        return vba.get_memory_at(self.wram[name]) +    @classmethod +    def setUpClass(cls): +        cls.bootstrap_state = bootstrap() -    def setUp(self): -        # clean the state -        vba.shutdown() -        vba.load_rom() +        cls.wram = setup_wram() + +        cls.cry = vba.crystal() +        cls.vba = cls.cry.vba + +        cls.vba.state = cls.bootstrap_state + +    @classmethod +    def tearDownClass(cls): +        cls.vba.shutdown() +    def setUp(self):          # reset to whatever the bootstrapper created -        vba.set_state(self.state) +        self.vba.state = self.bootstrap_state + +    def get_wram_value(self, name): +        return self.vba.memory[self.wram[name]] + +    def check_movement(self, direction="d"): +        """ +        Check if (y, x) before attempting to move and (y, x) after attempting +        to move are the same. +        """ +        start = (self.get_wram_value("MapY"), self.get_wram_value("MapX")) +        self.cry.move(direction) +        end = (self.get_wram_value("MapY"), self.get_wram_value("MapX")) +        return start != end -    def tearDown(self): -        vba.shutdown() +    def bootstrap_name_prompt(self): +        runner = autoplayer.SpeedRunner(cry=None) +        runner.setup() +        runner.skip_intro(stop_at_name_selection=True, skip=False, override=False) + +        self.cry.vba.press("a", hold=20) + +        # wait for "Your name?" to show up +        while "YOUR NAME?" not in self.cry.get_text(): +            self.cry.step(count=50)      def test_movement_changes_player_direction(self):          player_direction = self.get_wram_value("PlayerDirection") -        vba.crystal.move("u") +        self.cry.move("u")          # direction should have changed          self.assertNotEqual(player_direction, self.get_wram_value("PlayerDirection")) @@ -86,7 +148,7 @@ class VbaTests(unittest.TestCase):      def test_movement_changes_y_coord(self):          first_map_y = self.get_wram_value("MapY") -        vba.crystal.move("u") +        self.cry.move("u")          # y location should be different          second_map_y = self.get_wram_value("MapY") @@ -96,11 +158,184 @@ class VbaTests(unittest.TestCase):          # should start with standing          self.assertEqual(self.get_wram_value("PlayerAction"), 1) -        vba.crystal.move("l") +        self.cry.move("l")          # should be standing          player_action = self.get_wram_value("PlayerAction")          self.assertEqual(player_action, 1) # 1 = standing +    def test_PlaceString(self): +        self.cry.call(0, 0x1078) + +        # where to draw the text +        self.cry.registers["hl"] = 0xc4a0 + +        # what text to read from +        self.cry.registers["de"] = 0x1276 + +        self.cry.vba.step(count=10) + +        text = self.cry.get_text() + +        self.assertTrue("TRAINER" in text) + +    def test_speedrunner_constructor(self): +        runner = autoplayer.SpeedRunner(cry=self.cry) + +    def test_speedrunner_handle_mom(self): +        # TODO: why can't i pass in the current state of the emulator? +        runner = autoplayer.SpeedRunner(cry=None) +        runner.setup() +        runner.skip_intro(skip=True) +        runner.handle_mom(skip=False) + +        # confirm that handle_mom is done by attempting to move on the map +        self.assertTrue(self.check_movement("d")) + +    def test_speedrunner_walk_into_new_bark_town(self): +        runner = autoplayer.SpeedRunner(cry=None) +        runner.setup() +        runner.skip_intro(skip=True) +        runner.handle_mom(skip=True) +        runner.walk_into_new_bark_town(skip=False) + +        # test that the game is in a state such that the player can walk +        self.assertTrue(self.check_movement("d")) + +        # check that the map is correct +        self.assertEqual(self.get_wram_value("MapGroup"), 24) +        self.assertEqual(self.get_wram_value("MapNumber"), 4) + +    def test_speedrunner_handle_elm(self): +        runner = autoplayer.SpeedRunner(cry=None) +        runner.setup() +        runner.skip_intro(skip=True) +        runner.handle_mom(skip=True) +        runner.walk_into_new_bark_town(skip=False) + +        # go through the Elm's Lab sequence +        runner.handle_elm("cyndaquil", skip=False) + +        # test again if the game is in a state where the player can walk +        self.assertTrue(self.check_movement("u")) + +        # check that the map is correct +        self.assertEqual(self.get_wram_value("MapGroup"), 24) +        self.assertEqual(self.get_wram_value("MapNumber"), 5) + +    def test_moving_back_and_forth(self): +        runner = autoplayer.SpeedRunner(cry=None) +        runner.setup() +        runner.skip_intro(skip=True) +        runner.handle_mom(skip=True) +        runner.walk_into_new_bark_town(skip=False) + +        # must be in New Bark Town +        self.assertEqual(self.get_wram_value("MapGroup"), 24) +        self.assertEqual(self.get_wram_value("MapNumber"), 4) + +        runner.cry.move("l") +        runner.cry.move("l") +        runner.cry.move("l") +        runner.cry.move("d") +        runner.cry.move("d") + +        for x in range(0, 10): +            runner.cry.move("l") +            runner.cry.move("d") +            runner.cry.move("r") +            runner.cry.move("u") + +        # must still be in New Bark Town +        self.assertEqual(self.get_wram_value("MapGroup"), 24) +        self.assertEqual(self.get_wram_value("MapNumber"), 4) + +    def test_crystal_move_list(self): +        runner = autoplayer.SpeedRunner(cry=None) +        runner.setup() +        runner.skip_intro(skip=True) +        runner.handle_mom(skip=True) +        runner.walk_into_new_bark_town(skip=False) + +        # must be in New Bark Town +        self.assertEqual(self.get_wram_value("MapGroup"), 24) +        self.assertEqual(self.get_wram_value("MapNumber"), 4) + +        first_map_x = self.get_wram_value("MapX") + +        runner.cry.move(["l", "l", "l"]) + +        # x location should be different +        second_map_x = self.get_wram_value("MapX") +        self.assertNotEqual(first_map_x, second_map_x) + +        # must still be in New Bark Town +        self.assertEqual(self.get_wram_value("MapGroup"), 24) +        self.assertEqual(self.get_wram_value("MapNumber"), 4) + +    def test_keyboard_typing_dumb_name(self): +        self.bootstrap_name_prompt() + +        name = "tRaInEr" +        self.cry.write(name) + +        # save this selection +        self.cry.vba.press("a", hold=20) + +        self.assertEqual(name, self.cry.get_player_name()) + +    def test_keyboard_typing_cap_name(self): +        names = [ +            "trainer", +            "TRAINER", +            "TrAiNeR", +            "tRaInEr", +            "ExAmPlE", +            "Chris", +            "Kris", +            "beepaaa", +            "chris", +            "CHRIS", +            "Python", +            "pYthon", +            "pyThon", +            "pytHon", +            "pythOn", +            "pythoN", +            "python", +            "PyThOn", +            "Zot", +            "Death", +            "Hiro", +            "HIRO", +        ] + +        self.bootstrap_name_prompt() +        start_state = self.cry.vba.state + +        for name in names: +            print "Writing name: " + name + +            self.cry.vba.state = start_state + +            sequence = self.cry.write(name) + +            print "sequence is: " + str(sequence) + +            # save this selection +            self.cry.vba.press("start", hold=20) +            self.cry.vba.press("a", hold=20) + +            pname = self.cry.get_player_name().replace("@", "") +            self.assertEqual(name, pname) + +    def test_battle_is_player_turn(self): +        state = bootstrap_trainer_battle() +        self.cry.vba.state = state + +        battle = Battle(emulator=self.cry) + +        self.assertTrue(battle.is_player_turn()) +  if __name__ == "__main__":      unittest.main() | 
