.. _character_module: ########################## ``character`` ########################## .. py:module:: opend6_tools.character :no-index: The :py:mod:`opend6_tools.character` module provides the DSL definitions for characters and creatures. The module has a number of features for creating formatted displays of characters, working with creature or character definitions as command-line application, and extracting definitions from a Jupyter Lab notebook. Dice ==== This is -- to an extent -- a duplicate of the :py:mod:`opend6_tools.magic2.dice` definitions. The supplemental material is the :py:class:`Roll` class hierarchy. .. uml:: @startuml 'https://plantuml.com/class-diagram title The DieCode DSL class Roll class CriticalSuccess Roll <|-- CriticalSuccess class CriticalFailure Roll <|-- CriticalFailure class DieCode DieCode --> Roll : "Creates" @enduml The :py:class:`DieCode` is more than merely a definition of dice. It can also roll to generate values for strength damage and body. This includes the *OpenD6* "Wild Die" rules, creating values with a somewhat larger distribution than a handful of dice. Defining Characters and Creatures ================================= Because the **make** tool relies on file definitions, it helps to isolate creature and character definitions into distinct Python modules. Any of a number of organizing principles could be used for creatures, including likely environments, or the number of dice in their budget. Keeping creature and character definitions in separate files makes testing and publication relatively straightforward because the **make** tool can build the required RST-format files automatically. This leads to the following ways in which the :py:mod:`opend6_tools.character` module is used: - An character or creature module imports the :py:mod:`opend6_tools.character` module to define character or creatures. Ordinary software testing techniques validate sure the syntax is correct. A ``__test__`` block can be used to apply doctest tools can for validating the dice budget. - The character or creature module is **also** an application with a CLI that can emit RST-format files for publication, debugging output, or detailed displays of the definitions. The top-level organization of Character and Creature modules in the context of campaign books is what a software architect might call an "aggregate root." A module is a container for one or more related Characters or Creatures. The source is a ``creatures_subsection.py`` file with the Python version of the creature definitions. .. uml:: @startuml 'https://plantuml.com/class-diagram title Campaign Documents package python { package opend6_tools { component character } } package document_source { artifact index.rst <> artifact characters.rst <> index.rst -> characters.rst : """toctree::"" directive" package characters { component characters_subsection.py <> { component SomeCharacter } artifact characters_subsection.txt <> characters_subsection.py ..> character : import } characters_subsection.py -> characters_subsection.txt : "Run with 'display'" characters.rst --> characters_subsection.txt : """include::"" directive" } @enduml Often, the characters or creatures are created interactively, using Jupyter Lab. This means the :py:mod:`opend6_tools.notebook_extract` builds the module from the notebook. For more information, see :ref:`notebook_extract_app`. The structure within the character or creature definition module is often a Python list object. A Character is an object with a number of other ``Attributes`` and ``Options``. Here is the essential structure: .. uml:: @startuml 'https://plantuml.com/class-diagram title Character or Creature Module Components object "list[Creature]" as book object Creature { name attributes options } book *-- "1..m" Creature object Attribute { description dice } Creature *-- "6..7" Attribute object Option { description dice } Creature *-- "0..m" Option object "~_~_test~_~_" as test book <.. test object app { display debug } book <.. app @enduml The :py:class:`Character` definition is almost identical to the :py:class:`Creature` definition. A creature can have a collection of abilities that are natural abilities. These come from the pool of Special Ability definitions, but don't have an associated cost. Character and Creature DSL --------------------------- A Character (and a Creature) is a collection of descriptive strings. For the purposese of computing the dice budget, there are :py:class:`Attribute` objects and a number of distinct :py:class:`OptionList` objects. .. uml:: @startuml 'https://plantuml.com/class-diagram title Character or Creature classes class Character { name: str occupation: str race: str gender: str age: str height: str weight: str physical_description: str agility: Agility intellect: Intellect coordination: Coordination acumen: Acumen physique: Physique charisma: Charisma extranormal: Magic | Miracles advantages: OptionList disadvantages: OptionList special_abilities: OptionList equipment: str description: str realm: str fate_points: int character_points: int .. computable .. move: int strength_damage: DieCode body: int finds: DieCode } abstract class Attribute Attribute <|-- Agility Attribute <|-- Coordination Attribute <|-- Physique Attribute <|--- Intellect Attribute <|--- Acumen Attribute <|--- Charisma Attribute <|---- Magic Attribute <|---- Miracles Character *-- "{6..7}" Attribute /'Character *-- Agility Character *-- Intellect Character *-- Coordination Character *-- Acumen Character *-- Physique Character *-- Charisma Character *-- Magic Character *-- Miracles '/ Character *-- OptionList : "advantages\ndisadvantages\nspecial_abilities" class OptionList <> abstract class CharacterOption OptionList *-- "0..m" CharacterOption abstract class Disadvantage CharacterOption <|-- Disadvantage abstract class Advantage CharacterOption <|-- Advantage abstract class SpecialAbility CharacterOption <|-- SpecialAbility class Creature { natural_abilities: OptionList } Character <|-- Creature Creature -- OptionList : "natural abilities" @enduml The character has a wide variety of features. Attributes ---------- A Character (and most creatures) have six required attributes. There are three physical and three mental attributes. Optionally, some characters or creatures may have an *Extranormal*, attribute. While the game play consequence of each attribute are profound, from the perspective of defining a character, they're all essentially identical. .. uml:: @startuml 'https://plantuml.com/class-diagram title Character or Creature Attributes abstract class Attribute { skills: dict[str, DieCode } class DieCode { dice: int pips: int } Attribute *- DieCode Attribute <|-- Agility Attribute <|-- Coordination Attribute <|-- Physique Attribute <|--- Intellect Attribute <|--- Acumen Attribute <|--- Charisma Attribute <|---- Magic Attribute <|---- Miracles @enduml The attributes (and skills) have a simple, uniform definition. Each skill description has a name and a :py:class:`DieCode` cost. During game play, the skill defines how many dice are rolled to overcome difficulties. Any skill without a specific budget defaults to the :py:class:`DieCode` cost of the controlling :py:class:`Attribute` for that skill. Options ------- Beyond the core attributes, a character or creature may have options. There are three distinct types of character options. For creatures (and some non-human characters) an option may be identified as a "natural ability". This small shift in terminology permits pigs to fly, by calling the special ability of flight a natural ability. .. uml:: @startuml 'https://plantuml.com/class-diagram title Character or Creature Advantages and Limitations abstract class CharacterOption { rank: int notes: str dice: DieCode } abstract class Disadvantage CharacterOption <|-- Disadvantage abstract class Advantage CharacterOption <|-- Advantage abstract class SpecialAbility CharacterOption <|-- SpecialAbility @enduml Each of these subclasses -- :py:class:`Disadvantage`, :py:class:`Advantage`, and :py:class:`SpecialAbility` -- is the parent of a flat collection of subclasses. The only unique feature to each subclass is the costs-per-rank of the option. Here are the subclasses of ``Disadvantage``: - AchillesHeel - AdvantageFlaw - Age - BadLuck - BurnOut - CulturalUnfamiliarity - Debt - Devotion - Employed - Enemy - Hindrance - Infamy - LanguageProblems - LearningProblems - Poverty - Prejudice - Price - Quirk - ReducedAttribute Outside the Fantasy rules, this additional disadvantage is added in the unpublished Magic rules. - MinorStigma Here are the subclasses of ``Advantage``: - Authority - Contacts - Cultures - Equipment - Fame - Patron - Size - TrademarkSpecialization - Wealth The Special Abilities include a class-level ``rank_cost`` value that's not simply set to one. Each special ability has a distinct rank cost. Here are the subclasses of ``SpecialAbility``: - AcceleratedHealing - Ambidextrous - AnimalControl - ArmorDefeatingAttack - AtmosphericTolerance - AttackResistance - AttributeScramble - Blur - CombatSense - Confusion - Darkness - Elasticity - Endurance - EnhancedSense - EnvironmentalResistance - ExtraBodyPart - ExtraSense - FastReactions - Fear - Flight - GliderWings - Hardiness - Hypermovement - Immortality - Immunity - IncreasedAttribute - InfravisionUltravision - Intangibility - Invisibility - IronWill - LifeDrain - Longevity - LuckGood - LuckGreat - MasterOfDisguise - MultipleAbilities - NaturalArmor - NaturalHandWeapon - NaturalMagick - NaturalRangedWeapon - Omnivorous - ParalyzingTouch - PossessionLimited - PossessionFull - QuickStudy - SenseOfDirection - Shapeshifting - Silence - SkillBonus - SkillMinimum - Teleportation - Transmutation - UncannyAptitude - Ventriloquism - WaterBreathing - YouthfulAppearance Display and Output ================== The output features of this module perform a number of output conversions for characters and creature definitions. .. uml:: @startuml 'https://plantuml.com/class-diagram title character module output features class CharacterWriter { base_template: str list_template: str dict_template: str report(spell | book) -> str } class CharacterWriter_Short CharacterWriter <|-- CharacterWriter_Short class CharacterWriter_Long2 CharacterWriter <|-- CharacterWriter_Long2 class CharacterWriter_Table CharacterWriter <|-- CharacterWriter_Table class CharacterWriter_Literal CharacterWriter <|-- CharacterWriter_Literal class "detail(character | creature)" as detail << (F,orchid) Function >> hide detail empty members detail --> CharacterWriter class "display(character | book)" as display << (F,orchid) Function >> hide display empty members class "debug(character | book)" as debug << (F,orchid) Function >> hide debug empty members debug --> display class "sheet(character)" as sheet << (F,orchid) Function >> hide sheet empty members sheet --> CharacterWriter @enduml Plus functions summary(), detail(), sheet() And display(), debug() Workbook Features ================== This module has a few functions for extracting characters or creatures from a Jupyter Lab Notebook. Generally, these functions are designed to be part of a notebook, and introspect the notebook by looking at the ``globals()`` mapping. Application Wrapper =================== This module has a few functions to build elements of a spellbook application. These functions serve to create a CLI application using the ``typer`` library. Generally, these are used as follows: .. code-block:: python from opend6_tools.character import * # Character or Creature definitions creatures = [...] if __name__ == "__main__": app = build_app(creatures) app() This will -- when run from the command line -- build the application around spells (or items) defined in the module. It will then launch the application. This will parse command-line parameters and execute one various alternative sub-commands: ``test``, ``debug``, or ``display``. Implementation ============== .. automodule:: opend6_tools.character