summaryrefslogtreecommitdiff
path: root/extras/vba.py
diff options
context:
space:
mode:
Diffstat (limited to 'extras/vba.py')
-rw-r--r--extras/vba.py216
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()
+