Example #1
0
class Character(object):
    def __init__(self):
        self.graph = DAG.DAG()
        self.MiscVals = {
            'Name': '',
            'PlayerName': '',
            'Profession': '',
            'Level': 0,
            'Experience': 0
        }
        self.Events = EventHandler()

    def SetMisc(self, key, val):
        if key in self.MiscVals:
            self.MiscVals[key] = val
            self.Events('Misc Changed')
        else:
            raise KeyError(val)

    def GetMisc(self, key):
        return self.MiscVals[key]

    def Update(self):
        self.Events.Execute()

    def __getitem__(self, key):
        return self.graph[key]

    def MoveTo(self, nodeA, nodeB, before=False):
        res = self.graph.MoveTo(nodeA, nodeB, before)
        if res:
            self.Events('Values Reordered', nodeA, nodeB, before)
            #Reordering the weapons changes the weapon costs.
            for val in self.Values:
                if 'Weapon' in val.Options:
                    val.Changed()

    @property
    def Values(self):
        return iter(self.graph)

    @property
    def Skills(self):
        return (val for val in self.graph if isinstance(val, Skill))

    @property
    def Stats(self):
        return (val for val in self.graph if isinstance(val, Stat))

    @property
    def Resistances(self):
        return (val for val in self.graph if isinstance(val, Resistance))

    @property
    def Items(self):
        return (val for val in self.graph if isinstance(val, Item))

    @property
    def Talents(self):
        return (val for val in self.graph if isinstance(val, Talent))

    @property
    def Culture(self):
        try:
            return self._culture
        except AttributeError:
            return None

    @Culture.setter
    def Culture(self, val):
        if self.Culture is not None:
            self.RemoveVal(self.Culture)
        self._culture = val
        self.AddVal(val)

    @property
    def Race(self):
        try:
            return self._race
        except AttributeError:
            return None

    @Race.setter
    def Race(self, val):
        if self.Race is not None:
            self.RemoveVal(self.Race)
        self._race = val
        self.AddVal(val)

    def AddVal(self, newVal):
        """
        Adds the value to the list of values.
        Also, links the parent values together.
        Raises the 'Skill Added','Stat Added', or 'Resistance Added' event.
        """
        newVal.char = self
        self.graph.Add(newVal)
        self.Events('{0} Added'.format(newVal.Type), newVal)
        newVal.Events = self.Events

    def RemoveVal(self, val):
        """
        Removes the value given.
        Also, removes all children of the given value.
        Raises the 'Value Removed' event, first of the children, then of itself.
        """
        self.graph.Remove(val)
        for ch in val.Children:
            self.RemoveVal(ch)
        self.Events('{0} Removed'.format(val.Type), val)

    def ApplyLevelUp(self):
        """
        Applies the increase in level as given by the Delta of each Value.
        Increments the Level by 1.
        """
        for val in self.graph:
            val.ApplyLevelUp()
        self.SetMisc('Level', self.GetMisc('Level') + 1)

    def LoadProfession(self, prof):
        """
        Expects a dictionary from skill names to a list of skill costs.
        """
        for val in self.Values:
            val.Costs = None
        self.SetMisc("Profession", prof.Name)
        weaponcosts = []
        for skill, costs in prof.Costs:
            if skill.startswith("Combat Training"):
                weaponcosts.append(costs)
            else:
                try:
                    self[skill].Costs = costs[:]
                except KeyError:
                    pass
        self.WeaponCostList = weaponcosts

    @property
    def WeaponCostList(self):
        try:
            return self._WeaponCostList
        except AttributeError:
            self._WeaponCostList = []
            return self._WeaponCostList

    @WeaponCostList.setter
    def WeaponCostList(self, val):
        """
        Set the cost of increasing each weapon skill.
        The input should be a list of lists,
          with each outer list corresponding to a weapon,
          and each inner list corresponding to the skill cost list.
        """
        self._WeaponCostList = val
        for val in self.Values:
            if 'Weapon' in val.Options:
                val.Changed()

    def WeaponCost(self, sk):
        i = -1
        weaponGen = (val for val in self.Values if 'Weapon' in val.Options)
        for weapon, cost in zip(weaponGen, self.WeaponCostList):
            if weapon is sk:
                return cost
        else:
            return []

    def StatPoints(self, unlevelled=False, potl=False):
        return sum(st.Points(unlevelled, potl) for st in self.Stats)

    def StatPointsAllowed(self, level=None, potl=False):
        if potl:
            return 355
        else:
            level = self.GetMisc('Level') if level is None else level
            return 55 if level == 1 else 12

    def DPspent(self):
        return sum(sk.DP for sk in self.Skills) + sum(sk.DP
                                                      for sk in self.Talents)

    def DPallowed(self):
        return 50

    def SaveString(self):
        lines = [
            '{0}: {1}'.format(Parser.escape_ID(k), Parser.escape_ID(str(v)))
            for k, v in self.MiscVals.items()
        ]
        lines += [
            'WeaponCosts: ' + ' '.join('<' + ','.join(str(i)
                                                      for i in ilist) + '>'
                                       for ilist in self.WeaponCostList)
        ]
        #Escape all the character-based lines.
        #The Value-based lines are escaped in Value.SaveString()
        lines += [val.SaveString() for val in self.graph]
        return '\n'.join(lines)

    @staticmethod
    def Open(filename):
        """Given a filename, constructs and returns the character as read from the file"""
        return Parser.characterFile(filename)