示例#1
0
 def is_applied(self, rom: NintendoDSRom, config: Pmd2Data) -> bool:
     overlay29 = get_binary_from_rom_ppmdu(
         rom, config.binaries['overlay/overlay_0029.bin'])
     overlay31 = get_binary_from_rom_ppmdu(
         rom, config.binaries['overlay/overlay_0031.bin'])
     if config.game_version == GAME_VERSION_EOS:
         if config.game_region == GAME_REGION_US:
             x = 0
             while x < totaloverlay29checks:
                 if overlay29[CHECK_US[x]:CHECK_US[x] + 4] != BYTES_US[x]:
                     return True
                 x += 1
             if overlay31[CHECK_US[6]:CHECK_US[6] + 4] != BYTES_US[6]:
                 return True
             return False
         if config.game_region == GAME_REGION_EU:
             x = 0
             while x < totaloverlay29checks:
                 if overlay29[CHECK_EU[x]:CHECK_EU[x] + 4] != BYTES_EU[x]:
                     return True
                 x += 1
             if overlay31[CHECK_EU[6]:CHECK_EU[6] + 4] != BYTES_EU[6]:
                 return True
             return False
     raise NotImplementedError()
示例#2
0
    def run(self, status: Status):
        if not self.config['improvements']['download_portraits']:
            return status.done()

        status.step("Apply 'ActorAndLevelLoader' patch...")
        patcher = Patcher(self.rom, self.static_data)
        if not patcher.is_applied('ActorAndLevelLoader'):
            patcher.apply('ActorAndLevelLoader')

        overlay13 = get_binary_from_rom_ppmdu(
            self.rom, self.static_data.binaries['overlay/overlay_0013.bin'])
        actor_list: ActorListBin = FileType.SIR0.unwrap_obj(
            FileType.SIR0.deserialize(
                self.rom.getFileByName('BALANCE/actor_list.bin')),
            ActorListBin)
        starters = HardcodedPersonalityTestStarters.get_partner_md_ids(
            overlay13, self.static_data)
        partners = HardcodedPersonalityTestStarters.get_player_md_ids(
            overlay13, self.static_data)
        md = FileType.MD.deserialize(
            self.rom.getFileByName('BALANCE/monster.md'))

        with urllib.request.urlopen(
                "http://sprites.pmdcollab.org/resources/pokemons.json") as url:
            config = json.loads(url.read().decode())

        kao = FileType.KAO.deserialize(
            self.rom.getFileByName('FONT/kaomado.kao'))

        if fun.is_fun_allowed():
            status.step("Downloading portraits...")
            fun.replace_portraits(self.rom, self.static_data)
            return status.done()

        status.step("Downloading portraits for NPCs...")
        for actor in actor_list.list:
            if actor.entid > 0:
                self._import_portrait(kao, config, actor.entid,
                                      md.entries[actor.entid])

        status.step("Downloading portraits for starters...")
        for starter in starters:
            self._import_portrait(kao, config, starter, md.entries[starter])

        status.step("Downloading portraits for partners...")
        for partner in partners:
            self._import_portrait(kao, config, partner, md.entries[partner])

        self.rom.setFileByName('FONT/kaomado.kao', FileType.KAO.serialize(kao))

        def add_rows():
            if Global.main_builder:
                o = Global.main_builder.get_object('store_debug_portraits')
                o.clear()
                for row in self._debugs:
                    o.append(row)

        self.frontend.idle_add(add_rows)

        status.done()
    def run(self, status: Status):
        if not self.config['starters_npcs']['starters']:
            return status.done()
        status.step("Randomizing Partner Starters...")
        overlay13 = get_binary_from_rom_ppmdu(
            self.rom, self.static_data.binaries['overlay/overlay_0013.bin'])
        pokemon_string_data = self.static_data.string_index_data.string_blocks[
            "Pokemon Names"]
        langs = list(get_all_string_files(self.rom, self.static_data))

        orig_partner_ids = HardcodedPersonalityTestStarters.get_partner_md_ids(
            overlay13, self.static_data)
        new_partner_ids = [
            self._random_gender(choice(get_allowed_md_ids(self.config)))
            for _ in range(0, len(orig_partner_ids))
        ]
        HardcodedPersonalityTestStarters.set_partner_md_ids(
            new_partner_ids, overlay13, self.static_data)

        status.step("Randomizing Player Starters...")
        # The player options are put into two-pairs for each nature, first male then female.
        orig_player_ids = HardcodedPersonalityTestStarters.get_player_md_ids(
            overlay13, self.static_data)
        new_player_ids = []
        k = 0  # Index of text for "Will be..."
        for i in range(0, len(orig_player_ids)):
            new_id = choice(get_allowed_md_ids(self.config))
            if k % 3 == 0:
                k += 1
            # todo: refactor, this isn't really efficient.
            for lang, string_file in langs:
                string_file.strings[0x67C + k] = replace_strings(
                    string_file.strings[0x67C + k], {
                        self._get_name(string_file, orig_player_ids[i], pokemon_string_data):
                        self._get_name(string_file, new_id,
                                       pokemon_string_data)
                    })
            if i % 2 == 1 and new_id + NUM_ENTITIES <= 1154:
                new_id += NUM_ENTITIES
            new_player_ids.append(new_id)
            k += 1
        HardcodedPersonalityTestStarters.set_player_md_ids(
            new_player_ids, overlay13, self.static_data)

        status.step("Cloning missing starter portraits...")
        kao = FileType.KAO.deserialize(
            self.rom.getFileByName('FONT/kaomado.kao'))
        for new in new_player_ids + new_partner_ids:
            new_base = new % 600
            clone_missing_portraits(kao, new_base - 1)

        set_binary_in_rom_ppmdu(
            self.rom, self.static_data.binaries['overlay/overlay_0013.bin'],
            overlay13)
        for lang, string_file in langs:
            self.rom.setFileByName(f'MESSAGE/{lang.filename}',
                                   FileType.STR.serialize(string_file))
        self.rom.setFileByName('FONT/kaomado.kao', FileType.KAO.serialize(kao))

        status.done()
 def is_applied(self, rom: NintendoDSRom, config: Pmd2Data) -> bool:
     overlay13 = get_binary_from_rom_ppmdu(
         rom, config.binaries['overlay/overlay_0013.bin'])
     if config.game_version == GAME_VERSION_EOS:
         if config.game_region == GAME_REGION_US or config.game_region == GAME_REGION_EU:
             return overlay13[OFFSET:OFFSET + 4] != ORIGINAL_BYTESEQ
     raise NotImplementedError()
    def run(self, status: Status):
        if not self.config['starters_npcs']['npcs']:
            return status.done()

        status.step("Apply 'ActorAndLevelLoader' patch...")
        patcher = Patcher(self.rom, self.static_data)
        if not patcher.is_applied('ActorAndLevelLoader'):
            patcher.apply('ActorAndLevelLoader')

        status.step("Updating special recruitment table...")

        actor_list: ActorListBin = FileType.SIR0.unwrap_obj(
            FileType.SIR0.deserialize(
                self.rom.getFileByName('BALANCE/actor_list.bin')),
            ActorListBin)

        binary = get_binary_from_rom_ppmdu(
            self.rom, self.static_data.binaries['overlay/overlay_0011.bin'])
        sp_list = HardcodedRecruitmentTables.get_monster_species_list(
            binary, self.static_data)

        for i, actor in enumerate(actor_list.list):
            if i in ACTOR_TO_RECRUIT_MAPPING:
                for bi in ACTOR_TO_RECRUIT_MAPPING[i]:
                    sp_list[bi] = actor.entid

        HardcodedRecruitmentTables.set_monster_species_list(
            sp_list, binary, self.static_data)
        set_binary_in_rom_ppmdu(
            self.rom, self.static_data.binaries['overlay/overlay_0011.bin'],
            binary)

        status.done()
    def __init__(self, config: RandomizerConfig, rom: NintendoDSRom,
                 static_data: Pmd2Data, seed: str):
        super().__init__(config, rom, static_data, seed)

        self.dungeons = HardcodedDungeons.get_dungeon_list(
            get_binary_from_rom_ppmdu(self.rom,
                                      self.static_data.binaries['arm9.bin']),
            self.static_data)
示例#7
0
def create_mapping():
    from ndspy.rom import NintendoDSRom
    rom = NintendoDSRom.fromFile(
        '/home/marco/dev/skytemple/skytemple/skyworkcopy_us_unpatched.nds')
    from skytemple_files.common.util import get_ppmdu_config_for_rom
    static_data = get_ppmdu_config_for_rom(rom)
    from skytemple_files.patch.patches import Patcher
    patcher = Patcher(rom, static_data)
    patcher.apply('ActorAndLevelLoader')

    from skytemple_files.common.types.file_types import FileType
    from skytemple_files.data.md.model import Md
    md: Md = FileType.MD.deserialize(rom.getFileByName('BALANCE/monster.md'))
    from skytemple_files.list.actor.model import ActorListBin
    actor_list: ActorListBin = FileType.SIR0.unwrap_obj(
        FileType.SIR0.deserialize(rom.getFileByName('BALANCE/actor_list.bin')),
        ActorListBin)
    from skytemple_files.hardcoded.fixed_floor import HardcodedFixedFloorTables
    from skytemple_files.common.util import get_binary_from_rom_ppmdu
    boss_list = HardcodedFixedFloorTables.get_monster_spawn_list(
        get_binary_from_rom_ppmdu(
            rom, static_data.binaries['overlay/overlay_0029.bin']),
        static_data)

    actor_list_pokedex_number_mapping = []
    for e in actor_list.list:
        monster = md.entries[e.entid]
        actor_list_pokedex_number_mapping.append(
            monster.national_pokedex_number)

    boss_list_pokedex_number_mapping = []
    for boss in boss_list:
        try:
            monster = md.entries[boss.md_idx]
            boss_list_pokedex_number_mapping.append(
                monster.national_pokedex_number)
        except IndexError:
            boss_list_pokedex_number_mapping.append(0)

    mapping = {}
    for idx, a in enumerate(actor_list_pokedex_number_mapping):
        if a == 0:
            continue
        indices = [
            i for i, x in enumerate(boss_list_pokedex_number_mapping) if x == a
        ]
        if len(indices) > 0:
            mapping[idx] = indices

    print(mapping)
示例#8
0
 def is_applied(self, rom: NintendoDSRom, config: Pmd2Data) -> bool:
     if config.game_version == GAME_VERSION_EOS:
         ORIGINAL_BYTES = bytes([0xD8, 0x0D, 0x00, 0xEB])
         OFFSETS = {
             GAME_REGION_US: 0x605F4,
             GAME_REGION_EU: 0x60898,
         }
         offset = OFFSETS.get(config.game_region)
         if offset is not None:
             overlay29 = get_binary_from_rom_ppmdu(
                 rom, config.binaries["overlay/overlay_0029.bin"])
             return overlay29[offset:offset +
                              len(ORIGINAL_BYTES)] != ORIGINAL_BYTES
     raise NotImplementedError()
示例#9
0
    def _artist_credits(self):
        credit_map: Dict[str, ArtistCredits] = {}
        credits = ""

        overlay13 = get_binary_from_rom_ppmdu(self.rom, self.static_data.binaries['overlay/overlay_0013.bin'])
        actor_list: ActorListBin = FileType.SIR0.unwrap_obj(
            FileType.SIR0.deserialize(self.rom.getFileByName('BALANCE/actor_list.bin')), ActorListBin
        )
        starters = HardcodedPersonalityTestStarters.get_partner_md_ids(overlay13, self.static_data)
        partners = HardcodedPersonalityTestStarters.get_player_md_ids(overlay13, self.static_data)
        md = FileType.MD.deserialize(self.rom.getFileByName('BALANCE/monster.md'))

        with urllib.request.urlopen("http://sprites.pmdcollab.org/resources/pokemons.json") as url:
            config = json.loads(url.read().decode())

        with urllib.request.urlopen("http://sprites.pmdcollab.org/resources/credits.json") as url:
            credits_config = json.loads(url.read().decode())

        for starter in starters:
            self._process_portrait(credit_map, config, credits_config, starter, md.entries[starter], None)

        for partner in partners:
            self._process_portrait(credit_map, config, credits_config, partner, md.entries[partner], None)

        for actor in actor_list.list:
            if actor.entid > 0:
                self._process_portrait(credit_map, config, credits_config, actor.entid, md.entries[actor.entid], actor)

        credit_map = {k: credit_map[k] for k in sorted(credit_map)}

        for entry in credit_map.values():
            setface = ""
            if entry.actor:
                setface = f"message_SetFaceEmpty({SsbConstant.create_for(entry.actor).name}, FACE_HAPPY, FACE_POS_TOP_L_FACEINW);"
            others = ""
            if entry.other_artists:
                others = list(set(entry.other_artists))
                main = ''
                others_short = others[:3]
                if len(others_short) != len(others):
                    main += ' + more'
                others = f"More Authors: [CS:A]{', '.join(others_short) + main}[CR]"
            credits += f"""
        case menu("{entry.name}"):
            {setface}
            message_Talk("Last Author: [CS:A]{escape(entry.main_artist)}[CR]\\n{escape(others)}\\nsprites.pmdcollab.org/portrait.html?id={escape(entry.id_str)}");
            jump @l_artists;
"""
        return credits
示例#10
0
 def extract(self,
             entry_len: int,
             string_offs_per_entry: List[int],
             write_subheader=True):
     """Performs the extraction. Raises a RuntimeError on error."""
     try:
         binary = get_binary_from_rom_ppmdu(self._rom, self._binary)
         data = self._wrap_sir0(binary,
                                binary[self._block.begin:self._block.end],
                                entry_len, string_offs_per_entry,
                                write_subheader)
         if self._out_path not in self._rom.filenames:
             create_file_in_rom(self._rom, self._out_path, data)
         else:
             self._rom.setFileByName(self._out_path, data)
     except BaseException as ex:
         raise RuntimeError("Error during extraction for patch.") from ex
示例#11
0
    def run(self, status: Status):
        if not self.config['starters_npcs']['npcs']:
            return status.done()

        status.step("Apply 'ActorAndLevelLoader' patch...")
        patcher = Patcher(self.rom, self.static_data)
        if not patcher.is_applied('ActorAndLevelLoader'):
            patcher.apply('ActorAndLevelLoader')

        status.step("Updating bosses...")

        actor_list: ActorListBin = FileType.SIR0.unwrap_obj(
            FileType.SIR0.deserialize(
                self.rom.getFileByName('BALANCE/actor_list.bin')),
            ActorListBin)

        binary = get_binary_from_rom_ppmdu(
            self.rom, self.static_data.binaries['overlay/overlay_0029.bin'])
        boss_list = HardcodedFixedFloorTables.get_monster_spawn_list(
            binary, self.static_data)

        for i, actor in enumerate(actor_list.list):
            if i in ACTOR_TO_BOSS_MAPPING:
                for bi in ACTOR_TO_BOSS_MAPPING[i]:
                    boss_list[bi].md_idx = actor.entid

        for extra_id in EXTRA_FF_MONSTER_RANDOMIZE:
            boss_list[extra_id].md_idx = choice(
                get_allowed_md_ids(self.config, False))

        HardcodedFixedFloorTables.set_monster_spawn_list(
            binary, boss_list, self.static_data)
        set_binary_in_rom_ppmdu(
            self.rom, self.static_data.binaries['overlay/overlay_0029.bin'],
            binary)

        status.done()
示例#12
0
 def get_binary(self, binary: Union[Pmd2Binary, BinaryName, str]) -> bytes:
     if not isinstance(binary, Pmd2Binary):
         binary = self.get_rom_module().get_static_data().binaries[str(
             binary)]
     return get_binary_from_rom_ppmdu(self._rom, binary)  # type: ignore
示例#13
0
from skytemple_files.dungeon_data.fixed_bin.handler import FixedBinHandler
from skytemple_files.dungeon_data.fixed_bin.model import TileRule, TileRuleType, EntityRule
from skytemple_files.hardcoded.fixed_floor import HardcodedFixedFloorTables, EntitySpawnEntry, ItemSpawn, \
    MonsterSpawn, TileSpawn

output_dir = os.path.join(os.path.dirname(__file__), 'dbg_output')
base_dir = os.path.join(os.path.dirname(__file__), '..', '..', '..', '..', '..')
os.makedirs(output_dir, exist_ok=True)

rom = NintendoDSRom.fromFile('/home/marco/dev/skytemple/skytemple/skyworkcopy.nds')
static_data = get_ppmdu_config_for_rom(rom)

fixed_bin = rom.getFileByName('BALANCE/fixed.bin')
fixed = FixedBinHandler.deserialize(fixed_bin, static_data=static_data)

ov29 = get_binary_from_rom_ppmdu(rom, static_data.binaries['overlay/overlay_0029.bin'])
ov10 = get_binary_from_rom_ppmdu(rom, static_data.binaries['overlay/overlay_0010.bin'])

entity_table = HardcodedFixedFloorTables.get_entity_spawn_table(ov29, static_data)
item_table = HardcodedFixedFloorTables.get_item_spawn_list(ov29, static_data)
tile_table = HardcodedFixedFloorTables.get_tile_spawn_list(ov29, static_data)
monster_table = HardcodedFixedFloorTables.get_monster_spawn_list(ov29, static_data)
monster_stats_table = HardcodedFixedFloorTables.get_monster_spawn_stats_table(ov10, static_data)

T = TileRule
WH = TileRuleType.WALL_HALLWAY
FR = TileRuleType.FLOOR_ROOM
WZ = TileRuleType.WARP_ZONE
SR = TileRuleType.SECONDARY_ROOM
FH = TileRuleType.FLOOR_HALLWAY
K1 = TileRuleType.FL_WA_ROOM_FLAG_0C
示例#14
0
from skytemple_files.graphics.dma.dma_drawer import DmaDrawer
from skytemple_files.graphics.dma.model import Dma, DmaType
from skytemple_files.graphics.dpc.model import Dpc
from skytemple_files.graphics.dpci.model import Dpci
from skytemple_files.graphics.dpl.model import Dpl
from skytemple_files.graphics.dpla.model import Dpla
from skytemple_files.hardcoded.fixed_floor import HardcodedFixedFloorTables

output_dir = os.path.join(os.path.dirname(__file__), 'dbg_output')
base_dir = os.path.join(os.path.dirname(__file__), '..', '..', '..', '..', '..')
os.makedirs(output_dir, exist_ok=True)

rom = NintendoDSRom.fromFile(os.path.join(output_dir, 'test_fixed_floor.nds'))
static_data = get_ppmdu_config_for_rom(rom)

ov29 = get_binary_from_rom_ppmdu(rom, static_data.binaries['overlay/overlay_0029.bin'])

fixed = FileType.FIXED_BIN.deserialize(rom.getFileByName('BALANCE/fixed.bin'), static_data)
dungeon_bin = FileType.DUNGEON_BIN.deserialize(rom.getFileByName('DUNGEON/dungeon.bin'), static_data)
mappa = FileType.MAPPA_BIN.deserialize(rom.getFileByName('BALANCE/mappa_s.bin'))
monster_bin = FileType.BIN_PACK.deserialize(rom.getFileByName('MONSTER/monster.bin'))
monster_md = FileType.MD.deserialize(rom.getFileByName('BALANCE/monster.md'))
entity_table = HardcodedFixedFloorTables.get_entity_spawn_table(ov29, static_data)
item_table = HardcodedFixedFloorTables.get_item_spawn_list(ov29, static_data)
monster_table = HardcodedFixedFloorTables.get_monster_spawn_list(ov29, static_data)


def draw_monster_sprite(img: Image.Image, x: int, y: int, monster_id: int, direction: Pmd2ScriptDirection):
    sprite_index = monster_md.entries[monster_id].sprite_index
    if sprite_index >= len(monster_bin):
        return False
示例#15
0
#  You should have received a copy of the GNU General Public License
#  along with SkyTemple.  If not, see <https://www.gnu.org/licenses/>.
# mypy: ignore-errors
import os

from ndspy.rom import NintendoDSRom

from skytemple_files.common.util import get_ppmdu_config_for_rom, get_binary_from_rom_ppmdu
from skytemple_files.hardcoded.main_menu_music import HardcodedMainMenuMusic

base_dir = os.path.join(os.path.dirname(__file__), '..', '..', '..', '..')
rom_us = NintendoDSRom.fromFile(os.path.join(base_dir, 'skyworkcopy_us.nds'))
rom_eu = NintendoDSRom.fromFile(os.path.join(base_dir, 'skyworkcopy.nds'))
ppmdu_us = get_ppmdu_config_for_rom(rom_us)
ppmdu_eu = get_ppmdu_config_for_rom(rom_eu)
ov00_us = get_binary_from_rom_ppmdu(
    rom_us, ppmdu_us.binaries['overlay/overlay_0000.bin'])
ov00_eu = get_binary_from_rom_ppmdu(
    rom_eu, ppmdu_us.binaries['overlay/overlay_0000.bin'])
ov09_us = get_binary_from_rom_ppmdu(
    rom_us, ppmdu_us.binaries['overlay/overlay_0009.bin'])
ov09_eu = get_binary_from_rom_ppmdu(
    rom_eu, ppmdu_us.binaries['overlay/overlay_0009.bin'])

print(HardcodedMainMenuMusic.get_main_menu_music(ov00_us, ppmdu_us, ov09_us))
print(HardcodedMainMenuMusic.get_main_menu_music(ov00_eu, ppmdu_eu, ov09_eu))

HardcodedMainMenuMusic.set_main_menu_music(123, ov00_us, ppmdu_us, ov09_us)
HardcodedMainMenuMusic.set_main_menu_music(4, ov00_eu, ppmdu_eu, ov09_eu)

print(HardcodedMainMenuMusic.get_main_menu_music(ov00_us, ppmdu_us, ov09_us))
print(HardcodedMainMenuMusic.get_main_menu_music(ov00_eu, ppmdu_eu, ov09_eu))
示例#16
0
from ndspy.rom import NintendoDSRom

from skytemple_files.common.types.file_types import FileType
from skytemple_files.common.util import get_ppmdu_config_for_rom, get_binary_from_rom_ppmdu
from skytemple_files.dungeon_data.mappa_bin.validator.exception import DungeonTotalFloorCountInvalidError
from skytemple_files.dungeon_data.mappa_bin.validator.validator import DungeonValidator
from skytemple_files.hardcoded.dungeons import HardcodedDungeons

rom = NintendoDSRom.fromFile('../../../../../4261 - Pokemon Mystery Dungeon Explorers of Sky (U)(Xenophobia).nds')
config = get_ppmdu_config_for_rom(rom)

mappa_bin = rom.getFileByName('BALANCE/mappa_s.bin')
mappa = FileType.MAPPA_BIN.deserialize(mappa_bin)

dungeons = HardcodedDungeons.get_dungeon_list(
    get_binary_from_rom_ppmdu(rom, config.binaries['arm9.bin']),
    config
)

for i, dungeon in enumerate(dungeons):
    print(i, dungeon)
print("")

validator = DungeonValidator(mappa.floor_lists)
validator.validate(dungeons)
for e in validator.errors:
    if not isinstance(e, DungeonTotalFloorCountInvalidError):
        print(repr(e))

print("")
print(validator.invalid_dungeons)
示例#17
0
#
#  SkyTemple is free software: you can redistribute it and/or modify
#  it under the terms of the GNU General Public License as published by
#  the Free Software Foundation, either version 3 of the License, or
#  (at your option) any later version.
#
#  SkyTemple is distributed in the hope that it will be useful,
#  but WITHOUT ANY WARRANTY; without even the implied warranty of
#  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
#  GNU General Public License for more details.
#
#  You should have received a copy of the GNU General Public License
#  along with SkyTemple.  If not, see <https://www.gnu.org/licenses/>.
# mypy: ignore-errors
import os

from ndspy.rom import NintendoDSRom

from skytemple_files.common.util import get_ppmdu_config_for_rom, get_binary_from_rom_ppmdu
from skytemple_files.hardcoded.ground_dungeon_tilesets import HardcodedGroundDungeonTilesets

base_dir = os.path.join(os.path.dirname(__file__), '..', '..', '..', '..')
rom = NintendoDSRom.fromFile(os.path.join(base_dir, 'skyworkcopy.nds'))
ppmdu = get_ppmdu_config_for_rom(rom)

l = HardcodedGroundDungeonTilesets.get_ground_dungeon_tilesets(
    get_binary_from_rom_ppmdu(rom, ppmdu.binaries['overlay/overlay_0011.bin']),
    ppmdu)
for i, d in enumerate(l):
    print(i, d)
#  You should have received a copy of the GNU General Public License
#  along with SkyTemple.  If not, see <https://www.gnu.org/licenses/>.
# mypy: ignore-errors
import os

from ndspy.rom import NintendoDSRom

from skytemple_files.common.util import get_ppmdu_config_for_rom, get_binary_from_rom_ppmdu
from skytemple_files.hardcoded.dungeon_misc import HardcodedDungeonMisc

base_dir = os.path.join(os.path.dirname(__file__), '..', '..', '..', '..')
rom_us = NintendoDSRom.fromFile(os.path.join(base_dir, 'skyworkcopy_us.nds'))
rom_eu = NintendoDSRom.fromFile(os.path.join(base_dir, 'skyworkcopy.nds'))
ppmdu_us = get_ppmdu_config_for_rom(rom_us)
ppmdu_eu = get_ppmdu_config_for_rom(rom_eu)
arm9_us = get_binary_from_rom_ppmdu(rom_us, ppmdu_us.binaries['arm9.bin'])
arm9_eu = get_binary_from_rom_ppmdu(rom_eu, ppmdu_us.binaries['arm9.bin'])
ov10_us = get_binary_from_rom_ppmdu(
    rom_us, ppmdu_us.binaries['overlay/overlay_0010.bin'])
ov10_eu = get_binary_from_rom_ppmdu(
    rom_eu, ppmdu_us.binaries['overlay/overlay_0010.bin'])
ov29_us = get_binary_from_rom_ppmdu(
    rom_us, ppmdu_us.binaries['overlay/overlay_0029.bin'])
ov29_eu = get_binary_from_rom_ppmdu(
    rom_eu, ppmdu_us.binaries['overlay/overlay_0029.bin'])


def test(getter, setter, expected_value, ov_us, ov_eu):
    assert getter(ov_us, ppmdu_us) == expected_value
    assert getter(ov_eu, ppmdu_eu) == expected_value
    setter(123, ov_us, ppmdu_us)
示例#19
0
def draw_dungeon_map_bgs(rom, dungeon_map_bg_dir, config):
    os.makedirs(dungeon_map_bg_dir, exist_ok=True)
    dungeon_bin = FileType.DUNGEON_BIN.deserialize(rom.getFileByName('DUNGEON/dungeon.bin'), config)

    ground_dungeon_tilesets = HardcodedGroundDungeonTilesets.get_ground_dungeon_tilesets(
        get_binary_from_rom_ppmdu(rom, config.binaries['overlay/overlay_0011.bin']),
        config
    )
    dungeons = HardcodedDungeons.get_dungeon_list(
        get_binary_from_rom_ppmdu(rom, config.binaries['arm9.bin']),
        config
    )
    mappa = FileType.MAPPA_BIN.deserialize(rom.getFileByName('BALANCE/mappa_s.bin'))
    
    levels_by_id = config.script_data.level_list__by_id

    bg_list_bin = rom.getFileByName('MAP_BG/bg_list.dat')
    bg_list = FileType.BG_LIST_DAT.deserialize(bg_list_bin)

    for i, entry in enumerate(ground_dungeon_tilesets):
        if entry.ground_level >= 0xFFFF:
            continue
        level = levels_by_id[entry.ground_level]
        print(f"{i + 1}/{len(ground_dungeon_tilesets)-1} - {level.name}")
        print(entry)

        mappa_idx = dungeons[entry.dungeon_id].mappa_index
        start_offset = dungeons[entry.dungeon_id].start_after
        length = dungeons[entry.dungeon_id].number_floors
        if entry.dungeon_id == 71:
            print("DEEP CONCEALED RUINS SKIPPED")
            continue
        if entry.unk2 == 1:
            tileset_id = mappa.floor_lists[mappa_idx][start_offset].layout.tileset_id
        elif entry.unk2 == 100:
            tileset_id = mappa.floor_lists[mappa_idx][start_offset + length - 1].layout.tileset_id
        else:
            raise ValueError("Unknown unk2")
        if tileset_id == 170:
            tileset_id = 1
        dma: Dma = dungeon_bin.get(f'dungeon{tileset_id}.dma')
        dpl: Dpl = dungeon_bin.get(f'dungeon{tileset_id}.dpl')
        dpla: Dpla = dungeon_bin.get(f'dungeon{tileset_id}.dpla')
        dpci: Dpci = dungeon_bin.get(f'dungeon{tileset_id}.dpci')
        dpc: Dpc = dungeon_bin.get(f'dungeon{tileset_id}.dpc')

        bma: Bma = bg_list.level[level.mapid].get_bma(rom)

        duration = round(1000 / 60 * max(16, min(dpla.durations_per_frame_for_colors)))

        drawer = DmaDrawer(dma)
        rules = drawer.rules_from_bma(bma)
        mappings = drawer.get_mappings_for_rules(rules, treat_outside_as_wall=True, variation_index=0)
        frames = drawer.draw(mappings, dpci, dpc, dpl, dpla)
        frames[0].save(
            os.path.join(dungeon_map_bg_dir, level.name + '.gif'),
            save_all=True,
            append_images=frames[1:],
            duration=duration,
            loop=0,
            optimize=False
        )
        frames[0].save(
            os.path.join(dungeon_map_bg_dir, level.name + '.png')
        )
示例#20
0
    def apply(self, patch: Union[Pmd2Patch, Pmd2SimplePatch],
              binaries: Dict[str, Pmd2Binary], patch_file_dir: str,
              stub_path: str, game_id: str):
        try:
            with tempfile.TemporaryDirectory() as tmp:
                shutil.copytree(patch_file_dir, tmp, dirs_exist_ok=True)

                # Build ASM file to run
                asm_entrypoint = ''

                # First read in  stub
                with open(os.path.join(tmp, stub_path)) as f:
                    asm_entrypoint += f.read() + '\n'

                if isinstance(patch, Pmd2SimplePatch):
                    for replace in patch.string_replacements:
                        fn = os.path.join(tmp, replace.filename)
                        game = None
                        for game_candidate in replace.games:
                            if game_candidate.game_id == game_id:
                                game = game_candidate
                        if game is not None:
                            with open(os.path.join(tmp, fn), 'r') as f:
                                new_content = replace.regexp.sub(
                                    game.replace, f.read())
                            with open(os.path.join(tmp, fn), 'w') as f:
                                f.write(new_content)

                    # If it's a simple patch just output and re-import all binaries.
                    for binary_name, binary in binaries.items():
                        binary_path = os.path.join(tmp,
                                                   binary_name.split('/')[-1])
                        # Write binary to tmp dir
                        with open(binary_path, 'wb') as f:
                            try:
                                f.write(
                                    get_binary_from_rom_ppmdu(
                                        self.rom, binary))
                            except ValueError as err:
                                if binary_name.split(
                                        '/')[-1] == 'overlay_0036.bin':
                                    continue  # We ignore if End's extra overlay is missing.
                                raise err
                    # For simple patches we also output the overlay table as y9.bin:
                    binary_path = os.path.join(tmp, Y9_BIN)
                    # Write binary to tmp dir
                    with open(binary_path, 'wb') as f:
                        f.write(self.rom.arm9OverlayTable)

                # Then include other includes
                for include in patch.includes:
                    asm_entrypoint += f'.include "{os.path.join(tmp, include.filename)}"\n'

                # Build binary blocks
                if isinstance(patch, Pmd2Patch):
                    for open_bin in patch.open_bins:
                        binary = binaries[open_bin.filepath]
                        binary_path = os.path.join(
                            tmp,
                            open_bin.filepath.split('/')[-1])
                        os.makedirs(os.path.dirname(binary_path),
                                    exist_ok=True)
                        # Write binary to tmp dir
                        with open(binary_path, 'wb') as f:
                            f.write(get_binary_from_rom_ppmdu(
                                self.rom, binary))
                        asm_entrypoint += f'.open "{binary_path}", 0x{binary.loadaddress:0x}\n'
                        for include in open_bin.includes:
                            asm_entrypoint += f'.include "{os.path.join(tmp, include.filename)}"\n'
                        asm_entrypoint += '.close\n'

                # Write final asm file
                with open_utf8(os.path.join(tmp, ASM_ENTRYPOINT_FN), 'w') as f:
                    f.write(asm_entrypoint)

                # Run armips
                original_cwd = os.getcwd()
                os.chdir(tmp)
                try:
                    prefix = ""
                    # Under Windows, try to load from SkyTemple _resources dir first.
                    if sys.platform.startswith('win') and os.path.exists(
                            os.path.join(get_resources_dir(), 'armips.exe')):
                        prefix = os.path.join(get_resources_dir(), '')
                    result = subprocess.Popen(
                        [f'{prefix}armips', ASM_ENTRYPOINT_FN],
                        stdout=subprocess.PIPE,
                        stderr=subprocess.STDOUT)
                    retcode = result.wait()
                except FileNotFoundError as ex:
                    raise ArmipsNotInstalledError(
                        "ARMIPS could not be found. Make sure, that "
                        "'armips' is inside your system's PATH.") from ex
                finally:
                    # Restore cwd
                    os.chdir(original_cwd)

                if retcode != 0:
                    raise PatchError(
                        "ARMIPS reported an error while applying the patch.",
                        str(result.stdout.read(), 'utf-8'),
                        str(result.stderr.read(), 'utf-8')
                        if result.stderr else '')

                # Load the binaries back into the ROM
                opened_binaries = {}
                if isinstance(patch, Pmd2SimplePatch):
                    # Read in all binaries again
                    opened_binaries = binaries
                    # Also read in arm9OverlayTable
                    binary_path = os.path.join(tmp, Y9_BIN)
                    with open(binary_path, 'rb') as f:
                        self.rom.arm9OverlayTable = f.read()
                else:
                    # Read opened binaries again
                    for open_bin in patch.open_bins:
                        opened_binaries[open_bin.filepath] = binaries[
                            open_bin.filepath]
                for binary_name, binary in opened_binaries.items():
                    binary_path = os.path.join(tmp, binary_name.split('/')[-1])
                    with open(binary_path, 'rb') as f:
                        try:
                            set_binary_in_rom_ppmdu(self.rom, binary, f.read())
                        except ValueError as err:
                            if binary_name.split(
                                    '/')[-1] == 'overlay_0036.bin':
                                continue  # We ignore if End's extra overlay is missing.
                            raise err

        except (PatchError, ArmipsNotInstalledError):
            raise
        except BaseException as ex:
            raise RuntimeError(f"Error while applying the patch: {ex}") from ex
示例#21
0
#  the Free Software Foundation, either version 3 of the License, or
#  (at your option) any later version.
# 
#  SkyTemple is distributed in the hope that it will be useful,
#  but WITHOUT ANY WARRANTY; without even the implied warranty of
#  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
#  GNU General Public License for more details.
# 
#  You should have received a copy of the GNU General Public License
#  along with SkyTemple.  If not, see <https://www.gnu.org/licenses/>.
import os

from ndspy.rom import NintendoDSRom

from skytemple_files.common.util import get_ppmdu_config_for_rom, get_binary_from_rom_ppmdu
from skytemple_files.hardcoded.rank_up_table import HardcodedRankUpTable

base_dir = os.path.join(os.path.dirname(__file__), '..', '..', '..', '..')
rom_us = NintendoDSRom.fromFile(os.path.join(base_dir, 'skyworkcopy_us.nds'))
ppmdu_us = get_ppmdu_config_for_rom(rom_us)
arm9_us = get_binary_from_rom_ppmdu(rom_us, ppmdu_us.binaries['arm9.bin'])

rank_up = HardcodedRankUpTable.get_rank_up_table(arm9_us, ppmdu_us)

for i, rank in enumerate(rank_up):
    print(i, rank)
    
# Try setting and see if still same.
HardcodedRankUpTable.set_rank_up_table(rank_up, arm9_us, ppmdu_us)
assert rank_up == HardcodedRankUpTable.get_rank_up_table(arm9_us, ppmdu_us)
示例#22
0
#
#  You should have received a copy of the GNU General Public License
#  along with SkyTemple.  If not, see <https://www.gnu.org/licenses/>.
# mypy: ignore-errors
import os

from ndspy.rom import NintendoDSRom

from skytemple_files.common.util import get_ppmdu_config_for_rom, get_binary_from_rom_ppmdu
from skytemple_files.hardcoded.fixed_floor import HardcodedFixedFloorTables

base_dir = os.path.join(os.path.dirname(__file__), '..', '..', '..', '..')
rom = NintendoDSRom.fromFile(os.path.join(base_dir, 'skyworkcopy.nds'))
ppmdu = get_ppmdu_config_for_rom(rom)

ov29 = get_binary_from_rom_ppmdu(rom,
                                 ppmdu.binaries['overlay/overlay_0029.bin'])
ov10 = get_binary_from_rom_ppmdu(rom,
                                 ppmdu.binaries['overlay/overlay_0010.bin'])


def print_and_test(binary, getter, setter):
    values = getter(binary, ppmdu)

    for i, val in enumerate(values):
        print(i, val)

    # Try setting and see if still same.
    setter(binary, values, ppmdu)
    assert values == getter(binary, ppmdu)

示例#23
0
#  GNU General Public License for more details.
# 
#  You should have received a copy of the GNU General Public License
#  along with SkyTemple.  If not, see <https://www.gnu.org/licenses/>.
# mypy: ignore-errors
import os

from ndspy.rom import NintendoDSRom

from skytemple_files.common.util import get_ppmdu_config_for_rom, get_binary_from_rom_ppmdu
from skytemple_files.hardcoded.recruitment_tables import HardcodedRecruitmentTables

base_dir = os.path.join(os.path.dirname(__file__), '..', '..', '..', '..')
rom_us = NintendoDSRom.fromFile(os.path.join(base_dir, 'skyworkcopy_us.nds'))
ppmdu_us = get_ppmdu_config_for_rom(rom_us)
ov11_us = get_binary_from_rom_ppmdu(rom_us, ppmdu_us.binaries['overlay/overlay_0011.bin'])

species = HardcodedRecruitmentTables.get_monster_species_list(ov11_us, ppmdu_us)
level = HardcodedRecruitmentTables.get_monster_levels_list(ov11_us, ppmdu_us)
location = HardcodedRecruitmentTables.get_monster_locations_list(ov11_us, ppmdu_us)

for i, (e_species, e_level, e_location) in enumerate(zip(species, level, location)):
    print(i, e_species, e_level, e_location)
    
# Try setting and see if still same.
HardcodedRecruitmentTables.set_monster_species_list(species, ov11_us, ppmdu_us)
assert species == HardcodedRecruitmentTables.get_monster_species_list(ov11_us, ppmdu_us)

HardcodedRecruitmentTables.set_monster_levels_list(level, ov11_us, ppmdu_us)
assert level == HardcodedRecruitmentTables.get_monster_levels_list(ov11_us, ppmdu_us)
示例#24
0
    def apply(self, patch: Union[Pmd2Patch, Pmd2SimplePatch],
              binaries: Dict[str,
                             Pmd2Binary], patch_file_dir: str, stub_path: str,
              game_id: str, parameter_values: Dict[str, Union[int, str]]):
        with tempfile.TemporaryDirectory() as tmp:
            try:
                shutil.copytree(patch_file_dir,
                                tmp,
                                symlinks=True,
                                dirs_exist_ok=True)

                set_rw_permission_folder(tmp)

                # Build ASM file to run
                asm_entrypoint = ''

                # First read in  stub
                with open(os.path.join(tmp, stub_path)) as fi:
                    asm_entrypoint += fi.read() + '\n'

                if isinstance(patch, Pmd2SimplePatch):
                    for replace in patch.string_replacements:
                        fn = os.path.join(tmp, replace.filename)
                        game = None
                        for game_candidate in replace.games:
                            if game_candidate.game_id == game_id:
                                game = game_candidate
                        if game is not None:
                            with open_utf8(os.path.join(tmp, fn), 'r') as fi:
                                new_content = replace.regexp.sub(
                                    game.replace, fi.read())
                            with open_utf8(os.path.join(tmp, fn), 'w') as fi:
                                fi.write(new_content)

                    # If it's a simple patch just output and re-import all binaries.
                    for binary_name, binary in binaries.items():
                        binary_path = os.path.join(tmp,
                                                   binary_name.split('/')[-1])
                        # Write binary to tmp dir
                        with open(binary_path, 'wb') as fib:
                            try:
                                fib.write(
                                    get_binary_from_rom_ppmdu(
                                        self.rom, binary))
                            except ValueError as err:
                                if binary_name.split(
                                        '/')[-1] == 'overlay_0036.bin':
                                    continue  # We ignore if End's extra overlay is missing.
                                raise err
                    # For simple patches we also output the overlay table as y9.bin:
                    binary_path = os.path.join(tmp, Y9_BIN)
                    # Write binary to tmp dir
                    with open(binary_path, 'wb') as fib:
                        fib.write(self.rom.arm9OverlayTable)

                # Then include other includes
                for include in patch.includes:
                    asm_entrypoint += f'.include "{os.path.join(tmp, include.filename)}"\n'

                # Build binary blocks
                if isinstance(patch, Pmd2Patch):
                    for open_bin in patch.open_bins:
                        binary = binaries[open_bin.filepath]
                        binary_path = os.path.join(
                            tmp,
                            open_bin.filepath.split('/')[-1])
                        os.makedirs(os.path.dirname(binary_path),
                                    exist_ok=True)
                        # Write binary to tmp dir
                        with open(binary_path, 'wb') as fib:
                            fib.write(
                                get_binary_from_rom_ppmdu(self.rom, binary))
                        asm_entrypoint += f'.open "{binary_path}", 0x{binary.loadaddress:0x}\n'
                        for include in open_bin.includes:
                            asm_entrypoint += f'.include "{os.path.join(tmp, include.filename)}"\n'
                        asm_entrypoint += '.close\n'

                # Write final asm file
                with open_utf8(os.path.join(tmp, ASM_ENTRYPOINT_FN),
                               'w') as fi:
                    fi.write(asm_entrypoint)

                # Build parameters for equ
                parameters = []
                for param_name, param_value in parameter_values.items():
                    parameters += [
                        '-equ', param_name, f'"{param_value}"' if isinstance(
                            param_value, str) else str(param_value)
                    ]

                # Run armips
                try:
                    prefix = ""
                    # Under Windows, try to load from SkyTemple _resources dir first.
                    if sys.platform.startswith('win') and os.path.exists(
                            os.path.join(get_resources_dir(), 'armips.exe')):
                        prefix = os.path.join(get_resources_dir(), '')
                    exec_name = os.getenv('SKYTEMPLE_ARMIPS_EXEC',
                                          f'{prefix}armips')
                    cmd_line = [exec_name, ASM_ENTRYPOINT_FN] + parameters
                    if os.getenv('SKYTEMPLE_DEBUG_ARMIPS_OUTPUT', False):
                        print("ARMIPS CMDLINE:")
                        print(cmd_line)
                    result = subprocess.Popen(cmd_line,
                                              stdout=subprocess.PIPE,
                                              stderr=subprocess.STDOUT,
                                              cwd=tmp)
                    retcode = result.wait()
                except FileNotFoundError as ex:
                    raise make_user_err(
                        ArmipsNotInstalledError,
                        _("ARMIPS could not be found. Make sure, that "
                          "'armips' is inside your system's PATH.")) from ex

                if os.getenv('SKYTEMPLE_DEBUG_ARMIPS_OUTPUT', False):
                    print("ARMIPS OUTPUT:")
                    if result is not None:
                        print(str(result.stdout.read(),
                                  'utf-8'))  # type: ignore
                        print(
                            str(result.stderr.read(), 'utf-8')
                            if result.stderr else '')  # type: ignore

                if retcode != 0:
                    raise make_user_err(
                        PatchError,
                        _("ARMIPS reported an error while applying the patch."
                          ),
                        str(result.stdout.read(), 'utf-8'),
                        str(result.stderr.read(), 'utf-8')  # type: ignore
                        if result.stderr else '')  # type: ignore

                # Load the binaries back into the ROM
                opened_binaries = {}
                if isinstance(patch, Pmd2SimplePatch):
                    # Read in all binaries again
                    opened_binaries = binaries
                    # Also read in arm9OverlayTable
                    binary_path = os.path.join(tmp, Y9_BIN)
                    with open(binary_path, 'rb') as fib:
                        self.rom.arm9OverlayTable = fib.read()
                else:
                    # Read opened binaries again
                    for open_bin in patch.open_bins:
                        opened_binaries[open_bin.filepath] = binaries[
                            open_bin.filepath]
                for binary_name, binary in opened_binaries.items():
                    binary_path = os.path.join(tmp, binary_name.split('/')[-1])
                    with open(binary_path, 'rb') as fib:
                        try:
                            set_binary_in_rom_ppmdu(self.rom, binary,
                                                    fib.read())
                        except ValueError as err:
                            if binary_name.split(
                                    '/')[-1] == 'overlay_0036.bin':
                                continue  # We ignore if End's extra overlay is missing.
                            raise err

            except (PatchError, ArmipsNotInstalledError):
                raise
            except BaseException as ex:
                raise RuntimeError(f(
                    _("Error while applying the patch: {ex}"))) from ex
示例#25
0
    os.makedirs(out_dir, exist_ok=True)

    in_rom = NintendoDSRom.fromFile(
        os.path.join(base_dir, 'skyworkcopy_us.nds'))

    # Load PPMDU config, but remove all data about Patches and LooseBinFiles.
    config = get_ppmdu_config_for_rom(in_rom)
    config.asm_patches_constants.patches = {}
    config.asm_patches_constants.loose_bin_files = {}

    patcher = Patcher(in_rom, config, skip_core_patches=True)

    # Load the package
    patcher.add_pkg(package)
    assert not patcher.is_applied('ExamplePatch')

    patcher.apply('ExamplePatch')
    with open(os.path.join(out_dir, 'example_patch_ov11.bin'), 'wb') as f:
        f.write(
            get_binary_from_rom_ppmdu(
                in_rom, config.binaries['overlay/overlay_0011.bin']))

    assert patcher.is_applied('ExamplePatch')
    in_rom.saveToFile(os.path.join(out_dir, 'patched.nds'))

    # Check if really patched
    out_rom = NintendoDSRom.fromFile(os.path.join(out_dir, 'patched.nds'))
    new_patcher = Patcher(out_rom, get_ppmdu_config_for_rom(out_rom))
    new_patcher.add_pkg(package)
    assert new_patcher.is_applied('ExamplePatch')