``` ~/go/bin/sourcemapper -output ddb -jsurl https://media.dndbeyond.com/character-app/static/js/main.90aa78c5.js ```
330 lines
17 KiB
JavaScript
330 lines
17 KiB
JavaScript
import { characterActions } from "../actions";
|
|
import { ActivationAccessors } from "../engine/Activation";
|
|
import { ClassAccessors } from "../engine/Class";
|
|
import { ConditionAccessors } from "../engine/Condition";
|
|
import { DataOriginTypeEnum } from "../engine/DataOrigin";
|
|
import { DiceRenderers } from "../engine/Dice";
|
|
import { EntityUtils } from "../engine/Entity";
|
|
import { HelperUtils } from "../engine/Helper";
|
|
import { ItemAccessors } from "../engine/Item";
|
|
import { LimitedUseAccessors } from "../engine/LimitedUse";
|
|
import { ModifierAccessors, ModifierValidators } from "../engine/Modifier";
|
|
import { RuleDataUtils } from "../engine/RuleData";
|
|
import { SpellAccessors, SpellDerivers, SpellNotes, SpellUtils, SpellValidators } from "../engine/Spell";
|
|
import { FormatUtils } from "../index";
|
|
import { rulesEngineSelectors } from "../selectors";
|
|
import { ItemManager } from './ItemManager';
|
|
import { getSpellManager } from './SpellManager';
|
|
import { SpellsManager } from './SpellsManager';
|
|
export const leveledSpellManagerMap = new Map();
|
|
export const getLeveledSpellManager = (params) => {
|
|
const { spell } = params;
|
|
const spellManager = getSpellManager(params);
|
|
const leveledKnownKey = spellManager.deriveLeveledKnownKey(SpellAccessors.getCastLevel(spell));
|
|
if (leveledSpellManagerMap.has(leveledKnownKey)) {
|
|
const leveledSpellManager = leveledSpellManagerMap.get(leveledKnownKey);
|
|
if (!leveledSpellManager) {
|
|
throw new Error(`leveledSpellManager for spell ${leveledKnownKey} is null`);
|
|
}
|
|
if (leveledSpellManager.spell === spell) {
|
|
return leveledSpellManager;
|
|
}
|
|
}
|
|
const newLeveledSpellManager = new LeveledSpellManager(params);
|
|
leveledSpellManagerMap.set(leveledKnownKey, newLeveledSpellManager);
|
|
return newLeveledSpellManager;
|
|
};
|
|
export class LeveledSpellManager extends SpellsManager {
|
|
constructor(params) {
|
|
super(params);
|
|
// Handlers
|
|
this.onSpellLimitedUseSet = (uses) => {
|
|
const mappingId = this.getMappingId();
|
|
const mappingTypeId = this.getMappingEntityTypeId();
|
|
if (mappingId !== null && mappingTypeId !== null) {
|
|
this.dispatch(characterActions.spellUseSet(mappingId, mappingTypeId, uses, this.getDataOriginType()));
|
|
}
|
|
};
|
|
this.onUse = (useSpellSlot, usePactMagicSlot, dataOriginType, uses, mappingId, mappingTypeId) => {
|
|
if (useSpellSlot) {
|
|
this.handleSpellSlotChange(1, this.getCastLevel());
|
|
}
|
|
if (usePactMagicSlot) {
|
|
this.handlePactSlotChange(1, this.getCastLevel());
|
|
}
|
|
if (uses !== null && mappingId !== null && mappingTypeId !== null) {
|
|
switch (dataOriginType) {
|
|
case DataOriginTypeEnum.ITEM:
|
|
const item = ItemManager.getItem(mappingId);
|
|
item.handleItemLimitedUseSet(uses);
|
|
break;
|
|
default:
|
|
this.onSpellLimitedUseSet(uses);
|
|
}
|
|
}
|
|
};
|
|
this.handleSpellUse = (useSpellSlot, usePactMagicSlot) => {
|
|
let dataOrigin = this.getDataOrigin();
|
|
let dataOriginType = this.getDataOriginType();
|
|
let limitedUse = this.getLimitedUse();
|
|
let uses = null;
|
|
let mappingId = null;
|
|
let mappingTypeId = null;
|
|
if (limitedUse) {
|
|
let numberUsed = LimitedUseAccessors.getNumberUsed(limitedUse);
|
|
let minConsumed = LimitedUseAccessors.getMinNumberConsumed(limitedUse);
|
|
let consumedAmount = minConsumed + this.getScaledAmount();
|
|
if (dataOriginType === DataOriginTypeEnum.ITEM) {
|
|
uses = numberUsed + consumedAmount;
|
|
mappingId = ItemAccessors.getMappingId(dataOrigin.primary);
|
|
mappingTypeId = ItemAccessors.getMappingEntityTypeId(dataOrigin.primary);
|
|
}
|
|
else {
|
|
uses = numberUsed + 1;
|
|
mappingId = this.getMappingId();
|
|
mappingTypeId = this.getMappingEntityTypeId();
|
|
}
|
|
}
|
|
if (this.onUse) {
|
|
this.onUse(useSpellSlot, usePactMagicSlot, dataOriginType, uses, mappingId, mappingTypeId);
|
|
}
|
|
};
|
|
this.handleCastClick = (bothSlotsCallback) => {
|
|
let usesSpellSlot = this.getUsesSpellSlot();
|
|
let limitedUse = this.getLimitedUse();
|
|
let spellSlotLevel = this.getSpellSlotInfo();
|
|
let pactMagicLevel = this.getPactSlotInfo();
|
|
let doesSpellSlotExist = !!spellSlotLevel && spellSlotLevel.available > 0;
|
|
let doesPactSlotExist = !!pactMagicLevel && pactMagicLevel.available > 0;
|
|
let isSpellSlotAvailable = false;
|
|
if (doesSpellSlotExist && spellSlotLevel) {
|
|
isSpellSlotAvailable = spellSlotLevel.used < spellSlotLevel.available;
|
|
}
|
|
let isPactSlotAvailable = false;
|
|
if (doesPactSlotExist && pactMagicLevel) {
|
|
isPactSlotAvailable = pactMagicLevel.used < pactMagicLevel.available;
|
|
}
|
|
if (usesSpellSlot) {
|
|
if (limitedUse) {
|
|
const spellDataOrigin = this.getDataOrigin();
|
|
const spellDataOriginType = this.getDataOriginType();
|
|
if (spellDataOriginType === DataOriginTypeEnum.CLASS_FEATURE &&
|
|
ClassAccessors.isPactMagicActive(spellDataOrigin.parent)) {
|
|
if (isPactSlotAvailable) {
|
|
this.handleSpellUse(false, true);
|
|
}
|
|
}
|
|
else {
|
|
if (isSpellSlotAvailable) {
|
|
this.handleSpellUse(true, false);
|
|
}
|
|
}
|
|
}
|
|
else {
|
|
if (doesSpellSlotExist && doesPactSlotExist) {
|
|
if (!bothSlotsCallback) {
|
|
throw new Error('No callback passed for encountering both slots');
|
|
}
|
|
bothSlotsCallback();
|
|
}
|
|
else {
|
|
if (isSpellSlotAvailable) {
|
|
this.handleSpellUse(true, false);
|
|
}
|
|
else if (isPactSlotAvailable) {
|
|
this.handleSpellUse(false, true);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
else {
|
|
this.handleSpellUse(false, false);
|
|
}
|
|
};
|
|
// Accessors
|
|
this.getId = () => SpellAccessors.getId(this.spell);
|
|
this.getDataOrigin = () => SpellAccessors.getDataOrigin(this.spell);
|
|
this.getDataOriginType = () => SpellAccessors.getDataOriginType(this.spell);
|
|
this.getLimitedUse = () => SpellAccessors.getLimitedUse(this.spell);
|
|
this.getScaledAmount = () => SpellAccessors.getScaledAmount(this.spell);
|
|
this.getScaleType = () => SpellAccessors.getScaleType(this.spell);
|
|
this.getMappingId = () => SpellAccessors.getMappingId(this.spell);
|
|
this.getMappingEntityTypeId = () => SpellAccessors.getMappingEntityTypeId(this.spell);
|
|
this.getUsesSpellSlot = () => SpellAccessors.getUsesSpellSlot(this.spell);
|
|
this.getName = () => SpellAccessors.getName(this.spell);
|
|
this.asPartOfWeaponAttack = () => SpellAccessors.asPartOfWeaponAttack(this.spell);
|
|
this.getRequiresAttackRoll = () => SpellAccessors.getRequiresAttackRoll(this.spell);
|
|
this.getRequiresSavingThrow = () => SpellAccessors.getRequiresSavingThrow(this.spell);
|
|
this.getToHit = () => SpellAccessors.getToHit(this.spell);
|
|
this.getAttackSaveValue = () => SpellAccessors.getAttackSaveValue(this.spell);
|
|
this.getSaveDcAbilityKey = () => {
|
|
const ruleData = rulesEngineSelectors.getRuleData(this.state);
|
|
return SpellUtils.getSaveDcAbilityKey(this.spell, ruleData);
|
|
};
|
|
this.getRange = () => SpellAccessors.getRange(this.spell);
|
|
this.getActivation = () => SpellAccessors.getActivation(this.spell);
|
|
this.getCastLevel = () => SpellAccessors.getCastLevel(this.spell);
|
|
this.getLevel = () => SpellAccessors.getLevel(this.spell);
|
|
this.isAtWill = () => SpellAccessors.isAtWill(this.spell);
|
|
this.getMaxUses = () => SpellAccessors.getMaxUses(this.spell);
|
|
this.getConsumedUses = () => SpellAccessors.getConsumedUses(this.spell);
|
|
this.isLimitedUseAvailableAtScaledAmount = () => SpellAccessors.isLimitedUseAvailableAtScaledAmount(this.spell);
|
|
this.getLimitedUseNumberUsed = () => {
|
|
const limitedUse = this.getLimitedUse();
|
|
if (limitedUse) {
|
|
return LimitedUseAccessors.getNumberUsed(limitedUse);
|
|
}
|
|
else {
|
|
return null;
|
|
}
|
|
};
|
|
this.getExpandedDataOriginRef = () => SpellAccessors.getExpandedDataOriginRef(this.spell);
|
|
this.isCastAsRitual = () => SpellAccessors.isCastAsRitual(this.spell);
|
|
this.getNoteComponents = () => {
|
|
var _a;
|
|
const castLevel = this.getCastLevel();
|
|
const characterLevel = (_a = rulesEngineSelectors.getExperienceInfo(this.state)) === null || _a === void 0 ? void 0 : _a.currentLevel;
|
|
const abilityLookup = rulesEngineSelectors.getAbilityLookup(this.state);
|
|
const ruleData = rulesEngineSelectors.getRuleData(this.state);
|
|
const spellScaledAmount = this.getScaledAmount();
|
|
const proficiencyBonus = rulesEngineSelectors.getProficiencyBonus(this.state);
|
|
return SpellNotes.getNoteComponents(this.spell, castLevel, characterLevel, abilityLookup, ruleData, spellScaledAmount, proficiencyBonus);
|
|
};
|
|
this.isCustomized = () => SpellAccessors.isCustomized(this.spell);
|
|
this.getConcentration = () => SpellAccessors.getConcentration(this.spell);
|
|
this.isRitual = () => SpellAccessors.isRitual(this.spell);
|
|
this.getCharacterLevel = () => SpellAccessors.getCharacterLevel(this.spell);
|
|
this.getModifiers = () => SpellAccessors.getModifiers(this.spell);
|
|
this.getTags = () => SpellAccessors.getTags(this.spell);
|
|
this.getConditions = () => SpellAccessors.getConditions(this.spell);
|
|
this.isLegacy = () => SpellAccessors.isLegacy(this.spell);
|
|
this.isValidToUsePactSlots = () => SpellValidators.isValidToUsePactSlots(this.spell);
|
|
// Utils
|
|
this.getActivationTime = () => ActivationAccessors.getTime(this.getActivation());
|
|
this.getActivationUnit = () => ActivationAccessors.getType(this.getActivation());
|
|
this.getFriendlySubtypeName = (modifier) => { var _a; return (_a = ModifierAccessors.getFriendlySubtypeName(modifier)) !== null && _a !== void 0 ? _a : ''; };
|
|
this.getPrimaryConditionName = () => {
|
|
const spellCondition = this.getConditions()[0];
|
|
const ruleData = rulesEngineSelectors.getRuleData(this.state);
|
|
let condition = RuleDataUtils.getCondition(spellCondition.conditionId, ruleData);
|
|
if (condition) {
|
|
return ConditionAccessors.getName(condition);
|
|
}
|
|
return null;
|
|
};
|
|
this.getDamageModifiers = (modifiers) => {
|
|
return modifiers.filter((modifier) => ModifierValidators.isSpellDamageModifier(modifier));
|
|
};
|
|
this.getHitPointHealingModifiers = (modifiers) => {
|
|
return modifiers.filter((modifier) => ModifierValidators.isSpellHealingHitPointsModifier(modifier));
|
|
};
|
|
this.getTempHitPointHealingModifiers = (modifiers) => {
|
|
return modifiers.filter((modifier) => ModifierValidators.isSpellHealingTempHitPointsModifier(modifier));
|
|
};
|
|
this.getEffectModifierDiceContract = (modifier) => {
|
|
const scaleType = this.getScaleType();
|
|
const points = this.getHigherLevelEntryContracts(modifier);
|
|
const atHigherDamage = SpellDerivers.getSpellScaledAtHigher(this.spell, scaleType, points, this.getCharacterLevel(), this.getCastLevel());
|
|
return SpellUtils.getSpellFinalScaledDie(this.spell, modifier, atHigherDamage);
|
|
};
|
|
this.getEffectRenderedDiceModifier = (modifier) => {
|
|
const scaledDamageDie = this.getEffectModifierDiceContract(modifier);
|
|
return DiceRenderers.renderDice(scaledDamageDie);
|
|
};
|
|
this.getHigherLevelEntryContracts = (modifier) => {
|
|
const atHigherLevels = ModifierAccessors.getAtHigherLevels(modifier);
|
|
let points = [];
|
|
if (atHigherLevels && atHigherLevels.points !== null) {
|
|
points = atHigherLevels.points;
|
|
}
|
|
return points;
|
|
};
|
|
this.getUsedSpellSlotLevelAmount = (changeAmount, spellSlots) => {
|
|
const foundSlotLevel = spellSlots.find((spellSlot) => spellSlot.level === this.getCastLevel());
|
|
if (!foundSlotLevel) {
|
|
return null;
|
|
}
|
|
const usedAmount = foundSlotLevel.used + changeAmount;
|
|
const maxAmount = foundSlotLevel.available;
|
|
return HelperUtils.clampInt(usedAmount, 0, maxAmount);
|
|
};
|
|
this.getSpellSlotInfo = () => {
|
|
const spellCasterInfo = rulesEngineSelectors.getSpellCasterInfo(this.state);
|
|
const { spellSlots } = spellCasterInfo;
|
|
let spellSlotInfo = spellSlots.find((spellSlotGroup) => spellSlotGroup.level === this.getCastLevel());
|
|
return spellSlotInfo ? spellSlotInfo : null;
|
|
};
|
|
this.getPactSlotInfo = () => {
|
|
const spellCasterInfo = rulesEngineSelectors.getSpellCasterInfo(this.state);
|
|
const { pactMagicSlots } = spellCasterInfo;
|
|
let spellSlotInfo = pactMagicSlots.find((pactSlotGroup) => pactSlotGroup.level === this.getCastLevel());
|
|
return spellSlotInfo ? spellSlotInfo : null;
|
|
};
|
|
this.getExpandedDataOriginRefName = () => {
|
|
const expandedDataOriginRef = this.getExpandedDataOriginRef();
|
|
if (expandedDataOriginRef) {
|
|
const dataOriginRefData = rulesEngineSelectors.getDataOriginRefData(this.state);
|
|
return EntityUtils.getDataOriginRefName(expandedDataOriginRef, dataOriginRefData);
|
|
}
|
|
else {
|
|
return null;
|
|
}
|
|
};
|
|
this.getDataOriginName = () => EntityUtils.getDataOriginName(this.getDataOrigin());
|
|
this.getClassId = () => {
|
|
if (this.getDataOriginType() === DataOriginTypeEnum.CLASS) {
|
|
return ClassAccessors.getMappingId(this.getDataOrigin().primary);
|
|
}
|
|
else {
|
|
return null;
|
|
}
|
|
};
|
|
this.getSchoolName = () => SpellAccessors.getSchool(this.spell);
|
|
this.getSchoolIconSlug = () => {
|
|
const school = this.getSchoolName();
|
|
return FormatUtils.slugify(school);
|
|
};
|
|
this.getActionMetaItems = () => {
|
|
const metaItems = [];
|
|
metaItems.push(FormatUtils.renderSpellLevelName(this.getLevel()));
|
|
const spellDataOrigin = this.getDataOrigin();
|
|
if (spellDataOrigin) {
|
|
const dataOriginName = this.getDataOriginName();
|
|
metaItems.push(dataOriginName);
|
|
}
|
|
let expandedDataOriginRefName = this.getExpandedDataOriginRefName();
|
|
if (expandedDataOriginRefName) {
|
|
metaItems.push(expandedDataOriginRefName);
|
|
}
|
|
if (this.getConcentration()) {
|
|
metaItems.push('Concentration');
|
|
}
|
|
if (this.isCustomized()) {
|
|
metaItems.push('Customized');
|
|
}
|
|
return metaItems;
|
|
};
|
|
this.deriveKnownKey = () => {
|
|
return SpellDerivers.deriveKnownKey(this.spell);
|
|
};
|
|
this.deriveLeveledKnownKey = (castLevel) => {
|
|
return SpellDerivers.deriveLeveledKnownKey(this.spell, castLevel);
|
|
};
|
|
this.params = params;
|
|
this.spell = params.spell;
|
|
}
|
|
static getLeveledSpellManager(knownLevelKey) {
|
|
const leveledSpellManager = leveledSpellManagerMap.get(knownLevelKey);
|
|
if (!leveledSpellManager) {
|
|
throw new Error(`SpellManager for spell ${knownLevelKey} is null`);
|
|
}
|
|
return leveledSpellManager;
|
|
}
|
|
static makeKnownKey(mappingId, mappingEntityTypeId) {
|
|
return SpellUtils.makeKnownKey(mappingId, mappingEntityTypeId);
|
|
}
|
|
static makeLeveledKnownKey(mappingId, mappingEntityTypeId, castLevel) {
|
|
return SpellUtils.makeLeveledKnownKey(mappingId, mappingEntityTypeId, castLevel);
|
|
}
|
|
}
|