def find_undone_texts(): usable_table = {} if analyze_incbins.asm == None: analyze_incbins.load_asm() for map_id in extract_maps.map_headers: #skip bad maps if map_id in extract_maps.bad_maps: continue map2 = extract_maps.map_headers[map_id] name = map_name_cleaner(map2["name"], None)[:-2] + "Text" for text_id in map2["referenced_texts"]: label = name + str(text_id) if len(extract_maps.map_headers[map_id]["texts"][text_id].keys()) == 0: continue if len(extract_maps.map_headers[map_id]["texts"][text_id][0].keys()) == 0: continue try: address = extract_maps.map_headers[map_id]["texts"][text_id][0]["start_address"] except: address = extract_maps.map_headers[map_id]["texts"][text_id][1]["start_address"] if not is_label_in_asm(label): print label + " map_id=" + str(map_id) + " text_id=" + str(text_id) + " at " + hex(address) + " byte is: " + hex(ord(extract_maps.rom[address])) if not address in usable_table.keys(): usable_table[address] = 1 else: usable_table[address] += 1 print "\n\n which ones are priority?" sorted_results = sorted(usable_table.iteritems(), key=itemgetter(1), reverse=True) for result in sorted_results: print str(result[1]) + " times: " + hex(result[0])
def texts_label_pretty_printer(map_id): "output a texts label for map if all texts are TX_FARs and in the asm already" #extract_maps.map_headers[map_id]["texts"][text_id][0]["TX_FAR"] #if not all_texts_are_tx_fars(map_id): return None map2 = extract_maps.map_headers[map_id] #pointer to the list of texts texts_list_pointer = int(map2["texts_pointer"], 16) #get the label for this texts list base_label = map_name_cleaner(map2["name"], None)[:-2] label = base_label + "Texts" #make up a label for each text text_labels = [] text_id = 1 for text in map2["texts"].keys(): text_label = base_label + "Text" + str(text_id) text_labels.append(text_label) text_id += 1 output = label + ": ; " + hex(texts_list_pointer) output += "\n" output += spacing + "dw " first = True for labela in text_labels: if not first: output += ", " + labela else: output += labela first = False return output
def get_map_size_constants(do_sed=False): output = "" sed_lines = "" for map_id in extract_maps.map_headers.keys(): if map_id in extract_maps.bad_maps: continue #skip map2 = extract_maps.map_headers[map_id] base_name = map_name_cleaner(map2["name"], None)[:-2] constant_name = map_constants[map_id] height = int(map2["y"], 16) width = int(map2["x"], 16) output += "; " + base_name + "_h map_id=" + str(map_id) + "\n" output += constant_name + "_HEIGHT EQU $%.2x\n" % (height) output += constant_name + "_WIDTH EQU $%.2x\n" % (width) output += "\n" sed_lines += "sed -i 's/" + base_name + "Height/" + constant_name + "_HEIGHT" + "/g' main.asm" + "\n" sed_lines += "sed -i 's/" + base_name + "Width/" + constant_name + "_WIDTH" + "/g' main.asm" + "\n" if do_sed: return sed_lines else: return output
def extract_map_block_data(map_id, savefile=False): map = extract_maps.map_headers[map_id] if map["name"] == "FREEZE": return # skip this one blocksdata_pointer = int(map["map_pointer"], 16) y = int(map["y"], 16) x = int(map["x"], 16) size = x * y # fetch the data from the rom blocksdata = extract_maps.rom[blocksdata_pointer : blocksdata_pointer + size] # clean up the filename and label (for pokered.asm) cleaned_name = map_name_cleaner(map["name"], None) label_text = cleaned_name.replace("_h", "Blocks") filename = cleaned_name.replace("_h", "").lower() full_filepath = "maps/" + filename + ".blk" if savefile: print "Saving ../maps/" + filename + ".blk for map id=" + str(map_id) fh = open("../maps/" + filename + ".blk", "w") fh.write(blocksdata) fh.close()
def current_map_position_formula(map_id, connection_id): map1_id = map_id map1 = extract_maps.map_headers[map_id] connections = map1["connections"] connection = connections[connection_id] map1_height = int(map1["y"], 16) map1_width = int(map1["x"], 16) map1_name = map1["name"] map1_name = map_name_cleaner(map1_name, None)[:-2] direction = connection["direction"] current_map_location = int(connection["current_map_tile_pointer"], 16) map2_id = connection["map_id"] map2 = extract_maps.map_headers[map2_id] map2_name = map2["name"] map2_name = map_name_cleaner(map2_name, None)[:-2] map2_height = int(map2["y"], 16) map2_width = int(map2["x"], 16) y_mov = None if direction == "WEST": y_mov = ((current_map_location - 0xC6E8) / (map1_width + 6)) - 3 elif direction == "EAST": y_mov = ((current_map_location - 0xC6E5) / (map1_width + 6)) - 4 x_mov = None if direction == "NORTH": x_mov = current_map_location - 0xC6EB elif direction == "SOUTH": x_mov = current_map_location - 0xC6EB - ((map1_height + 3) * (map1_width + 6)) formula = "" if direction == "NORTH": formula = "$C6EB + " + str(x_mov) elif direction == "SOUTH": formula = "$C6EB + (" + map1_name + "Height + 3) * (" + map1_name + "Width + 6) + " + str(x_mov) elif direction == "WEST": formula = "$C6E8 + (" + map1_name + "Width + 6) * (" + str(y_mov) + " + 3)" elif direction == "EAST": formula = "$C6E5 + (" + map1_name + "Width + 6) * (" + str(y_mov) + " + 4)" return formula
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 insert_08_asm(map_id, text_id, line_id=0): map2 = extract_maps.map_headers[map_id] base_label = map_name_cleaner(map2["name"], None)[:-2] label = base_label + "Text" + str(text_id) start_address = all_texts[map_id][text_id][line_id]["start_address"] (text_asm, end_address) = text_asm_pretty_printer(label, start_address) print "end address is: " + hex(end_address) #find where to insert the assembly line_number = find_incbin_to_replace_for(start_address) if line_number == None: print "skipping text label for a $08 on map_id=" + str(map_id) + " text_id=" + str(text_id) + " because the address is taken" return #also do a name check if 1 <= ("\n".join(analyze_incbins.asm)).count("\n" + label + ":"): print "skipping text label for a $08 on map_id=" + str(map_id) + " text_id=" + str(text_id) + " because the label is already taken (" + label + ":)" return newlines = split_incbin_line_into_three(line_number, start_address, end_address - start_address ) 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] = text_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 result = apply_diff(diff) if result == False: failed_attempts[len(failed_attempts.keys())] = {"map_id": map_id, "text_id": text_id}
def find_undone_texts(): usable_table = {} if analyze_incbins.asm == None: analyze_incbins.load_asm() for map_id in extract_maps.map_headers: #skip bad maps if map_id in extract_maps.bad_maps: continue map2 = extract_maps.map_headers[map_id] name = map_name_cleaner(map2["name"], None)[:-2] + "Text" for text_id in map2["referenced_texts"]: label = name + str(text_id) if len(extract_maps.map_headers[map_id]["texts"] [text_id].keys()) == 0: continue if len(extract_maps.map_headers[map_id]["texts"][text_id] [0].keys()) == 0: continue try: address = extract_maps.map_headers[map_id]["texts"][text_id][ 0]["start_address"] except: address = extract_maps.map_headers[map_id]["texts"][text_id][ 1]["start_address"] if not is_label_in_asm(label): print label + " map_id=" + str(map_id) + " text_id=" + str( text_id) + " at " + hex(address) + " byte is: " + hex( ord(extract_maps.rom[address])) if not address in usable_table.keys(): usable_table[address] = 1 else: usable_table[address] += 1 print "\n\n which ones are priority?" sorted_results = sorted(usable_table.iteritems(), key=itemgetter(1), reverse=True) for result in sorted_results: print str(result[1]) + " times: " + hex(result[0])
def insert_texts_label(map_id): #if not all_texts_are_tx_fars(map_id): return None map2 = extract_maps.map_headers[map_id] base_label = map_name_cleaner(map2["name"], None)[:-2] label = base_label + "Texts" texts_pointer = int(map2["texts_pointer"], 16) insert_asm = texts_label_pretty_printer(map_id) line_number = find_incbin_to_replace_for(texts_pointer) if line_number == None: print "skipping texts label for map_id=" + str(map_id) + " texts_pointer=" + hex(texts_pointer) + " because the address is taken" return #also do a name check if (label + ":") in "\n".join(analyze_incbins.asm): print "skipping texts label for map_id=" + str(map_id) + " texts_pointer=" + hex(texts_pointer) + " because the label is already used" return newlines = split_incbin_line_into_three(line_number, texts_pointer, len(map2["referenced_texts"])*2 ) 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] = insert_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) + " texts_pointer=" + hex(texts_pointer) print diff apply_diff(diff)
def print_connections(map_id, in_connection_id=None, do_output=False): map1 = extract_maps.map_headers[map_id] map1_name = map1["name"] connections = map1["connections"] output = "" if in_connection_id != None: connections2 = {} connections2[in_connection_id] = connections[in_connection_id] connections = connections2 for connection_id in connections: connection = connections[connection_id] direction = connection["direction"] connected_pointer = int(connection["connected_map_tile_pointer"], 16) current_pointer = int(connection["current_map_tile_pointer"], 16) map2_id = connection["map_id"] map2 = extract_maps.map_headers[map2_id] map2_name = map2["name"] map2_cname = map_name_cleaner(map2["name"], None)[:-2] map2_bank = int(map2["bank"], 16) map2_blocks_pointer = offset_to_pointer(int(map2["map_pointer"], 16)) map2_height = int(map2["y"], 16) map2_width = int(map2["x"], 16) output += map1_name + " (id=" + str(map_id) + ") " + direction + " to " + map2_name + "\n" output += "map2 blocks pointer: " + hex(map2_blocks_pointer) + "\n" output += "map2 height: " + str(map2_height) + "\n" output += "map2 width: " + str(map2_width) + "\n" output += "map1 connection pointer: " + hex(connected_pointer) + "\n" shift = 0 #not sure about the calculated shift for NORTH or SOUTH if direction == "NORTH": calculated = map2_blocks_pointer + (map2_height - 3) * map2_width result = connected_pointer - calculated if result != 0: shift = result #seems to always be 2? calculated = map2_blocks_pointer + (map2_height - 3) * map2_width + shift output += "shift: " + str(shift) + "\n" formula = map2_cname + "Blocks + (" + map2_cname + "Height - 3) * " + map2_cname + "Width + " + str(shift) else: formula = map2_cname + "Blocks + (" + map2_cname + "Height - 3) * " + map2_cname + "Width" elif direction == "SOUTH": calculated = map2_blocks_pointer result = connected_pointer - calculated formula = map2_cname + "Blocks" if result != 0: shift = result calculated = map2_blocks_pointer + shift output += "shift: " + str(shift) + "\n" formula += " + " + str(shift) elif direction == "WEST": calculated = map2_blocks_pointer - 3 + (map2_width) result = connected_pointer - calculated formula = map2_cname + "Blocks - 3 + (" + map2_cname + "Width)" if result != 0: shift = result / map2_width shift += 1 calculated = map2_blocks_pointer - 3 + (map2_width * shift) output += "shift: " + str(shift) + "\n" formula = map2_cname + "Blocks - 3 + (" + map2_cname + "Width * " + str(shift) + ")" elif direction == "EAST": calculated = map2_blocks_pointer + (map2_width) result = connected_pointer - calculated output += ".. result is: " + str(result) + "\n" formula = map2_cname + "Blocks + (" + map2_cname + "Width)" if result != 0: shift = result / map2_width shift += 1 calculated = map2_blocks_pointer + (map2_width * shift) output += "shift: " + str(shift) + "\n" formula = map2_cname + "Blocks" + " + (" + map2_cname + "Width * " + str(shift) + ")" output += "formula: " + formula + "\n" result = connected_pointer - calculated output += "result: " + str(result) + "\n" output += "\n\n" if in_connection_id != None: return formula if do_output == True: return output
def replace_values(): global asm_lines #0-15 ok for map_id in [3]: #extract_maps.map_headers.keys(): if map_id in extract_maps.bad_maps: continue #skip if map_id == 12: continue #skip Route 1 map1 = extract_maps.map_headers[map_id] label_name = map_name_cleaner(map1["name"], None) clean_name = label_name[:-2] line_number = find_line_starting_with(label_name) if line_number == False: continue #skip, not found #replace dimensions if necessary if "dimensions" in asm_lines[line_number + 2] and "$" in asm_lines[line_number + 2] and not "\t" in asm_lines[line_number+2]: asm_lines[line_number + 2] = spacing + "db " + clean_name + "Height, " + clean_name + "Width ; dimensions (y, x)" #skip the rest of this if there are no connections if len(map1["connections"]) == 0: continue if not "; connections data" in asm_lines[line_number + 6]: continue connection_offset = line_number + 8 for connection_id in map1["connections"]: connection = map1["connections"][connection_id] direction = connection["direction"] map2_id = connection["map_id"] map2 = extract_maps.map_headers[map2_id] map2_name = map_name_cleaner(map2["name"], None)[:-2] map2_height = int(map2["y"], 16) map2_width = int(map2["x"], 16) movements = get_xy_movement_of_connection_strip(map_id, connection_id) y_mov = movements["y_mov"] x_mov = movements["x_mov"] #replace the first two pointers if " dw " in asm_lines[connection_offset + 1]: formula = print_connections(map_id, in_connection_id=connection_id) formula2 = current_map_position_formula(map_id, connection_id) temp_line = asm_lines[connection_offset + 1] temp_line = spacing + "dw " + formula + " ; connection strip location\n" #connection strip location temp_line += spacing + "dw " + formula2 + " ; current map position" #current map position asm_lines[connection_offset + 1] = temp_line #bigness, width if "bigness, width" in asm_lines[connection_offset + 2]: temp_line = spacing + "db " if int(connection["bigness"],16) == map2_width: temp_line += map2_name + "Width" elif int(connection["bigness"],16) == map2_height: temp_line += map2_name + "Height" else: #dunno wtf to do temp_line += "$" + hex(int(connection["bigness"],16))[2:] #if direction in ["NORTH", "SOUTH"]: # temp_line += map2_name + "Width" #elif direction in ["WEST", "EAST"]: # temp_line += map2_name + "Height" temp_line += ", " + map2_name + "Width" temp_line += " ; bigness, width" asm_lines[connection_offset + 2] = temp_line #alignments (y, x) if "alignments (y, x)" in asm_lines[connection_offset + 3]: temp_line = spacing + "db " if direction == "NORTH": temp_line += "(" + map2_name + "Height * 2) - 1" elif direction == "SOUTH": temp_line += "0" elif direction in ["WEST", "EAST"]: #TODO: this might be y_mov/4 ?? temp_line += "(" + str(y_mov) + " * -2)" temp_line += ", " #Relative X-Position of player after entering connected map. if direction in ["NORTH", "SOUTH"]: temp_line += "(" + str(x_mov) + " * -2)" elif direction == "WEST": temp_line += "(" + map2_name + "Width * 2) - 1" elif direction == "EAST": temp_line += "0" temp_line += " ; alignments (y, x)" asm_lines[connection_offset + 3] = temp_line #window if "; window" in asm_lines[connection_offset + 4]: temp_line = spacing + "dw " if direction == "NORTH": temp_line += "$C6E9 + " + map2_name + "Height * (" + map2_name + "Width + 6)" elif direction in ["SOUTH", "EAST"]: temp_line += "$C6EF + " + map2_name + "Width" elif direction == "WEST": temp_line += "$C6EE + 2 * " + map2_name + "Width" temp_line += " ; window" asm_lines[connection_offset + 4] = temp_line #jump to the next connection connection_offset += 6
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 make_labels(name): cleaned_name = map_name_cleaner(name, None) label_text = cleaned_name.replace("_h", "Blocks") filename = cleaned_name.replace("_h", "").lower() full_filepath = "maps/" + filename + ".blk" return cleaned_name, label_text, filename, full_filepath