diff --git a/.gitignore b/.gitignore index 77577a838..502cab285 100644 --- a/.gitignore +++ b/.gitignore @@ -37,3 +37,5 @@ pokecrystal.rtc # some users are dumping png.py into extras/ extras/png.py + +*$py.class diff --git a/extras/gfx.py b/extras/gfx.py index 22ecc7cc6..1504933a4 100644 --- a/extras/gfx.py +++ b/extras/gfx.py @@ -27,23 +27,23 @@ def mkdir_p(path): else: raise -def hex_dump(input, debug = True): +def hex_dump(input, debug=True): """ Display hex dump in rows of 16 bytes. """ - + dump = '' output = '' stream = '' address = 0x00 margin = 2 + len(hex(len(input))[2:]) - + # dump for byte in input: cool = hex(byte)[2:].zfill(2) dump += cool + ' ' if debug: stream += cool - + # convenient for testing quick edits in bgb if debug: output += stream + '\n' @@ -52,17 +52,16 @@ def hex_dump(input, debug = True): chars_per_byte = 3 # '__ ' chars_per_line = bytes_per_line * chars_per_byte num_lines = int(ceil(float(len(dump)) / float(chars_per_line))) - + # top # margin for char in range(margin): output += ' ' - # for byte in range(bytes_per_line): output += hex(byte)[2:].zfill(2) + ' ' output = output[:-1] # last space - + # print hex for line in range(num_lines): # address @@ -72,7 +71,7 @@ def hex_dump(input, debug = True): end = chars_per_line + start - 1 # ignore last space output += dump[start:end] address += 0x10 - + return output @@ -83,7 +82,7 @@ def get_tiles(image): tiles = [] tile = [] bytes_per_tile = 16 - + cur_byte = 0 for byte in image: # build tile @@ -113,7 +112,7 @@ def transpose(tiles): """ Transpose a tile arrangement along line y=x. """ - + # horizontal <-> vertical # 00 01 02 03 04 05 00 06 0c 12 18 1e # 06 07 08 09 0a 0b 01 07 0d 13 19 1f @@ -122,7 +121,7 @@ def transpose(tiles): # 18 19 1a 1b 1c 1d 04 0a 10 16 1c 22 # 1e 1f 20 21 22 23 05 0b 11 17 1d 23 # etc - + flipped = [] t = 0 # which tile we're on w = int(sqrt(len(tiles))) # assume square image @@ -196,18 +195,18 @@ lowmax = 1 << 5 # standard 5-bit param class Compressed: - + """ Compress 2bpp data. """ - - def __init__(self, image = None, mode = 'horiz', size = None): + + def __init__(self, image=None, mode='horiz', size=None): assert image, 'need something to compress!' image = list(image) self.image = image self.pic = [] self.animtiles = [] - + # only transpose pic (animtiles were never transposed in decompression) if size != None: for byte in range((size*size)*16): @@ -221,7 +220,7 @@ class Compressed: self.tiles = get_tiles(self.pic) self.tiles = transpose(self.tiles) self.pic = connect(self.tiles) - + self.image = self.pic + self.animtiles self.end = len(self.image) @@ -326,15 +325,15 @@ class Compressed: def scanRepeats(self): """ Works, but doesn't do flipped/reversed streams yet. - + This takes up most of the compress time and only saves a few bytes it might be more feasible to exclude it entirely. """ - + self.repeats = [] self.flips = [] self.reverses = [] - + # make a 5-letter word list of the sequence letters = 5 # how many bytes it costs to use a repeat over a literal # any shorter and it's not worth the trouble @@ -345,7 +344,7 @@ class Compressed: for j in range(letters): word.append( ord(self.image[i+j]) ) words.append((word, i)) - + zeros = [] for zero in range(letters): zeros.append( 0 ) @@ -405,13 +404,13 @@ class Compressed: else: # no more overlaps buffer.append(match) else: # last match, so there's nothing to check - buffer.append(match) + buffer.append(match) matches = buffer # remove alternating sequences buffer = [] for match in matches: - for i in range(6 if letters > 6 else letters): + for i in range(6 if letters > 6 else letters): if match[0][i] != match[0][i&1]: buffer.append(match) break @@ -422,7 +421,7 @@ class Compressed: def doRepeats(self): """doesn't output the right values yet""" - + unusedrepeats = [] for repeat in self.repeats: if self.address >= repeat[2]: @@ -598,7 +597,7 @@ class Decompressed: data can be fed in from rom if [start] is specified """ - def __init__(self, lz = None, mode = None, size = None, start = 0): + def __init__(self, lz=None, mode=None, size=None, start=0): # todo: play nice with Compressed assert lz, 'need something to compress!' @@ -734,7 +733,7 @@ class Decompressed: def doFlip(self): """ Repeat flipped bytes from 2bpp output. - + eg 11100100 -> 00100111 quat 3 2 1 0 -> 0 2 1 3 """ @@ -831,7 +830,7 @@ unowns = 0x124000 num_unowns = 26 unown_dex = 201 -def decompress_monster_by_id(id = 0, type = front): +def decompress_monster_by_id(id=0, type=front): # no unowns here if id + 1 == unown_dex: return None # get size @@ -847,7 +846,7 @@ def decompress_monster_by_id(id = 0, type = front): monster = Decompressed(rom, 'vert', size, address) return monster -def decompress_monsters(type = front): +def decompress_monsters(type=front): for id in range(num_monsters): # decompress monster = decompress_monster_by_id(id, type) @@ -865,7 +864,7 @@ def decompress_monsters(type = front): to_file(folder+filename, monster.pic) -def decompress_unown_by_id(letter, type = front): +def decompress_unown_by_id(letter, type=front): # get size if type == front: size = sizes[unown_dex-1] @@ -879,7 +878,7 @@ def decompress_unown_by_id(letter, type = front): unown = Decompressed(rom, 'vert', size, address) return unown -def decompress_unowns(type = front): +def decompress_unowns(type=front): for letter in range(num_unowns): # decompress unown = decompress_unown_by_id(letter, type) @@ -993,7 +992,7 @@ def decompress_misc(): gfx = Decompressed( rom, mode, None, address ) to_file(filename, gfx.output) -def decompress_all(debug = False): +def decompress_all(debug=False): """ Decompress all known compressed data in baserom. """ @@ -1028,7 +1027,7 @@ def decompress_all(debug = False): return -def decompress_from_address(address, mode='horiz', filename = 'de.2bpp', size = None): +def decompress_from_address(address, mode='horiz', filename='de.2bpp', size=None): """ Write decompressed data from an address to a 2bpp file. """ @@ -1036,7 +1035,7 @@ def decompress_from_address(address, mode='horiz', filename = 'de.2bpp', size = to_file(filename, image.pic) -def decompress_file(filein, fileout, mode = 'horiz', size = None): +def decompress_file(filein, fileout, mode='horiz', size=None): f = open(filein, 'rb') image = f.read() f.close() @@ -1046,7 +1045,7 @@ def decompress_file(filein, fileout, mode = 'horiz', size = None): to_file(fileout, de.pic) -def compress_file(filein, fileout, mode = 'horiz'): +def compress_file(filein, fileout, mode='horiz'): f = open(filein, 'rb') image = f.read() f.close() @@ -1099,7 +1098,7 @@ def hex_to_rgb(word): blue = word & 0b11111 return (red, green, blue) -def grab_palettes(address, length = 0x80): +def grab_palettes(address, length=0x80): output = '' for word in range(length/2): color = ord(rom[address+1])*0x100 + ord(rom[address]) @@ -1228,7 +1227,7 @@ def dmg2rgb(word): blue = word & 0b11111 alpha = 255 return ((red<<3)+0b100, (green<<3)+0b100, (blue<<3)+0b100, alpha) - + def rgb_to_dmg(color): word = (color['r'] / 8) word += (color['g'] / 8) << 5 @@ -1556,8 +1555,8 @@ def lz_to_png_by_file(filename): def dump_tileset_pngs(): """ - Convert .lz format tilesets into .png format tilesets. - + Convert .lz format tilesets into .png format tilesets. + Also, leaves a bunch of wonderful .2bpp files everywhere for your amusement. """ for tileset_id in range(37): @@ -1581,7 +1580,7 @@ def decompress_frontpic_anim(lz_file): def expand_pic_palettes(): """ Add white and black to palette files with fewer than 4 colors. - + Pokemon Crystal only defines two colors for a pic palette to save space, filling in black/white at runtime. Instead of managing palette files of varying length, black @@ -1601,7 +1600,7 @@ def expand_pic_palettes(): if __name__ == "__main__": debug = False - + argv = [None] * 5 for i, arg in enumerate(sys.argv): argv[i] = arg @@ -1667,7 +1666,7 @@ if __name__ == "__main__": filein = argv[2] fileout = argv[3] compress_file(filein, fileout) - + elif argv[1] == '2bpp-to-png': to_png(argv[2]) diff --git a/extras/vba.py b/extras/vba.py index c48e377b5..9b5d6e443 100644 --- a/extras/vba.py +++ b/extras/vba.py @@ -119,9 +119,9 @@ if not os.path.exists(rom_path): def _check_java_library_path(): """ - Returns the value of java.library.path. - - The vba-clojure library must be compiled + Returns the value of java.library.path. + + The vba-clojure library must be compiled and linked from this location. """ return System.getProperty("java.library.path") @@ -159,8 +159,8 @@ a, b, r, l, u, d, select, start, restart = "a", "b", "r", "l", "u", "d", "select def button_combiner(buttons): """ - Combines multiple button presses into an integer. - + Combines multiple button presses into an integer. + This is used when sending a keypress to the emulator. """ result = 0 @@ -196,8 +196,8 @@ def button_combiner(buttons): def load_rom(path=None): """ - Starts the emulator with a certain ROM. - + Starts the emulator with a certain ROM. + Defaults to rom_path if no parameters are given. """ if path == None: @@ -215,8 +215,8 @@ def load_rom(path=None): def shutdown(): """ - Stops the emulator. Closes the window. - + Stops the emulator. Closes the window. + The "opposite" of this is the load_rom function. """ Gb.shutdown() @@ -251,8 +251,8 @@ def translate_chars(charz): def _create_byte_buffer(data): """ - Converts data into a ByteBuffer. - + Converts data into a ByteBuffer. + This is useful for interfacing with the Gb class. """ buf = ByteBuffer.allocateDirect(len(data)) @@ -266,11 +266,11 @@ def _create_byte_buffer(data): def set_state(state, do_step=False): """ - Injects the given state into the emulator. - - Use do_step if you want to call step(), which also allows - SDL to render the latest frame. Note that the default is to - not step, and that the screen (if it is enabled) will appear + Injects the given state into the emulator. + + Use do_step if you want to call step(), which also allows + SDL to render the latest frame. Note that the default is to + not step, and that the screen (if it is enabled) will appear as if it still has the last state loaded. This is normal. """ Gb.loadState(_create_byte_buffer(state)) @@ -289,8 +289,8 @@ def get_state(): def save_state(name, state=None, override=False): """ - Saves the given state to save_state_path. - + Saves the given state to save_state_path. + The file format must be ".sav" (and this will be appended to your string if necessary). """ @@ -313,8 +313,8 @@ def save_state(name, state=None, override=False): def load_state(name): """ - Reads a state from file based on name. - + Reads a state from file based on name. + Looks in save_state_path for a file with this name (".sav" is optional). """ @@ -340,8 +340,8 @@ def generate_root(): def get_root(): """ - Loads the root state. - + Loads the root state. + (Or restarts the emulator and creates a new root state.) """ try: @@ -397,16 +397,16 @@ def get_memory(): def set_memory(memory): """ - Sets memory in the emulator. - + 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. - + Returns a list of pixels on the screen display. + Broken, probably. Use screenshot() instead. """ sys.stderr.write("ERROR: seems to be broken on VBA's end? Good luck. Use" @@ -418,9 +418,9 @@ def get_pixels(): def screenshot(filename, literal=False): """ - Saves a PNG screenshot to the file at filename. - - Use literal if you want to store it in the current directory. + Saves a PNG screenshot to the file at filename. + + Use literal if you want to store it in the current directory. Default is to save it to screenshots/ under the project. """ screenshots_path = os.path.join(project_path, "screenshots/") @@ -453,17 +453,17 @@ def get_memory_range(start_address, byte_count): def set_memory_at(address, value): """ - Sets a byte at a certain address in memory. - - This directly sets the memory instead of copying + 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, holdsteps=1, aftersteps=1): """ - Press a button. - + Press a button. + Use steplimit to say for how many steps you want to press the button (try leaving it at the default, 1). """ @@ -483,8 +483,8 @@ def press(buttons, holdsteps=1, aftersteps=1): def get_buttons(): """ - Returns the currentButtons[0] value - + Returns the currentButtons[0] value + (an integer with bits set for which buttons are currently pressed). """ @@ -773,11 +773,11 @@ class crystal: @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 + 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) @@ -793,7 +793,7 @@ class crystal: def nstep(steplimit=500): """ Steps the CPU forward and calls some functions in between each step. - + (For example, to manipulate memory.) This is pretty slow. """ for step_counter in range(0, steplimit): @@ -848,9 +848,9 @@ class crystal: @staticmethod def menu_select(id=1): """ - Sets the cursor to the given pokemon in the player's party. - - This is under Start -> PKMN. This is useful for selecting a + Sets the cursor to the given pokemon in the player's party. + + This is under Start -> PKMN. This is useful for selecting a certain pokemon with fly or another skill. This probably works on other menus. @@ -936,8 +936,8 @@ class crystal: @staticmethod def get_text(): """ - Returns alphanumeric text on the screen. - + Returns alphanumeric text on the screen. + Other characters will not be shown. """ output = ""