diff options
Diffstat (limited to 'extras/vba.py')
-rw-r--r-- | extras/vba.py | 216 |
1 files changed, 216 insertions, 0 deletions
diff --git a/extras/vba.py b/extras/vba.py index 1d1e1e5c5..14c96e3f1 100644 --- a/extras/vba.py +++ b/extras/vba.py @@ -70,7 +70,11 @@ TOOD: import os import sys +import re from array import array +import string +from copy import copy +import unittest # for converting bytes to readable text from chars import chars @@ -432,6 +436,136 @@ def press(buttons, steplimit=1): for step_counter in range(0, steplimit): Gb.step(number) +class Registers: + order = [ + "pc", + "sp", + "af", + "bc", + "de", + "hl", + "iff", + "div", + "tima", + "tma", + "tac", + "if", + "lcdc", + "stat", + "scy", + "scx", + "ly", + "lyc", + "dma", + "wy", + "wx", + "vbk", + "hdma1", + "hdma2", + "hdma3", + "hdma4", + "hdma5", + "svbk", + "ie", + ] + + def __setitem__(self, key, value): + current_registers = get_registers() + current_registers[Registers.order.index(key)] = value + set_registers(current_registers) + + def __getitem__(self, key): + current_registers = get_registers() + return current_registers[Registers.order.index(key)] + + def __list__(self): + return get_registers() + + def _get_register(id): + def constructed_func(self, id=copy(id)): + return get_registers()[id] + return constructed_func + + def _set_register(id): + def constructed_func(self, value, id=copy(id)): + current_registers = get_registers() + current_registers[id] = value + set_registers(current_registers) + return constructed_func + + pc = property(fget=_get_register(0), fset=_set_register(0)) + sp = property(fget=_get_register(1), fset=_set_register(1)) + af = property(fget=_get_register(2), fset=_set_register(2)) + bc = property(fget=_get_register(3), fset=_set_register(3)) + de = property(fget=_get_register(4), fset=_set_register(4)) + hl = property(fget=_get_register(5), fset=_set_register(5)) + iff = property(fget=_get_register(6), fset=_set_register(6)) + div = property(fget=_get_register(7), fset=_set_register(7)) + tima = property(fget=_get_register(8), fset=_set_register(8)) + tma = property(fget=_get_register(9), fset=_set_register(9)) + tac = property(fget=_get_register(10), fset=_set_register(10)) + _if = property(fget=_get_register(11), fset=_set_register(11)) + lcdc = property(fget=_get_register(12), fset=_set_register(12)) + stat = property(fget=_get_register(13), fset=_set_register(13)) + scy = property(fget=_get_register(14), fset=_set_register(14)) + scx = property(fget=_get_register(15), fset=_set_register(15)) + ly = property(fget=_get_register(16), fset=_set_register(16)) + lyc = property(fget=_get_register(17), fset=_set_register(17)) + dma = property(fget=_get_register(18), fset=_set_register(18)) + wy = property(fget=_get_register(19), fset=_set_register(19)) + wx = property(fget=_get_register(20), fset=_set_register(20)) + vbk = property(fget=_get_register(21), fset=_set_register(21)) + hdma1 = property(fget=_get_register(22), fset=_set_register(22)) + hdma2 = property(fget=_get_register(23), fset=_set_register(23)) + hdma3 = property(fget=_get_register(24), fset=_set_register(24)) + hdma4 = property(fget=_get_register(25), fset=_set_register(25)) + hdma5 = property(fget=_get_register(26), fset=_set_register(26)) + svbk = property(fget=_get_register(27), fset=_set_register(27)) + ie = property(fget=_get_register(28), fset=_set_register(28)) + + def __repr__(self): + spacing = "\t" + output = "Registers:\n" + for (id, each) in enumerate(self.order): + output += spacing + each + " = " + hex(get_registers()[id]) + #hex(self[each]) + output += "\n" + return output + +registers = Registers() + +def call(bank, address): + """ + Jumps into a function at a certain address. + + Go into the start menu, pause the game and try call(1, 0x1078) to see a + string printed to the screen. + """ + push = [ + registers.pc, + registers.hl, + registers.de, + registers.bc, + registers.af, + 0x3bb7, + ] + + for value in push: + registers.sp -= 2 + set_memory_at(registers.sp + 1, value >> 8) + set_memory_at(registers.sp, value & 0xFF) + if get_memory_range(registers.sp, 2) != [value & 0xFF, value >> 8]: + print "desired memory values: " + str([value & 0xFF, value >> 8] ) + print "actual memory values: " + str(get_memory_range(registers.sp , 2)) + print "wrong value at " + hex(registers.sp) + " expected " + hex(value) + " but got " + hex(get_memory_at(registers.sp)) + + if bank != 0: + registers["af"] = (bank << 8) | (registers["af"] & 0xFF) + registers["hl"] = address + registers["pc"] = 0x2d63 # FarJump + else: + registers["pc"] = address + class crystal: """ Just a simple namespace to store a bunch of functions for Pokémon Crystal. @@ -459,6 +593,10 @@ class crystal: set_memory_at(0xC2FC, 0) set_memory_at(0xC2FD, 0) + #@staticmethod + #def set_enemy_level(level): + # set_memory_at(0xd213, level) + @staticmethod def nstep(steplimit=500): """ @@ -467,6 +605,7 @@ class crystal: """ for step_counter in range(0, steplimit): crystal.walk_through_walls() + #call(0x1, 0x1078) step() @staticmethod @@ -581,6 +720,55 @@ class crystal: set_memory_at(0xd434, 0 & 251) @staticmethod + def warp_pokecenter(): + crystal.warp(1, 1, 3, 3) + crystal.nstep(200) + + @staticmethod + def masterballs(): + # masterball + set_memory_at(0xd8d8, 1) + set_memory_at(0xd8d9, 99) + + # ultraball + set_memory_at(0xd8da, 2) + set_memory_at(0xd8db, 99) + + # pokeballs + set_memory_at(0xd8dc, 5) + set_memory_at(0xd8dd, 99) + + @staticmethod + def get_text(): + """ + Returns alphanumeric text on the screen. Other characters will not be + shown. + """ + output = "" + tiles = get_memory_range(0xc4a0, 1000) + for each in tiles: + if each in chars.keys(): + thing = chars[each] + acceptable = False + + if len(thing) == 2: + portion = thing[1:] + else: + portion = thing + + if portion in string.printable: + acceptable = True + + if acceptable: + output += thing + + # remove extra whitespace + output = re.sub(" +", " ", output) + output = output.strip() + + return output + + @staticmethod def set_partymon2(): """ This causes corruption, so it's not working yet. @@ -621,3 +809,31 @@ class crystal: set_memory(memory) +class TestEmulator(unittest.TestCase): + state = load_state("cheating-12") + + def setUp(self): + load_rom() + set_state(self.state) + + def tearDown(self): + shutdown() + + def test_PlaceString(self): + call(0, 0x1078) + + # where to draw the text + registers["hl"] = 0xc4a0 + + # what text to read from + registers["de"] = 0x1276 + + nstep(10) + + text = crystal.get_text() + + self.assertTrue("TRAINER" in text) + +if __name__ == "__main__": + unittest.main() + |