def scan_rom_for_tx_fars(printer=True): """find TX_FARs search only addresses that are INCBINed keep only TX_FARs that are valid returns a list of [TX_FAR target address, TX_FAR address]""" rom = extract_maps.rom analyze_incbins.load_asm() analyze_incbins.isolate_incbins() analyze_incbins.process_incbins() possible_tx_fars = [] possible_tx_far_targets = [] for incbin_line_number in analyze_incbins.processed_incbins.keys(): incbin = analyze_incbins.processed_incbins[incbin_line_number] start_address = incbin["start"] end_address = incbin["end"] if incbin["interval"] == 0: continue #skip this one subrom = rom[start_address:end_address] for address in range(start_address, end_address): current_byte = ord(rom[address]) if current_byte == 0x17: if ord(rom[address + 4]) == 0x50: byte1 = ord(rom[address + 1]) byte2 = ord(rom[address + 2]) address2 = byte1 + (byte2 << 8) if address2 > 0x3fff: address2 = extract_maps.calculate_pointer( address2, ord(rom[address + 3])) #print "possible TX_FAR at " + hex(address) + " to " + hex(address2) possible_tx_fars.append(address) possible_tx_far_targets.append([address2, address]) if printer: pre_handled = [] #address_bundle is [TX_FAR target address, TX_FAR address] for address_bundle in possible_tx_far_targets: if address_bundle[0] in [0xa82f8, 0xa8315]: continue #bad if address_bundle[0] in pre_handled: continue #already did this print "-------" print "TX_FAR is at: " + hex(address_bundle[1]) #let's try printing out the TX_FAR? text_pretty_printer_at(address_bundle[1], "blah") text_pretty_printer_at(address_bundle[0], "_blah") print "-------" pre_handled.append(address_bundle[0]) return possible_tx_far_targets
def scan_rom_for_tx_fars(printer=True): """find TX_FARs search only addresses that are INCBINed keep only TX_FARs that are valid returns a list of [TX_FAR target address, TX_FAR address]""" rom = extract_maps.rom analyze_incbins.load_asm() analyze_incbins.isolate_incbins() analyze_incbins.process_incbins() possible_tx_fars = [] possible_tx_far_targets = [] for incbin_line_number in analyze_incbins.processed_incbins.keys(): incbin = analyze_incbins.processed_incbins[incbin_line_number] start_address = incbin["start"] end_address = incbin["end"] if incbin["interval"] == 0: continue #skip this one subrom = rom[start_address:end_address] for address in range(start_address, end_address): current_byte = ord(rom[address]) if current_byte == 0x17: if ord(rom[address+4]) == 0x50: byte1 = ord(rom[address+1]) byte2 = ord(rom[address+2]) address2 = byte1 + (byte2 << 8) if address2 > 0x3fff: address2 = extract_maps.calculate_pointer(address2, ord(rom[address+3])) #print "possible TX_FAR at " + hex(address) + " to " + hex(address2) possible_tx_fars.append(address) possible_tx_far_targets.append([address2, address]) if printer: pre_handled = [] #address_bundle is [TX_FAR target address, TX_FAR address] for address_bundle in possible_tx_far_targets: if address_bundle[0] in [0xa82f8, 0xa8315]: continue #bad if address_bundle[0] in pre_handled: continue #already did this print "-------" print "TX_FAR is at: " + hex(address_bundle[1]) #let's try printing out the TX_FAR? text_pretty_printer_at(address_bundle[1], "blah") text_pretty_printer_at(address_bundle[0], "_blah") print "-------" pre_handled.append(address_bundle[0]) return possible_tx_far_targets
def insert_text_label_tx_far(map_id, text_id): if map_id in extract_maps.bad_maps: print "bad map id=" + str(map_id) return map2 = extract_maps.map_headers[map_id] if map2["texts"][text_id] == {0: {}}: return None base_label = map_name_cleaner(map2["name"], None)[:-2] label = base_label + "Text" + str(text_id) target_label = "_" + label start_address = map2["texts"][text_id][0]["start_address"] if 0x4000 <= start_address <= 0x7fff: start_address = extract_maps.calculate_pointer(start_address, int(map2["bank"],16)) include_byte = False print map2["texts"][text_id] if "type" in map2["texts"][text_id][1].keys(): if map2["texts"][text_id][1]["type"] == 0x50: include_byte = True tx_far_asm = txt_to_tx_far_pretty_printer(start_address, label, target_label, include_byte=include_byte) line_number = find_incbin_to_replace_for(start_address) if line_number == None: print "skipping text label that calls TX_FAR for map_id=" + str(map_id) + " text_id=" + str(text_id) + " because the address is taken " + hex(start_address) return #also do a name check if 1 < ("\n".join(analyze_incbins.asm)).count("\n" + label + ":"): print "skipping text label that calls TX_FAR for map_id=" + str(map_id) + " text_id" + str(text_id) + " because the label is already used (" + label + ":)" return extra = 0 if include_byte: extra += 1 newlines = split_incbin_line_into_three(line_number, start_address, 4 + extra ) newlines = newlines.split("\n") if len(newlines) == 2: index = 0 #replace the 1st line with new content elif len(newlines) == 3: index = 1 #replace the 2nd line with new content newlines[index] = tx_far_asm if len(newlines) == 3 and newlines[2][-2:] == "$0": #get rid of the last incbin line if it is only including 0 bytes del newlines[2] #note that this has to be done after adding in the new asm newlines = "\n".join(line for line in newlines) newlines = newlines.replace("$x", "$") diff = generate_diff_insert(line_number, newlines) print "working on map_id=" + str(map_id) + " text_id=" + str(text_id) print diff apply_diff(diff)
def test_first_text_pointer_bytes( range=20 ): #30 for viridian city, 34 for cerulean city, 36 for celadon, 48 for fuchsia city, 50 for safron """ does the first text pointer byte always point to (end address of text pointer list) + 1? range determines how far is acceptable. r=15 means 30 text pointers """ for map_id in extract_maps.map_headers: map = extract_maps.map_headers[map_id] bank = int(map["bank"], 16) text_list_pointer = int(map["texts_pointer"], 16) bad_names = [ "FREEZE", "COPY: Cinnibar Mart", "COPY OF: Underground Tunnel Entrance (Route 6)", "COPY OF: Trashed House", "COPY OF: Underground Path Entrance (Route 7)" ] if map["name"] in bad_names: continue #extract the bytes making up the first text pointer pointer_byte1 = ord(extract_maps.rom[text_list_pointer]) pointer_byte2 = ord(extract_maps.rom[text_list_pointer + 1]) #swap the bytes temp = pointer_byte1 pointer_byte1 = pointer_byte2 pointer_byte2 = temp del temp #combine these into a single pointer partial_pointer = (pointer_byte2 + (pointer_byte1 << 8)) #get the full pointer first_text_pointer = extract_maps.calculate_pointer( partial_pointer, bank) #if (first_text_pointer <= (text_list_pointer+range)): print "map " + map["name"] + " (" + str(map["id"]) + ")" print spacing + "text_pointer (list) = " + hex(text_list_pointer) print spacing + "first_text_pointer (first text) = " + hex( first_text_pointer) print spacing + "difference = " + str(first_text_pointer - text_list_pointer) #return False return True
def analyze_texts(): global should_be_total texts = {} for map_id in extract_maps.map_headers: if map_id in extract_maps.bad_maps: continue #skip map2 = extract_maps.map_headers[map_id] map2["texts"] = {} referenced_texts = map2["referenced_texts"] should_be_total += len(referenced_texts) texts_pointer = int(map2["texts_pointer"], 16) #print "Checking texts on... map_id=" + str(map_id) + " and len(referenced_texts)=" + str(len(referenced_texts)) for text_id in referenced_texts: text_pointer = get_text_pointer(texts_pointer, text_id) if 0x4000 <= text_pointer <= 0x7fff: #only care about bank when it's between 4000-7fff text_pointer = extract_maps.calculate_pointer( text_pointer, int(map2["bank"], 16)) #print "Working on map id=" + str(map2["id"]) + " and text id=" + str(text_id) #print "for map_id=" + str(map_id) + " texts_pointer=" + hex(texts_pointer) + " text_id=" + str(text_id) + " the pointer=" + hex(text_pointer) commands = parse_text_script(text_pointer, text_id, map_id) #process TX_FARs for command_id in commands: #skip commands starting with an unknown command byte if len(commands[command_id]) == 0: continue if commands[command_id]["type"] == 0x17: TX_FAR = parse_text_script(commands[command_id]["pointer"], text_id, map_id, txfar=True) if debug: if len(TX_FAR.keys()) > 0: #print "TX_FAR object: " + str(TX_FAR) print "processing a TX_FAR at " + hex( commands[command_id] ["pointer"]) + "... first byte is: " + str( ord(extract_maps.rom[commands[command_id][ "pointer"]])) + " .. offset: " + hex( commands[command_id]["pointer"]) ##sys.exit(0) commands[command_id]["TX_FAR"] = TX_FAR #map2["texts"][text_id][command_id]["TX_FAR"] = parse_text_script(command["pointer"], text_id, map_id) map2["texts"][text_id] = commands texts[map_id] = map2["texts"] extract_maps.map_headers[map_id]["texts"] = map2["texts"] return texts
def test_first_text_pointer_bytes( range=20 ): # 30 for viridian city, 34 for cerulean city, 36 for celadon, 48 for fuchsia city, 50 for safron """ does the first text pointer byte always point to (end address of text pointer list) + 1? range determines how far is acceptable. r=15 means 30 text pointers """ for map_id in extract_maps.map_headers: map = extract_maps.map_headers[map_id] bank = int(map["bank"], 16) text_list_pointer = int(map["texts_pointer"], 16) bad_names = [ "FREEZE", "COPY: Cinnibar Mart", "COPY OF: Underground Tunnel Entrance (Route 6)", "COPY OF: Trashed House", "COPY OF: Underground Path Entrance (Route 7)", ] if map["name"] in bad_names: continue # extract the bytes making up the first text pointer pointer_byte1 = ord(extract_maps.rom[text_list_pointer]) pointer_byte2 = ord(extract_maps.rom[text_list_pointer + 1]) # swap the bytes temp = pointer_byte1 pointer_byte1 = pointer_byte2 pointer_byte2 = temp del temp # combine these into a single pointer partial_pointer = pointer_byte2 + (pointer_byte1 << 8) # get the full pointer first_text_pointer = extract_maps.calculate_pointer(partial_pointer, bank) # if (first_text_pointer <= (text_list_pointer+range)): print "map " + map["name"] + " (" + str(map["id"]) + ")" print spacing + "text_pointer (list) = " + hex(text_list_pointer) print spacing + "first_text_pointer (first text) = " + hex(first_text_pointer) print spacing + "difference = " + str(first_text_pointer - text_list_pointer) # return False return True
def analyze_texts(): global should_be_total texts = {} for map_id in extract_maps.map_headers: if map_id in extract_maps.bad_maps: continue #skip map2 = extract_maps.map_headers[map_id] map2["texts"] = {} referenced_texts = map2["referenced_texts"] should_be_total += len(referenced_texts) texts_pointer = int(map2["texts_pointer"], 16) #print "Checking texts on... map_id=" + str(map_id) + " and len(referenced_texts)=" + str(len(referenced_texts)) for text_id in referenced_texts: text_pointer = get_text_pointer(texts_pointer, text_id) if 0x4000 <= text_pointer <= 0x7fff: #only care about bank when it's between 4000-7fff text_pointer = extract_maps.calculate_pointer(text_pointer, int(map2["bank"], 16)) #print "Working on map id=" + str(map2["id"]) + " and text id=" + str(text_id) #print "for map_id=" + str(map_id) + " texts_pointer=" + hex(texts_pointer) + " text_id=" + str(text_id) + " the pointer=" + hex(text_pointer) commands = parse_text_script(text_pointer, text_id, map_id) #process TX_FARs for command_id in commands: #skip commands starting with an unknown command byte if len(commands[command_id]) == 0: continue if commands[command_id]["type"] == 0x17: TX_FAR = parse_text_script(commands[command_id]["pointer"], text_id, map_id, txfar=True) if debug: if len(TX_FAR.keys()) > 0: #print "TX_FAR object: " + str(TX_FAR) print "processing a TX_FAR at " + hex(commands[command_id]["pointer"]) + "... first byte is: " + str(ord(extract_maps.rom[commands[command_id]["pointer"]])) + " .. offset: " + hex(commands[command_id]["pointer"]) ##sys.exit(0) commands[command_id]["TX_FAR"] = TX_FAR #map2["texts"][text_id][command_id]["TX_FAR"] = parse_text_script(command["pointer"], text_id, map_id) map2["texts"][text_id] = commands texts[map_id] = map2["texts"] extract_maps.map_headers[map_id]["texts"] = map2["texts"] return texts
def parse_sprite_sheet_pointer_table(): """parses the bytes making up the pointer table first two bytes are the pointer third byte is the number of bytes (1 * 4 tiles * 16 bytes each, or 3 * 4 tiles * 16 bytes per tile) 1 = 1 pose 3 = 3 poses, possibly 6 immediately after $C0 or $40 fourth byte is the rom bank so a quick estimation is that, if it has 3, and there's no other pointer that points to the one after the 3rd & next 3, then assume those next 3 are the 4th, 5th and 6th """ rom = extract_maps.rom ptable_address = 0x17b27 #5:7b27 ptable_pointers = [] ptable_sheet_data = {} #load up pointers please for sprite_id in sprite_constants.keys(): pointer_offset = 0x17b27 + ((sprite_id - 1) * 4) pointer_byte1 = ord(rom[pointer_offset]) pointer_byte2 = ord(rom[pointer_offset + 1]) partial_pointer = (pointer_byte1 + (pointer_byte2 << 8)) bank = ord(rom[pointer_offset + 3]) pointer = extract_maps.calculate_pointer(partial_pointer, bank) ptable_pointers.append(pointer) #72 sprite pointers, we're not using id=$32 for sprite_id in sprite_constants.keys(): sprite_name = sprite_constants[sprite_id] #some basic information about this sprite first data_entry = {"sprite_id": sprite_id, "sprite_name": sprite_name} #calculate where it is in the 0x17b27 pointer table pointer_offset = 0x17b27 + ((sprite_id - 1) * 4) data_entry["sprite_ptr_table_entry_address"] = pointer_offset #actual sprite pointer pointer_byte1 = ord(rom[pointer_offset]) pointer_byte2 = ord(rom[pointer_offset + 1]) partial_pointer = (pointer_byte1 + (pointer_byte2 << 8)) bank = ord(rom[pointer_offset + 3]) pointer = extract_maps.calculate_pointer(partial_pointer, bank) data_entry["pointer"] = pointer data_entry["bank"] = bank byte_count = ord(rom[pointer_offset + 2]) data_entry["byte_count"] = byte_count has_more_text = "" data_entry["poses"] = 1 if byte_count == 0xc0: #has at least 3 poses setter1, setter2, setter3 = False, False, False data_entry["poses"] = 3 #let's check if there's possibly more if not ((byte_count + pointer) in ptable_pointers): #yep, probably (#4) data_entry["poses"] += 1 data_entry["byte_count"] += 64 setter1 = True if setter1 and not ((byte_count + pointer + 64) in ptable_pointers): #has another (#5) data_entry["poses"] += 1 data_entry["byte_count"] += 64 setter2 = True if setter2 and not ((byte_count + pointer + 64 + 64) in ptable_pointers): #has a #6 data_entry["poses"] += 1 data_entry["byte_count"] += 64 setter3 = True print("$%.2x " % (sprite_id)) + sprite_name + " has $%.2x bytes" % ( byte_count) + " pointing to 0x%.x" % ( pointer) + " bank is $%.2x" % ( bank) + " with pose_count=" + str(data_entry["poses"]) ptable_sheet_data[sprite_id] = data_entry return ptable_sheet_data
def parse_sprite_sheet_pointer_table(): """parses the bytes making up the pointer table first two bytes are the pointer third byte is the number of bytes (1 * 4 tiles * 16 bytes each, or 3 * 4 tiles * 16 bytes per tile) 1 = 1 pose 3 = 3 poses, possibly 6 immediately after $C0 or $40 fourth byte is the rom bank so a quick estimation is that, if it has 3, and there's no other pointer that points to the one after the 3rd & next 3, then assume those next 3 are the 4th, 5th and 6th """ rom = extract_maps.rom ptable_address = 0x17b27 #5:7b27 ptable_pointers = [] ptable_sheet_data = {} #load up pointers please for sprite_id in sprite_constants.keys(): pointer_offset = 0x17b27 + ((sprite_id -1) * 4) pointer_byte1 = ord(rom[pointer_offset]) pointer_byte2 = ord(rom[pointer_offset+1]) partial_pointer = (pointer_byte1 + (pointer_byte2 << 8)) bank = ord(rom[pointer_offset+3]) pointer = extract_maps.calculate_pointer(partial_pointer, bank) ptable_pointers.append(pointer) #72 sprite pointers, we're not using id=$32 for sprite_id in sprite_constants.keys(): sprite_name = sprite_constants[sprite_id] #some basic information about this sprite first data_entry = {"sprite_id": sprite_id, "sprite_name": sprite_name} #calculate where it is in the 0x17b27 pointer table pointer_offset = 0x17b27 + ((sprite_id -1) * 4) data_entry["sprite_ptr_table_entry_address"] = pointer_offset #actual sprite pointer pointer_byte1 = ord(rom[pointer_offset]) pointer_byte2 = ord(rom[pointer_offset+1]) partial_pointer = (pointer_byte1 + (pointer_byte2 << 8)) bank = ord(rom[pointer_offset+3]) pointer = extract_maps.calculate_pointer(partial_pointer, bank) data_entry["pointer"] = pointer data_entry["bank"] = bank byte_count = ord(rom[pointer_offset+2]) data_entry["byte_count"] = byte_count has_more_text = "" data_entry["poses"] = 1 if byte_count == 0xc0: #has at least 3 poses setter1, setter2, setter3 = False, False, False data_entry["poses"] = 3 #let's check if there's possibly more if not ((byte_count + pointer) in ptable_pointers): #yep, probably (#4) data_entry["poses"] += 1 data_entry["byte_count"] += 64 setter1 = True if setter1 and not ((byte_count + pointer + 64) in ptable_pointers): #has another (#5) data_entry["poses"] += 1 data_entry["byte_count"] += 64 setter2 = True if setter2 and not ((byte_count + pointer + 64 + 64) in ptable_pointers): #has a #6 data_entry["poses"] += 1 data_entry["byte_count"] += 64 setter3 = True print ("$%.2x " % (sprite_id)) + sprite_name + " has $%.2x bytes" % (byte_count) + " pointing to 0x%.x" % (pointer) + " bank is $%.2x" % (bank) + " with pose_count=" + str(data_entry["poses"]) ptable_sheet_data[sprite_id] = data_entry return ptable_sheet_data
def parse_text_script(text_pointer, text_id, map_id, txfar=False): global total_text_commands offset = text_pointer commands = {} command_counter = 0 if extract_maps.rom == None: extract_maps.load_rom() end = False while not end: command = {} command_byte = ord(extract_maps.rom[offset]) print_command_debug_info(command_byte, text_id, text_pointer, map_id) if command_byte == 0: #read until $57, $50 or $58 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 command = {"type": command_byte, "start_address": offset, "end_address": end_address, "size": jump, "lines": process_00_subcommands(offset+1, end_address), } offset += jump elif command_byte == 0x17: #TX_FAR [pointer][bank] pointer_byte1 = ord(extract_maps.rom[offset+1]) pointer_byte2 = ord(extract_maps.rom[offset+2]) pointer_bank = ord(extract_maps.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(extract_maps.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 add_command_byte_to_totals(command_byte) elif command_byte == 0x50: #only end if we started with $0 if len(commands.keys()) > 0: if commands[0]["type"] == 0x0: end = True elif command_byte == 0x57 or command_byte == 0x58: #end completely end = True offset += 1 #go past this 0x50 elif command_byte == 0x1: #01 = text from RAM. [01][2-byte pointer] size = 3 #total size, including the command byte pointer_byte1 = ord(extract_maps.rom[offset+1]) pointer_byte2 = ord(extract_maps.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 = extract_maps.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(extract_maps.rom[offset])) + " ... we are at command number: " + str(command_counter) + " near " + hex(offset) + " on map_id=" + str(map_id) + " for text_id=" + str(text_id) + " and txfar(recursion)=" + str(txfar) elif command_byte == 0x7: #07 = shift texts 1 row above (2nd line becomes 1st line); address for next text = 2nd line. [07] size = 1 command = {"type": command_byte, "start_address": offset, "end_address": offset, } offset += 1 elif command_byte == 0x3: #03 = set new address in RAM for text. [03][2-byte RAM address] size = 3 command = {"type": command_byte, "start_address": offset, "end_address": offset+2} offset += size elif command_byte == 0x4: #draw box #04 = draw box. [04][2-Byte pointer][height Y][width X] size = 5 #including the command command = { "type": command_byte, "start_address": offset, "end_address": offset + size, "pointer_bytes": [ord(extract_maps.rom[offset+1]), ord(extract_maps.rom[offset+2])], "y": ord(extract_maps.rom[offset+3]), "x": ord(extract_maps.rom[offset+4]), } offset += size + 1 elif command_byte == 0x5: #05 = write text starting at 2nd line of text-box. [05][text][ending command] #read until $57, $50 or $58 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 command = {"type": command_byte, "start_address": offset, "end_address": end_address, "size": jump, "lines": process_00_subcommands(offset+1, end_address), } offset = end_address + 1 elif command_byte == 0x6: #06 = wait for keypress A or B (put blinking arrow in textbox). [06] command = {"type": command_byte, "start_address": offset, "end_address": offset} offset += 1 elif command_byte == 0x7: #07 = shift texts 1 row above (2nd line becomes 1st line); address for next text = 2nd line. [07] command = {"type": command_byte, "start_address": offset, "end_address": offset} offset += 1 elif command_byte == 0x8: #08 = asm until whenever command = {"type": command_byte, "start_address": offset, "end_address": offset} offset += 1 end = True elif command_byte == 0x9: #09 = write hex-to-dec number from RAM to textbox [09][2-byte RAM address][byte bbbbcccc] # bbbb = how many bytes to read (read number is big-endian) # cccc = how many digits display (decimal) #(note: max of decimal digits is 7,i.e. max number correctly displayable is 9999999) ram_address_byte1 = ord(extract_maps.rom[offset+1]) ram_address_byte2 = ord(extract_maps.rom[offset+2]) read_byte = ord(extract_maps.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 elif command_byte == 0xB: #0B = sound_86 (Hiro obtains ITEM)[same as 0F] command = {"type": command_byte, "start_address": offset, "end_address": offset} offset += 1 elif command_byte == 0xE: #0E = sound_91 (learnt something) command = {"type": command_byte, "start_address": offset, "end_address": offset} offset += 1 elif command_byte == 0xF: #0F = sound_86 (given rare candy)[same as 0B] command = {"type": command_byte, "start_address": offset, "end_address": offset} offset += 1 elif command_byte == 0x10: #10 = sound_89 (PKMN successfully caught) command = {"type": command_byte, "start_address": offset, "end_address": offset} offset += 1 elif command_byte == 0x11: #11 = sound_94 (Hiro gives OAK the PARCEL) command = {"type": command_byte, "start_address": offset, "end_address": offset} offset += 1 elif command_byte == 0x12: #12 = sound_9A (successfully caught) command = {"type": command_byte, "start_address": offset, "end_address": offset} offset += 1 elif command_byte == 0x13: #13 = sound_98 (song heard when "new data will be added for..") command = {"type": command_byte, "start_address": offset, "end_address": offset} offset += 1 elif command_byte == 0x14: #14 = MonCry (Nidorina) command = {"type": command_byte, "start_address": offset, "end_address": offset} offset += 1 elif command_byte == 0x15: #14 = MonCry (Pidgeot) command = {"type": command_byte, "start_address": offset, "end_address": offset} offset += 1 elif command_byte == 0x16: #14 = MonCry (Dewgong) command = {"type": command_byte, "start_address": offset, "end_address": offset} offset += 1 elif command_byte == 0x19: #19 = play a 'bump' noise command = {"type": command_byte, "start_address": offset, "end_address": offset} offset += 1 elif command_byte == 0x1F: #1F = play some pokemon's roar, don't know which.. command = {"type": command_byte, "start_address": offset, "end_address": offset} offset += 1 elif command_byte == 0x20: #20 = oddish roar? command = {"type": command_byte, "start_address": offset, "end_address": offset} offset += 1 elif command_byte == 0x3F: #3F = some other roar command = {"type": command_byte, "start_address": offset, "end_address": offset} offset += 1 elif command_byte == 0x9D: #9D = a roar or some other sound, four times in quick succession command = {"type": command_byte, "start_address": offset, "end_address": offset} offset += 1 elif command_byte == 0x76: #76 = another roar command = {"type": command_byte, "start_address": offset, "end_address": offset} offset += 1 elif command_byte == 0xCA: #CA = stop music, start this other song that i can't name command = {"type": command_byte, "start_address": offset, "end_address": offset} offset += 1 elif command_byte == 0xF6: #F6 = play a 'blurp blurp' noise.. like something is increasing command = {"type": command_byte, "start_address": offset, "end_address": offset} offset += 1 elif command_byte == 0xFA: #FA = change music to champion song? command = {"type": command_byte, "start_address": offset, "end_address": offset} offset += 1 elif command_byte == 0xFE: #FE = another roar, kinda glitchy? command = {"type": command_byte, "start_address": offset, "end_address": offset} offset += 1 elif command_byte == 0xFF: #FF = change music to a specific song that i don't know the name of command = {"type": command_byte, "start_address": offset, "end_address": offset} offset += 1 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(extract_maps.rom[offset])) + " on map_id=" + str(map_id) + " text_id=" + str(text_id) #end at the first unknown command end = True add_command_byte_to_totals(command_byte) commands[command_counter] = command command_counter += 1 total_text_commands += len(commands) return commands
def scan_for_map_scripts_pointer(): for map_id in extract_maps.map_headers.keys( ): #skip id=0 (Pallet Town) because the naming conventions are wonky map2 = extract_maps.map_headers[map_id] if map_id in extract_maps.bad_maps or map_id in [0, 39, 37, 38]: continue #skip script_pointer = int(map2["script_pointer"], 16) main_asm_output, offset, last_hl_address, last_a_address, used_3d97 = output_bank_opcodes( script_pointer) hl_pointer = "None" first_script_text = "" if last_hl_address != None and last_hl_address != "None" and used_3d97 == True: if last_hl_address > 0x3fff: hl_pointer = extract_maps.calculate_pointer( last_hl_address, int(map2["bank"], 16)) else: hl_pointer = last_hl_address byte1 = ord(extract_maps.rom[hl_pointer]) byte2 = ord(extract_maps.rom[hl_pointer + 1]) address = byte1 + (byte2 << 8) if address > 0x3fff: first_script_pointer = extract_maps.calculate_pointer( address, int(map2["bank"], 16)) else: first_script_pointer = address #for later output first_script_text = " first_script=" + hex(first_script_pointer) #go ahead and insert this script pointer insert_asm(first_script_pointer, map_name_cleaner(map2["name"], None)[:-2] + "Script0") #reset everything #analyze_incbins.reset_incbins() asm = None incbin_lines = [] processed_incbins = {} analyze_incbins.asm = None analyze_incbins.incbin_lines = [] analyze_incbins.processed_incbins = {} #reload load_asm() isolate_incbins() process_incbins() a_numbers = [0] last_a_id = 0 script_pointers = [hex(first_script_pointer)] latest_script_pointer = first_script_pointer while last_a_id == (max(a_numbers)) or last_a_id == 0: asm_output, offset, last_hl_address2, last_a_id, byte1, byte2, address = None, None, None, None, None, None, None asm_output, offset, last_hl_address2, last_a_id, used_3d97_2 = output_bank_opcodes( latest_script_pointer) if last_a_id == (max(a_numbers) + 1): a_numbers.append(last_a_id) else: break byte1 = ord(extract_maps.rom[hl_pointer + (2 * last_a_id)]) byte2 = ord(extract_maps.rom[hl_pointer + (2 * last_a_id) + 1]) address2 = byte1 + (byte2 << 8) if address2 > 0x3fff: latest_script_pointer = extract_maps.calculate_pointer( address2, int(map2["bank"], 16)) else: latest_script_pointer = address2 script_pointers.append(hex(latest_script_pointer)) #print "latest script pointer (part 1): " + hex(address2) #print "latest script pointer: " + hex(latest_script_pointer) #go ahead and insert the asm for this script result = insert_asm( latest_script_pointer, map_name_cleaner(map2["name"], None)[:-2] + "Script" + str(len(script_pointers) - 1)) if result: #reset everything #analyze_incbins.reset_incbins() asm = None incbin_lines = [] processed_incbins = {} analyze_incbins.asm = None analyze_incbins.incbin_lines = [] analyze_incbins.processed_incbins = {} #reload load_asm() isolate_incbins() process_incbins() print "map_id=" + str(map_id) + " scripts are: " + str( script_pointers) if last_hl_address == None: last_hl_address = "None" else: last_hl_address = hex(last_hl_address) if hl_pointer != None and hl_pointer != "None": hl_pointer = hex(hl_pointer) print "map_id=" + str( map_id) + " " + map2["name"] + " script_pointer=" + hex( script_pointer ) + " script_pointers=" + hl_pointer + first_script_text print main_asm_output print "\n\n" #insert asm for the main script result = insert_asm( script_pointer, map_name_cleaner(map2["name"], None)[:-2] + "Script") if result: #reset everything #analyze_incbins.reset_incbins() asm = None incbin_lines = [] processed_incbins = {} analyze_incbins.asm = None analyze_incbins.incbin_lines = [] analyze_incbins.processed_incbins = {} #reload load_asm() isolate_incbins() process_incbins() #insert script pointer list asm if there's anything of value if hl_pointer != None and hl_pointer != "None" and used_3d97 == True: start_address = int(hl_pointer, 16) #where to insert this list total_size = len(a_numbers) * 2 script_label = map_name_cleaner(map2["name"], None)[:-2] + "Script" scripts_label = script_label + "s" script_asm = scripts_label + ": ; " + hex(start_address) + "\n" script_asm += spacing + "dw" first = True for id in a_numbers: if first: script_asm += " " first = False else: script_asm += ", " script_asm += script_label + str(id) script_asm += "\n" #extra newline? result = insert_asm(start_address, scripts_label, text_asm=script_asm, end_address=start_address + total_size) if result: #reset everything #analyze_incbins.reset_incbins() asm = None incbin_lines = [] processed_incbins = {} analyze_incbins.asm = None analyze_incbins.incbin_lines = [] analyze_incbins.processed_incbins = {} #reload load_asm() isolate_incbins() process_incbins() else: print "trouble inserting map script pointer list" print script_asm sys.exit(0)
def pretty_print_trainer_header(address, label=None): """make pretty text for a trainer header""" global rom output = "" bank_id = 0 if address > 0x4000: bank_id = address / 0x4000 #convert address to an integer if necessary if type(address) == str: if "$" in address: address = address.replace("$", "0x") address = int(address, 16) #label this section of asm if label == None: output += "TrainerHeader_" + hex(address)[2:] + ": ; 0x" + hex(address)[2:] + "\n" else: output += label + ": ; 0x" + hex(address)[2:] + "\n" #flag's bit output += spacing + "db $" + hex(ord(rom[address]))[2:] + " ; flag's bit\n" #trainer's view range view_range = ord(rom[address+1]) >> 4 output += spacing + "db ($" + hex(view_range)[2:] + " << 4) ; trainer's view range\n" #flag's byte pointer_byte1 = ord(rom[address+2]) pointer_byte2 = ord(rom[address+3]) partial_pointer = (pointer_byte1 + (pointer_byte2 << 8)) partial_pointer = "$%.2x" % partial_pointer output += spacing + "dw " + partial_pointer + " ; flag's byte\n" #TextBeforeBattle pointer_byte1 = ord(rom[address+4]) pointer_byte2 = ord(rom[address+5]) partial_pointer = (pointer_byte1 + (pointer_byte2 << 8)) label = find_label(partial_pointer, bank_id) if label == None: print "label not found for (TextBeforeBattle) " + hex(calculate_pointer(partial_pointer, bank_id)) print "" label = "$" + hex(partial_pointer)[2:] #sys.exit(0) output += spacing + "dw " + label + " ; " + hex(partial_pointer) + " TextBeforeBattle\n" #TextAfterBattle pointer_byte1 = ord(rom[address+6]) pointer_byte2 = ord(rom[address+7]) partial_pointer = (pointer_byte1 + (pointer_byte2 << 8)) label = find_label(partial_pointer, bank_id) if label == None: print "label not found for (TextAfterBattle) " + hex(calculate_pointer(partial_pointer, bank_id)) print "" label = "$" + hex(partial_pointer)[2:] #sys.exit(0) output += spacing + "dw " + label + " ; " + hex(partial_pointer) + " TextAfterBattle\n" #TextEndBattle pointer_byte1 = ord(rom[address+8]) pointer_byte2 = ord(rom[address+9]) partial_pointer = (pointer_byte1 + (pointer_byte2 << 8)) label = find_label(partial_pointer, bank_id) if label == None: print "label not found for (TextEndBattle) " + hex(calculate_pointer(partial_pointer, bank_id)) print "" label = "$" + hex(partial_pointer)[2:] #sys.exit(0) output += spacing + "dw " + label + " ; " + hex(partial_pointer) + " TextEndBattle\n" #TextEndBattle pointer_byte1 = ord(rom[address+10]) pointer_byte2 = ord(rom[address+11]) partial_pointer = (pointer_byte1 + (pointer_byte2 << 8)) label = find_label(partial_pointer, bank_id) if label == None: print "label not found for (TextEndBattle) " + hex(calculate_pointer(partial_pointer, bank_id)) print "" label = "$" + hex(partial_pointer)[2:] #sys.exit(0) output += spacing + "dw " + label + " ; " + hex(partial_pointer) + " TextEndBattle\n" output += "; " + hex(address+12) + "\n" return output
def get_labels_between(start_line_id, end_line_id, bank_id): labels = [] #label = { # "line_number": 15, # "bank_id": 32, # "label": "PalletTownText1", # "local_pointer": "$5315", # "address": 0x75315, #} global label_errors errors = "" current_line_offset = 0 sublines = asm[start_line_id : end_line_id + 1] for line in sublines: label = {} line_id = start_line_id + current_line_offset address = None local_pointer = None if ": ; 0x" in line: temp = line.split(": ; 0x")[1] # just read until the comma appears if "," in line: temp = temp.split(",")[0] if not " " in temp: address = int("0x" + temp, 16) else: temp2 = temp.split(" ")[0] address = int("0x" + temp2, 16) elif ": ; " in line: partial = line.split(": ; ")[1] if ": ; $" in line: temp = line.split(": ; $")[1] if " " in temp: temp = temp.split(" ")[0] local_pointer = "$" + temp elif " " in partial: if " to " in partial: temp = partial.split(" to ")[0] if "0x" in temp: address = int(temp, 16) elif len(temp) == 4: local_pointer = "$" + temp else: errors += "found \" to \" in partial on line " + str(line_id) + ", but don't know what to do (debug14)" + "\n" errors += "line is: " + line + "\n" continue elif partial[4] == " " and partial[5] == "(": temp = partial[0:4] address = int(temp, 16) elif partial[5] == " " and partial[6] == "(": temp = partial[0:5] address = int(temp, 16) elif len(partial[4]) == 4 or partial[4] == " ": #then it's probably a local pointer temp = partial[0:4] local_pointer = "$" + temp else: errors += "found \": ; \" and another \" \" in line " + str(line_id) + ", but don't know what to do (debug15)" + "\n" errors += "line is: " + line + "\n" continue else: if len(partial) > 3 and partial[2] == ":": #14:3BAC temp = partial[2].split(":")[1] if len(temp) == 3 or len(temp) == 4: local_pointer = "$" + temp else: temp = temp.split(" ")[0] local_pointer = "$" + temp elif len(partial) == 4 or (len(partial) == 3 and is_probably_pointer(partial)): local_pointer = "$" + partial else: errors += "found \": ; \" in line " + str(line_id) + ", but don't know what to do (debug16)" + "\n" errors += "line is: " + line + "\n" continue else: #this line doesn't have a label continue if local_pointer != None and not is_probably_pointer(local_pointer.replace("0x", "").replace("$", "")): continue line_label = line.split(": ;")[0] if address == None and local_pointer != None: temp = int(local_pointer.replace("$", "0x"), 16) if temp < 0x4000 or bank_id == 0: address = temp else: address = calculate_pointer(int(local_pointer.replace("$", "0x"), 16), bank_id) elif local_pointer == None and address != None: if address < 0x4000: local_pointer = hex(address).replace("0x", "$") else: local_pointer = hex((address % 0x4000) + 0x4000).replace("0x", "$") print line_label + " is at " + hex(address) label = { "line_number": line_id, "bank_id": bank_id, "label": line_label, "local_pointer": local_pointer, "address": address } labels.append(label) current_line_offset += 1 label_errors += errors return labels
def scan_for_map_scripts_pointer(): for map_id in extract_maps.map_headers.keys(): #skip id=0 (Pallet Town) because the naming conventions are wonky map2 = extract_maps.map_headers[map_id] if map_id in extract_maps.bad_maps or map_id in [0, 39, 37, 38]: continue #skip script_pointer = int(map2["script_pointer"], 16) main_asm_output, offset, last_hl_address, last_a_address, used_3d97 = output_bank_opcodes(script_pointer) hl_pointer = "None" first_script_text = "" if last_hl_address != None and last_hl_address != "None" and used_3d97==True: if last_hl_address > 0x3fff: hl_pointer = extract_maps.calculate_pointer(last_hl_address, int(map2["bank"], 16)) else: hl_pointer = last_hl_address byte1 = ord(extract_maps.rom[hl_pointer]) byte2 = ord(extract_maps.rom[hl_pointer+1]) address = byte1 + (byte2 << 8) if address > 0x3fff: first_script_pointer = extract_maps.calculate_pointer(address, int(map2["bank"], 16)) else: first_script_pointer = address #for later output first_script_text = " first_script=" + hex(first_script_pointer) #go ahead and insert this script pointer insert_asm(first_script_pointer, map_name_cleaner(map2["name"], None)[:-2] + "Script0") #reset everything #analyze_incbins.reset_incbins() asm = None incbin_lines = [] processed_incbins = {} analyze_incbins.asm = None analyze_incbins.incbin_lines = [] analyze_incbins.processed_incbins = {} #reload load_asm() isolate_incbins() process_incbins() a_numbers = [0] last_a_id = 0 script_pointers = [hex(first_script_pointer)] latest_script_pointer = first_script_pointer while last_a_id == (max(a_numbers)) or last_a_id==0: asm_output, offset, last_hl_address2, last_a_id, byte1, byte2, address = None, None, None, None, None, None, None asm_output, offset, last_hl_address2, last_a_id, used_3d97_2 = output_bank_opcodes(latest_script_pointer) if last_a_id == (max(a_numbers) + 1): a_numbers.append(last_a_id) else: break byte1 = ord(extract_maps.rom[hl_pointer + (2*last_a_id)]) byte2 = ord(extract_maps.rom[hl_pointer + (2*last_a_id) + 1]) address2 = byte1 + (byte2 << 8) if address2 > 0x3fff: latest_script_pointer = extract_maps.calculate_pointer(address2, int(map2["bank"], 16)) else: latest_script_pointer = address2 script_pointers.append(hex(latest_script_pointer)) #print "latest script pointer (part 1): " + hex(address2) #print "latest script pointer: " + hex(latest_script_pointer) #go ahead and insert the asm for this script result = insert_asm(latest_script_pointer, map_name_cleaner(map2["name"], None)[:-2] + "Script" + str(len(script_pointers) - 1)) if result: #reset everything #analyze_incbins.reset_incbins() asm = None incbin_lines = [] processed_incbins = {} analyze_incbins.asm = None analyze_incbins.incbin_lines = [] analyze_incbins.processed_incbins = {} #reload load_asm() isolate_incbins() process_incbins() print "map_id=" + str(map_id) + " scripts are: " + str(script_pointers) if last_hl_address == None: last_hl_address = "None" else: last_hl_address = hex(last_hl_address) if hl_pointer != None and hl_pointer != "None": hl_pointer = hex(hl_pointer) print "map_id=" + str(map_id) + " " + map2["name"] + " script_pointer=" + hex(script_pointer) + " script_pointers=" + hl_pointer + first_script_text print main_asm_output print "\n\n" #insert asm for the main script result = insert_asm(script_pointer, map_name_cleaner(map2["name"], None)[:-2] + "Script") if result: #reset everything #analyze_incbins.reset_incbins() asm = None incbin_lines = [] processed_incbins = {} analyze_incbins.asm = None analyze_incbins.incbin_lines = [] analyze_incbins.processed_incbins = {} #reload load_asm() isolate_incbins() process_incbins() #insert script pointer list asm if there's anything of value if hl_pointer != None and hl_pointer != "None" and used_3d97==True: start_address = int(hl_pointer, 16) #where to insert this list total_size = len(a_numbers) * 2 script_label = map_name_cleaner(map2["name"], None)[:-2] + "Script" scripts_label = script_label + "s" script_asm = scripts_label + ": ; " + hex(start_address) + "\n" script_asm += spacing + "dw" first = True for id in a_numbers: if first: script_asm += " " first = False else: script_asm += ", " script_asm += script_label + str(id) script_asm += "\n" #extra newline? result = insert_asm(start_address, scripts_label, text_asm=script_asm, end_address=start_address + total_size) if result: #reset everything #analyze_incbins.reset_incbins() asm = None incbin_lines = [] processed_incbins = {} analyze_incbins.asm = None analyze_incbins.incbin_lines = [] analyze_incbins.processed_incbins = {} #reload load_asm() isolate_incbins() process_incbins() else: print "trouble inserting map script pointer list" print script_asm sys.exit(0)
def get_labels_between(start_line_id, end_line_id, bank_id): labels = [] #label = { # "line_number": 15, # "bank_id": 32, # "label": "PalletTownText1", # "local_pointer": "$5315", # "address": 0x75315, #} global label_errors errors = "" current_line_offset = 0 sublines = asm[start_line_id:end_line_id + 1] for line in sublines: label = {} line_id = start_line_id + current_line_offset address = None local_pointer = None if ": ; 0x" in line: temp = line.split(": ; 0x")[1] # just read until the comma appears if "," in line: temp = temp.split(",")[0] if not " " in temp: address = int("0x" + temp, 16) else: temp2 = temp.split(" ")[0] address = int("0x" + temp2, 16) elif ": ; " in line: partial = line.split(": ; ")[1] if ": ; $" in line: temp = line.split(": ; $")[1] if " " in temp: temp = temp.split(" ")[0] local_pointer = "$" + temp elif " " in partial: if " to " in partial: temp = partial.split(" to ")[0] if "0x" in temp: address = int(temp, 16) elif len(temp) == 4: local_pointer = "$" + temp else: errors += "found \" to \" in partial on line " + str( line_id ) + ", but don't know what to do (debug14)" + "\n" errors += "line is: " + line + "\n" continue elif partial[4] == " " and partial[5] == "(": temp = partial[0:4] address = int(temp, 16) elif partial[5] == " " and partial[6] == "(": temp = partial[0:5] address = int(temp, 16) elif len(partial[4]) == 4 or partial[ 4] == " ": #then it's probably a local pointer temp = partial[0:4] local_pointer = "$" + temp else: errors += "found \": ; \" and another \" \" in line " + str( line_id ) + ", but don't know what to do (debug15)" + "\n" errors += "line is: " + line + "\n" continue else: if len(partial) > 3 and partial[2] == ":": #14:3BAC temp = partial[2].split(":")[1] if len(temp) == 3 or len(temp) == 4: local_pointer = "$" + temp else: temp = temp.split(" ")[0] local_pointer = "$" + temp elif len(partial) == 4 or (len(partial) == 3 and is_probably_pointer(partial)): local_pointer = "$" + partial else: errors += "found \": ; \" in line " + str( line_id ) + ", but don't know what to do (debug16)" + "\n" errors += "line is: " + line + "\n" continue else: #this line doesn't have a label continue if local_pointer != None and not is_probably_pointer( local_pointer.replace("0x", "").replace("$", "")): continue line_label = line.split(": ;")[0] if address == None and local_pointer != None: temp = int(local_pointer.replace("$", "0x"), 16) if temp < 0x4000 or bank_id == 0: address = temp else: address = calculate_pointer( int(local_pointer.replace("$", "0x"), 16), bank_id) elif local_pointer == None and address != None: if address < 0x4000: local_pointer = hex(address).replace("0x", "$") else: local_pointer = hex((address % 0x4000) + 0x4000).replace( "0x", "$") print line_label + " is at " + hex(address) label = { "line_number": line_id, "bank_id": bank_id, "label": line_label, "local_pointer": local_pointer, "address": address } labels.append(label) current_line_offset += 1 label_errors += errors return labels
def parse_text_script(text_pointer, text_id, map_id, txfar=False): global total_text_commands offset = text_pointer commands = {} command_counter = 0 if extract_maps.rom == None: extract_maps.load_rom() end = False while not end: command = {} command_byte = ord(extract_maps.rom[offset]) print_command_debug_info(command_byte, text_id, text_pointer, map_id) if command_byte == 0: #read until $57, $50 or $58 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 command = { "type": command_byte, "start_address": offset, "end_address": end_address, "size": jump, "lines": process_00_subcommands(offset + 1, end_address), } offset += jump elif command_byte == 0x17: #TX_FAR [pointer][bank] pointer_byte1 = ord(extract_maps.rom[offset + 1]) pointer_byte2 = ord(extract_maps.rom[offset + 2]) pointer_bank = ord(extract_maps.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( extract_maps.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 add_command_byte_to_totals(command_byte) elif command_byte == 0x50: #only end if we started with $0 if len(commands.keys()) > 0: if commands[0]["type"] == 0x0: end = True elif command_byte == 0x57 or command_byte == 0x58: #end completely end = True offset += 1 #go past this 0x50 elif command_byte == 0x1: #01 = text from RAM. [01][2-byte pointer] size = 3 #total size, including the command byte pointer_byte1 = ord(extract_maps.rom[offset + 1]) pointer_byte2 = ord(extract_maps.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 = extract_maps.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(extract_maps.rom[offset]) ) + " ... we are at command number: " + str( command_counter ) + " near " + hex(offset) + " on map_id=" + str( map_id) + " for text_id=" + str( text_id) + " and txfar(recursion)=" + str(txfar) elif command_byte == 0x7: #07 = shift texts 1 row above (2nd line becomes 1st line); address for next text = 2nd line. [07] size = 1 command = { "type": command_byte, "start_address": offset, "end_address": offset, } offset += 1 elif command_byte == 0x3: #03 = set new address in RAM for text. [03][2-byte RAM address] size = 3 command = { "type": command_byte, "start_address": offset, "end_address": offset + 2 } offset += size elif command_byte == 0x4: #draw box #04 = draw box. [04][2-Byte pointer][height Y][width X] size = 5 #including the command command = { "type": command_byte, "start_address": offset, "end_address": offset + size, "pointer_bytes": [ ord(extract_maps.rom[offset + 1]), ord(extract_maps.rom[offset + 2]) ], "y": ord(extract_maps.rom[offset + 3]), "x": ord(extract_maps.rom[offset + 4]), } offset += size + 1 elif command_byte == 0x5: #05 = write text starting at 2nd line of text-box. [05][text][ending command] #read until $57, $50 or $58 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 command = { "type": command_byte, "start_address": offset, "end_address": end_address, "size": jump, "lines": process_00_subcommands(offset + 1, end_address), } offset = end_address + 1 elif command_byte == 0x6: #06 = wait for keypress A or B (put blinking arrow in textbox). [06] command = { "type": command_byte, "start_address": offset, "end_address": offset } offset += 1 elif command_byte == 0x7: #07 = shift texts 1 row above (2nd line becomes 1st line); address for next text = 2nd line. [07] command = { "type": command_byte, "start_address": offset, "end_address": offset } offset += 1 elif command_byte == 0x8: #08 = asm until whenever command = { "type": command_byte, "start_address": offset, "end_address": offset } offset += 1 end = True elif command_byte == 0x9: #09 = write hex-to-dec number from RAM to textbox [09][2-byte RAM address][byte bbbbcccc] # bbbb = how many bytes to read (read number is big-endian) # cccc = how many digits display (decimal) #(note: max of decimal digits is 7,i.e. max number correctly displayable is 9999999) ram_address_byte1 = ord(extract_maps.rom[offset + 1]) ram_address_byte2 = ord(extract_maps.rom[offset + 2]) read_byte = ord(extract_maps.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 elif command_byte == 0xB: #0B = sound_86 (Hiro obtains ITEM)[same as 0F] command = { "type": command_byte, "start_address": offset, "end_address": offset } offset += 1 elif command_byte == 0xE: #0E = sound_91 (learnt something) command = { "type": command_byte, "start_address": offset, "end_address": offset } offset += 1 elif command_byte == 0xF: #0F = sound_86 (given rare candy)[same as 0B] command = { "type": command_byte, "start_address": offset, "end_address": offset } offset += 1 elif command_byte == 0x10: #10 = sound_89 (PKMN successfully caught) command = { "type": command_byte, "start_address": offset, "end_address": offset } offset += 1 elif command_byte == 0x11: #11 = sound_94 (Hiro gives OAK the PARCEL) command = { "type": command_byte, "start_address": offset, "end_address": offset } offset += 1 elif command_byte == 0x12: #12 = sound_9A (successfully caught) command = { "type": command_byte, "start_address": offset, "end_address": offset } offset += 1 elif command_byte == 0x13: #13 = sound_98 (song heard when "new data will be added for..") command = { "type": command_byte, "start_address": offset, "end_address": offset } offset += 1 elif command_byte == 0x14: #14 = MonCry (Nidorina) command = { "type": command_byte, "start_address": offset, "end_address": offset } offset += 1 elif command_byte == 0x15: #14 = MonCry (Pidgeot) command = { "type": command_byte, "start_address": offset, "end_address": offset } offset += 1 elif command_byte == 0x16: #14 = MonCry (Dewgong) command = { "type": command_byte, "start_address": offset, "end_address": offset } offset += 1 elif command_byte == 0x19: #19 = play a 'bump' noise command = { "type": command_byte, "start_address": offset, "end_address": offset } offset += 1 elif command_byte == 0x1F: #1F = play some pokemon's roar, don't know which.. command = { "type": command_byte, "start_address": offset, "end_address": offset } offset += 1 elif command_byte == 0x20: #20 = oddish roar? command = { "type": command_byte, "start_address": offset, "end_address": offset } offset += 1 elif command_byte == 0x3F: #3F = some other roar command = { "type": command_byte, "start_address": offset, "end_address": offset } offset += 1 elif command_byte == 0x9D: #9D = a roar or some other sound, four times in quick succession command = { "type": command_byte, "start_address": offset, "end_address": offset } offset += 1 elif command_byte == 0x76: #76 = another roar command = { "type": command_byte, "start_address": offset, "end_address": offset } offset += 1 elif command_byte == 0xCA: #CA = stop music, start this other song that i can't name command = { "type": command_byte, "start_address": offset, "end_address": offset } offset += 1 elif command_byte == 0xF6: #F6 = play a 'blurp blurp' noise.. like something is increasing command = { "type": command_byte, "start_address": offset, "end_address": offset } offset += 1 elif command_byte == 0xFA: #FA = change music to champion song? command = { "type": command_byte, "start_address": offset, "end_address": offset } offset += 1 elif command_byte == 0xFE: #FE = another roar, kinda glitchy? command = { "type": command_byte, "start_address": offset, "end_address": offset } offset += 1 elif command_byte == 0xFF: #FF = change music to a specific song that i don't know the name of command = { "type": command_byte, "start_address": offset, "end_address": offset } offset += 1 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(extract_maps.rom[offset])) + " on map_id=" + str( map_id) + " text_id=" + str(text_id) #end at the first unknown command end = True add_command_byte_to_totals(command_byte) commands[command_counter] = command command_counter += 1 total_text_commands += len(commands) return commands