forked from GitHub-Mirrors/foundry-sw5e
DND5e Core 1.2.2
DND5e Core 1.2.2 modded to SW5e system
This commit is contained in:
parent
ab510e336c
commit
063f924183
58 changed files with 337 additions and 155 deletions
|
@ -1,6 +1,5 @@
|
|||
import {d20Roll, damageRoll} from "../dice.js";
|
||||
import {simplifyRollFormula, d20Roll, damageRoll} from "../dice.js";
|
||||
import AbilityUseDialog from "../apps/ability-use-dialog.js";
|
||||
import AbilityTemplate from "../pixi/ability-template.js";
|
||||
|
||||
/**
|
||||
* Override and extend the basic :class:`Item` implementation
|
||||
|
@ -227,6 +226,9 @@ export default class Item5e extends Item {
|
|||
// Saving throws
|
||||
this.getSaveDC();
|
||||
|
||||
// To Hit
|
||||
this.getAttackToHit();
|
||||
|
||||
// Damage
|
||||
let dam = data.damage || {};
|
||||
if ( dam.parts ) {
|
||||
|
@ -274,6 +276,74 @@ export default class Item5e extends Item {
|
|||
|
||||
/* -------------------------------------------- */
|
||||
|
||||
/**
|
||||
* Update a label to the Item detailing its total to hit bonus.
|
||||
* Sources:
|
||||
* - item entity's innate attack bonus
|
||||
* - item's actor's proficiency bonus if applicable
|
||||
* - item's actor's global bonuses to the given item type
|
||||
* - item's ammunition if applicable
|
||||
*
|
||||
* @returns {Object} returns `rollData` and `parts` to be used in the item's Attack roll
|
||||
*/
|
||||
getAttackToHit() {
|
||||
const itemData = this.data.data;
|
||||
if ( !this.hasAttack || !itemData ) return;
|
||||
const rollData = this.getRollData();
|
||||
|
||||
// Define Roll bonuses
|
||||
const parts = [];
|
||||
|
||||
// Include the item's innate attack bonus as the initial value and label
|
||||
if ( itemData.attackBonus ) {
|
||||
parts.push(itemData.attackBonus)
|
||||
this.labels.toHit = itemData.attackBonus;
|
||||
}
|
||||
|
||||
// Take no further action for un-owned items
|
||||
if ( !this.isOwned ) return {rollData, parts};
|
||||
|
||||
// Ability score modifier
|
||||
parts.push(`@mod`);
|
||||
|
||||
// Add proficiency bonus if an explicit proficiency flag is present or for non-item features
|
||||
if ( !["weapon", "consumable"].includes(this.data.type) || itemData.proficient ) {
|
||||
parts.push("@prof");
|
||||
}
|
||||
|
||||
// Actor-level global bonus to attack rolls
|
||||
const actorBonus = this.actor.data.data.bonuses?.[itemData.actionType] || {};
|
||||
if ( actorBonus.attack ) parts.push(actorBonus.attack);
|
||||
|
||||
// One-time bonus provided by consumed ammunition
|
||||
if ( (itemData.consume?.type === 'ammo') && !!this.actor.items ) {
|
||||
const ammoItemData = this.actor.items.get(itemData.consume.target)?.data;
|
||||
|
||||
if (ammoItemData) {
|
||||
const ammoItemQuantity = ammoItemData.data.quantity;
|
||||
const ammoCanBeConsumed = ammoItemQuantity && (ammoItemQuantity - (itemData.consume.amount ?? 0) >= 0);
|
||||
const ammoItemAttackBonus = ammoItemData.data.attackBonus;
|
||||
const ammoIsTypeConsumable = (ammoItemData.type === "consumable") && (ammoItemData.data.consumableType === "ammo")
|
||||
if ( ammoCanBeConsumed && ammoItemAttackBonus && ammoIsTypeConsumable ) {
|
||||
parts.push("@ammo");
|
||||
rollData["ammo"] = ammoItemAttackBonus;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Condense the resulting attack bonus formula into a simplified label
|
||||
let toHitLabel = simplifyRollFormula(parts.join('+'), rollData).trim();
|
||||
if (toHitLabel.charAt(0) !== '-') {
|
||||
toHitLabel = '+ ' + toHitLabel
|
||||
}
|
||||
this.labels.toHit = toHitLabel;
|
||||
|
||||
// Update labels and return the prepared roll data
|
||||
return {rollData, parts};
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
|
||||
/**
|
||||
* Roll the item to Chat, creating a chat card which contains follow up attack or damage roll options
|
||||
* @param {boolean} [configureDialog] Display a configuration dialog for the item roll, if applicable?
|
||||
|
@ -344,7 +414,7 @@ export default class Item5e extends Item {
|
|||
|
||||
// Initiate measured template creation
|
||||
if ( createMeasuredTemplate ) {
|
||||
const template = AbilityTemplate.fromItem(item);
|
||||
const template = game.sw5e.canvas.AbilityTemplate.fromItem(item);
|
||||
if ( template ) template.drawPreview();
|
||||
}
|
||||
|
||||
|
@ -414,8 +484,8 @@ export default class Item5e extends Item {
|
|||
itemUpdates["data.uses.value"] = remaining;
|
||||
}
|
||||
|
||||
// Otherwise reduce quantity
|
||||
if ( consumeQuantity && !used ) {
|
||||
// Reduce quantity if not reducing usages or if usages hit 0 and we are set to consumeQuantity
|
||||
if ( consumeQuantity && (!used || (remaining === 0)) ) {
|
||||
const q = Number(id.quantity ?? 1);
|
||||
if ( q >= 1 ) {
|
||||
used = true;
|
||||
|
@ -593,7 +663,7 @@ export default class Item5e extends Item {
|
|||
|
||||
// Equipment properties
|
||||
if ( data.hasOwnProperty("equipped") && !["loot", "tool"].includes(this.data.type) ) {
|
||||
if ( data.attunement === 1 ) props.push(game.i18n.localize(CONFIG.SW5E.attunements[1]));
|
||||
if ( data.attunement === CONFIG.SW5E.attunementTypes.REQUIRED ) props.push(game.i18n.localize(CONFIG.SW5E.attunements[CONFIG.SW5E.attunementTypes.REQUIRED]));
|
||||
props.push(
|
||||
game.i18n.localize(data.equipped ? "SW5E.Equipped" : "SW5E.Unequipped"),
|
||||
game.i18n.localize(data.proficient ? "SW5E.Proficient" : "SW5E.NotProficient"),
|
||||
|
@ -718,43 +788,28 @@ export default class Item5e extends Item {
|
|||
*/
|
||||
async rollAttack(options={}) {
|
||||
const itemData = this.data.data;
|
||||
const actorData = this.actor.data.data;
|
||||
const flags = this.actor.data.flags.sw5e || {};
|
||||
if ( !this.hasAttack ) {
|
||||
throw new Error("You may not place an Attack Roll with this Item.");
|
||||
}
|
||||
let title = `${this.name} - ${game.i18n.localize("SW5E.AttackRoll")}`;
|
||||
const rollData = this.getRollData();
|
||||
|
||||
// Define Roll bonuses
|
||||
const parts = [`@mod`];
|
||||
if ( !["weapon", "consumable"].includes(this.data.type) || itemData.proficient ) {
|
||||
parts.push("@prof");
|
||||
}
|
||||
// get the parts and rollData for this item's attack
|
||||
const {parts, rollData} = this.getAttackToHit();
|
||||
|
||||
// Attack Bonus
|
||||
if ( itemData.attackBonus ) parts.push(itemData.attackBonus);
|
||||
const actorBonus = actorData?.bonuses?.[itemData.actionType] || {};
|
||||
if ( actorBonus.attack ) parts.push(actorBonus.attack);
|
||||
|
||||
// Ammunition Bonus
|
||||
// Handle ammunition consumption
|
||||
delete this._ammo;
|
||||
let ammo = null;
|
||||
let ammoUpdate = null;
|
||||
const consume = itemData.consume;
|
||||
if ( consume?.type === "ammo" ) {
|
||||
ammo = this.actor.items.get(consume.target);
|
||||
if(ammo?.data){
|
||||
if (ammo?.data) {
|
||||
const q = ammo.data.data.quantity;
|
||||
const consumeAmount = consume.amount ?? 0;
|
||||
if ( q && (q - consumeAmount >= 0) ) {
|
||||
this._ammo = ammo;
|
||||
let ammoBonus = ammo.data.data.attackBonus;
|
||||
if ( ammoBonus ) {
|
||||
parts.push("@ammo");
|
||||
rollData["ammo"] = ammoBonus;
|
||||
title += ` [${ammo.name}]`;
|
||||
}
|
||||
title += ` [${ammo.name}]`;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -874,10 +929,13 @@ export default class Item5e extends Item {
|
|||
parts.push(actorBonus.damage);
|
||||
}
|
||||
|
||||
// Add ammunition damage
|
||||
if ( this._ammo ) {
|
||||
// Handle ammunition damage
|
||||
const ammoData = this._ammo?.data;
|
||||
|
||||
// only add the ammunition damage if the ammution is a consumable with type 'ammo'
|
||||
if ( this._ammo && (ammoData.type === "consumable") && (ammoData.data.consumableType === "ammo") ) {
|
||||
parts.push("@ammo");
|
||||
rollData["ammo"] = this._ammo.data.data.damage.parts.map(p => p[0]).join("+");
|
||||
rollData["ammo"] = ammoData.data.damage.parts.map(p => p[0]).join("+");
|
||||
rollConfig.flavor += ` [${this._ammo.name}]`;
|
||||
delete this._ammo;
|
||||
}
|
||||
|
@ -1039,6 +1097,7 @@ export default class Item5e extends Item {
|
|||
left: window.innerWidth - 710,
|
||||
},
|
||||
halflingLucky: this.actor.getFlag("sw5e", "halflingLucky" ) || false,
|
||||
reliableTalent: (this.data.data.proficient >= 1) && this.actor.getFlag("sw5e", "reliableTalent"),
|
||||
messageData: {"flags.sw5e.roll": {type: "tool", itemId: this.id }}
|
||||
}, options);
|
||||
rollConfig.event = options.event;
|
||||
|
@ -1140,7 +1199,7 @@ export default class Item5e extends Item {
|
|||
case "toolCheck":
|
||||
await item.rollToolCheck({event}); break;
|
||||
case "placeTemplate":
|
||||
const template = AbilityTemplate.fromItem(item);
|
||||
const template = game.sw5e.canvas.AbilityTemplate.fromItem(item);
|
||||
if ( template ) template.drawPreview();
|
||||
break;
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue