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,80 @@
|
||||
/**
|
||||
*
|
||||
* @param rule
|
||||
*/
|
||||
export function getCreatureGroupId(rule) {
|
||||
return rule.creatureGroupId;
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param rule
|
||||
*/
|
||||
export function getLevelDivisor(rule) {
|
||||
return rule.levelDivisor;
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param rule
|
||||
*/
|
||||
export function getMaxChallengeRatingId(rule) {
|
||||
return rule.maxChallengeRatingId;
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param rule
|
||||
*/
|
||||
export function getMonsterIds(rule) {
|
||||
var _a;
|
||||
return (_a = rule.monsterIds) !== null && _a !== void 0 ? _a : [];
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param rule
|
||||
*/
|
||||
export function getMonsterTypeId(rule) {
|
||||
return rule.monsterTypeId;
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param rule
|
||||
*/
|
||||
export function getMovementIds(rule) {
|
||||
var _a;
|
||||
return (_a = rule.movementIds) !== null && _a !== void 0 ? _a : [];
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param rule
|
||||
*/
|
||||
export function getSizeIds(rule) {
|
||||
var _a;
|
||||
return (_a = rule.sizeIds) !== null && _a !== void 0 ? _a : [];
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param rule
|
||||
*/
|
||||
export function getContextLevelChallengeMax(rule) {
|
||||
return rule.contextLevelChallengeMax;
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param rule
|
||||
*/
|
||||
export function getMaxChallengeInfo(rule) {
|
||||
return rule.maxChallengeInfo;
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param rule
|
||||
*/
|
||||
export function getMaxChallengeValue(rule) {
|
||||
return rule.maxChallengeValue;
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param rule
|
||||
*/
|
||||
export function getDataOrigin(rule) {
|
||||
return rule.dataOrigin;
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
import { ClassAccessors } from '../Class';
|
||||
import { DataOriginTypeEnum } from '../DataOrigin';
|
||||
import { getLevelDivisor } from './accessors';
|
||||
export function deriveContextLevelChallengeMax(rule, dataOrigin, xpInfo) {
|
||||
if (!getLevelDivisor(rule)) {
|
||||
return null;
|
||||
}
|
||||
let levelDivisor = getLevelDivisor(rule);
|
||||
if (levelDivisor === null) {
|
||||
levelDivisor = 1;
|
||||
}
|
||||
if (dataOrigin) {
|
||||
switch (dataOrigin.type) {
|
||||
case DataOriginTypeEnum.CLASS_FEATURE:
|
||||
return Math.floor(ClassAccessors.getLevel(dataOrigin.parent) / levelDivisor);
|
||||
default:
|
||||
// not implemented
|
||||
}
|
||||
}
|
||||
return Math.floor(xpInfo.currentLevel / levelDivisor);
|
||||
}
|
||||
@@ -0,0 +1,115 @@
|
||||
import { intersection, union, groupBy } from 'lodash';
|
||||
import { DataOriginGenerators, DataOriginTypeEnum } from '../DataOrigin';
|
||||
import { RuleDataUtils } from '../RuleData';
|
||||
import { getContextLevelChallengeMax, getCreatureGroupId, getMaxChallengeRatingId, getMaxChallengeValue, getMonsterTypeId, getMovementIds, getSizeIds, } from './accessors';
|
||||
import { deriveContextLevelChallengeMax } from './derivers';
|
||||
/**
|
||||
*
|
||||
* @param rule
|
||||
* @param dataOrigin
|
||||
* @param xpInfo
|
||||
* @param ruleData
|
||||
*/
|
||||
export function generateRule(rule, dataOrigin, xpInfo, ruleData) {
|
||||
const maxChallengeRatingId = getMaxChallengeRatingId(rule);
|
||||
let maxChallengeInfo = null;
|
||||
if (maxChallengeRatingId) {
|
||||
maxChallengeInfo = RuleDataUtils.getChallengeInfo(maxChallengeRatingId, ruleData);
|
||||
}
|
||||
const contextLevelChallengeMax = deriveContextLevelChallengeMax(rule, dataOrigin, xpInfo);
|
||||
let maxChallengeValue = null;
|
||||
const possibleMaxes = [];
|
||||
if (maxChallengeInfo !== null) {
|
||||
possibleMaxes.push(maxChallengeInfo.value);
|
||||
}
|
||||
if (contextLevelChallengeMax != null) {
|
||||
possibleMaxes.push(contextLevelChallengeMax);
|
||||
}
|
||||
if (possibleMaxes.length) {
|
||||
maxChallengeValue = Math.max(...possibleMaxes);
|
||||
}
|
||||
const ruleInfo = Object.assign(Object.assign({}, rule), { maxChallengeInfo,
|
||||
contextLevelChallengeMax,
|
||||
maxChallengeValue });
|
||||
return Object.assign(Object.assign({}, ruleInfo), { dataOrigin });
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param rules
|
||||
*/
|
||||
export function generateConsolidatedSingleTypeRule(rules) {
|
||||
if (rules.length === 1) {
|
||||
return rules[0];
|
||||
}
|
||||
const movementIdsGroups = [];
|
||||
const sizeIdsGroups = [];
|
||||
const maxChallengeValues = [];
|
||||
const contextLevelChallengeMaxValues = [];
|
||||
rules.forEach((rule) => {
|
||||
movementIdsGroups.push(getMovementIds(rule));
|
||||
sizeIdsGroups.push(getSizeIds(rule));
|
||||
const maxChallengeValue = getMaxChallengeValue(rule);
|
||||
if (maxChallengeValue !== null) {
|
||||
maxChallengeValues.push(maxChallengeValue);
|
||||
}
|
||||
const contextLevelChallengeMax = getContextLevelChallengeMax(rule);
|
||||
if (contextLevelChallengeMax !== null) {
|
||||
contextLevelChallengeMaxValues.push(contextLevelChallengeMax);
|
||||
}
|
||||
});
|
||||
const consolidatedRule = {
|
||||
contextLevelChallengeMax: contextLevelChallengeMaxValues.length
|
||||
? Math.max(...contextLevelChallengeMaxValues)
|
||||
: null,
|
||||
creatureGroupId: getCreatureGroupId(rules[0]),
|
||||
levelDivisor: null,
|
||||
maxChallengeRatingId: null,
|
||||
maxChallengeInfo: null,
|
||||
monsterIds: [],
|
||||
monsterTypeId: getMonsterTypeId(rules[0]),
|
||||
movementIds: intersection(...movementIdsGroups),
|
||||
sizeIds: union(...sizeIdsGroups),
|
||||
maxChallengeValue: maxChallengeValues.length ? Math.max(...maxChallengeValues) : null,
|
||||
};
|
||||
return Object.assign({ dataOrigin: DataOriginGenerators.generateDataOrigin(DataOriginTypeEnum.SIMULATED) }, consolidatedRule);
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param rules
|
||||
*/
|
||||
export function consolidateRules(rules) {
|
||||
const consolidatedRules = [];
|
||||
const rulesByGroup = groupBy(rules, (rule) => getCreatureGroupId(rule));
|
||||
Object.keys(rulesByGroup).forEach((groupId) => {
|
||||
const groupRules = rulesByGroup[groupId];
|
||||
const rulesByTypes = groupBy(groupRules, (rule) => getMonsterTypeId(rule));
|
||||
Object.keys(rulesByTypes).forEach((typeId) => {
|
||||
const rules = rulesByTypes[typeId];
|
||||
// null is cast to string when it groups by null
|
||||
if (typeId === 'null') {
|
||||
consolidatedRules.push(...rules);
|
||||
}
|
||||
else {
|
||||
consolidatedRules.push(generateConsolidatedSingleTypeRule(rules));
|
||||
}
|
||||
});
|
||||
});
|
||||
return consolidatedRules;
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param classRules
|
||||
* @param raceRules
|
||||
* @param featRules
|
||||
*/
|
||||
export function generateCreatureRules(classRules, raceRules, featRules) {
|
||||
const allRules = [...classRules, ...raceRules, ...featRules];
|
||||
return consolidateRules(allRules);
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param creatureRules
|
||||
*/
|
||||
export function generateCreatureGroupRulesLookup(creatureRules) {
|
||||
return groupBy(creatureRules, (rule) => getCreatureGroupId(rule));
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
import * as CreatureRuleAccessors from './accessors';
|
||||
import * as CreatureRuleDerivers from './derivers';
|
||||
import * as CreatureRuleGenerators from './generators';
|
||||
import * as CreatureRuleTypings from './typings';
|
||||
import * as CreatureRuleUtils from './utils';
|
||||
export * from './typings';
|
||||
export { CreatureRuleAccessors, CreatureRuleDerivers, CreatureRuleGenerators, CreatureRuleUtils };
|
||||
export default Object.assign(Object.assign(Object.assign(Object.assign(Object.assign({}, CreatureRuleAccessors), CreatureRuleDerivers), CreatureRuleGenerators), CreatureRuleTypings), CreatureRuleUtils);
|
||||
@@ -0,0 +1,35 @@
|
||||
import { intersection } from 'lodash';
|
||||
import { CreatureAccessors } from '../Creature';
|
||||
import { getCreatureGroupId, getMaxChallengeValue, getMonsterIds, getMonsterTypeId, getMovementIds, getSizeIds, } from './accessors';
|
||||
export function isRuleGroup(rule, groupId) {
|
||||
return getCreatureGroupId(rule) === groupId;
|
||||
}
|
||||
export function isValidCreature(creature, rule) {
|
||||
const challengeInfo = CreatureAccessors.getChallengeInfo(creature);
|
||||
// max challenge rating
|
||||
const maxChallengeValue = getMaxChallengeValue(rule);
|
||||
if (maxChallengeValue !== null && challengeInfo !== null && challengeInfo.value > maxChallengeValue) {
|
||||
return false;
|
||||
}
|
||||
// specific monster id
|
||||
const monsterIds = getMonsterIds(rule);
|
||||
if (monsterIds.length && !monsterIds.includes(CreatureAccessors.getId(creature))) {
|
||||
return false;
|
||||
}
|
||||
// monster type
|
||||
if (getMonsterTypeId(rule) !== null && CreatureAccessors.getTypeId(creature) !== getMonsterTypeId(rule)) {
|
||||
return false;
|
||||
}
|
||||
// size
|
||||
const sizeIds = getSizeIds(rule);
|
||||
if (sizeIds.length && !sizeIds.includes(CreatureAccessors.getSizeId(creature))) {
|
||||
return false;
|
||||
}
|
||||
// excluded movements
|
||||
const excludedMovementIds = getMovementIds(rule);
|
||||
if (excludedMovementIds.length &&
|
||||
intersection(CreatureAccessors.getMovementIds(creature), excludedMovementIds).length) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
Reference in New Issue
Block a user