From ae3857d64fbd3e9eb21e51420389829af0833175 Mon Sep 17 00:00:00 2001 From: C Nelson Date: Tue, 17 Apr 2012 20:16:42 -0500 Subject: [PATCH] Revert "Fix whitespace." Discovered an overwritten incoming change. This reverts commit 9ddcf90fccbab1f7be75c8675d875472ef016945. --- extras/crystal.py | 604 +++++++++++----------------------------------- 1 file changed, 141 insertions(+), 463 deletions(-) diff --git a/extras/crystal.py b/extras/crystal.py index 37b9b1da0..d483b960e 100644 --- a/extras/crystal.py +++ b/extras/crystal.py @@ -61,16 +61,16 @@ chars = { 0x50: "@", 0x54: "#", 0x75: "…", - + 0x79: "┌", 0x7A: "─", 0x7B: "┐", 0x7C: "│", 0x7D: "└", 0x7E: "┘", - + 0x74: "№", - + 0x7F: " ", 0x80: "A", 0x81: "B", @@ -333,15 +333,12 @@ class Size(): includes the first value or not, like for whether or not the size of a command in a script also includes the command byte or not""" - def __init__(self, size, inclusive=False): self.inclusive = inclusive if inclusive: size = size-1 self.size = size - def inclusive(self): return self.size + 1 - def exclusive(self): return self.size @@ -355,32 +352,30 @@ class IntervalMap(object): >>> print i[4] "hello world" """ - def __init__(self): """initializes an empty IntervalMap""" self._bounds = [] self._items = [] self._upperitem = None - def __setitem__(self, _slice, _value): """sets an interval mapping""" assert isinstance(_slice, slice), 'The key must be a slice object' - + if _slice.start is None: start_point = -1 else: start_point = bisect_left(self._bounds, _slice.start) - + if _slice.stop is None: end_point = -1 else: end_point = bisect_left(self._bounds, _slice.stop) - + if start_point>=0: if start_point < len(self._bounds) and self._bounds[start_point]<_slice.start: - start_point += 1 + start_point += 1 - if end_point>=0: + if end_point>=0: self._bounds[start_point:end_point] = [_slice.start, _slice.stop] if start_point < len(self._items): self._items[start_point:end_point] = [self._items[start_point], _value] @@ -401,17 +396,15 @@ class IntervalMap(object): self._bounds[:] = [] self._items[:] = [] self._upperitem = _value - def __getitem__(self,_point): """gets a value from the mapping""" - assert not isinstance(_point, slice), 'The key cannot be a slice object' - + assert not isinstance(_point, slice), 'The key cannot be a slice object' + index = bisect_right(self._bounds, _point) if index < len(self._bounds): return self._items[index] else: return self._upperitem - def items(self): """returns an iterator with each item being ((low_bound, high_bound), value) @@ -423,7 +416,6 @@ class IntervalMap(object): previous_bound = b if self._upperitem is not None: yield (previous_bound, None), self._upperitem - def values(self): """returns an iterator with each item being a stored value the items are returned in order""" @@ -432,7 +424,6 @@ class IntervalMap(object): yield v if self._upperitem is not None: yield self._upperitem - def __repr__(self): s = [] for b,v in self.items(): @@ -444,7 +435,6 @@ class IntervalMap(object): )) return '{'+', '.join(s)+'}' - # ---- script_parse_table explanation ---- # This is an IntervalMap that keeps track of previously parsed scripts, texts # and other objects. Anything that has a location in the ROM should be mapped @@ -463,7 +453,6 @@ def is_script_already_parsed_at(address): """looks up whether or not a script is parsed at a certain address""" if script_parse_table[address] == None: return False return True - def script_parse_table_pretty_printer(): """helpful debugging output""" for each in script_parse_table.items(): @@ -483,14 +472,11 @@ def map_name_cleaner(input): class RomStr(str): """simple wrapper to prevent a giant rom from being shown on screen""" - def length(self): """len(self)""" return len(self) - def __repr__(self): return "RomStr(too long)" - def interval(self, offset, length, strings=True, debug=True): """returns hex values for the rom starting at offset until offset+length""" returnable = [] @@ -500,14 +486,10 @@ class RomStr(str): else: returnable.append(ord(byte)) return returnable - def until(self, offset, byte, strings=True, debug=False): """returns hex values from rom starting at offset until the given byte""" return self.interval(offset, self.find(chr(byte), offset) - offset, strings=strings) - - rom = RomStr(None) - def direct_load_rom(filename="../baserom.gbc"): """loads bytes into memory""" global rom @@ -515,7 +497,6 @@ def direct_load_rom(filename="../baserom.gbc"): rom = RomStr(file_handler.read()) file_handler.close() return rom - def load_rom(filename="../baserom.gbc"): """checks that the loaded rom matches the path and then loads the rom if necessary.""" @@ -529,15 +510,11 @@ def load_rom(filename="../baserom.gbc"): class AsmList(list): """simple wrapper to prevent all asm lines from being shown on screen""" - def length(self): """len(self)""" return len(self) - def __repr__(self): return "AsmList(too long)" - - def load_asm(filename="../main.asm"): """loads the asm source code into memory""" global asm @@ -593,7 +570,6 @@ def calculate_bank(address): if 0x4000 <= address <= 0x7FFF: raise Exception, "bank 1 does not exist" return int(address) / 0x4000 - def calculate_pointer(short_pointer, bank=None): """calculates the full address given a 4-byte pointer and bank byte""" short_pointer = int(short_pointer) @@ -604,7 +580,6 @@ def calculate_pointer(short_pointer, bank=None): bank = 0 pointer = short_pointer + (bank * 0x4000) return pointer - def calculate_pointer_from_bytes_at(address, bank=False): """calculates a pointer from 2 bytes at a location or 3-byte pointer [bank][2-byte pointer] if bank=True""" @@ -655,21 +630,18 @@ def command_debug_information(command_byte=None, map_group=None, map_id=None, ad #info1 += " long_info: " + long_info return info1 - class TextScript(): "a text is a sequence of commands different from a script-engine script" - def __init__(self, address, map_group=None, map_id=None, debug=True, show=True, force=False): self.address = address self.map_group, self.map_id, self.debug, self.show, self.force = map_group, map_id, debug, show, force self.label = "UnknownTextLabel_"+hex(address) self.parse_text_at(address) - @staticmethod def find_addresses(): """returns a list of text pointers useful for testing parse_text_engine_script_at - + Note that this list is not exhaustive. There are some texts that are only pointed to from some script that a current script just points to. So find_all_text_pointers_in_script_engine_script will @@ -754,13 +726,12 @@ class TextScript(): texts2 = find_all_text_pointers_in_script_engine_script(script2, trainer_bank) addresses.update(texts2) return addresses - def parse_text_at(self, address): """parses a text-engine script ("in-text scripts") http://hax.iimarck.us/files/scriptingcodes_eng.htm#InText - + This is presently very broken. - + see parse_text_at2, parse_text_at, and process_00_subcommands """ global rom, text_count, max_texts, texts, script_parse_table @@ -774,7 +745,7 @@ class TextScript(): if is_script_already_parsed_at(address) and not force: print "text is already parsed at this location: " + hex(address) return script_parse_table[address] - + total_text_commands = 0 command_counter = 0 original_address = address @@ -793,56 +764,56 @@ class TextScript(): jump57 = how_many_until(chr(0x57), offset) jump50 = how_many_until(chr(0x50), offset) jump58 = how_many_until(chr(0x58), offset) - + #whichever command comes first jump = min([jump57, jump50, jump58]) - + end_address = offset + jump - 1 #we want the address before $57 - + lines = process_00_subcommands(offset+1, end_address, debug=debug) - + if show and debug: text = parse_text_at2(offset+1, end_address-offset+1, debug=debug) print text - + command = {"type": command_byte, "start_address": offset, "end_address": end_address, "size": jump, "lines": lines, - } - + } + offset += jump elif command_byte == 0x17: #TX_FAR [pointer][bank] pointer_byte1 = ord(rom[offset+1]) pointer_byte2 = ord(rom[offset+2]) pointer_bank = ord(rom[offset+3]) - + pointer = (pointer_byte1 + (pointer_byte2 << 8)) pointer = extract_maps.calculate_pointer(pointer, pointer_bank) - + command = {"type": command_byte, "start_address": offset, "end_address": offset + 3, #last byte belonging to this command "pointer": pointer, #parameter } - + offset += 3 + 1 elif command_byte == 0x50 or command_byte == 0x57 or command_byte == 0x58: #end text command = {"type": command_byte, "start_address": offset, "end_address": offset, } - + #this byte simply indicates to end the script end = True - + #this byte simply indicates to end the script if command_byte == 0x50 and ord(rom[offset+1]) == 0x50: #$50$50 means end completely end = True commands[command_counter+1] = command - + #also save the next byte, before we quit commands[command_counter+1]["start_address"] += 1 commands[command_counter+1]["end_address"] += 1 @@ -858,21 +829,21 @@ class TextScript(): size = 3 #total size, including the command byte pointer_byte1 = ord(rom[offset+1]) pointer_byte2 = ord(rom[offset+2]) - + command = {"type": command_byte, "start_address": offset+1, "end_address": offset+2, #last byte belonging to this command "pointer": [pointer_byte1, pointer_byte2], #RAM pointer } - + #view near these bytes #subsection = rom[offset:offset+size+1] #peak ahead #for x in subsection: # print hex(ord(x)) #print "--" - + offset += 2 + 1 #go to the next byte - + #use this to look at the surrounding bytes if debug: print "next command is: " + hex(ord(rom[offset])) + " ... we are at command number: " + str(command_counter) + " near " + hex(offset) + " on map_id=" + str(map_id) @@ -907,17 +878,17 @@ class TextScript(): jump57 = how_many_until(chr(0x57), offset) jump50 = how_many_until(chr(0x50), offset) jump58 = how_many_until(chr(0x58), offset) - + #whichever command comes first jump = min([jump57, jump50, jump58]) - + end_address = offset + jump - 1 #we want the address before $57 lines = process_00_subcommands(offset+1, end_address, debug=debug) - + if show and debug: text = parse_text_at2(offset+1, end_address-offset+1, debug=debug) print text - + command = {"type": command_byte, "start_address": offset, "end_address": end_address, @@ -946,34 +917,33 @@ class TextScript(): ram_address_byte1 = ord(rom[offset+1]) ram_address_byte2 = ord(rom[offset+2]) read_byte = ord(rom[offset+3]) - + command = { "type": command_byte, "address": [ram_address_byte1, ram_address_byte2], "read_byte": read_byte, #split this up when we make a macro for this } - + offset += 4 else: #if len(commands) > 0: # print "Unknown text command " + hex(command_byte) + " at " + hex(offset) + ", script began with " + hex(commands[0]["type"]) if debug: print "Unknown text command at " + hex(offset) + " - command: " + hex(ord(rom[offset])) + " on map_id=" + str(map_id) - + #end at the first unknown command end = True commands[command_counter] = command command_counter += 1 total_text_commands += len(commands) - + text_count += 1 #if text_count >= max_texts: # sys.exit() - + self.commands = commands script_parse_table[original_address:offset-1] = self return commands - def to_asm(self, label=None): address = self.address start_address = address @@ -982,7 +952,7 @@ class TextScript(): #apparently this isn't important anymore? needs_to_begin_with_0 = True #start with zero please - byte_count = 0 + byte_count = 0 #where we store all output output = "" had_text_end_byte = False @@ -997,7 +967,7 @@ class TextScript(): if not "type" in command.keys(): print "ERROR in command: " + str(command) continue #dunno what to do here? - + if command["type"] == 0x1: #TX_RAM if first_line: output = "\n" @@ -1005,7 +975,7 @@ class TextScript(): first_line = False p1 = command["pointer"][0] p2 = command["pointer"][1] - + #remember to account for big endian -> little endian output += "\n" + spacing + "TX_RAM $%.2x%.2x" %(p2, p1) byte_count += 3 @@ -1086,27 +1056,27 @@ class TextScript(): else: print "ERROR in command: " + hex(command["type"]) had_db_last = False - + #everything else is for $0s, really continue lines = commands[this_command]["lines"] - + #reset this in case we have non-$0s later had_db_last = False - + #add the ending byte to the last line- always seems $57 #this should already be in there, but it's not because of a bug in the text parser lines[len(lines.keys())-1].append(commands[len(commands.keys())-1]["type"]) - + #XXX to_asm should probably not include label output - #so this will need to be removed eventually + #so this will need to be removed eventually if first_line: output = "\n" output += label + ": ; " + hex(start_address) + "\n" first_line = False else: output += "\n" - + first = True #first byte for line_id in lines: line = lines[line_id] @@ -1115,7 +1085,7 @@ class TextScript(): output += "$0, " first = False byte_count += 1 - + quotes_open = False first_byte = True was_byte = False @@ -1124,7 +1094,7 @@ class TextScript(): had_text_end_byte = True #don't repeat it if byte in [0x58, 0x57]: had_text_end_byte_57_58 = True - + if byte in chars: if not quotes_open and not first_byte: #start text output += ", \"" @@ -1145,26 +1115,26 @@ class TextScript(): if quotes_open: output += "\"" quotes_open = False - + #if you want the ending byte on the last line #if not (byte == 0x57 or byte == 0x50 or byte == 0x58): if not first_byte: output += ", " - + output += "$" + hex(byte)[2:] was_byte = True - + #add a comma unless it's the end of the line #if byte_count+1 != len(line): # output += ", " - + first_byte = False byte_count += 1 #close final quotes if quotes_open: output += "\"" quotes_open = False - + output += "\n" include_newline = "\n" if len(output)!=0 and output[-1] == "\n": @@ -1181,7 +1151,6 @@ def parse_text_engine_script_at(address, map_group=None, map_id=None, debug=True if is_script_already_parsed_at(address) and not force: return script_parse_table[address] return TextScript(address, map_group=map_group, map_id=map_id, debug=debug, show=show, force=force) - def find_text_addresses(): """returns a list of text pointers useful for testing parse_text_engine_script_at""" @@ -1190,9 +1159,7 @@ def find_text_addresses(): class EncodedText(): """a sequence of bytes that, when decoded, represent readable text based on the chars table from textpre.py and other places""" - def to_asm(self): raise NotImplementedError, bryan_message - @staticmethod def process_00_subcommands(start_address, end_address, debug=True): """split this text up into multiple lines @@ -1201,7 +1168,7 @@ class EncodedText(): print "process_00_subcommands(" + hex(start_address) + ", " + hex(end_address) + ")" lines = {} subsection = rom[start_address:end_address] - + line_count = 0 current_line = [] for pbyte in subsection: @@ -1211,12 +1178,11 @@ class EncodedText(): lines[line_count] = current_line current_line = [] line_count += 1 - + #don't forget the last line lines[line_count] = current_line line_count += 1 return lines - @staticmethod def from_bytes(bytes, debug=True, japanese=False): """assembles a string based on bytes looked up in the chars table""" @@ -1231,7 +1197,6 @@ class EncodedText(): elif debug: print "byte not known: " + hex(byte) return line - @staticmethod def parse_text_at(address, count=10, debug=True, japanese=False): """returns a string of text from an address @@ -1243,22 +1208,17 @@ class EncodedText(): output += "\n" texts.append([address, output]) return output - - def process_00_subcommands(start_address, end_address, debug=True): """split this text up into multiple lines based on subcommands ending each line""" return EncodedText.process_00_subcommands(start_address, end_address, debug=debug) - def parse_text_from_bytes(bytes, debug=True, japanese=False): """assembles a string based on bytes looked up in the chars table""" return EncodedText.from_bytes(bytes, debug=debug, japanese=japanese) - def parse_text_at(address, count=10, debug=True): """returns a list of bytes from an address see parse_text_at2 for pretty printing""" return parse_text_from_bytes(rom_interval(address, count, strings=False), debug=debug) - def parse_text_at2(address, count=10, debug=True, japanese=False): """returns a string of text from an address this does not handle text commands""" @@ -1278,12 +1238,10 @@ def get_map_constant_label(map_group=None, map_id=None): if each["map_group"] == map_group and each["map_id"] == map_id: return each["label"] return None - def get_map_constant_label_by_id(global_id): """returns a map constant label for a particular map id""" global map_internal_ids return map_internal_ids[global_id]["label"] - def get_id_for_map_constant_label(label): """returns some global id for a given map constant label PALLET_TOWN = 1, for instance.""" @@ -1291,7 +1249,6 @@ def get_id_for_map_constant_label(label): for (id, each) in map_internal_ids.items(): if each["label"] == label: return id return None - def generate_map_constant_labels(): """generates the global for this script mapping ids to map groups/ids/labels""" @@ -1311,7 +1268,6 @@ def generate_map_constant_labels(): "map_group": map_group} i += 1 return map_internal_ids - #see generate_map_constant_labels() later def generate_map_constants(): """generates content for constants.asm @@ -1586,7 +1542,6 @@ pokemon_constants = { 250: "HO_OH", 251: "CELEBI", } - def get_pokemon_constant_by_id(id): if id == 0: return None return pokemon_constants[id] @@ -1817,12 +1772,10 @@ item_constants = {1: 'MASTER_BALL', 247: 'HM_05', 248: 'HM_06', 249: 'HM_07'} - def find_item_label_by_id(id): if id in item_constants.keys(): - return item_constants[id] + return item_constants[id] else: return None - def generate_item_constants(): """make a list of items to put in constants.asm""" output = "" @@ -2177,18 +2130,16 @@ pksv_crystal_unknowns = [ 0xA6, 0xA7, 0xA8, 0xA9, 0xAA, 0xAB, 0xAC, 0xAD, 0xAE, 0xAF, 0xB0, 0xB1, 0xB2, 0xB3, 0xB4, 0xB5, 0xB6, 0xB7, 0xB8, 0xCC, 0xCD, - 0xD1, 0xD2, 0xD3, 0xD4, 0xD5, 0xD6, + 0xD1, 0xD2, 0xD3, 0xD4, 0xD5, 0xD6, 0xE4, 0xE5, 0xE6, 0xE7, 0xE8, 0xE9, 0xEA, 0xEB, 0xEC, 0xED, 0xEE, 0xEF, 0xF0, 0xF1, 0xF2, 0xF3, 0xF4, 0xF5, 0xF6, 0xF7, 0xF8, 0xFA, 0xFB, 0xFC, 0xFD, 0xFE, 0xFF, ] - class SingleByteParam(): """or SingleByte(CommandParam)""" size = 1 should_be_decimal = False - def __init__(self, *args, **kwargs): for (key, value) in kwargs.items(): setattr(self, key, value) @@ -2204,39 +2155,27 @@ class SingleByteParam(): raise Exception, "size is probably 1?" #parse bytes from ROM self.parse() - def parse(self): self.byte = ord(rom[self.address]) - def to_asm(self): if not self.should_be_decimal: return hex(self.byte).replace("0x", "$") else: return str(self.byte) - - class HexByte(SingleByteParam): - def to_asm(self): return hex(self.byte) - - + def to_asm(self): return "$%.2x" % (self.byte) class DollarSignByte(SingleByteParam): #def to_asm(self): return "$%.2x"%self.byte def to_asm(self): return hex(self.byte).replace("0x", "$") - - class ItemLabelByte(DollarSignByte): def to_asm(self): label = find_item_label_by_id(self.byte) if label: return label elif not label: return DollarSignByte.to_asm(self) - - class DecimalParam(SingleByteParam): should_be_decimal = True - class MultiByteParam(): """or MultiByte(CommandParam)""" size = 2 should_be_decimal = False - def __init__(self, *args, **kwargs): self.prefix = "$" #default.. feel free to set 0x in kwargs for (key, value) in kwargs.items(): @@ -2250,9 +2189,7 @@ class MultiByteParam(): if not hasattr(self, "size") or self.size == None: raise Exception, "don't know how many bytes to read (size)" self.parse() - def parse(self): self.bytes = rom_interval(self.address, self.size, strings=False) - #you won't actually use this to_asm because it's too generic #def to_asm(self): return ", ".join([(self.prefix+"%.2x")%x for x in self.bytes]) def to_asm(self): @@ -2261,8 +2198,6 @@ class MultiByteParam(): elif self.should_be_decimal: decimal = int("0x"+"".join([("%.2x")%x for x in reversed(self.bytes)]), 16) return str(decimal) - - class PointerLabelParam(MultiByteParam): #default size is 2 bytes default_size = 2 @@ -2270,7 +2205,6 @@ class PointerLabelParam(MultiByteParam): #default is to not parse out a bank bank = False force = False - def __init__(self, *args, **kwargs): #bank can be overriden if "bank" in kwargs.keys(): @@ -2283,7 +2217,6 @@ class PointerLabelParam(MultiByteParam): raise Exception, "param size is too large" #continue instantiation.. self.bank will be set down the road MultiByteParam.__init__(self, *args, **kwargs) - def to_asm(self): bank = self.bank #we pass bank= for whether or not to include a bank byte when reading @@ -2291,7 +2224,7 @@ class PointerLabelParam(MultiByteParam): caddress = calculate_pointer_from_bytes_at(self.address, bank=self.bank) label = get_label_for(caddress) pointer_part = label #use the label, if it is found - + #check that the label actually points to the right place result = script_parse_table[caddress] if result != None and hasattr(result, "label"): @@ -2301,7 +2234,7 @@ class PointerLabelParam(MultiByteParam): label = None elif result != None: label = None - + #setup output bytes if the label was not found if not label: #pointer_part = (", ".join([(self.prefix+"%.2x")%x for x in reversed(self.bytes[1:])])) @@ -2327,27 +2260,15 @@ class PointerLabelParam(MultiByteParam): #raise Exception, "this should never happen" return pointer_part #probably in the same bank ? raise Exception, "this should never happen" - - class PointerLabelBeforeBank(PointerLabelParam): bank = True #bank appears first, see calculate_pointer_from_bytes_at size = 3 - - class PointerLabelAfterBank(PointerLabelParam): bank = "reverse" #bank appears last, see calculate_pointer_from_bytes_at size = 3 - - class ScriptPointerLabelParam(PointerLabelParam): pass - - class ScriptPointerLabelBeforeBank(PointerLabelBeforeBank): pass - - class ScriptPointerLabelAfterBank(PointerLabelAfterBank): pass - - def _parse_script_pointer_bytes(self): PointerLabelParam.parse(self) print "_parse_script_pointer_bytes - calculating the pointer located at " + hex(self.address) @@ -2358,50 +2279,37 @@ def _parse_script_pointer_bytes(self): ScriptPointerLabelParam.parse = _parse_script_pointer_bytes ScriptPointerLabelBeforeBank.parse = _parse_script_pointer_bytes ScriptPointerLabelAfterBank.parse = _parse_script_pointer_bytes - class PointerLabelToScriptPointer(PointerLabelParam): def parse(self): PointerLabelParam.parse(self) address = calculate_pointer_from_bytes_at(self.address, bank=self.bank) address2 = calculate_pointer_from_bytes_at(address, bank="reverse") #maybe not "reverse"? self.script = parse_script_engine_script_at(address2, origin=False, map_group=self.map_group, map_id=self.map_id, force=self.force, debug=self.debug) - - class AsmPointerParam(PointerLabelBeforeBank): def parse(self): PointerLabelBeforeBank.parse(self) address = calculate_pointer_from_bytes_at(self.address, bank=self.bank) #3-byte pointer self.asm = parse_script_asm_at(address, map_group=self.map_group, map_id=self.map_id, force=self.force, debug=self.debug) #might end in some specific way? - - class PointerToAsmPointerParam(PointerLabelParam): def parse(self): PointerLabelParam.parse(self) address = calculate_pointer_from_bytes_at(self.address, bank=self.bank) #2-byte pointer address2 = calculate_pointer_from_bytes_at(address, bank="reverse") #maybe not "reverse"? self.asm = parse_script_asm_at(address, map_group=self.map_group, map_id=self.map_id, force=self.force, debug=self.debug) #might end in some specific way? - - class RAMAddressParam(MultiByteParam): def to_asm(self): address = calculate_pointer_from_bytes_at(self.address, bank=False) label = get_ram_label(address) if label: return "["+label+"]" else: return "[$"+"".join(["%.2x"%x for x in self.bytes])+"]" - - class MoneyByteParam(MultiByteParam): size = 3 max_value = 0x0F423F should_be_decimal = True - - class CoinByteParam(MultiByteParam): size = 2 max_value = 0x270F should_be_decimal = True - - class MapGroupParam(SingleByteParam): def to_asm(self): map_id = ord(rom[self.address+1]) @@ -2409,68 +2317,48 @@ class MapGroupParam(SingleByteParam): if map_constant_label == None: return str(self.byte) #else: return "GROUP("+map_constant_label+")" else: return "GROUP_"+map_constant_label - - class MapIdParam(SingleByteParam): def parse(self): SingleByteParam.parse(self) self.map_group = ord(rom[self.address-1]) - def to_asm(self): map_group = ord(rom[self.address-1]) map_constant_label = get_map_constant_label(map_id=self.byte, map_group=map_group) if map_constant_label == None: return str(self.byte) #else: return "MAP("+map_constant_label+")" else: return "MAP_"+map_constant_label - - class MapGroupIdParam(MultiByteParam): def parse(self): MultiByteParam.parse(self) self.map_group = self.bytes[0] self.map_id = self.bytes[1] - def to_asm(self): map_group = self.map_group map_id = self.map_id label = get_map_constant_label(map_group=map_group, map_id=map_id) return label - - class PokemonParam(SingleByteParam): def to_asm(self): pokemon_constant = get_pokemon_constant_by_id(self.byte) if pokemon_constant: return pokemon_constant else: return str(self.byte) - - class PointerParamToItemAndLetter(MultiByteParam): #[2F][2byte pointer to item no + 0x20 bytes letter text] #raise NotImplementedError, bryan_message pass - - class TrainerIdParam(SingleByteParam): #raise NotImplementedError, bryan_message pass - - class TrainerGroupParam(SingleByteParam): #raise NotImplementedError, bryan_message pass - - class MenuDataPointerParam(PointerLabelParam): #read menu data at the target site #raise NotImplementedError, bryan_message pass - - class RawTextPointerLabelParam(PointerLabelParam): #not sure if these are always to a text script or raw text? pass - - class TextPointerLabelParam(PointerLabelParam): """this is a pointer to a text script""" bank = False @@ -2479,16 +2367,11 @@ class TextPointerLabelParam(PointerLabelParam): address = calculate_pointer_from_bytes_at(self.address, bank=self.bank) if address != None and address != 0: self.text = parse_text_engine_script_at(address, map_group=self.map_group, map_id=self.map_id, force=self.force, debug=self.debug) - - class MovementPointerLabelParam(PointerLabelParam): pass - - class MapDataPointerParam(PointerLabelParam): pass - #byte: [name, [param1 name, param1 type], [param2 name, param2 type], ...] #0x9E: ["verbosegiveitem", ["item", ItemLabelByte], ["quantity", SingleByteParam]], pksv_crystal_more = { @@ -2610,7 +2493,7 @@ pksv_crystal_more = { 0x6D: ["variablesprite", ["byte", SingleByteParam], ["sprite", SingleByteParam]], 0x6E: ["disappear", ["person", SingleByteParam]], #hideperson 0x6F: ["appear", ["person", SingleByteParam]], #showperson - 0x70: ["follow", ["person2", SingleByteParam], ["person1", SingleByteParam]], + 0x70: ["follow", ["person2", SingleByteParam], ["person1", SingleByteParam]], 0x71: ["stopfollow"], 0x72: ["moveperson", ["person", SingleByteParam], ["x", SingleByteParam], ["y", SingleByteParam]], 0x73: ["writepersonxy", ["person", SingleByteParam]], #not pksv @@ -2669,7 +2552,6 @@ pksv_crystal_more = { 0xCC: ["unknown0xcc"], } - class Command: """ Note: when dumping to asm, anything in script_parse_table that directly @@ -2678,7 +2560,7 @@ class Command: #use this when the "byte id" doesn't matter #.. for example, a non-script command doesn't use the "byte id" override_byte_check = False - + def __init__(self, address=None, *pargs, **kwargs): """params: address - where the command starts @@ -2704,7 +2586,6 @@ class Command: self.args = defaults #start parsing this command's parameter bytes self.parse() - def to_asm(self): #start with the rgbasm macro name for this command output = self.macro_name @@ -2744,7 +2625,6 @@ class Command: # output += obj.to_asm() # current_address += obj.size return output - def parse(self): #id, size (inclusive), param_types #param_type = {"name": each[1], "class": each[0]} @@ -2769,8 +2649,6 @@ class Command: i += 1 self.last_address = current_address return True - - class GivePoke(Command): id = 0x2D macro_name = "givepoke" @@ -2810,7 +2688,6 @@ class GivePoke(Command): self.last_address = current_address return True - #these cause the script to end; used in create_command_classes pksv_crystal_more_enders = [0x03, 0x04, 0x05, 0x0C, 0x51, 0x53, 0x8D, 0x8F, 0x90, 0x91, 0x92, 0x9B, @@ -2862,7 +2739,6 @@ def rec_parse_script_engine_script_at(address, origin=None, debug=True): parser.""" recursive_scripts.add((address, origin)) return parse_script_engine_script_at(address, origin=origin, debug=debug) - def find_broken_recursive_scripts(output=False, debug=True): """well.. these at least have a chance of maybe being broken?""" for r in list(recursive_scripts): @@ -2878,7 +2754,6 @@ def find_broken_recursive_scripts(output=False, debug=True): parse_script_engine_script_at(r[0], force=True, debug=True) print "==================== end" - stop_points = [0x1aafa2, 0x9f58f, #battle tower 0x9f62f, #battle tower @@ -2905,7 +2780,6 @@ class Script(): self.old_parse(**kwargs) else: self.parse(self.address, **kwargs) - def pksv_list(self): """shows a list of pksv names for each command in the script""" items = [] @@ -2919,8 +2793,6 @@ class Script(): for command in self.commands: items.append(command.macro_name) return items - - def to_pksv(self): """returns a string of pksv command names""" pksv = self.pksv_list() @@ -2934,15 +2806,13 @@ class Script(): else: output += ", "+item return output - def show_pksv(self): """prints a list of pksv command names in this script""" print self.to_pksv() - def parse(self, start_address, force=False, map_group=None, map_id=None, force_top=True, origin=True, debug=False): """parses a script using the Command classes as an alternative to the old method using hard-coded commands - + force_top just means 'force the main script to get parsed, but not any subscripts' """ global command_classes, rom, script_parse_table @@ -2991,11 +2861,9 @@ class Script(): print "--------------\n"+asm_output self.commands = commands return commands - def to_asm(self): asm_output = "".join([command.to_asm()+"\n" for command in self.commands]) return asm_output - def old_parse(self, *args, **kwargs): """parses a script-engine script; force=True if you want to re-parse and get the debug information""" @@ -3024,18 +2892,18 @@ class Script(): origin = kwargs["origin"] self.map_group = map_group self.map_id = map_id - + global rom if rom == None: direct_load_rom() - + #max number of commands in a 'recursive' script max_cmds = 150 - + #set the address to be parsed address = self.address original_start_address = address - + #don't parse these crazy things (battle tower things, some rival things, etc.) if address in stop_points: print "got " + hex(address) + ".. map_group=" + str(map_group) + " map_id=" + str(map_id) @@ -3044,28 +2912,28 @@ class Script(): if address < 0x4000 and address not in [0x26ef, 0x114, 0x1108]: print "address is less than 0x4000.. address is: " + hex(address) sys.exit() - + #check if work is being repeated if is_script_already_parsed_at(address) and not force: raise Exception, "this script has already been parsed before, please use that instance" #use the commands from a previously-parsed Script object #self.commands = script_parse_table[address].commands #return True - + #return a previously-created Script object #return script_parse_table[address] - + #this next line stops the same script from being re-parsed multiple times #for instance.. maybe there's a script jump, then a jump back #the original script should only be parsed once script_parse_table[original_start_address:original_start_address+1] = "incomplete Script" - + #set up some variables self.commands = {} commands = self.commands offset = address end = False - + #main loop.. parse each command byte while not end: #reset variables so we don't contaminate this command @@ -3074,16 +2942,16 @@ class Script(): command_byte = ord(rom[offset]) #setup the current command representation command = {"type": command_byte, "start_address": offset} - + #size is the total size including the command byte #last_byte_address is offset+size-1 start_address = offset - + if (len(commands.keys()) > max_cmds) and origin != False: print "too many commands in this script? might not be a script (starting at: " +\ hex(original_start_address) + ").. called from a script at: " + hex(origin) sys.exit() - + #start checking against possible command bytes if command_byte == 0x00: #Pointer code [2b+ret] pksv_name = "2call" @@ -3179,7 +3047,7 @@ class Script(): size = 3 command["pointer"] = calculate_pointer_from_bytes_at(start_address+1) command["target_pointer"] = calculate_pointer_from_bytes_at(command["pointer"], bank=True) - + if debug: print "in script starting at "+hex(original_start_address)+\ " about to parse script at "+hex(command["target_pointer"])+\ @@ -3813,7 +3681,7 @@ class Script(): #in a command queue, because with every regular move of HIRO the bits #are reset again. This code is an alternative to the trigger events and #can be used via the command queue code. - #See Write command queue, Additional documentation: 3:4661 with c= index + #See Write command queue, Additional documentation: 3:4661 with c= index #in table (start=00), hl=D171, b=01, d=00. """ size = 3 @@ -4846,7 +4714,7 @@ class Script(): #raise NotImplementedError, "command byte is " + hex(command_byte) + " at " + hex(offset) + " on map " + str(map_group) + "." + str(map_id) print "dunno what this command is: " + hex(command_byte) long_info = clean_up_long_info(long_info) - + if command_byte in pksv_crystal.keys(): pksv_name = pksv_crystal[command_byte] else: @@ -4855,10 +4723,10 @@ class Script(): pksv_no_names[command_byte].append(address) else: pksv_no_names[command_byte] = [address] - + if debug: print command_debug_information(command_byte=command_byte, map_group=map_group, map_id=map_id, address=offset, info=info, long_info=long_info, pksv_name=pksv_name) - + #store the size of the command command["size"] = size #the end address is just offset + size - 1 (because size includes command byte) @@ -4869,12 +4737,10 @@ class Script(): offset += 1 #add the command into the command list please commands[len(commands.keys())] = command - + self.commands = commands script_parse_table[original_start_address : offset] = self return True - - def parse_script_engine_script_at(address, map_group=None, map_id=None, force=False, debug=True, origin=True): if is_script_already_parsed_at(address) and not force: return script_parse_table[address] @@ -4919,7 +4785,6 @@ def compare_script_parsing_methods(address): print "total comparison errors: " + str(errors) return oldscript, newscript - class Warp(Command): """only used outside of scripts""" size = warp_byte_size @@ -4932,7 +4797,6 @@ class Warp(Command): 4: {"name": "map_id", "class": MapIdParam}, } override_byte_check = True - def __init__(self, *args, **kwargs): self.id = kwargs["id"] script_parse_table[kwargs["address"] : kwargs["address"] + self.size] = self @@ -4981,7 +4845,6 @@ class XYTrigger(Command): 6: {"name": "unknown3", "class": SingleByteParam}, } override_byte_check = True - def __init__(self, *args, **kwargs): self.id = kwargs["id"] #XYTrigger shouldn't really be in the globals, should it.. @@ -5017,7 +4880,7 @@ def old_parse_xy_trigger_bytes(some_bytes, bank=None, map_group=None, map_id=Non script_address = calculate_pointer(script_ptr, bank) print "******* parsing xy trigger byte scripts... x=" + str(x) + " y=" + str(y) script = parse_script_engine_script_at(script_address, map_group=map_group, map_id=map_id) - + triggers.append({ "trigger_number": trigger_number, "y": y, @@ -5030,7 +4893,6 @@ def old_parse_xy_trigger_bytes(some_bytes, bank=None, map_group=None, map_id=Non }) return triggers - class ItemFragment(Command): """used by ItemFragmentParam and PeopleEvent (for items placed on a map)""" @@ -5042,7 +4904,6 @@ class ItemFragment(Command): 0: {"name": "item", "class": ItemLabelByte}, 1: {"name": "quantity", "class": DecimalParam}, } - def __init__(self, address=None, bank=None, map_group=None, map_id=None, debug=False, label=None): assert is_valid_address(address), "PeopleEvent must be given a valid address" self.address = address @@ -5057,18 +4918,13 @@ class ItemFragment(Command): self.args = {"debug": debug, "map_group": map_group, "map_id": map_id, "bank": bank} script_parse_table[self.address : self.last_address] = self self.parse() - - class ItemFragmentParam(PointerLabelParam): """used by PeopleEvent""" - def parse(self): PointerLabelParam.parse(self) address = calculate_pointer_from_bytes_at(self.address, bank=self.bank) itemfrag = ItemFragment(address=address, map_group=self.map_group, map_id=self.map_id, debug=self.debug) self.remotes = [itemfrag] - - class TrainerFragment(Command): """used by TrainerFragmentParam and PeopleEvent for trainer data [Bit no. (2byte)][Trainer group][Trainer] @@ -5076,10 +4932,10 @@ class TrainerFragment(Command): [2byte pointer to text when trainer beaten] [2byte pointer to script when lost (0000=Blackout)] [2byte pointer to script if won/talked to again] - + The bit number tell the game later on if the trainer has been beaten already (bit = 1) or not (bit = 0). All Bit number of BitTable1. - + 03 = Nothing 04 = Nothing 05 = Nothing @@ -5098,7 +4954,6 @@ class TrainerFragment(Command): 5: {"name": "script_when_lost", "class": ScriptPointerLabelParam}, 6: {"name": "script_talk_again", "class": ScriptPointerLabelParam}, } - def __init__(self, *args, **kwargs): address = kwargs["address"] print "TrainerFragment address=" + hex(address) @@ -5106,18 +4961,13 @@ class TrainerFragment(Command): Command.__init__(self, *args, **kwargs) self.last_address = self.address + self.size script_parse_table[self.address : self.last_address] = self - - class TrainerFragmentParam(PointerLabelParam): """used by PeopleEvent to point to trainer data""" - def parse(self): address = calculate_pointer_from_bytes_at(self.address, bank=self.bank) trainerfrag = TrainerFragment(address=address, map_group=self.map_group, map_id=self.map_id, debug=self.debug) self.remotes = [trainerfrag] PointerLabelParam.parse(self) - - class PeopleEvent(Command): size = people_event_byte_size macro_name = "person_event" @@ -5136,7 +4986,6 @@ class PeopleEvent(Command): 9: {"name": "pointer", "class": PointerLabelParam}, #or ScriptPointerLabelParam or ItemLabelParam 10: {"name": "BitTable1 bit number", "class": MultiByteParam}, } - def __init__(self, address, id, bank=None, map_group=None, map_id=None, debug=False, label=None, force=False): assert is_valid_address(address), "PeopleEvent must be given a valid address" self.address = address @@ -5153,7 +5002,6 @@ class PeopleEvent(Command): #PeopleEvent should probably not be in the global script_parse_table #script_parse_table[self.address : self.last_address] = self self.parse() - def parse(self): address = self.address bank = self.bank @@ -5216,7 +5064,6 @@ class PeopleEvent(Command): self.bit_number = self.params[10].bytes return True - all_people_events = [] def parse_people_events(address, people_event_count, bank=None, map_group=None, map_id=None, debug=False, force=False): #people_event_byte_size @@ -5236,7 +5083,7 @@ def old_parse_people_event_bytes(some_bytes, address=None, map_group=None, map_i see http://hax.iimarck.us/files/scriptingcodes_eng.htm#Scripthdr For example, map 1.1 (group 1 map 1) has four person-events. - + 37 05 07 06 00 FF FF 00 00 02 40 FF FF 3B 08 0C 05 01 FF FF 00 00 05 40 FF FF 3A 07 06 06 00 FF FF A0 00 08 40 FF FF @@ -5260,7 +5107,7 @@ def old_parse_people_event_bytes(some_bytes, address=None, map_group=None, map_i clock_time_byte2 = int(bytes[6], 16) color_function_byte = int(bytes[7], 16) #Color|Function trainer_sight_range = int(bytes[8], 16) - + lower_bits = color_function_byte & 0xF #lower_bits_high = lower_bits >> 2 #lower_bits_low = lower_bits & 3 @@ -5308,7 +5155,7 @@ def old_parse_people_event_bytes(some_bytes, address=None, map_group=None, map_i "trainer_data_address": ptr_address, "trainer_data": parsed_trainer, } - + #XXX not sure what's going on here #bit no. of bit table 1 (hidden if set) #note: FFFF for none @@ -5345,7 +5192,6 @@ def old_parse_people_event_bytes(some_bytes, address=None, map_group=None, map_i people_events.append(people_event) return people_events - class SignpostRemoteBase: def __init__(self, address, bank=None, map_group=None, map_id=None, signpost=None, debug=False, label=None): self.address = address @@ -5361,21 +5207,17 @@ class SignpostRemoteBase: self.label = self.base_label + hex(self.address) else: self.label = label self.parse() - def to_asm(self): """very similar to Command.to_asm""" if len(self.params) == 0: return "" output = ", ".join([p.to_asm() for p in self.params]) return output - - class SignpostRemoteScriptChunk(SignpostRemoteBase): """ a signpost might point to [Bit-Nr. (2byte)][2byte pointer to script] """ base_label = "SignpostRemoteScript_" size = 4 - def parse(self): address = self.address bank = self.bank @@ -5395,45 +5237,38 @@ class SignpostRemoteScriptChunk(SignpostRemoteBase): #self.bit_table_bytes = [bit_table_byte1, bit_table_byte2] #self.script_address = script_address #self.script = script - - class SignpostRemoteItemChunk(SignpostRemoteBase): """ a signpost might point to [Bit-Nr. (2byte)][Item no.] """ base_label = "SignpostRemoteItem_" size = 3 - def parse(self): address = self.address bank = self.bank - + bit_table = MultiByteParam(address=address, map_group=self.map_group, map_id=self.map_id, debug=self.debug) self.params.append(bit_table) - + item = ItemLabelByte(address=address+2) self.params.append(item) self.item = item - - class SignpostRemoteUnknownChunk(SignpostRemoteBase): """ a signpost might point to [Bit-Nr. (2byte)][??] """ base_label = "SignpostRemoteUnknown_" size = 3 - def parse(self): address = self.address bank = self.bank - + bit_table = MultiByteParam(address=address, bank=self.bank, map_group=self.map_group, map_id=self.map_id, debug=self.debug) self.params.append(bit_table) - + byte = SingleByteParam(address=address+2) self.params.append(byte) - #this could potentially extend Command #see how class Warp does this class Signpost: @@ -5463,7 +5298,6 @@ class Signpost: """ size = 5 macro_name = "signpost" - def __init__(self, address, id, bank=None, map_group=None, map_id=None, debug=True, label=None): self.address = address self.id = id @@ -5482,14 +5316,13 @@ class Signpost: self.remotes = [] self.params = [] self.parse() - def parse(self): """parse just one signpost""" address = self.address bank = self.bank self.last_address = self.address + self.size bytes = rom_interval(self.address, self.size) #, signpost_byte_size) - + self.y = int(bytes[0], 16) self.x = int(bytes[1], 16) self.func = int(bytes[2], 16) @@ -5511,14 +5344,14 @@ class Signpost: script_ptr_byte1 = int(bytes[3], 16) script_ptr_byte2 = int(bytes[4], 16) script_pointer = script_ptr_byte1 + (script_ptr_byte2 << 8) - + script_address = calculate_pointer(script_pointer, bank) output += " script@"+hex(script_address) print output param = ScriptPointerLabelParam(address=self.address+3, map_group=self.map_group, map_id=self.map_id, debug=self.debug, force=False) self.params.append(param) - + #self.script_address = script_address #self.script = script elif func in [5, 6]: @@ -5527,21 +5360,21 @@ class Signpost: ptr_byte2 = int(bytes[4], 16) pointer = ptr_byte1 + (ptr_byte2 << 8) address = calculate_pointer(pointer, bank) - + bit_table_byte1 = ord(rom[address]) bit_table_byte2 = ord(rom[address+1]) script_ptr_byte1 = ord(rom[address+2]) script_ptr_byte2 = ord(rom[address+3]) script_address = calculate_pointer_from_bytes_at(address+2, bank=bank) - + output += " remote_chunk@"+hex(address)+" remote_script@"+hex(script_address) print output - + r1 = SignpostRemoteScriptChunk(address, signpost=self, \ bank=self.bank, map_group=self.map_group, map_id=self.map_id, \ debug=self.debug) self.remotes.append(r1) - + mb = PointerLabelParam(address=address, map_group=self.map_group, map_id=self.map_id, debug=self.debug) self.params.append(mb) elif func == 7: @@ -5550,16 +5383,16 @@ class Signpost: ptr_byte2 = int(bytes[4], 16) pointer = ptr_byte1 + (ptr_byte2 << 8) address = calculate_pointer(pointer, bank) - + item_id = ord(rom[address+2]) output += " item_id="+str(item_id) print output - + r1 = SignpostRemoteItemChunk(address, signpost=self, \ bank=self.bank, map_group=self.map_group, map_id=self.map_id, \ debug=self.debug) self.remotes.append(r1) - + mb = PointerLabelParam(address=address, map_group=self.map_group, map_id=self.map_id, debug=self.debug) self.params.append(mb) @@ -5573,15 +5406,15 @@ class Signpost: ptr_byte2 = int(bytes[4], 16) pointer = ptr_byte1 + (ptr_byte2 << 8) address = calculate_pointer(pointer, bank) - + output += " remote unknown chunk at="+hex(address) print output - + r1 = SignpostRemoteUnknownChunk(address, signpost=self, \ bank=self.bank, map_group=self.map_group, map_id=self.map_id, \ debug=self.debug) self.remotes.append(r1) - + mb = PointerLabelParam(address=address, map_group=self.map_group, map_id=self.map_id, debug=self.debug) self.params.append(mb) else: @@ -5592,7 +5425,6 @@ class Signpost: output += ", ".join([p.to_asm() for p in self.params]) return output - all_signposts = [] def parse_signposts(address, signpost_count, bank=None, map_group=None, map_id=None, debug=True): if bank == None: raise Exception, "signposts need to know their bank" @@ -5621,10 +5453,10 @@ def old_parse_signpost_bytes(some_bytes, bank=None, map_group=None, map_id=None, script_ptr_byte1 = int(bytes[3], 16) script_ptr_byte2 = int(bytes[4], 16) script_pointer = script_ptr_byte1 + (script_ptr_byte2 << 8) - + script_address = None script = None - + script_address = calculate_pointer(script_pointer, bank) script = parse_script_engine_script_at(script_address, map_group=map_group, map_id=map_id) @@ -5646,7 +5478,7 @@ def old_parse_signpost_bytes(some_bytes, bank=None, map_group=None, map_id=None, script_ptr_byte2 = ord(rom[address+3]) script_address = calculate_pointer_from_bytes_at(address+2, bank=bank) script = parse_script_engine_script_at(script_address, map_group=map_group, map_id=map_id) - + additional = { "bit_table_bytes": {"1": bit_table_byte1, "2": bit_table_byte2}, "script_ptr": script_ptr_byte1 + (script_ptr_byte2 << 8), @@ -5656,7 +5488,7 @@ def old_parse_signpost_bytes(some_bytes, bank=None, map_group=None, map_id=None, } else: print ".. type 7 or 8 signpost not parsed yet." - + spost = { "y": y, "x": x, @@ -5666,10 +5498,8 @@ def old_parse_signpost_bytes(some_bytes, bank=None, map_group=None, map_id=None, signposts.append(spost) return signposts - class MapHeader: base_label = "MapHeader_" - def __init__(self, address, map_group=None, map_id=None, debug=True, label=None, bank=0x25): print "creating a MapHeader at "+hex(address)+" map_group="+str(map_group)+" map_id="+str(map_id) self.address = address @@ -5684,7 +5514,6 @@ class MapHeader: self.last_address = address + 8 script_parse_table[address : self.last_address] = self self.parse() - def parse(self): address = self.address print "parsing a MapHeader at " + hex(address) @@ -5699,7 +5528,6 @@ class MapHeader: self.music = HexByte(address=address+6) self.time_of_day = DecimalParam(address=address+7) self.fishing_group = DecimalParam(address=address+8) - def to_asm(self): output = "; bank, tileset, permission\n" output += "db " + ", ".join([self.bank.to_asm(), self.tileset.to_asm(), self.permission.to_asm()]) @@ -5709,7 +5537,6 @@ class MapHeader: output += "db " + ", ".join([self.location_on_world_map.to_asm(), self.music.to_asm(), self.time_of_day.to_asm(), self.fishing_group.to_asm()]) return output - all_map_headers = [] def parse_map_header_at(address, map_group=None, map_id=None, debug=True): """parses an arbitrary map header at some address""" @@ -5751,10 +5578,8 @@ def old_parse_map_header_at(address, map_group=None, map_id=None, debug=True): map_header["script_header"] = old_parse_map_script_header_at(script_header_address, map_group=map_group, map_id=map_id, debug=debug) return map_header - class SecondMapHeader: base_label = "SecondMapHeader_" - def __init__(self, address, map_group=None, map_id=None, debug=True, bank=None, label=None): print "creating a SecondMapHeader at " + hex(address) self.address = address @@ -5769,7 +5594,6 @@ class SecondMapHeader: #i think it's always a static size? script_parse_table[address : self.last_address] = self self.parse() - def parse(self): address = self.address bytes = rom_interval(address, second_map_header_byte_size, strings=False) @@ -5777,13 +5601,13 @@ class SecondMapHeader: self.border_block = HexByte(address=address) self.height = DecimalParam(address=address+1) self.width = DecimalParam(address=address+2) - + #TODO: process blockdata ? #bank appears first ###self.blockdata_address = PointerLabelBeforeBank(address+3) self.blockdata_address = calculate_pointer_from_bytes_at(address+3, bank=True) self.blockdata = MapBlockData(self.blockdata_address, map_group=self.map_group, map_id=self.map_id, debug=self.debug, width=self.width, height=self.height) - + #bank appears first #TODO: process MapScriptHeader ###self.script_address = PointerLabelBeforeBank(address+6) @@ -5824,9 +5648,8 @@ class SecondMapHeader: #self.event_pointer = event_pointer #self.event_address = event_address #self.connections = connections - + return True - def to_asm(self): output = "; border block\n" output += "db " + self.border_block.to_asm() + "\n\n" @@ -5842,7 +5665,6 @@ class SecondMapHeader: output += "db " + self.connections.to_asm() return output - all_second_map_headers = [] def parse_second_map_header_at(address, map_group=None, map_id=None, debug=True): """each map has a second map header""" @@ -5882,11 +5704,9 @@ def old_parse_second_map_header_at(address, map_group=None, map_id=None, debug=T "connections": connections, } - class MapBlockData: base_label = "MapBlockData_" maps_path = os.path.realpath(os.path.join(os.path.realpath("."), "../maps")) - def __init__(self, address, map_group=None, map_id=None, debug=True, bank=None, label=None, width=None, height=None): self.address = address self.map_group = map_group @@ -5907,7 +5727,6 @@ class MapBlockData: self.last_address = self.address + (self.width.byte * self.height.byte) script_parse_table[address : self.last_address] = self self.parse() - def save_to_file(self): #check if the file exists already map_path = self.map_path @@ -5918,17 +5737,13 @@ class MapBlockData: file_handler = open(map_path, "w") file_handler.write(bytes) file_handler.close() - def parse(self): self.save_to_file() - def to_asm(self): return "INCBIN \"maps/"+self.map_name+".blk\"" - class MapEventHeader: base_label = "MapEventHeader_" - def __init__(self, address, map_group=None, map_id=None, debug=True, bank=None, label=None): print "making a MapEventHeader at "+hex(address)+" map_group="+str(map_group)+" map_id="+str(map_id) self.address = address @@ -5942,17 +5757,16 @@ class MapEventHeader: self.label = self.base_label + hex(address) self.parse() script_parse_table[address : self.last_address] = self - def parse(self): map_group, map_id, debug = self.map_group, self.map_id, self.debug address = self.address bank = calculate_bank(self.address) #or use self.bank print "event header address is: " + hex(address) - + filler1 = ord(rom[address]) filler2 = ord(rom[address+1]) self.fillers = [filler1, filler2] - + #warps warp_count = ord(rom[address+2]) warp_byte_count = warp_byte_size * warp_count @@ -5968,7 +5782,7 @@ class MapEventHeader: after_triggers = after_warps + 1 + trigger_byte_count self.xy_trigger_count = xy_trigger_count self.xy_triggers = xy_triggers - + #signposts signpost_count = ord(rom[after_triggers]) signpost_byte_count = signpost_byte_size * signpost_count @@ -5977,7 +5791,7 @@ class MapEventHeader: after_signposts = after_triggers + 1 + signpost_byte_count self.signpost_count = signpost_count self.signposts = signposts - + #people events people_event_count = ord(rom[after_signposts]) people_event_byte_count = people_event_byte_size * people_event_count @@ -5986,13 +5800,12 @@ class MapEventHeader: people_events = parse_people_events(after_signposts+1, people_event_count, bank=bank, map_group=map_group, map_id=map_id, debug=debug) self.people_event_count = people_event_count self.people_events = people_events - + if people_event_count > 0: self.last_address = people_events[-1].last_address else: self.last_address = after_signposts+1 return True - def to_asm(self): xspacing = "" #was =spacing output = "" @@ -6017,7 +5830,6 @@ class MapEventHeader: return output - all_map_event_headers = [] def parse_map_event_header_at(address, map_group=None, map_id=None, debug=True, bank=None): """parse crystal map event header byte structure thing""" @@ -6035,28 +5847,28 @@ def old_parse_map_event_header_at(address, map_group=None, map_id=None, debug=Tr filler1 = ord(rom[address]) filler2 = ord(rom[address+1]) returnable.update({"1": filler1, "2": filler2}) - + #warps warp_count = ord(rom[address+2]) warp_byte_count = warp_byte_size * warp_count warps = rom_interval(address+3, warp_byte_count) after_warps = address + 3 + warp_byte_count returnable.update({"warp_count": warp_count, "warps": old_parse_warp_bytes(warps)}) - + #triggers (based on xy location) trigger_count = ord(rom[after_warps]) trigger_byte_count = trigger_byte_size * trigger_count triggers = rom_interval(after_warps+1, trigger_byte_count) after_triggers = after_warps + 1 + trigger_byte_count returnable.update({"xy_trigger_count": trigger_count, "xy_triggers": old_parse_xy_trigger_bytes(triggers, bank=bank, map_group=map_group, map_id=map_id)}) - + #signposts signpost_count = ord(rom[after_triggers]) signpost_byte_count = signpost_byte_size * signpost_count signposts = rom_interval(after_triggers+1, signpost_byte_count) after_signposts = after_triggers + 1 + signpost_byte_count returnable.update({"signpost_count": signpost_count, "signposts": old_parse_signpost_bytes(signposts, bank=bank, map_group=map_group, map_id=map_id)}) - + #people events people_event_count = ord(rom[after_signposts]) people_event_byte_count = people_event_byte_size * people_event_count @@ -6066,10 +5878,9 @@ def old_parse_map_event_header_at(address, map_group=None, map_id=None, debug=Tr return returnable - class MapScriptHeader: """parses a script header - + This structure allows the game to have e.g. one-time only events on a map or first enter events or permanent changes to the map or permanent script calls. @@ -6079,7 +5890,7 @@ class MapScriptHeader: referenced in the map event header, so this might need to be renamed very soon. The scripts in MapEventHeader are called XYTrigger. - trigger scripts: + trigger scripts: [[Number1 of pointers] Number1 * [2byte pointer to script][00][00]] callback scripts: @@ -6120,7 +5931,6 @@ class MapScriptHeader: 01, 04 """ base_label = "MapScriptHeader_" - def __init__(self, address, map_group=None, map_id=None, debug=True, bank=None, label=None): print "creating a MapScriptHeader at " + hex(address) + " map_group="+str(map_group)+" map_id="+str(map_id) self.address = address @@ -6134,7 +5944,6 @@ class MapScriptHeader: self.label = self.base_label + hex(address) self.parse() script_parse_table[address : self.last_address] = self - def parse(self): address = self.address map_group = self.map_group @@ -6167,7 +5976,6 @@ class MapScriptHeader: self.last_address = current_address print "done parsing a MapScriptHeader map_group="+str(map_group)+" map_id="+str(map_id) return True - def to_asm(self): output = "" output += "; trigger count\n" @@ -6183,7 +5991,6 @@ class MapScriptHeader: output += "\n".join(["dbw "+str(p["hook"].byte)+", "+p["callback"].to_asm() for p in self.callbacks]) return output - all_map_script_headers = [] def parse_map_script_header_at(address, map_group=None, map_id=None, debug=True): evv = MapScriptHeader(address, map_group=map_group, map_id=map_id, debug=debug) @@ -6209,10 +6016,10 @@ def old_parse_map_script_header_at(address, map_group=None, map_id=None, debug=T "address": trigger_address, "pointer": {"1": byte1, "2": byte2}, } - + #bump ahead in the byte stream address += trigger_ptr_cnt * ptr_line_size + 1 - + #[[Number2 of pointers] Number2 * [hook number][2byte pointer to script]] callback_ptr_line_size = 3 callback_ptr_cnt = ord(rom[address]) @@ -6233,7 +6040,7 @@ def old_parse_map_script_header_at(address, map_group=None, map_id=None, debug=T "address": callback_address, "pointer": {"1": callback_byte1, "2": callback_byte2}, } - + #XXX do these triggers/callbacks call asm or script engine scripts? return { #"trigger_ptr_cnt": trigger_ptr_cnt, @@ -6266,13 +6073,13 @@ def old_parse_trainer_header_at(address, map_group=None, map_id=None, debug=True silver_avoids = [0xfa53] if script_when_lost_ptr > 0x4000 and not script_when_lost_ptr in silver_avoids: script_when_lost = parse_script_engine_script_at(script_when_lost_ptr, map_group=map_group, map_id=map_id, debug=debug) - + print "parsing script-talk-again" #or is this a text? script_talk_again_ptr = calculate_pointer_from_bytes_at(address+10, bank=bank) script_talk_again = None if script_talk_again_ptr > 0x4000: script_talk_again = parse_script_engine_script_at(script_talk_again_ptr, map_group=map_group, map_id=map_id, debug=debug) - + return { "bit_number": bit_number, "trainer_group": trainer_group, @@ -6293,12 +6100,12 @@ def old_parse_people_event_bytes(some_bytes, address=None, map_group=None, map_i see http://hax.iimarck.us/files/scriptingcodes_eng.htm#Scripthdr For example, map 1.1 (group 1 map 1) has four person-events. - + 37 05 07 06 00 FF FF 00 00 02 40 FF FF 3B 08 0C 05 01 FF FF 00 00 05 40 FF FF 3A 07 06 06 00 FF FF A0 00 08 40 FF FF 29 05 0B 06 00 FF FF 00 00 0B 40 FF FF - + max of 14 people per map? """ assert len(some_bytes) % people_event_byte_size == 0, "wrong number of bytes" @@ -6319,7 +6126,7 @@ def old_parse_people_event_bytes(some_bytes, address=None, map_group=None, map_i clock_time_byte2 = int(bytes[6], 16) color_function_byte = int(bytes[7], 16) #Color|Function trainer_sight_range = int(bytes[8], 16) - + lower_bits = color_function_byte & 0xF #lower_bits_high = lower_bits >> 2 #lower_bits_low = lower_bits & 3 @@ -6367,7 +6174,7 @@ def old_parse_people_event_bytes(some_bytes, address=None, map_group=None, map_i "trainer_data_address": ptr_address, "trainer_data": parsed_trainer, } - + #XXX not sure what's going on here #bit no. of bit table 1 (hidden if set) #note: FFFF for none @@ -6439,13 +6246,13 @@ def parse_all_map_headers(debug=True): if debug: print "map_group is: " + str(group_id) + " map_id is: " + str(map_id) map_header_offset = offset + ((map_id - 1) * map_header_byte_size) map_names[group_id][map_id]["header_offset"] = map_header_offset - + new_parsed_map = parse_map_header_at(map_header_offset, map_group=group_id, map_id=map_id, debug=debug) map_names[group_id][map_id]["header_new"] = new_parsed_map old_parsed_map = old_parse_map_header_at(map_header_offset, map_group=group_id, map_id=map_id, debug=debug) map_names[group_id][map_id]["header_old"] = old_parsed_map -#map names with no labels will be generated at the end of the structure +#map names with no labels will be generated at the end of the structure map_names = { 1: { 0x1: {"name": "Olivine Pokémon Center 1F", @@ -6927,7 +6734,6 @@ map_names = { 0xB: {"name": "Route 31 Violet Gate"}, }, } - #generate labels for each map name for map_group_id in map_names.keys(): map_group = map_names[map_group_id] @@ -7057,7 +6863,7 @@ def split_incbin_line_into_three(line, start_address, byte_count, rom_file="../b """ splits an incbin line into three pieces. you can replace the middle one with the new content of length bytecount - + start_address: where you want to start inserting bytes byte_count: how many bytes you will be inserting """ @@ -7201,7 +7007,7 @@ def get_label_for(address): for thing in all_labels: if thing["address"] == address: return thing["label"] - + #the new way if is_script_already_parsed_at(address): obj = script_parse_table[address] @@ -7337,7 +7143,6 @@ def line_has_comment_address(line, returnable={}, bank=None): returnable["offset"] = offset returnable["address"] = calculate_pointer(offset, bank=bank) return True - def line_has_label(line): """returns True if the line has an asm label""" if not isinstance(line, str): @@ -7357,7 +7162,6 @@ def line_has_label(line): if "::" in line: return False return True - def get_label_from_line(line): """returns the label from the line""" #check if the line has a label @@ -7366,7 +7170,6 @@ def get_label_from_line(line): #split up the line label = line.split(":")[0] return label - def find_labels_without_addresses(): """scans the asm source and finds labels that are unmarked""" without_addresses = [] @@ -7458,7 +7261,7 @@ def scan_for_predefined_labels(debug=False): output += " to " output += str(end_line_id) print output - + #store the start/stop line number for this bank bank_intervals[bank_id] = {"start": start_line_id, "end": end_line_id,} @@ -7479,21 +7282,17 @@ def scan_for_predefined_labels(debug=False): class TestCram(unittest.TestCase): "this is where i cram all of my unit tests together" - @classmethod def setUpClass(cls): global rom cls.rom = direct_load_rom() rom = cls.rom - @classmethod def tearDownClass(cls): del cls.rom - def test_generic_useless(self): "do i know how to write a test?" self.assertEqual(1, 1) - def test_map_name_cleaner(self): name = "hello world" cleaned_name = map_name_cleaner(name) @@ -7504,7 +7303,6 @@ class TestCram(unittest.TestCase): self.assertNotEqual(name, cleaned_name) self.failIf(" " in cleaned_name) self.failIf("é" in cleaned_name) - def test_grouper(self): data = range(0, 10) groups = grouper(data, count=2) @@ -7514,12 +7312,10 @@ class TestCram(unittest.TestCase): self.assertEquals(len(groups), 10) self.assertNotEqual(data, groups) self.assertNotEqual(len(data), len(groups)) - def test_direct_load_rom(self): rom = self.rom self.assertEqual(len(rom), 2097152) self.failUnless(isinstance(rom, RomStr)) - def test_load_rom(self): global rom rom = None @@ -7528,29 +7324,24 @@ class TestCram(unittest.TestCase): rom = RomStr(None) load_rom() self.failIf(rom == RomStr(None)) - def test_load_asm(self): asm = load_asm() joined_lines = "\n".join(asm) self.failUnless("SECTION" in joined_lines) self.failUnless("bank" in joined_lines) self.failUnless(isinstance(asm, AsmList)) - def test_rom_file_existence(self): "ROM file must exist" self.failUnless("baserom.gbc" in os.listdir("../")) - def test_rom_md5(self): "ROM file must have the correct md5 sum" rom = self.rom correct = "9f2922b235a5eeb78d65594e82ef5dde" md5sum = md5.md5(rom).hexdigest() self.assertEqual(md5sum, correct) - def test_bizarre_http_presence(self): rom_segment = self.rom[0x112116:0x112116+8] self.assertEqual(rom_segment, "HTTP/1.0") - def test_rom_interval(self): address = 0x100 interval = 10 @@ -7561,7 +7352,6 @@ class TestCram(unittest.TestCase): correct_ints = [0, 195, 110, 1, 206, 237, 102, 102, 204, 13] ints = rom_interval(address, interval, strings=False) self.assertEqual(ints, correct_ints) - def test_rom_until(self): address = 0x1337 byte = 0x13 @@ -7571,18 +7361,15 @@ class TestCram(unittest.TestCase): bytes = rom_until(address, byte, strings=False) self.failUnless(len(bytes) == 3) self.failUnless(bytes[0] == 0xd5) - def test_how_many_until(self): how_many = how_many_until(chr(0x13), 0x1337) self.assertEqual(how_many, 3) - def test_calculate_bank(self): self.failUnless(calculate_bank(0x8000) == 2) self.failUnless(calculate_bank("0x9000") == 2) self.failUnless(calculate_bank(0) == 0) for address in [0x4000, 0x5000, 0x6000, 0x7000]: self.assertRaises(Exception, calculate_bank, address) - def test_calculate_pointer(self): #for offset <= 0x4000 self.assertEqual(calculate_pointer(0x0000), 0x0000) @@ -7591,16 +7378,13 @@ class TestCram(unittest.TestCase): self.assertEqual(calculate_pointer(0x430F, bank=5), 0x1430F) #for offset >= 0x7FFF self.assertEqual(calculate_pointer(0x8FFF, bank=6), calculate_pointer(0x8FFF, bank=7)) - def test_calculate_pointer_from_bytes_at(self): addr1 = calculate_pointer_from_bytes_at(0x100, bank=False) self.assertEqual(addr1, 0xc300) addr2 = calculate_pointer_from_bytes_at(0x100, bank=True) self.assertEqual(addr2, 0x2ec3) - def test_rom_text_at(self): self.assertEquals(rom_text_at(0x112116, 8), "HTTP/1.0") - def test_translate_command_byte(self): self.failUnless(translate_command_byte(crystal=0x0) == 0x0) self.failUnless(translate_command_byte(crystal=0x10) == 0x10) @@ -7614,7 +7398,6 @@ class TestCram(unittest.TestCase): self.failUnless(translate_command_byte(crystal=0x53) == 0x52) self.failUnless(translate_command_byte(crystal=0x52) == None) self.assertRaises(Exception, translate_command_byte, None, gold=0xA4) - def test_pksv_integrity(self): "does pksv_gs look okay?" self.assertEqual(pksv_gs[0x00], "2call") @@ -7623,19 +7406,16 @@ class TestCram(unittest.TestCase): self.assertEqual(pksv_crystal[0x00], "2call") self.assertEqual(pksv_crystal[0x86], "waitbutton") self.assertEqual(pksv_crystal[0xA2], "credits") - def test_chars_integrity(self): self.assertEqual(chars[0x80], "A") self.assertEqual(chars[0xA0], "a") self.assertEqual(chars[0xF0], "¥") self.assertEqual(jap_chars[0x44], "ぱ") - def test_map_names_integrity(self): def map_name(map_group, map_id): return map_names[map_group][map_id]["name"] self.assertEqual(map_name(2, 7), "Mahogany Town") self.assertEqual(map_name(3, 0x34), "Ilex Forest") self.assertEqual(map_name(7, 0x11), "Cerulean City") - def test_load_map_group_offsets(self): addresses = load_map_group_offsets() self.assertEqual(len(addresses), 26, msg="there should be 26 map groups") @@ -7646,29 +7426,24 @@ class TestCram(unittest.TestCase): self.assertGreaterEqual(address, 0x4000) self.failIf(0x4000 <= address <= 0x7FFF) self.failIf(address <= 0x4000) - def test_index(self): self.assertTrue(index([1,2,3,4], lambda f: True) == 0) self.assertTrue(index([1,2,3,4], lambda f: f==3) == 2) - def test_get_pokemon_constant_by_id(self): x = get_pokemon_constant_by_id self.assertEqual(x(1), "BULBASAUR") self.assertEqual(x(151), "MEW") self.assertEqual(x(250), "HO_OH") - def test_find_item_label_by_id(self): x = find_item_label_by_id self.assertEqual(x(249), "HM_07") self.assertEqual(x(173), "BERRY") self.assertEqual(x(45), None) - def test_generate_item_constants(self): x = generate_item_constants r = x() self.failUnless("HM_07" in r) self.failUnless("EQU" in r) - def test_get_label_for(self): global all_labels temp = copy(all_labels) @@ -7679,24 +7454,20 @@ class TestCram(unittest.TestCase): }] self.assertEqual(get_label_for(5), "poop") all_labels = temp - def test_generate_map_constant_labels(self): ids = generate_map_constant_labels() self.assertEqual(ids[0]["label"], "OLIVINE_POKECENTER_1F") self.assertEqual(ids[1]["label"], "OLIVINE_GYM") - def test_get_id_for_map_constant_label(self): global map_internal_ids map_internal_ids = generate_map_constant_labels() self.assertEqual(get_id_for_map_constant_label("OLIVINE_GYM"), 1) self.assertEqual(get_id_for_map_constant_label("OLIVINE_POKECENTER_1F"), 0) - def test_get_map_constant_label_by_id(self): global map_internal_ids map_internal_ids = generate_map_constant_labels() self.assertEqual(get_map_constant_label_by_id(0), "OLIVINE_POKECENTER_1F") self.assertEqual(get_map_constant_label_by_id(1), "OLIVINE_GYM") - def test_is_valid_address(self): self.assertTrue(is_valid_address(0)) self.assertTrue(is_valid_address(1)) @@ -7709,8 +7480,6 @@ class TestCram(unittest.TestCase): addresses = [random.randrange(0,2097153) for i in range(0, 9+1)] for address in addresses: self.assertTrue(is_valid_address(address)) - - class TestIntervalMap(unittest.TestCase): def test_intervals(self): i = IntervalMap() @@ -7725,7 +7494,6 @@ class TestIntervalMap(unittest.TestCase): i[3:10] = second self.assertEqual(i[3], second) self.assertNotEqual(i[4], first) - def test_items(self): i = IntervalMap() first = "hello world" @@ -7736,43 +7504,33 @@ class TestIntervalMap(unittest.TestCase): self.failUnless(len(results) == 2) self.assertEqual(results[0], ((0, 5), "hello world")) self.assertEqual(results[1], ((5, 10), "testing 123")) - - class TestRomStr(unittest.TestCase): """RomStr is a class that should act exactly like str() except that it never shows the contents of it string unless explicitly forced""" sample_text = "hello world!" sample = None - def setUp(self): if self.sample == None: self.__class__.sample = RomStr(self.sample_text) - def test_equals(self): "check if RomStr() == str()" self.assertEquals(self.sample_text, self.sample) - def test_not_equal(self): "check if RomStr('a') != RomStr('b')" self.assertNotEqual(RomStr('a'), RomStr('b')) - def test_appending(self): "check if RomStr()+'a'==str()+'a'" self.assertEquals(self.sample_text+'a', self.sample+'a') - def test_conversion(self): "check if RomStr() -> str() works" self.assertEquals(str(self.sample), self.sample_text) - def test_inheritance(self): self.failUnless(issubclass(RomStr, str)) - def test_length(self): self.assertEquals(len(self.sample_text), len(self.sample)) self.assertEquals(len(self.sample_text), self.sample.length()) self.assertEquals(len(self.sample), self.sample.length()) - def test_rom_interval(self): global rom load_rom() @@ -7785,7 +7543,6 @@ class TestRomStr(unittest.TestCase): correct_ints = [0, 195, 110, 1, 206, 237, 102, 102, 204, 13] ints = rom.interval(address, interval, strings=False) self.assertEqual(ints, correct_ints) - def test_rom_until(self): global rom load_rom() @@ -7797,23 +7554,18 @@ class TestRomStr(unittest.TestCase): bytes = rom.until(address, byte, strings=False) self.failUnless(len(bytes) == 3) self.failUnless(bytes[0] == 0xd5) - - class TestAsmList(unittest.TestCase): """AsmList is a class that should act exactly like list() except that it never shows the contents of its list unless explicitly forced""" - def test_equals(self): base = [1,2,3] asm = AsmList(base) self.assertEquals(base, asm) self.assertEquals(asm, base) self.assertEquals(base, list(asm)) - def test_inheritance(self): self.failUnless(issubclass(AsmList, list)) - def test_length(self): base = range(0, 10) asm = AsmList(base) @@ -7821,7 +7573,6 @@ class TestAsmList(unittest.TestCase): self.assertEquals(len(base), asm.length()) self.assertEquals(len(base), len(list(asm))) self.assertEquals(len(asm), asm.length()) - def test_remove_quoted_text(self): x = remove_quoted_text self.assertEqual(x("hello world"), "hello world") @@ -7831,7 +7582,6 @@ class TestAsmList(unittest.TestCase): input = "hello world 'testing 123'" self.assertNotEqual(x(input), input) self.failIf("testing" in x(input)) - def test_line_has_comment_address(self): x = line_has_comment_address self.assertFalse(x("")) @@ -7866,7 +7616,6 @@ class TestAsmList(unittest.TestCase): returnable = {} self.assertTrue(x("hello_world: ; 0x4050", returnable=returnable, bank=5)) self.assertTrue(returnable["address"] == 0x14050) - def test_line_has_label(self): x = line_has_label self.assertTrue(x("hi:")) @@ -7876,13 +7625,11 @@ class TestAsmList(unittest.TestCase): self.assertFalse(x(";HelloWorld:")) self.assertFalse(x("::::")) self.assertFalse(x(":;:;:;:::")) - def test_get_label_from_line(self): x = get_label_from_line self.assertEqual(x("HelloWorld: "), "HelloWorld") self.assertEqual(x("HiWorld:"), "HiWorld") self.assertEqual(x("HiWorld"), None) - def test_find_labels_without_addresses(self): global asm asm = ["hello_world: ; 0x1", "hello_world2: ;"] @@ -7892,7 +7639,6 @@ class TestAsmList(unittest.TestCase): labels = find_labels_without_addresses() self.failUnless(len(labels) == 0) asm = None - def test_get_labels_between(self): global asm x = get_labels_between#(start_line_id, end_line_id, bank) @@ -7904,7 +7650,6 @@ class TestAsmList(unittest.TestCase): self.assertEqual(len(labels), 1) self.assertEqual(labels[0]["label"], "HelloWorld") del asm - def test_scan_for_predefined_labels(self): #label keys: line_number, bank, label, offset, address load_asm() @@ -7913,7 +7658,6 @@ class TestAsmList(unittest.TestCase): self.assertIn("GetFarByte", label_names) self.assertIn("AddNTimes", label_names) self.assertIn("CheckShininess", label_names) - def test_write_all_labels(self): """dumping json into a file""" filename = "test_labels.json" @@ -7940,7 +7684,6 @@ class TestAsmList(unittest.TestCase): self.assertEqual(len(obj), len(labels)) self.assertEqual(len(obj), 2) self.assertEqual(obj, labels) - def test_isolate_incbins(self): global asm asm = ["123", "456", "789", "abc", "def", "ghi", @@ -7952,7 +7695,6 @@ class TestAsmList(unittest.TestCase): self.assertIn(asm[8], lines) for line in lines: self.assertIn("baserom", line) - def test_process_incbins(self): global incbin_lines, processed_incbins, asm incbin_lines = ['INCBIN "baserom.gbc",$12DA,$12F8 - $12DA', @@ -7963,7 +7705,6 @@ class TestAsmList(unittest.TestCase): self.assertEqual(len(processed_incbins), len(incbin_lines)) self.assertEqual(processed_incbins[0]["line"], incbin_lines[0]) self.assertEqual(processed_incbins[2]["line"], incbin_lines[1]) - def test_reset_incbins(self): global asm, incbin_lines, processed_incbins #temporarily override the functions @@ -7980,7 +7721,6 @@ class TestAsmList(unittest.TestCase): self.assertTrue(processed_incbins == {}) #reset the original functions load_asm, isolate_incbins, process_incbins = temp1, temp2, temp3 - def test_find_incbin_to_replace_for(self): global asm, incbin_lines, processed_incbins asm = ['first line', 'second line', 'third line', @@ -7991,7 +7731,6 @@ class TestAsmList(unittest.TestCase): line_num = find_incbin_to_replace_for(0x100) #must be the 4th line (the INBIN line) self.assertEqual(line_num, 3) - def test_split_incbin_line_into_three(self): global asm, incbin_lines, processed_incbins asm = ['first line', 'second line', 'third line', @@ -8002,7 +7741,6 @@ class TestAsmList(unittest.TestCase): content = split_incbin_line_into_three(3, 0x100, 10) #must end up with three INCBINs in output self.failUnless(content.count("INCBIN") == 3) - def test_analyze_intervals(self): global asm, incbin_lines, processed_incbins asm, incbin_lines, processed_incbins = None, [], {} @@ -8017,7 +7755,6 @@ class TestAsmList(unittest.TestCase): self.assertEqual(largest[0]["line"], asm[6]) self.assertEqual(largest[1]["line_number"], 3) self.assertEqual(largest[1]["line"], asm[3]) - def test_generate_diff_insert(self): global asm asm = ['first line', 'second line', 'third line', @@ -8029,8 +7766,6 @@ class TestAsmList(unittest.TestCase): self.assertIn("INCBIN", diff) self.assertNotIn("No newline at end of file", diff) self.assertIn("+"+asm[1], diff) - - class TestMapParsing(unittest.TestCase): #def test_parse_warp_bytes(self): # pass #or raise NotImplementedError, bryan_message @@ -8048,7 +7783,6 @@ class TestMapParsing(unittest.TestCase): # pass #or raise NotImplementedError, bryan_message #def test_parse_map_header_by_id(self): # pass #or raise NotImplementedError, bryan_message - def test_parse_all_map_headers(self): global parse_map_header_at, counter counter = 0 @@ -8063,8 +7797,6 @@ class TestMapParsing(unittest.TestCase): parse_all_map_headers(debug=False) self.assertEqual(counter, 388) parse_map_header_at = temp - - class TestTextScript(unittest.TestCase): """for testing 'in-script' commands, etc.""" #def test_to_asm(self): @@ -8073,39 +7805,30 @@ class TestTextScript(unittest.TestCase): # pass #or raise NotImplementedError, bryan_message #def test_parse_text_at(self): # pass #or raise NotImplementedError, bryan_message - - class TestEncodedText(unittest.TestCase): """for testing chars-table encoded text chunks""" - def test_process_00_subcommands(self): g = process_00_subcommands(0x197186, 0x197186+601, debug=False) self.assertEqual(len(g), 42) self.assertEqual(len(g[0]), 13) self.assertEqual(g[1], [184, 174, 180, 211, 164, 127, 20, 231, 81]) - def test_parse_text_at2(self): oakspeech = parse_text_at2(0x197186, 601, debug=False) self.assertIn("encyclopedia", oakspeech) self.assertIn("researcher", oakspeech) self.assertIn("dependable", oakspeech) - def test_parse_text_engine_script_at(self): p = parse_text_engine_script_at(0x197185, debug=False) self.assertEqual(len(p), 2) self.assertEqual(len(p[0]["lines"]), 41) - #don't really care about these other two def test_parse_text_from_bytes(self): pass def test_parse_text_at(self): pass - - class TestScript(unittest.TestCase): """for testing parse_script_engine_script_at and script parsing in general. Script should be a class.""" #def test_parse_script_engine_script_at(self): # pass #or raise NotImplementedError, bryan_message - def test_find_all_text_pointers_in_script_engine_script(self): address = 0x197637 #0x197634 script = parse_script_engine_script_at(address, debug=False) @@ -8113,8 +7836,6 @@ class TestScript(unittest.TestCase): r = find_all_text_pointers_in_script_engine_script(script, bank=bank, debug=False) results = list(r) self.assertIn(0x197661, results) - - class TestLabel(unittest.TestCase): def test_label_making(self): line_number = 2 @@ -8130,68 +7851,53 @@ class TestLabel(unittest.TestCase): self.assertEqual(l.line_number, line_number) self.assertEqual(l.name, label_name) self.assertEqual(l.address, address) - - class TestByteParams(unittest.TestCase): @classmethod def setUpClass(cls): load_rom() cls.address = 10 cls.sbp = SingleByteParam(address=cls.address) - @classmethod def tearDownClass(cls): del cls.sbp - def test__init__(self): self.assertEqual(self.sbp.size, 1) self.assertEqual(self.sbp.address, self.address) - def test_parse(self): self.sbp.parse() self.assertEqual(str(self.sbp.byte), str(45)) - def test_to_asm(self): self.assertEqual(self.sbp.to_asm(), "$2d") self.sbp.should_be_decimal = True self.assertEqual(self.sbp.to_asm(), str(45)) - def test_HexByte_to_asm(self): h = HexByte(address=10) a = h.to_asm() self.assertEqual(a, "0x2d") - def test_DollarSignByte_to_asm(self): d = DollarSignByte(address=10) a = d.to_asm() self.assertEqual(a, "$2d") - def test_ItemLabelByte_to_asm(self): i = ItemLabelByte(address=433) self.assertEqual(i.byte, 54) self.assertEqual(i.to_asm(), "COIN_CASE") self.assertEqual(ItemLabelByte(address=10).to_asm(), "$2d") - def test_DecimalParam_to_asm(self): d = DecimalParam(address=10) x = d.to_asm() self.assertEqual(x, str(0x2d)) - - class TestMultiByteParam(unittest.TestCase): def setup_for(self, somecls, byte_size=2, address=443, **kwargs): self.cls = somecls(address=address, size=byte_size, **kwargs) self.assertEqual(self.cls.address, address) self.assertEqual(self.cls.bytes, rom_interval(address, byte_size, strings=False)) self.assertEqual(self.cls.size, byte_size) - def test_two_byte_param(self): self.setup_for(MultiByteParam, byte_size=2) self.assertEqual(self.cls.to_asm(), "$f0c0") - def test_three_byte_param(self): self.setup_for(MultiByteParam, byte_size=3) - def test_PointerLabelParam_no_bank(self): self.setup_for(PointerLabelParam, bank=None) #assuming no label at this location.. @@ -8203,84 +7909,66 @@ class TestMultiByteParam(unittest.TestCase): "line_number": 2 }] self.assertEqual(self.cls.to_asm(), "poop") - - class TestPostParsing: #(unittest.TestCase): """tests that must be run after parsing all maps""" @classmethod def setUpClass(cls): run_main() - def test_signpost_counts(self): self.assertEqual(len(map_names[1][1]["signposts"]), 0) self.assertEqual(len(map_names[1][2]["signposts"]), 2) self.assertEqual(len(map_names[10][5]["signposts"]), 7) - def test_warp_counts(self): self.assertEqual(map_names[10][5]["warp_count"], 9) self.assertEqual(map_names[18][5]["warp_count"], 3) self.assertEqual(map_names[15][1]["warp_count"], 2) - def test_map_sizes(self): self.assertEqual(map_names[15][1]["height"], 18) self.assertEqual(map_names[15][1]["width"], 10) self.assertEqual(map_names[7][1]["height"], 4) self.assertEqual(map_names[7][1]["width"], 4) - def test_map_connection_counts(self): self.assertEqual(map_names[7][1]["connections"], 0) self.assertEqual(map_names[10][1]["connections"], 12) self.assertEqual(map_names[10][2]["connections"], 12) self.assertEqual(map_names[11][1]["connections"], 9) #or 13? - def test_second_map_header_address(self): self.assertEqual(map_names[11][1]["second_map_header_address"], 0x9509c) self.assertEqual(map_names[1][5]["second_map_header_address"], 0x95bd0) - def test_event_address(self): self.assertEqual(map_names[17][5]["event_address"], 0x194d67) self.assertEqual(map_names[23][3]["event_address"], 0x1a9ec9) - def test_people_event_counts(self): self.assertEqual(len(map_names[23][3]["people_events"]), 4) self.assertEqual(len(map_names[10][3]["people_events"]), 9) - - class TestMetaTesting(unittest.TestCase): """test whether or not i am finding at least some of the tests in this file""" tests = None - def setUp(self): if self.tests == None: self.__class__.tests = assemble_test_cases() - def test_assemble_test_cases_count(self): "does assemble_test_cases find some tests?" self.failUnless(len(self.tests) > 0) - def test_assemble_test_cases_inclusion(self): "is this class found by assemble_test_cases?" #i guess it would have to be for this to be running? self.failUnless(self.__class__ in self.tests) - def test_assemble_test_cases_others(self): "test other inclusions for assemble_test_cases" self.failUnless(TestRomStr in self.tests) self.failUnless(TestCram in self.tests) - def test_check_has_test(self): self.failUnless(check_has_test("beaver", ["test_beaver"])) self.failUnless(check_has_test("beaver", ["test_beaver_2"])) self.failIf(check_has_test("beaver_1", ["test_beaver"])) - def test_find_untested_methods(self): untested = find_untested_methods() #the return type must be an iterable self.failUnless(hasattr(untested, "__iter__")) #.. basically, a list self.failUnless(isinstance(untested, list)) - def test_find_untested_methods_method(self): """create a function and see if it is found""" #setup a function in the global namespace @@ -8296,7 +7984,6 @@ class TestMetaTesting(unittest.TestCase): self.assertIn("some_random_test_method", untested) #remove the test method from the global namespace del some_random_test_method - def test_load_tests(self): loader = unittest.TestLoader() suite = load_tests(loader, None, None) @@ -8307,7 +7994,6 @@ class TestMetaTesting(unittest.TestCase): classes = [x[1] for x in tests] for test in suite._tests: self.assertIn(test.__class__, classes) - def test_report_untested(self): untested = find_untested_methods() output = report_untested() @@ -8317,11 +8003,9 @@ class TestMetaTesting(unittest.TestCase): self.assertIn(name, output) elif len(untested) == 0: self.assertNotIn("NOT TESTED", output) - - def assemble_test_cases(): """finds classes that inherit from unittest.TestCase - because i am too lazy to remember to add them to a + because i am too lazy to remember to add them to a global list of tests for the suite runner""" classes = [] clsmembers = inspect.getmembers(sys.modules[__name__], inspect.isclass) @@ -8329,14 +8013,12 @@ def assemble_test_cases(): if issubclass(some_class, unittest.TestCase): classes.append(some_class) return classes - def load_tests(loader, tests, pattern): suite = unittest.TestSuite() for test_class in assemble_test_cases(): tests = loader.loadTestsFromTestCase(test_class) suite.addTests(tests) return suite - def check_has_test(func_name, tested_names): """checks if there is a test dedicated to this function""" if "test_"+func_name in tested_names: @@ -8345,7 +8027,6 @@ def check_has_test(func_name, tested_names): if "test_"+func_name in name: return True return False - def find_untested_methods(): """finds all untested functions in this module by searching for method names in test case @@ -8375,13 +8056,12 @@ def find_untested_methods(): #we don't care about some of these if name in avoid_funcs: continue #skip functions beginning with _ - if name[0] == "_": continue + if name[0] == "_": continue #check if this function has a test named after it has_test = check_has_test(name, tested_names) if not has_test: untested.append(name) return untested - def report_untested(): untested = find_untested_methods() output = "NOT TESTED: [" @@ -8402,7 +8082,6 @@ def run_tests(): #rather than unittest.main() suite = load_tests(loader, None, None) unittest.TextTestRunner(verbosity=2).run(suite) print report_untested() - def run_main(): #read the rom and figure out the offsets for maps direct_load_rom() @@ -8411,7 +8090,6 @@ def run_main(): [map_names[map_group_id+1].update({"offset": offset}) for map_group_id, offset in enumerate(map_group_offsets)] #parse map header bytes for each map parse_all_map_headers() - #just a helpful alias main=run_main #when you run the file.. do unit tests