summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBryan Bishop <kanzure@gmail.com>2013-09-07 23:37:05 -0500
committerBryan Bishop <kanzure@gmail.com>2013-09-07 23:37:05 -0500
commit92a4be1776c89bafff0a39c58dbad7b3f7dc77e2 (patch)
tree454909a76b0cff87a7c6718eea1e09b329c9990a
parent63bd0e4d6fcb77766dc12fd94788deff586972cd (diff)
better vba automation methods
-rw-r--r--vba.py187
1 files changed, 179 insertions, 8 deletions
diff --git a/vba.py b/vba.py
index f0d8430..1efec4c 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,142 @@ 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 better_text_wait(limit=500):
+ """
+ Try to get out of text.
+ """
+ done = False
+
+ while not done:
+ if limit == 0:
+ raise Exception("limit reached")
+
+ press("a", holdsteps=10, aftersteps=1)
+
+ stack = get_stack()
+
+ # PrintLetterDelay
+ pld = range(0x313d, 0x318c)
+
+ delayframes = range(0x468, 0x46f)
+
+ if any([address in stack for address in [0xaef] + pld + delayframes + range(0xa35, 0xa46)]):
+ press("a", holdsteps=10, aftersteps=1)
+ else:
+ print str([hex(x) for x in stack])
+ break
+
+ limit = limit - 1
+
+ print "limit is: " + str(limit)
+
+ @staticmethod
+ 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()
- press("a", holdsteps=50, aftersteps=1)
+ # 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
+
+ # "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 +1137,65 @@ 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()
+
+ @staticmethod
+ def bad_move_d042(cmd, limit=1000):
+ """
+ Move until not moving.
+ """
+ press(cmd, holdsteps=10, aftersteps=0)
+ press([])
+
+ # still standing? probably at a wall or something.
+ if get_memory()[0xd042] == 0x3e:
+ return
+
+ counter = 0
+
+ # this doesn't work because sometimes 0xd042 happens more/less times
+ while counter <= 6:
+ # check MovementAnimation
+ if get_memory()[0xd042] != 0x3e:
+ print "0xd042 is not 0x3e"
+ counter += 1
+
+ # make the emulator state advance one frame or w/e
+ step()
+
+ print "counter: " + str(counter)
+
class TestEmulator(unittest.TestCase):
try:
state = load_state("cheating-12")