示例#1
0
    def get_patch(self):
        """

        Returns:
            randomizer.logic.patch.Patch: Patch data

        """
        patch = Patch()

        # Add boss data.
        data = bytearray()
        data += utils.ByteField(0x4a).as_bytes()
        data += utils.ByteField(self.pack.index).as_bytes()
        data += utils.ByteField(0x00).as_bytes()

        # If boss formation requires a specific battlefield, use that.  Otherwise use the location battlefield.
        if self.formation.required_battlefield is not None:
            data += utils.ByteField(
                self.formation.required_battlefield).as_bytes()
        else:
            data += utils.ByteField(self.battlefield).as_bytes()

        # Check for list of addresses if spot has multiple addresses that need to be set.
        if isinstance(self.battle_address, (list, tuple)):
            addrs = self.battle_address
        else:
            addrs = [self.battle_address]

        for addr in addrs:
            patch.add_data(addr, data)

        return patch
示例#2
0
    def finalize(self):
        # Return a patch next time...
        acc = []
        credit_start = 0x3FDBB0
        credit_len = 3380
        string_table_start = 0x3FE8E4
        string_table_size = len(self.strings) * 2
        assert len(self.acc) <= credit_len
        # Fill the unused section of credits script with 0.
        # This is very important.
        self.acc += (3380 - len(self.acc)) * [0]

        free_list = {
            0x3f9c40: 952,
            credit_start + len(self.acc): credit_len - len(self.acc),
            string_table_start + string_table_size: 2080 - string_table_size
        }

        patch = Patch()
        patch.add_data(credit_start, bytearray(self.acc))
        for i in range(len(self.strings)):
            string = inv_str(self.strings[i])
            base = allocate_string(len(string), free_list)
            patch.add_data(base, string)
            patch.add_data(
                string_table_start + i * 2,
                utils.ByteField(base & 0xFFFF, num_bytes=2).as_bytes())

        # Underscore
        patch.add_data(0x3FFDDA, '\x3F\xC0\x7F\x80')
        return patch
示例#3
0
    def get_patch(self):
        """Get patch for this spell.

        :return: Patch data.
        :rtype: randomizer.logic.patch.Patch
        """
        patch = Patch()

        # FP is byte 3, power is byte 6, hit rate is byte 7.  Each spell is 12 bytes.
        base_addr = self.BASE_ADDRESS + (self.index * 12)
        patch.add_data(base_addr + 2, utils.ByteField(self.fp).as_bytes())
        data = utils.ByteField(self.power).as_bytes()
        data += utils.ByteField(self.hit_rate).as_bytes()
        patch.add_data(base_addr + 5, data)

        return patch
示例#4
0
    def as_bytes(self):
        """Return byte representation of this stat growth object for the patch.

        :rtype: bytearray
        """
        data = bytearray()

        # HP is one byte on its own.  Attack/defense stats are 4 bits each combined into a single byte together.
        data += utils.ByteField(self.max_hp).as_bytes()

        physical = self.attack << 4
        physical |= self.defense
        data += utils.ByteField(physical).as_bytes()

        magical = self.magic_attack << 4
        magical |= self.magic_defense
        data += utils.ByteField(magical).as_bytes()

        return data
示例#5
0
    def get_patch(self):
        """

        Returns:
            randomizer.logic.patch.Patch: Patch data

        """
        patch = Patch()

        for addr in self.addresses:
            patch.add_data(addr, utils.ByteField(self.item.index).as_bytes())

        return patch
示例#6
0
    def get_patch(self):
        """
        Returns:
            randomizer.logic.patch.Patch: Patch data
        """
        patch = Patch()

        for dialog_id, pointer, question in self.questions:
            table_entry = DIALOG_POINTER_BASE_ADDRESS + dialog_id * 2
            patch.add_data(table_entry, utils.ByteField((pointer - 8) & 0xFFFF, num_bytes=2).as_bytes())
            if question:
                patch.add_data(pointer, question)

        return patch
示例#7
0
    def get_patch(self):
        """Get patch for exp required for each level up.

        :return: Patch data.
        :rtype: randomizer.logic.patch.Patch
        """
        # Data is 29 blocks (starting at level 2), 2 bytes each block.
        data = bytearray()
        for level in range(2, 31):
            data += utils.ByteField(self.get_xp_for_level(level), num_bytes=2).as_bytes()

        patch = Patch()
        patch.add_data(self.BASE_ADDRESS, data)
        return patch
示例#8
0
    def get_patch(self):
        """

        Returns:
            randomizer.logic.patch.Patch: Patch data

        """
        patch = Patch()

        # Zero for no star, or 255 if this boss has a star.
        val = 0xff if self.has_star else 0x00
        patch.add_data(self.star_address, utils.ByteField(val).as_bytes())

        return patch
示例#9
0
    def get_patch(self):
        """Override patch generation because this is an overworld spot that needs special data.

        Returns:
            randomizer.logic.patch.Patch: Patch data

        """
        patch = Patch()

        # Different values needed for this spot.
        val = 0x9c if self.has_star else 0x1c
        patch.add_data(self.star_address, utils.ByteField(val).as_bytes())

        return patch
示例#10
0
    def get_patch(self):
        """
        Returns:
            randomizer.logic.patch.Patch: Patch data
        """
        patch = Patch()

        # A big assumption here is that the dialogs aren't getting relocated
        # out if the 0x240000 bank.
        for dialog_id, pointer, wish in self.wishes:
            table_entry = DIALOG_POINTER_BASE_ADDRESS + dialog_id * 2
            patch.add_data(table_entry, utils.ByteField((pointer - 4) & 0xFFFF, num_bytes=2).as_bytes())
            patch.add_data(pointer, wish)

        return patch
示例#11
0
    def get_patch(self):
        """

        Returns:
            randomizer.logic.patch.Patch: Patch data

        """
        patch = Patch()

        # Spots should be in 0-indexed bit order already.
        result = 0
        for i, spot in enumerate(self.spots):
            if spot.pressed:
                result |= (1 << i)
        patch.add_data(self.BASE_ADDRESS,
                       utils.ByteField(result, num_bytes=2).as_bytes())

        return patch
示例#12
0
    def get_patch(self):
        """Get patch for this item.

        :return: Patch data.
        :rtype: randomizer.logic.patch.Patch
        """
        patch = Patch()
        base_addr = self.BASE_ADDRESS + (self.index * 4)

        data = bytearray()

        # First byte is attack level + damage type flags in a bitmap.
        attack_flags = [i for i in range(3) if self.attack_level & (1 << i)]
        attack_flags += self.damage_types
        data += utils.BitMapSet(1, attack_flags).as_bytes()

        # Other bytes are hit rate, status effects, and buffs.
        data += utils.ByteField(self.hit_rate).as_bytes()
        data += utils.BitMapSet(1, self.status_effects).as_bytes()
        data += utils.BitMapSet(1, self.buffs).as_bytes()

        patch.add_data(base_addr, data)
        return patch
示例#13
0
    def get_patch(self):
        """Build patch data for this character.

        :return: Patch data for this character.
        :rtype: randomizer.logic.patch.Patch
        """
        patch = Patch()

        # Build character patch data.
        char_data = bytearray()
        char_data += utils.ByteField(self.starting_level).as_bytes()
        char_data += utils.ByteField(self.max_hp, num_bytes=2).as_bytes()  # Current HP
        char_data += utils.ByteField(self.max_hp, num_bytes=2).as_bytes()  # Max HP
        char_data += utils.ByteField(self.speed).as_bytes()
        char_data += utils.ByteField(self.attack).as_bytes()
        char_data += utils.ByteField(self.defense).as_bytes()
        char_data += utils.ByteField(self.magic_attack).as_bytes()
        char_data += utils.ByteField(self.magic_defense).as_bytes()
        char_data += utils.ByteField(self.xp, num_bytes=2).as_bytes()
        # Set starting weapon/armor/accessory as blank for all characters.
        char_data += utils.ByteField(0xff).as_bytes()
        char_data += utils.ByteField(0xff).as_bytes()
        char_data += utils.ByteField(0xff).as_bytes()
        char_data.append(0x00)  # Unused byte
        char_data += utils.BitMapSet(4, [spell.index for spell in self.starting_spells]).as_bytes()

        # Base address plus offset based on character index.
        addr = self.BASE_ADDRESS + (self.index * 20)
        patch.add_data(addr, char_data)

        # Add levelup stat growth and bonuses to the patch data for this character.  Offset is 15 bytes for each stat
        # object, 3 bytes per character.
        for i, stat in enumerate(self.levelup_growths):
            addr = self.BASE_STAT_GROWTH_ADDRESS + (i * 15) + (self.index * 3)
            patch.add_data(addr, stat.as_bytes())

        for i, stat in enumerate(self.levelup_bonuses):
            addr = self.BASE_STAT_BONUS_ADDRESS + (i * 15) + (self.index * 3)
            patch.add_data(addr, stat.as_bytes())

        # Add learned spells data.
        # Data is 29 blocks (starting at level 2), 5 bytes each block (1 byte per character in order)
        base_addr = self.BASE_LEARNED_SPELLS_ADDRESS + self.index
        for level in range(2, 31):
            level_addr = base_addr + ((level - 2) * 5)
            # If we have a spell for this level, add the index.  Otherwise it should be 0xff for no spell learned.
            if self.learned_spells.get(level):
                patch.add_data(level_addr, utils.ByteField(self.learned_spells[level].index).as_bytes())
            else:
                patch.add_data(level_addr, utils.ByteField(0xff).as_bytes())

        if self.palette:
            colourbytes = palette_to_bytes(self.palette.colours)
            poisonbytes = palette_to_bytes(self.palette.poison_colours)
            underwaterbytes = palette_to_bytes(self.palette.underwater_colours)
            for address in self.palette.starting_addresses:
                patch.add_data(address, colourbytes)
            for address in self.palette.poison_addresses:
                patch.add_data(address, poisonbytes)
            for address in self.palette.underwater_addresses:
                patch.add_data(address, underwaterbytes)

            if self.palette.rename_character:
                name = self.palette.name
                clone_name = self.palette.name.upper()
                while len(name) < 10:
                    name += " "
                if len(clone_name) < 8:
                    clone_name = clone_name + " CLONE"
                else:
                    clone_name = clone_name + " 2"
                while len(clone_name) < 13:
                    clone_name += " "
                patch.add_data(self.palette.name_address, name)
                patch.add_data(self.palette.clone_name_address, clone_name)

        return patch