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:
2025-05-28 11:50:03 -07:00
commit 8df9031d27
3592 changed files with 319051 additions and 0 deletions
@@ -0,0 +1,283 @@
import { ActivationAccessors } from '../Activation';
import { PrerequisiteAccessors } from '../Prerequisite';
/**
*
* @param feat
*/
export function getDefinition(feat) {
return feat.definition;
}
/**
*
* @param feat
*/
export function getId(feat) {
var _a, _b;
return (_b = (_a = feat.definition) === null || _a === void 0 ? void 0 : _a.id) !== null && _b !== void 0 ? _b : -1;
}
/**
*
* @param feat
*/
export function getEntityTypeId(feat) {
return getDefinitionEntityTypeId(feat);
}
/**
*
* @param feat
*/
export function getDefinitionEntityTypeId(feat) {
var _a, _b;
return (_b = (_a = feat.definition) === null || _a === void 0 ? void 0 : _a.entityTypeId) !== null && _b !== void 0 ? _b : -1;
}
/**
*
* @param feat
*/
export function getUniqueKey(feat) {
return `${getId(feat)}-${getEntityTypeId(feat)}`;
}
/**
*
* @param feat
*/
export function getName(feat) {
return getDefinitionName(feat);
}
/**
*
* @param feat
*/
export function getDefinitionName(feat) {
var _a, _b;
return (_b = (_a = feat.definition) === null || _a === void 0 ? void 0 : _a.name) !== null && _b !== void 0 ? _b : '';
}
/**
*
* @param feat
*/
export function getActivation(feat) {
return getDefinitionActivation(feat);
}
/**
*
* @param feat
*/
export function getDefinitionActivation(feat) {
var _a, _b;
return (_b = (_a = feat.definition) === null || _a === void 0 ? void 0 : _a.activation) !== null && _b !== void 0 ? _b : null;
}
/**
*
* @param feat
*/
export function getActivationTime(feat) {
return ActivationAccessors.getTime(getActivation(feat));
}
/**
*
* @param feat
*/
export function getActivationType(feat) {
return ActivationAccessors.getType(getActivation(feat));
}
/**
*
* @param feat
*/
export function getSnippet(feat) {
return getDefinitionSnippet(feat);
}
/**
*
* @param feat
*/
export function getDefinitionSnippet(feat) {
var _a, _b;
return (_b = (_a = feat.definition) === null || _a === void 0 ? void 0 : _a.snippet) !== null && _b !== void 0 ? _b : null;
}
/**
*
* @param feat
*/
export function getDescription(feat) {
return getDefinitionDescription(feat);
}
/**
*
* @param feat
*/
export function getDefinitionDescription(feat) {
var _a, _b;
return (_b = (_a = feat.definition) === null || _a === void 0 ? void 0 : _a.description) !== null && _b !== void 0 ? _b : null;
}
/**
*
* @param feat
*/
export function getCreatureRules(feat) {
return getDefinitionCreatureRules(feat);
}
/**
*
* @param feat
*/
export function getDefinitionCreatureRules(feat) {
var _a, _b;
return (_b = (_a = feat.definition) === null || _a === void 0 ? void 0 : _a.creatureRules) !== null && _b !== void 0 ? _b : [];
}
/**
*
* @param feat
*/
export function getPrerequisites(feat) {
return getDefinitionPrerequisites(feat);
}
/**
*
* @param feat
*/
export function getDefinitionPrerequisites(feat) {
var _a, _b;
return (_b = (_a = feat.definition) === null || _a === void 0 ? void 0 : _a.prerequisites) !== null && _b !== void 0 ? _b : [];
}
/**
*
* @param feat
*/
export function getPrerequisiteDescription(feat) {
const prerequisites = getPrerequisites(feat);
return PrerequisiteAccessors.getDescription(prerequisites);
}
/**
*
* @param feat
*/
export function getComponentId(feat) {
return feat.componentId;
}
/**
*
* @param feat
*/
export function getComponentTypeId(feat) {
return feat.componentTypeId;
}
/**
*
* @param feat
*/
export function getOptions(feat) {
return feat.options;
}
/**
*
* @param feat
*/
export function getActions(feat) {
return feat.actions;
}
/**
*
* @param feat
*/
export function getChoices(feat) {
return feat.choices;
}
/**
*
* @param feat
*/
export function getModifiers(feat) {
return feat.modifiers;
}
/**
*
* @param feat
*/
export function getSpells(feat) {
return feat.spells;
}
/**
*
* @param feat
*/
export function getDataOrigin(feat) {
return feat.dataOrigin;
}
/**
*
* @param feat
*/
export function getDataOriginType(feat) {
const dataOrigin = getDataOrigin(feat);
return dataOrigin.type;
}
/**
*
* @param feat
*/
export function getDefinitionSources(feat) {
var _a, _b;
return (_b = (_a = feat.definition) === null || _a === void 0 ? void 0 : _a.sources) !== null && _b !== void 0 ? _b : [];
}
/**
*
* @param feat
*/
export function getSources(feat) {
return getDefinitionSources(feat);
}
/**
*
* @param feat
*/
export function getDefinitionIsHomebrew(feat) {
var _a, _b;
return (_b = (_a = feat.definition) === null || _a === void 0 ? void 0 : _a.isHomebrew) !== null && _b !== void 0 ? _b : false;
}
/**
*
* @param feat
*/
export function isHomebrew(feat) {
return getDefinitionIsHomebrew(feat);
}
/**
*
* @param feat
*/
export function getCategories(feat) {
var _a, _b;
return (_b = (_a = feat.definition) === null || _a === void 0 ? void 0 : _a.categories) !== null && _b !== void 0 ? _b : [];
}
/**
*
* @param feat
*/
export function getDefinitionIsRepeatable(feat) {
var _a, _b;
return (_b = (_a = feat.definition) === null || _a === void 0 ? void 0 : _a.isRepeatable) !== null && _b !== void 0 ? _b : false;
}
/**
*
* @param feat
*/
export function isRepeatable(feat) {
return getDefinitionIsRepeatable(feat);
}
/**
*
* @param feat
*/
export function getDefinitionRepeatableParentId(feat) {
var _a, _b;
return (_b = (_a = feat.definition) === null || _a === void 0 ? void 0 : _a.repeatableParentId) !== null && _b !== void 0 ? _b : null;
}
/**
*
* @param feat
*/
export function getRepeatableParentId(feat) {
return getDefinitionRepeatableParentId(feat);
}
@@ -0,0 +1,344 @@
import { groupBy, keyBy } from 'lodash';
import { FeatAccessors } from '.';
import { ActionGenerators } from '../Action';
import { BackgroundAccessors } from '../Background';
import { ChoiceGenerators } from '../Choice';
import { ClassAccessors } from '../Class';
import { ClassFeatureAccessors } from '../ClassFeature';
import { EntityTypeEnum, INITIAL_ASI_TAG_NAME, DISPLAY_WITH_DATA_ORIGIN_TAG_NAME, BuilderChoiceTypeEnum, } from '../Core';
import { CreatureRuleGenerators } from '../CreatureRule';
import { DataOriginDataInfoKeyEnum, DataOriginGenerators, DataOriginTypeEnum, } from '../DataOrigin';
import { tryGetParentId, tryGetPrimaryId } from '../Entity/utils';
import { HelperUtils } from '../Helper';
import { ModifierGenerators } from '../Modifier';
import { OptionAccessors, OptionGenerators } from '../Option';
import { RaceAccessors } from '../Race';
import { SpellGenerators } from '../Spell';
import { getComponentId, getComponentTypeId, getCreatureRules, getEntityTypeId, getId, getModifiers, getOptions, getUniqueKey, } from './accessors';
/**
*
* @param feat
*/
export function generateDataOriginKey(feat) {
const componentId = getComponentId(feat);
const componentTypeId = getComponentTypeId(feat);
return DataOriginGenerators.generateDataOriginKey(componentId ? componentId : -1, componentTypeId ? componentTypeId : -1);
}
/**
*
* @param feats
* @param optionLookup
* @param actionLookup
* @param choiceLookup
* @param modifierLookup
* @param spellLookup
* @param valueLookup
* @param spellListDataOriginLookup
* @param ruleData
*/
export function generateBaseFeats(feats, optionLookup, actionLookup, choiceLookup, modifierLookup, spellLookup, valueLookup, spellListDataOriginLookup, ruleData) {
return feats.map((feat) => generateBaseFeat(feat, optionLookup, actionLookup, choiceLookup, modifierLookup, spellLookup, valueLookup, spellListDataOriginLookup, ruleData));
}
/**
*
* @param feat
* @param optionLookup
* @param actionLookup
* @param choiceLookup
* @param modifierLookup
* @param spellLookup
* @param valueLookup
* @param spellListDataOriginLookup
* @param ruleData
*/
export function generateBaseFeat(feat, optionLookup, actionLookup, choiceLookup, modifierLookup, spellLookup, valueLookup, spellListDataOriginLookup, ruleData) {
const id = getId(feat);
const entityTypeId = getEntityTypeId(feat);
const actions = ActionGenerators.generateBaseActions(id, entityTypeId, actionLookup, valueLookup, DataOriginTypeEnum.FEAT, feat);
const choices = ChoiceGenerators.generateBaseChoices(id, entityTypeId, choiceLookup, DataOriginTypeEnum.FEAT, feat);
const spells = SpellGenerators.generateBaseSpells(id, entityTypeId, spellLookup, DataOriginTypeEnum.FEAT, feat, feat, ruleData, spellListDataOriginLookup, valueLookup);
const modifiers = ModifierGenerators.generateModifiers(id, entityTypeId, modifierLookup, DataOriginTypeEnum.FEAT, feat, feat);
const options = generateBaseFeatOptions(feat, actionLookup, spellLookup, optionLookup, modifierLookup, valueLookup, spellListDataOriginLookup, ruleData);
return Object.assign(Object.assign({}, feat), { actions,
choices,
spells,
modifiers,
options });
}
/**
* Returns a lookup mapping of Feat List Contracts by Feat List ID,
* for any Feat Lists that come from the Background.
*/
function getBackgroundFeatListsById(background) {
const mapping = new Map();
if (!background)
return mapping;
for (const featList of BackgroundAccessors.getFeatListContracts(background)) {
mapping.set(featList.id, featList);
}
return mapping;
}
/**
* Returns a lookup mapping of Feat List Contracts by Feat List ID,
* for any Feat Lists that come from Class Features.
*/
function getClassFeatureFeatListsById(classes) {
const mapping = new Map();
for (const cls of classes) {
for (const clsFeature of ClassAccessors.getClassFeatures(cls)) {
const featLists = ClassFeatureAccessors.getFeatListContracts(clsFeature);
for (const featList of featLists) {
mapping.set(featList.id, featList);
}
}
}
return mapping;
}
/**
* Returns a lookup mapping of Class Features by Feat List ID,
* for any Feat Lists that come from Class Features.
*/
function getClassFeaturesByFeatListId(classes) {
// this assumes a feat list only belongs to one class feature
const mapping = new Map();
for (const cls of classes) {
for (const clsFeature of ClassAccessors.getClassFeatures(cls)) {
const featLists = ClassFeatureAccessors.getFeatListContracts(clsFeature);
for (const featList of featLists) {
mapping.set(featList.id, clsFeature);
}
}
}
return mapping;
}
export function generateAggregatedFeats(baseFeats, classes, race, background, choicesFromClasses) {
const feats = [];
classes.forEach((charClass) => {
feats.push(...ClassAccessors.getFeats(charClass));
});
if (race) {
feats.push(...RaceAccessors.getFeats(race));
}
// Group entities by FeatList ID
const backgroundFeatListsById = getBackgroundFeatListsById(background);
const classFeatureFeatListsById = getClassFeatureFeatListsById(classes);
const classFeaturesByFeatListId = getClassFeaturesByFeatListId(classes);
baseFeats.forEach((feat) => {
if (feat.componentId === null) {
feats.push(Object.assign(Object.assign({}, feat), { dataOrigin: DataOriginGenerators.generateDataOrigin(DataOriginTypeEnum.ADHOC, feat) }));
}
else if (feat.componentTypeId === EntityTypeEnum.FEAT_LIST) {
// Find which entity this feat list comes from
const featListId = feat.componentId;
if (backgroundFeatListsById.has(featListId)) {
const featListContract = backgroundFeatListsById.get(featListId);
feats.push(Object.assign(Object.assign({}, feat), { dataOrigin: DataOriginGenerators.generateDataOrigin(DataOriginTypeEnum.FEAT_LIST, featListContract, // primary
background, // parent
DataOriginTypeEnum.BACKGROUND) }));
}
else if (classFeatureFeatListsById.has(featListId)) {
const featListContract = classFeatureFeatListsById.get(featListId);
const classFeature = classFeaturesByFeatListId.get(featListId);
feats.push(Object.assign(Object.assign({}, feat), { dataOrigin: DataOriginGenerators.generateDataOrigin(DataOriginTypeEnum.FEAT_LIST, featListContract, // primary
classFeature, // parent
DataOriginTypeEnum.CLASS_FEATURE) }));
}
}
else if (feat.componentTypeId === EntityTypeEnum.CLASS_FEATURE_OPTION_KNOWN) {
// These are feats that come from class feature options.
// Primary data origin is the class feature.
// Parent data origin is the class.
const dataOrigin = findClassFeatureOptionFeatDataOrigin(feat, classes, choicesFromClasses);
if (dataOrigin) {
feats.push(Object.assign(Object.assign({}, feat), { dataOrigin }));
}
}
});
return feats;
}
function findClassFeatureOptionFeatDataOrigin(feat, classes, choicesFromClasses) {
// It's not exactly a hack, but it is tricky to find the data origin
// for Feats that come from Class Feature Options.
// Search for the corresponding builder choice for this feat id.
const featId = FeatAccessors.getId(feat);
const choice = choicesFromClasses.find((c) => c.type === BuilderChoiceTypeEnum.FEAT_CHOICE_OPTION && c.optionValue === featId);
// Ensure that the builder choice has a parent, and the component type is the expected kind.
if ((choice === null || choice === void 0 ? void 0 : choice.parentChoiceId) && choice.componentTypeId === EntityTypeEnum.CLASS_FEATURE) {
// The parent choice key has the slot id in the second part.
const slotId = parseChoiceKey(choice.parentChoiceId)[1];
// Confirm that this slot matches the component id of the feat
if (slotId && feat.componentId === slotId) {
// The class feature id is the component id of the builder choice.
const classFeatureId = choice.componentId;
// Find the class and class feature that it came from
for (const cls of classes) {
for (const classFeature of ClassAccessors.getClassFeatures(cls)) {
if (ClassFeatureAccessors.getId(classFeature) === classFeatureId) {
// Make the data origin. Finally!
return DataOriginGenerators.generateDataOrigin(DataOriginTypeEnum.CLASS_FEATURE, // primary type
classFeature, // primary
cls, // parent
DataOriginTypeEnum.CLASS);
}
}
}
}
}
return null;
}
function parseChoiceKey(choiceKey) {
// choice keys are hyphen separated strings of numbers, with 1, 2, or 3 parts.
return choiceKey.split('-').map((part) => parseInt(part));
}
/**
*
* @param feats
*/
export function generateFeatComponentLookup(feats) {
return groupBy(feats, (feat) => generateDataOriginKey(feat));
}
/**
*
* @param feats
*/
export function generateFeatLookup(feats) {
return keyBy(feats, (feat) => getId(feat));
}
/**
*
* @param feats
* @param xpInfo
* @param ruleData
*/
export function generateFeatCreatureRules(feats, xpInfo, ruleData) {
const rules = [];
feats.forEach((feat) => {
const dataOrigin = DataOriginGenerators.generateDataOrigin(DataOriginTypeEnum.FEAT, feat);
const featureRules = getCreatureRules(feat);
featureRules.forEach((rule) => {
rules.push(CreatureRuleGenerators.generateRule(rule, dataOrigin, xpInfo, ruleData));
});
});
return rules;
}
/**
*
* @param feat
* @param actionLookup
* @param spellLookup
* @param optionLookup
* @param modifierLookup
* @param valueLookup
* @param spellListDataOriginLookup
* @param ruleData
*/
export function generateBaseFeatOptions(feat, actionLookup, spellLookup, optionLookup, modifierLookup, valueLookup, spellListDataOriginLookup, ruleData) {
const featId = getId(feat);
const featEntityTypeId = getEntityTypeId(feat);
const baseOptions = OptionGenerators.generateDataOriginBaseOptions(featId, featEntityTypeId, optionLookup, DataOriginTypeEnum.FEAT, feat);
return OptionGenerators.generateOptions(baseOptions, DataOriginTypeEnum.FEAT, {}, actionLookup, spellLookup, optionLookup, modifierLookup, valueLookup, spellListDataOriginLookup, ruleData, feat);
}
/**
*
* @param id
* @param entityTypeId
* @param featLookup
* @param dataOriginType
* @param primary
* @param parent
*/
export function generateDataOriginFeats(id, entityTypeId, featLookup, dataOriginType, primary, parent = null) {
const feats = HelperUtils.lookupDataOrFallback(featLookup, DataOriginGenerators.generateDataOriginKey(id, entityTypeId));
if (!feats) {
return [];
}
return feats.map((feat) => (Object.assign(Object.assign({}, feat), { dataOrigin: DataOriginGenerators.generateDataOrigin(dataOriginType, primary, parent) })));
}
/**
*
* @param feats
*/
export function generateFeatModifiers(feats) {
const modifiers = [];
if (feats.length === 0) {
return modifiers;
}
feats.forEach((feat) => {
modifiers.push(...getModifiers(feat));
getOptions(feat).forEach((option) => {
modifiers.push(...OptionAccessors.getModifiers(option));
});
});
return modifiers;
}
/**
*
* @param feats
*/
export function generateRefFeatData(feats) {
let data = {};
feats.forEach((feat) => {
data[getUniqueKey(feat)] = {
[DataOriginDataInfoKeyEnum.PRIMARY]: feat,
[DataOriginDataInfoKeyEnum.PARENT]: null,
};
});
return data;
}
export function generateIsInitialAsiFromFeat(feats) {
return feats.some((feat) => FeatAccessors.getCategories(feat).some((cat) => cat.tagName === INITIAL_ASI_TAG_NAME));
}
export function generateStandardFeats(feats) {
return feats.filter((feat) => !FeatAccessors.getCategories(feat).some((cat) => cat.tagName === DISPLAY_WITH_DATA_ORIGIN_TAG_NAME));
}
const makeLookup = () => ({
[DataOriginTypeEnum.ADHOC]: {},
[DataOriginTypeEnum.BACKGROUND]: {},
[DataOriginTypeEnum.CLASS]: {},
[DataOriginTypeEnum.CLASS_FEATURE]: {},
[DataOriginTypeEnum.CONDITION]: {},
[DataOriginTypeEnum.CUSTOM]: {},
[DataOriginTypeEnum.FEAT]: {},
[DataOriginTypeEnum.ITEM]: {},
[DataOriginTypeEnum.RACE]: {},
[DataOriginTypeEnum.RULE_DATA]: {},
[DataOriginTypeEnum.SIMULATED]: {},
[DataOriginTypeEnum.UNKNOWN]: {},
[DataOriginTypeEnum.VEHICLE]: {},
[DataOriginTypeEnum.FEAT_LIST]: {},
});
/**
* Builds a multilayered lookup object for feats that are tagged as data origin only.
*/
export function generateDataOriginPairedFeats(feats) {
const dataOriginOnly = feats.filter((feat) => FeatAccessors.getCategories(feat).some((cat) => cat.tagName === DISPLAY_WITH_DATA_ORIGIN_TAG_NAME));
const lookup = { byPrimary: makeLookup(), byParent: makeLookup() };
for (const feat of dataOriginOnly) {
const dataOrigin = FeatAccessors.getDataOrigin(feat);
// primary
if (dataOrigin.primary) {
const id = tryGetPrimaryId(dataOrigin);
if (id) {
if (!lookup.byPrimary[dataOrigin.type].hasOwnProperty(id)) {
lookup.byPrimary[dataOrigin.type][id] = [feat];
}
else {
lookup.byPrimary[dataOrigin.type][id].push(feat);
}
}
}
// parent
if (dataOrigin.parent && dataOrigin.parentType) {
const id = tryGetParentId(dataOrigin);
if (id) {
if (!lookup.byParent[dataOrigin.parentType].hasOwnProperty(id)) {
lookup.byParent[dataOrigin.parentType][id] = [feat];
}
else {
lookup.byParent[dataOrigin.parentType][id].push(feat);
}
}
}
}
return lookup;
}
@@ -0,0 +1,8 @@
import * as FeatAccessors from './accessors';
import * as FeatGenerators from './generators';
import * as FeatSimulators from './simulators';
import * as FeatTypings from './typings';
import * as FeatUtils from './utils';
export * from './typings';
export { FeatAccessors, FeatGenerators, FeatSimulators, FeatUtils };
export default Object.assign(Object.assign(Object.assign(Object.assign(Object.assign({}, FeatAccessors), FeatGenerators), FeatSimulators), FeatTypings), FeatUtils);
@@ -0,0 +1,19 @@
import { DataOriginGenerators, DataOriginTypeEnum } from '../DataOrigin';
/**
*
* @param definition
*/
export function simulateFeat(definition) {
return {
dataOrigin: DataOriginGenerators.generateDataOrigin(DataOriginTypeEnum.SIMULATED),
actions: [],
definition,
definitionId: definition.id,
componentId: -1,
componentTypeId: -1,
choices: [],
spells: [],
modifiers: [],
options: [],
};
}
@@ -0,0 +1,50 @@
import { FeatAccessors } from '.';
import { DB_STRING_ELDRITCH_ADEPT, DB_STRING_MEDIUM_ARMOR_MASTER, DISGUISE_FEAT_TAG_NAME, INITIAL_ASI_TAG_NAME, } from '../Core';
import { getId, getName, getRepeatableParentId, isRepeatable } from './accessors';
/**
*
* @param feat
*/
export function isEldritchAdept(feat) {
return getName(feat) === DB_STRING_ELDRITCH_ADEPT;
}
export function isMediumArmorMaster(feat) {
return getName(feat) === DB_STRING_MEDIUM_ARMOR_MASTER;
}
export function doesTagSatisfyConstraint(tag, constraint) {
return tag.entityTagId === constraint.entityTagId;
}
export function doesSatisfyTagConstraints(tags, constraints) {
// For every constraint C,
return constraints.every((constraint) => {
// There exists at least one tag T such that
return tags.some((tag) => {
// T satisfies/matches C (i.e. T.entityTagId === C.entityTagId)
return this.doesTagSatisfyConstraint(tag, constraint);
});
});
}
/*
* Some feats, such as the ASI feats granted to new backgrounds
* aren't Feats in the official sense. We're just using the feat
* data structure to support other rules.
* Another example is the Weapon Mastery class feature, which
* actually just grants a special Weapon Mastery feat.
*
* Returns true when it is representing something other than a feat.
* Returns false when the feat is a real feat from the rules.
*/
export function isHiddenFeat(feat) {
return FeatAccessors.getCategories(feat).some(
// TODO: Consider simplifying the logic by adding the __DISGUISE_FEAT tag to initial ASI feats.
(cat) => cat.tagName === INITIAL_ASI_TAG_NAME || cat.tagName === DISGUISE_FEAT_TAG_NAME);
}
/**
* @param feat
*/
export const getRepeatableGroupId = (feat) => {
if (!isRepeatable(feat)) {
return null;
}
return getRepeatableParentId(feat) || getId(feat);
};