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)