Files
dndbeyond_src/ddb_main/packages/rules-engine/es/engine/Prerequisite/utils.js
T

254 lines
8.7 KiB
JavaScript

import sortBy from 'lodash/sortBy';
import { AbilityAccessors } from '../Ability';
import { FormatUtils } from '../Format';
import { getEntityId, getFriendlySubtypeName, getPrerequisites, getSubType, getType, getValue, getShouldExclude, } from './accessors';
import { PrerequisiteSubTypeEnum, PrerequisiteTypeEnum } from './constants';
import { validatePrerequisite } from './validators';
/**
*
* @param prerequisite
* @param prerequisiteData
*/
export function getPrerequisiteFailure(prerequisite, prerequisiteData) {
switch (getType(prerequisite)) {
case PrerequisiteTypeEnum.ABILITY_SCORE:
return getPrerequisiteFailureAbilityScore(prerequisite, prerequisiteData);
case PrerequisiteTypeEnum.PROFICIENCY:
return getPrerequisiteFailureProficiency(prerequisite);
case PrerequisiteTypeEnum.SPECIES:
return getPrerequisiteFailureRace(prerequisite);
case PrerequisiteTypeEnum.SIZE:
return getPrerequisiteFailureSize(prerequisite);
case PrerequisiteTypeEnum.SPECIES_OPTION:
return getPrerequisiteFailureSubrace(prerequisite);
case PrerequisiteTypeEnum.LEVEL:
return getPrerequisiteFailureLevel(prerequisite);
case PrerequisiteTypeEnum.CLASS:
return getPrerequisiteFailureClass(prerequisite);
case PrerequisiteTypeEnum.FEAT:
return getPrerequisiteFailureFeat(prerequisite);
case PrerequisiteTypeEnum.CLASS_FEATURE:
return getPrerequisiteFailureClassFeature(prerequisite);
case PrerequisiteTypeEnum.CUSTOM_VALUE:
default:
// not defined
}
return null;
}
/**
*
* @param prerequisite
* @param prerequisiteData
*/
export function getPrerequisiteFailureLevel(prerequisite) {
let requiredDescription = '';
switch (getSubType(prerequisite)) {
case PrerequisiteSubTypeEnum.CHARACTER_LEVEL:
let value = getValue(prerequisite);
value = value ? value : 1;
requiredDescription = `${FormatUtils.ordinalize(value)} Level`;
break;
default:
// not implemented
}
return {
type: PrerequisiteTypeEnum.LEVEL,
data: {
requiredChoice: getFriendlySubtypeName(prerequisite),
requiredDescription,
},
shouldExclude: !!getShouldExclude(prerequisite),
};
}
/**
*
* @param prerequisite
* @param prerequisiteData
*/
export function getPrerequisiteFailureAbilityScore(prerequisite, prerequisiteData) {
let statKey = '';
let currentAmount = null;
const entityId = getEntityId(prerequisite);
if (entityId !== null) {
const ability = prerequisiteData.abilityLookup[entityId];
statKey = AbilityAccessors.getStatKey(ability);
currentAmount = AbilityAccessors.getScore(ability);
}
return {
type: PrerequisiteTypeEnum.ABILITY_SCORE,
data: {
statKey,
currentAmount,
requiredValue: getValue(prerequisite),
requiredChoice: getFriendlySubtypeName(prerequisite),
requiredDescription: `${getFriendlySubtypeName(prerequisite)} ${getValue(prerequisite)}+`,
},
shouldExclude: !!getShouldExclude(prerequisite),
};
}
/**
*
* @param prerequisite
* @param prerequisiteData
*/
export function getPrerequisiteFailureProficiency(prerequisite) {
return {
type: PrerequisiteTypeEnum.PROFICIENCY,
data: {
requiredChoice: getFriendlySubtypeName(prerequisite),
requiredDescription: `${getFriendlySubtypeName(prerequisite)} Proficiency`,
},
shouldExclude: !!getShouldExclude(prerequisite),
};
}
/**
*
* @param prerequisite
* @param prerequisiteData
*/
export function getPrerequisiteFailureRace(prerequisite) {
return {
type: PrerequisiteTypeEnum.SPECIES,
data: {
requiredChoice: getFriendlySubtypeName(prerequisite),
requiredDescription: getFriendlySubtypeName(prerequisite),
},
shouldExclude: !!getShouldExclude(prerequisite),
};
}
/**
*
* @param prerequisite
* @param prerequisiteData
*/
export function getPrerequisiteFailureSubrace(prerequisite) {
return {
type: PrerequisiteTypeEnum.SPECIES_OPTION,
data: {
requiredChoice: getFriendlySubtypeName(prerequisite),
requiredDescription: getFriendlySubtypeName(prerequisite),
},
shouldExclude: !!getShouldExclude(prerequisite),
};
}
/**
*
* @param prerequisite
* @param prerequisiteData
*/
export function getPrerequisiteFailureSize(prerequisite) {
return {
type: PrerequisiteTypeEnum.SIZE,
data: {
requiredChoice: getFriendlySubtypeName(prerequisite),
requiredDescription: `${getFriendlySubtypeName(prerequisite)} Size`,
},
shouldExclude: !!getShouldExclude(prerequisite),
};
}
/**
*
* @param prerequisite
* @param prerequisiteData
*/
export function getPrerequisiteFailureClass(prerequisite) {
return {
type: PrerequisiteTypeEnum.CLASS,
data: {
requiredChoice: getFriendlySubtypeName(prerequisite),
requiredDescription: `${getFriendlySubtypeName(prerequisite)}`,
},
shouldExclude: !!getShouldExclude(prerequisite),
};
}
export const getPrerequisiteFailureClassFeature = (prerequisite) => ({
type: PrerequisiteTypeEnum.CLASS_FEATURE,
data: {
requiredChoice: prerequisite.friendlySubTypeName,
requiredDescription: prerequisite.friendlySubTypeName,
},
shouldExclude: !!getShouldExclude(prerequisite),
});
/**
*
* @param prerequisite
* @param prerequisiteData
*/
export function getPrerequisiteFailureFeat(prerequisite) {
return {
type: PrerequisiteTypeEnum.FEAT,
data: {
requiredChoice: getFriendlySubtypeName(prerequisite),
requiredDescription: `${getFriendlySubtypeName(prerequisite)}`,
},
shouldExclude: !!getShouldExclude(prerequisite),
};
}
/**
*
* @param prerequisiteGrouping
* @param prerequisiteData
*/
export function getPrerequisiteGroupingFailures(prerequisiteGrouping, prerequisiteData) {
const groupingFailures = [];
if (prerequisiteGrouping !== null) {
prerequisiteGrouping.forEach((prerequisiteGroup) => {
const groupFailures = [];
const prerequisites = getPrerequisites(prerequisiteGroup);
prerequisites.forEach((prerequisite) => {
if (!validatePrerequisite(prerequisite, prerequisiteData)) {
const prereqFailure = getPrerequisiteFailure(prerequisite, prerequisiteData);
if (prereqFailure) {
groupFailures.push(prereqFailure);
}
}
});
groupingFailures.push(groupFailures);
});
}
return groupingFailures.filter((group) => group.length);
}
// Creates a string that summarizes the prerequisite failures for feats and multiclassing
export function getPrerequisiteFailuresText(prereqFailures) {
//get all the prerequisite failures, sorted so that if every group failure is a missing prereq, they come first
const failures = sortBy(prereqFailures, (failureGroup) => (failureGroup.every((f) => !f.shouldExclude) ? 0 : 1));
// Create an intro string for the summary
let intro = '';
// Check if all failures are either missing or prohibited
const hasOnlyMissingFailures = failures.every((failureGroup) => failureGroup.every((f) => !f.shouldExclude));
const hasOnlyProhibitedFailures = failures.every((failureGroup) => failureGroup.every((f) => f.shouldExclude));
// Determine the intro text based on the type of failures
if (hasOnlyMissingFailures) {
intro = 'Missing: ';
}
else if (hasOnlyProhibitedFailures) {
intro = 'Prohibited by: ';
}
else {
intro = 'Requires: ';
}
// Each failure is sorted so that prohibited failures come last, and then combined into a single string
const combinedStrings = failures
.map((failure) => sortBy(failure, (f) => (f.shouldExclude ? 1 : 0))
.map((failureAnd) => {
if (failureAnd.shouldExclude && !hasOnlyProhibitedFailures && !hasOnlyMissingFailures) {
return `Prohibited by: ${failureAnd.data.requiredDescription}`;
}
return `${failureAnd.data.requiredDescription}`;
})
.reduce((acc, desc, idx) => {
let connector = '';
if (idx < failure.length - 2) {
connector = ', ';
}
else if (idx < failure.length - 1) {
connector = ' and ';
}
acc += `${desc}${connector}`;
return acc;
}, ''))
.join(' or ');
// return the intro text followed by the combined strings
return `${intro}${combinedStrings}`;
}