Register

Build-a-Bonus

An Add-on Module for Foundry Virtual Tabletop

Author: Zhell Project Source: Project URL Versions 11.315 - 11.315 (Verified 11.315) Last Updated 1 week ago

Build-a-Bonus

2022 Package Jam winner of the 'Most Polished' category and runner-up for 'Best Package'

A module for the Foundry dnd5e system. After installing this module, you can find a 'Build-a-Bonus' application in any actor's, items, or effect's header. This gives you the ability to apply a bonus to any attack roll, damage roll, saving throw DC, saving throw, ability check, or hit die roll, for bonuses that should apply only under specific circumstances. If a bonus is embedded in an item or effect, they transfer with the item/effect if placed on another actor.

Interested in following along with development of any of my modules? Join the Discord server.

Any bonuses you create will automatically be calculated and applied when you perform a relevant roll. The module uses filters to determine when and if a bonus should be applied. For example:

The Build-a-Bonus has countless options for how or what to apply and when. Scroll down to the bottom for the full list.

How to Use

Open any actor's sheet, any item sheet, or any effect config, then click the otter icon in the header. Choose the type of bonus you want to create, then fill out the name, description, and the bonus. Then start narrowing down when and how the bonus should apply, using the available filters.

If you need additional hints, hover over any of the labels to get tooltips. Not all filters are available for each type of bonus. Below is an example using the artificer's Alchemical Savant feature.

The Build-a-Bonus Sheet

Description Tab

This tab shows the current properties of the babonus. Note that these might be dependant on what kind of parent the bonus is embedded on.

Bonuses Tab

This tab allows for configuring the bonus that should be applying, assuming all filters are matched. Some babonus types also support dice modifiers.

Depending on the type you choose, Build-a-Bonus can add on top of the value or roll, or even several kinds at once. For example, for attack rolls, you can add bonuses on top of the roll itself, but also increase the critical range and the fumble range. This can be roll data and scale values, such as @abilities.int.mod, or just integers or dice expressions.

For damage rolls and hit dice rolls, you can also affect die modifiers. The supported modifiers are minimum and maximum values, rerolling, and explosive dice, as well as the quantity of the dice, and the size of dice.

The 'minimum' modifier will be forced to be no higher than the size of the die. E.g., if you input '99', then a d8 will still roll no higher than 8. You can maximize dice by inputting '-1'.

Configuration and Filters Tabs

These tabs are for configuring the filters on the babonus. The full list of filters can be found below.

For any fields that support roll data (such as bonuses or comparison fields detailed below), you can use the roll data of the target as well as your own; use roll data as you normally would, and for targets simply prefix with @target.

In addition, when a bonus is 'transferred' either via an effect being copied through a template aura or regular aura, the roll data used will be source's roll data, if any. This means that your paladin player can have their Aura of Protection set up using @abilties.cha.mod and all allies within the aura will receive a bonus equal to the paladin's Charisma modifier, not their own Charisma modifier.

One thing to keep in mind is that bonuses use the source's roll data, while the filters use the recipient's roll data.

Advanced Tab

This tab allows for toggling the bonus, making it exclusive to its parent item, making it opt-in, or configuring consumption or an aura.

You can set the bonus to act as an aura within a set range or within a template created by an item, and define if the aura should apply to allied targets, enemy targets, or all within range or within the template, and whether it applies to the owner or not. The bonus is applied when another token actor makes a relevant roll. The module never makes use of token movement to calculate ranges, so the usage of auras and templates is incredibly lightweight.

You can configure a list of effect statuses that prevent the aura from affecting targets and the owner (such as if the source of the aura is dead or unconscious). The Keys button on the sheet will help you pick out statuses from those that exist on the token HUD. The field itself is not validated; if you are able to give an effect a status of your own choosing, that is respected as well; simply write the status in the field.

Lastly, you can configure a non-template aura to require direct line of sight from the source token to the rolling token's actor, or to require an unobstructed path of movement.

If the bonus additively affects an attack roll, damage roll, saving throw, or ability check (adding a bonus on top), the bonus can be toggled to be optional. Other types of bonuses will apply regardless. The actor will then have the choice when adding the bonus, which is shown in the roll configuration dialog when making the roll.

If the bonus is optional as described above, the bonus can also be configured to consume limited uses, item quantity, spell slots, hit points, currencies, the active effect on which it is created, or even the inspiration granted to the character from the GM. You can configure the minimum required consumption, as well as the maximum if the bonus should scale. For example, if you create an item with 10 limited uses, a bonus of "1d6", configure that the bonus is optional, and consumes between 2 and 6 uses when opted into, the actor making the roll can easily add between 2d6 and 6d6 in the roll configuration dialog, and the expended uses are automatically subtracted. This works similarly for spell slots, instead using 1 slot and scaling with spell level. A bonus consuming its effect or GM inspiration cannot scale.

Available Filters

These are the available filters that narrow down if the bonus should apply when making a roll.

Abilities. The ability score used for the roll. This respects items set to use defaults, such as spells using the spellcasting ability, or finesse weapons using either Strength or Dexterity.

Arbitrary Comparisons. An array of arbitrary comparisons you can use for anything that is not covered in the Build-a-Bonus natively. This supports numbers, roll data, and strings. If you enter strings, you can use the inequalities to match substrings. It will otherwise attempt to determine numeric values after replacing roll data with the roll data of the item and actor performing the roll. For example, you can have a bonus apply only when the actor is below full health with @attributes.hp.value <= @attributes.hp.max. Unlike other filters, you can add this filter to the builder multiple times.

Attack Types. Filter the bonus to only apply if the item used to perform the roll has an attack roll of that specific kind.

Available Spell Slots. Filter the bonus to apply only if the actor performing the roll has more than the set minimum amount of spell slots available and/or less than the set maximum amount of spell slots available. Not both fields are required.

Base Armors. Filter the bonus to only apply if the actor is wearing a specific type of armor or a shield.

Base Tools. The type of tool the item must be for the bonus to apply. For example Herbalism Kit, Thieves' Tools, or Cobbler's Tools.

Base Weapons. Filter the bonus to only apply if the item is a weapon with one of these base weapon types, such as 'battleaxe' or 'blowgun'.

Conditions (Target). Filter the bonus to only apply if the target (of the client performing the roll) is affected by any of the included status conditions while having none of the excluded status conditions.

Conditions. Filter the bonus to only apply if the actor is affected by any of the included status conditions while having none of the excluded status conditions. This uses the statuses stored in status conditions, as detailed above.

Creature Sizes. Filter the bonus to only apply if the actor performing the roll is a certain size, like medium, huge, or gargantuan.

Creature Types (Target). Filter the bonus to only apply if you are targeting an enemy belonging to one of the included creature types, such as 'undead', 'fey', or 'humanoid', while not targeting any of the excluded creature types.

Creature Types. Filter the bonus to only apply if you are belonging to one of the included creature types, such as 'undead', 'fey', or 'humanoid', while not belonging to any of the excluded creature types.

Custom Scripts. A blank text field for users to write any JavaScript code they like. The script must be fully synchronous and return true or false. The available variables declared for the script will vary by the roll type, but actor, item, token, and bonus are always provided if possible, as well as an object, details, used for the iteration of parsing the validity of the bonuses. For those uncomfortable with having all clients execute these scripts, a setting is available for the module which will completely ignore the scripts and simply immediately return true.

Damage Types. Filter the bonus to only apply if the item used to perform the roll has a damage formula with any of the included damage types while having none of the excluded damage types.

Feature Types. Filter the bonus to only apply if the item used to perform the attack or damage roll (or prompt for a saving throw) is a feature-type item of a specific type, and optionally also a specific subtype.

Health Percentages. A percentage value and whether the actor must have at least or at most this amount of remaining hit points for the bonus to apply.

Item Types. The type of item the bonus should apply to. For example if you want to increase the save DC globally but only for equipment type items, not spells.

Proficiency Levels. The level of proficiency that the actor must have with the roll made. This is available for ability checks, saving throws, and attack rolls.

Save DC Ability. Filter the bonus such that it only applies if the DC is set using a specific ability. This respects spellcasting abilities in case the item has its save DC set using 'Spellcasting'.

Saving Throw Types. The type of saving throw the bonus should apply to (any ability score as well as death saving throws). If you are using the module Concentration Notifier, you can also apply a bonus specifically to saves for maintaining concentration.

Skills. The type of skill the roll must be for the bonus to apply. For example Athletics, Nature, or Survival.

Spell Components. Filter the bonus to only apply if the item is a spell that has any one (or all) of the given components.

Spell Levels. Filter the bonus to only apply if the item is a spell and is or was cast at one of the given levels.

Spell Preparation Modes. Filter the bonus to only apply if the item is a spell and is set as one of a selected few preparation modes such as 'pact magic' or 'innate'.

Spell Schools. Filter the bonus to only apply if the item is a spell belonging to one of the given spell schools.

Spoken Languages. Filter the bonus to only apply if the actor performing the roll is able to speak a certain language.

Token Sizes (Target). Filter the bonus to only apply if the target (of the client performing the roll) is a token of a certain size or greater (or smaller), and optionally clamped using the roller's token's size.

Weapon Properties. Filter the bonus to only apply if the item is a weapon that has at least one of the included weapon properties while having none of the excluded properties.

API

An API can be accessed at game.modules.get("babonus").api or through the global namespace babonus. The parameter object below refers to an Actor, ActiveEffect, Item, or MeasuredTemplateDocument. The methods are currently:

/**
 * Return a babonus that has the given id.
 * @param {Document} object     The document that has the babonus.
 * @param {string} id           The id of the babonus.
 * @returns {Babonus}           The found babonus.
 */
function getId(object, id)
/**
 * Return the ids of all bonuses on the document.
 * @param {Document} object     The document that has the babonuses.
 * @returns {string[]}          An array of ids.
 */
function getIds(object)
/**
 * Return a babonus that has the given name. If more are found, returns the first found.
 * @param {Document} object     The document that has the babonus.
 * @param {string} name         The name of the babonus.
 * @returns {Babonus}           The found babonus.
 */
function getName(object, name)
/**
 * Return the names of all bonuses on the document.
 * @param {Document} object     The document that has the babonuses.
 * @returns {string[]}          An array of names.
 */
function getNames(object)
/**
 * Return an array of the bonuses of a given type on the document.
 * @param {Document} object     The document that has the babonuses.
 * @param {string} type         The type of babonuses to find.
 * @returns {Babonus[]}         An array of babonuses.
 */
function getType(object, type)
/**
 * Return the collection of bonuses on the document.
 * @param {Document} object           An actor, item, effect, or template.
 * @returns {Collection<Babonus>}     A collection of babonuses.
 */
function getCollection(object)
/**
 * Return a babonus using its uuid.
 * @param {string} uuid                  The babonus uuid.
 * @returns {Promise<Babonus|null>}      The found babonus.
 */
async function fromUuid(uuid)
/**
 * Return a babonus using its uuid.
 * @param {string} uuid        The babonus uuid.
 * @returns {Babonus|null}     The found babonus.
 */
function fromUuidSync(uuid)
/**
 * Create a babonus in memory with the given data.
 * @param {object} data           An object of babonus data.
 * @param {Document} [parent]     The document to act as parent of the babonus.
 * @returns {Babonus}             The created babonus.
 */
function createBabonus(data, parent = null)
/**
 * Embed a created babonus onto the target object.
 * @param {Document} object         The actor, item, or effect that should have the babonus.
 * @param {Babonus} bonus           The created babonus.
 * @returns {Promise<Document>}     The actor, item, or effect that has received the babonus.
 */
async function embedBabonus(object, bonus)
/**
 * Copy a babonus from a document to another.
 * @param {Document} original       A measured template, active effect, actor, or item to copy from.
 * @param {Document} other          A measured template, active effect, actor, or item to copy to.
 * @param {string} id               The id of the babonus to copy.
 * @returns {Promise<Document>}     The original after the update.
 */
async function copyBonus(original, other, id)
/**
 * Delete a babonus from a document.
 * @param {Document} object         A measured template, active effect, actor, or item to delete from.
 * @param {string} id               The id of the babonus to remove.
 * @returns {Promise<Document>}     The updated document.
 */
async function deleteBonus(object, id)
/**
 * Move a babonus from a document to another.
 * @param {Document} original       A measured template, active effect, actor, or item to move from.
 * @param {Document} other          A measured template, active effect, actor, or item to move to.
 * @param {string} id               The id of the babonus to move.
 * @returns {Promise<Document>}     The other document after the update.
 */
async function moveBonus(original, other, id)
/**
 * Toggle a babonus on a document
 * @param {Document} object         A measured template, active effect, actor, or item.
 * @param {string} id               The id of the babonus to toggle.
 * @param {boolean} [state]         A specific toggle state to set a babonus to.
 * @returns {Promise<Document>}     The document after the update.
 */
async function toggleBonus(object, id, state = null)
/**
 * Return an object of arrays of items and effects on the given document
 * that have one or more babonuses embedded in them.
 * @param {Document} object     An actor or item with embedded documents.
 * @returns {object}            An object with an array of effects and array of items.
 */
function findEmbeddedDocumentsWithBonuses(object)
/**
 * Return all token documents that are in range of an aura.
 * This does not take sight and movement restrictions into account.
 * @param {Document} object         The actor, item, or effect with the babonus.
 * @param {string} id               The id of the babonus.
 * @returns {TokenDocument5e[]}     An array of token documents.
 */
function findTokensInRangeOfAura(object, id)
/**
 * Return an array of tokens that are within a radius of the source token.
 * Credit to @Freeze#2689 for much artistic aid.
 * @param {Token5e} source      The source token placeable.
 * @param {number} radius       The radius (usually feet) to extend from the source.
 * @param {string} [type]       The type of shape to use for locating ('circle' or 'rect').
 * @returns {Token5e[]}         An array of token placeables, excluding the source.
 */
function findTokensInRangeOfToken(source, radius, type = "circle")
/**
 * Render the build-a-bonus application for a document.
 * @param {Document} object       An actor, item, or effect.
 * @returns {BabonusWorkshop}     The rendered workshop.
 */
function openBabonusWorkshop(object)
/**
 * Return the ids of all templates on the scene if they contain the token document.
 * @param {TokenDocument5e} tokenDoc      The token document.
 * @param {object} [options]              Search options.
 * @param {boolean} [options.ids]         Whether to return ids or template documents.
 * @returns {string[]}                    An array of ids.
 */
function getAllContainingTemplates(tokenDoc, {ids = true} = {})
/**
 * Return the minimum distance between two tokens, evaluating height and all grid spaces they occupy.
 * @param {Token5e} tokenA        One token placeable.
 * @param {Token5e} tokenB        Another token placeable.
 * @param {object} [options]      Options to modify the measurements.
 * @returns {number}              The minimum distance (in units of measurement).
 */
function getMinimumDistanceBetweenTokens(tokenA, tokenB, options = {})
/**
 * Return the scene's token documents in four arrays split by disposition.
 * @param {Scene} scene     A scene that contains tokens.
 * @returns {object}        An object of the four arrays.
 */
function sceneTokensByDisposition(scene)
/**
 * Get the centers of all grid spaces that overlap with a token document.
 * @param {TokenDocument5e} tokenDoc      The token document on the scene.
 * @returns {object[]}                    An array of xy coordinates.
 */
function getOccupiedGridSpaces(tokenDoc)
/**
 * Does this actor speak a given language?
 * @param {Actor5e} actor     The actor to test.
 * @param {string} trait      The language to test.
 * @returns {boolean}
 */
function speaksLanguage(actor, trait)
/**
 * Does this actor have a given weapon proficiency?
 * @param {Actor5e} actor     The actor to test.
 * @param {string} trait      The trait to test.
 * @returns {boolean}
 */
function hasWeaponProficiency(actor, trait)
/**
 * Does this actor have a given armor proficiency?
 * @param {Actor5e} actor     The actor to test.
 * @param {string} trait      The trait to test.
 * @returns {boolean}
 */
function hasArmorProficiency(actor, trait)
/**
 * Does this actor have a given tool proficiency?
 * @param {Actor5e} actor     The actor to test.
 * @param {string} trait      The trait to test.
 * @returns {boolean}
 */
function hasToolProficiency(actor, trait)
/**
 * Retrieve a path through nested proficiencies to find a specific proficiency in a category.
 * E.g., 'smith' and 'tool' will return ['art', 'smith'], and 'aquan' and 'languages' will
 * return ['exotic', 'primordial', 'aquan'].
 * @param {string} key          The specific proficiency (can be a category), e.g., "smith" or "primordial".
 * @param {string} category     The trait category, e.g., "tool", "weapon", "armor", "languages".
 * @returns {string[]}
 */
function proficiencyTree(key, category)
/**
 * Hotbar method for toggling a bonus via uuid.
 * @param {string} uuid       Uuid of the bonus to toggle.
 * @returns {Promise<null|Babonus>}
 */
async function hotbarToggle(uuid)
/**
 * Create pixi circle with some size and restrictions, centered on a token.
 * @param {Token5e} token             The center.
 * @param {number} size               The range in feet.
 * @param {object} [restrictions]     Wall restrictions.
 * @returns {ClockwiseSweepPolygon}
 */
function createRestrictedCircle(token, size, restrictions = {})
/**
 * Create pixi rectangle with some size and restrictions, centered on a token.
 * @param {Token5e} token             The center.
 * @param {number} size               The range in feet.
 * @param {object} [restrictions]     Wall restrictions.
 * @returns {ClockwiseSweepPolygon}
 */
function createRestrictedRect(token, size, restrictions = {})
/**
 * Find tokens within a given circular distance from another token.
 * @param {Token5e} token             The token that is in the center of the circle.
 * @param {number} size               The radius of the circle, in feet.
 * @param {object} [restrictions]     Valid wall restrictions within the area.
 * @returns {Token5e[]}
 */
function findTokensCircle(token, size, restrictions = {})
/**
 * Find tokens within a given rectangular distance from another token.
 * @param {Token5e} token             The token that is in the center of the rectangle.
 * @param {number} size               The 'radius' of the rectangle, in feet.
 * @param {object} [restrictions]     Valid wall restrictions within the area.
 * @returns {Token5e[]}
 */
function findTokensRect(token, size, restrictions = {})
/**
 * Create a rectangle of a given size centered on a token.
 * @param {Token5e} token     The token that is in the center of the rectangle.
 * @param {number} size       The 'radius' of the rectangle, in feet.
 * @returns {PIXI}
 */
function createRect(token, size)

Within the API's filters object, you can find all the filtering functions used by the module internally. They are too numerous to list here.

Instance Methods

Instance methods are functions found directly on an instance of a created bonus.

  • Babonus#toggle enables or disables the bonus on its parent.
  • Babonus#update updates the bonus itself with the given new properties.
  • Babonus#delete removes the bonus off of its parent.
Hooks

The hook, babonus.applyOptionalBonus is called when applying an optional bonus; after updates or deletions are performed, but before the bonus is applied to the roll. It provides the babonus, the rolling item or actor, the item, actor, or effect that was updated or deleted, and an object with the bonus that will be applied. The bonus to be applied can be modified. Explicitly returning false will prevent the bonus from being applied entirely.

Two hooks are called during the filtering of the collected bonuses when making a relevant roll.

/**
 * A hook that is called before the collection of bonuses has been filtered.
 * @param {Collection<Babonus>} bonuses     The collection of bonuses, before filtering.
 * @param {Actor5e|Item5e} object           The actor or item performing the roll.
 * @param {object} [details]                Additional data passed along to perform the filtering.
 * @param {string} hookType                 The type of hook being executed ('attack',
 *                                          'damage', 'save', 'throw', 'test', 'hitdie').
 */
Hooks.callAll("babonus.preFilterBonuses", bonuses, object, details, hookType);
/**
 * A hook that is called after the collection of bonuses has been filtered.
 * @param {Babonus[]} bonuses         The array of bonuses, after filtering.
 * @param {Actor5e|Item5e} object     The actor or item performing the roll.
 * @param {object} [details]          Additional data passed along to perform the filtering.
 * @param {string} hookType           The type of hook being executed ('attack',
 *                                    'damage', 'save', 'throw', 'test', 'hitdie').
 */
Hooks.callAll("babonus.filterBonuses", bonuses, object, details, hookType);
`

Supported Game Systems

  1. Dungeons & Dragons Fifth Edition

    Latest Version: Version 3.2.0 Last Updated 1 week ago

Categories

Available Versions

  1. Version 11.11.1

    1 week ago
    Foundry Version 11.315 - 11.315 (Verified 11.315) Manifest URL Read Notes
  2. Version 11.11.0

    1 week, 6 days ago
    Foundry Version 11.315 - 11.315 (Verified 11.315) Manifest URL Read Notes
  3. Version 11.10.6

    3 weeks ago
    Foundry Version 11.315 - 11.315 (Verified 11.315) Manifest URL Read Notes
  4. Version 10.5.4

    1 year ago
    Foundry Version 10 - 10 (Verified 10.291) Manifest URL Read Notes