UNPKG

character-sheet

Version:

CharacterSheet library for assembling relationships between stats and modifiers.

450 lines (333 loc) 10.5 kB
# :game_die: Character-Sheet: Beta :game_die: :crown: Quickly define the relationships between stats. :crown: Manage inventories, talents, equipment, etc. :crown: Create items, skills, buffs. :crown: Save and export modified sheets. :triangular_flag_on_post: This library is still in beta. ## Concepts **Sheet** - A sheet is used to define stats. - Stats may have computable relationships between them. - For example: **hitpoints** can be based off of **constitution**. **Character** - A character is one instance of a sheet. - Characters may assign values to stats. - For example: You may set **constitution** from _8_ to _10_, which will cause **hitpoints** to rise from _80_ to _100_. **Stats** - A stat is a single named property on a character. - Computed stats must be numerical, but sheets may also store other types of information. - For example: **player level**, **character name**, or **experience**. **Modifiers** - Modifiers allow you to define sets of modifications to stats on a character. - They can be added or removed at any time. - For example: **talents**, **equipment**, **spells**, **items**, and **buffs**. **Inventory** - Inventories hold modifiers that are applied to a character. - Inventories may also serve as storage for modifiers that are set to inactive. - Example inventories: **equipment**, **active effects**, **bags**, or **class features**. ## Design a Sheet In the below snippet you will learn how to: - Generate a sheet - Define some stats ```js // import the library import CharacterSheet from 'character-sheet'; // generate a new sheet called "TableDungeons" const TableDungeons = CharacterSheet(); // define constitution TableDungeons.define('constitution').initially(10); // hp is based on constitution TableDungeons .define('hp') .initially(0) .using('constitution') .calculate((currentValue, constitution) { return currentValue + constitution * 10; }); ``` ## Create a Character A continuation of the previous example, here we'll: - Create a character - Derive a stats' computed value ```js // create a character called sirKnight const sirKnight = new TableDungeons(); // check what sirKnight's hp is sirKnight('hp').is(); // 125 ``` ## Save My Character After a sheet has been designed, and a character created, it can be exported and stored. ```js // export the sheet as an object const exportedSheet = sirKnight.export(); // { ... constitution: 10, hp: 125 } ``` **For in depth examples see below.** ## *Define* API - Used to define base stats on a Sheet ```js // define constitution TableDungeons.define('constitution').initially(10); ``` ### Chainable Heirarchy - `.define()` - `.describe()` - `.initially()` - `.add()` - `.subtract()` - `.divideBy()` - `.roundUp()` - `.roundDown()` - `.calculate()` - `.using()` - `.calculate()` #### .define(*stat* `String`) > Define a **stat** on a Sheet ```js // import the library import CharacterSheet from 'character-sheet'; // generate a new CharacterSheet Class const TableDungeons = CharacterSheet(); // generate a new CharacterSheet Class TableDungeons // a stat named constitution .define('player-name') // initial value of 10 .initially("Anonymous Player"); // a new character sheet const sirKnight = new TableDungeons(); // get player name sirKnight('player-name').is(); // "Anonymous Player" ``` #### .initially(*value* `String | Number | Boolean`) > Set the initial value of the *stat*. The type of value cannot change once set. ```js // import the library import CharacterSheet from 'character-sheet'; // generate a new Sheet const TableDungeons = CharacterSheet(); // define a string TableDungeons .define('player-name') .initially(''); // define a number TableDungeons .define('strength') .initially(10); // define a boolean TableDungeons .define('poisoned') .initially(false); ``` #### .add | .subtract | .divideBy (*value* `String | Number`) > Mathematical operation - `String` will add the computed value of another stat. - `Number` will add a static value. ```js // import the library import CharacterSheet from 'character-sheet'; // generate a new Sheet const TableDungeons = CharacterSheet(); // create a new character const sirKnight = new TableDungeons(); TableDungeons // define a stat named constitution .define('constitution') // initial value of 10 .initially(10); TableDungeons // define a stat named hp .define('hp') // initially 100 .initially(100) // + whatever constitution's calculated value is .add('constitution') // + 25 .add(25); ``` #### .roundUp(), .roundDown() > Round to a whole number, with the respective rule to describe which way to round. ## *Inventory* API > A storage mechanism that contains modifiers, defined in the CharacterSheet, and accessed on the character. ### Functional Heirarchy - `.give()` - `.of()` - `.filter()` - `.prune()` - `.remove()` - `.move()` - `.to()` - `.forEach()` - `.on()` - `.off()` ## *Modifier* API > Modifiers represent templates of modifications, that can be added to inventories. They are not in effect until added to an inventory that is on. ### Features - Create a modifier template which can be placed into any inventory - Describe which stat to modify and augment it with sequential mathematical operations - Switch default on or off ### Functional Heirarchy - modifier - modifies - add - subtract - divideBy - roundDown - roundUp - on - off ## *Modifier* API > Modifiers are placed exclusively on the character, and not on the CharacterSheet. They represent any mechanical adjustments to stats during computation. ### Features - Switch on or off - Move to another inventory - Destroy - Duplicate and place in desired inventory ### Functional Heirachy - on - off - moveTo - destroy - duplicate - to ## Example Character Sheets ### Example 1: Dungeons and Dragons - Stat Modifiers Let's replicate the functionality of Dungeons and Dragons style stat modifiers. The rule is: whatever your stat is, your stat modifier is that number divided by 2, rounded down, subtract 5. For example: - Stat is **15** - 15 / 2 = **7.5** - Round Down 7.5 = **7** - 7 - 5 = **2** - Stat Modifier is **2**. > Let's build our CharacterSheet Class, called `TableDungeons`. ```js // import the library import CharacterSheet from 'character-sheet'; // generate a new CharacterSheet Class const TableDungeons = CharacterSheet(); // define whatever stats to attach to CharacterSheet Class const stats = ['strength', 'dexterity', 'charisma']; // loop over each stat - 'strength', 'dexterity', 'charisma' stats.forEach(stat => { // define the stat - ex: 'strength' TableDungeons .define(stat) .initially(10); // define that stat modifier - ex: 'strength-modifier' TableDungeons // define the stat .define(`${stat}-modifier`) // set its initial value .initially(0) // pull stat into the calculation context .using(stat) // caclulate the final value .calculate(stat => (stat / 2) - 5); }); ``` > Let's create our `CharacterSheet Instance` of the `CharacterSheet Class` called `sirKnight`. ```js // sirKnights previously exported sheet const savedSheet = { strength: 8, dexterity: 10, charisma: 18 }; // instantiate a character sheet for a player const sirKnight = new TableDungeon(savedSheet); // the modifiers are calculated and vailable for query sirKnight('strength-modifier').is(); // -1 sirKnight('dexterity-modifier').is(); // 0 sirKnight('charisma-modifier').is(); // 4 ``` ### Example 2: Talents, Equipment, and Inventory In most table top games, there are ways to augment your character as you go. These kinds of things can include **inventory**, **spells**, **equipment**, **talents**, and so on. In this example we'll work with **passive talents**, active **equipment**, and an **inventory** which holds items not currently equipped. > Let's build our CharacterSheet Class, called `TableDungeons`. ```js // import the library import CharacterSheet from 'character-sheet'; // generate a new CharacterSheet Class const TableDungeons = CharacterSheet(); ``` > We'll add 3 inventories, with an `initially()` of `[]` to indiciate that these will hold modifiers. ```js // holds items that are not actively in use - we'll turn this one off() TableDungeons.define('inventory').initially([]).off(); // holds passive talents, on() by default TableDungeons.define('passive-talents').initially([]); // holds items that are actively in use, on() by default TableDungeons.define('equipment').initially([]); // health TableDungeons.define('hp').initially(100); // mana TableDungeons.define('mana').initially(250); ``` > We'll instantiate our good sir knight ```js // instantiate a character sheet for a player const sirKnight = new TableDungeon(); ``` > Let's create some modifiers that `sirKnight` will be able to consume ```js // create the Wand of Power sirKnight // let's give it a descriptive name .modifier('1h/wand-of-power') // and modify mana .modifies('mana') // by adding 100 to it .add(100); // no change - we have to give sirKnight // a wand in order for him to gain its bonus sirKnight('mana').is(); // 250 ``` > We'll equip the Wand of Power ```js // select the equipment inventory sirKnight('equipment') // sirKnight will gain 1 .give(1) // Wand of Power .of('1h/wand-of-power'); // the bonus is now being applied sirKnight('mana').is(); // 350 ``` > Let's take the wand off for now ```js // select the equipment inventory sirKnight('equipment') // find the 1h/wand-of-power .findOne('1h/wand-of-power') // and move to the inventory .giveTo('inventory'); // because inventory is .off() // the Wand of Power no longer // affects mana. sirKnight('mana').is(); // 250 ``` > The same thing can be done with talents. ```js // create the talent: Sturdy and Stout sirKnight // give it a descriptive namespace .modifier('talent/sturdy-and-stout') // modifies hp .modifies('hp') // adds 50 to hp .add(50) // also modifies mana .modifies('mana') // subtracts 50 from mana .subtract(50); // select sigKnight's equipment sirKnight('passive-talent') // give 1 .give(1) // Study and Stout .of('talent/sturdy-and-stout'); // it behaves just like the equipment // inventory. talents and items are really // the same thing. :)~ sirKnight('hp').is(); // 150 sirKnight('mana').is(); // 200 ```