diff options
Diffstat (limited to 'pokemontools/vba/battle.py')
-rw-r--r-- | pokemontools/vba/battle.py | 129 |
1 files changed, 115 insertions, 14 deletions
diff --git a/pokemontools/vba/battle.py b/pokemontools/vba/battle.py index 87cd7b1..b1ac0fe 100644 --- a/pokemontools/vba/battle.py +++ b/pokemontools/vba/battle.py @@ -38,7 +38,7 @@ class Battle(EmulatorController): """ Detects if the battle is waiting for player input. """ - return self.is_player_turn() or self.is_mandatory_switch() + return self.is_player_turn() or self.is_mandatory_switch() or self.is_trainer_switch_prompt() def is_fight_pack_run_menu(self): """ @@ -49,12 +49,86 @@ class Battle(EmulatorController): screentext = self.emulator.get_text() return all([sign in screentext for sign in signs]) + def select_battle_menu_action(self, action, execute=True): + """ + Moves the cursor to the requested action and selects it. + + :param action: fight, pkmn, pack, run + """ + if not self.is_fight_pack_run_menu(): + raise Exception( + "This isn't the fight-pack-run menu." + ) + + action = action.lower() + + action_map = { + "fight": (1, 1), + "pkmn": (1, 2), + "pack": (2, 1), + "run": (2, 2), + } + + if action not in action_map.keys(): + raise Exception( + "Unexpected requested action {0}".format(action) + ) + + current_row = self.vba.read_memory_at(0xcfa9) + current_column = self.vba.read_memory_at(0xcfaa) + + direction = None + if current_row != action_map[action][0]: + if current_row > action_map[action][0]: + direction = "u" + elif current_row < action_map[action][0]: + direction = "d" + + self.vba.press(direction, hold=5, after=10) + + direction = None + if current_column != action_map[action][1]: + if current_column > action_map[action][1]: + direction = "l" + elif current_column < action_map[action][1]: + direction = "r" + + self.vba.press(direction, hold=5, after=10) + + # now select the action + if execute: + self.vba.press(a, hold=5, after=100) + def is_player_turn(self): """ Detects if the battle is waiting for the player to choose an attack. """ return self.is_fight_pack_run_menu() + def is_trainer_switch_prompt(self): + """ + Detects if the battle is waiting for the player to choose whether or + not to switch pokemon. This is the prompt that asks yes/no for whether + to switch pokemon, like if the trainer is switching pokemon at the end + of a turn set. + """ + return self.emulator.is_trainer_switch_prompt() + + def is_wild_switch_prompt(self): + """ + Detects if the battle is waiting for the player to choose whether or + not to continue to fight the wild pokemon. + """ + return self.emulator.is_wild_switch_prompt() + + def is_switch_prompt(self): + """ + Detects both trainer and wild switch prompts (for prompting whether to + switch pokemon). This is a yes/no box and not the actual pokemon + selection menu. + """ + return self.is_trainer_switch_prompt() or self.is_wild_switch_prompt() + def is_mandatory_switch(self): """ Detects if the battle is waiting for the player to choose a next @@ -134,6 +208,10 @@ class Battle(EmulatorController): if self.is_player_turn(): # battle hook provides input to handle this situation self.handle_turn() + elif self.is_trainer_switch_prompt(): + self.handle_trainer_switch_prompt() + elif self.is_wild_switch_prompt(): + self.handle_wild_switch_prompt() elif self.is_mandatory_switch(): # battle hook provides input to handle this situation too self.handle_mandatory_switch() @@ -141,6 +219,7 @@ class Battle(EmulatorController): raise BattleException("unknown state, aborting") # "how did i lose? wah" + # TODO: this doesn't happen for wild battles self.skip_end_text() # TODO: return should indicate win/loss (blackout) @@ -151,6 +230,20 @@ class Battle(EmulatorController): """ raise NotImplementedError + def handle_trainer_switch_prompt(self): + """ + The trainer is switching pokemon. The game asks yes/no for whether or + not the player would like to switch. + """ + raise NotImplementedError + + def handle_wild_switch_prompt(self): + """ + The wild pokemon defeated the party pokemon. This is the yes/no box for + whether to switch pokemon or not. + """ + raise NotImplementedError + def handle_turn(self): """ Take actions inside of a battle based on the game state. @@ -159,35 +252,43 @@ class Battle(EmulatorController): class BattleStrategy(Battle): """ - Throw a pokeball until everyone dies. + This class shows the relevant methods to make a battle handler. """ def handle_mandatory_switch(self): """ Something fainted, pick the next mon. """ - for pokemon in self.emulator.party: - if pokemon.hp > 0: - break - else: - # the game failed to do a blackout.. not sure what to do now. - raise BattleException("No partymons left. wtf?") + raise NotImplementedError + + def handle_trainer_switch_prompt(self): + """ + The trainer is switching pokemon. The game asks yes/no for whether or + not the player would like to switch. + """ + raise NotImplementedError - return pokemon.id + def handle_wild_switch_prompt(self): + """ + The wild pokemon defeated the party pokemon. This is the yes/no box for + whether to switch pokemon or not. + """ + raise NotImplementedError def handle_turn(self): """ Take actions inside of a battle based on the game state. """ - self.throw_pokeball() + raise NotImplementedError -class SimpleBattleStrategy(BattleStrategy): +class SpamBattleStrategy(BattleStrategy): """ - Attack the enemy with the first move. + A really simple battle strategy that always picks the first move of the + first pokemon to attack the enemy. """ def handle_turn(self): """ - Always attack the enemy with the first move. + Always picks the first move of the current pokemon. """ - self.attack(self.battle.party[0].moves[0].name) + pass |