예제 #1
0
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
예제 #3
0
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)
예제 #4
0
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
예제 #5
0
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
예제 #8
0
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
예제 #11
0
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)
예제 #15
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
예제 #16
0
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