diff --git a/extras/comparator.py b/extras/comparator.py index 48bdb6b09..e338f4391 100644 --- a/extras/comparator.py +++ b/extras/comparator.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- """ -Finds shared functions between red/crystal. +Find shared functions between red/crystal. """ from crystal import ( @@ -18,13 +18,13 @@ from romstr import ( def load_rom(path): """ - Loads a ROM file into an abbreviated RomStr object. + Load a ROM file into an abbreviated RomStr object. """ return direct_load_rom(filename=path) def load_asm(path): """ - Loads source ASM into an abbreviated AsmList object. + Load source ASM into an abbreviated AsmList object. """ return direct_load_asm(filename=path) @@ -63,7 +63,8 @@ found_blobs = [] class BinaryBlob(object): """ - Stores a label, line number, and addresses of a function from Pokémon Red. + Store a label, line number, and addresses of a function from Pokémon Red. + These details can be used to determine whether or not the function was copied into Pokémon Crystal. """ @@ -128,7 +129,7 @@ class BinaryBlob(object): def parse_from_red(self): """ - Reads bytes from Pokémon Red and stores them. + Read bytes from Pokémon Red and stores them. """ self.bytes = redrom[self.start_address : self.end_address + 1] @@ -146,7 +147,7 @@ class BinaryBlob(object): def find_in_crystal(self): """ - Checks whether or not the bytes appear in Pokémon Crystal. + Check whether or not the bytes appear in Pokémon Crystal. """ finditer = findall_iter(self.bytes, cryrom) @@ -160,7 +161,7 @@ class BinaryBlob(object): def find_by_first_bytes(self): """ - Finds this blob in Crystal based on the first n bytes. + Find this blob in Crystal based on the first n bytes. """ # how many bytes to match @@ -194,7 +195,7 @@ redsrc = load_asm(pokered_src_path) def scan_red_asm(bank_stop=3, debug=True): """ - Scans the ASM from Pokémon Red. Finds labels and objects. Does things. + Scan the ASM from Pokémon Red. Finds labels and objects. Does things. Uses get_label_from_line and get_address_from_line_comment. """ diff --git a/extras/gbz80disasm.py b/extras/gbz80disasm.py index 2dc57e579..7de8e71e2 100644 --- a/extras/gbz80disasm.py +++ b/extras/gbz80disasm.py @@ -13,6 +13,11 @@ if not hasattr(json, "read"): json.read = json.loads def load_rom(filename="../baserom.gbc"): + """ + Load the specified rom. + + If no rom is given, load "../baserom.gbc". + """ global rom rom = bytearray(open(filename,'rb').read()) return rom @@ -557,6 +562,11 @@ call_commands = [0xdc, 0xd4, 0xc4, 0xcc, 0xcd] all_labels = {} def load_labels(filename="labels.json"): + """ + Load labels from specified file. + + If no filename is given, loads 'labels.json'. + """ global all_labels # don't re-load labels each time @@ -588,21 +598,28 @@ def find_label(local_address, bank_id=0): return None def asm_label(address): - # why using a random value when you can use the address? + """ + Return the ASM label using the address. + """ + return ".ASM_" + hex(address)[2:] -def output_bank_opcodes(original_offset, max_byte_count=0x4000, include_last_address=True, stop_at=[], debug = False): - #fs = current_address - #b = bank_byte - #in = input_data -- rom - #bank_size = byte_count - #i = offset - #ad = end_address - #a, oa = current_byte_number +def output_bank_opcodes(original_offset, max_byte_count=0x4000, include_last_address=True, stop_at=[], debug=False): + """ + Output bank opcodes. - # stop_at can be used to supply a list of addresses to not disassemble - # over. This is useful if you know in advance that there are a lot of - # fall-throughs. + fs = current_address + b = bank_byte + in = input_data -- rom + bank_size = byte_count + i = offset + ad = end_address + a, oa = current_byte_number + + stop_at can be used to supply a list of addresses to not disassemble + over. This is useful if you know in advance that there are a lot of + fall-throughs. + """ load_labels() load_rom() @@ -851,8 +868,9 @@ def output_bank_opcodes(original_offset, max_byte_count=0x4000, include_last_add def has_outstanding_labels(byte_labels): """ - If a label is used once in the asm output, then that means it has to be - called or specified later. + Check whether a label is used once in the asm output. + + If so, then that means it has to be called or specified later. """ for label_line in byte_labels.keys(): real_line = byte_labels[label_line] diff --git a/extras/gfx.py b/extras/gfx.py index a8e06cce8..b76f1df82 100644 --- a/extras/gfx.py +++ b/extras/gfx.py @@ -16,6 +16,9 @@ if __name__ != "__main__": def mkdir_p(path): + """ + Make a directory at a given path. + """ try: os.makedirs(path) except OSError as exc: # Python >2.5 @@ -25,7 +28,9 @@ def mkdir_p(path): def hex_dump(input, debug = True): - """display hex dump in rows of 16 bytes""" + """ + Display hex dump in rows of 16 bytes. + """ dump = '' output = '' @@ -71,7 +76,9 @@ def hex_dump(input, debug = True): def get_tiles(image): - """split a 2bpp image into 8x8 tiles""" + """ + Split a 2bpp image into 8x8 tiles. + """ tiles = [] tile = [] bytes_per_tile = 16 @@ -91,7 +98,9 @@ def get_tiles(image): def connect(tiles): - """combine 8x8 tiles into a 2bpp image""" + """ + Combine 8x8 tiles into a 2bpp image. + """ out = [] for tile in tiles: for byte in tile: @@ -100,7 +109,9 @@ def connect(tiles): def transpose(tiles): - """transpose a tile arrangement along line y=x""" + """ + Transpose a tile arrangement along line y=x. + """ # horizontal <-> vertical # 00 01 02 03 04 05 00 06 0c 12 18 1e @@ -184,7 +195,10 @@ lowmax = 1 << 5 # standard 5-bit param class Compressed: - """compress 2bpp data""" + + """ + Compress 2bpp data. + """ def __init__(self, image = None, mode = 'horiz', size = None): @@ -231,7 +245,9 @@ class Compressed: def compress(self): - """incomplete, but outputs working compressed data""" + """ + Incomplete, but outputs working compressed data. + """ self.address = 0 @@ -308,10 +324,11 @@ class Compressed: def scanRepeats(self): - """works, but doesn't do flipped/reversed streams yet + """ + 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""" + 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 = [] @@ -478,7 +495,7 @@ class Compressed: while (ord(self.image[(self.address)+1]) == self.alts[num_alts&1]) & (num_alts <= max_length): num_alts += 1 self.next() - # include the last alternated byte + # include the last alternated byte num_alts += 1 self.address = original_address if num_alts > lowmax: @@ -567,7 +584,8 @@ class Compressed: class Decompressed: - """parse compressed 2bpp data + """ + Parse compressed 2bpp data. parameters: [compressed 2bpp data] @@ -576,7 +594,8 @@ class Decompressed: [start] (optional) splits output into pic [size] and animation tiles if applicable - data can be fed in from rom if [start] is specified""" + data can be fed in from rom if [start] is specified + """ def __init__(self, lz = None, mode = None, size = None, start = 0): # todo: play nice with Compressed @@ -615,7 +634,9 @@ class Decompressed: def decompress(self): - """replica of crystal's decompression""" + """ + Replica of crystal's decompression. + """ self.output = [] @@ -674,19 +695,25 @@ class Decompressed: self.getCurByte() def doLiteral(self): - # copy 2bpp data directly + """ + Copy 2bpp data directly. + """ for byte in range(self.length): self.next() self.output.append(self.byte) def doIter(self): - # write one byte repeatedly + """ + Write one byte repeatedly. + """ self.next() for byte in range(self.length): self.output.append(self.byte) def doAlt(self): - # write alternating bytes + """ + Write alternating bytes. + """ self.alts = [] self.next() self.alts.append(self.byte) @@ -697,25 +724,27 @@ class Decompressed: self.output.append(self.alts[byte&1]) def doZeros(self): - # write zeros + """Write zeros.""" for byte in range(self.length): self.output.append(0x00) def doFlip(self): - # repeat flipped bytes from 2bpp output - # eg 11100100 -> 00100111 - # quat 3 2 1 0 -> 0 2 1 3 + """Repeat flipped bytes from 2bpp output. + + eg 11100100 -> 00100111 + quat 3 2 1 0 -> 0 2 1 3 + """ for byte in range(self.length): flipped = sum(1<<(7-i) for i in range(8) if self.output[self.displacement+byte]>>i&1) self.output.append(flipped) def doReverse(self): - # repeat reversed bytes from 2bpp output + """Repeat reversed bytes from 2bpp output.""" for byte in range(self.length): self.output.append(self.output[self.displacement-byte]) def doRepeat(self): - # repeat bytes from 2bpp output + """Repeat bytes from 2bpp output.""" for byte in range(self.length): self.output.append(self.output[self.displacement+byte]) @@ -741,7 +770,9 @@ sizes = [ ] def make_sizes(): - """front pics have specified sizes""" + """ + Front pics have specified sizes. + """ top = 251 base_stats = 0x51424 # print monster sizes @@ -955,7 +986,9 @@ def decompress_misc(): to_file(filename, gfx.output) def decompress_all(debug = False): - """decompress all known compressed data in baserom""" + """ + Decompress all known compressed data in baserom. + """ if debug: print 'fronts' decompress_monsters(front) @@ -988,7 +1021,9 @@ def decompress_all(debug = False): def decompress_from_address(address, mode='horiz', filename = 'de.2bpp', size = None): - """write decompressed data from an address to a 2bpp file""" + """ + Write decompressed data from an address to a 2bpp file. + """ image = Decompressed(rom, mode, size, address) to_file(filename, image.pic) @@ -1034,7 +1069,9 @@ def compress_monster_frontpic(id, fileout): def get_uncompressed_gfx(start, num_tiles, filename): - """grab tiles directly from rom and write to file""" + """ + Grab tiles directly from rom and write to file. + """ bytes_per_tile = 0x10 length = num_tiles*bytes_per_tile end = start + length @@ -1139,7 +1176,7 @@ def dump_trainer_pals(): def flatten(planar): """ - Flattens planar 2bpp image data into a quaternary pixel map. + Flatten planar 2bpp image data into a quaternary pixel map. """ strips = [] for pair in range(len(planar)/2): @@ -1155,7 +1192,7 @@ def flatten(planar): def to_lines(image, width): """ - Converts a tiled quaternary pixel map to lines of quaternary pixels. + Convert a tiled quaternary pixel map to lines of quaternary pixels. """ tile = 8 * 8 @@ -1208,8 +1245,8 @@ def png_pal(filename): def to_png(filein, fileout=None, pal_file=None, height=None, width=None): """ - Takes a planar 2bpp graphics file and converts it to png. - """ + Take a planar 2bpp graphics file and converts it to png. + """ if fileout == None: fileout = '.'.join(filein.split('.')[:-1]) + '.png' diff --git a/extras/overworldripper.py b/extras/overworldripper.py index 7148db6fd..654f28747 100644 --- a/extras/overworldripper.py +++ b/extras/overworldripper.py @@ -1,6 +1,11 @@ import gfx def rip_sprites_from_bank(bank, offset=0): + """ + Rips sprites from specified bank. + + Sprites are 4x4. + """ file_handler = open("../gfx/overworld/bank" + str(hex(bank))[2:] + ".asm", "w") for sprite in range(0 + offset, 256 + offset): filename = "../gfx/overworld/" + str(sprite).zfill(3) + ".2bpp" @@ -10,4 +15,4 @@ def rip_sprites_from_bank(bank, offset=0): file_handler.close() rip_sprites_from_bank(0x30) -rip_sprites_from_bank(0x31, offset=256) \ No newline at end of file +rip_sprites_from_bank(0x31, offset=256) diff --git a/extras/romstr.py b/extras/romstr.py index 90c099f3d..7a14fdc37 100644 --- a/extras/romstr.py +++ b/extras/romstr.py @@ -50,7 +50,7 @@ class RomStr(str): @classmethod def load(cls, filename=None, crystal=True, red=False): """ - Loads a ROM into a RomStr. + Load a ROM into a RomStr. """ if crystal and not red and not filename: file_handler = open("../baserom.gbc", "r") @@ -66,8 +66,10 @@ class RomStr(str): def load_labels(self, filename="labels.json"): """ - Loads labels from labels.json, or parses the source code file and - generates new labels. + Loads labels from labels.json. + + (Or parses the source code file and + generates new labels.) """ filename = os.path.join(os.path.dirname(__file__), filename) @@ -114,8 +116,9 @@ class RomStr(str): def get_address_for(self, label): """ - Returns the address of a label. This is slow and could be improved - dramatically. + Return the address of a label. + + This is slow and could be improved dramatically. """ label = str(label) for address in self.labels.keys(): @@ -137,7 +140,7 @@ class RomStr(str): def interval(self, offset, length, strings=True, debug=True): """ - returns hex values for the rom starting at offset until offset+length + Return hex values for the rom starting at offset until offset+length. """ returnable = [] for byte in self[offset:offset+length]: @@ -149,16 +152,17 @@ class RomStr(str): def until(self, offset, byte, strings=True, debug=False): """ - Returns hex values from rom starting at offset until the given byte. + Return hex values from rom starting at offset until the given byte. """ return self.interval(offset, self.find(chr(byte), offset) - offset, strings=strings) def to_asm(self, address, end_address=None, size=None, max_size=0x4000, debug=None): """ - Disassembles ASM at some address. This will stop disassembling when - either the end_address or size is met. Also, there's a maximum size - that will be parsed, so that large patches of data aren't parsed as - code. + Disassemble ASM at some address. + + This will stop disassembling when either the end_address or size is + met. Also, there's a maximum size that will be parsed, so that large + patches of data aren't parsed as code. """ if type(address) in [str, unicode] and "0x" in address: address = int(address, 16) diff --git a/extras/vba_autoplayer.py b/extras/vba_autoplayer.py index eafbff134..349fc2033 100644 --- a/extras/vba_autoplayer.py +++ b/extras/vba_autoplayer.py @@ -26,8 +26,10 @@ def main(): def skippable(func): """ - Makes a function skippable by saving the state before and after the - function runs. Pass "skip=True" to the function to load the previous save + Makes a function skippable. + + Saves the state before and after the function runs. + Pass "skip=True" to the function to load the previous save state from when the function finished. """ def wrapped_function(*args, **kwargs): @@ -433,6 +435,8 @@ def handle_elm(starter_choice): @skippable def new_bark_level_grind(level): """ + Do level grinding in New Bark. + Starting just outside of Elm's Lab, do some level grinding until the first partymon level is equal to the given value.. """