Exemple #1
0
    def load(self, filename, data):
        self._filename = filename
        self._world_index = int(os.path.basename(filename)[1]) - 1

        stream = StreamRead.from_file(filename, Endianness.BIG)

        self._offset_tile_gfx = stream.read_uint() - WORLD_BASE_OFFSET
        self._offset_tile_collision = stream.read_uint() - WORLD_BASE_OFFSET
        self._offset_palette = stream.read_uint() - WORLD_BASE_OFFSET
        self._offset_u1 = stream.read_uint() - WORLD_BASE_OFFSET
        self._offset_u2 = stream.read_uint() - WORLD_BASE_OFFSET

        if self._offset_tile_gfx > stream.size or self._offset_tile_collision > stream.size or self._offset_palette > stream.size:
            raise Exception('"{}" is not a valid world file.'.format(filename))

        # Read level header offsets.
        level_count = stream.read_ushort()
        self._level_offsets = []
        for _ in range(0, level_count):
            self._level_offsets.append(stream.read_uint() - WORLD_BASE_OFFSET)

        # Read level headers.
        self._levels = []
        for level_index, offset in enumerate(self._level_offsets):
            stream.seek(offset)

            level = Level(self._world_index, level_index)
            level.name = '{}-{}: {}'.format(self._world_index + 1, level_index + 1, data[level_index]['name'])
            level.maximum_blockmap_size = data[level_index]['blockmap_size']
            level.load_header(stream)
            self._levels.append(level)

        # Read the world palette.
        stream.seek(self._offset_palette)
        self._palette = Palette.from_stream(stream, 16, 4)

        # Read tileset.
        self._tileset = TileSet.from_stream(stream, self._offset_tile_gfx, self._offset_tile_collision, self._palette)

        # Read level data.
        for level_index, level in enumerate(self._levels):
            if level_index > 0:
                game_dir = os.path.dirname(filename)
                level_file = 'L{}-{}'.format(self._world_index + 1, level_index + 1)
                level_file = os.path.join(game_dir, level_file)
                stream.insert(level_file, level.data_offset)

            if self._world_index == 2 and level_index == 1:
                offset = 19620
            else:
                offset = 0

            level.load(stream, offset)
Exemple #2
0
    def load_graphics(self, json_filename, directory):
        with open(json_filename, 'r') as fp:
            data = json.load(fp)

        # Read palettes.
        palettes = {}
        for filename, file_data in data.items():
            filename = os.path.join(directory, filename)
            stream = StreamRead.from_file(filename, Endianness.BIG)

            for pal_name, pal_data in file_data['palettes'].items():
                stream.seek(pal_data['offset'])
                palettes[pal_name] = Palette.from_stream(stream, pal_data['length'], 4)

        # Read and generate graphics.
        for filename, file_data in data.items():
            filename = os.path.join(directory, filename)
            stream = StreamRead.from_file(filename, Endianness.BIG)

            for gfx in file_data['graphics']:
                width = gfx['width']
                height = gfx['height']
                planes = gfx['planes']
                count = gfx['count']
                palette = palettes[gfx['palette']]

                # Determine the bitplane mode to use.
                if gfx['mode'] == 'amiga_sprite':
                    mode = BitplaneType.AMIGA_SPRITE
                elif gfx['mode'] == 'chunky':
                    mode = BitplaneType.CHUNKY
                elif gfx['mode'] == 'planar':
                    mode = BitplaneType.PLANAR
                else:
                    raise Exception('Unknown bitplane mode "{}".'.format(gfx['mode']))

                # Read all bitplanes in order.
                surfaces = []
                stream.seek(gfx['offset'])
                for _ in range(0, count):
                    bitplane = Bitplane.from_stream(stream, mode, width, height, planes)

                    # Create a surface, and use a masking mode if needed.
                    if gfx['mask'] == 'color_zero':
                        surface = bitplane.create_surface(None, palette, 0, 0, MaskMode.INDEX)
                    elif gfx['mask'] == 'none':
                        surface = bitplane.create_surface(None, palette, 0, 0, MaskMode.NONE)
                    elif gfx['mask'] == 'bitplane':
                        if gfx['mode'] == 'planar':
                            mask = bitplane.from_stream(stream, BitplaneType.PLANAR, width, height, planes)
                        else:
                            mask = bitplane.from_stream(stream, BitplaneType.CHUNKY, width, height, 1)
                        surface = bitplane.create_surface(mask, palette, 0, 0, MaskMode.BITPLANE)
                    else:
                        raise Exception('Unknown mask mode "{}".'.format(gfx['mask']))

                    if gfx['flip_y']:
                        surface = surface.flipped_y()

                    surfaces.append(surface)

                if gfx['name'] in self.graphics:
                    self.graphics[gfx['name']].extend(surfaces)
                else:
                    self.graphics[gfx['name']] = surfaces