Skip to content

Commit

Permalink
v13.0.7-beta2 Fix feat/magic item/race spells
Browse files Browse the repository at this point in the history
•	Fixed spells from feats, magic items, and race not appearing on the spell pages
•	Improved compatibility between dynamic spell changes and spells gained from magic items
•	Added option to disable upcasting of a singular spell (with the `spellChanges` attribute)
  • Loading branch information
morepurplemorebetter committed Jul 2, 2021
1 parent c4347ab commit ba59045
Showing 5 changed files with 44 additions and 17 deletions.
21 changes: 13 additions & 8 deletions _functions/FunctionsSpells.js
Original file line number Diff line number Diff line change
@@ -108,7 +108,10 @@ function GetSpellObject(theSpl, theCast, firstCol, noOverrides, tipShortDescr) {
if (!foundSpell) return aSpell;
var aDescrAttr = ["description", "descriptionMetric", "descriptionShorter", "descriptionShorterMetric"];
var aCast = theCast && CurrentSpells[theCast] ? CurrentSpells[theCast] : "";
for (var key in foundSpell) aSpell[key] = foundSpell[key];
for (var key in foundSpell) {
if (key === 'allowUpCasting') continue;
aSpell[key] = foundSpell[key];
}
// set the firstCol attribute so the CurrentEval can change it
aSpell.firstCol = firstCol ? firstCol : aSpell.firstCol ? aSpell.firstCol : "";
// If this spell is gained from an item, remove components
@@ -139,6 +142,8 @@ function GetSpellObject(theSpl, theCast, firstCol, noOverrides, tipShortDescr) {
aSpell[key] = theOver[key];
}
}
// If this set the spell to not allow upcasting, apply this now
if (aSpell.allowUpCasting === false) removeSpellUpcasting(aSpell);

// Change some things into metric if set to do so
if (What("Unit System") === "metric") {
@@ -223,7 +228,7 @@ function GetSpellObject(theSpl, theCast, firstCol, noOverrides, tipShortDescr) {

if (ttSpellObj.time) spTooltip += "\n Casting Time: " + ttSpellObj.time.replace(/1 a\b/i, '1 action').replace(/1 bns\b/i, '1 bonus action').replace(/1 rea\b/i, '1 reaction').replace(/\b1 min\b/i, '1 minute').replace(/\b1 h\b/i, '1 hour').replace(/\bmin\b/i, 'minutes').replace(/\bh\b/i, 'hours');

if (ttSpellObj.range) spTooltip += "\n Range: " + ttSpellObj.range.replace(/s: */i, "self: ").replace(/rad\b/i, "radius");
if (ttSpellObj.range) spTooltip += "\n Range: " + ttSpellObj.range.replace(/s: *(.*)/i, "Self ($1)").replace(/rad\b/i, "radius").replace(/(\d+)(ft|m)/i, "$1-$2");

if (ttSpellObj.components) spTooltip += "\n Components: " + ttSpellObj.components + (ttSpellObj.compMaterial ? " (" + ttSpellObj.compMaterial.substr(0,1).toLowerCase() + ttSpellObj.compMaterial.substr(1) + ")" : "");

@@ -256,7 +261,7 @@ function fixSpellRangeOverflow(rangeStr) {
// under certain conditions, we want to remove any upcasting from the spell's short description
function removeSpellUpcasting(oSpell) {
var bReturn = false;
var removeRegex = /\+\d+d?\d*\/\d*SL\b|\bSL used/ig
var removeRegex = /\+\d+d?\d*\/(\d*SL|PP)\b|\bSL used/ig;
["description", "descriptionMetric", "descriptionShorter", "descriptionShorterMetric"].forEach (function (attr) {
if ( !oSpell[attr] || !removeRegex.test(oSpell[attr]) ) return;
oSpell[attr] = oSpell[attr]
@@ -5560,7 +5565,7 @@ function genericSpellDmgEdit(spellKey, spellObj, dmgType, ability, notMultiple,
var isDieType = (/^\d*d\d+$/i).test(ability), addDieType;
var abiMod = isDieType ? ability.replace(/^1d(\d+)$/i, "d$1") : !isNaN(ability) ? ability : tDoc.getField(ability + " Mod") ? Number(What(ability + " Mod")) : ability;
var abiIsStr = !isDieType && isNaN(abiMod);
var abiIfUpcasting = abiIsStr && /\/(\d*SL|PP|extra PP)/i.test(abiMod);
var abiIfUpcasting = abiIsStr && /\/(\d*SL|PP|extra \w+)/i.test(abiMod);

// Stop now if there is nothing (positive) to add or nothing to maximize
if (!maximizeRolls && ((isNaN(ability) && abiMod < 1) || abiMod === 0 || (abiIfUpcasting && spellObj.noSpellUpcasting))) return;
@@ -5590,10 +5595,10 @@ function genericSpellDmgEdit(spellKey, spellObj, dmgType, ability, notMultiple,
strReplace = strReplace.replace(bMatch, bTotal);
}
// Add consecutive bonuses (per group 'X/SL' and not 'X/SL')
var qRx = /(([\+\-]?\d+)(\/\d*SL|\/PP|\/extra PP)?)+( \((Str|Dex|Con|Int|Wis|Cha)\))?/i;
var qRx = /(([\+\-]?\d+)(\/\d*SL|\/PP|\/extra \w+)?)+( \((Str|Dex|Con|Int|Wis|Cha)\))?/i;
if (qRx.test(strReplace)) {
var qMatch = strReplace.match(qRx)[0];
var qParts = qMatch.match(/[\+\-]?\d+(\/\d*SL|\/PP|\/extra PP)?/ig);
var qParts = qMatch.match(/[\+\-]?\d+(\/\d*SL|\/PP|\/extra \w+)?/ig);
var qObj = { nr : 0 };
for (var q = 0; q < qParts.length; q++) {
if (!isNaN(qParts[q])) {
@@ -5617,7 +5622,7 @@ function genericSpellDmgEdit(spellKey, spellObj, dmgType, ability, notMultiple,
}
// The function to fix a string of multiple X/SL+Y/SL to (X+Y)/SL
var fixMultiPerSL = function(strSl) {
var slMatch = strSl.match(/(\+?)(\d+d?\d*)(\/\d*SL|\/PP|\/extra PP)\+(\d+d?\d*|\(.*?\))(\3)/i);
var slMatch = strSl.match(/(\+?)(\d+d?\d*)(\/\d*SL|\/PP|\/extra \w+)\+(\d+d?\d*|\(.*?\))(\3)/i);
if (!slMatch) return strSl;
var aVals = [slMatch[2], slMatch[4]]; // Make an array of just the numerical/dice parts
if ((/\(.*?\)/).test(aVals[1])) {
@@ -5710,7 +5715,7 @@ function genericSpellDmgEdit(spellKey, spellObj, dmgType, ability, notMultiple,

// Create the matching regex with non-capturing inner groups
var isHealing = /heal|\bhp\b|restore/.test(dmgType);
var sRegex = (isHealing ? "(heals? |to life with )" : "") + "((?:\\+?\\d+d?\\d*)+)((?:\\+(?:\\((?:\\+?\\d+d?\\d*)+\\)|\\d+d?\\d*)\\/(?:\\d*SL|PP|extra PP))*(?:\\+ ?(?:my )?spell(?:casting)? (?:ability )?mod(?:ifier)?|(?:\\+|-)\\d+ \\(.{3}\\))? (?:" + (isHealing ? "" : dmgType) + ") ?(?:" + (isHealing ? "hp|hit points?" : "dmg|damage") + ")(?: per \\w+| each|/rnd|/turn)?)";
var sRegex = (isHealing ? "(heals? |to life with )" : "") + "((?:\\+?\\d+d?\\d*)+)((?:\\+(?:\\((?:\\+?\\d+d?\\d*)+\\)|\\d+d?\\d*)\\/(?:\\d*SL|PP|extra \\w+))*(?:\\+ ?(?:my )?spell(?:casting)? (?:ability )?mod(?:ifier)?|(?:\\+|-)\\d+ \\(.{3}\\))? (?:" + (isHealing ? "" : dmgType) + ") ?(?:" + (isHealing ? "hp|hit points?" : "dmg|damage") + ")(?: per \\w+| each|/rnd|/turn)?)";

// If the spell has multiple damage types, we need to check if any or all of them match the dmgType we are looking for
var onlySomeDmgTypes = false;
4 changes: 3 additions & 1 deletion _variables/ListsClasses.js
Original file line number Diff line number Diff line change
@@ -2117,6 +2117,8 @@ var Base_ClassList = {
spellChanges : {
"eldritch blast" : {
description : "Spell attack beam 1d10 Force damage \u0026 push 10 ft; beams can be combined; +1 beam at CL5,11,17",
descriptionShorter : "Spell atk beam 1d10 Force damage \u0026 push 10 ft; can combine beams; +1 beam at CL5,11,17",
descriptionCantripDie : "Spell atk for `CD` beam(s), each 1d10 Force damage \u0026 push 10 ft; can combine/split beams",
changes : "When I hit a creature with my Eldritch Blast cantrip, it is pushed 10 ft away from me."
}
}
@@ -2560,7 +2562,7 @@ var Base_ClassSubList = {
};
var alwaysOthers = ["life transference", "raise dead", "revivify", "resurrection", "true resurrection"];
var strPart = alwaysOthers.indexOf(spellKey) === -1 ? "; if other, I heal " : "; I heal ";
var strAdd = spellObj.level < 9 ? strPart + (spellObj.level + 2) + "+1/SL HP" : strPart + "11 HP";
var strAdd = spellObj.level < 9 ? strPart + (spellObj.level + 2) + (spellObj.noSpellUpcasting ? "" : "+1/SL") + " HP" : strPart + "11 HP";
spellObj.description = useSpellDescr + strAdd;
return true;
}
10 changes: 6 additions & 4 deletions _variables/ListsMagicItems.js
Original file line number Diff line number Diff line change
@@ -3158,7 +3158,7 @@ var Base_MagicItemsList = {
fixedDC : 15,
spellChanges : {
"fireball" : {
description : "20-ft rad all crea 8d6 (+1d6/extra bead) Fire dmg; save halves; unattended flammable objects ignite",
description : "20-ft rad all crea 8d6+1d6/extra bead Fire dmg; save halves; unattended flammable objects ignite",
components : "M\u2020",
compMaterial : "Using the Necklace of Fireballs to cast Fireball requires removing and destorying one or more of the beads from it.",
changes : "Using the Necklace of Fireballs to cast Fireball requires removing and destorying one or more of the beads from it. The damage is that of a Fireball cast a 3rd-level, +1 level per bead thrown as part of the same action beyond the first."
@@ -4309,6 +4309,7 @@ var Base_MagicItemsList = {
duration : "Conc, 1 min",
save : "Dex",
description : "1-4 spheres; bns a move all 30 ft; 1st crea in 5 ft save or Lightning dmg (1:4d12, 2:5d4, 3:2d6, 4:2d4)",
descriptionShorter : false,
descriptionFull : "You can expend 2 charges from the ring of shooting starts as an action to create one to four 3-foot-diameter spheres of lightning. The more spheres you create, the less powerful each sphere is individually.\n Each sphere appears in an unoccupied space you can see within 120 feet of you. The spheres last as long as you concentrate (as if concentrating on a spell), up to 1 minute. Each sphere sheds dim light in a 30-foot radius.\n As a bonus action, you can move each sphere up to 30 feet, but no farther than 120 feet away from you. When a creature other than you comes within 5 feet of a sphere, the sphere discharges lightning at that creature and disappears. That creature must make a DC 15 Dexterity saving throw. On a failed save, the creature takes lightning damage based on the number of spheres you created (4 spheres = 2d4, 3 spheres = 2d6, 2 spheres = 5d4, 1 sphere = 4d12).",
completeRewrite : true, // indicates that the changes here even overwrite the tooltip
changes : "The listing of 'Flaming Sphere' has been completely changed to reflect the 'Ball Lightning' ability of the Ring of Shooting Stars. Even the information above is changed."
@@ -5225,7 +5226,8 @@ var Base_MagicItemsList = {
}],
spellChanges : {
"cure wounds" : {
description : "1 living creature heals 1d8+spellcasting ability modifier HP, +1d8 per charge spend after the 1st",
noSpellUpcasting : false,
description : "1 living creature heals 1d8+1d8/SL+spell mod HP; +1 SL/extra charge",
changes : "The spell level Cure Wounds is cast at depends on the amount of charges spend, 1 charge per spell slot level."
}
}
@@ -6131,7 +6133,7 @@ var Base_MagicItemsList = {
},
spellChanges : {
"fireball" : {
description : "20-ft rad all crea 8d6 Fire dmg (+1d6/extra charge); save halves; unattended flammable objects ignite",
description : "20-ft rad all crea 8d6+1d6/extra charge Fire dmg; save halves; unattended flammable objects ignite",
changes : "For 1 charge, it is cast as the 3rd-level version of the spell, but I can increase the spell slot level by one for each additional charge expended."
}
}
@@ -6161,7 +6163,7 @@ var Base_MagicItemsList = {
},
spellChanges : {
"lightning bolt" : {
description : "100-ft long 5-ft wide all 8d6 Lightn. dmg (+1d6/extra charge); save halves; unattended objects ignite",
description : "100-ft long 5-ft wide all 8d6+1d6/extra charge Lightn. dmg; save halves; unattended objects ignite",
changes : "For 1 charge, it is cast as the 3rd-level version of the spell, but I can increase the spell slot level by one for each additional charge expended."
}
}
7 changes: 4 additions & 3 deletions additional content syntax/_common attributes.js
Original file line number Diff line number Diff line change
@@ -48,7 +48,7 @@
Magic Item main attributes
Magic Item choices
Sheet: v13.0.6 and newer
Sheet: v13.0.7 and newer
*/
"example feature name" = { // you can ignore this, it is just here to make this file valid JavaScript

@@ -1612,8 +1612,9 @@ calcChanges : {
By changing the attributes of the spellObj, you change what is put in the fields.
Changing that object has no affect on the original SpellsList entry.
You can call on the `genericSpellDmgEdit()` function to automatically increase the damage or healing
of a spell. This function dynamically adds an ability modifier, value, or die to the damage
Since v13.0.7 you can call on the `genericSpellDmgEdit()` function to automatically increase
the damage or healing of a spell.
This function dynamically adds an ability modifier, value, or die to the damage
or healing displayed in the short description on the spell sheet.
genericSpellDmgEdit(spellKey, spellObj, dmgType, ability, notMultiple, onlyRolls, maximizeRolls)
19 changes: 18 additions & 1 deletion additional content syntax/spell (SpellsList).js
Original file line number Diff line number Diff line change
@@ -38,7 +38,7 @@
If you want attack cantrips or spells to be added to the attack section,
use the syntax for adding a weapon (as well), see "weapon (WeaponsList).js".
Sheet: v13.0.6 and newer
Sheet: v13.0.7 and newer
*/

@@ -468,6 +468,23 @@ SpellsList["sindering purple"] = {
Setting this attribute to an empty array ([]) is the same as not including this attribute, but doing so will slow the sheet down considerably.
*/
allowUpCasting : false,
/* allowUpCasting // OPTIONAL //
TYPE: boolean
USE: limit spell to only be cast at their lowest level
ADDED: v13.0.7
IMPORTANT
This attribute is only useful as part of a `spellChanges` object (see "_common attributes.js").
It is ignored if part of a SpellsList object, because you can just not include upcasting in
the description.
By setting this attribute to false, you force the sheet to remove the upcasting from the spell's
description.
Normally, the sheet will limit spells gained from a feat, magic item, or race to be cast only at
its lowest level, removing any upcasting options from the short spell description.
Use this attribute with the `spellChanges` attribute, if a class feature doesn't allow upcasting.
*/


// >>>>>>>>>>>>>>>>>>>>>>>>>>> //

0 comments on commit ba59045

Please sign in to comment.