Esempio n. 1
0
    def load(filename, req_book=None):
        """
        Static method to load a map file.  This will open the file once
        and read in a bit of data to determine which Eschalon game the mapfile
        comes from, and calls the appropriate constructor to return the object.
        If req_book is passed in, it will raise a LoadException if the detected
        Book number doesn't match.  This will also raise a LoadException if
        it's unable to determine the version (generally due to being passed
        something that's not a map file).

        Note that this method does not actually read in the entire map file.
        It does "preload" the map name, however, so that it can be easily
        referenced in lists.  Use .read() on the resulting map object to actually
        read in the map data.
        """

        # Get some information about the filename
        (detected_book, detected_mapname, df) = Map.get_mapinfo(filename)

        # See if we're required to conform to a specific book
        if (req_book is not None and detected_book != req_book):
            raise LoadException('This utility can only load Book %d map files; this file is from Book %d' % (req_book, detected_book))

        # Now actually return the object
        if detected_book == 1:
            c.switch_to_book(1)
            return B1Map(df)
        elif detected_book == 2:
            c.switch_to_book(2)
            return B2Map(df)
        elif detected_book == 3:
            c.switch_to_book(3)
            return B3Map(df)
        else:
            raise LoadException('Unknown book version found for "%s"; perhaps it is not an Eschalon map file' % (filename))
Esempio n. 2
0
 def new(filename, book, map_df=None, ent_df=None):
     """
     Sets up a new, blank Map object with the given book.  Will raise a
     LoadException if we're passed a book we don't know about.  Optionally
     pass in a datafile object to load our data from.
     """
     if map_df is None:
         df = Savefile(filename)
     else:
         df = map_df
     if book == 1:
         c.switch_to_book(1)
         return B1Map(df, ent_df)
     elif book == 2:
         c.switch_to_book(2)
         return B2Map(df, ent_df)
     elif book == 3:
         c.switch_to_book(3)
         return B3Map(df, ent_df)
     else:
         raise LoadException('Unknown book version specified: %d' % (book))
Esempio n. 3
0
 def new(filename, book, map_df=None, ent_df=None):
     """
     Sets up a new, blank Map object with the given book.  Will raise a
     LoadException if we're passed a book we don't know about.  Optionally
     pass in a datafile object to load our data from.
     """
     if map_df is None:
         df = Savefile(filename)
     else:
         df = map_df
     if book == 1:
         c.switch_to_book(1)
         return B1Map(df, ent_df)
     elif book == 2:
         c.switch_to_book(2)
         return B2Map(df, ent_df)
     elif book == 3:
         c.switch_to_book(3)
         return B3Map(df, ent_df)
     else:
         raise LoadException('Unknown book version specified: %d' % (book))
Esempio n. 4
0
    def load(filename, req_book=None):
        """
        Static method to load a map file.  This will open the file once
        and read in a bit of data to determine which Eschalon game the mapfile
        comes from, and calls the appropriate constructor to return the object.
        If req_book is passed in, it will raise a LoadException if the detected
        Book number doesn't match.  This will also raise a LoadException if
        it's unable to determine the version (generally due to being passed
        something that's not a map file).

        Note that this method does not actually read in the entire map file.
        It does "preload" the map name, however, so that it can be easily
        referenced in lists.  Use .read() on the resulting map object to actually
        read in the map data.
        """

        # Get some information about the filename
        (detected_book, detected_mapname, df) = Map.get_mapinfo(filename)

        # See if we're required to conform to a specific book
        if (req_book is not None and detected_book != req_book):
            raise LoadException(
                'This utility can only load Book %d map files; this file is from Book %d'
                % (req_book, detected_book))

        # Now actually return the object
        if detected_book == 1:
            c.switch_to_book(1)
            return B1Map(df)
        elif detected_book == 2:
            c.switch_to_book(2)
            return B2Map(df)
        elif detected_book == 3:
            c.switch_to_book(3)
            return B3Map(df)
        else:
            raise LoadException(
                'Unknown book version found for "%s"; perhaps it is not an Eschalon map file'
                % (filename))
Esempio n. 5
0
class Savename(object):
    book = None

    def __init__(self, df):
        """ A fresh object. """

        self.savename = ''
        self.savedate = ''
        self.savetime = ''
        self.mapname = ''
        self.totalsecs = 0
        self.totalturns = 0
        self.totaldays = 0
        self.coloration = 0
        self.narratives = []  # Has the player seen this narrative? 0=no, 1=yes
        self.quests = []
        self.npcs = []  # Has the player talked to this NPC? 0=no, 1=yes
        self.quicktravel = 0
        self.options = []  # volume controls, tactical grid, etc.
        self.unknowns = []
        self.df = df

    def replicate(self):
        newsn = Savename.load(self.df.filename, self.book)

        if self.book == 1:
            newsn = B1Savename(Savefile(self.df.filename))
        elif self.book == 2:
            newsn = B2Savename(Savefile(self.df.filename))
        elif self.book == 3:
            newsn = B3Savename(Savefile(self.df.filename))

        # Single vals (no need to do actual replication)
        newsn.savename = self.savename
        newsn.savedate = self.savedate
        newsn.savetime = self.savetime
        newsn.mapname = self.mapname
        newsn.totalsecs = self.totalsecs
        newsn.totalturns = self.totalturns
        newsn.totaldays = self.totaldays
        newsn.coloration = self.coloration
        newsn.quicktravel = self.quicktravel

        # Lists that need copying
        for val in self.options:
            newsn.options.append(val)
        for val in self.narratives:
            newsn.narratives.append(val)
        for val in self.quests:
            newsn.quests.append(val)
        for val in self.npcs:
            newsn.npcs.append(val)

        # Call out to the subclass replication function
        self._sub_replicate(newsn)

        # Now return our duplicated object
        return newsn

    def _sub_replicate(self, newsn):
        """
        Just a stub function for superclasses to override, to replicate any
        superclass-specific data
        """
        pass

    def write(self):
        raise NotImplementedError(
            'Writing savenames is not currently supported')

    @staticmethod
    def load(filename, book=None, req_book=None):
        """
        Static method to load a savename file.  This will open the file once and
        read in a bit of data to determine whether this is a Book 1 character file or
        a Book 2 character file, and then call the appropriate constructor and
        return the object.  The individual Book constructors expect to be passed in
        an 
        """
        df = Savefile(filename)

        # First figure out what format to load, if needed
        if book is None:
            try:
                df.open_r()
                name = df.readstr()
                date = df.readstr()
                time = df.readstr()
                map_or_version = df.readstr()
                df.close()
            except (IOError, struct.error), e:
                raise LoadException(str(e))

            if map_or_version.startswith('book3'):
                book = 3
            elif map_or_version in B1Constants.maps:
                book = 1
            else:
                book = 2

        # See if we're required to conform to a specific book
        if (req_book is not None and book != req_book):
            raise LoadException(
                'This utility can only load Book %d Character files; this file is from Book %d'
                % (req_book, book))

        # Now actually return the object
        if book == 1:
            c.switch_to_book(1)
            return B1Savename(df)
        elif book == 2:
            c.switch_to_book(2)
            return B2Savename(df)
        else:
            c.switch_to_book(3)
            return B3Savename(df)
Esempio n. 6
0
            if not Map.is_ascii(strings[9]):
                book = 2
            elif not Map.is_ascii(strings[10]):
                book = 1
            else:
                book = 3

        # See if we're required to conform to a specific book
        if req_book is not None and book != req_book:
            raise LoadException(
                "This utility can only load Book %d map files; this file is from Book %d" % (req_book, book)
            )

        # Now actually return the object
        if book == 1:
            c.switch_to_book(1)
            return B1Map(df)
        elif book == 2:
            c.switch_to_book(2)
            return B2Map(df)
        elif book == 3:
            c.switch_to_book(3)
            return B3Map(df)


class B1Map(Map):
    """
    Book 1 Map definitions
    """

    book = 1
Esempio n. 7
0
class Character(object):
    """
    The base Character class.  Interestingly, some items which are NOT stored in
    the char file:
      * Which map the character's currently on (orientation/position ARE stored here though)
      * Time of day in the game world
      * Total time spent playing the game

    Note that the base class does not define read() and write() methods, which
    are left up to the specific Book classes (the theory being that the actual
    underlying formats can be rather different, and it doesn't really make sense
    to try and work around that.
    """

    book = None
    form_elements = []

    def __init__(self, df):
        """ A fresh object. """

        #self.book = c.book
        self.name = ''
        self.strength = -1
        self.dexterity = -1
        self.endurance = -1
        self.speed = -1
        self.intelligence = -1
        self.wisdom = -1
        self.perception = -1
        self.concentration = -1
        self.skills = {}
        self.maxhp = -1
        self.maxmana = -1
        self.curhp = -1
        self.curmana = -1
        self.experience = -1
        self.level = -1
        self.gold = -1
        self.torches = -1
        self.torchused = -1
        self.readyslots = []
        self.inventory = []
        for i in range(self.inv_rows):
            self.inventory.append([])
            for j in range(self.inv_cols):
                self.inventory[i].append(Item.new(c.book))
        self.readyitems = []
        for i in range(self.ready_rows * self.ready_cols):
            self.readyitems.append(Item.new(c.book))
        self.curinvcol = 0
        self.curinvrow = 0
        self.quiver = Item.new(c.book)
        self.helm = Item.new(c.book)
        self.cloak = Item.new(c.book)
        self.amulet = Item.new(c.book)
        self.torso = Item.new(c.book)
        self.weap_prim = Item.new(c.book)
        self.belt = Item.new(c.book)
        self.gauntlet = Item.new(c.book)
        self.legs = Item.new(c.book)
        self.ring1 = Item.new(c.book)
        self.ring2 = Item.new(c.book)
        self.shield = Item.new(c.book)
        self.feet = Item.new(c.book)
        self.spells = []
        self.orientation = -1
        self.xpos = -1
        self.ypos = -1
        self.fxblock = []
        self.picid = -1
        self.statuses = []
        self.extra_att_points = -1
        self.extra_skill_points = -1
        self.df = df

    def set_inv_size(self, rows, cols, ready_rows, ready_cols):
        """
        Sets the size of the inventory array
        """
        self.inv_rows = rows
        self.inv_cols = cols
        self.ready_rows = ready_rows
        self.ready_cols = ready_cols

    def replicate(self):
        newchar = Character.load(self.df.filename, self.book)

        if self.book == 1:
            newchar = B1Character(Savefile(self.df.filename))
        elif self.book == 2:
            newchar = B2Character(Savefile(self.df.filename))
        elif self.book == 3:
            newchar = B3Character(Savefile(self.df.filename))

        # Single vals (no need to do actual replication)
        #newchar.book = self.book
        newchar.inv_rows = self.inv_rows
        newchar.inv_cols = self.inv_cols
        newchar.name = self.name
        newchar.strength = self.strength
        newchar.dexterity = self.dexterity
        newchar.endurance = self.endurance
        newchar.speed = self.speed
        newchar.intelligence = self.intelligence
        newchar.wisdom = self.wisdom
        newchar.perception = self.perception
        newchar.concentration = self.concentration
        newchar.maxhp = self.maxhp
        newchar.maxmana = self.maxmana
        newchar.curhp = self.curhp
        newchar.curmana = self.curmana
        newchar.experience = self.experience
        newchar.level = self.level
        newchar.gold = self.gold
        newchar.torches = self.torches
        newchar.torchused = self.torchused
        newchar.curinvcol = self.curinvcol
        newchar.curinvrow = self.curinvrow
        newchar.orientation = self.orientation
        newchar.xpos = self.xpos
        newchar.ypos = self.ypos
        newchar.picid = self.picid
        newchar.extra_att_points = self.extra_att_points
        newchar.extra_skill_points = self.extra_skill_points

        # Lists that need copying
        for val in self.spells:
            newchar.spells.append(val)
        for val in self.fxblock:
            newchar.fxblock.append(val)
        for val in self.statuses:
            newchar.statuses.append(val)

        # More complex lists that need copying
        for val in self.readyslots:
            newchar.readyslots.append([val[0], val[1]])

        # Dicts that need copying
        for key, val in self.skills.iteritems():
            newchar.skills[key] = val

        # Objects that need copying
        for i in range(self.inv_rows):
            for j in range(self.inv_cols):
                newchar.inventory[i][j] = self.inventory[i][j].replicate()
        for i in range(self.ready_rows * self.ready_cols):
            newchar.readyitems[i] = self.readyitems[i].replicate()
        newchar.quiver = self.quiver.replicate()
        newchar.helm = self.helm.replicate()
        newchar.cloak = self.cloak.replicate()
        newchar.amulet = self.amulet.replicate()
        newchar.torso = self.torso.replicate()
        newchar.weap_prim = self.weap_prim.replicate()
        newchar.belt = self.belt.replicate()
        newchar.gauntlet = self.gauntlet.replicate()
        newchar.legs = self.legs.replicate()
        newchar.ring1 = self.ring1.replicate()
        newchar.ring2 = self.ring2.replicate()
        newchar.shield = self.shield.replicate()
        newchar.feet = self.feet.replicate()

        # Call out to the subclass replication function
        self._sub_replicate(newchar)

        # Now return our duplicated object
        return newchar

    def _sub_replicate(self, newchar):
        """
        Just a stub function for superclasses to override, to replicate any
        superclass-specific data
        """
        pass

    def setGold(self,goldValue):
        """ Alter gold to new amount. """
        self.gold = goldValue

    def setMaxMana(self,manaValue):
        """
        Alter max mana value & set current to max.
        Note that equipped-item modifiers will raise the actual in-game
        maximums.
        """
        self.maxmana = manaValue
        if (self.curmana < manaValue):
            self.setCurMana(manaValue)

    def setCurMana(self,manaValue):
        """ Replenish mana to input value. """
        self.curmana = manaValue

    def setMaxHp(self,hpValue):
        """
        Alter max HP & set current to max.
        Note that equipped-item modifiers will raise the actual in-game
        maximums.
        """
        self.maxhp = hpValue
        if (self.curhp < hpValue):
            self.setCurHp(hpValue)

    def setCurHp(self,hpValue):
        """ Replenish HP to input value. """
        self.curhp = hpValue

    def clearDiseases(self):
        """
        Clear all diseases.  Also clears out severe injuries/curses/etc on Book 2 chars
        """
        if self.book == 1:
            self.disease = 0x0000
        else:
            self.permstatuses = self.permstatuses & 0xFFFF0000

    def resetHunger(self):
        """
        Resets hunger and thirst; only valid for Book 2 characters, of course.
        """
        if self.book > 1:
            self.hunger = 1000
            self.thirst = 1000

    def addskill(self, skillnum, level):
        """ Add a new skill at a given level. """
        self.skills[skillnum] = level

    def addreadyslot(self, spell, level):
        """ Add a new spell to a 'ready' slot. """
        self.readyslots.append([spell, level])

    def additem(self):
        """ Add a new item, assuming that the items are stored in a
            left-to-right, top-to-bottom format on the inventory screen. """
        self.inventory[self.curinvrow][self.curinvcol].read(self.df)
        self.curinvcol = self.curinvcol + 1
        if (self.curinvcol == self.inv_cols):
            self.curinvcol = 0
            self.curinvrow = self.curinvrow + 1

    @staticmethod
    def load(filename, book=None, req_book=None):
        """
        Static method to load a character file.  This will open the file once and
        read in a bit of data to determine whether this is a Book 1 character file or
        a Book 2 character file, and then call the appropriate constructor and
        return the object.  The individual Book constructors expect to be passed in
        an 
        """
        df = Savefile(filename)

        # First figure out what format to load, if needed
        if book is None:
            # The initial "zero" padding in Book 1 is four bytes, and only one byte in
            # Book 2.  Since the next bit of data is the character name, as a string,
            # if the second byte of the file is 00, we'll assume that it's a Book 1 file,
            # and Book 2 otherwise.
            try:
                df.open_r()
                initital = df.readuchar()
                second = df.readuchar()
                df.close()
            except (IOError, struct.error), e:
                raise LoadException(str(e))

            if second == 0:
                book = 1
            else:
                book = 2

        # See if we're required to conform to a specific book
        if (req_book is not None and book != req_book):
            raise LoadException('This utility can only load Book %d Character files; this file is from Book %d' % (req_book, book))

        # Now actually return the object
        if book == 1:
            c.switch_to_book(1)
            return B1Character(df)
        elif book == 2:
            c.switch_to_book(2)
            return B2Character(df)
        else:
            c.switch_to_book(3)
            return B3Character(df)