shithub: pokecrystal

Download patch

ref: ec098d1a03e28e07c3bbd3174b5f02b713c24b6f
parent: 160acfa2967e898f97ba2b92e8602146bdf5b714
author: Bryan Bishop <[email protected]>
date: Tue Feb 26 16:49:54 EST 2013

various helper functions for the vba interface

New vba.py features include:
* get_memory_at
* get_memory_range
* set_memory_at

Also, the "crystal" class has a number of specialty helpers:
* crystal.walk_through_walls
* crystal.get_player_name
* crystal.get_map_name
* crystal.get_xy
* crystal.nstep (which sets memory each step by calling certain
* functions, like walk_through_walls)
* crystal.is_in_battle
* crystal.get_gender

--- a/extras/vba.py
+++ b/extras/vba.py
@@ -54,12 +54,13 @@
     # or why not the other way around?
     vba.set_state(vba.load_state("unknown-delete-me"))
 
-    registers = vba.get_registers()
+    vba.get_memory_at(0xDCDA)
+    vba.set_memory_at(0xDCDB, 0xFF)
+    vba.get_memory_range(0xDCDA, 10)
 
 TOOD:
     [ ] set a specific register
     [ ] get a specific register
-    [ ] write value at address
     [ ] breakpoints
     [ ] vgm stuff
     [ ] gbz80disasm integration
@@ -71,6 +72,11 @@
 import sys
 from array import array
 
+# for converting bytes to readable text
+from chars import chars
+
+from map_names import map_names
+
 # for _check_java_library_path
 from java.lang import System
 
@@ -157,7 +163,7 @@
 
     for each in buttons:
         result |= button_masks[each]
-    
+
     print "button: " + str(result)
     return result
 
@@ -208,6 +214,12 @@
 # just some aliases for step_until_capture
 run = go = step_until_capture
 
+def translate_chars(charz):
+    result = ""
+    for each in charz:
+        result += chars[each]
+    return result
+
 def _create_byte_buffer(data):
     """
     Converts data into a ByteBuffer. This is useful for interfacing with the Gb
@@ -310,7 +322,7 @@
 
 def get_rom():
     """
-    Returns the ROM in bytes.. in a string.
+    Returns the ROM in bytes.
     """
     rom_array = jarray.zeros(Gb.ROM_SIZE, "i")
     Gb.getROM(rom_array)
@@ -318,7 +330,7 @@
 
 def get_ram():
     """
-    Returns the RAM in bytes in a string.
+    Returns the RAM in bytes.
     """
     ram_array = jarray.zeros(Gb.RAM_SIZE, "i")
     Gb.getRAM(ram_array)
@@ -332,14 +344,20 @@
 
 def get_memory():
     """
-    Returns memory in bytes in a string.
+    Returns memory in bytes.
     """
-    raise NotImplementedError("dunno how to calculate memory size")
-    # memory_size = ...
+    memory_size = 0x10000
     memory = jarray.zeros(memory_size, "i")
     Gb.getMemory(memory)
     return RomList(memory)
 
+def set_memory(memory):
+    """
+    Sets memory in the emulator. Use get_memory() to retrieve the current
+    state.
+    """
+    Gb.writeMemory(memory)
+
 def get_pixels():
     """
     Returns a list of pixels on the screen display. Broken, probably. Use
@@ -371,7 +389,28 @@
     Read an integer at an address.
     """
     return Gb.readMemory(address)
+get_memory_at = read_memory
 
+def get_memory_range(start_address, byte_count):
+    """
+    Returns a list of bytes.
+
+    start_address - address to start reading at
+    byte_count - how many bytes (0 returns just 1 byte)
+    """
+    bytez = []
+    for counter in range(0, byte_count):
+        byte = get_memory_at(start_address + counter)
+        bytez.append(byte)
+    return bytez
+
+def set_memory_at(address, value):
+    """
+    Sets a byte at a certain address in memory. This directly sets the memory
+    instead of copying the memory from the emulator.
+    """
+    Gb.setMemoryAt(address, value)
+
 def press(buttons, steplimit=1):
     """
     Press a button. Use steplimit to say for how many steps you want to press
@@ -385,4 +424,161 @@
         number = buttons
     for step_counter in range(0, steplimit):
         Gb.step(number)
+
+class crystal:
+    """
+    Just a simple namespace to store a bunch of functions for Pokémon Crystal.
+    """
+
+    @staticmethod
+    def walk_through_walls_slow():
+        memory = get_memory()
+        memory[0xC2FA] = 0
+        memory[0xC2FB] = 0
+        memory[0xC2FC] = 0
+        memory[0xC2FD] = 0
+        set_memory(memory)
+
+    @staticmethod
+    def walk_through_walls():
+        """
+        Lets the player walk all over the map. These values are probably reset
+        by some of the map/collision functions when you move on to a new
+        location, so this needs to be executed each step/tick if continuous
+        walk-through-walls is desired.
+        """
+        set_memory_at(0xC2FA, 0)
+        set_memory_at(0xC2FB, 0)
+        set_memory_at(0xC2FC, 0)
+        set_memory_at(0xC2FD, 0)
+
+    @staticmethod
+    def nstep(steplimit=500):
+        """
+        Steps the CPU forward and calls some functions in between each step,
+        like to manipulate memory. This is pretty slow.
+        """
+        for step_counter in range(0, steplimit):
+            crystal.walk_through_walls()
+            step()
+
+    @staticmethod
+    def get_map_group_id():
+        """
+        Returns the current map group.
+        """
+        return get_memory_at(0xdcb5)
+
+    @staticmethod
+    def get_map_id():
+        """
+        Returns the map number of the current map.
+        """
+        return get_memory_at(0xdcb6)
+
+    @staticmethod
+    def get_map_name():
+        """
+        Figures out the current map name.
+        """
+        map_group_id = crystal.get_map_group_id()
+        map_id = crystal.get_map_id()
+        return map_names[map_group_id][map_id]["name"]
+
+    @staticmethod
+    def get_xy():
+        """
+        (x, y) coordinates of player on map.
+        Relative to top-left corner of map.
+        """
+        x = get_memory_at(0xdcb8)
+        y = get_memory_at(0xdcb7)
+        return (x, y)
+
+    @staticmethod
+    def is_in_battle():
+        """
+        Checks whether or not we're in a battle.
+        """
+        return (get_memory_at(0xd22d) != 0) or crystal.is_in_link_battle()
+
+    @staticmethod
+    def is_in_link_battle():
+        return get_memory_at(0xc2dc) != 0
+
+    @staticmethod
+    def unlock_flypoints():
+        """
+        Unlocks different destinations for flying.
+
+        Note: this might start at 0xDCA4 (minus one on all addresses), but not
+        sure.
+        """
+        set_memory_at(0xDCA5, 0xFF)
+        set_memory_at(0xDCA6, 0xFF)
+        set_memory_at(0xDCA7, 0xFF)
+        set_memory_at(0xDCA8, 0xFF)
+
+    @staticmethod
+    def get_gender():
+        """
+        Returns 'male' or 'female'.
+        """
+        gender = get_memory_at(0xD472)
+        if gender == 0:
+            return "male"
+        elif gender == 1:
+            return "female"
+        else:
+            return gender
+
+    @staticmethod
+    def get_player_name():
+        """
+        Returns the 7 characters making up the player's name.
+        """
+        bytez = get_memory_range(0xD47D, 7)
+        name = translate_chars(bytez)
+        return name
+
+    @staticmethod
+    def set_partymon2():
+        """
+        This causes corruption, so it's not working yet.
+        """
+        memory = get_memory()
+        memory[0xdcd7] = 2
+        memory[0xdcd9] = 0x7
+
+        memory[0xdd0f] = 0x7
+        memory[0xdd10] = 0x1
+
+        # moves
+        memory[0xdd11] = 0x1
+        memory[0xdd12] = 0x2
+        memory[0xdd13] = 0x3
+        memory[0xdd14] = 0x4
+
+        # id
+        memory[0xdd15] = 0x1
+        memory[0xdd16] = 0x2
+
+        # experience
+        memory[0xdd17] = 0x2
+        memory[0xdd18] = 0x3
+        memory[0xdd19] = 0x4
+
+        # hp
+        memory[0xdd1a] = 0x5
+        memory[0xdd1b] = 0x6
+
+        # current hp
+        memory[0xdd31] = 0x10
+        memory[0xdd32] = 0x25
+
+        # max hp
+        memory[0xdd33] = 0x10
+        memory[0xdd34] = 0x40
+
+        set_memory(memory)