示例#1
0
class PakIndex(object):
    """ A class to hold information on an individual file in the pak. """

    def __init__(self, data):
        (self.size_compressed,
                self.abs_index,
                self.size_real,
                self.unknowni1) = unpack('<IIII', data[:16])
        self.filename = data[16:]
        self.filename = self.filename[:self.filename.index("\x00")]

df = Savefile(sys.argv[1])

df.open_r()
header = df.read(4)
if (header != '!PAK'):
  df.close()
  raise LoadException('Invalid PAK header')

# Initial Values
unknownh1 = df.readshort()
unknownh2 = df.readshort()
numfiles = df.readint()
compressed_idx_size = df.readint()
unknowni1 = df.readint()

# Now load in the index
decobj = zlib.decompressobj()
indexdata = decobj.decompress(df.read())
zeroindex = df.tell() - len(decobj.unused_data)
示例#2
0
class B1Gfx(Gfx):
    """
    Grphics structure for Book 1
    """

    book = 1
    wall_types: Dict[Any, Any] = {}
    wall_gfx_group: Dict[Any, Any] = {}
    tilebuf_mult = 1
    item_dim = 42
    item_cols = 10
    item_rows = 24
    tile_width = 52
    tile_height = 26
    floor_cols = 6
    floor_rows = 32
    decal_cols = 6
    decal_rows = 32
    obj_a_width = 52
    obj_a_height = 52
    obj_a_cols = 6
    obj_a_rows = 16
    obj_a_offset = 1
    obj_b_width = 52
    obj_b_height = 78
    obj_b_cols = 6
    obj_b_rows = 10
    obj_b_offset = 101
    obj_c_width = 52
    obj_c_height = 78
    obj_c_cols = 6
    obj_c_rows = 10
    obj_c_offset = 161
    obj_d_width = 52
    obj_d_height = 130
    obj_d_cols = 5
    obj_d_rows = 1
    obj_d_offset = 251
    walldecal_cols = 6
    walldecal_rows = 10

    GFX_SET_A = 1
    GFX_SET_B = 2
    GFX_SET_C = 3
    GFX_SET_TREE = 4

    def __init__(self, datadir, eschalondata):

        # Wall graphic groupings
        for i in range(101):
            self.wall_gfx_group[i] = self.GFX_SET_A
        for i in range(101, 161):
            self.wall_gfx_group[i] = self.GFX_SET_B
        for i in range(161, 251):
            self.wall_gfx_group[i] = self.GFX_SET_C
        for i in range(251, 256):
            self.wall_gfx_group[i] = self.GFX_SET_TREE

        # Wall object types
        for i in (list(range(127)) + list(range(132, 142)) + list(range(143, 153)) +
                  list(range(154, 161)) + list(range(214, 251))):
            self.wall_types[i] = self.TYPE_OBJ
        for i in range(161, 214):
            self.wall_types[i] = self.TYPE_WALL
        for i in (list(range(251, 256)) + list(range(127, 132)) + [142, 153]):
            self.wall_types[i] = self.TYPE_TREE

        # Restricted entities (only one direction)
        self.restrict_ents = [50, 55, 58, 66, 67, 71]

        # Book 1 specific vars (just the PAK structure stuff)
        self.unknownh1 = -1
        self.unknownh2 = -1
        self.numfiles = -1
        self.compressed_idx_size = -1
        self.unknowni1 = -1
        self.fileindex = {}
        self.zeroindex = -1

        # Book 1 specific caches
        self.itemcache = None

        # Graphics PAK file
        self.pakloc = os.path.join(eschalondata.gamedir, 'gfx.pak')
        if os.path.isfile(self.pakloc):
            self.df = Savefile(self.pakloc)
        else:
            self.df = None

        # Set our loaded status
        self.loaded = False

        # Finally call the parent constructor
        super(B1Gfx, self).__init__(datadir, eschalondata)

    def readfile(self, filename: str) -> object:
        """ Reads a given filename out of the PAK. """
        if self.loaded:
            filepath = os.path.join(
                self.eschalondata.gamedir, 'packedgraphics', filename)
            if os.path.isfile(filepath):
                return open(filepath, 'rb').read()
            if filename in self.fileindex:
                self.df.open_r()
                self.df.seek(self.zeroindex +
                             self.fileindex[filename].abs_index)
                # On Windows, we need to specify bufsize or memory gets clobbered
                filedata = zlib.decompress(
                    self.df.read(self.fileindex[filename].size_compressed),
                    15,
                    self.fileindex[filename].size_real)
                self.df.close()
                return filedata
            else:
                raise LoadException(
                    'Filename %s not found in archive' % (filename))
        else:
            raise LoadException('PAK Index has not been loaded')

    def initialread(self):
        """ Read in the main file index. """

        df = self.df
        if df is None:
            self.loaded = True
            return

        df.open_r()
        header = df.read(4)
        if (header != b'!PAK'):
            df.close()
            raise LoadException('Invalid PAK header')

        # Initial Values
        self.unknownh1 = df.readshort()
        self.unknownh2 = df.readshort()
        self.numfiles = df.readint()
        self.compressed_idx_size = df.readint()
        self.unknowni1 = df.readint()

        # Now load in the index
        decobj = zlib.decompressobj()
        indexdata = decobj.decompress(df.read())
        self.zeroindex = df.tell() - len(decobj.unused_data)
        for i in range(self.numfiles):
            index = PakIndex(indexdata[:272])
            indexdata = indexdata[272:]
            self.fileindex[index.filename] = index

        # Close and clean up
        df.close()
        self.loaded = True

    def get_item(self, item, size=None, gdk=True):
        if (self.itemcache is None):
            self.itemcache = GfxCache(self.readfile(
                'items_mastersheet.png'), 42, 42, 10)
        return self.itemcache.getimg(item.pictureid + 1, size, gdk)

    def get_floor(self, floornum, size=None, gdk=False):
        if (floornum == 0):
            return None
        if (self.floorcache is None):
            self.floorcache = GfxCache(self.readfile(
                'iso_tileset_base.png'), 52, 26, 6)
        return self.floorcache.getimg(floornum, size, gdk)

    def get_decal(self, decalnum, size=None, gdk=False):
        if (decalnum == 0):
            return None
        if (self.decalcache is None):
            self.decalcache = GfxCache(self.readfile(
                'iso_tileset_base_decals.png'), 52, 26, 6)
        return self.decalcache.getimg(decalnum, size, gdk)

    # Returns a tuple, first item is the surface, second is the extra height to add while drawing
    def get_object(self, objnum, size=None, gdk=False, treeset=0):
        """
        Note that we ignore the treeset flag in book 1
        """
        if (objnum == 0):
            return (None, 0, 0)
        try:
            gfxgroup = self.wall_gfx_group[objnum]
        except KeyError:
            return (None, 0, 0)
        if gfxgroup == self.GFX_SET_A:
            if (self.objcache1 is None):
                self.objcache1 = GfxCache(self.readfile(
                    'iso_tileset_obj_a.png'), 52, 52, 6)
            return (self.objcache1.getimg(objnum, size, gdk), 1, 0)
        elif gfxgroup == self.GFX_SET_B:
            if (self.objcache2 is None):
                self.objcache2 = GfxCache(self.readfile(
                    'iso_tileset_obj_b.png'), 52, 78, 6)
            return (self.objcache2.getimg(objnum - 100, size, gdk), 2, 0)
        elif gfxgroup == self.GFX_SET_C:
            if (self.objcache3 is None):
                self.objcache3 = GfxCache(self.readfile(
                    'iso_tileset_obj_c.png'), 52, 78, 6)
            return (self.objcache3.getimg(objnum - 160, size, gdk), 2, 0)
        else:
            if (self.objcache4 is None):
                self.objcache4 = GfxCache(
                    self.readfile('iso_trees.png'), 52, 130, 5)
            if (objnum in self.treemap):
                return (self.objcache4.getimg(self.treemap[objnum], size, gdk), 4, 0)
            else:
                return (None, 4, 0)

    def get_object_decal(self, decalnum, size=None, gdk=False):
        if (decalnum == 0):
            return None
        if (self.objdecalcache is None):
            self.objdecalcache = GfxCache(self.readfile(
                'iso_tileset_obj_decals.png'), 52, 78, 6)
        return self.objdecalcache.getimg(decalnum, size, gdk)

    def get_flame(self, size=None, gdk=False):
        """
        Grabs the flame graphic, so it's clear when viewing maps.  I provide my own
        image here instead of using the game's because the file bundled with the game
        doesn't have transparency information, and I don't feel like doing a conversion.
        """
        if (self.flamecache is None):
            with open(os.path.join(self.datadir, 'torch_single.png'), 'rb') as df:
                flamedata = df.read()
            self.flamecache = B1GfxEntCache(flamedata, 1, 1)
        if (size is None):
            size = self.tile_width
        return self.flamecache.getimg(1, int(size * self.flamecache.size_scale), gdk)

    def get_entity(self, entnum, direction, size=None, gdk=False):
        entity = self.eschalondata.get_entity(entnum)
        if not entity:
            return None
        entnum = entity.gfxfile
        if (entnum not in self.entcache):
            filename = 'mo%d.png' % (entnum)
            if (entnum in self.restrict_ents):
                self.entcache[entnum] = B1GfxEntCache(
                    self.readfile(filename), 2, 1)
            else:
                self.entcache[entnum] = B1GfxEntCache(self.readfile(filename))
        cache = self.entcache[entnum]
        if (size is None):
            size = self.tile_width
        return cache.getimg(direction, int(size * cache.size_scale), gdk)

    def get_avatar(self, avatarnum):
        if avatarnum < 0 or avatarnum > 7:
            return None
        if avatarnum not in self.avatarcache:
            if avatarnum == 7:
                if os.path.exists(os.path.join(self.eschalondata.gamedir, 'mypic.png')):
                    self.avatarcache[avatarnum] = GdkPixbuf.Pixbuf.new_from_file(
                        os.path.join(self.eschalondata.gamedir, 'mypic.png'))
                else:
                    return None
            else:
                self.avatarcache[avatarnum] = GfxCache(
                    self.readfile('{}.png'.format(avatarnum)), 60, 60, 1).pixbuf
        return self.avatarcache[avatarnum]
示例#3
0
class B1Gfx(Gfx):
    """
    Grphics structure for Book 1
    """

    book = 1
    wall_types = {}
    wall_gfx_group = {}
    tilebuf_mult = 1
    item_dim = 42
    item_cols = 10
    item_rows = 24
    tile_width = 52
    tile_height = 26
    floor_cols = 6
    floor_rows = 32
    decal_cols = 6
    decal_rows = 32
    obj_a_width = 52
    obj_a_height = 52
    obj_a_cols = 6
    obj_a_rows = 16
    obj_a_offset = 1
    obj_b_width = 52
    obj_b_height = 78
    obj_b_cols = 6
    obj_b_rows = 10
    obj_b_offset = 101
    obj_c_width = 52
    obj_c_height = 78
    obj_c_cols = 6
    obj_c_rows = 10
    obj_c_offset = 161
    obj_d_width = 52
    obj_d_height = 130
    obj_d_cols = 5
    obj_d_rows = 1
    obj_d_offset = 251
    walldecal_cols = 6
    walldecal_rows = 10

    GFX_SET_A = 1
    GFX_SET_B = 2
    GFX_SET_C = 3
    GFX_SET_TREE = 4

    def __init__(self, datadir, eschalondata):

        # Wall graphic groupings
        for i in range(101):
            self.wall_gfx_group[i] = self.GFX_SET_A
        for i in range(101, 161):
            self.wall_gfx_group[i] = self.GFX_SET_B
        for i in range(161, 251):
            self.wall_gfx_group[i] = self.GFX_SET_C
        for i in range(251, 256):
            self.wall_gfx_group[i] = self.GFX_SET_TREE

        # Wall object types
        for i in (range(127) + range(132, 142) + range(143, 153) +
                range(154, 161) + range(214, 251)):
            self.wall_types[i] = self.TYPE_OBJ
        for i in range(161, 214):
            self.wall_types[i] = self.TYPE_WALL
        for i in (range(251, 256) + range(127, 132) + [142, 153]):
            self.wall_types[i] = self.TYPE_TREE

        # Restricted entities (only one direction)
        self.restrict_ents = [50, 55, 58, 66, 67, 71]

        # Book 1 specific vars (just the PAK structure stuff)
        self.unknownh1 = -1
        self.unknownh2 = -1
        self.numfiles = -1
        self.compressed_idx_size = -1
        self.unknowni1 = -1
        self.fileindex = {}
        self.zeroindex = -1

        # Book 1 specific caches
        self.itemcache = None

        # Graphics PAK file
        self.pakloc = os.path.join(eschalondata.gamedir, 'gfx.pak')
        if os.path.isfile(self.pakloc):
            self.df = Savefile(self.pakloc)
        else:
            self.df = None

        # Set our loaded status
        self.loaded = False

        # Finally call the parent constructor
        super(B1Gfx, self).__init__(datadir, eschalondata)

    def readfile(self, filename):
        """ Reads a given filename out of the PAK. """
        if self.loaded:
            filepath = os.path.join(self.eschalondata.gamedir, 'packedgraphics', filename)
            if os.path.isfile(filepath):
                return open(filepath, 'rb').read()
            if (filename in self.fileindex):
                self.df.open_r()
                self.df.seek(self.zeroindex + self.fileindex[filename].abs_index)
                # On Windows, we need to specify bufsize or memory gets clobbered
                filedata = zlib.decompress(
                    self.df.read(self.fileindex[filename].size_compressed),
                    15,
                    self.fileindex[filename].size_real)
                self.df.close()
                return filedata
            else:
                raise LoadException('Filename %s not found in archive' % (filename))
        else:
            raise LoadException('PAK Index has not been loaded')

    def initialread(self):
        """ Read in the main file index. """

        df = self.df
        if df is None:
            self.loaded = True
            return

        df.open_r()
        header = df.read(4)
        if (header != '!PAK'):
            df.close()
            raise LoadException('Invalid PAK header')
        
        # Initial Values
        self.unknownh1 = df.readshort()
        self.unknownh2 = df.readshort()
        self.numfiles = df.readint()
        self.compressed_idx_size = df.readint()
        self.unknowni1 = df.readint()

        # Now load in the index
        decobj = zlib.decompressobj()
        indexdata = decobj.decompress(df.read())
        self.zeroindex = df.tell() - len(decobj.unused_data)
        decobj = None
        for i in range(self.numfiles):
            index = PakIndex(indexdata[:272])
            indexdata = indexdata[272:]
            self.fileindex[index.filename] = index

        # Close and clean up
        df.close()
        self.loaded = True

    def get_item(self, item, size=None, gdk=True):
        if (self.itemcache is None):
            self.itemcache = GfxCache(self.readfile('items_mastersheet.png'), 42, 42, 10)
        return self.itemcache.getimg(item.pictureid+1, size, gdk)

    def get_floor(self, floornum, size=None, gdk=False):
        if (floornum == 0):
            return None
        if (self.floorcache is None):
            self.floorcache = GfxCache(self.readfile('iso_tileset_base.png'), 52, 26, 6)
        return self.floorcache.getimg(floornum, size, gdk)

    def get_decal(self, decalnum, size=None, gdk=False):
        if (decalnum == 0):
            return None
        if (self.decalcache is None):
            self.decalcache = GfxCache(self.readfile('iso_tileset_base_decals.png'), 52, 26, 6)
        return self.decalcache.getimg(decalnum, size, gdk)

    # Returns a tuple, first item is the surface, second is the extra height to add while drawing
    def get_object(self, objnum, size=None, gdk=False, treeset=0):
        """
        Note that we ignore the treeset flag in book 1
        """
        if (objnum == 0):
            return (None, 0, 0)
        try:
            gfxgroup = self.wall_gfx_group[objnum]
        except KeyError:
            return (None, 0, 0)
        if gfxgroup == self.GFX_SET_A:
            if (self.objcache1 is None):
                self.objcache1 = GfxCache(self.readfile('iso_tileset_obj_a.png'), 52, 52, 6)
            return (self.objcache1.getimg(objnum, size, gdk), 1, 0)
        elif gfxgroup == self.GFX_SET_B:
            if (self.objcache2 is None):
                self.objcache2 = GfxCache(self.readfile('iso_tileset_obj_b.png'), 52, 78, 6)
            return (self.objcache2.getimg(objnum-100, size, gdk), 2, 0)
        elif gfxgroup == self.GFX_SET_C:
            if (self.objcache3 is None):
                self.objcache3 = GfxCache(self.readfile('iso_tileset_obj_c.png'), 52, 78, 6)
            return (self.objcache3.getimg(objnum-160, size, gdk), 2, 0)
        else:
            if (self.objcache4 is None):
                self.objcache4 = GfxCache(self.readfile('iso_trees.png'), 52, 130, 5)
            if (objnum in self.treemap):
                return (self.objcache4.getimg(self.treemap[objnum], size, gdk), 4, 0)
            else:
                return (None, 4, 0)

    def get_object_decal(self, decalnum, size=None, gdk=False):
        if (decalnum == 0):
            return None
        if (self.objdecalcache is None):
            self.objdecalcache = GfxCache(self.readfile('iso_tileset_obj_decals.png'), 52, 78, 6)
        return self.objdecalcache.getimg(decalnum, size, gdk)

    def get_flame(self, size=None, gdk=False):
        """
        Grabs the flame graphic, so it's clear when viewing maps.  I provide my own
        image here instead of using the game's because the file bundled with the game
        doesn't have transparency information, and I don't feel like doing a conversion.
        """
        if (self.flamecache is None):
            df = open(os.path.join(self.datadir, 'torch_single.png'), 'rb')
            flamedata = df.read()
            df.close()
            self.flamecache = B1GfxEntCache(flamedata, 1, 1)
        if (size is None):
            size = self.tile_width
        return self.flamecache.getimg(1, int(size*self.flamecache.size_scale), gdk)

    def get_entity(self, entnum, direction, size=None, gdk=False):
        entity = self.eschalondata.get_entity(entnum)
        if not entity:
            return None
        entnum = entity.gfxfile
        if (entnum not in self.entcache):
            filename = 'mo%d.png' % (entnum)
            if (entnum in self.restrict_ents):
                self.entcache[entnum] = B1GfxEntCache(self.readfile(filename), 2, 1)
            else:
                self.entcache[entnum] = B1GfxEntCache(self.readfile(filename))
        cache = self.entcache[entnum]
        if (size is None):
            size = self.tile_width
        return cache.getimg(direction, int(size*cache.size_scale), gdk)

    def get_avatar(self, avatarnum):
        if (avatarnum < 0 or avatarnum > 7):
            return None
        if (avatarnum not in self.avatarcache):
            if (avatarnum == 7):
                if (os.path.exists(os.path.join(self.eschalondata.gamedir, 'mypic.png'))):
                    self.avatarcache[avatarnum] = gtk.gdk.pixbuf_new_from_file(os.path.join(self.eschalondata.gamedir, 'mypic.png'))
                else:
                    return None
            else:
                self.avatarcache[avatarnum] = GfxCache(self.readfile('%d.png' % (avatarnum)), 60, 60, 1).pixbuf
        return self.avatarcache[avatarnum]