Exemple #1
0
    def write(self, rom: Rom) -> Rom:
        # Since there's a LUT and the data that it points to, create two output streams.
        # This should work because both are continuous.
        data_lut_stream = OutputStream()
        shop_inventory = OutputStream()

        next_shop_addr = self.shop_data_pointers[0].pointer
        start_size = 0
        for index in range(51):

            new_shop_length = self.shop_inventories[index].write(
                shop_inventory)
            sdp = self.shop_data_pointers[index]
            sdp.contents = (
                (sdp.shop_graphic << 4) & 0xf0) | (new_shop_length & 0x0f)
            sdp.pointer = next_shop_addr
            sdp.write(data_lut_stream)

            # Because the size of the data varies by shop, we have to keep track of how
            # large the output buffer was and move the pointer up by the difference.
            next_shop_addr += (shop_inventory.size() - start_size)
            start_size = shop_inventory.size()

        # Make a dictionary for the two parts so we only have to write the new Rom once.
        patches = {
            0x1E070C:
            data_lut_stream.get_buffer(),
            Rom.pointer_to_offset(self.shop_data_pointers[0].pointer):
            shop_inventory.get_buffer()
        }
        return rom.apply_patches(patches)
Exemple #2
0
def add_credits(rom: Rom) -> Rom:
    credits_lut = rom.get_lut(0x1D871C, 128)
    base_addr = credits_lut[0]

    new_lut = OutputStream()
    data_stream = OutputStream()

    for index, line in enumerate(CREDITS_TEXT.splitlines()[1:]):
        line = line.strip()
        if len(line) > 0:
            encoded = TextBlock.encode_text(line)

            new_lut.put_u32(base_addr + data_stream.size())
            data_stream.put_bytes(encoded)
        else:
            new_lut.put_u32(0x0)

    # And EOF marker
    new_lut.put_u32(0xffffffff)

    # Change the duration so it doesn't take so long to scroll
    duration = OutputStream()
    duration.put_u16(60 * 60)

    return rom.apply_patches({
        0x016848:
        duration.get_buffer(),
        0x1D871C:
        new_lut.get_buffer(),
        Rom.pointer_to_offset(base_addr):
        data_stream.get_buffer()
    })
Exemple #3
0
    def _do_placement(self, key_item_locations: tuple):
        source_headers = self._prepare_header(key_item_locations)

        patches = {}
        for event_id, source in EVENT_SOURCE_MAP.items():
            event_source = pparse(f"{source_headers}\n\n{source}")

            event_addr = self.events.get_addr(event_id)
            event_space = self.rom.get_event(
                Rom.pointer_to_offset(event_addr)).size()

            # See if the event fits into it's vanilla location.
            event = easm.parse(event_source, event_addr)
            if len(event) > event_space:
                # Didn't fit. Move it to our space.
                event_addr = self.our_events.current_addr()
                self.events.set_addr(event_id, event_addr)

                # We'll write all of our events together at the end
                event = easm.parse(event_source, event_addr)
                self.our_events.put_bytes(event)
            else:
                # Add the event to the vanilla patches.
                patches[Rom.pointer_to_offset(event_addr)] = event

        self._update_npcs(key_item_locations)
        self._unite_mystic_key_doors()
        self._better_earth_plate()
        self._rewrite_give_texts()
        self._save_chests()

        # Append our new (relocated) events in the patch data.
        patches[0x223F4C] = self.our_events.get_buffer()

        # And then get all the patch data for the LUTs
        for offset, patch in self.events.get_patches().items():
            patches[offset] = patch
        self.rom = self.rom.apply_patches(patches)
        self.rom = self.maps.write(self.rom)
Exemple #4
0
    def write(self, rom: Rom) -> Rom:
        patches = {}
        for index, map in enumerate(self._maps):
            # TODO: Figure out what breaks the Caravan.
            if index == 0x73:
                continue

            data = OutputStream()
            map.write(data)

            patches[Rom.pointer_to_offset(
                self._map_lut[index])] = data.get_buffer()
        return rom.apply_patches(patches)
Exemple #5
0
    def __init__(self, rom: Rom):
        self._maps = []
        self.dummy_chests = []

        self._map_lut = rom.get_lut(0x1E4F40, 124)
        for map_id, map_addr in enumerate(self._map_lut):
            map_stream = rom.get_stream(Rom.pointer_to_offset(map_addr),
                                        bytearray.fromhex("ffff"))
            map = MapFeatures(map_id, map_stream)
            self._maps.append(map)

            # Collect the dummy chests together
            self.dummy_chests += map.dummy_chests
Exemple #6
0
    def __init__(self, rom: Rom):
        data_lut_stream = rom.open_bytestream(0x1DFB04, 0x198)
        self.shop_data_pointers = []
        self.shop_inventories = []
        for index in range(51):
            shop = ShopDataPointer(data_lut_stream)
            self.shop_data_pointers.append(shop)

            # This is overkill for vanilla, but is still small. Since code bytes don't count, the
            # value in shop.shop_data_length isn't quite as useful as it could be.
            inventory = ShopInventory(
                rom.open_bytestream(Rom.pointer_to_offset(shop.pointer), 0x20),
                shop.shop_data_length)
            self.shop_inventories.append(inventory)
Exemple #7
0
    def pack(self, rom: Rom) -> Rom:
        text_block = OutputStream()
        text_lut = OutputStream()

        next_addr = self.lut[0]
        text_block_offset = Rom.pointer_to_offset(next_addr)

        for index, data in enumerate(self.strings):
            if data is not None:
                text_lut.put_u32(next_addr)
                text_block.put_bytes(data)
                next_addr += len(data)
            else:
                text_lut.put_u32(self.lut[0])

        patches = {
            self.lut_offset: text_lut.get_buffer(),
            text_block_offset: text_block.get_buffer()
        }
        return rom.apply_patches(patches)
Exemple #8
0
 def __init__(self, rom: Rom, lut_offset: int, count: int):
     self.lut_offset = lut_offset
     self.lut = list(rom.get_lut(lut_offset, count))
     self.strings = []
     for addr in self.lut:
         self.strings.append(rom.get_string(Rom.pointer_to_offset(addr)))
Exemple #9
0
 def get_map_offset(self, map_id: int) -> int:
     return Rom.pointer_to_offset(self._map_lut[map_id])