Edit some docstrings in /extras.

This commit is contained in:
Kat Harrison
2013-06-23 12:43:16 -04:00
parent 897d8b744c
commit 1120eaaaf5
6 changed files with 135 additions and 66 deletions

View File

@@ -1,6 +1,6 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
""" """
Finds shared functions between red/crystal. Find shared functions between red/crystal.
""" """
from crystal import ( from crystal import (
@@ -18,13 +18,13 @@ from romstr import (
def load_rom(path): 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) return direct_load_rom(filename=path)
def load_asm(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) return direct_load_asm(filename=path)
@@ -63,7 +63,8 @@ found_blobs = []
class BinaryBlob(object): 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 These details can be used to determine whether or not the function was
copied into Pokémon Crystal. copied into Pokémon Crystal.
""" """
@@ -128,7 +129,7 @@ class BinaryBlob(object):
def parse_from_red(self): 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] self.bytes = redrom[self.start_address : self.end_address + 1]
@@ -146,7 +147,7 @@ class BinaryBlob(object):
def find_in_crystal(self): 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) finditer = findall_iter(self.bytes, cryrom)
@@ -160,7 +161,7 @@ class BinaryBlob(object):
def find_by_first_bytes(self): 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 # how many bytes to match
@@ -194,7 +195,7 @@ redsrc = load_asm(pokered_src_path)
def scan_red_asm(bank_stop=3, debug=True): 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. Uses get_label_from_line and get_address_from_line_comment.
""" """

View File

@@ -13,6 +13,11 @@ if not hasattr(json, "read"):
json.read = json.loads json.read = json.loads
def load_rom(filename="../baserom.gbc"): def load_rom(filename="../baserom.gbc"):
"""
Load the specified rom.
If no rom is given, load "../baserom.gbc".
"""
global rom global rom
rom = bytearray(open(filename,'rb').read()) rom = bytearray(open(filename,'rb').read())
return rom return rom
@@ -557,6 +562,11 @@ call_commands = [0xdc, 0xd4, 0xc4, 0xcc, 0xcd]
all_labels = {} all_labels = {}
def load_labels(filename="labels.json"): def load_labels(filename="labels.json"):
"""
Load labels from specified file.
If no filename is given, loads 'labels.json'.
"""
global all_labels global all_labels
# don't re-load labels each time # don't re-load labels each time
@@ -588,21 +598,28 @@ def find_label(local_address, bank_id=0):
return None return None
def asm_label(address): 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:] return ".ASM_" + hex(address)[2:]
def output_bank_opcodes(original_offset, max_byte_count=0x4000, include_last_address=True, stop_at=[], debug = False): def output_bank_opcodes(original_offset, max_byte_count=0x4000, include_last_address=True, stop_at=[], debug=False):
#fs = current_address """
#b = bank_byte Output bank opcodes.
#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 fs = current_address
# over. This is useful if you know in advance that there are a lot of b = bank_byte
# fall-throughs. 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_labels()
load_rom() 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): def has_outstanding_labels(byte_labels):
""" """
If a label is used once in the asm output, then that means it has to be Check whether a label is used once in the asm output.
called or specified later.
If so, then that means it has to be called or specified later.
""" """
for label_line in byte_labels.keys(): for label_line in byte_labels.keys():
real_line = byte_labels[label_line] real_line = byte_labels[label_line]

View File

@@ -16,6 +16,9 @@ if __name__ != "__main__":
def mkdir_p(path): def mkdir_p(path):
"""
Make a directory at a given path.
"""
try: try:
os.makedirs(path) os.makedirs(path)
except OSError as exc: # Python >2.5 except OSError as exc: # Python >2.5
@@ -25,7 +28,9 @@ def mkdir_p(path):
def hex_dump(input, debug = True): def hex_dump(input, debug = True):
"""display hex dump in rows of 16 bytes""" """
Display hex dump in rows of 16 bytes.
"""
dump = '' dump = ''
output = '' output = ''
@@ -71,7 +76,9 @@ def hex_dump(input, debug = True):
def get_tiles(image): def get_tiles(image):
"""split a 2bpp image into 8x8 tiles""" """
Split a 2bpp image into 8x8 tiles.
"""
tiles = [] tiles = []
tile = [] tile = []
bytes_per_tile = 16 bytes_per_tile = 16
@@ -91,7 +98,9 @@ def get_tiles(image):
def connect(tiles): def connect(tiles):
"""combine 8x8 tiles into a 2bpp image""" """
Combine 8x8 tiles into a 2bpp image.
"""
out = [] out = []
for tile in tiles: for tile in tiles:
for byte in tile: for byte in tile:
@@ -100,7 +109,9 @@ def connect(tiles):
def transpose(tiles): def transpose(tiles):
"""transpose a tile arrangement along line y=x""" """
Transpose a tile arrangement along line y=x.
"""
# horizontal <-> vertical # horizontal <-> vertical
# 00 01 02 03 04 05 00 06 0c 12 18 1e # 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: class Compressed:
"""compress 2bpp data"""
"""
Compress 2bpp data.
"""
def __init__(self, image = None, mode = 'horiz', size = None): def __init__(self, image = None, mode = 'horiz', size = None):
@@ -231,7 +245,9 @@ class Compressed:
def compress(self): def compress(self):
"""incomplete, but outputs working compressed data""" """
Incomplete, but outputs working compressed data.
"""
self.address = 0 self.address = 0
@@ -308,10 +324,11 @@ class Compressed:
def scanRepeats(self): 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 This takes up most of the compress time and only saves a few bytes
it might be more feasible to exclude it entirely""" it might be more feasible to exclude it entirely."""
self.repeats = [] self.repeats = []
self.flips = [] self.flips = []
@@ -478,7 +495,7 @@ class Compressed:
while (ord(self.image[(self.address)+1]) == self.alts[num_alts&1]) & (num_alts <= max_length): while (ord(self.image[(self.address)+1]) == self.alts[num_alts&1]) & (num_alts <= max_length):
num_alts += 1 num_alts += 1
self.next() self.next()
# include the last alternated byte # include the last alternated byte
num_alts += 1 num_alts += 1
self.address = original_address self.address = original_address
if num_alts > lowmax: if num_alts > lowmax:
@@ -567,7 +584,8 @@ class Compressed:
class Decompressed: class Decompressed:
"""parse compressed 2bpp data """
Parse compressed 2bpp data.
parameters: parameters:
[compressed 2bpp data] [compressed 2bpp data]
@@ -576,7 +594,8 @@ class Decompressed:
[start] (optional) [start] (optional)
splits output into pic [size] and animation tiles if applicable 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): def __init__(self, lz = None, mode = None, size = None, start = 0):
# todo: play nice with Compressed # todo: play nice with Compressed
@@ -615,7 +634,9 @@ class Decompressed:
def decompress(self): def decompress(self):
"""replica of crystal's decompression""" """
Replica of crystal's decompression.
"""
self.output = [] self.output = []
@@ -674,19 +695,25 @@ class Decompressed:
self.getCurByte() self.getCurByte()
def doLiteral(self): def doLiteral(self):
# copy 2bpp data directly """
Copy 2bpp data directly.
"""
for byte in range(self.length): for byte in range(self.length):
self.next() self.next()
self.output.append(self.byte) self.output.append(self.byte)
def doIter(self): def doIter(self):
# write one byte repeatedly """
Write one byte repeatedly.
"""
self.next() self.next()
for byte in range(self.length): for byte in range(self.length):
self.output.append(self.byte) self.output.append(self.byte)
def doAlt(self): def doAlt(self):
# write alternating bytes """
Write alternating bytes.
"""
self.alts = [] self.alts = []
self.next() self.next()
self.alts.append(self.byte) self.alts.append(self.byte)
@@ -697,25 +724,27 @@ class Decompressed:
self.output.append(self.alts[byte&1]) self.output.append(self.alts[byte&1])
def doZeros(self): def doZeros(self):
# write zeros """Write zeros."""
for byte in range(self.length): for byte in range(self.length):
self.output.append(0x00) self.output.append(0x00)
def doFlip(self): def doFlip(self):
# repeat flipped bytes from 2bpp output """Repeat flipped bytes from 2bpp output.
# eg 11100100 -> 00100111
# quat 3 2 1 0 -> 0 2 1 3 eg 11100100 -> 00100111
quat 3 2 1 0 -> 0 2 1 3
"""
for byte in range(self.length): for byte in range(self.length):
flipped = sum(1<<(7-i) for i in range(8) if self.output[self.displacement+byte]>>i&1) flipped = sum(1<<(7-i) for i in range(8) if self.output[self.displacement+byte]>>i&1)
self.output.append(flipped) self.output.append(flipped)
def doReverse(self): def doReverse(self):
# repeat reversed bytes from 2bpp output """Repeat reversed bytes from 2bpp output."""
for byte in range(self.length): for byte in range(self.length):
self.output.append(self.output[self.displacement-byte]) self.output.append(self.output[self.displacement-byte])
def doRepeat(self): def doRepeat(self):
# repeat bytes from 2bpp output """Repeat bytes from 2bpp output."""
for byte in range(self.length): for byte in range(self.length):
self.output.append(self.output[self.displacement+byte]) self.output.append(self.output[self.displacement+byte])
@@ -741,7 +770,9 @@ sizes = [
] ]
def make_sizes(): def make_sizes():
"""front pics have specified sizes""" """
Front pics have specified sizes.
"""
top = 251 top = 251
base_stats = 0x51424 base_stats = 0x51424
# print monster sizes # print monster sizes
@@ -955,7 +986,9 @@ def decompress_misc():
to_file(filename, gfx.output) to_file(filename, gfx.output)
def decompress_all(debug = False): def decompress_all(debug = False):
"""decompress all known compressed data in baserom""" """
Decompress all known compressed data in baserom.
"""
if debug: print 'fronts' if debug: print 'fronts'
decompress_monsters(front) decompress_monsters(front)
@@ -988,7 +1021,9 @@ def decompress_all(debug = False):
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""" """
Write decompressed data from an address to a 2bpp file.
"""
image = Decompressed(rom, mode, size, address) image = Decompressed(rom, mode, size, address)
to_file(filename, image.pic) to_file(filename, image.pic)
@@ -1034,7 +1069,9 @@ def compress_monster_frontpic(id, fileout):
def get_uncompressed_gfx(start, num_tiles, filename): 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 bytes_per_tile = 0x10
length = num_tiles*bytes_per_tile length = num_tiles*bytes_per_tile
end = start + length end = start + length
@@ -1139,7 +1176,7 @@ def dump_trainer_pals():
def flatten(planar): def flatten(planar):
""" """
Flattens planar 2bpp image data into a quaternary pixel map. Flatten planar 2bpp image data into a quaternary pixel map.
""" """
strips = [] strips = []
for pair in range(len(planar)/2): for pair in range(len(planar)/2):
@@ -1155,7 +1192,7 @@ def flatten(planar):
def to_lines(image, width): 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 tile = 8 * 8
@@ -1208,8 +1245,8 @@ def png_pal(filename):
def to_png(filein, fileout=None, pal_file=None, height=None, width=None): 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' if fileout == None: fileout = '.'.join(filein.split('.')[:-1]) + '.png'

View File

@@ -1,6 +1,11 @@
import gfx import gfx
def rip_sprites_from_bank(bank, offset=0): 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") file_handler = open("../gfx/overworld/bank" + str(hex(bank))[2:] + ".asm", "w")
for sprite in range(0 + offset, 256 + offset): for sprite in range(0 + offset, 256 + offset):
filename = "../gfx/overworld/" + str(sprite).zfill(3) + ".2bpp" filename = "../gfx/overworld/" + str(sprite).zfill(3) + ".2bpp"

View File

@@ -50,7 +50,7 @@ class RomStr(str):
@classmethod @classmethod
def load(cls, filename=None, crystal=True, red=False): 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: if crystal and not red and not filename:
file_handler = open("../baserom.gbc", "r") file_handler = open("../baserom.gbc", "r")
@@ -66,8 +66,10 @@ class RomStr(str):
def load_labels(self, filename="labels.json"): def load_labels(self, filename="labels.json"):
""" """
Loads labels from labels.json, or parses the source code file and Loads labels from labels.json.
generates new labels.
(Or parses the source code file and
generates new labels.)
""" """
filename = os.path.join(os.path.dirname(__file__), filename) filename = os.path.join(os.path.dirname(__file__), filename)
@@ -114,8 +116,9 @@ class RomStr(str):
def get_address_for(self, label): def get_address_for(self, label):
""" """
Returns the address of a label. This is slow and could be improved Return the address of a label.
dramatically.
This is slow and could be improved dramatically.
""" """
label = str(label) label = str(label)
for address in self.labels.keys(): for address in self.labels.keys():
@@ -137,7 +140,7 @@ class RomStr(str):
def interval(self, offset, length, strings=True, debug=True): 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 = [] returnable = []
for byte in self[offset:offset+length]: for byte in self[offset:offset+length]:
@@ -149,16 +152,17 @@ class RomStr(str):
def until(self, offset, byte, strings=True, debug=False): 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) 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): 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 Disassemble ASM at some address.
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 This will stop disassembling when either the end_address or size is
code. 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: if type(address) in [str, unicode] and "0x" in address:
address = int(address, 16) address = int(address, 16)

View File

@@ -26,8 +26,10 @@ def main():
def skippable(func): def skippable(func):
""" """
Makes a function skippable by saving the state before and after the Makes a function skippable.
function runs. Pass "skip=True" to the function to load the previous save
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. state from when the function finished.
""" """
def wrapped_function(*args, **kwargs): def wrapped_function(*args, **kwargs):
@@ -433,6 +435,8 @@ def handle_elm(starter_choice):
@skippable @skippable
def new_bark_level_grind(level): 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 Starting just outside of Elm's Lab, do some level grinding until the first
partymon level is equal to the given value.. partymon level is equal to the given value..
""" """