def create_spell(**params): """Create a new subclass of ``Spell`` with given default parameters. Useful for spells that haven't been entered into the ``spells.py`` file yet. Parameters ---------- params : optional Saved as attributes of the new class. Returns ------- NewSpell New spell class, subclass of ``Spell``, with given params. """ NewSpell = type('UnknownSpell', (Spell,), params) return NewSpell class Spell(): """A magical spell castable by a player character.""" level = 0 name = "Unknown spell" casting_time = "1 action" casting_range = "60 ft" components = () materials = "" duration = "instantaneous" ritual = False magic_school = "" classes = () def __str__(self): s = self.name + ' ({:s}) '.format(','.join(self.components)) # Indicate if this is a ritual or a concentration indicators = [('R', self.ritual), ('C', self.concentration), ('$', self.special_material)] indicators = tuple(letter for letter, is_active in indicators if is_active) if len(indicators): s += f' ({", ".join(indicators)})' return s def __repr__(self): return f'<{self.name}>' @property def component_string(self): s = f'{", ".join(self.components)}' if "M" in self.components: s += f' ({self.materials})' return s @property def concentration(self): return ('concentration' in self.duration.lower()) @property def special_material(self): return ('worth at least' in self.materials.lower())