Grabbed dndbeyond's source code
``` ~/go/bin/sourcemapper -output ddb -jsurl https://media.dndbeyond.com/character-app/static/js/main.90aa78c5.js ```
This commit is contained in:
@@ -0,0 +1,832 @@
|
||||
import { ActivationAccessors } from '../Activation';
|
||||
/**
|
||||
*
|
||||
* @param spell
|
||||
*/
|
||||
export function getDefinition(spell) {
|
||||
return spell.definition;
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param spell
|
||||
*/
|
||||
export function getUniqueKey(spell) {
|
||||
return spell.uniqueKey;
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param spell
|
||||
*/
|
||||
export function getDefinitionName(spell) {
|
||||
var _a, _b;
|
||||
return (_b = (_a = spell.definition) === null || _a === void 0 ? void 0 : _a.name) !== null && _b !== void 0 ? _b : null;
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param spell
|
||||
*/
|
||||
export function getAttackType(spell) {
|
||||
return getDefinitionAttackType(spell);
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param spell
|
||||
*/
|
||||
export function getDefinitionAttackType(spell) {
|
||||
var _a, _b;
|
||||
return (_b = (_a = spell.definition) === null || _a === void 0 ? void 0 : _a.attackType) !== null && _b !== void 0 ? _b : null;
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param spell
|
||||
*/
|
||||
export function getId(spell) {
|
||||
var _a, _b;
|
||||
return (_b = (_a = spell.definition) === null || _a === void 0 ? void 0 : _a.id) !== null && _b !== void 0 ? _b : -1;
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param spell - The spell in question
|
||||
*/
|
||||
export function getSpellGroups(spell) {
|
||||
var _a;
|
||||
return ((_a = getDefinition(spell)) === null || _a === void 0 ? void 0 : _a.spellGroups) || [];
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param spell
|
||||
*/
|
||||
export function getDefinitionRange(spell) {
|
||||
var _a, _b;
|
||||
return (_b = (_a = spell.definition) === null || _a === void 0 ? void 0 : _a.range) !== null && _b !== void 0 ? _b : null;
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param spell
|
||||
*/
|
||||
export function getDefinitionRangeArea(spell) {
|
||||
var _a, _b;
|
||||
return (_b = (_a = spell.definition) === null || _a === void 0 ? void 0 : _a.rangeArea) !== null && _b !== void 0 ? _b : null;
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param spell
|
||||
*/
|
||||
export function getMappingId(spell) {
|
||||
return spell.id;
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param spell
|
||||
*/
|
||||
export function getMappingEntityTypeId(spell) {
|
||||
return spell.entityTypeId;
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param spell
|
||||
*/
|
||||
export function getLimitedUse(spell) {
|
||||
return spell.limitedUse;
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param spell
|
||||
*/
|
||||
export function getActivation(spell) {
|
||||
return spell.activation;
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param spell
|
||||
*/
|
||||
export function getDefinitionActivation(spell) {
|
||||
var _a, _b;
|
||||
return (_b = (_a = spell.definition) === null || _a === void 0 ? void 0 : _a.activation) !== null && _b !== void 0 ? _b : null;
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param spell
|
||||
*/
|
||||
export function getActivationTime(spell) {
|
||||
return ActivationAccessors.getTime(getActivation(spell));
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param spell
|
||||
*/
|
||||
export function getActivationType(spell) {
|
||||
return ActivationAccessors.getType(getActivation(spell));
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param spell
|
||||
*/
|
||||
export function getCastingTimeDescription(spell) {
|
||||
return getDefinitionCastingTimeDescription(spell);
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param spell
|
||||
*/
|
||||
export function getDefinitionCastingTimeDescription(spell) {
|
||||
var _a, _b;
|
||||
return (_b = (_a = spell.definition) === null || _a === void 0 ? void 0 : _a.castingTimeDescription) !== null && _b !== void 0 ? _b : null;
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param spell
|
||||
*/
|
||||
export function getTags(spell) {
|
||||
return getDefinitionTags(spell);
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param spell
|
||||
*/
|
||||
export function getDefinitionTags(spell) {
|
||||
var _a, _b;
|
||||
return (_b = (_a = spell.definition) === null || _a === void 0 ? void 0 : _a.tags) !== null && _b !== void 0 ? _b : [];
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param spell
|
||||
*/
|
||||
export function getDefinitionTempHpDice(spell) {
|
||||
var _a, _b;
|
||||
return (_b = (_a = spell.definition) === null || _a === void 0 ? void 0 : _a.tempHpDice) !== null && _b !== void 0 ? _b : [];
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param spell
|
||||
*/
|
||||
export function getConditions(spell) {
|
||||
return getDefinitionConditions(spell);
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param spell
|
||||
*/
|
||||
export function getDefinitionConditions(spell) {
|
||||
var _a, _b;
|
||||
return (_b = (_a = spell.definition) === null || _a === void 0 ? void 0 : _a.conditions) !== null && _b !== void 0 ? _b : [];
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param spell
|
||||
*/
|
||||
export function getDefinitionDamageEffect(spell) {
|
||||
var _a, _b;
|
||||
return (_b = (_a = spell.definition) === null || _a === void 0 ? void 0 : _a.damageEffect) !== null && _b !== void 0 ? _b : null;
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param spell
|
||||
*/
|
||||
export function getLevel(spell) {
|
||||
return getDefinitionLevel(spell);
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param spell
|
||||
*/
|
||||
export function getDefinitionLevel(spell) {
|
||||
var _a, _b;
|
||||
return (_b = (_a = spell.definition) === null || _a === void 0 ? void 0 : _a.level) !== null && _b !== void 0 ? _b : 0;
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param spell
|
||||
*/
|
||||
export function getSchool(spell) {
|
||||
return getDefinitionSchool(spell);
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param spell
|
||||
*/
|
||||
export function getDefinitionSchool(spell) {
|
||||
var _a, _b;
|
||||
return (_b = (_a = spell.definition) === null || _a === void 0 ? void 0 : _a.school) !== null && _b !== void 0 ? _b : null;
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param spell
|
||||
*/
|
||||
export function getDefinitionSnippet(spell) {
|
||||
var _a, _b;
|
||||
return (_b = (_a = spell.definition) === null || _a === void 0 ? void 0 : _a.snippet) !== null && _b !== void 0 ? _b : null;
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param spell
|
||||
*/
|
||||
export function getDescription(spell) {
|
||||
return getDefinitionDescription(spell);
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param spell
|
||||
*/
|
||||
export function getDefinitionDescription(spell) {
|
||||
var _a, _b;
|
||||
return (_b = (_a = spell.definition) === null || _a === void 0 ? void 0 : _a.description) !== null && _b !== void 0 ? _b : null;
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param spell
|
||||
*/
|
||||
export function getDefinitionIsHomebrew(spell) {
|
||||
var _a, _b;
|
||||
return (_b = (_a = spell.definition) === null || _a === void 0 ? void 0 : _a.isHomebrew) !== null && _b !== void 0 ? _b : false;
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param spell
|
||||
*/
|
||||
export function getVersion(spell) {
|
||||
return getDefinitionVersion(spell);
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param spell
|
||||
*/
|
||||
export function getDefinitionVersion(spell) {
|
||||
var _a, _b;
|
||||
return (_b = (_a = spell.definition) === null || _a === void 0 ? void 0 : _a.version) !== null && _b !== void 0 ? _b : null;
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param spell
|
||||
*/
|
||||
export function getUsesSpellSlot(spell) {
|
||||
if (isCantrip(spell)) {
|
||||
return false;
|
||||
}
|
||||
return spell.usesSpellSlot;
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param spell
|
||||
*/
|
||||
export function isDisplayAsAttack(spell) {
|
||||
return spell.displayAsAttack;
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param spell
|
||||
*/
|
||||
export function isAlwaysPrepared(spell) {
|
||||
return spell.alwaysPrepared;
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param spell
|
||||
*/
|
||||
export function isCantrip(spell) {
|
||||
return getLevel(spell) === 0;
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param spell
|
||||
*/
|
||||
export function isAttack(spell) {
|
||||
return getDefinitionRequiresAttackRoll(spell);
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param spell
|
||||
*/
|
||||
export function getDefinitionRequiresAttackRoll(spell) {
|
||||
var _a, _b;
|
||||
return (_b = (_a = spell.definition) === null || _a === void 0 ? void 0 : _a.requiresAttackRoll) !== null && _b !== void 0 ? _b : false;
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param spell
|
||||
*/
|
||||
export function asPartOfWeaponAttack(spell) {
|
||||
return getDefinitionAsPartOfWeaponAttack(spell);
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param spell
|
||||
*/
|
||||
export function getDefinitionAsPartOfWeaponAttack(spell) {
|
||||
var _a, _b;
|
||||
return (_b = (_a = spell.definition) === null || _a === void 0 ? void 0 : _a.asPartOfWeaponAttack) !== null && _b !== void 0 ? _b : false;
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param spell
|
||||
*/
|
||||
export function getToHit(spell) {
|
||||
return spell.toHit;
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param spell
|
||||
*/
|
||||
export function canRemove(spell) {
|
||||
return spell.canRemove;
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param spell
|
||||
*/
|
||||
export function canPrepare(spell) {
|
||||
return spell.canPrepare;
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param spell
|
||||
*/
|
||||
export function canAdd(spell) {
|
||||
return spell.canAdd;
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param spell
|
||||
*/
|
||||
export function getModifiers(spell) {
|
||||
return spell.modifiers;
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param spell
|
||||
*/
|
||||
export function getDefinitionModifiers(spell) {
|
||||
var _a, _b;
|
||||
return (_b = (_a = spell.definition) === null || _a === void 0 ? void 0 : _a.modifiers) !== null && _b !== void 0 ? _b : [];
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param spell
|
||||
*/
|
||||
export function getCastAtLevel(spell) {
|
||||
return spell.castAtLevel;
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param spell
|
||||
*/
|
||||
export function getCastOnlyAsRitual(spell) {
|
||||
return spell.castOnlyAsRitual;
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param spell
|
||||
*/
|
||||
export function getRitualCastingType(spell) {
|
||||
return spell.ritualCastingType;
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param spell
|
||||
*/
|
||||
export function getBaseLevelAtWill(spell) {
|
||||
return spell.baseLevelAtWill;
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param spell
|
||||
*/
|
||||
export function getConcentration(spell) {
|
||||
return getDefinitionConcentration(spell);
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param spell
|
||||
*/
|
||||
export function getDefinitionConcentration(spell) {
|
||||
var _a, _b;
|
||||
return (_b = (_a = spell.definition) === null || _a === void 0 ? void 0 : _a.concentration) !== null && _b !== void 0 ? _b : false;
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param spell
|
||||
*/
|
||||
export function getRitual(spell) {
|
||||
return getDefinitionRitual(spell);
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param spell
|
||||
*/
|
||||
export function getDefinitionRitual(spell) {
|
||||
var _a, _b;
|
||||
return (_b = (_a = spell.definition) === null || _a === void 0 ? void 0 : _a.ritual) !== null && _b !== void 0 ? _b : false;
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param spell
|
||||
*/
|
||||
export function isCustomized(spell) {
|
||||
return spell.isCustomized;
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param spell
|
||||
*/
|
||||
export function getDuration(spell) {
|
||||
return getDefinitionDuration(spell);
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param spell
|
||||
*/
|
||||
export function getDefinitionDuration(spell) {
|
||||
var _a, _b;
|
||||
return (_b = (_a = spell.definition) === null || _a === void 0 ? void 0 : _a.duration) !== null && _b !== void 0 ? _b : null;
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param spell
|
||||
*/
|
||||
export function getDefinitionHealing(spell) {
|
||||
var _a, _b;
|
||||
return (_b = (_a = spell.definition) === null || _a === void 0 ? void 0 : _a.healing) !== null && _b !== void 0 ? _b : null;
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param spell
|
||||
*/
|
||||
export function getDefinitionHealingDice(spell) {
|
||||
var _a, _b;
|
||||
return (_b = (_a = spell.definition) === null || _a === void 0 ? void 0 : _a.healingDice) !== null && _b !== void 0 ? _b : [];
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param spell
|
||||
*/
|
||||
export function getComponents(spell) {
|
||||
return getDefinitionComponents(spell);
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param spell
|
||||
*/
|
||||
export function getDefinitionComponents(spell) {
|
||||
var _a, _b;
|
||||
return (_b = (_a = spell.definition) === null || _a === void 0 ? void 0 : _a.components) !== null && _b !== void 0 ? _b : [];
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param spell
|
||||
*/
|
||||
export function getComponentsDescription(spell) {
|
||||
return getDefinitionComponentsDescription(spell);
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param spell
|
||||
*/
|
||||
export function getDefinitionComponentsDescription(spell) {
|
||||
var _a, _b;
|
||||
return (_b = (_a = spell.definition) === null || _a === void 0 ? void 0 : _a.componentsDescription) !== null && _b !== void 0 ? _b : null;
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param spell
|
||||
*/
|
||||
export function getRange(spell) {
|
||||
return spell.range;
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param spell
|
||||
*/
|
||||
export function getRescriction(spell) {
|
||||
return spell.restriction;
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param spell
|
||||
*/
|
||||
export function getAdditionalDescription(spell) {
|
||||
return spell.additionalDescription;
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param spell
|
||||
*/
|
||||
export function getRequiresAttackRoll(spell) {
|
||||
return getDefinitionRequiresAttackRoll(spell);
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param spell
|
||||
*/
|
||||
export function getRequiresSavingThrow(spell) {
|
||||
return getDefinitionRequiresSavingThrow(spell);
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param spell
|
||||
*/
|
||||
export function getDefinitionRequiresSavingThrow(spell) {
|
||||
var _a, _b;
|
||||
return (_b = (_a = spell.definition) === null || _a === void 0 ? void 0 : _a.requiresSavingThrow) !== null && _b !== void 0 ? _b : false;
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param spell
|
||||
*/
|
||||
export function getAtHigherLevels(spell) {
|
||||
return spell.atHigherLevels;
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param spell
|
||||
*/
|
||||
export function getDefinitionAtHigherLevels(spell) {
|
||||
var _a, _b;
|
||||
return (_b = (_a = spell.definition) === null || _a === void 0 ? void 0 : _a.atHigherLevels) !== null && _b !== void 0 ? _b : null;
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param spell
|
||||
*/
|
||||
export function getCanCastAtHigherLevel(spell) {
|
||||
return getDefinitionCanCastAtHigherLevel(spell);
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param spell
|
||||
*/
|
||||
export function getDefinitionCanCastAtHigherLevel(spell) {
|
||||
var _a, _b;
|
||||
return (_b = (_a = spell.definition) === null || _a === void 0 ? void 0 : _a.canCastAtHigherLevel) !== null && _b !== void 0 ? _b : false;
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param spell
|
||||
*/
|
||||
export function getAttackSaveValue(spell) {
|
||||
return spell.attackSaveValue;
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param spell
|
||||
*/
|
||||
export function getBonusFixedDamage(spell) {
|
||||
return spell.bonusFixedDamage;
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param spell
|
||||
*/
|
||||
export function getSaveDcAbility(spell) {
|
||||
return getDefinitionSaveDcAbility(spell);
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param spell
|
||||
*/
|
||||
export function getDefinitionSaveDcAbility(spell) {
|
||||
var _a, _b;
|
||||
return (_b = (_a = spell.definition) === null || _a === void 0 ? void 0 : _a.saveDcAbilityId) !== null && _b !== void 0 ? _b : null;
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param spell
|
||||
*/
|
||||
export function getDefinitionScaleType(spell) {
|
||||
var _a, _b;
|
||||
return (_b = (_a = spell.definition) === null || _a === void 0 ? void 0 : _a.scaleType) !== null && _b !== void 0 ? _b : null;
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param spell
|
||||
*/
|
||||
export function getScaleType(spell) {
|
||||
return getDefinitionScaleType(spell);
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param spell
|
||||
*/
|
||||
export function getNotes(spell) {
|
||||
return spell.notes;
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param spell
|
||||
*/
|
||||
export function getDataOrigin(spell) {
|
||||
return spell.dataOrigin;
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param spell
|
||||
*/
|
||||
export function getDataOriginType(spell) {
|
||||
const dataOrigin = getDataOrigin(spell);
|
||||
return dataOrigin.type;
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param spell
|
||||
*/
|
||||
export function getExpandedDataOriginRef(spell) {
|
||||
return spell.expandedDataOriginRef;
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param spell
|
||||
*/
|
||||
export function getAtWillLimitedUseLevel(spell) {
|
||||
return spell.atWillLimitedUseLevel;
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param spell
|
||||
*/
|
||||
export function getComponentId(spell) {
|
||||
return spell.componentId;
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param spell
|
||||
*/
|
||||
export function getComponentTypeId(spell) {
|
||||
return spell.componentTypeId;
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param spell
|
||||
*/
|
||||
export function countsAsKnownSpell(spell) {
|
||||
return spell.countsAsKnownSpell;
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param spell
|
||||
*/
|
||||
export function getSpellCastingAbilityId(spell) {
|
||||
return spell.spellCastingAbilityId;
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param spell
|
||||
*/
|
||||
export function getOverrideSaveDc(spell) {
|
||||
return spell.overrideSaveDc;
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param spell
|
||||
*/
|
||||
export function getSpellListId(spell) {
|
||||
return spell.spellListId;
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param spell
|
||||
* @param useOverride
|
||||
*/
|
||||
export function getName(spell, useOverride = true) {
|
||||
var _a;
|
||||
if (useOverride && spell.name) {
|
||||
return spell.name;
|
||||
}
|
||||
return (_a = getDefinitionName(spell)) !== null && _a !== void 0 ? _a : '';
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param spell
|
||||
*/
|
||||
export function getCharacterLevel(spell) {
|
||||
return spell.characterLevel;
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param spell
|
||||
*/
|
||||
export function getEntity(spell) {
|
||||
return spell.entity;
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param spell
|
||||
*/
|
||||
export function getSpellcastingModifier(spell) {
|
||||
return spell.spellcastingModifier;
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param spell
|
||||
*/
|
||||
export function getDefinitionId(spell) {
|
||||
return spell.definitionId;
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param spell
|
||||
*/
|
||||
export function getIsSignatureSpell(spell) {
|
||||
return spell.isSignatureSpell;
|
||||
}
|
||||
/**
|
||||
* This is the mapping value of whether it is prepared, but may be false and the spell has
|
||||
* alwaysPrepared, so if you are checking for if the spell really is prepared use isPrepared()
|
||||
* @param spell
|
||||
*/
|
||||
export function getPrepared(spell) {
|
||||
return spell.prepared;
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param spell
|
||||
*/
|
||||
export function isPrepared(spell) {
|
||||
return spell.isPrepared;
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param spell
|
||||
*/
|
||||
export function isRitual(spell) {
|
||||
return spell.isRitual;
|
||||
}
|
||||
/**
|
||||
* @param spell
|
||||
*/
|
||||
export function isActive(spell) {
|
||||
return spell.isActive;
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param spell
|
||||
*/
|
||||
export function isCastAsRitual(spell) {
|
||||
return spell.isCastAsRitual;
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param spell
|
||||
*/
|
||||
export function getDefinitionSources(spell) {
|
||||
var _a, _b;
|
||||
return (_b = (_a = spell.definition) === null || _a === void 0 ? void 0 : _a.sources) !== null && _b !== void 0 ? _b : [];
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param spell
|
||||
*/
|
||||
export function getSources(spell) {
|
||||
return getDefinitionSources(spell);
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param spell - The spell in question
|
||||
*/
|
||||
export function getSpellGroupInfoLookup(spell) {
|
||||
return spell.spellGroupInfoLookup;
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param spell
|
||||
*/
|
||||
export function isAtWill(spell) {
|
||||
return spell.isAtWill;
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param spell
|
||||
*/
|
||||
export function isLimitedUseAvailableAtScaledAmount(spell) {
|
||||
return spell.isLimitedUseAvailableAtScaledAmount;
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param spell
|
||||
*/
|
||||
export function getScaledAmount(spell) {
|
||||
return spell.scaledAmount;
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param spell
|
||||
*/
|
||||
export function getCastLevel(spell) {
|
||||
return spell.castLevel;
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param spell
|
||||
*/
|
||||
export function getMaxUses(spell) {
|
||||
return spell.maxUses;
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param spell
|
||||
*/
|
||||
export function getConsumedUses(spell) {
|
||||
return spell.consumedUses;
|
||||
}
|
||||
export function isLegacy(spell) {
|
||||
var _a, _b;
|
||||
return (_b = (_a = getDefinition(spell)) === null || _a === void 0 ? void 0 : _a.isLegacy) !== null && _b !== void 0 ? _b : false;
|
||||
}
|
||||
@@ -0,0 +1,78 @@
|
||||
import { AdjustmentTypeEnum } from '../Value';
|
||||
export const DB_STRING_SPELL_ELDRITCH_BLAST = 'Eldritch Blast';
|
||||
export var SpellRangeTypeEnum;
|
||||
(function (SpellRangeTypeEnum) {
|
||||
SpellRangeTypeEnum[SpellRangeTypeEnum["SELF"] = 1] = "SELF";
|
||||
SpellRangeTypeEnum[SpellRangeTypeEnum["TOUCH"] = 2] = "TOUCH";
|
||||
SpellRangeTypeEnum[SpellRangeTypeEnum["RANGED"] = 3] = "RANGED";
|
||||
SpellRangeTypeEnum[SpellRangeTypeEnum["SIGHT"] = 4] = "SIGHT";
|
||||
SpellRangeTypeEnum[SpellRangeTypeEnum["UNLIMITED"] = 9] = "UNLIMITED";
|
||||
})(SpellRangeTypeEnum || (SpellRangeTypeEnum = {}));
|
||||
export var SpellRangeTypeNameEnum;
|
||||
(function (SpellRangeTypeNameEnum) {
|
||||
SpellRangeTypeNameEnum["SELF"] = "Self";
|
||||
SpellRangeTypeNameEnum["TOUCH"] = "Touch";
|
||||
SpellRangeTypeNameEnum["RANGED"] = "Ranged";
|
||||
SpellRangeTypeNameEnum["SIGHT"] = "Sight";
|
||||
SpellRangeTypeNameEnum["UNLIMITED"] = "Unlimited";
|
||||
})(SpellRangeTypeNameEnum || (SpellRangeTypeNameEnum = {}));
|
||||
export var SpellConditionTypeEnum;
|
||||
(function (SpellConditionTypeEnum) {
|
||||
SpellConditionTypeEnum[SpellConditionTypeEnum["APPLY"] = 1] = "APPLY";
|
||||
SpellConditionTypeEnum[SpellConditionTypeEnum["REMOVE"] = 2] = "REMOVE";
|
||||
SpellConditionTypeEnum[SpellConditionTypeEnum["SUPRESS"] = 3] = "SUPRESS";
|
||||
})(SpellConditionTypeEnum || (SpellConditionTypeEnum = {}));
|
||||
export var SpellDurationTypeEnum;
|
||||
(function (SpellDurationTypeEnum) {
|
||||
SpellDurationTypeEnum["INSTANTANEOUS"] = "Instantaneous";
|
||||
SpellDurationTypeEnum["CONCENTRATION"] = "Concentration";
|
||||
SpellDurationTypeEnum["TIME"] = "Time";
|
||||
SpellDurationTypeEnum["SPECIAL"] = "Special";
|
||||
SpellDurationTypeEnum["UNIT_DISPELLED"] = "Unit Dispelled";
|
||||
SpellDurationTypeEnum["UNIT_DISPELLED_TRIGGERED"] = "Unit Dispelled or Triggered";
|
||||
})(SpellDurationTypeEnum || (SpellDurationTypeEnum = {}));
|
||||
export var SpellPrepareTypeEnum;
|
||||
(function (SpellPrepareTypeEnum) {
|
||||
SpellPrepareTypeEnum[SpellPrepareTypeEnum["LEVEL"] = 1] = "LEVEL";
|
||||
SpellPrepareTypeEnum[SpellPrepareTypeEnum["HALF_LEVEL"] = 2] = "HALF_LEVEL";
|
||||
})(SpellPrepareTypeEnum || (SpellPrepareTypeEnum = {}));
|
||||
export var SpellScaleTypeNameEnum;
|
||||
(function (SpellScaleTypeNameEnum) {
|
||||
SpellScaleTypeNameEnum["CHARACTER_LEVEL"] = "characterlevel";
|
||||
SpellScaleTypeNameEnum["SPELL_SCALE"] = "spellscale";
|
||||
SpellScaleTypeNameEnum["SPELL_LEVEL"] = "spelllevel";
|
||||
})(SpellScaleTypeNameEnum || (SpellScaleTypeNameEnum = {}));
|
||||
export var RitualCastingTypeEnum;
|
||||
(function (RitualCastingTypeEnum) {
|
||||
RitualCastingTypeEnum[RitualCastingTypeEnum["CAN_CAST_AS_RITUAL"] = 1] = "CAN_CAST_AS_RITUAL";
|
||||
RitualCastingTypeEnum[RitualCastingTypeEnum["MUST_CAST_AS_RITUAL"] = 2] = "MUST_CAST_AS_RITUAL";
|
||||
})(RitualCastingTypeEnum || (RitualCastingTypeEnum = {}));
|
||||
export var SpellGroupEnum;
|
||||
(function (SpellGroupEnum) {
|
||||
SpellGroupEnum[SpellGroupEnum["HEALING"] = 1] = "HEALING";
|
||||
})(SpellGroupEnum || (SpellGroupEnum = {}));
|
||||
export const SPELL_CUSTOMIZATION_ADJUSTMENT_TYPES = [
|
||||
AdjustmentTypeEnum.SAVE_DC_BONUS,
|
||||
AdjustmentTypeEnum.SAVE_DC_OVERRIDE,
|
||||
AdjustmentTypeEnum.FIXED_VALUE_BONUS,
|
||||
AdjustmentTypeEnum.NAME_OVERRIDE,
|
||||
AdjustmentTypeEnum.TO_HIT_BONUS,
|
||||
AdjustmentTypeEnum.TO_HIT_OVERRIDE,
|
||||
AdjustmentTypeEnum.NOTES,
|
||||
AdjustmentTypeEnum.DISPLAY_AS_ATTACK,
|
||||
];
|
||||
export var SpellCastingLearningStyle;
|
||||
(function (SpellCastingLearningStyle) {
|
||||
SpellCastingLearningStyle[SpellCastingLearningStyle["Prepared"] = 1] = "Prepared";
|
||||
SpellCastingLearningStyle[SpellCastingLearningStyle["Learned"] = 2] = "Learned";
|
||||
})(SpellCastingLearningStyle || (SpellCastingLearningStyle = {}));
|
||||
;
|
||||
export const SpellCastingLearningStyleAddText = {
|
||||
[SpellCastingLearningStyle.Learned]: "Learn",
|
||||
[SpellCastingLearningStyle.Prepared]: "Prepare",
|
||||
};
|
||||
export const SpellCastingLearningStyleRemoveText = {
|
||||
[SpellCastingLearningStyle.Learned]: "Delete",
|
||||
[SpellCastingLearningStyle.Prepared]: "Unprepare",
|
||||
};
|
||||
export const DefaultSpellCastingLearningStyle = SpellCastingLearningStyle.Learned;
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,702 @@
|
||||
import { flatten, groupBy, orderBy, uniqBy } from 'lodash';
|
||||
import { TypeScriptUtils } from '../../utils';
|
||||
import { AbilityDerivers } from '../Ability';
|
||||
import { BackgroundAccessors, BackgroundDerivers } from '../Background';
|
||||
import { CampaignAccessors } from '../Campaign';
|
||||
import { CharacterDerivers, } from '../Character';
|
||||
import { ClassAccessors } from '../Class';
|
||||
import { ClassFeatureAccessors, ClassFeatureSimulators } from '../ClassFeature';
|
||||
import { DB_STRING_RITUAL_CASTER_LIST } from '../Core';
|
||||
import { DataOriginGenerators, DataOriginTypeEnum } from '../DataOrigin';
|
||||
import { FeatAccessors } from '../Feat';
|
||||
import { HelperUtils } from '../Helper';
|
||||
import { ItemAccessors, ItemDerivers, ItemValidators } from '../Item';
|
||||
import { LimitedUseDerivers } from '../LimitedUse';
|
||||
import { ModifierAccessors, ModifierBonusTypeEnum, ModifierDerivers, ModifierValidators, } from '../Modifier';
|
||||
import { OptionalClassFeatureAccessors } from '../OptionalClassFeature';
|
||||
import { OptionalOriginAccessors } from '../OptionalOrigin';
|
||||
import { RaceAccessors } from '../Race';
|
||||
import { RacialTraitAccessors, RacialTraitSimulators } from '../RacialTrait';
|
||||
import { RuleDataAccessors } from '../RuleData';
|
||||
import { asPartOfWeaponAttack, countsAsKnownSpell, getAttackType, getAtWillLimitedUseLevel, getBaseLevelAtWill, getComponentId, getComponentTypeId, getDataOrigin, getDataOriginType, getId, getLevel, getLimitedUse, getMappingId, getName, getSpellGroups, isActive, isAlwaysPrepared, isAttack, isCantrip, isDisplayAsAttack, } from './accessors';
|
||||
import { deriveAtHigherLevels, deriveCanPrepare, deriveCanRemove, deriveCharacterLevel, deriveExpandedDataOriginRef, deriveIsActive, deriveIsCantripsKnownMaxed, deriveIsCastAsRitual, deriveIsCastedByRitualSpellcaster, deriveIsCastedBySpellbookSpellcaster, deriveIsCustomized, deriveIsDisplayAsAttack, deriveIsPrepared, deriveIsRitual, deriveIsSpellsKnownMaxed, deriveKnownKey, deriveModifiers, deriveName, deriveNotes, deriveRange, deriveSpellAttackModifier, deriveSpellAttackSaveValue, deriveSpellBonusFixedDamage, deriveSpellPrepareMax, deriveSpellSpellcastingModifier, deriveSpellToHit, deriveStartingCastLevel, deriveUniqueKey, getCastLevelRange, getConsumedLimitedUse, getScaledDamage, } from './derivers';
|
||||
import { getScaledRange } from './utils';
|
||||
import { validateIsAtWill, validateIsLimitedUseAvailableAtScaledAmount, validateShouldShowCharacterSpellAtLevel, validateShouldShowClassSpellAtLevel, } from './validators';
|
||||
/**
|
||||
*
|
||||
* @param dataOriginSpell
|
||||
* @param valueLookup
|
||||
* @param ruleData
|
||||
*/
|
||||
export function generateBaseSpell(dataOriginSpell, valueLookup, ruleData) {
|
||||
return Object.assign(Object.assign({}, dataOriginSpell), { modifiers: deriveModifiers(dataOriginSpell, ruleData), isPrepared: deriveIsPrepared(dataOriginSpell), isActive: deriveIsActive(dataOriginSpell), isRitual: deriveIsRitual(dataOriginSpell), name: deriveName(dataOriginSpell, valueLookup), uniqueKey: deriveUniqueKey(dataOriginSpell), isCustomized: deriveIsCustomized(dataOriginSpell, valueLookup), atHigherLevels: deriveAtHigherLevels(dataOriginSpell, ruleData) });
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param spell
|
||||
* @param classInfo
|
||||
* @param overallInfo
|
||||
* @param valueLookup
|
||||
* @param ruleData
|
||||
* @param modifierData
|
||||
*/
|
||||
export function generateClassSpell(spell, classInfo, overallInfo, valueLookup, ruleData, modifierData) {
|
||||
const { proficiencyBonus, modifiers, abilityLookup, characterLevel, bonusCantripDamage } = overallInfo;
|
||||
const baseSpell = generateBaseSpell(spell, valueLookup, ruleData);
|
||||
let classFixedDamageTotal = classInfo.spellDamage;
|
||||
if (isCantrip(baseSpell)) {
|
||||
classFixedDamageTotal += bonusCantripDamage + classInfo.bonusCantripDamage;
|
||||
}
|
||||
return Object.assign(Object.assign({}, baseSpell), { range: deriveRange(baseSpell, modifiers, abilityLookup), name: deriveName(baseSpell, valueLookup), displayAsAttack: deriveIsDisplayAsAttack(baseSpell, valueLookup), isCastAsRitual: deriveIsCastAsRitual(baseSpell), notes: deriveNotes(baseSpell, valueLookup), toHit: deriveSpellToHit(baseSpell, modifiers, abilityLookup, proficiencyBonus, classInfo.toHit, valueLookup), attackSaveValue: deriveSpellAttackSaveValue(baseSpell, modifiers, proficiencyBonus, abilityLookup, classInfo.spellSaveDc, valueLookup), bonusFixedDamage: deriveSpellBonusFixedDamage(baseSpell, modifiers, abilityLookup, classFixedDamageTotal, valueLookup), spellcastingModifier: classInfo.spellcastingModifier, characterLevel: deriveCharacterLevel(baseSpell, characterLevel), canRemove: deriveCanRemove(baseSpell, classInfo), canPrepare: deriveCanPrepare(baseSpell, classInfo), canAdd: false, entity: null, spellGroupInfoLookup: generateSpellGroupInfoLookup(baseSpell, modifiers, modifierData) });
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param spell
|
||||
* @param modifiers
|
||||
* @param modifierData
|
||||
*/
|
||||
export function generateSpellGroupInfo(spell, spellGroupId, spellGroupModifiers, modifierData) {
|
||||
const highestGroupModifier = ModifierDerivers.deriveHighestValueModifier(spellGroupModifiers, modifierData);
|
||||
if (!highestGroupModifier) {
|
||||
return null;
|
||||
}
|
||||
return {
|
||||
spellGroupId,
|
||||
bonusFixedValue: ModifierDerivers.deriveValue(highestGroupModifier, modifierData, 0, true, {
|
||||
[ModifierBonusTypeEnum.SPELL_LEVEL]: getLevel(spell),
|
||||
}),
|
||||
useCastLevel: ModifierAccessors.getBonusTypes(highestGroupModifier).includes(ModifierBonusTypeEnum.SPELL_LEVEL),
|
||||
};
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param spell
|
||||
* @param modifiers
|
||||
* @param modifierData
|
||||
*/
|
||||
export function generateSpellGroupInfoLookup(spell, modifiers, modifierData) {
|
||||
const spellGroupInfos = getSpellGroups(spell)
|
||||
.map((spellGroupId) => {
|
||||
const spellGroupModifiers = modifiers.filter((modifier) => ModifierValidators.isValidBonusSpellGroupModifier(modifier, spellGroupId));
|
||||
return generateSpellGroupInfo(spell, spellGroupId, spellGroupModifiers, modifierData);
|
||||
})
|
||||
.filter(TypeScriptUtils.isNotNullOrUndefined);
|
||||
return HelperUtils.generateNonNullLookup(spellGroupInfos, (spellGroupInfo) => spellGroupInfo.spellGroupId);
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param toHitFallback
|
||||
* @param attackSaveFallback
|
||||
* @param bonusFixedDamageFallback
|
||||
* @param spellcastingModifier
|
||||
*/
|
||||
export function generateCharacterSpell_contextInfo(toHitFallback, attackSaveFallback, bonusFixedDamageFallback, spellcastingModifier) {
|
||||
return {
|
||||
toHitFallback,
|
||||
attackSaveFallback,
|
||||
bonusFixedDamageFallback,
|
||||
spellcastingModifier,
|
||||
};
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param spell
|
||||
* @param overallInfo
|
||||
* @param contextInfo
|
||||
* @param valueLookup
|
||||
* @param ruleData
|
||||
*/
|
||||
export function generateCharacterSpell(spell, overallInfo, contextInfo, valueLookup, ruleData, modifierData) {
|
||||
const { proficiencyBonus, modifiers, abilityLookup, characterLevel } = overallInfo;
|
||||
const baseSpell = generateBaseSpell(spell, valueLookup, ruleData);
|
||||
return Object.assign(Object.assign({}, baseSpell), { range: deriveRange(baseSpell, modifiers, abilityLookup), name: deriveName(baseSpell, valueLookup), displayAsAttack: deriveIsDisplayAsAttack(baseSpell, valueLookup), isCastAsRitual: deriveIsCastAsRitual(baseSpell), notes: deriveNotes(baseSpell, valueLookup), toHit: deriveSpellToHit(baseSpell, modifiers, abilityLookup, proficiencyBonus, contextInfo.toHitFallback, valueLookup), attackSaveValue: deriveSpellAttackSaveValue(baseSpell, modifiers, proficiencyBonus, abilityLookup, contextInfo.attackSaveFallback, valueLookup), bonusFixedDamage: deriveSpellBonusFixedDamage(baseSpell, modifiers, abilityLookup, contextInfo.bonusFixedDamageFallback, valueLookup), spellcastingModifier: deriveSpellSpellcastingModifier(baseSpell, abilityLookup, contextInfo.spellcastingModifier), canPrepare: false, canRemove: false, characterLevel: deriveCharacterLevel(baseSpell, characterLevel), canAdd: false, entity: null, spellGroupInfoLookup: generateSpellGroupInfoLookup(baseSpell, modifiers, modifierData) });
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param featureSpells
|
||||
* @param classSpells
|
||||
*/
|
||||
export function updateClassSpells(featureSpells, classSpells) {
|
||||
featureSpells.forEach((spell, spellIdx) => {
|
||||
if (getAtWillLimitedUseLevel(spell) !== null) {
|
||||
const classSpellIdx = classSpells.findIndex((decoratedSpell) => getId(decoratedSpell) === getId(spell));
|
||||
if (classSpellIdx > -1) {
|
||||
const classSpell = classSpells[classSpellIdx];
|
||||
const spellAlwaysPrepared = isAlwaysPrepared(spell);
|
||||
classSpells[classSpellIdx] = Object.assign(Object.assign({}, classSpell), { alwaysPrepared: spellAlwaysPrepared ? spellAlwaysPrepared : isAlwaysPrepared(classSpell) });
|
||||
}
|
||||
}
|
||||
});
|
||||
const alwaysPreparedSpellIds = classSpells.filter((spell) => isAlwaysPrepared(spell)).map((spell) => getId(spell));
|
||||
let finalSpells = classSpells;
|
||||
if (alwaysPreparedSpellIds.length) {
|
||||
finalSpells = classSpells.filter((spell) => {
|
||||
if (!isAlwaysPrepared(spell) && alwaysPreparedSpellIds.includes(getId(spell))) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
});
|
||||
}
|
||||
return finalSpells;
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param featureSpells
|
||||
* @param classSpells
|
||||
*/
|
||||
export function updateClassFeatureSpells(featureSpells, classSpells) {
|
||||
return featureSpells.map((spell, spellIdx) => {
|
||||
if (getBaseLevelAtWill(spell)) {
|
||||
const decoratedSpellIdx = classSpells.findIndex((decoratedSpell) => getId(decoratedSpell) === getId(spell));
|
||||
if (decoratedSpellIdx > -1) {
|
||||
const decoratedSpell = classSpells[decoratedSpellIdx];
|
||||
return Object.assign(Object.assign({}, spell), { prepared: deriveIsPrepared(decoratedSpell) });
|
||||
}
|
||||
}
|
||||
return spell;
|
||||
});
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param characterLevel
|
||||
* @param charClasses
|
||||
* @param abilityLookup
|
||||
* @param profBonus
|
||||
* @param modifiers
|
||||
*/
|
||||
export function generateClassSpellLists(characterLevel, charClasses, abilityLookup, profBonus, modifiers) {
|
||||
return charClasses.map((charClass) => generateClassSpellsInfo(characterLevel, charClass, abilityLookup, profBonus, modifiers));
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param characterLevel
|
||||
* @param charClass
|
||||
* @param abilityLookup
|
||||
* @param profBonus
|
||||
* @param modifiers
|
||||
*/
|
||||
export function generateClassSpellsInfo(characterLevel, charClass, abilityLookup, profBonus, modifiers) {
|
||||
var _a;
|
||||
let decoratedSpells = ClassAccessors.getSpells(charClass);
|
||||
const classSlug = ClassAccessors.getSlug(charClass);
|
||||
const classLevel = ClassAccessors.getLevel(charClass);
|
||||
const classSpellRules = ClassAccessors.getSpellRules(charClass);
|
||||
const spellPrepareType = ClassAccessors.getSpellPrepareType(charClass);
|
||||
const spellcastingModifier = AbilityDerivers.deriveStatModifier(classSpellRules.spellcastingAbilityStatId, abilityLookup);
|
||||
const knownCantripsMax = classSpellRules.levelCantripsKnownMaxes
|
||||
? classSpellRules.levelCantripsKnownMaxes[classLevel]
|
||||
: null;
|
||||
const knownSpellsMax = classSpellRules.levelSpellKnownMaxes
|
||||
? classSpellRules.levelSpellKnownMaxes[classLevel]
|
||||
: null;
|
||||
const preparedSpellsMax = classSpellRules.levelPreparedSpellMaxes
|
||||
? (_a = classSpellRules.levelPreparedSpellMaxes[classLevel]) !== null && _a !== void 0 ? _a : null // coallesce if the array is shorter than the class level, happens for prepared classes not using OSIRIS rules
|
||||
: null;
|
||||
const prepareMax = preparedSpellsMax !== null && preparedSpellsMax !== void 0 ? preparedSpellsMax : deriveSpellPrepareMax(spellPrepareType, classLevel, spellcastingModifier);
|
||||
const canAddSpells = !classSpellRules.knowsAllSpells || knownCantripsMax !== null || knownSpellsMax === null;
|
||||
const baseToHitModifier = deriveSpellAttackModifier(profBonus, spellcastingModifier);
|
||||
const bonusSpellSaveDcModifiers = modifiers.filter((modifier) => ModifierValidators.isBonusSpellSaveDc(modifier));
|
||||
const bonusSpellSaveDcModifierTotal = ModifierDerivers.sumModifiers(bonusSpellSaveDcModifiers, abilityLookup);
|
||||
const classSaveDcModifiers = modifiers.filter((modifier) => ModifierValidators.isValidBonusClassSpellSaveDcModifier(modifier, classSlug));
|
||||
const classSaveDcModifierTotal = ModifierDerivers.sumModifiers(classSaveDcModifiers, abilityLookup);
|
||||
const spellSaveDc = CharacterDerivers.deriveAttackSaveValue(profBonus, spellcastingModifier) +
|
||||
bonusSpellSaveDcModifierTotal +
|
||||
classSaveDcModifierTotal;
|
||||
decoratedSpells = orderBy(decoratedSpells, [(spell) => getLevel(spell), (spell) => getName(spell)]);
|
||||
const activeSpells = decoratedSpells.filter((spell) => deriveIsActive(spell));
|
||||
let activeCantripsCount = decoratedSpells.filter((s) => countsAsKnownSpell(s) && isCantrip(s)).length;
|
||||
const activeFeatureCantripCount = ClassAccessors.getFeatureSpells(charClass).filter((s) => countsAsKnownSpell(s) && isCantrip(s)).length;
|
||||
activeCantripsCount += activeFeatureCantripCount;
|
||||
let knownSpellCount = decoratedSpells.filter((s) => countsAsKnownSpell(s) && !isCantrip(s)).length;
|
||||
const knownFeatureSpellCount = ClassAccessors.getFeatureSpells(charClass).filter((s) => countsAsKnownSpell(s) && !isCantrip(s)).length;
|
||||
knownSpellCount += knownFeatureSpellCount;
|
||||
const preparedSpellCount = decoratedSpells.filter((s) => !isCantrip(s) && deriveIsPrepared(s, false) && countsAsKnownSpell(s)).length;
|
||||
const knownSpellNames = decoratedSpells.map((spell) => getName(spell, false));
|
||||
const knownSpellIds = decoratedSpells.map((spell) => deriveKnownKey(spell));
|
||||
const isSpellsKnownMaxed = deriveIsSpellsKnownMaxed(knownSpellsMax, knownSpellCount, classSpellRules.knowsAllSpells);
|
||||
const isCantripsKnownMaxed = deriveIsCantripsKnownMaxed(knownCantripsMax, activeCantripsCount);
|
||||
const isPrepareMaxed = !!prepareMax && preparedSpellCount >= prepareMax;
|
||||
let ritualSpells = [];
|
||||
if (classSpellRules.isRitualSpellCaster) {
|
||||
ritualSpells = decoratedSpells.filter((spell) => deriveIsRitual(spell) &&
|
||||
(isCantrip(spell) ||
|
||||
(classSpellRules.isPreparedSpellcaster && deriveIsPrepared(spell)) ||
|
||||
classSpellRules.isKnownSpellcaster ||
|
||||
classSpellRules.isSpellbookSpellcaster));
|
||||
}
|
||||
return {
|
||||
charClass,
|
||||
knownSpellcaster: classSpellRules.isKnownSpellcaster,
|
||||
preparedSpellcaster: classSpellRules.isPreparedSpellcaster,
|
||||
spellbookSpellcaster: classSpellRules.isSpellbookSpellcaster,
|
||||
spellcastingModifier,
|
||||
spellcastingAbility: classSpellRules.spellcastingAbilityStat,
|
||||
attackSaveValue: spellSaveDc,
|
||||
toHitValue: baseToHitModifier,
|
||||
prepareMax,
|
||||
knownCantripsMax,
|
||||
knownSpellsMax,
|
||||
canAddSpells,
|
||||
isSpellsKnownMaxed,
|
||||
isCantripsKnownMaxed,
|
||||
isPrepareMaxed,
|
||||
spells: decoratedSpells,
|
||||
activeSpells,
|
||||
ritualSpells,
|
||||
knownSpellNames,
|
||||
knownSpellIds,
|
||||
activeCantripsCount,
|
||||
activeFeatureCantripCount,
|
||||
knownSpellCount,
|
||||
knownFeatureSpellCount,
|
||||
preparedSpellCount,
|
||||
};
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param spell
|
||||
*/
|
||||
export function generateDataOriginKey(spell) {
|
||||
return DataOriginGenerators.generateDataOriginKey(getComponentId(spell), getComponentTypeId(spell));
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param spells
|
||||
*/
|
||||
export function generateSpellComponentLookup(spells) {
|
||||
return groupBy(spells, (spell) => generateDataOriginKey(spell));
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param spells
|
||||
* @param partyInfo
|
||||
*/
|
||||
export function generateItemSpellLookup(spells, partyInfo) {
|
||||
const partyItemSpells = partyInfo ? CampaignAccessors.getItemSpells(partyInfo) : [];
|
||||
return generateSpellComponentLookup(uniqBy([...partyItemSpells, ...spells], (spell) => getMappingId(spell)));
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param modifiers
|
||||
* @param items
|
||||
* @param feats
|
||||
* @param race
|
||||
* @param classes
|
||||
* @param proficiencyBonus
|
||||
* @param abilityLookup
|
||||
* @param classSpellInfoLookup
|
||||
* @param overallSpellInfo
|
||||
* @param valueLookup
|
||||
* @param ruleData
|
||||
* @param modifierData
|
||||
*/
|
||||
export function generateCharacterSpells(modifiers, items, feats, race, classes, proficiencyBonus, abilityLookup, classSpellInfoLookup, overallSpellInfo, valueLookup, ruleData, modifierData) {
|
||||
/**
|
||||
* NOTE: Talked through, and we decided that any character spell cannot be forced
|
||||
* to go lower than a 0 value for each of these highest values. You shouldn't be forced
|
||||
* to take a -1 into your calculation if you are very unoptimized
|
||||
*/
|
||||
let highestMiscAttackSave = CharacterDerivers.deriveAttackSaveValue(proficiencyBonus, 0);
|
||||
let highestMiscToHit = proficiencyBonus;
|
||||
let highestSpellcastingModifier = 0;
|
||||
let highestFixedDamage = 0;
|
||||
classes.forEach((charClass) => {
|
||||
if (ClassAccessors.isSpellcastingActive(charClass) || ClassAccessors.isPactMagicActive(charClass)) {
|
||||
// TODO fix lookup
|
||||
const classSpellInfo = classSpellInfoLookup[ClassAccessors.getId(charClass)];
|
||||
if (classSpellInfo.spellSaveDc > highestMiscAttackSave) {
|
||||
highestMiscAttackSave = classSpellInfo.spellSaveDc;
|
||||
}
|
||||
if (classSpellInfo.baseToHitModifier > highestMiscToHit) {
|
||||
highestMiscToHit = classSpellInfo.baseToHitModifier;
|
||||
}
|
||||
if (classSpellInfo.spellcastingModifier > highestSpellcastingModifier) {
|
||||
highestSpellcastingModifier = classSpellInfo.spellcastingModifier;
|
||||
}
|
||||
if (classSpellInfo.spellDamage > highestFixedDamage) {
|
||||
highestFixedDamage = classSpellInfo.spellDamage;
|
||||
}
|
||||
}
|
||||
});
|
||||
const spells = [];
|
||||
items.forEach((item) => {
|
||||
const itemSpells = ItemAccessors.getSpells(item);
|
||||
const updatedSpells = itemSpells.map((spell) => {
|
||||
const contextInfo = generateCharacterSpell_contextInfo(highestMiscToHit, highestMiscAttackSave, isCantrip(spell) ? overallSpellInfo.bonusCantripDamage : highestFixedDamage, highestSpellcastingModifier);
|
||||
return generateCharacterSpell(spell, overallSpellInfo, contextInfo, valueLookup, ruleData, modifierData);
|
||||
});
|
||||
spells.push(...updatedSpells);
|
||||
});
|
||||
const featureFallbackToHit = CharacterDerivers.deriveAttackModifier(proficiencyBonus, 0);
|
||||
const featureFallbackSaveDc = CharacterDerivers.deriveAttackSaveValue(proficiencyBonus, 0);
|
||||
const featureFallbackSpellcastingModifier = 0;
|
||||
const featureFixedDamage = 0;
|
||||
feats.forEach((feat) => {
|
||||
const featSpells = FeatAccessors.getSpells(feat);
|
||||
const updatedSpells = featSpells.map((spell) => {
|
||||
const contextInfo = generateCharacterSpell_contextInfo(featureFallbackToHit, featureFallbackSaveDc, isCantrip(spell) ? overallSpellInfo.bonusCantripDamage : featureFixedDamage, featureFallbackSpellcastingModifier);
|
||||
return generateCharacterSpell(spell, overallSpellInfo, contextInfo, valueLookup, ruleData, modifierData);
|
||||
});
|
||||
spells.push(...updatedSpells);
|
||||
});
|
||||
if (race) {
|
||||
const raceSpells = RaceAccessors.getSpells(race);
|
||||
const updatedRaceSpells = raceSpells.map((spell) => {
|
||||
const contextInfo = generateCharacterSpell_contextInfo(featureFallbackToHit, featureFallbackSaveDc, isCantrip(spell) ? overallSpellInfo.bonusCantripDamage : featureFixedDamage, featureFallbackSpellcastingModifier);
|
||||
return generateCharacterSpell(spell, overallSpellInfo, contextInfo, valueLookup, ruleData, modifierData);
|
||||
});
|
||||
spells.push(...updatedRaceSpells);
|
||||
}
|
||||
classes.forEach((charClass) => {
|
||||
const classSpellInfo = classSpellInfoLookup[ClassAccessors.getId(charClass)];
|
||||
ClassAccessors.getFeatureSpells(charClass).forEach((spell) => {
|
||||
let fixedDamageTotal = classSpellInfo.spellDamage;
|
||||
if (isCantrip(spell)) {
|
||||
fixedDamageTotal += overallSpellInfo.bonusCantripDamage + classSpellInfo.bonusCantripDamage;
|
||||
}
|
||||
const contextInfo = generateCharacterSpell_contextInfo(classSpellInfo.toHit, classSpellInfo.spellSaveDc, fixedDamageTotal, classSpellInfo.spellcastingModifier);
|
||||
spells.push(generateCharacterSpell(spell, overallSpellInfo, contextInfo, valueLookup, ruleData, modifierData));
|
||||
});
|
||||
});
|
||||
return spells;
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param spellSlots
|
||||
*/
|
||||
export function generateMaxSpellSlotLevel(spellSlots) {
|
||||
if (spellSlots.length) {
|
||||
const sortedSlot = HelperUtils.getLast(spellSlots, ['level']);
|
||||
if (sortedSlot) {
|
||||
return sortedSlot.level;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param maxSpellSlotLevel
|
||||
* @param maxPactMagicSlotLevel
|
||||
*/
|
||||
export function generateCombinedMaxSpellSlotLevel(maxSpellSlotLevel, maxPactMagicSlotLevel) {
|
||||
return Math.max(maxSpellSlotLevel, maxPactMagicSlotLevel);
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param spellSlots
|
||||
*/
|
||||
export function generateAvailableSpellSlotLevels(spellSlots) {
|
||||
return spellSlots.filter((slot) => slot.available > 0).map((slot) => slot.level);
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param spellSlots
|
||||
*/
|
||||
export function generateCastableSpellSlotLevels(spellSlots) {
|
||||
return spellSlots.filter((slot) => slot.available - slot.used > 0).map((slot) => slot.level);
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param classes
|
||||
*/
|
||||
export function generateClassSpells(classes) {
|
||||
const spells = [];
|
||||
for (let i = 0; i < classes.length; i++) {
|
||||
const charClass = classes[i];
|
||||
spells.push(...ClassAccessors.getSpells(charClass));
|
||||
}
|
||||
return spells;
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param classSpells
|
||||
*/
|
||||
export function generateActiveClassSpells(classSpells) {
|
||||
return classSpells.filter(isActive);
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param attackClassSpellLists
|
||||
* @param characterSpells
|
||||
*/
|
||||
export function generateActiveSpellAttackList(attackClassSpellLists, characterSpells) {
|
||||
return [
|
||||
...flatten(attackClassSpellLists.map((ClassSpellInfo) => ClassSpellInfo.activeSpells)),
|
||||
...characterSpells,
|
||||
].filter((spell) => !asPartOfWeaponAttack(spell) &&
|
||||
((isAttack(spell) && (isDisplayAsAttack(spell) || isDisplayAsAttack(spell) === null)) ||
|
||||
isDisplayAsAttack(spell)));
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param classSpells
|
||||
* @param characterSpells
|
||||
* @param xpInfo
|
||||
*/
|
||||
export function generateWeaponSpellDamageGroups(classSpells, characterSpells, xpInfo) {
|
||||
const damageSources = [];
|
||||
classSpells.forEach((spell) => {
|
||||
if (!asPartOfWeaponAttack(spell)) {
|
||||
return;
|
||||
}
|
||||
const damageDice = getScaledDamage(spell);
|
||||
if (damageDice.length) {
|
||||
damageSources.push({
|
||||
spell,
|
||||
damageDice,
|
||||
attackTypeRange: getAttackType(spell),
|
||||
});
|
||||
}
|
||||
});
|
||||
characterSpells.forEach((spell) => {
|
||||
if (!asPartOfWeaponAttack(spell)) {
|
||||
return;
|
||||
}
|
||||
const damageDice = getScaledDamage(spell);
|
||||
if (damageDice.length) {
|
||||
damageSources.push({
|
||||
spell,
|
||||
damageDice,
|
||||
attackTypeRange: getAttackType(spell),
|
||||
});
|
||||
}
|
||||
});
|
||||
return damageSources;
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param activeCharacterSpells
|
||||
* @param classSpells
|
||||
*/
|
||||
export function generateRitualSpells(activeCharacterSpells, classSpells) {
|
||||
const ritualCharacterSpells = activeCharacterSpells.filter((spell) => {
|
||||
const dataOrigin = getDataOrigin(spell);
|
||||
const dataOriginType = getDataOriginType(spell);
|
||||
if (dataOriginType === DataOriginTypeEnum.FEAT &&
|
||||
DB_STRING_RITUAL_CASTER_LIST.includes(FeatAccessors.getName(dataOrigin.primary)) &&
|
||||
deriveIsRitual(spell)) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
});
|
||||
const ritualClassSpells = classSpells.filter((spell) => {
|
||||
if (deriveIsRitual(spell) && deriveIsCastedByRitualSpellcaster(spell)) {
|
||||
if (deriveIsCastedBySpellbookSpellcaster(spell)) {
|
||||
return true;
|
||||
}
|
||||
return deriveIsActive(spell);
|
||||
}
|
||||
return false;
|
||||
});
|
||||
return [...ritualCharacterSpells, ...ritualClassSpells];
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param spell
|
||||
* @param castLevel
|
||||
* @param spellCasterInfo
|
||||
* @param ruleData
|
||||
* @param abilityLookup
|
||||
* @param proficiencyBonus
|
||||
*/
|
||||
function generateScaledSpell(spell, castLevel, spellCasterInfo, ruleData, abilityLookup, proficiencyBonus) {
|
||||
const startingCastLevel = deriveStartingCastLevel(spell);
|
||||
const scaledAmount = Math.max(0, castLevel - startingCastLevel);
|
||||
const limitedUse = getLimitedUse(spell);
|
||||
let maxUses = null;
|
||||
if (limitedUse != null) {
|
||||
maxUses = LimitedUseDerivers.deriveMaxUses(limitedUse, abilityLookup, ruleData, proficiencyBonus);
|
||||
}
|
||||
const isLimitedUseAvailableAtScaledAmount = validateIsLimitedUseAvailableAtScaledAmount(spell, castLevel, scaledAmount, abilityLookup, ruleData, spellCasterInfo, proficiencyBonus);
|
||||
return Object.assign(Object.assign({}, spell), { range: getScaledRange(spell, castLevel), consumedUses: getConsumedLimitedUse(spell, scaledAmount), isAtWill: validateIsAtWill(spell, castLevel), isLimitedUseAvailableAtScaledAmount,
|
||||
castLevel,
|
||||
maxUses,
|
||||
scaledAmount });
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param xpInfo
|
||||
* @param classSpells
|
||||
* @param characterSpells
|
||||
* @param proficiencyBonus
|
||||
* @param spellCasterInfo
|
||||
* @param ruleData
|
||||
* @param preferences
|
||||
* @param abilityLookup
|
||||
*/
|
||||
export function generateLevelSpells(xpInfo, classSpells, characterSpells, proficiencyBonus, spellCasterInfo, ruleData, preferences, abilityLookup) {
|
||||
const maxSpellLevel = RuleDataAccessors.getMaxSpellLevel(ruleData);
|
||||
const levels = [];
|
||||
// Setup array to exist for all possible spell levels cantrip => maxSpellLevel
|
||||
for (let i = 0; i <= maxSpellLevel; i++) {
|
||||
levels.push([]);
|
||||
}
|
||||
classSpells.forEach((spell) => {
|
||||
const startLevel = getLevel(spell);
|
||||
for (let i = startLevel; i <= maxSpellLevel; i++) {
|
||||
if (validateShouldShowClassSpellAtLevel(spell, i, spellCasterInfo, preferences)) {
|
||||
levels[i].push(generateScaledSpell(spell, i, spellCasterInfo, ruleData, abilityLookup, proficiencyBonus));
|
||||
}
|
||||
}
|
||||
});
|
||||
characterSpells.forEach((spell) => {
|
||||
const { startLevel, endLevel } = getCastLevelRange(spell, spellCasterInfo, ruleData);
|
||||
for (let i = startLevel; i <= endLevel; i++) {
|
||||
if (validateShouldShowCharacterSpellAtLevel(spell, i, spellCasterInfo, preferences)) {
|
||||
levels[i].push(generateScaledSpell(spell, i, spellCasterInfo, ruleData, abilityLookup, proficiencyBonus));
|
||||
}
|
||||
}
|
||||
});
|
||||
const sortOrderLookup = {
|
||||
[DataOriginTypeEnum.RACE]: 1,
|
||||
[DataOriginTypeEnum.CLASS]: 2,
|
||||
[DataOriginTypeEnum.FEAT]: 3,
|
||||
[DataOriginTypeEnum.BACKGROUND]: 4,
|
||||
[DataOriginTypeEnum.ITEM]: 5,
|
||||
};
|
||||
const sortedLevels = [];
|
||||
for (let i = 0; i <= maxSpellLevel; i++) {
|
||||
sortedLevels.push(orderBy(levels[i], [
|
||||
(spell) => getName(spell),
|
||||
(spell) => {
|
||||
const type = getDataOriginType(spell);
|
||||
let orderNum = 100;
|
||||
if (type !== null) {
|
||||
const lookupOrderNum = sortOrderLookup[type];
|
||||
if (lookupOrderNum) {
|
||||
orderNum = lookupOrderNum;
|
||||
}
|
||||
}
|
||||
return orderNum;
|
||||
},
|
||||
]));
|
||||
}
|
||||
return sortedLevels;
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param spell
|
||||
* @param dataOriginType
|
||||
* @param primary
|
||||
* @param parent
|
||||
* @param spellListDataOriginLookup
|
||||
*/
|
||||
export function generateDataOriginSpell(spell, dataOriginType, primary, parent, spellListDataOriginLookup) {
|
||||
return Object.assign(Object.assign({}, spell), { dataOrigin: DataOriginGenerators.generateDataOrigin(dataOriginType, primary, parent), expandedDataOriginRef: deriveExpandedDataOriginRef(spell, spellListDataOriginLookup) });
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param id
|
||||
* @param entityTypeId
|
||||
* @param spellLookup
|
||||
* @param dataOriginType
|
||||
* @param primary
|
||||
* @param parent
|
||||
* @param ruleData
|
||||
* @param spellListDataOriginLookup
|
||||
* @param valueLookup
|
||||
*/
|
||||
export function generateBaseSpells(id, entityTypeId, spellLookup, dataOriginType, primary, parent, ruleData, spellListDataOriginLookup, valueLookup) {
|
||||
const spells = HelperUtils.lookupDataOrFallback(spellLookup, DataOriginGenerators.generateDataOriginKey(id, entityTypeId));
|
||||
if (!spells) {
|
||||
return [];
|
||||
}
|
||||
return spells.map((spell) => {
|
||||
const dataOriginSpell = generateDataOriginSpell(spell, dataOriginType, primary, parent, spellListDataOriginLookup);
|
||||
return generateBaseSpell(dataOriginSpell, valueLookup, ruleData);
|
||||
});
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param spells
|
||||
* @param inventoryInfusionLookup
|
||||
* @param characterId
|
||||
*/
|
||||
export function generateActiveCharacterSpells(spells, inventoryInfusionLookup, characterId) {
|
||||
return spells.filter((spell) => {
|
||||
const dataOrigin = getDataOrigin(spell);
|
||||
const dataOriginType = getDataOriginType(spell);
|
||||
if (dataOriginType === DataOriginTypeEnum.ITEM) {
|
||||
const item = dataOrigin.primary;
|
||||
const mappingId = ItemAccessors.getMappingId(item);
|
||||
const infusion = HelperUtils.lookupDataOrFallback(inventoryInfusionLookup, mappingId);
|
||||
if (ItemDerivers.deriveCanAttune(item, infusion)) {
|
||||
return ItemValidators.isEquippedToCurrentCharacter(item, characterId) && ItemAccessors.isAttuned(item);
|
||||
}
|
||||
return ItemValidators.isEquippedToCurrentCharacter(item, characterId);
|
||||
}
|
||||
return true;
|
||||
});
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param race
|
||||
* @param classes
|
||||
* @param background
|
||||
* @param optionalOrigins
|
||||
* @param optionalClassFeatures
|
||||
* @param definitionPool
|
||||
*/
|
||||
export function generateSpellListDataOriginLookup(race, classes, background, optionalOrigins, optionalClassFeatures, definitionPool) {
|
||||
let lookup = {};
|
||||
if (race !== null) {
|
||||
RaceAccessors.getDefinitionRacialTraits(race).forEach((feature) => {
|
||||
const uniqueKey = RacialTraitAccessors.getUniqueKey(feature);
|
||||
RacialTraitAccessors.getSpellListIds(feature).forEach((spellListId) => {
|
||||
lookup[spellListId] = DataOriginGenerators.generateDataOriginRef(DataOriginTypeEnum.RACE, uniqueKey);
|
||||
});
|
||||
});
|
||||
}
|
||||
if (background !== null) {
|
||||
const uniqueKey = BackgroundDerivers.deriveUniqueKey(background);
|
||||
BackgroundAccessors.getSpellListIds(background).forEach((spellListId) => {
|
||||
lookup[spellListId] = DataOriginGenerators.generateDataOriginRef(DataOriginTypeEnum.BACKGROUND, uniqueKey);
|
||||
});
|
||||
}
|
||||
classes.forEach((charClass) => {
|
||||
ClassAccessors.getDefinitionClassFeatures(charClass).forEach((feature) => {
|
||||
const uniqueKey = ClassFeatureAccessors.getUniqueKey(feature);
|
||||
ClassFeatureAccessors.getSpellListIds(feature).forEach((spellListId) => {
|
||||
lookup[spellListId] = DataOriginGenerators.generateDataOriginRef(DataOriginTypeEnum.CLASS_FEATURE, uniqueKey);
|
||||
});
|
||||
});
|
||||
});
|
||||
optionalOrigins.forEach((optionalOrigin) => {
|
||||
const definitionKey = OptionalOriginAccessors.getDefinitionKey(optionalOrigin);
|
||||
if (!definitionKey) {
|
||||
return;
|
||||
}
|
||||
const racialTrait = RacialTraitSimulators.simulateRacialTrait(definitionKey, definitionPool);
|
||||
if (!racialTrait) {
|
||||
return;
|
||||
}
|
||||
const uniqueKey = RacialTraitAccessors.getUniqueKey(racialTrait);
|
||||
RacialTraitAccessors.getSpellListIds(racialTrait).forEach((spellListId) => {
|
||||
lookup[spellListId] = DataOriginGenerators.generateDataOriginRef(DataOriginTypeEnum.RACE, uniqueKey);
|
||||
});
|
||||
});
|
||||
optionalClassFeatures.forEach((optionalClassFeature) => {
|
||||
const definitionKey = OptionalClassFeatureAccessors.getDefinitionKey(optionalClassFeature);
|
||||
if (!definitionKey) {
|
||||
return;
|
||||
}
|
||||
const feature = ClassFeatureSimulators.simulateClassFeature(definitionKey, definitionPool, classes);
|
||||
if (!feature) {
|
||||
return;
|
||||
}
|
||||
const uniqueKey = ClassFeatureAccessors.getUniqueKey(feature);
|
||||
ClassFeatureAccessors.getSpellListIds(feature).forEach((spellListId) => {
|
||||
lookup[spellListId] = DataOriginGenerators.generateDataOriginRef(DataOriginTypeEnum.CLASS_FEATURE, uniqueKey);
|
||||
});
|
||||
});
|
||||
return lookup;
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param raceSpellListIds
|
||||
* @param backgroundSpellListIds
|
||||
*/
|
||||
export function generateGlobalSpellListIds(raceSpellListIds, backgroundSpellListIds) {
|
||||
return [...raceSpellListIds, ...backgroundSpellListIds];
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
import { HelperUtils } from '../Helper';
|
||||
import { ModifierValidators } from '../Modifier';
|
||||
import { getSpellGroupInfoLookup } from './accessors';
|
||||
import { SpellGroupEnum } from './constants';
|
||||
/**
|
||||
* We needed to display very contextual verbiage for
|
||||
* spells that did damage and the healed based on that
|
||||
* damage on SpellDetail.tsx via SpellCaster.tsx on
|
||||
* the healing node.
|
||||
* - Ask Julie or Brian Life Domain Cleric
|
||||
* @param modifiers
|
||||
* @param spell
|
||||
* @param scaledHealingDie
|
||||
*/
|
||||
export function hack__isHealingDieAdditionalBonusFixedValue(modifiers, spell, scaledHealingDie) {
|
||||
if (!scaledHealingDie) {
|
||||
return false;
|
||||
}
|
||||
const damageModifiers = modifiers.filter((modifier) => ModifierValidators.isSpellDamageModifier(modifier));
|
||||
return (damageModifiers.length > 0 &&
|
||||
HelperUtils.lookupDataOrFallback(getSpellGroupInfoLookup(spell), SpellGroupEnum.HEALING, false) &&
|
||||
!scaledHealingDie.diceValue &&
|
||||
!scaledHealingDie.diceCount &&
|
||||
scaledHealingDie.fixedValue !== null);
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
import * as SpellAccessors from './accessors';
|
||||
import * as SpellConstants from './constants';
|
||||
import * as SpellDerivers from './derivers';
|
||||
import * as SpellGenerators from './generators';
|
||||
import * as SpellHacks from './hacks';
|
||||
import * as SpellNotes from './notes';
|
||||
import * as SpellSimulators from './simulators';
|
||||
import * as SpellTypings from './typings';
|
||||
import * as SpellUtils from './utils';
|
||||
import * as SpellValidators from './validators';
|
||||
export * from './constants';
|
||||
export * from './typings';
|
||||
export { SpellAccessors, SpellDerivers, SpellGenerators, SpellNotes, SpellSimulators, SpellUtils, SpellValidators, SpellHacks, };
|
||||
export default Object.assign(Object.assign(Object.assign(Object.assign(Object.assign(Object.assign(Object.assign(Object.assign(Object.assign(Object.assign({}, SpellAccessors), SpellConstants), SpellDerivers), SpellGenerators), SpellNotes), SpellSimulators), SpellTypings), SpellUtils), SpellValidators), SpellHacks);
|
||||
@@ -0,0 +1,160 @@
|
||||
import { TypeScriptUtils } from '../../utils';
|
||||
import { DataOriginTypeEnum } from '../DataOrigin';
|
||||
import { DurationAccessors, DurationRenderers } from '../Duration';
|
||||
import { FormatUtils } from '../Format';
|
||||
import { LimitedUseAccessors, LimitedUseDerivers, LimitedUseRenderers } from '../LimitedUse';
|
||||
import { NoteGenerators } from '../Note';
|
||||
import { DisplayIntentionEnum } from '../Note';
|
||||
import { RuleDataUtils } from '../RuleData';
|
||||
import { getAtHigherLevels, getComponents, getConcentration, getDuration, getLimitedUse, getNotes, getRange, getDataOriginType, isCantrip, getScaleType, } from './accessors';
|
||||
import { SpellDurationTypeEnum } from './constants';
|
||||
import { getConsumedLimitedUse, getSpellScaledAtHigher, isSpellScaledByCastLevel } from './derivers';
|
||||
/**
|
||||
*
|
||||
* @param spell
|
||||
* @param castLevel
|
||||
* @param characterLevel
|
||||
*/
|
||||
export function getScaledNoteComponent(spell, castLevel, characterLevel) {
|
||||
const atHigherLevels = getAtHigherLevels(spell);
|
||||
if (!atHigherLevels) {
|
||||
return null;
|
||||
}
|
||||
const scaleType = getScaleType(spell);
|
||||
const additionalAttacks = atHigherLevels.additionalAttacks === null ? [] : atHigherLevels.additionalAttacks;
|
||||
const additionalTargets = atHigherLevels.additionalTargets === null ? [] : atHigherLevels.additionalTargets;
|
||||
const areaOfEffect = atHigherLevels.areaOfEffect === null ? [] : atHigherLevels.areaOfEffect;
|
||||
const duration = atHigherLevels.duration === null ? [] : atHigherLevels.duration;
|
||||
const creatures = atHigherLevels.creatures === null ? [] : atHigherLevels.creatures;
|
||||
const special = atHigherLevels.special === null ? [] : atHigherLevels.special;
|
||||
if (!additionalAttacks.length &&
|
||||
!additionalTargets.length &&
|
||||
!areaOfEffect.length &&
|
||||
!duration.length &&
|
||||
!creatures.length &&
|
||||
!special.length) {
|
||||
return null;
|
||||
}
|
||||
let isScaled = false;
|
||||
isScaled = isScaled || isSpellScaledByCastLevel(spell, getScaleType(spell), additionalAttacks, castLevel);
|
||||
isScaled = isScaled || isSpellScaledByCastLevel(spell, getScaleType(spell), additionalTargets, castLevel);
|
||||
isScaled = isScaled || isSpellScaledByCastLevel(spell, getScaleType(spell), areaOfEffect, castLevel);
|
||||
isScaled = isScaled || isSpellScaledByCastLevel(spell, getScaleType(spell), duration, castLevel);
|
||||
isScaled = isScaled || isSpellScaledByCastLevel(spell, getScaleType(spell), creatures, castLevel);
|
||||
isScaled = isScaled || isSpellScaledByCastLevel(spell, getScaleType(spell), special, castLevel);
|
||||
let higherDisplay;
|
||||
const additionalAttackInfo = getSpellScaledAtHigher(spell, scaleType, additionalAttacks, characterLevel, castLevel);
|
||||
if (additionalAttackInfo) {
|
||||
const totalCount = additionalAttackInfo.totalCount;
|
||||
const additionalAttackCount = isCantrip(spell) ? totalCount + 1 : totalCount;
|
||||
const additionalAttackLabel = isCantrip(spell) ? '' : '+';
|
||||
higherDisplay = `Count: ${additionalAttackLabel}${additionalAttackCount}`;
|
||||
}
|
||||
const additionalTargetInfo = getSpellScaledAtHigher(spell, scaleType, additionalTargets, characterLevel, castLevel);
|
||||
if (!higherDisplay && additionalTargetInfo) {
|
||||
higherDisplay = `Targets: +${additionalTargetInfo.targets}`;
|
||||
}
|
||||
const aoeInfo = getSpellScaledAtHigher(spell, scaleType, areaOfEffect, characterLevel, castLevel);
|
||||
if (!higherDisplay && aoeInfo) {
|
||||
const extArea = aoeInfo.extendedAoe;
|
||||
if (extArea) {
|
||||
higherDisplay = `Ext. Area: ${FormatUtils.renderDistance(extArea)}`;
|
||||
}
|
||||
}
|
||||
const durationInfo = getSpellScaledAtHigher(spell, scaleType, duration, characterLevel, castLevel);
|
||||
if (!higherDisplay && durationInfo) {
|
||||
higherDisplay = `Ext. D: ${durationInfo.description}`;
|
||||
}
|
||||
const creatureInfo = getSpellScaledAtHigher(spell, scaleType, creatures, characterLevel, castLevel);
|
||||
if (!higherDisplay && creatureInfo) {
|
||||
higherDisplay = `Creatures: ${creatureInfo.description}`;
|
||||
}
|
||||
const specialInfo = getSpellScaledAtHigher(spell, scaleType, special, characterLevel, castLevel);
|
||||
if (!higherDisplay && specialInfo) {
|
||||
higherDisplay = `Special: ${specialInfo.description}`;
|
||||
}
|
||||
if (!higherDisplay) {
|
||||
return null;
|
||||
}
|
||||
const displayIntention = isScaled ? DisplayIntentionEnum.SCALED : null;
|
||||
return NoteGenerators.createPlainText(higherDisplay, displayIntention);
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param spell
|
||||
*/
|
||||
function getUserNoteComponent(spell) {
|
||||
const notes = getNotes(spell);
|
||||
if (notes) {
|
||||
return NoteGenerators.createPlainText(notes);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param spell
|
||||
* @param castLevel
|
||||
* @param characterLevel
|
||||
* @param abilityLookup
|
||||
* @param ruleData
|
||||
* @param scaledAmount
|
||||
* @param proficiencyBonus
|
||||
*/
|
||||
export function getNoteComponents(spell, castLevel, characterLevel, abilityLookup, ruleData, scaledAmount = 0, proficiencyBonus) {
|
||||
const notes = [];
|
||||
const range = getRange(spell);
|
||||
const components = getComponents(spell);
|
||||
const duration = getDuration(spell);
|
||||
const limitedUse = getLimitedUse(spell);
|
||||
if (limitedUse) {
|
||||
const consumedAmount = getConsumedLimitedUse(spell, scaledAmount);
|
||||
const maxUses = LimitedUseDerivers.deriveMaxUses(limitedUse, abilityLookup, ruleData, proficiencyBonus);
|
||||
const numberUsed = LimitedUseAccessors.getNumberUsed(limitedUse);
|
||||
const numberRemaining = maxUses - numberUsed;
|
||||
if (getDataOriginType(spell) === DataOriginTypeEnum.ITEM) {
|
||||
if (consumedAmount !== null) {
|
||||
if (maxUses === 1) {
|
||||
const isUsed = numberUsed === 1;
|
||||
notes.push(NoteGenerators.createPlainText(`1 Charge${isUsed ? ' (Used)' : ''}`));
|
||||
}
|
||||
else {
|
||||
notes.push(NoteGenerators.createPlainText(`${consumedAmount} Charge${consumedAmount !== 1 ? 's' : ''} (${numberRemaining}/${maxUses})`));
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (maxUses === 1) {
|
||||
const resetType = LimitedUseAccessors.getResetType(limitedUse);
|
||||
const resetTypeAbbr = LimitedUseRenderers.renderLimitedUseResetAbbreviation(resetType);
|
||||
const isUsed = numberUsed === 1;
|
||||
const limitedUseResetTypeName = resetType === null ? '' : RuleDataUtils.getLimitedUseResetTypeName(resetType, ruleData);
|
||||
notes.push(NoteGenerators.createTooltip(`1/${resetTypeAbbr}${isUsed ? ' (Used)' : ''}`, `Once per ${limitedUseResetTypeName}${isUsed ? ' (Used)' : ''}`, {
|
||||
dynamicTitle: true,
|
||||
}));
|
||||
}
|
||||
else {
|
||||
notes.push(NoteGenerators.createPlainText(`${consumedAmount} Use${consumedAmount !== 1 ? 's' : ''} (${numberRemaining}/${maxUses})`));
|
||||
}
|
||||
}
|
||||
const scaledNotesNode = getScaledNoteComponent(spell, castLevel, characterLevel);
|
||||
if (scaledNotesNode) {
|
||||
notes.push(scaledNotesNode);
|
||||
}
|
||||
if (duration && DurationAccessors.getType(duration) !== SpellDurationTypeEnum.INSTANTANEOUS) {
|
||||
notes.push(NoteGenerators.createTooltip(`D: ${DurationRenderers.renderDurationAbbreviation(duration)}`, `${DurationRenderers.renderDuration(duration, getConcentration(spell))} Duration`));
|
||||
}
|
||||
if (range && range.aoeValue !== null && range.aoeType !== null) {
|
||||
notes.push(NoteGenerators.createGroup([NoteGenerators.createDistance(range.aoeValue), NoteGenerators.createAoeIcon(range.aoeType)], ''));
|
||||
}
|
||||
if (components) {
|
||||
const componentNoteParts = [];
|
||||
components.forEach((componentId, idx) => {
|
||||
const componentInfo = RuleDataUtils.getSpellComponentInfo(componentId, ruleData);
|
||||
if (componentInfo && componentInfo.shortName !== null) {
|
||||
componentNoteParts.push(NoteGenerators.createTooltip(componentInfo.shortName, componentInfo.name));
|
||||
}
|
||||
});
|
||||
notes.push(NoteGenerators.createGroup(componentNoteParts, '/'));
|
||||
}
|
||||
notes.push(getUserNoteComponent(spell));
|
||||
return notes.filter(TypeScriptUtils.isNotNullOrUndefined);
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
import { DataOriginTypeEnum } from '../DataOrigin';
|
||||
import { deriveCharacterLevel, deriveIsCastAsRitual, deriveName } from './derivers';
|
||||
import { generateBaseSpell, generateDataOriginSpell } from './generators';
|
||||
/**
|
||||
*
|
||||
* @param spell
|
||||
* @param overallInfo
|
||||
* @param ruleData
|
||||
* @param primary
|
||||
* @param parent
|
||||
*/
|
||||
export function simulateSpell(spell, overallInfo, ruleData, primary, parent) {
|
||||
const dataOriginSpell = generateDataOriginSpell(spell, DataOriginTypeEnum.SIMULATED, primary, parent, overallInfo.spellListDataOriginLookup);
|
||||
const baseSpell = generateBaseSpell(dataOriginSpell, {}, ruleData);
|
||||
return Object.assign(Object.assign({}, baseSpell), { attackSaveValue: null, bonusFixedDamage: 0, canPrepare: false, canRemove: false, characterLevel: deriveCharacterLevel(baseSpell, overallInfo.characterLevel), isCustomized: false, isCastAsRitual: deriveIsCastAsRitual(baseSpell), name: deriveName(baseSpell, {}), notes: '', spellcastingModifier: 0, toHit: null, canAdd: true, entity: spell, spellGroupInfoLookup: {} });
|
||||
}
|
||||
@@ -0,0 +1,86 @@
|
||||
import { DiceAccessors } from '../Dice';
|
||||
import { HelperUtils } from '../Helper';
|
||||
import { ModifierAccessors, ModifierValidators } from '../Modifier';
|
||||
import { RuleDataUtils } from '../RuleData';
|
||||
import { SpellGroupEnum } from '../Spell';
|
||||
import { getAtHigherLevels, getBonusFixedDamage, getLevel, getRange, getSaveDcAbility, getScaleType, getSpellcastingModifier, getSpellGroupInfoLookup, } from './accessors';
|
||||
import { getSpellScaledAtHigher } from './derivers';
|
||||
/**
|
||||
* @deprecated
|
||||
*/
|
||||
export function getSaveDcAbilityKey(spell, ruleData) {
|
||||
return RuleDataUtils.getAbilityKey(getSaveDcAbility(spell), ruleData);
|
||||
}
|
||||
export function getSaveDcAbilityShortName(spell, ruleData) {
|
||||
return RuleDataUtils.getAbilityShortName(getSaveDcAbility(spell), ruleData);
|
||||
}
|
||||
/**
|
||||
* @param spell
|
||||
* @param modifier
|
||||
* @param atHigherLevelInfo
|
||||
* @param castLevel
|
||||
*/
|
||||
export function getSpellFinalScaledDie(spell, modifier, atHigherLevelInfo, castLevel = null) {
|
||||
let scaledDie = atHigherLevelInfo === null ? ModifierAccessors.getDie(modifier) : atHigherLevelInfo.die;
|
||||
if (scaledDie === null) {
|
||||
return null;
|
||||
}
|
||||
const fixedDiceValue = DiceAccessors.getFixedValue(scaledDie);
|
||||
let fixedValue = (fixedDiceValue === null ? 0 : fixedDiceValue) + getBonusFixedDamage(spell);
|
||||
if (ModifierAccessors.getUsePrimaryStat(modifier)) {
|
||||
fixedValue += getSpellcastingModifier(spell);
|
||||
}
|
||||
const isHealingHitModifier = ModifierValidators.isSpellHealingHitPointsModifier(modifier);
|
||||
const spellGroupInfoLookup = getSpellGroupInfoLookup(spell);
|
||||
const healingGroupInfo = HelperUtils.lookupDataOrFallback(spellGroupInfoLookup, SpellGroupEnum.HEALING);
|
||||
if (isHealingHitModifier && healingGroupInfo) {
|
||||
fixedValue += healingGroupInfo.bonusFixedValue;
|
||||
if (healingGroupInfo.useCastLevel && castLevel) {
|
||||
fixedValue += castLevel - getLevel(spell);
|
||||
}
|
||||
}
|
||||
return Object.assign(Object.assign({}, scaledDie), { fixedValue });
|
||||
}
|
||||
export function getScaledRange(spell, castLevel) {
|
||||
var _a, _b, _c;
|
||||
const spellRange = getRange(spell);
|
||||
if (spellRange === null) {
|
||||
return null;
|
||||
}
|
||||
const higherLevel = getSpellScaledAtHigher(spell, getScaleType(spell), (_b = (_a = getAtHigherLevels(spell)) === null || _a === void 0 ? void 0 : _a.range) !== null && _b !== void 0 ? _b : [], null, castLevel);
|
||||
return Object.assign(Object.assign({}, spellRange), { rangeValue: (_c = higherLevel === null || higherLevel === void 0 ? void 0 : higherLevel.range) !== null && _c !== void 0 ? _c : spellRange.rangeValue });
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param spell
|
||||
*/
|
||||
export function makeKnownKey(mappingId, mappingEntityTypeId) {
|
||||
return `${mappingId}-${mappingEntityTypeId}`;
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param spell
|
||||
*/
|
||||
export function makeLeveledKnownKey(mappingId, mappingEntityTypeId, castLevel) {
|
||||
return `${makeKnownKey(mappingId, mappingEntityTypeId)}-${castLevel}`;
|
||||
}
|
||||
/**
|
||||
* Given a ClassSpellInfo object and a SpellID, determine if the spell is known by the character
|
||||
* using RPGSpell ID as key
|
||||
* @param spellList
|
||||
* @param spellId
|
||||
* @returns
|
||||
*/
|
||||
export const isSpellKnown = (spellList, spellId) => spellList.spells.some(
|
||||
// Compare the given SpellID with the Spell Definition ID
|
||||
// SpellID is the ID of the record from RPGSpell (SQL Server: Waterdeep)
|
||||
(spell) => {
|
||||
var _a;
|
||||
return ((_a = spell.definition) === null || _a === void 0 ? void 0 : _a.id) === spellId &&
|
||||
spellList.knownSpellIds.some(
|
||||
// Compare the resulting Spell's ID with the KnownSpellID
|
||||
// KnownSpellID is a combination of the ClassMappingID of the record from CharacterSpellMapping (MySQL: YawningPortal)
|
||||
// and the EntityTypeID of its granting feature (i.e.- a Wizard's class spells will be granted as RPGClassSpellMapping) in
|
||||
// the format of "{ClassMappingID}-{EntityTypeID}"
|
||||
(knownSpellId) => spell.id === Number(knownSpellId.split('-')[0]));
|
||||
});
|
||||
@@ -0,0 +1,184 @@
|
||||
import { ClassAccessors } from '../Class';
|
||||
import { DataOriginTypeEnum } from '../DataOrigin';
|
||||
import { FeatUtils } from '../Feat';
|
||||
import { LimitedUseAccessors, LimitedUseDerivers } from '../LimitedUse';
|
||||
import { getBaseLevelAtWill, getCanCastAtHigherLevel, getCastAtLevel, getDataOrigin, getDataOriginType, getLevel, getLimitedUse, getUsesSpellSlot, isActive, isCantrip, isRitual, } from './accessors';
|
||||
import { deriveIsActive, deriveIsCastedByRitualSpellcaster, deriveIsCastedBySpellbookSpellcaster, deriveIsPrepared, deriveIsRitual, deriveMustCastAsRitual, getCastLevelAvailableCount, getConsumedLimitedUse, isSpellAvailableAtLevel, } from './derivers';
|
||||
/**
|
||||
*
|
||||
* @param spell
|
||||
* @param level
|
||||
* @param spellCasterInfo
|
||||
*/
|
||||
export function validateHasShownSpellSlotsBeforeLevel(spell, level, spellCasterInfo) {
|
||||
if ((spellCasterInfo.firstAvailableSpellSlotLevel !== null &&
|
||||
spellCasterInfo.lastAvailableSpellSlotLevel !== null &&
|
||||
spellCasterInfo.firstAvailableSpellSlotLevel < level &&
|
||||
spellCasterInfo.lastAvailableSpellSlotLevel >= getLevel(spell)) ||
|
||||
(spellCasterInfo.firstAvailablePactMagicSlotLevel !== null &&
|
||||
spellCasterInfo.lastAvailablePactMagicSlotLevel !== null &&
|
||||
spellCasterInfo.firstAvailablePactMagicSlotLevel < level &&
|
||||
spellCasterInfo.lastAvailablePactMagicSlotLevel >= getLevel(spell))) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param spell
|
||||
* @param level
|
||||
* @param spellCasterInfo
|
||||
* @param preferences
|
||||
*/
|
||||
export function validateShouldShowClassSpellAtLevel(spell, level, spellCasterInfo, preferences) {
|
||||
if (!deriveIsActive(spell)) {
|
||||
if (deriveIsRitual(spell) &&
|
||||
getLevel(spell) === level &&
|
||||
deriveIsCastedByRitualSpellcaster(spell) &&
|
||||
deriveIsCastedBySpellbookSpellcaster(spell)) {
|
||||
return true;
|
||||
}
|
||||
else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
if (isCantrip(spell)) {
|
||||
return getLevel(spell) === level;
|
||||
}
|
||||
// show spells that have to show at a specific level
|
||||
if (getCastAtLevel(spell) === level) {
|
||||
return true;
|
||||
}
|
||||
if (isSpellAvailableAtLevel(spell, level, spellCasterInfo)) {
|
||||
if (getLevel(spell) === level) {
|
||||
// Check for normal spellcasting rules if a spell is just supposed to show at current level
|
||||
return true;
|
||||
}
|
||||
else {
|
||||
// show scalable spells
|
||||
if (preferences.showScaledSpells && getCanCastAtHigherLevel(spell)) {
|
||||
return true;
|
||||
}
|
||||
// Force scale spells that don't normally scale, but this is first time slots are available (warlocks)
|
||||
if (!validateHasShownSpellSlotsBeforeLevel(spell, level, spellCasterInfo)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param spell
|
||||
* @param level
|
||||
* @param spellCasterInfo
|
||||
* @param preferences
|
||||
*/
|
||||
export function validateShouldShowCharacterSpellAtLevel(spell, level, spellCasterInfo, preferences) {
|
||||
if (isCantrip(spell)) {
|
||||
return getLevel(spell) === level;
|
||||
}
|
||||
if (getUsesSpellSlot(spell)) {
|
||||
if (isSpellAvailableAtLevel(spell, level, spellCasterInfo)) {
|
||||
if (preferences.showScaledSpells) {
|
||||
return true;
|
||||
}
|
||||
else {
|
||||
return getLevel(spell) === level;
|
||||
}
|
||||
}
|
||||
else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
if (getBaseLevelAtWill(spell)) {
|
||||
return deriveIsPrepared(spell);
|
||||
}
|
||||
if (preferences.showScaledSpells) {
|
||||
return true;
|
||||
}
|
||||
else {
|
||||
if (getCastAtLevel(spell) === level) {
|
||||
return true;
|
||||
}
|
||||
return getLevel(spell) === level;
|
||||
}
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param spell
|
||||
* @param castLevel
|
||||
*/
|
||||
export function validateIsAtWill(spell, castLevel) {
|
||||
const limitedUse = getLimitedUse(spell);
|
||||
const usesSpellSlot = getUsesSpellSlot(spell);
|
||||
const baseLevelAtWill = getBaseLevelAtWill(spell);
|
||||
if (isCantrip(spell)) {
|
||||
return limitedUse === null;
|
||||
}
|
||||
if (baseLevelAtWill && castLevel === getLevel(spell)) {
|
||||
return true;
|
||||
}
|
||||
if (!limitedUse && !usesSpellSlot) {
|
||||
return true;
|
||||
}
|
||||
if (isRitual(spell) && deriveMustCastAsRitual(spell)) {
|
||||
return true;
|
||||
}
|
||||
if (isRitual(spell) &&
|
||||
!isActive(spell) &&
|
||||
deriveIsCastedByRitualSpellcaster(spell) &&
|
||||
deriveIsCastedBySpellbookSpellcaster(spell)) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param spell
|
||||
* @param castLevel
|
||||
* @param scaledAmount
|
||||
* @param abilityLookup
|
||||
* @param ruleData
|
||||
* @param spellCasterInfo
|
||||
* @param proficiencyBonus
|
||||
*/
|
||||
export function validateIsLimitedUseAvailableAtScaledAmount(spell, castLevel, scaledAmount, abilityLookup, ruleData, spellCasterInfo, proficiencyBonus) {
|
||||
const limitedUse = getLimitedUse(spell);
|
||||
if (limitedUse === null) {
|
||||
return false;
|
||||
}
|
||||
const maxUses = LimitedUseDerivers.deriveMaxUses(limitedUse, abilityLookup, ruleData, proficiencyBonus);
|
||||
const numberUsed = LimitedUseAccessors.getNumberUsed(limitedUse);
|
||||
const usesSpellSlots = getUsesSpellSlot(spell);
|
||||
const consumedAmount = getConsumedLimitedUse(spell, scaledAmount);
|
||||
let isAvailable = numberUsed + consumedAmount <= maxUses;
|
||||
let areSpellSlotsAvailable;
|
||||
if (isAvailable && usesSpellSlots) {
|
||||
const dataOrigin = getDataOrigin(spell);
|
||||
const dataOriginType = getDataOriginType(spell);
|
||||
if (dataOriginType === DataOriginTypeEnum.CLASS_FEATURE &&
|
||||
ClassAccessors.isPactMagicActive(dataOrigin.parent)) {
|
||||
areSpellSlotsAvailable = getCastLevelAvailableCount(castLevel, spellCasterInfo.pactMagicSlots);
|
||||
}
|
||||
else {
|
||||
areSpellSlotsAvailable = getCastLevelAvailableCount(castLevel, spellCasterInfo.spellSlots);
|
||||
}
|
||||
if (areSpellSlotsAvailable !== null) {
|
||||
isAvailable = areSpellSlotsAvailable > 0;
|
||||
}
|
||||
}
|
||||
return isAvailable;
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param spell
|
||||
*/
|
||||
export function isValidToUsePactSlots(spell) {
|
||||
const dataOrigin = getDataOrigin(spell);
|
||||
const dataOriginType = getDataOriginType(spell);
|
||||
return ((dataOriginType === DataOriginTypeEnum.CLASS_FEATURE &&
|
||||
ClassAccessors.isPactMagicActive(dataOrigin.parent)) ||
|
||||
(dataOriginType === DataOriginTypeEnum.FEAT &&
|
||||
FeatUtils.isEldritchAdept(dataOrigin.parent)));
|
||||
}
|
||||
Reference in New Issue
Block a user