character-sheet
v1.7.4
Published
CharacterSheet library for assembling relationships between stats and modifiers.
Downloads
21
Maintainers
Readme
: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
// 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
// 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.
// 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
// 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
// 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.
// 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.
// 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
- modifies
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
.
// 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 theCharacterSheet Class
calledsirKnight
.
// 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
.
// 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.
// 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
// instantiate a character sheet for a player
const sirKnight = new TableDungeon();
Let's create some modifiers that
sirKnight
will be able to consume
// 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
// 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
// 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.
// 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