Skip to content

Commit

Permalink
Improvements to chat card displays and saving throws
Browse files Browse the repository at this point in the history
  • Loading branch information
aaclayton committed Nov 29, 2019
1 parent e96e57a commit f8889d1
Show file tree
Hide file tree
Showing 6 changed files with 80 additions and 174 deletions.
1 change: 1 addition & 0 deletions lang/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -139,6 +139,7 @@
"DND5E.Equipped": "Equipped",
"DND5E.Exhaustion": "Exhaustion",
"DND5E.Health": "Health",
"DND5E.Healing": "Healing",
"DND5E.HealthFormula": "Health Formula",
"DND5E.HitDice": "Hit Dice",
"DND5E.Inventory": "Inventory",
Expand Down
16 changes: 8 additions & 8 deletions module/dice.js
Original file line number Diff line number Diff line change
Expand Up @@ -24,18 +24,18 @@ export class Dice5e {
*/
static d20Roll({event, parts, data, template, title, speaker, flavor, advantage=true, situational=true,
fastForward=true, critical=20, fumble=1, onClose, dialogOptions, }) {
flavor = flavor || title;

// Inner roll function
let rollMode = game.settings.get("core", "rollMode");
let roll = (parts, adv) => {
let flav = ( flavor instanceof Function ) ? flavor(parts, data) : title;
if (adv === 1) {
parts[0] = ["2d20kh"];
flav = `${title} (Advantage)`;
flavor = `${title} (Advantage)`;
}
else if (adv === -1) {
parts[0] = ["2d20kl"];
flav = `${title} (Disadvantage)`;
flavor = `${title} (Disadvantage)`;
}

// Don't include situational bonus unless it is defined
Expand All @@ -52,7 +52,7 @@ export class Dice5e {
// Convert the roll to a chat message
roll.toMessage({
speaker: speaker,
flavor: flav,
flavor: flavor,
rollMode: rollMode
});
};
Expand Down Expand Up @@ -122,23 +122,23 @@ export class Dice5e {
* @param {Object} dialogOptions Modal dialog options
*/
static damageRoll({event={}, parts, actor, data, template, title, speaker, flavor, critical=true, onClose, dialogOptions}) {
flavor = flavor || title;

// Inner roll function
let rollMode = game.settings.get("core", "rollMode");
let roll = crit => {
let roll = new Roll(parts.join("+"), data),
flav = ( flavor instanceof Function ) ? flavor(parts, data) : title;
let roll = new Roll(parts.join("+"), data);
if ( crit === true ) {
let add = (actor && actor.getFlag("dnd5e", "savageAttacks")) ? 1 : 0;
let mult = 2;
roll.alter(add, mult);
flav = `${title} (Critical)`;
flavor = `${flavor} (Critical)`;
}

// Execute the roll and send it to chat
roll.toMessage({
speaker: speaker,
flavor: flav,
flavor: flavor,
rollMode: rollMode
});

Expand Down
43 changes: 32 additions & 11 deletions module/item/entity.js
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,16 @@ export class Item5e extends Item {

/* -------------------------------------------- */

/**
* Does the item provide an amount of healing instead of conventional damage?
* @return {boolean}
*/
get isHealing() {
return (this.data.data.actionType === "heal") && this.data.data.damage.parts.length;
}

/* -------------------------------------------- */

/**
* Does the Item implement a saving throw as part of its usage
* @type {boolean}
Expand Down Expand Up @@ -126,7 +136,10 @@ export class Item5e extends Item {

// Damage
let dam = item.data.damage || {};
if ( dam.parts ) labels.damage = dam.parts.map(d => d[0]).join(" + ").replace(/\+ -/g, "- ");
if ( dam.parts ) {
labels.damage = dam.parts.map(d => d[0]).join(" + ").replace(/\+ -/g, "- ");
labels.damageTypes = dam.parts.map(d => C.damageTypes[d[1]]).join(", ");
}
}

// Assign labels and return the Item
Expand All @@ -151,6 +164,7 @@ export class Item5e extends Item {
data: this.getChatData(),
labels: this.labels,
hasAttack: this.hasAttack,
isHealing: this.isHealing,
hasDamage: this.hasDamage,
isVersatile: this.isVersatile,
hasSave: this.hasSave
Expand Down Expand Up @@ -411,6 +425,7 @@ export class Item5e extends Item {
prof: actorData.attributes.prof
});
const title = `${this.name} - Damage Roll`;
const flavor = this.labels.damageTypes.length ? `${title} (${this.labels.damageTypes})` : title;

// Call the roll helper utility
Dice5e.damageRoll({
Expand All @@ -419,6 +434,7 @@ export class Item5e extends Item {
actor: this.actor,
data: rollData,
title: title,
flavor: flavor,
speaker: ChatMessage.getSpeaker({actor: this.actor}),
dialogOptions: {
width: 400,
Expand Down Expand Up @@ -582,7 +598,7 @@ export class Item5e extends Item {
template: "systems/dnd5e/templates/chat/tool-roll-dialog.html",
title: title,
speaker: ChatMessage.getSpeaker({actor: this.actor}),
flavor: (parts, data) => `${this.name} - ${CONFIG.DND5E.abilities[abl]} Check`,
flavor: `${this.name} - ${CONFIG.DND5E.abilities[abl]} Check`,
dialogOptions: {
width: 400,
top: options.event ? event.clientY - 80 : null,
Expand Down Expand Up @@ -626,17 +642,21 @@ export class Item5e extends Item {
// Get the Item
const item = actor.getOwnedItem(card.dataset.itemId);

// Get the target
const target = isTargetted ? this._getChatCardTarget(card) : null;
// Get card targets
const targets = isTargetted ? this._getChatCardTargets(card) : [];

// Attack and Damage Rolls
if ( action === "attack" ) await item.rollAttack({event});
else if ( action === "damage" ) await item.rollDamage({event});
else if ( action === "versatile" ) await item.rollDamage({event, versatile: true});
else if ( action === "formula" ) await item.rollFormula({event});

// Saving Throw
else if ( action === "save" ) await target.rollAbilitySave(button.dataset.ability, {event});
// Saving Throws for card targets
else if ( action === "save" ) {
for ( let t of targets ) {
await t.rollAbilitySave(button.dataset.ability, {event});
}
}

// Consumable usage
else if ( action === "consume" ) await item.rollConsumable({event});
Expand Down Expand Up @@ -680,14 +700,15 @@ export class Item5e extends Item {
/**
* Get the Actor which is the author of a chat card
* @param {HTMLElement} card The chat card being used
* @return {Actor|null} The Actor entity or null
* @return {Array.<Actor>} The Actor entity or null
* @private
*/
static _getChatCardTarget(card) {
static _getChatCardTargets(card) {
const character = game.user.character;
const controlled = canvas.tokens.controlled;
if ( controlled.length === 0 ) return character || null;
if ( controlled.length === 1 ) return controlled[0].actor;
else throw new Error(`You must designate a specific Token as the roll target`);
const targets = controlled.reduce((arr, t) => t.actor ? arr.concat([t.actor]) : arr, []);
if ( character && (controlled.length === 0) ) targets.push(character);
if ( !targets.length ) throw new Error(`You must designate a specific Token as the roll target`);
return targets;
}
}
186 changes: 33 additions & 153 deletions packs/monsters.db

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion system.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
"name": "dnd5e",
"title": "Dungeons & Dragons 5th Edition",
"description": "A comprehensive game system for running games of Dungeons & Dragons 5th Edition in the Foundry VTT environment.",
"version": 0.71,
"version": 0.72,
"author": "Atropos",
"templateVersion": 2,
"scripts": [],
Expand Down
6 changes: 5 additions & 1 deletion templates/chat/item-card.html
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,11 @@ <h3>{{item.name}}</h3>

<div class="card-buttons">
{{#if hasAttack}}<button data-action="attack">{{ localize "DND5E.Attack" }}</button>{{/if}}
{{#if hasDamage}}<button data-action="damage">{{ localize "DND5E.Damage" }}</button>{{/if}}
{{#if hasDamage}}
<button data-action="damage">
{{#if isHealing}}{{ localize "DND5E.Healing" }}
{{else}}{{localize "DND5E.Damage" }}{{/if}}
</button>{{/if}}
{{#if isVersatile}}<button data-action="versatile">{{ localize "DND5E.Versatile" }}</button>{{/if}}
{{#if hasSave}}
<button data-action="save" data-ability="{{data.save.ability}}" disabled>
Expand Down

0 comments on commit f8889d1

Please sign in to comment.