summaryrefslogtreecommitdiff
path: root/vba.py
diff options
context:
space:
mode:
authorBryan Bishop <kanzure@gmail.com>2013-09-08 17:11:17 -0700
committerBryan Bishop <kanzure@gmail.com>2013-09-08 17:11:17 -0700
commit87ab004d7014e1826a43f751c8a34e4b470faab3 (patch)
tree5d19a8bb6e8a77b3a0a89e5b7bac87a2baa1b641 /vba.py
parentc5983b0ddc6efd59e72c64bafc95af5b8fd93d86 (diff)
parent15c04c9885c639bd9b52cd94f6dc5442df52fab0 (diff)
Merge pull request #19 from kanzure/vba-automation
More VBA automation.
Diffstat (limited to 'vba.py')
-rw-r--r--vba.py131
1 files changed, 123 insertions, 8 deletions
diff --git a/vba.py b/vba.py
index f0d8430..ea7bb2e 100644
--- a/vba.py
+++ b/vba.py
@@ -115,7 +115,7 @@ except ImportError:
print "Not loading the keyboard module (which uses networkx)."
if not os.path.exists(rom_path):
- raise Exception("rom_path is not configured properly; edit vba_config.py?")
+ raise Exception("rom_path is not configured properly; edit vba_config.py? " + str(rom_path))
def _check_java_library_path():
"""
@@ -736,30 +736,112 @@ class cheats:
"""
Gb.cheatAddGameshark(code, description)
-class crystal:
+def get_stack():
+ """
+ Return a list of functions on the stack.
+ """
+ addresses = []
+ sp = registers.sp
+
+ for x in range(0, 11):
+ sp = sp - (2 * x)
+ hi = get_memory_at(sp + 1)
+ lo = get_memory_at(sp)
+ address = ((hi << 8) | lo)
+ addresses.append(address)
+ return addresses
+
+class crystal:
"""
Just a simple namespace to store a bunch of functions for Pokémon Crystal.
"""
@staticmethod
- def text_wait(step_size=10, max_wait=500):
+ def text_wait(step_size=1, max_wait=200, sfx_limit=0, debug=False, callback=None):
"""
Presses the "A" button when text is done being drawn to screen.
+ The `debug` parameter is only useful when debugging this function. It
+ enables the `max_wait` feature, which causes the function to exit
+ instead of hanging around.
+
+ The `sfx_limit` parameter is useful for when the player is given an
+ item during the text. Set it to 1 to not treat the sound as the end of
+ text. The next loop around it will return to the normal behavior of the
+ function.
+
:param step_size: number of steps per wait loop
:param max_wait: number of wait loops to perform
"""
- for x in range(0, max_wait):
+ while max_wait > 0:
hi = get_memory_at(registers.sp + 1)
lo = get_memory_at(registers.sp)
address = ((hi << 8) | lo)
- if address == 0xaef:
- break
+
+ if address in range(0xa1b, 0xa46) + range(0xaaf, 0xaf5): # 0xaef:
+ print "pressing, then breaking.. address is: " + str(hex(address))
+
+ # set CurSFX
+ set_memory_at(0xc2bf, 0)
+
+ press("a", holdsteps=10, aftersteps=1)
+
+ # check if CurSFX is SFX_READ_TEXT_2
+ if get_memory_at(0xc2bf) == 0x8:
+ print "cursfx is set to SFX_READ_TEXT_2, looping.."
+ return crystal.text_wait(step_size=step_size, max_wait=max_wait, debug=debug, callback=callback, sfx_limit=sfx_limit)
+ else:
+ if sfx_limit > 0:
+ sfx_limit = sfx_limit - 1
+ print "decreasing sfx_limit"
+ else:
+ # probably the last textbox in a sequence
+ print "cursfx is not set to SFX_READ_TEXT_2, so: breaking"
+
+ break
else:
- nstep(step_size)
+ stack = get_stack()
+
+ # yes/no box or the name selection box
+ if address in range(0xa46, 0xaaf):
+ print "probably at a yes/no box.. exiting."
+ break
+
+ # date/time box (day choice)
+ # 0x47ab is the one from the intro, 0x49ab is the one from mom.
+ elif 0x47ab in stack or 0x49ab in stack: # was any([x in stack for x in range(0x46EE, 0x47AB)])
+ print "probably at a date/time box ? exiting."
+ break
- press("a", holdsteps=50, aftersteps=1)
+ # "How many minutes?" selection box
+ elif 0x4826 in stack:
+ print "probably at a \"How many minutes?\" box ? exiting."
+ break
+
+ else:
+ nstep(step_size)
+
+ # if there is a callback, then call the callback and exit when the
+ # callback returns True. This is especially useful during the
+ # OakSpeech intro where textboxes are running constantly, and then
+ # suddenly the player can move around. One way to detect that is to
+ # set callback to a function that returns
+ # "vba.get_memory_at(0xcfb1) != 0".
+ if callback != None:
+ result = callback()
+ if result == True:
+ print "callback returned True, exiting"
+ return
+
+ # only useful when debugging. When this is left on, text that
+ # takes a while to print to screen will cause this function to
+ # exit.
+ if debug == True:
+ max_wait = max_wait - 1
+
+ if max_wait == 0:
+ print "max_wait was hit"
@staticmethod
def walk_through_walls_slow():
@@ -1025,6 +1107,39 @@ class crystal:
set_memory(memory)
+ @staticmethod
+ def wait_for_script_running(debug=False, limit=1000):
+ """
+ Wait until ScriptRunning isn't -1.
+ """
+ while limit > 0:
+ if get_memory_at(0xd438) != 255:
+ print "script is done executing"
+ return
+ else:
+ step()
+
+ if debug:
+ limit = limit - 1
+
+ if limit == 0:
+ print "limit ran out"
+
+ @staticmethod
+ def move(cmd):
+ """
+ Attempt to move the player.
+ """
+ press(cmd, holdsteps=10, aftersteps=0)
+ press([])
+
+ memory = get_memory()
+ #while memory[0xd4e1] == 2 and memory[0xd042] != 0x3e:
+ while memory[0xd043] in [0, 1, 2, 3]:
+ #while memory[0xd043] in [0, 1, 2, 3] or memory[0xd042] != 0x3e:
+ nstep(10)
+ memory = get_memory()
+
class TestEmulator(unittest.TestCase):
try:
state = load_state("cheating-12")