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()
示例#2
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')
        )
示例#3
0
                    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')
                # Warp zone
                if action.tr_type == TileRuleType.WARP_ZONE or action.tr_type == TileRuleType.WARP_ZONE_2:
示例#4
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')
        )