Exemple #1
0
 def __init__(self, dma: Dma, dpci: Dpci, dpc: Dpc, dpl: Dpl):
     self._cached_rules = None
     self._cached_dungeon_surface = None
     self.dma = dma
     self.dpci = dpci
     self.dpc = dpc
     self.dpl = dpl
     self.dma_drawer = DmaDrawer(self.dma)
     chunks = self.dpc.chunks_to_pil(self.dpci, self.dpl.palettes, 1)
     self.single_tiles = {
         DmaType.FLOOR: self._single_tile(chunks, DmaType.FLOOR),
         DmaType.WALL: self._single_tile(chunks, DmaType.WALL),
         DmaType.WATER: self._single_tile(chunks, DmaType.WATER),
     }
Exemple #2
0
 def __init__(self, dbg: Dbg, dbg_dpci: Dpci, dbg_dpc: Dpc, dbg_dpl: Dpl,
              dma: Dma, chunks: Image.Image):
     self.dbg = dbg
     self.dbg_dpci = dbg_dpci
     self.dbg_dpc = dbg_dpc
     self.dbg_dpl = dbg_dpl
     self.dma = dma
     self.chunks = chunks
     self.dma_drawer = DmaDrawer(self.dma)
     self._cached_bg = None
     self._cached_rules = None
     self._cached_dungeon_surface = None
     self.single_tiles = {
         DmaType.FLOOR: self._single_tile(DmaType.FLOOR),
         DmaType.WALL: self._single_tile(DmaType.WALL),
         DmaType.WATER: self._single_tile(DmaType.WATER),
     }
Exemple #3
0
class FixedFloorDrawerTileset(AbstractTilesetRenderer):

    def __init__(self, dma: Dma, dpci: Dpci, dpc: Dpc, dpl: Dpl):
        self._cached_rules = None
        self._cached_dungeon_surface = None
        self.dma = dma
        self.dpci = dpci
        self.dpc = dpc
        self.dpl = dpl
        self.dma_drawer = DmaDrawer(self.dma)
        chunks = self.dpc.chunks_to_pil(self.dpci, self.dpl.palettes, 1)
        self.single_tiles = {
            DmaType.FLOOR: self._single_tile(chunks, DmaType.FLOOR),
            DmaType.WALL: self._single_tile(chunks, DmaType.WALL),
            DmaType.WATER: self._single_tile(chunks, DmaType.WATER),
        }

    def get_background(self) -> Optional[cairo.Surface]:
        return None

    def get_dungeon(self, rules: List[List[DmaType]]) -> cairo.Surface:
        # TODO: If rules change only update the parts that need to be updated
        if rules != self._cached_rules:
            mappings = self.dma_drawer.get_mappings_for_rules(rules, treat_outside_as_wall=True, variation_index=0)
            self._cached_dungeon_surface = pil_to_cairo_surface(
                self.dma_drawer.draw(mappings, self.dpci, self.dpc, self.dpl, None)[0].convert('RGBA')
            )
            self._cached_rules = rules
        return self._cached_dungeon_surface

    def get_single_tile(self, tile: DmaType) -> cairo.Surface:
        return self.single_tiles[tile]

    def _single_tile(self, chunks, type):
        index = self.dma.get(type, False)[0]
        chunk_dim = DPC_TILING_DIM * DPCI_TILE_DIM
        return pil_to_cairo_surface(
            chunks.crop((0, index * chunk_dim, chunk_dim, index * chunk_dim + chunk_dim)).convert('RGBA')
        )
 def draw_full(self, ctx: cairo.Context, bma_chunks: List[int],
               bma_chunk_width: int, bma_chunk_height: int):
     if bma_chunk_width != self._cached__bma_chunk_width or self._cached__bma_chunks != bma_chunks:
         self._cached__bma_chunk_width = bma_chunk_width
         self._cached__bma_chunks = list(bma_chunks)
         self._cached = None
     if self._cached is None:
         drawer = DmaDrawer(self.dma)
         if self.fixed_room:
             rules = drawer.rules_from_fixed_room(self.fixed_room)
         else:
             rules = drawer.rules_from_bma(bma_chunks, bma_chunk_width)
         mappings = drawer.get_mappings_for_rules(
             rules, treat_outside_as_wall=True, variation_index=0)
         frame = pil_to_cairo_surface(
             drawer.draw(mappings, self.dpci, self.dpc, self.dpl,
                         None)[0].convert('RGBA'))
         self._cached = frame
     ctx.set_source_surface(self._cached)
     ctx.get_source().set_filter(cairo.Filter.NEAREST)
     ctx.paint()
Exemple #5
0
class FixedFloorDrawerBackground(AbstractTilesetRenderer):
    def __init__(self, dbg: Dbg, dbg_dpci: Dpci, dbg_dpc: Dpc, dbg_dpl: Dpl,
                 dma: Dma, chunks: Image.Image):
        self.dbg = dbg
        self.dbg_dpci = dbg_dpci
        self.dbg_dpc = dbg_dpc
        self.dbg_dpl = dbg_dpl
        self.dma = dma
        self.chunks = chunks
        self.dma_drawer = DmaDrawer(self.dma)
        self._cached_bg = None
        self._cached_rules = None
        self._cached_dungeon_surface = None
        self.single_tiles = {
            DmaType.FLOOR: self._single_tile(DmaType.FLOOR),
            DmaType.WALL: self._single_tile(DmaType.WALL),
            DmaType.WATER: self._single_tile(DmaType.WATER),
        }

    def get_background(self) -> Optional[cairo.Surface]:
        if not self._cached_bg:
            self._cached_bg = pil_to_cairo_surface(
                self.dbg.to_pil(self.dbg_dpc, self.dbg_dpci,
                                self.dbg_dpl.palettes).convert('RGBA'))
        return self._cached_bg

    def get_dungeon(self, rules: List[List[DmaType]]) -> cairo.Surface:
        # TODO: If rules change only update the parts that need to be updated
        if rules != self._cached_rules:
            mappings = self.dma_drawer.get_mappings_for_rules(
                rules, treat_outside_as_wall=True, variation_index=0)
            self._cached_dungeon_surface = pil_to_cairo_surface(
                self._draw_dungeon(mappings))
            self._cached_rules = rules
        return self._cached_dungeon_surface

    def get_single_tile(self, tile: DmaType) -> cairo.Surface:
        return self.single_tiles[tile]

    def _single_tile(self, type):
        index = self.dma.get(type, False)[0]
        chunk_dim = DPC_TILING_DIM * DPCI_TILE_DIM
        chunk_width = int(self.chunks.width / chunk_dim)
        cy = int(index / chunk_width) * chunk_dim
        cx = index % chunk_width * chunk_dim
        return pil_to_cairo_surface(
            self.chunks.crop((cx, cy, cx + chunk_dim, cy + chunk_dim)))

    def _draw_dungeon(self, mappings: List[List[int]]) -> Image.Image:
        chunk_dim = DPCI_TILE_DIM * DPC_TILING_DIM
        chunk_width = int(self.chunks.width / chunk_dim)

        fimg = Image.new(
            'RGBA', (len(mappings[0]) * chunk_dim, len(mappings) * chunk_dim))

        def paste(chunk_index, x, y):
            cy = int(chunk_index / chunk_width) * chunk_dim
            cx = chunk_index % chunk_width * chunk_dim
            fimg.paste(
                self.chunks.crop((cx, cy, cx + chunk_dim, cy + chunk_dim)),
                (x * chunk_dim, y * chunk_dim))

        for y, row in enumerate(mappings):
            for x, cell in enumerate(row):
                paste(cell, x, y)

        return fimg
Exemple #6
0
                    row.append(DmaType.WALL)
                elif action.tr_type.floor_type == FloorType.SECONDARY:
                    row.append(DmaType.WATER)
                elif action.tr_type.floor_type == FloorType.FLOOR_OR_WALL:
                    row.append(DmaType.WALL)
            else:
                # TODO? Could be something else
                row.append(DmaType.FLOOR)
            ridx += 1
        row += [outside, outside, outside, outside]
    rules.append([outside] * (ffloor.width + 8))
    rules.append([outside] * (ffloor.width + 8))
    rules.append([outside] * (ffloor.width + 8))
    rules.append([outside] * (ffloor.width + 8))

    drawer = DmaDrawer(dma)
    mappings = drawer.get_mappings_for_rules(rules, None, True)
    dungeon_floor = drawer.draw(mappings, dpci, dpc, dpl, dpla)[0].convert('RGBA')

    ridx = 0
    # Draw items and Pokémon
    for y in range(4, ffloor.height + 4):
        for x in range(4, ffloor.width + 4):
            action = ffloor.actions[ridx]
            if isinstance(action, TileRule):
                # Leader spawn tile
                if action.tr_type == TileRuleType.LEADER_SPAWN:
                    draw_monster_sprite(dungeon_floor, x, y, 1, action.direction)
                # Key walls
                if action.tr_type == TileRuleType.FL_WA_ROOM_FLAG_0C or action.tr_type == TileRuleType.FL_WA_ROOM_FLAG_0D:
                    draw_text(dungeon_floor, x, y, (0, 255, 0), f'KEY\nDOOR')
Exemple #7
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')
        )