System 1.1.1 ** Requires Foundry 0.7.6

System main update to be inline with dnd5e 1.1.1

Added active effects to as many sheets as I thought applicable. Please check loot, I made an attempt but it may be broken

All .less .css and actor .html updates were made to the old actors.  New actors may be broken with this update

removed templates\actors\oldActor\parts\actor-effects.html for newer templates\actors\parts\active-effects.html

removed module\apps\cast-dialog, templates\apps\cast-cast.html, and templates\items\cast.html.  I do not think they are used, I think they were deprecated when powers were treated as items, if not we can add them back in.

**NOTE** REQUIRES Foundry 0.7.6
This commit is contained in:
supervj 2020-11-12 17:30:07 -05:00
parent 27f5fa3670
commit 68a1b6a9f0
58 changed files with 1417 additions and 1706 deletions

View file

@ -6,7 +6,7 @@ import AbilityTemplate from "../pixi/ability-template.js";
import {SW5E} from '../config.js';
/**
* Extend the base Actor class to implement additional logic specialized for SW5e.
* Extend the base Actor class to implement additional system-specific logic for SW5e.
*/
export default class Actor5e extends Actor {
@ -20,48 +20,6 @@ export default class Actor5e extends Actor {
/* -------------------------------------------- */
/**
* @override
* TODO: This becomes unnecessary after 0.7.x is released
*/
initialize() {
try {
this.prepareData();
} catch(err) {
console.error(`Failed to initialize data for ${this.constructor.name} ${this.id}:`);
console.error(err);
}
}
/* -------------------------------------------- */
/**
* @override
* TODO: This becomes unnecessary after 0.7.x is released
*/
prepareData() {
const is07x = !isNewerVersion("0.7.1", game.data.version);
if ( is07x ) this.data = duplicate(this._data);
if (!this.data.img) this.data.img = CONST.DEFAULT_TOKEN;
if ( !this.data.name ) this.data.name = "New " + this.entity;
this.prepareBaseData();
this.prepareEmbeddedEntities();
if ( is07x ) this.applyActiveEffects();
this.prepareDerivedData();
}
/* -------------------------------------------- */
/**
* @override
* TODO: This becomes unnecessary after 0.7.x is released
*/
applyActiveEffects() {
if (!isNewerVersion("0.7.1", game.data.version)) return super.applyActiveEffects();
}
/* -------------------------------------------- */
/** @override */
prepareBaseData() {
switch ( this.data.type ) {
@ -116,6 +74,11 @@ export default class Actor5e extends Actor {
abl.save = Math.max(abl.save, originalSaves[id].save);
}
}
// Inventory encumbrance
data.attributes.encumbrance = this._computeEncumbrance(actorData);
// Prepare skills
this._prepareSkills(actorData, bonuses, checkBonus, originalSkills);
// Determine Initiative Modifier
@ -126,7 +89,8 @@ export default class Actor5e extends Actor {
if ( joat ) init.prof = Math.floor(0.5 * data.attributes.prof);
else if ( athlete ) init.prof = Math.ceil(0.5 * data.attributes.prof);
else init.prof = 0;
init.bonus = Number(init.value + (flags.initiativeAlert ? 5 : 0));
init.value = init.value ?? 0;
init.bonus = init.value + (flags.initiativeAlert ? 5 : 0);
init.total = init.mod + init.prof + init.bonus;
// Prepare power-casting data
@ -169,7 +133,7 @@ export default class Actor5e extends Actor {
}
return obj;
}, {});
data.prof = this.data.data.attributes.prof;
data.prof = this.data.data.attributes.prof || 0;
return data;
}
@ -177,33 +141,36 @@ export default class Actor5e extends Actor {
/**
* Return the features which a character is awarded for each class level
* @param cls {Object} Data object for class, equivalent to Item5e.data or raw compendium entry
* @param {string} className The class name being added
* @param {string} subclassName The subclass of the class being added, if any
* @param {number} level The number of levels in the added class
* @param {number} priorLevel The previous level of the added class
* @return {Promise<Item5e[]>} Array of Item5e entities
*/
static async getClassFeatures(cls) {
const level = cls.data.levels;
const className = cls.name.toLowerCase();
static async getClassFeatures({className="", subclassName="", level=1, priorLevel=0}={}) {
className = className.toLowerCase();
subclassName = subclassName.slugify();
// Get the configuration of features which may be added
const clsConfig = CONFIG.SW5E.classFeatures[className];
if (!clsConfig) return [];
let featureIDs = clsConfig["features"][level] || [];
const subclassName = cls.data.subclass.toLowerCase().slugify();
if (!clsConfig) return [];
// Identify subclass features
if ( subclassName !== "" ) {
const subclassConfig = clsConfig["subclasses"][subclassName];
if ( subclassConfig !== undefined ) {
const subclassFeatureIDs = subclassConfig["features"][level];
if ( subclassFeatureIDs ) {
featureIDs = featureIDs.concat(subclassFeatureIDs);
}
}
else console.warn("Invalid subclass: " + subclassName);
// Acquire class features
let ids = [];
for ( let [l, f] of Object.entries(clsConfig.features || {}) ) {
l = parseInt(l);
if ( (l <= level) && (l > priorLevel) ) ids = ids.concat(f);
}
// Acquire subclass features
const subConfig = clsConfig.subclasses[subclassName] || {};
for ( let [l, f] of Object.entries(subConfig.features || {}) ) {
l = parseInt(l);
if ( (l <= level) && (l > priorLevel) ) ids = ids.concat(f);
}
// Load item data for all identified features
const features = await Promise.all(featureIDs.map(id => fromUuid(id)));
const features = await Promise.all(ids.map(id => fromUuid(id)));
// Class powers should always be prepared
for ( const feature of features ) {
@ -237,35 +204,28 @@ export default class Actor5e extends Actor {
for (let u of updated instanceof Array ? updated : [updated]) {
const item = this.items.get(u._id);
if (!item || (item.data.type !== "class")) continue;
const classData = duplicate(item.data);
let changed = false;
const updateData = expandObject(u);
const config = {
className: updateData.name || item.data.name,
subclassName: updateData.data.subclass || item.data.data.subclass,
level: getProperty(updateData, "data.levels"),
priorLevel: item ? item.data.data.levels : 0
}
// Get and create features for an increased class level
const newLevels = getProperty(u, "data.levels");
if (newLevels && (newLevels > item.data.data.levels)) {
classData.data.levels = newLevels;
changed = true;
}
let changed = false;
if ( config.level && (config.level > config.priorLevel)) changed = true;
if ( config.subclassName !== item.data.data.subclass ) changed = true;
// Get features for a newly changed subclass
const newSubclass = getProperty(u, "data.subclass");
if (newSubclass && (newSubclass !== item.data.data.subclass)) {
classData.data.subclass = newSubclass;
changed = true;
}
// Get the new features
// Get features to create
if ( changed ) {
const features = await Actor5e.getClassFeatures(classData);
if ( features.length ) toCreate.push(...features);
const existing = new Set(this.items.map(i => i.name));
const features = await Actor5e.getClassFeatures(config);
for ( let f of features ) {
if ( !existing.has(f.name) ) toCreate.push(f);
}
}
}
// De-dupe created items with ones that already exist (by name)
if ( toCreate.length ) {
const existing = new Set(this.items.map(i => i.name));
toCreate = toCreate.filter(c => !existing.has(c.name));
}
return toCreate
}
@ -301,9 +261,6 @@ export default class Actor5e extends Actor {
const required = xp.max - prior;
const pct = Math.round((xp.value - prior) * 100 / required);
xp.pct = Math.clamped(pct, 0, 100);
// Inventory encumbrance
data.attributes.encumbrance = this._computeEncumbrance(actorData);
}
/* -------------------------------------------- */
@ -369,17 +326,17 @@ export default class Actor5e extends Actor {
}
if ( joat && (skl.value === 0 ) ) multi = 0.5;
// Retain the maximum skill proficiency when skill proficiencies are merged
if ( originalSkills ) {
skl.value = Math.max(skl.value, originalSkills[id].value);
}
// Compute modifier
skl.bonus = checkBonus + skillBonus;
skl.mod = data.abilities[skl.ability].mod;
skl.prof = round(multi * data.attributes.prof);
skl.total = skl.mod + skl.prof + skl.bonus;
// If we merged skills when transforming, take the highest bonus here.
if (originalSkills && skl.value > 0.5) {
skl.total = Math.max(skl.total, originalSkills[id].total);
}
// Compute passive bonus
const passive = observant && (feats.observantFeat.skills.includes(id)) ? 5 : 0;
skl.passive = 10 + skl.total + passive;
@ -489,8 +446,8 @@ export default class Actor5e extends Actor {
else powers.pact.max = Math.max(1, Math.min(pl, 2), Math.min(pl - 8, 3), Math.min(pl - 13, 4));
powers.pact.value = Math.min(powers.pact.value, powers.pact.max);
} else {
powers.pact.level = 0;
powers.pact.max = 0;
powers.pact.max = parseInt(powers.pact.override) || 0
powers.pact.level = powers.pact.max > 0 ? 1 : 0;
}
}
@ -513,14 +470,14 @@ export default class Actor5e extends Actor {
if ( !physicalItems.includes(i.type) ) return weight;
const q = i.data.quantity || 0;
const w = i.data.weight || 0;
return weight + Math.round(q * w * 10) / 10;
return weight + (q * w);
}, 0);
// [Optional] add Currency Weight
if ( game.settings.get("sw5e", "currencyWeight") ) {
const currency = actorData.data.currency;
const numCoins = Object.values(currency).reduce((val, denom) => val += Math.max(denom, 0), 0);
weight += Math.round((numCoins * 10) / CONFIG.SW5E.encumbrance.currencyPerWeight) / 10;
weight += numCoins / CONFIG.SW5E.encumbrance.currencyPerWeight;
}
// Determine the encumbrance size class
@ -535,9 +492,10 @@ export default class Actor5e extends Actor {
if ( this.getFlag("sw5e", "powerfulBuild") ) mod = Math.min(mod * 2, 8);
// Compute Encumbrance percentage
weight = weight.toNearest(0.1);
const max = actorData.data.abilities.str.value * CONFIG.SW5E.encumbrance.strMultiplier * mod;
const pct = Math.clamped((weight* 100) / max, 0, 100);
return { value: weight, max, pct, encumbered: pct > (2/3) };
const pct = Math.clamped((weight * 100) / max, 0, 100);
return { value: weight.toNearest(0.1), max, pct, encumbered: pct > (2/3) };
}
/* -------------------------------------------- */
@ -564,9 +522,6 @@ export default class Actor5e extends Actor {
/** @override */
async update(data, options={}) {
// TODO: 0.7.1 compatibility - remove when stable
if ( !data.hasOwnProperty("data") ) data = expandObject(data);
// Apply changes in Actor size to Token width/height
const newSize = getProperty(data, "data.traits.size");
if ( newSize && (newSize !== getProperty(this.data, "data.traits.size")) ) {
@ -577,7 +532,7 @@ export default class Actor5e extends Actor {
data["token.width"] = size;
}
}
// Reset death save counters
if ( (this.data.data.attributes.hp.value <= 0) && (getProperty(data, "data.attributes.hp.value") > 0) ) {
setProperty(data, "data.attributes.death.success", 0);
@ -858,7 +813,7 @@ export default class Actor5e extends Actor {
rollAbilitySave(abilityId, options={}) {
const label = CONFIG.SW5E.abilities[abilityId];
const abl = this.data.data.abilities[abilityId];
// Construct parts
const parts = ["@mod"];
const data = {mod: abl.mod};
@ -937,7 +892,7 @@ export default class Actor5e extends Actor {
// Take action depending on the result
const success = roll.total >= 10;
const d20 = roll.dice[0].total;
const d20 = roll.dice[0].total;
// Save success
if ( success ) {
@ -1429,14 +1384,16 @@ export default class Actor5e extends Actor {
if ( !original ) return;
// Get the Tokens which represent this actor
const tokens = this.getActiveTokens(true);
const tokenUpdates = tokens.map(t => {
const tokenData = duplicate(original.data.token);
tokenData._id = t.id;
tokenData.actorId = original.id;
return tokenData;
});
canvas.scene.updateEmbeddedEntity("Token", tokenUpdates);
if ( canvas.ready ) {
const tokens = this.getActiveTokens(true);
const tokenUpdates = tokens.map(t => {
const tokenData = duplicate(original.data.token);
tokenData._id = t.id;
tokenData.actorId = original.id;
return tokenData;
});
canvas.scene.updateEmbeddedEntity("Token", tokenUpdates);
}
// Delete the polymorphed Actor and maybe re-render the original sheet
const isRendered = this.sheet.rendered;