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,187 @@
|
||||
/**
|
||||
*
|
||||
* @param ability
|
||||
*/
|
||||
export function getBaseScore(ability) {
|
||||
return ability.baseScore;
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param ability
|
||||
*/
|
||||
export function getClassBonuses(ability) {
|
||||
return ability.classBonuses;
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param ability
|
||||
*/
|
||||
export function getEntityTypeId(ability) {
|
||||
return ability.entityTypeId;
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param ability
|
||||
*/
|
||||
export function getId(ability) {
|
||||
return ability.id;
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param ability
|
||||
*/
|
||||
export function getIsMaxed(ability) {
|
||||
return ability.isMaxed;
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param ability
|
||||
*/
|
||||
export function getLabel(ability) {
|
||||
return ability.label;
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param ability
|
||||
*/
|
||||
export function getMaxStatScore(ability) {
|
||||
return ability.maxStatScore;
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param ability
|
||||
*/
|
||||
export function getMiscBonus(ability) {
|
||||
return ability.miscBonus;
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param ability
|
||||
*/
|
||||
export function getModifier(ability) {
|
||||
return ability.modifier;
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param ability
|
||||
*/
|
||||
export function getName(ability) {
|
||||
return ability.name;
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param ability
|
||||
*/
|
||||
export function getOtherBonus(ability) {
|
||||
return ability.otherBonus;
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param ability
|
||||
*/
|
||||
export function getOverrideScore(ability) {
|
||||
return ability.overrideScore;
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param ability
|
||||
*/
|
||||
export function getRacialBonus(ability) {
|
||||
return ability.racialBonus;
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param ability
|
||||
*/
|
||||
export function getScore(ability) {
|
||||
return ability.score;
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param ability
|
||||
*/
|
||||
export function getSetScore(ability) {
|
||||
return ability.setScore;
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param ability
|
||||
*/
|
||||
export function getStackingBonus(ability) {
|
||||
return ability.stackingBonus;
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param ability
|
||||
*/
|
||||
export function getStatKey(ability) {
|
||||
return ability.statKey;
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param ability
|
||||
*/
|
||||
export function getTotalScore(ability) {
|
||||
return ability.totalScore;
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param ability
|
||||
*/
|
||||
export function getProficiency(ability) {
|
||||
return ability.proficiency;
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param ability
|
||||
*/
|
||||
export function getProficiencyLevel(ability) {
|
||||
return ability.proficiencyLevel;
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param ability
|
||||
*/
|
||||
export function getIsSaveModifierModified(ability) {
|
||||
return ability.isSaveModifierModified;
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param ability
|
||||
*/
|
||||
export function getIsSaveOverridden(ability) {
|
||||
return ability.isSaveOverridden;
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param ability
|
||||
*/
|
||||
export function getIsSaveProficiencyModified(ability) {
|
||||
return ability.isSaveProficiencyModified;
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param ability
|
||||
*/
|
||||
export function getSave(ability) {
|
||||
return ability.save;
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param ability
|
||||
*/
|
||||
export function getSaveBonuses(ability) {
|
||||
return ability.saveBonuses;
|
||||
}
|
||||
export function getAllStatBonusSuppliers(ability) {
|
||||
return ability.allStatBonusSuppliers;
|
||||
}
|
||||
export function getStatSetScoreSuppliers(ability) {
|
||||
return ability.statSetScoreSuppliers;
|
||||
}
|
||||
export function getStatMaxBonusSuppliers(ability) {
|
||||
return ability.statMaxBonusSuppliers;
|
||||
}
|
||||
export function getStackingBonusSuppliers(ability) {
|
||||
return ability.stackingBonusSuppliers;
|
||||
}
|
||||
@@ -0,0 +1,114 @@
|
||||
import { TypeScriptUtils } from '../../utils';
|
||||
import { CharacterDerivers } from '../Character';
|
||||
import { ProficiencyLevelEnum } from '../Core';
|
||||
import { HelperUtils } from '../Helper';
|
||||
import { ModifierAccessors, ModifierValidators } from '../Modifier';
|
||||
import { getId, getModifier, getScore } from './accessors';
|
||||
/**
|
||||
*
|
||||
* @param abilityId
|
||||
* @param modifiers
|
||||
* @returns TODORETURN
|
||||
*/
|
||||
export function deriveHighestSetAbilityScore(abilityId, modifiers) {
|
||||
const statSetScoreModifiers = modifiers.filter((modifier) => ModifierValidators.isValidSetStatScoreModifier(modifier, abilityId));
|
||||
const statSetScoreModifierValues = statSetScoreModifiers
|
||||
.map((modifier) => ModifierAccessors.getValue(modifier))
|
||||
.filter(TypeScriptUtils.isNotNullOrUndefined);
|
||||
if (!statSetScoreModifierValues.length) {
|
||||
return 0;
|
||||
}
|
||||
return Math.max(...statSetScoreModifierValues);
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param id
|
||||
* @param abilityLookup
|
||||
* @param defaultValue
|
||||
*/
|
||||
export function deriveStatModifier(id, abilityLookup, defaultValue = 0) {
|
||||
if (id === null) {
|
||||
return defaultValue;
|
||||
}
|
||||
const ability = HelperUtils.lookupDataOrFallback(abilityLookup, id);
|
||||
if (ability === null) {
|
||||
return defaultValue;
|
||||
}
|
||||
const modifier = getModifier(ability);
|
||||
if (modifier === null) {
|
||||
return defaultValue;
|
||||
}
|
||||
return modifier;
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param id
|
||||
* @param abilityLookup
|
||||
* @param defaultValue
|
||||
*/
|
||||
export function deriveStatScore(id, abilityLookup, defaultValue = 0) {
|
||||
if (id === null) {
|
||||
return defaultValue;
|
||||
}
|
||||
const ability = HelperUtils.lookupDataOrFallback(abilityLookup, id);
|
||||
if (ability === null) {
|
||||
return defaultValue;
|
||||
}
|
||||
const score = getScore(ability);
|
||||
if (score === null) {
|
||||
return defaultValue;
|
||||
}
|
||||
return score;
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param hasSaveProficiency
|
||||
* @param proficiencyLevelOverride
|
||||
*/
|
||||
export function deriveProficiencyLevel(hasSaveProficiency, proficiencyLevelOverride) {
|
||||
let proficiencyLevel = hasSaveProficiency
|
||||
? ProficiencyLevelEnum.FULL
|
||||
: ProficiencyLevelEnum.NONE;
|
||||
if (proficiencyLevelOverride !== null) {
|
||||
proficiencyLevel = proficiencyLevelOverride;
|
||||
}
|
||||
return proficiencyLevel;
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param abilityScore
|
||||
* @param modifiers
|
||||
* @param proficiencyBonus
|
||||
* @param proficiencyLevelOverride
|
||||
* @param saveOverride
|
||||
* @param statBonusSaveModifierTotal
|
||||
* @param magicBonus
|
||||
* @param miscBonus
|
||||
*/
|
||||
export function deriveAbilitySaveInfo(abilityScore, modifiers, proficiencyBonus, proficiencyLevelOverride, saveOverride, statBonusSaveModifierTotal, magicBonus, miscBonus) {
|
||||
const abilityId = getId(abilityScore);
|
||||
const statProficiencySaveModifiers = modifiers.filter((modifier) => ModifierValidators.isValidProficiencySaveModifier(modifier, abilityId));
|
||||
const hasSaveProficiency = statProficiencySaveModifiers.length > 0;
|
||||
const proficiencyLevel = deriveProficiencyLevel(hasSaveProficiency, proficiencyLevelOverride);
|
||||
const proficiencyBonusAmount = CharacterDerivers.deriveProficiencyBonusAmount(proficiencyLevel, proficiencyBonus);
|
||||
let save = 0;
|
||||
let saveBonuses = 0;
|
||||
if (saveOverride !== null) {
|
||||
save = saveOverride;
|
||||
}
|
||||
else {
|
||||
saveBonuses = statBonusSaveModifierTotal + magicBonus + miscBonus;
|
||||
const modifier = getModifier(abilityScore);
|
||||
save = (modifier ? modifier : 0) + saveBonuses + proficiencyBonusAmount;
|
||||
}
|
||||
const isSaveOverridden = saveOverride !== null;
|
||||
return {
|
||||
proficiency: hasSaveProficiency,
|
||||
proficiencyLevel,
|
||||
isSaveProficiencyModified: proficiencyLevelOverride !== null,
|
||||
isSaveModifierModified: !!miscBonus || !!magicBonus || isSaveOverridden,
|
||||
save,
|
||||
saveBonuses,
|
||||
isSaveOverridden,
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,177 @@
|
||||
import { groupBy } from 'lodash';
|
||||
import keyBy from 'lodash/keyBy';
|
||||
import { ProficiencyLevelEnum } from '../Core';
|
||||
import { DataOriginGenerators, DataOriginTypeEnum } from '../DataOrigin';
|
||||
import { ModifierDerivers, ModifierGenerators, ModifierValidators } from '../Modifier';
|
||||
import { RuleDataAccessors } from '../RuleData';
|
||||
import { ValueHacks, ValueUtils } from '../Value';
|
||||
import { getEntityTypeId, getId } from './accessors';
|
||||
import { deriveAbilitySaveInfo, deriveHighestSetAbilityScore } from './derivers';
|
||||
import { getBestAbilityScore, getStatScoreModifier } from './utils';
|
||||
/**
|
||||
*
|
||||
* @param abilities
|
||||
*/
|
||||
export function generateAbilityLookup(abilities) {
|
||||
return keyBy(abilities, 'id');
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param abilities
|
||||
*/
|
||||
export function generateAbilityKeyLookup(abilities) {
|
||||
return keyBy(abilities, 'name');
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param stat
|
||||
* @param baseStats
|
||||
* @param bonusStats
|
||||
* @param overrideStats
|
||||
* @param raceModifiers
|
||||
* @param classesModifiers
|
||||
* @param miscModifiers
|
||||
* @param modifiers
|
||||
* @param proficiencyBonus
|
||||
* @param ruleData
|
||||
* @param modifierData
|
||||
*/
|
||||
export function generateBaseAbility(stat, baseStats, bonusStats, overrideStats, raceModifiers, classesModifiers, miscModifiers, modifiers, proficiencyBonus, ruleData, modifierData) {
|
||||
const statKey = stat.key === null ? '' : stat.key.toLowerCase();
|
||||
const abilityId = stat.id;
|
||||
const entityTypeId = stat.entityTypeId;
|
||||
const baseStat = baseStats.find((ability) => ability.id === abilityId);
|
||||
const bonusStat = bonusStats.find((ability) => ability.id === abilityId);
|
||||
const overrideStat = overrideStats.find((ability) => ability.id === abilityId);
|
||||
const racialBonus = ModifierDerivers.deriveTotalValue(ModifierGenerators.generateBonusStatScoreModifiers(raceModifiers, abilityId), modifierData);
|
||||
const classBonuses = ModifierDerivers.deriveTotalValue(ModifierGenerators.generateBonusStatScoreModifiers(classesModifiers, abilityId), modifierData);
|
||||
const miscBonus = ModifierDerivers.deriveTotalValue(ModifierGenerators.generateBonusStatScoreModifiers(miscModifiers, abilityId), modifierData);
|
||||
// generate all stat bonus suppliers
|
||||
const allStatBonusModifiers = modifiers.filter((modifier) => ModifierValidators.isValidBonusStatScoreModifier(modifier, abilityId));
|
||||
const allStatBonusSuppliers = generateAbilityScoreSupplierData(allStatBonusModifiers, 'bonus', modifierData);
|
||||
//generate setScore and all setScore suppliers
|
||||
const setScore = deriveHighestSetAbilityScore(abilityId, miscModifiers);
|
||||
const statSetScoreModifiers = modifiers.filter((modifier) => ModifierValidators.isValidSetStatScoreModifier(modifier, abilityId));
|
||||
const statSetScoreSuppliers = generateAbilityScoreSupplierData(statSetScoreModifiers, 'set', modifierData);
|
||||
//generate maxStatBonus and all maxStatBonus suppliers
|
||||
const statMaxBonusModifiers = modifiers.filter((modifier) => ModifierValidators.isValidBonusStatMaxModifier(modifier, abilityId));
|
||||
const statMaxBonus = ModifierDerivers.deriveTotalValue(statMaxBonusModifiers, modifierData);
|
||||
const statMaxBonusSuppliers = generateAbilityScoreSupplierData(statMaxBonusModifiers, 'max', modifierData);
|
||||
//generate stackingBonus and all stackingBonus suppliers
|
||||
const stackingBonusModifiers = modifiers.filter((modifier) => ModifierValidators.isValidStackingBonusStatScoreModifier(modifier, abilityId));
|
||||
const stackingBonus = ModifierDerivers.deriveTotalValue(stackingBonusModifiers, modifierData);
|
||||
const stackingBonusSuppliers = generateAbilityScoreSupplierData(stackingBonusModifiers, 'stacking', modifierData);
|
||||
// calculate baseScore, otherBonus, overrideScore, totalBonusScore, finalScore, and modifier
|
||||
const baseScore = baseStat ? baseStat.value : null;
|
||||
const otherBonus = bonusStat ? bonusStat.value : null;
|
||||
let overrideScore = overrideStat ? overrideStat.value : null;
|
||||
if (overrideScore === 0) {
|
||||
overrideScore = null;
|
||||
}
|
||||
let totalBonusScore = null;
|
||||
let finalScore = null;
|
||||
let modifier = null;
|
||||
let maxStatScore = ruleData.basicMaxStatScore;
|
||||
if (baseScore !== null) {
|
||||
totalBonusScore = baseScore + racialBonus + classBonuses + miscBonus;
|
||||
maxStatScore = ruleData.basicMaxStatScore + statMaxBonus;
|
||||
totalBonusScore = Math.min(maxStatScore, totalBonusScore);
|
||||
totalBonusScore += otherBonus ? otherBonus : 0;
|
||||
finalScore = getBestAbilityScore(totalBonusScore, setScore, ruleData);
|
||||
if (overrideScore) {
|
||||
finalScore = overrideScore;
|
||||
}
|
||||
if (stackingBonus > 0) {
|
||||
finalScore = Math.min(maxStatScore, finalScore + stackingBonus);
|
||||
}
|
||||
finalScore = Math.max(ruleData.minStatScore, Math.min(ruleData.maxStatScore, finalScore));
|
||||
modifier = getStatScoreModifier(finalScore, ruleData);
|
||||
}
|
||||
return {
|
||||
label: stat.name,
|
||||
id: stat.id,
|
||||
entityTypeId,
|
||||
name: statKey,
|
||||
statKey,
|
||||
totalScore: finalScore,
|
||||
score: finalScore,
|
||||
maxStatScore,
|
||||
isMaxed: !!finalScore && finalScore >= maxStatScore,
|
||||
modifier,
|
||||
baseScore,
|
||||
racialBonus,
|
||||
classBonuses,
|
||||
miscBonus,
|
||||
setScore,
|
||||
stackingBonus,
|
||||
otherBonus,
|
||||
overrideScore,
|
||||
allStatBonusSuppliers,
|
||||
statSetScoreSuppliers,
|
||||
statMaxBonusSuppliers,
|
||||
stackingBonusSuppliers,
|
||||
};
|
||||
}
|
||||
export function generateAbilityScoreSupplierData(abilityModifiers, type, modifierData) {
|
||||
const supplierGroups = groupBy(abilityModifiers, (modifier) => `${modifier.componentId}-${modifier.componentTypeId}`);
|
||||
return Object.keys(supplierGroups).map((groupKey) => {
|
||||
var _a;
|
||||
const modifiers = supplierGroups[groupKey];
|
||||
const totalValue = ModifierDerivers.deriveTotalValue(modifiers, modifierData);
|
||||
let dataOrigin = (_a = modifiers[0]) === null || _a === void 0 ? void 0 : _a.dataOrigin;
|
||||
let expandedOriginRef = null;
|
||||
if (dataOrigin && dataOrigin.type === DataOriginTypeEnum.FEAT) {
|
||||
expandedOriginRef = DataOriginGenerators.generateDataOriginRef(dataOrigin.type, groupKey);
|
||||
}
|
||||
return {
|
||||
key: groupKey,
|
||||
dataOrigin,
|
||||
expandedOriginRef,
|
||||
type,
|
||||
value: totalValue,
|
||||
};
|
||||
});
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param abilityScore
|
||||
* @param proficiencyBonus
|
||||
* @param modifiers
|
||||
* @param valueLookup
|
||||
* @param modifierData
|
||||
*/
|
||||
export function generateAbility(abilityScore, proficiencyBonus, modifiers, valueLookup, modifierData) {
|
||||
const abilityId = getId(abilityScore);
|
||||
const abilityIdString = ValueHacks.hack__toString(abilityId);
|
||||
const abilityEntityTypeId = getEntityTypeId(abilityScore);
|
||||
const abilityEntityTypeIdString = ValueHacks.hack__toString(abilityEntityTypeId);
|
||||
const miscBonus = ValueUtils.getSavingThrowMiscBonusValue(valueLookup, abilityIdString, abilityEntityTypeIdString);
|
||||
const magicBonus = ValueUtils.getSavingThrowMagicBonusValue(valueLookup, abilityIdString, abilityEntityTypeIdString);
|
||||
const saveOverride = ValueUtils.getSavingThrowOverrideValue(valueLookup, abilityIdString, abilityEntityTypeIdString);
|
||||
const proficiencyLevelOverride = ValueUtils.getSavingThrowProficiencyLevelValue(valueLookup, abilityIdString, abilityEntityTypeIdString);
|
||||
const statBonusSaveModifiers = modifiers.filter((modifier) => ModifierValidators.isValidBonusSaveModifier(modifier, abilityId));
|
||||
const statBonusSaveModifierTotal = ModifierDerivers.deriveTotalValue(statBonusSaveModifiers, modifierData, 1);
|
||||
const abilitySaveInfo = deriveAbilitySaveInfo(abilityScore, modifiers, proficiencyBonus, proficiencyLevelOverride, saveOverride, statBonusSaveModifierTotal, magicBonus, miscBonus);
|
||||
return Object.assign(Object.assign({}, abilityScore), abilitySaveInfo);
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param baseStats
|
||||
* @param bonusStats
|
||||
* @param overrideStats
|
||||
* @param raceModifiers
|
||||
* @param classesModifiers
|
||||
* @param miscModifiers
|
||||
* @param modifiers
|
||||
* @param proficiencyBonus
|
||||
* @param modifierData
|
||||
* @param ruleData
|
||||
* @param valueLookup
|
||||
*/
|
||||
export function generateAbilities(baseStats, bonusStats, overrideStats, raceModifiers, classesModifiers, miscModifiers, modifiers, proficiencyBonus, modifierData, ruleData, valueLookup) {
|
||||
const abilityScores = RuleDataAccessors.getStats(ruleData).map((stat) => generateBaseAbility(stat, baseStats, bonusStats, overrideStats, raceModifiers, classesModifiers, miscModifiers, modifiers, proficiencyBonus, ruleData, modifierData));
|
||||
const simulatedAbilities = abilityScores.map((ability) => (Object.assign(Object.assign({}, ability), { proficiency: false, proficiencyLevel: ProficiencyLevelEnum.NONE, isSaveProficiencyModified: false, isSaveModifierModified: false, save: 0, saveBonuses: 0, isSaveOverridden: false })));
|
||||
const abilityScoresLookup = generateAbilityLookup(simulatedAbilities);
|
||||
const updatedModifierData = Object.assign(Object.assign({}, modifierData), { abilityLookup: abilityScoresLookup });
|
||||
return abilityScores.map((abilityScore) => generateAbility(abilityScore, proficiencyBonus, modifiers, valueLookup, updatedModifierData));
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
import * as AbilityAccessors from './accessors';
|
||||
import * as AbilityDerivers from './derivers';
|
||||
import * as AbilityGenerators from './generators';
|
||||
import * as AbilityTypings from './typings';
|
||||
import * as AbilityUtils from './utils';
|
||||
export * from './typings';
|
||||
export { AbilityAccessors, AbilityDerivers, AbilityGenerators, AbilityUtils };
|
||||
export default Object.assign(Object.assign(Object.assign(Object.assign(Object.assign({}, AbilityAccessors), AbilityDerivers), AbilityGenerators), AbilityTypings), AbilityUtils);
|
||||
@@ -0,0 +1,19 @@
|
||||
import { HelperUtils } from '../Helper';
|
||||
import { RuleDataAccessors } from '../RuleData';
|
||||
/**
|
||||
*
|
||||
* @param score
|
||||
* @param ruleData
|
||||
*/
|
||||
export function getStatScoreModifier(score, ruleData) {
|
||||
return HelperUtils.lookupDataOrFallback(RuleDataAccessors.getStatModifiersLookup(ruleData), score, 0);
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param totalBonusScore
|
||||
* @param highestSetScore
|
||||
* @param ruleData
|
||||
*/
|
||||
export function getBestAbilityScore(totalBonusScore, highestSetScore, ruleData) {
|
||||
return Math.min(RuleDataAccessors.getMaxStatScore(ruleData), Math.max(totalBonusScore, highestSetScore));
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
export var AccessTypeEnum;
|
||||
(function (AccessTypeEnum) {
|
||||
AccessTypeEnum[AccessTypeEnum["FREE"] = 1] = "FREE";
|
||||
AccessTypeEnum[AccessTypeEnum["OWNED"] = 2] = "OWNED";
|
||||
AccessTypeEnum[AccessTypeEnum["SHARED"] = 3] = "SHARED";
|
||||
AccessTypeEnum[AccessTypeEnum["NO_ACCESS"] = 4] = "NO_ACCESS";
|
||||
})(AccessTypeEnum || (AccessTypeEnum = {}));
|
||||
@@ -0,0 +1,7 @@
|
||||
import * as AccessConstants from './constants';
|
||||
import * as AccessTypings from './typings';
|
||||
import * as AccessUtils from './utils';
|
||||
export * from './typings';
|
||||
export * from './constants';
|
||||
export { AccessUtils };
|
||||
export default Object.assign(Object.assign(Object.assign({}, AccessConstants), AccessTypings), AccessUtils);
|
||||
@@ -0,0 +1,6 @@
|
||||
import { AccessTypeEnum } from './constants';
|
||||
export function isAccessible(accessType) {
|
||||
return (accessType === AccessTypeEnum.FREE ||
|
||||
accessType === AccessTypeEnum.OWNED ||
|
||||
accessType === AccessTypeEnum.SHARED);
|
||||
}
|
||||
@@ -0,0 +1,526 @@
|
||||
/**
|
||||
*
|
||||
* @param action
|
||||
*/
|
||||
export function getDefinitionName(action) {
|
||||
return action.definition.name;
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param action
|
||||
*/
|
||||
export function getDefinitionAbilityModifierStatId(action) {
|
||||
return action.definition.abilityModifierStatId;
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param action
|
||||
*/
|
||||
export function getAbilityModifierStatId(action) {
|
||||
return getDefinitionAbilityModifierStatId(action);
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param action
|
||||
*/
|
||||
export function getDefinitionAttackSubtypeId(action) {
|
||||
return action.definition.attackSubtype;
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param action
|
||||
*/
|
||||
export function getAttackSubtypeId(action) {
|
||||
return getDefinitionAttackSubtypeId(action);
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param action
|
||||
*/
|
||||
export function getDefinitionAttackRangeId(action) {
|
||||
return action.definition.attackTypeRange;
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param action
|
||||
*/
|
||||
export function getAttackRangeId(action) {
|
||||
return getDefinitionAttackRangeId(action);
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param action
|
||||
*/
|
||||
export function getDefinitionActivation(action) {
|
||||
return action.definition.activation;
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param action
|
||||
*/
|
||||
export function getActivation(action) {
|
||||
return getDefinitionActivation(action);
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param action
|
||||
*/
|
||||
export function getDefinitionActionTypeId(action) {
|
||||
return action.definition.actionType;
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param action
|
||||
*/
|
||||
export function getActionTypeId(action) {
|
||||
return getDefinitionActionTypeId(action);
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param action
|
||||
*/
|
||||
export function getDefinitionDamageTypeId(action) {
|
||||
return action.definition.damageTypeId;
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param action
|
||||
*/
|
||||
export function getDamageTypeId(action) {
|
||||
return getDefinitionDamageTypeId(action);
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param action
|
||||
*/
|
||||
export function getDefinitionDescription(action) {
|
||||
return action.definition.description;
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param action
|
||||
*/
|
||||
export function getDescription(action) {
|
||||
return getDefinitionDescription(action);
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param action
|
||||
*/
|
||||
export function getDefinitionSnippet(action) {
|
||||
return action.definition.snippet;
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param action
|
||||
*/
|
||||
export function getSnippet(action) {
|
||||
return getDefinitionSnippet(action);
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param action
|
||||
*/
|
||||
export function getDefinitionDice(action) {
|
||||
return action.definition.dice;
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param action
|
||||
*/
|
||||
export function getDice(action) {
|
||||
return getDefinitionDice(action);
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param action
|
||||
*/
|
||||
export function getDefinitionIsMartialArts(action) {
|
||||
return action.definition.isMartialArts;
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param action
|
||||
*/
|
||||
export function getIsMartialArts(action) {
|
||||
return getDefinitionIsMartialArts(action);
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param action
|
||||
*/
|
||||
export function getDefinitionIsProficienct(action) {
|
||||
return action.definition.isProficient;
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param action
|
||||
*/
|
||||
export function getIsProficienct(action) {
|
||||
return getDefinitionIsProficienct(action);
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param action
|
||||
*/
|
||||
export function getDefinitionOnMissDescription(action) {
|
||||
return action.definition.onMissDescription;
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param action
|
||||
*/
|
||||
export function getOnMissDescription(action) {
|
||||
return getDefinitionOnMissDescription(action);
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param action
|
||||
*/
|
||||
export function getDefinitionRange(action) {
|
||||
return action.definition.range;
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param action
|
||||
*/
|
||||
export function getDefinitionFixedSaveDc(action) {
|
||||
return action.definition.fixedSaveDc;
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param action
|
||||
*/
|
||||
export function getFixedSaveDc(action) {
|
||||
return getDefinitionFixedSaveDc(action);
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param action
|
||||
*/
|
||||
export function getDefinitionSaveFailDescription(action) {
|
||||
return action.definition.saveFailDescription;
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param action
|
||||
*/
|
||||
export function getSaveFailDescription(action) {
|
||||
return getDefinitionSaveFailDescription(action);
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param action
|
||||
*/
|
||||
export function getDefinitionSaveStatId(action) {
|
||||
return action.definition.saveStatId;
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param action
|
||||
*/
|
||||
export function getSaveStatId(action) {
|
||||
return getDefinitionSaveStatId(action);
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param action
|
||||
*/
|
||||
export function getDefinitionSaveSuccessDescription(action) {
|
||||
return action.definition.saveSuccessDescription;
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param action
|
||||
*/
|
||||
export function getSaveSuccessDescription(action) {
|
||||
return getDefinitionSaveSuccessDescription(action);
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param action
|
||||
*/
|
||||
export function getDefinitionDisplayAsAttack(action) {
|
||||
return action.definition.displayAsAttack;
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param action
|
||||
*/
|
||||
export function getDisplayAsAttack(action) {
|
||||
return getDefinitionDisplayAsAttack(action);
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param action
|
||||
*/
|
||||
export function getDefinitionSpellRangeType(action) {
|
||||
return action.definition.spellRangeType;
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param action
|
||||
*/
|
||||
export function getSpellRangeType(action) {
|
||||
return getDefinitionSpellRangeType(action);
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param action
|
||||
*/
|
||||
export function getDefinitionFixedValue(action) {
|
||||
return action.definition.value;
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param action
|
||||
*/
|
||||
export function getFixedValue(action) {
|
||||
return getDefinitionFixedValue(action);
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param action
|
||||
*/
|
||||
export function getFixedToHit(action) {
|
||||
return getDefinitionFixedToHit(action);
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param action
|
||||
*/
|
||||
export function getDefinitionFixedToHit(action) {
|
||||
return action.definition.fixedToHit;
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param action
|
||||
*/
|
||||
export function getDefinitionNumberOfTargets(action) {
|
||||
return action.definition.numberOfTargets;
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param action
|
||||
*/
|
||||
export function getAmmunition(action) {
|
||||
return getDefinitionAmmunition(action);
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param action
|
||||
*/
|
||||
export function getDefinitionAmmunition(action) {
|
||||
return action.definition.ammunition;
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param action
|
||||
*/
|
||||
export function getNumberOfTargets(action) {
|
||||
return getDefinitionNumberOfTargets(action);
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param action
|
||||
*/
|
||||
export function getDefinition(action) {
|
||||
return action.definition;
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param action
|
||||
*/
|
||||
export function getComponentId(action) {
|
||||
return action.componentId;
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param action
|
||||
*/
|
||||
export function getComponentTypeId(action) {
|
||||
return action.componentTypeId;
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param action
|
||||
*/
|
||||
export function getEntityTypeId(action) {
|
||||
return getMappingEntityTypeId(action);
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param action
|
||||
*/
|
||||
export function getMappingEntityTypeId(action) {
|
||||
return action.entityTypeId;
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param action
|
||||
*/
|
||||
export function getId(action) {
|
||||
return getMappingId(action);
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param action
|
||||
*/
|
||||
export function getMappingId(action) {
|
||||
return action.id;
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param action
|
||||
*/
|
||||
export function getLimitedUse(action) {
|
||||
return action.limitedUse;
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param action
|
||||
*/
|
||||
export function displayAsAttack(action) {
|
||||
return action.displayAsAttack;
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param action
|
||||
*/
|
||||
export function getName(action) {
|
||||
return action.name;
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param action
|
||||
*/
|
||||
export function getNotes(action) {
|
||||
return action.notes;
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param action
|
||||
*/
|
||||
export function getOriginalContract(action) {
|
||||
return action.originalContract;
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param action
|
||||
*/
|
||||
export function isProficient(action) {
|
||||
return action.proficiency;
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param action
|
||||
*/
|
||||
export function requiresAttackRoll(action) {
|
||||
return action.requiresAttackRoll;
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param action
|
||||
*/
|
||||
export function requiresSavingThrow(action) {
|
||||
return action.requiresSavingThrow;
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param action
|
||||
*/
|
||||
export function getUniqueKey(action) {
|
||||
return action.uniqueKey;
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param action
|
||||
*/
|
||||
export function getDataOrigin(action) {
|
||||
return action.dataOrigin;
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param action
|
||||
*/
|
||||
export function getDataOriginType(action) {
|
||||
const dataOrigin = getDataOrigin(action);
|
||||
return dataOrigin.type;
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param action
|
||||
*/
|
||||
export function getAttackSaveValue(action) {
|
||||
return action.attackSaveValue;
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param action
|
||||
*/
|
||||
export function getAttackSubtypeName(action) {
|
||||
return action.attackSubtypeName;
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param action
|
||||
*/
|
||||
export function getDamage(action) {
|
||||
return action.damage;
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param action
|
||||
*/
|
||||
export function getRange(action) {
|
||||
return action.range;
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param action
|
||||
*/
|
||||
export function getReach(action) {
|
||||
return action.reach;
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param action
|
||||
*/
|
||||
export function getStatId(action) {
|
||||
return action.statId;
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param action
|
||||
*/
|
||||
export function getToHit(action) {
|
||||
return action.toHit;
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param action
|
||||
*/
|
||||
export function isOffhand(action) {
|
||||
return action.isOffhand;
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param action
|
||||
*/
|
||||
export function isSilvered(action) {
|
||||
return action.isSilvered;
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param action
|
||||
*/
|
||||
export function isDefaultDisplayAsAttack(action) {
|
||||
return action.isDefaultDisplayAsAttack;
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param action
|
||||
*/
|
||||
export function isCustomized(action) {
|
||||
return action.isCustomized;
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
import { AdjustmentTypeEnum } from '../Value';
|
||||
export var ActionTypeEnum;
|
||||
(function (ActionTypeEnum) {
|
||||
ActionTypeEnum[ActionTypeEnum["WEAPON"] = 1] = "WEAPON";
|
||||
ActionTypeEnum[ActionTypeEnum["SPELL"] = 2] = "SPELL";
|
||||
ActionTypeEnum[ActionTypeEnum["GENERAL"] = 3] = "GENERAL";
|
||||
})(ActionTypeEnum || (ActionTypeEnum = {}));
|
||||
export var AttackSubtypeEnum;
|
||||
(function (AttackSubtypeEnum) {
|
||||
AttackSubtypeEnum[AttackSubtypeEnum["MANUFACTURED"] = 1] = "MANUFACTURED";
|
||||
AttackSubtypeEnum[AttackSubtypeEnum["NATURAL"] = 2] = "NATURAL";
|
||||
AttackSubtypeEnum[AttackSubtypeEnum["UNARMED"] = 3] = "UNARMED";
|
||||
})(AttackSubtypeEnum || (AttackSubtypeEnum = {}));
|
||||
export const ACTION_CUSTOMIZATION_ADJUSTMENT_TYPES = [
|
||||
AdjustmentTypeEnum.TO_HIT_OVERRIDE,
|
||||
AdjustmentTypeEnum.TO_HIT_BONUS,
|
||||
AdjustmentTypeEnum.FIXED_VALUE_BONUS,
|
||||
AdjustmentTypeEnum.DISPLAY_AS_ATTACK,
|
||||
AdjustmentTypeEnum.NAME_OVERRIDE,
|
||||
AdjustmentTypeEnum.NOTES,
|
||||
];
|
||||
@@ -0,0 +1,467 @@
|
||||
import { TypeScriptUtils } from '../../utils';
|
||||
import { AbilityAccessors } from '../Ability';
|
||||
import { CharacterDerivers } from '../Character';
|
||||
import { ClassAccessors } from '../Class';
|
||||
import { AbilityStatEnum, AttackTypeRangeEnum } from '../Core';
|
||||
import { DataOriginTypeEnum } from '../DataOrigin';
|
||||
import { DiceAccessors, DiceDerivers, DiceUtils } from '../Dice';
|
||||
import { HelperUtils } from '../Helper';
|
||||
import { ModifierAccessors, ModifierDerivers, ModifierValidators } from '../Modifier';
|
||||
import { RuleDataAccessors, RuleDataUtils } from '../RuleData';
|
||||
import { AdjustmentTypeEnum, ValueUtils, ValueValidators } from '../Value';
|
||||
import { getAbilityModifierStatId, getActionTypeId, getAttackRangeId, getAttackSubtypeId, getDamageTypeId, getDataOrigin, getDataOriginType, getDefinitionName, getDefinitionRange, getDice, getDisplayAsAttack, getEntityTypeId, getFixedSaveDc, getFixedToHit, getId, getIsMartialArts, getIsProficienct, getMappingEntityTypeId, getMappingId, getSaveStatId, getSpellRangeType, requiresAttackRoll, } from './accessors';
|
||||
import { ACTION_CUSTOMIZATION_ADJUSTMENT_TYPES, ActionTypeEnum, AttackSubtypeEnum } from './constants';
|
||||
/**
|
||||
*
|
||||
* @param action
|
||||
*/
|
||||
export function deriveUniqueKey(action) {
|
||||
return `${getId(action)}-${getEntityTypeId(action)}`;
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param action
|
||||
*/
|
||||
export function deriveRequiresAttackRoll(action) {
|
||||
return getAttackRangeId(action) !== null;
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param action
|
||||
*/
|
||||
export function deriveRequiresSavingThrow(action) {
|
||||
return getSaveStatId(action) !== null;
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param action
|
||||
*/
|
||||
export function deriveIsDefaultDisplayAsAttack(action) {
|
||||
const displayAsAttack = getDisplayAsAttack(action);
|
||||
if (displayAsAttack !== null) {
|
||||
return displayAsAttack;
|
||||
}
|
||||
return deriveRequiresAttackRoll(action);
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param action
|
||||
*/
|
||||
export function deriveAttackSubtypeName(action) {
|
||||
switch (getAttackSubtypeId(action)) {
|
||||
case AttackSubtypeEnum.UNARMED:
|
||||
return 'Unarmed Strike';
|
||||
case AttackSubtypeEnum.NATURAL:
|
||||
return 'Natural Attack';
|
||||
}
|
||||
return null;
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param action
|
||||
* @param martialArtsLevelScale
|
||||
*/
|
||||
export function deriveIsMartialArtsAvailable(action, martialArtsLevelScale) {
|
||||
const isMartialArtsEnabled = getIsMartialArts(action);
|
||||
const attackSubtype = getAttackSubtypeId(action);
|
||||
if (martialArtsLevelScale !== null && (attackSubtype === AttackSubtypeEnum.UNARMED || isMartialArtsEnabled)) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param action
|
||||
* @param ruleData
|
||||
*/
|
||||
export function deriveFallbackAbilityIds(action, ruleData) {
|
||||
const actionType = getActionTypeId(action);
|
||||
const attackTypeRange = getAttackRangeId(action);
|
||||
const availableAbilities = [];
|
||||
if (actionType === ActionTypeEnum.WEAPON) {
|
||||
if (attackTypeRange === AttackTypeRangeEnum.RANGED) {
|
||||
availableAbilities.push(AbilityStatEnum.DEXTERITY);
|
||||
}
|
||||
else {
|
||||
availableAbilities.push(AbilityStatEnum.STRENGTH);
|
||||
}
|
||||
}
|
||||
else {
|
||||
const dataOrigin = getDataOrigin(action);
|
||||
const dataOriginType = getDataOriginType(action);
|
||||
switch (dataOriginType) {
|
||||
case DataOriginTypeEnum.CLASS_FEATURE:
|
||||
const primaryAbilities = ClassAccessors.getPrimaryAbilities(dataOrigin.parent);
|
||||
if (primaryAbilities.length) {
|
||||
availableAbilities.push(...primaryAbilities);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
return availableAbilities;
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param action
|
||||
* @param abilityLookup
|
||||
* @param ruleData
|
||||
*/
|
||||
export function deriveBestFallbackAbility(action, abilityLookup, ruleData) {
|
||||
const fallbackAbilityIds = deriveFallbackAbilityIds(action, ruleData);
|
||||
const fallbackAbilities = fallbackAbilityIds.map((id) => abilityLookup[id]);
|
||||
return HelperUtils.getLast(fallbackAbilities, 'modifier');
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param action
|
||||
* @param martialArtsLevelScale
|
||||
* @param ruleData
|
||||
* @param includeFallbacks
|
||||
*/
|
||||
export function deriveAvailableAbilities(action, martialArtsLevelScale, ruleData, includeFallbacks = true) {
|
||||
let attackStat = null;
|
||||
if (requiresAttackRoll(action)) {
|
||||
attackStat = getAbilityModifierStatId(action);
|
||||
}
|
||||
const availableAbilities = [];
|
||||
if (attackStat) {
|
||||
availableAbilities.push(attackStat);
|
||||
}
|
||||
else if (includeFallbacks) {
|
||||
availableAbilities.push(...deriveFallbackAbilityIds(action, ruleData));
|
||||
}
|
||||
if (deriveIsMartialArtsAvailable(action, martialArtsLevelScale) &&
|
||||
!availableAbilities.includes(AbilityStatEnum.DEXTERITY)) {
|
||||
availableAbilities.push(AbilityStatEnum.DEXTERITY);
|
||||
}
|
||||
return availableAbilities;
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param action
|
||||
* @param abilityLookup
|
||||
* @param proficiencyBonus
|
||||
* @param valueLookup
|
||||
* @param ruleData
|
||||
*/
|
||||
export function deriveAttackSaveValue(action, abilityLookup, proficiencyBonus, valueLookup, ruleData) {
|
||||
const id = getMappingId(action);
|
||||
const entityId = getMappingEntityTypeId(action);
|
||||
if (getSaveStatId(action) === null) {
|
||||
return null;
|
||||
}
|
||||
const fixedSaveDc = getFixedSaveDc(action);
|
||||
if (fixedSaveDc) {
|
||||
return fixedSaveDc;
|
||||
}
|
||||
const saveDcOverride = ValueUtils.getKeyValue(valueLookup, AdjustmentTypeEnum.SAVE_DC_OVERRIDE, id, entityId);
|
||||
if (saveDcOverride !== null) {
|
||||
return saveDcOverride;
|
||||
}
|
||||
let attackSaveAbility = null;
|
||||
const abilityModifierStatId = getAbilityModifierStatId(action);
|
||||
if (abilityModifierStatId) {
|
||||
attackSaveAbility = abilityLookup[abilityModifierStatId];
|
||||
}
|
||||
else {
|
||||
attackSaveAbility = deriveBestFallbackAbility(action, abilityLookup, ruleData);
|
||||
}
|
||||
if (!attackSaveAbility) {
|
||||
return null;
|
||||
}
|
||||
const abilityModifier = AbilityAccessors.getModifier(attackSaveAbility);
|
||||
const attackSaveAbilityModifier = abilityModifier ? abilityModifier : 0;
|
||||
let saveDc = CharacterDerivers.deriveAttackSaveValue(proficiencyBonus, attackSaveAbilityModifier);
|
||||
saveDc += ValueUtils.getKeyValue(valueLookup, AdjustmentTypeEnum.SAVE_DC_BONUS, id, entityId, 0);
|
||||
return saveDc;
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param bestAbilityInfo
|
||||
* @param action
|
||||
* @param modifiers
|
||||
* @param abilityLookup
|
||||
* @param valueLookup
|
||||
*/
|
||||
export function deriveToHit(bestAbilityInfo, action, modifiers, abilityLookup, valueLookup) {
|
||||
const actionType = getActionTypeId(action);
|
||||
let toHit = null;
|
||||
if (bestAbilityInfo && getAttackRangeId(action) !== null) {
|
||||
const id = getMappingId(action);
|
||||
const entityId = getMappingEntityTypeId(action);
|
||||
const toHitOverride = ValueUtils.getKeyValue(valueLookup, AdjustmentTypeEnum.TO_HIT_OVERRIDE, id, entityId);
|
||||
if (toHitOverride !== null) {
|
||||
return toHitOverride;
|
||||
}
|
||||
let bonusToHitModifiers = null;
|
||||
let bonusToHitModifierTotal = 0;
|
||||
if (actionType === ActionTypeEnum.SPELL) {
|
||||
bonusToHitModifiers = modifiers.filter((modifier) => ModifierValidators.isValidBonusActionSpellToHitModifier(modifier, action));
|
||||
}
|
||||
else if (actionType === ActionTypeEnum.WEAPON) {
|
||||
bonusToHitModifiers = modifiers.filter((modifier) => ModifierValidators.isValidBonusActionWeaponToHitModifier(modifier, action));
|
||||
}
|
||||
if (bonusToHitModifiers !== null) {
|
||||
bonusToHitModifierTotal = ModifierDerivers.sumModifiers(bonusToHitModifiers, abilityLookup);
|
||||
}
|
||||
const toHitCustomBonus = ValueUtils.getKeyValue(valueLookup, AdjustmentTypeEnum.TO_HIT_BONUS, id, entityId, 0);
|
||||
toHit = bestAbilityInfo.toHit + bonusToHitModifierTotal + toHitCustomBonus;
|
||||
}
|
||||
const fixedToHit = getFixedToHit(action);
|
||||
if (fixedToHit !== null) {
|
||||
toHit = fixedToHit;
|
||||
}
|
||||
return toHit;
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param action
|
||||
* @param baseDamage
|
||||
* @param fixedDamageBonuses
|
||||
* @param valueLookup
|
||||
* @param ruleData
|
||||
*/
|
||||
export function deriveDamage(action, baseDamage, fixedDamageBonuses, valueLookup, ruleData) {
|
||||
const id = getMappingId(action);
|
||||
const entityId = getMappingEntityTypeId(action);
|
||||
const damageTypeId = getDamageTypeId(action);
|
||||
let type = null;
|
||||
let value = null;
|
||||
let dataOrigin = null;
|
||||
let isMartialArts = false;
|
||||
const damageCustomBonus = ValueUtils.getKeyValue(valueLookup, AdjustmentTypeEnum.FIXED_VALUE_BONUS, id, entityId, 0);
|
||||
const fixedDamage = fixedDamageBonuses + damageCustomBonus;
|
||||
if (baseDamage !== null) {
|
||||
if (typeof baseDamage === 'number') {
|
||||
value = Math.max(0, baseDamage + fixedDamage);
|
||||
}
|
||||
else if (baseDamage.isMartialArts !== undefined) {
|
||||
if (baseDamage.dataOrigin) {
|
||||
dataOrigin = baseDamage.dataOrigin;
|
||||
}
|
||||
else if (baseDamage.isMartialArts) {
|
||||
isMartialArts = true;
|
||||
}
|
||||
const fixedValue = DiceAccessors.getFixedValue(baseDamage);
|
||||
value = Object.assign(Object.assign({}, baseDamage), { fixedValue: (fixedValue ? fixedValue : 0) + fixedDamage });
|
||||
}
|
||||
}
|
||||
if (damageTypeId) {
|
||||
type = RuleDataUtils.getDamageType(damageTypeId, ruleData);
|
||||
}
|
||||
return {
|
||||
type,
|
||||
value,
|
||||
dataOrigin,
|
||||
isMartialArts,
|
||||
};
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param action
|
||||
* @param valueLookup
|
||||
*/
|
||||
export function deriveName(action, valueLookup) {
|
||||
const id = getMappingId(action);
|
||||
const entityId = getMappingEntityTypeId(action);
|
||||
let derivedName = getDefinitionName(action);
|
||||
const nameOverride = ValueUtils.getKeyValue(valueLookup, AdjustmentTypeEnum.NAME_OVERRIDE, id, entityId);
|
||||
if (nameOverride) {
|
||||
derivedName = nameOverride;
|
||||
}
|
||||
if (derivedName === null) {
|
||||
derivedName = '';
|
||||
}
|
||||
return derivedName;
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param action
|
||||
* @param modifiers
|
||||
*/
|
||||
export function deriveLabel(action, modifiers) {
|
||||
const masteryModifiers = modifiers.filter((modifier) => ModifierValidators.isValidWeaponMasteryModifier(modifier));
|
||||
const masteryModifier = masteryModifiers.find((modifier) => modifier.componentId === action.componentId);
|
||||
if (masteryModifier) {
|
||||
return ModifierAccessors.getFriendlySubtypeName(masteryModifier);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param action
|
||||
* @param proficiencyBonus
|
||||
*/
|
||||
export function deriveProficiencyBonus(action, proficiencyBonus) {
|
||||
let bonus = 0;
|
||||
if (getIsProficienct(action)) {
|
||||
bonus = proficiencyBonus;
|
||||
}
|
||||
return bonus;
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param action
|
||||
*/
|
||||
export function deriveProficiency(action) {
|
||||
return getIsProficienct(action);
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param action
|
||||
* @param valueLookup
|
||||
*/
|
||||
export function deriveDisplayAsAttack(action, valueLookup) {
|
||||
const id = getMappingId(action);
|
||||
const entityId = getMappingEntityTypeId(action);
|
||||
const displayAsAttackOverride = ValueUtils.getKeyValue(valueLookup, AdjustmentTypeEnum.DISPLAY_AS_ATTACK, id, entityId);
|
||||
if (displayAsAttackOverride !== null) {
|
||||
return displayAsAttackOverride;
|
||||
}
|
||||
return deriveIsDefaultDisplayAsAttack(action);
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param action
|
||||
* @param modifiers
|
||||
* @param modifierData
|
||||
* @param ruleData
|
||||
*/
|
||||
export function deriveReach(action, modifiers, modifierData, ruleData) {
|
||||
let baseReach = null;
|
||||
if (getActionTypeId(action) === ActionTypeEnum.SPELL) {
|
||||
return null;
|
||||
}
|
||||
// Reach is null if it isn't a melee attack
|
||||
if (getAttackRangeId(action) !== AttackTypeRangeEnum.MELEE) {
|
||||
return null;
|
||||
}
|
||||
// Figure out base reach based on initial data
|
||||
const range = getDefinitionRange(action);
|
||||
if (range) {
|
||||
baseReach = range.range;
|
||||
}
|
||||
if (baseReach === null) {
|
||||
baseReach = RuleDataAccessors.getBaseWeaponReach(ruleData);
|
||||
}
|
||||
const bonusReachModifiers = modifiers.filter((modifier) => ModifierValidators.isBonusMeleeReachModifier(modifier));
|
||||
const bonusReachModifierTotal = ModifierDerivers.deriveTotalValue(bonusReachModifiers, modifierData);
|
||||
return baseReach + bonusReachModifierTotal;
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param action
|
||||
* @param martialArtsLevelScale
|
||||
* @param modifiers
|
||||
*/
|
||||
export function deriveHighestDamageDie(action, martialArtsLevelScale, modifiers) {
|
||||
const actionType = getActionTypeId(action);
|
||||
const baseDice = getDice(action);
|
||||
const attackSubtype = getAttackSubtypeId(action);
|
||||
const isMartialArtsAvailable = deriveIsMartialArtsAvailable(action, martialArtsLevelScale);
|
||||
const allDamageDice = [];
|
||||
if (baseDice) {
|
||||
allDamageDice.push(Object.assign(Object.assign({}, baseDice), { isMartialArts: false, dataOrigin: null }));
|
||||
}
|
||||
if (actionType === ActionTypeEnum.WEAPON && attackSubtype === AttackSubtypeEnum.UNARMED) {
|
||||
const setDamageDieModifiers = modifiers.filter((modifier) => ModifierValidators.isSetUnarmedDamageDieModifier(modifier));
|
||||
const setDamageDice = setDamageDieModifiers
|
||||
.map((modifier) => {
|
||||
const modifierDice = ModifierAccessors.getDice(modifier);
|
||||
if (modifierDice === null) {
|
||||
return null;
|
||||
}
|
||||
return Object.assign(Object.assign({}, modifierDice), { isMartialArts: false, dataOrigin: ModifierAccessors.getDataOrigin(modifier) });
|
||||
})
|
||||
.filter(TypeScriptUtils.isNotNullOrUndefined);
|
||||
allDamageDice.push(...setDamageDice);
|
||||
}
|
||||
if (martialArtsLevelScale !== null && isMartialArtsAvailable) {
|
||||
const martialArtsDie = DiceDerivers.deriveMartialArtsDamageDie(martialArtsLevelScale);
|
||||
allDamageDice.push(Object.assign(Object.assign({}, martialArtsDie), { isMartialArts: true, dataOrigin: null }));
|
||||
}
|
||||
return DiceUtils.getHighestDie(allDamageDice);
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param bestAbilityInfo
|
||||
* @param action
|
||||
* @param modifiers
|
||||
* @param abilityLookup
|
||||
*/
|
||||
export function deriveFixedDamageBonuses(bestAbilityInfo, action, modifiers, abilityLookup) {
|
||||
const actionType = getActionTypeId(action);
|
||||
let damageModifiers = [];
|
||||
let damageModifierTotal = 0;
|
||||
if (actionType === ActionTypeEnum.SPELL) {
|
||||
damageModifiers = modifiers.filter((modifier) => ModifierValidators.isValidDamageActionSpellModifier(modifier, action));
|
||||
}
|
||||
else if (actionType === ActionTypeEnum.WEAPON) {
|
||||
damageModifiers = modifiers.filter((modifier) => ModifierValidators.isValidDamageActionWeaponModifier(modifier, action));
|
||||
}
|
||||
if (damageModifiers.length) {
|
||||
damageModifierTotal = ModifierDerivers.sumModifiers(damageModifiers, abilityLookup);
|
||||
}
|
||||
return damageModifierTotal + (bestAbilityInfo ? bestAbilityInfo.damageBonus : 0);
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param action
|
||||
* @param modifiers
|
||||
* @param abilityLookup
|
||||
*/
|
||||
export function deriveRange(action, modifiers, abilityLookup) {
|
||||
const actionType = getActionTypeId(action);
|
||||
const definitionRange = getDefinitionRange(action);
|
||||
if (definitionRange === null) {
|
||||
return definitionRange;
|
||||
}
|
||||
let range = Object.assign(Object.assign({}, definitionRange), { origin: null });
|
||||
if (actionType === ActionTypeEnum.SPELL) {
|
||||
const attackTypeRange = getAttackRangeId(action);
|
||||
let newRange = definitionRange.range;
|
||||
if (attackTypeRange !== null && newRange) {
|
||||
const spellAttackRangeMultiplierModifiers = modifiers.filter((modifier) => ModifierValidators.isBonusSpellAttackRangeMultiplierModifier(modifier));
|
||||
const spellAttackRangeMultiplierTotal = Math.max(1, ModifierDerivers.sumModifiers(spellAttackRangeMultiplierModifiers, abilityLookup, 1));
|
||||
newRange *= spellAttackRangeMultiplierTotal;
|
||||
}
|
||||
range = Object.assign(Object.assign({}, definitionRange), { range: newRange, origin: getSpellRangeType(action) });
|
||||
}
|
||||
return range;
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param action
|
||||
* @param valueLookup
|
||||
*/
|
||||
export function deriveIsOffhand(action, valueLookup) {
|
||||
let isOffhand = false;
|
||||
if (getActionTypeId(action) === ActionTypeEnum.WEAPON) {
|
||||
const id = getMappingId(action);
|
||||
const entityId = getMappingEntityTypeId(action);
|
||||
isOffhand = ValueUtils.getKeyValue(valueLookup, AdjustmentTypeEnum.IS_OFFHAND, id, entityId, false);
|
||||
}
|
||||
return isOffhand;
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param action
|
||||
* @param valueLookup
|
||||
*/
|
||||
export function deriveIsSilvered(action, valueLookup) {
|
||||
let isSilvered = false;
|
||||
if (getActionTypeId(action) === ActionTypeEnum.WEAPON) {
|
||||
const id = getMappingId(action);
|
||||
const entityId = getMappingEntityTypeId(action);
|
||||
isSilvered = ValueUtils.getKeyValue(valueLookup, AdjustmentTypeEnum.IS_SILVER, id, entityId, false);
|
||||
}
|
||||
return isSilvered;
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param action
|
||||
* @param valueLookup
|
||||
*/
|
||||
export function deriveIsCustomized(action, valueLookup) {
|
||||
return ValueValidators.validateHasCustomization(ACTION_CUSTOMIZATION_ADJUSTMENT_TYPES, valueLookup, getMappingId(action), getMappingEntityTypeId(action));
|
||||
}
|
||||
@@ -0,0 +1,237 @@
|
||||
var __rest = (this && this.__rest) || function (s, e) {
|
||||
var t = {};
|
||||
for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0)
|
||||
t[p] = s[p];
|
||||
if (s != null && typeof Object.getOwnPropertySymbols === "function")
|
||||
for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) {
|
||||
if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i]))
|
||||
t[p[i]] = s[p[i]];
|
||||
}
|
||||
return t;
|
||||
};
|
||||
import { groupBy, keyBy } from 'lodash';
|
||||
import { CharacterDerivers } from '../Character';
|
||||
import { ClassAccessors } from '../Class';
|
||||
import { DataOriginGenerators, DataOriginTypeEnum } from '../DataOrigin';
|
||||
import { FeatAccessors } from '../Feat';
|
||||
import { HelperUtils } from '../Helper';
|
||||
import { ItemAccessors } from '../Item';
|
||||
import { OptionAccessors } from '../Option';
|
||||
import { RaceAccessors } from '../Race';
|
||||
import { RuleDataAccessors } from '../RuleData';
|
||||
import { AdjustmentTypeEnum, ValueUtils } from '../Value';
|
||||
import { getActionTypeId, getDisplayAsAttack, getFixedValue, getUniqueKey } from './accessors';
|
||||
import { ActionTypeEnum } from './constants';
|
||||
import { deriveAttackSaveValue, deriveAttackSubtypeName, deriveAvailableAbilities, deriveDamage, deriveDisplayAsAttack, deriveFixedDamageBonuses, deriveHighestDamageDie, deriveIsCustomized, deriveIsDefaultDisplayAsAttack, deriveIsOffhand, deriveIsSilvered, deriveName, deriveProficiency, deriveProficiencyBonus, deriveRange, deriveReach, deriveRequiresAttackRoll, deriveRequiresSavingThrow, deriveToHit, deriveUniqueKey, } from './derivers';
|
||||
/**
|
||||
*
|
||||
* @param action
|
||||
*/
|
||||
export function generateDataOriginKey(action) {
|
||||
return DataOriginGenerators.generateDataOriginKey(action.componentId, action.componentTypeId);
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param id
|
||||
* @param entityTypeId
|
||||
* @param actionLookup
|
||||
* @param valueLookup
|
||||
* @param dataOriginType
|
||||
* @param primary
|
||||
* @param parent
|
||||
*/
|
||||
export function generateBaseActions(id, entityTypeId, actionLookup, valueLookup, dataOriginType, primary, parent = null) {
|
||||
const actions = HelperUtils.lookupDataOrFallback(actionLookup, DataOriginGenerators.generateDataOriginKey(id, entityTypeId));
|
||||
if (!actions) {
|
||||
return [];
|
||||
}
|
||||
return actions.map((action) => generateDataOriginBaseAction(action, valueLookup, dataOriginType, primary, parent));
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param action
|
||||
* @param valueLookup
|
||||
*/
|
||||
export function generateBaseAction(action, valueLookup) {
|
||||
const { componentId, componentTypeId, displayAsAttack, entityTypeId, id, limitedUse, name } = action, definitionProps = __rest(action, ["componentId", "componentTypeId", "displayAsAttack", "entityTypeId", "id", "limitedUse", "name"]);
|
||||
const simulatedAction = {
|
||||
definition: Object.assign(Object.assign({}, definitionProps), { displayAsAttack,
|
||||
name }),
|
||||
componentId,
|
||||
componentTypeId,
|
||||
entityTypeId,
|
||||
id,
|
||||
limitedUse,
|
||||
};
|
||||
return Object.assign(Object.assign({}, simulatedAction), { displayAsAttack: deriveDisplayAsAttack(simulatedAction, valueLookup), name: deriveName(simulatedAction, valueLookup), notes: ValueUtils.getKeyValue(valueLookup, AdjustmentTypeEnum.NOTES, id, entityTypeId), originalContract: action, proficiency: deriveProficiency(simulatedAction), requiresAttackRoll: deriveRequiresAttackRoll(simulatedAction), requiresSavingThrow: deriveRequiresSavingThrow(simulatedAction), isDefaultDisplayAsAttack: deriveIsDefaultDisplayAsAttack(simulatedAction), uniqueKey: deriveUniqueKey(simulatedAction) });
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param actions
|
||||
* @param valueLookup
|
||||
* @param type
|
||||
* @param primary
|
||||
* @param parent
|
||||
*/
|
||||
export function generateDataOriginBaseActions(actions, valueLookup, type, primary = null, parent = null) {
|
||||
return actions.map((action) => generateDataOriginBaseAction(action, valueLookup, type, primary, parent));
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param action
|
||||
* @param valueLookup
|
||||
* @param dataOriginType
|
||||
* @param primary
|
||||
* @param parent
|
||||
*/
|
||||
export function generateDataOriginBaseAction(action, valueLookup, dataOriginType, primary, parent) {
|
||||
const dataOrigin = DataOriginGenerators.generateDataOrigin(dataOriginType, primary, parent);
|
||||
return Object.assign(Object.assign({}, generateBaseAction(action, valueLookup)), { dataOrigin });
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param action
|
||||
* @param valueLookup
|
||||
*/
|
||||
export function generateInnateNaturalDataOriginBaseAction(action, valueLookup) {
|
||||
return generateDataOriginBaseAction(action, valueLookup, DataOriginTypeEnum.RULE_DATA, null, null);
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param baseAction
|
||||
* @param proficiencyBonus
|
||||
* @param abilityLookup
|
||||
* @param modifiers
|
||||
* @param valueLookup
|
||||
* @param martialArtsLevelScale
|
||||
* @param ruleData
|
||||
* @param modifierData
|
||||
*/
|
||||
export function generateAction(baseAction, proficiencyBonus, abilityLookup, modifiers, valueLookup, martialArtsLevelScale, ruleData, modifierData) {
|
||||
const actionType = getActionTypeId(baseAction);
|
||||
const fixedValue = getFixedValue(baseAction);
|
||||
const highestDamageDie = deriveHighestDamageDie(baseAction, martialArtsLevelScale, modifiers);
|
||||
const includeFallback = actionType !== ActionTypeEnum.GENERAL;
|
||||
const availableAbilities = deriveAvailableAbilities(baseAction, martialArtsLevelScale, ruleData, includeFallback);
|
||||
const attackProficiencyBonus = deriveProficiencyBonus(baseAction, proficiencyBonus);
|
||||
const abilityPossibilities = CharacterDerivers.deriveAttackAbilityPossibilities(availableAbilities, modifiers, attackProficiencyBonus, abilityLookup);
|
||||
const bestAbilityInfo = HelperUtils.getLast(abilityPossibilities, ['toHit', 'modifier']);
|
||||
const fixedDamageBonuses = deriveFixedDamageBonuses(bestAbilityInfo, baseAction, modifiers, abilityLookup);
|
||||
const damage = deriveDamage(baseAction, highestDamageDie ? highestDamageDie : fixedValue, fixedDamageBonuses, valueLookup, ruleData);
|
||||
return Object.assign(Object.assign({}, baseAction), { attackSaveValue: deriveAttackSaveValue(baseAction, abilityLookup, proficiencyBonus, valueLookup, ruleData), attackSubtypeName: deriveAttackSubtypeName(baseAction), damage, range: deriveRange(baseAction, modifiers, abilityLookup), reach: deriveReach(baseAction, modifiers, modifierData, ruleData), statId: bestAbilityInfo ? bestAbilityInfo.abilityId : null, toHit: deriveToHit(bestAbilityInfo, baseAction, modifiers, abilityLookup, valueLookup), isOffhand: deriveIsOffhand(baseAction, valueLookup), isSilvered: deriveIsSilvered(baseAction, valueLookup), isCustomized: deriveIsCustomized(baseAction, valueLookup) });
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param actions
|
||||
*/
|
||||
export function generateActionComponentLookup(actions) {
|
||||
return groupBy(actions, (action) => generateDataOriginKey(action));
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param actions
|
||||
*/
|
||||
export function generateActionLookup(actions) {
|
||||
return keyBy(actions, (action) => getUniqueKey(action));
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param feats
|
||||
* @param race
|
||||
* @param classes
|
||||
* @param innateNaturalActions
|
||||
* @param inventory
|
||||
* @param proficiencyBonus
|
||||
* @param abilityLookup
|
||||
* @param modifiers
|
||||
* @param martialArtsLevel
|
||||
* @param ruleData
|
||||
* @param modifierData
|
||||
* @param valueLookup
|
||||
*/
|
||||
export function generateAggregatedActions(feats, race, classes, innateNaturalActions, inventory, proficiencyBonus, abilityLookup, modifiers, martialArtsLevelScale, ruleData, modifierData, valueLookup) {
|
||||
const actions = [];
|
||||
actions.push(...innateNaturalActions);
|
||||
if (race) {
|
||||
actions.push(...RaceAccessors.getActions(race));
|
||||
}
|
||||
classes.forEach((charClass) => {
|
||||
actions.push(...ClassAccessors.getActions(charClass));
|
||||
});
|
||||
feats.forEach((feat) => {
|
||||
actions.push(...FeatAccessors.getActions(feat));
|
||||
FeatAccessors.getOptions(feat).forEach((option) => {
|
||||
actions.push(...OptionAccessors.getActions(option));
|
||||
});
|
||||
});
|
||||
inventory.forEach((item) => {
|
||||
actions.push(...ItemAccessors.getInfusionActions(item));
|
||||
});
|
||||
return actions.map((baseAction) => generateAction(baseAction, proficiencyBonus, abilityLookup, modifiers, valueLookup, martialArtsLevelScale, ruleData, modifierData));
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param customActions
|
||||
* @param proficiencyBonus
|
||||
* @param abilityLookup
|
||||
* @param valueLookup
|
||||
* @param modifiers
|
||||
* @param martialArtsLevel
|
||||
* @param ruleData
|
||||
* @param modifierData
|
||||
*/
|
||||
export function generateCustomActions(customActions, proficiencyBonus, abilityLookup, valueLookup, modifiers, martialArtsLevelScale, ruleData, modifierData) {
|
||||
return customActions.map((customAction) => generateCustomAction(customAction, proficiencyBonus, abilityLookup, valueLookup, modifiers, martialArtsLevelScale, ruleData, modifierData));
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param customAction
|
||||
* @param proficiencyBonus
|
||||
* @param abilityLookup
|
||||
* @param valueLookup
|
||||
* @param modifiers
|
||||
* @param martialArtsLevelScale
|
||||
* @param ruleData
|
||||
* @param modifierData
|
||||
*/
|
||||
export function generateCustomAction(customAction, proficiencyBonus, abilityLookup, valueLookup, modifiers, martialArtsLevelScale, ruleData, modifierData) {
|
||||
const { aoeSize, aoeType, longRange, range, activationTime, activationType, diceCount, diceType, fixedValue, rangeId, statId, displayAsAttack, id, isSilvered, isOffhand } = customAction, similarActionProps = __rest(customAction, ["aoeSize", "aoeType", "longRange", "range", "activationTime", "activationType", "diceCount", "diceType", "fixedValue", "rangeId", "statId", "displayAsAttack", "id", "isSilvered", "isOffhand"]);
|
||||
let dice = null;
|
||||
let value = null;
|
||||
if (diceType) {
|
||||
dice = {
|
||||
diceCount: diceCount ? diceCount : 1,
|
||||
diceValue: diceType,
|
||||
fixedValue,
|
||||
diceMultiplier: null,
|
||||
diceString: null,
|
||||
};
|
||||
}
|
||||
else {
|
||||
value = fixedValue;
|
||||
}
|
||||
const actionLike = Object.assign(Object.assign({}, similarActionProps), { id, range: {
|
||||
range,
|
||||
longRange,
|
||||
aoeSize,
|
||||
aoeType,
|
||||
minimumRange: null,
|
||||
hasAoeSpecialDescription: false, // default
|
||||
}, activation: {
|
||||
activationType,
|
||||
activationTime,
|
||||
}, abilityModifierStatId: statId, attackTypeRange: rangeId, dice,
|
||||
value, limitedUse: null, displayAsAttack: null, componentId: -1, componentTypeId: -1, fixedToHit: null, numberOfTargets: null, ammunition: null });
|
||||
const dataOriginBaseAction = generateDataOriginBaseAction(actionLike, valueLookup, DataOriginTypeEnum.CUSTOM, null, null);
|
||||
const generatedAction = generateAction(dataOriginBaseAction, proficiencyBonus, abilityLookup, modifiers, valueLookup, martialArtsLevelScale, ruleData, modifierData);
|
||||
const generatedDisplayAsAttack = getDisplayAsAttack(generatedAction);
|
||||
return Object.assign(Object.assign({}, generatedAction), { displayAsAttack: displayAsAttack === null ? (generatedDisplayAsAttack ? generatedDisplayAsAttack : false) : displayAsAttack, isSilvered, isOffhand: isOffhand === null ? false : isOffhand });
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param ruleData
|
||||
* @param valueLookup
|
||||
*/
|
||||
export function generateInnateBaseActions(ruleData, valueLookup) {
|
||||
return RuleDataAccessors.getNaturalActions(ruleData).map((action) => generateInnateNaturalDataOriginBaseAction(action, valueLookup));
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
import * as ActionAccessors from './accessors';
|
||||
import * as ActionConstants from './constants';
|
||||
import * as ActionDerivers from './derivers';
|
||||
import * as ActionGenerators from './generators';
|
||||
import * as ActionNotes from './notes';
|
||||
import * as ActionTypings from './typings';
|
||||
import * as ActionValidators from './validators';
|
||||
export * from './typings';
|
||||
export * from './constants';
|
||||
export { ActionAccessors, ActionDerivers, ActionValidators, ActionGenerators, ActionNotes };
|
||||
export default Object.assign(Object.assign(Object.assign(Object.assign(Object.assign(Object.assign(Object.assign({}, ActionAccessors), ActionConstants), ActionDerivers), ActionValidators), ActionGenerators), ActionNotes), ActionTypings);
|
||||
@@ -0,0 +1,56 @@
|
||||
import { TypeScriptUtils } from '../../utils';
|
||||
import { LimitedUseAccessors, LimitedUseDerivers, LimitedUseRenderers } from '../LimitedUse';
|
||||
import { NoteGenerators } from '../Note';
|
||||
import { RuleDataUtils } from '../RuleData';
|
||||
import { getLimitedUse, getNotes } from './accessors';
|
||||
/**
|
||||
*
|
||||
* @param action
|
||||
*/
|
||||
function getUserNoteComponent(action) {
|
||||
const notes = getNotes(action);
|
||||
if (notes) {
|
||||
return NoteGenerators.createPlainText(notes);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param action
|
||||
* @param ruleData
|
||||
* @param abilityLookup
|
||||
* @param proficiencyBonus
|
||||
*/
|
||||
function getLimitedUseNoteComponent(action, ruleData, abilityLookup, proficiencyBonus) {
|
||||
const limitedUse = getLimitedUse(action);
|
||||
if (!limitedUse) {
|
||||
return null;
|
||||
}
|
||||
const numberConsumed = LimitedUseAccessors.getMinNumberConsumed(limitedUse);
|
||||
const maxUses = LimitedUseDerivers.deriveMaxUses(limitedUse, abilityLookup, ruleData, proficiencyBonus);
|
||||
const numberUsed = LimitedUseAccessors.getNumberUsed(limitedUse);
|
||||
const numberRemaining = maxUses - numberUsed;
|
||||
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);
|
||||
return NoteGenerators.createTooltip(`1/${resetTypeAbbr}${isUsed ? ' (Used)' : ''}`, `Once per ${limitedUseResetTypeName}${isUsed ? ' (Used)' : ''}`, {
|
||||
dynamicTitle: true,
|
||||
});
|
||||
}
|
||||
return NoteGenerators.createPlainText(`${numberConsumed} Use${numberConsumed !== 1 ? 's' : ''} (${numberRemaining}/${maxUses})`);
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param action
|
||||
* @param ruleData
|
||||
* @param abilityLookup
|
||||
* @param proficiencyBonus
|
||||
*/
|
||||
export function getNoteComponents(action, ruleData, abilityLookup, proficiencyBonus) {
|
||||
const notes = [];
|
||||
notes.push(getLimitedUseNoteComponent(action, ruleData, abilityLookup, proficiencyBonus));
|
||||
notes.push(getUserNoteComponent(action));
|
||||
return notes.filter(TypeScriptUtils.isNotNullOrUndefined);
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
import { ActivationAccessors } from '../Activation';
|
||||
import { getActivation } from './accessors';
|
||||
/**
|
||||
*
|
||||
* @param action
|
||||
* @param activationType
|
||||
*/
|
||||
export function validateIsActivationType(action, activationType) {
|
||||
const activation = getActivation(action);
|
||||
if (activation === null) {
|
||||
return false;
|
||||
}
|
||||
return activationType === ActivationAccessors.getType(activation);
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
/**
|
||||
*
|
||||
* @param activation
|
||||
*/
|
||||
export function getTime(activation) {
|
||||
var _a;
|
||||
return (_a = activation === null || activation === void 0 ? void 0 : activation.activationTime) !== null && _a !== void 0 ? _a : null;
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param activation
|
||||
*/
|
||||
export function getType(activation) {
|
||||
var _a;
|
||||
return (_a = activation === null || activation === void 0 ? void 0 : activation.activationType) !== null && _a !== void 0 ? _a : null;
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
export var ActivationTypeEnum;
|
||||
(function (ActivationTypeEnum) {
|
||||
ActivationTypeEnum[ActivationTypeEnum["ACTION"] = 1] = "ACTION";
|
||||
ActivationTypeEnum[ActivationTypeEnum["NO_ACTION"] = 2] = "NO_ACTION";
|
||||
ActivationTypeEnum[ActivationTypeEnum["BONUS_ACTION"] = 3] = "BONUS_ACTION";
|
||||
ActivationTypeEnum[ActivationTypeEnum["REACTION"] = 4] = "REACTION";
|
||||
ActivationTypeEnum[ActivationTypeEnum["MINUTE"] = 6] = "MINUTE";
|
||||
ActivationTypeEnum[ActivationTypeEnum["HOUR"] = 7] = "HOUR";
|
||||
ActivationTypeEnum[ActivationTypeEnum["SPECIAL"] = 8] = "SPECIAL";
|
||||
})(ActivationTypeEnum || (ActivationTypeEnum = {}));
|
||||
@@ -0,0 +1,6 @@
|
||||
import * as ActivationAccessors from './accessors';
|
||||
import * as ActivationConstants from './constants';
|
||||
import * as ActivationRenderers from './renderers';
|
||||
export * from './constants';
|
||||
export { ActivationAccessors, ActivationRenderers };
|
||||
export default Object.assign(Object.assign(Object.assign({}, ActivationAccessors), ActivationConstants), ActivationRenderers);
|
||||
@@ -0,0 +1,131 @@
|
||||
import { FormatUtils } from '../Format';
|
||||
import { RuleDataUtils } from '../RuleData';
|
||||
import { getTime, getType } from './accessors';
|
||||
import { ActivationTypeEnum } from './constants';
|
||||
/**
|
||||
*
|
||||
* @param time
|
||||
* @param type
|
||||
*/
|
||||
export function renderActivationPluralSuffix(time, type) {
|
||||
let pluralSuffix = '';
|
||||
if (time !== null && time !== 1) {
|
||||
switch (type) {
|
||||
case ActivationTypeEnum.REACTION:
|
||||
case ActivationTypeEnum.ACTION:
|
||||
case ActivationTypeEnum.HOUR:
|
||||
case ActivationTypeEnum.MINUTE:
|
||||
case ActivationTypeEnum.BONUS_ACTION:
|
||||
pluralSuffix = 's';
|
||||
break;
|
||||
default:
|
||||
// not implemented
|
||||
}
|
||||
}
|
||||
return pluralSuffix;
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param activation
|
||||
* @param ruleData
|
||||
* @param defaultTime
|
||||
*/
|
||||
export function renderActivation(activation, ruleData, defaultTime = 1) {
|
||||
const activationTime = getTime(activation);
|
||||
const activationType = getType(activation);
|
||||
if (!activationType) {
|
||||
return '';
|
||||
}
|
||||
const activationTypeInfo = RuleDataUtils.getActivationTypeInfo(activationType, ruleData);
|
||||
const activationTypeName = activationTypeInfo ? activationTypeInfo.name : '';
|
||||
let time = activationTime === null ? defaultTime : activationTime;
|
||||
if (activationType === ActivationTypeEnum.SPECIAL || activationType === ActivationTypeEnum.NO_ACTION) {
|
||||
time = null;
|
||||
}
|
||||
return `${time ? `${time} ` : ''}${activationTypeName}${renderActivationPluralSuffix(time, activationType)}`;
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param activation
|
||||
* @param additionalTime
|
||||
* @param ruleData
|
||||
*/
|
||||
export function renderCastingTime(activation, additionalTime, ruleData) {
|
||||
const activationTime = getTime(activation);
|
||||
const activationType = getType(activation);
|
||||
let activationTypeInfo = null;
|
||||
if (activationType) {
|
||||
activationTypeInfo = RuleDataUtils.getActivationTypeInfo(activationType, ruleData);
|
||||
}
|
||||
additionalTime = additionalTime ? additionalTime : 0;
|
||||
let castingTimeString = '';
|
||||
if (activationTime && activationTypeInfo) {
|
||||
if (additionalTime > 0) {
|
||||
if (activationType === ActivationTypeEnum.MINUTE) {
|
||||
const totalTime = activationTime + additionalTime;
|
||||
castingTimeString = `${totalTime} Minute${totalTime !== 1 ? 's' : ''}`;
|
||||
}
|
||||
else {
|
||||
castingTimeString = `${activationTime} ${activationTypeInfo.name} + ${additionalTime} Minute${additionalTime !== 1 ? 's' : ''}`;
|
||||
}
|
||||
}
|
||||
else {
|
||||
castingTimeString = `${activationTime} ${activationTypeInfo.name}${renderActivationPluralSuffix(activationTime, activationType)}`;
|
||||
}
|
||||
}
|
||||
else if (activationTypeInfo) {
|
||||
castingTimeString = activationTypeInfo.name ? activationTypeInfo.name : '';
|
||||
}
|
||||
return FormatUtils.upperCaseFirstLetterOnly(castingTimeString);
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param activation
|
||||
* @param additionalTime
|
||||
*/
|
||||
export function renderCastingTimeAbbreviation(activation, additionalTime = 0) {
|
||||
const activationTime = getTime(activation);
|
||||
const activationType = getType(activation);
|
||||
let castingTimeString = '';
|
||||
if (activationTime) {
|
||||
if (additionalTime > 0) {
|
||||
if (activationType === ActivationTypeEnum.MINUTE) {
|
||||
const totalTime = activationTime + additionalTime;
|
||||
castingTimeString = `${totalTime}${renderActivationAbbreviation(ActivationTypeEnum.MINUTE)}`;
|
||||
}
|
||||
else {
|
||||
castingTimeString = `${activationTime}${renderActivationAbbreviation(activationType)} + ${additionalTime}${renderActivationAbbreviation(ActivationTypeEnum.MINUTE)}`;
|
||||
}
|
||||
}
|
||||
else {
|
||||
castingTimeString = `${activationTime}${renderActivationAbbreviation(activationType)}`;
|
||||
}
|
||||
}
|
||||
else {
|
||||
castingTimeString = renderActivationAbbreviation(activationType);
|
||||
}
|
||||
return castingTimeString;
|
||||
}
|
||||
/**
|
||||
* Gets the abbreviation for the specified activation type
|
||||
* @param activationType The activation type to abbreviate
|
||||
*/
|
||||
export function renderActivationAbbreviation(activationType) {
|
||||
switch (activationType) {
|
||||
case ActivationTypeEnum.BONUS_ACTION:
|
||||
return 'BA';
|
||||
case ActivationTypeEnum.ACTION:
|
||||
return 'A';
|
||||
case ActivationTypeEnum.REACTION:
|
||||
return 'R';
|
||||
case ActivationTypeEnum.SPECIAL:
|
||||
return 'S';
|
||||
case ActivationTypeEnum.HOUR:
|
||||
return 'h';
|
||||
case ActivationTypeEnum.MINUTE:
|
||||
return 'm';
|
||||
default:
|
||||
// not implemented
|
||||
}
|
||||
return '';
|
||||
}
|
||||
@@ -0,0 +1,452 @@
|
||||
/**
|
||||
*
|
||||
* @param background
|
||||
*/
|
||||
export function getDefinitionAvatarUrl(background) {
|
||||
var _a, _b;
|
||||
return (_b = (_a = background.definition) === null || _a === void 0 ? void 0 : _a.avatarUrl) !== null && _b !== void 0 ? _b : null;
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param background
|
||||
*/
|
||||
export function getAvatarUrl(background) {
|
||||
return getDefinitionAvatarUrl(background);
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param background
|
||||
*/
|
||||
export function getDefinitionBonds(background) {
|
||||
var _a, _b;
|
||||
return (_b = (_a = background.definition) === null || _a === void 0 ? void 0 : _a.bonds) !== null && _b !== void 0 ? _b : [];
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param background
|
||||
*/
|
||||
export function getBonds(background) {
|
||||
return getDefinitionBonds(background);
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param background
|
||||
*/
|
||||
export function getDefinitionContractsDescription(background) {
|
||||
var _a, _b;
|
||||
return (_b = (_a = background.definition) === null || _a === void 0 ? void 0 : _a.contractsDescription) !== null && _b !== void 0 ? _b : null;
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param background
|
||||
*/
|
||||
export function getContractsDescription(background) {
|
||||
return getDefinitionContractsDescription(background);
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param background
|
||||
*/
|
||||
export function getDefinitionDescription(background) {
|
||||
var _a, _b;
|
||||
return (_b = (_a = background.definition) === null || _a === void 0 ? void 0 : _a.description) !== null && _b !== void 0 ? _b : null;
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param background
|
||||
*/
|
||||
export function getDescription(background) {
|
||||
return getDefinitionDescription(background);
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param background
|
||||
*/
|
||||
export function getEntityTypeId(background) {
|
||||
return getDefinitionEntityTypeId(background);
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param background
|
||||
*/
|
||||
export function getDefinitionEntityTypeId(background) {
|
||||
var _a, _b;
|
||||
return (_b = (_a = background.definition) === null || _a === void 0 ? void 0 : _a.entityTypeId) !== null && _b !== void 0 ? _b : -1;
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param background
|
||||
*/
|
||||
export function getDefinitionEquipmentDescription(background) {
|
||||
var _a, _b;
|
||||
return (_b = (_a = background.definition) === null || _a === void 0 ? void 0 : _a.equipmentDescription) !== null && _b !== void 0 ? _b : null;
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param background
|
||||
*/
|
||||
export function getEquipmentDescription(background) {
|
||||
return getDefinitionEquipmentDescription(background);
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param background
|
||||
*/
|
||||
export function getDefinitionFeatureDescription(background) {
|
||||
var _a, _b;
|
||||
return (_b = (_a = background.definition) === null || _a === void 0 ? void 0 : _a.featureDescription) !== null && _b !== void 0 ? _b : null;
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param background
|
||||
*/
|
||||
export function getFeatureDescription(background) {
|
||||
return getDefinitionFeatureDescription(background);
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param background
|
||||
*/
|
||||
export function getDefinitionFeatureName(background) {
|
||||
var _a, _b;
|
||||
return (_b = (_a = background.definition) === null || _a === void 0 ? void 0 : _a.featureName) !== null && _b !== void 0 ? _b : null;
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param background
|
||||
*/
|
||||
export function getFeatureName(background) {
|
||||
return getDefinitionFeatureName(background);
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param background
|
||||
*/
|
||||
export function getDefinitionFlaws(background) {
|
||||
var _a, _b;
|
||||
return (_b = (_a = background.definition) === null || _a === void 0 ? void 0 : _a.flaws) !== null && _b !== void 0 ? _b : [];
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param background
|
||||
*/
|
||||
export function getFlaws(background) {
|
||||
return getDefinitionFlaws(background);
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param background
|
||||
*/
|
||||
export function getId(background) {
|
||||
var _a, _b;
|
||||
return (_b = (_a = background.definition) === null || _a === void 0 ? void 0 : _a.id) !== null && _b !== void 0 ? _b : -1;
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param background
|
||||
*/
|
||||
export function getDefinitionIdeals(background) {
|
||||
var _a, _b;
|
||||
return (_b = (_a = background.definition) === null || _a === void 0 ? void 0 : _a.ideals) !== null && _b !== void 0 ? _b : [];
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param background
|
||||
*/
|
||||
export function getIdeals(background) {
|
||||
return getDefinitionIdeals(background);
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param background
|
||||
*/
|
||||
export function getDefinitionLanguagesDescription(background) {
|
||||
var _a, _b;
|
||||
return (_b = (_a = background.definition) === null || _a === void 0 ? void 0 : _a.languagesDescription) !== null && _b !== void 0 ? _b : null;
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param background
|
||||
*/
|
||||
export function getLanguagesDescription(background) {
|
||||
return getDefinitionLanguagesDescription(background);
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param background
|
||||
*/
|
||||
export function getDefinitionLargeAvatarUrl(background) {
|
||||
var _a, _b;
|
||||
return (_b = (_a = background.definition) === null || _a === void 0 ? void 0 : _a.largeAvatarUrl) !== null && _b !== void 0 ? _b : null;
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param background
|
||||
*/
|
||||
export function getLargeAvatarUrl(background) {
|
||||
return getDefinitionLargeAvatarUrl(background);
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param background
|
||||
*/
|
||||
export function getName(background) {
|
||||
return getDefinitionName(background);
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param background
|
||||
*/
|
||||
export function getDefinitionName(background) {
|
||||
var _a, _b;
|
||||
return (_b = (_a = background.definition) === null || _a === void 0 ? void 0 : _a.name) !== null && _b !== void 0 ? _b : '';
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param background
|
||||
*/
|
||||
export function getDefinitionOrganization(background) {
|
||||
var _a, _b;
|
||||
return (_b = (_a = background.definition) === null || _a === void 0 ? void 0 : _a.organization) !== null && _b !== void 0 ? _b : null;
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param background
|
||||
*/
|
||||
export function getOrganization(background) {
|
||||
return getDefinitionOrganization(background);
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param background
|
||||
*/
|
||||
export function getDefinitionPersonalityTraits(background) {
|
||||
var _a, _b;
|
||||
return (_b = (_a = background.definition) === null || _a === void 0 ? void 0 : _a.personalityTraits) !== null && _b !== void 0 ? _b : [];
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param background
|
||||
*/
|
||||
export function getPersonalityTraits(background) {
|
||||
return getDefinitionPersonalityTraits(background);
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param background
|
||||
*/
|
||||
export function getDefinitionShortDescription(background) {
|
||||
var _a, _b;
|
||||
return (_b = (_a = background.definition) === null || _a === void 0 ? void 0 : _a.shortDescription) !== null && _b !== void 0 ? _b : null;
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param background
|
||||
*/
|
||||
export function getShortDescription(background) {
|
||||
return getDefinitionShortDescription(background);
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param background
|
||||
*/
|
||||
export function getDefinitionSkillProficienciesDescription(background) {
|
||||
var _a, _b;
|
||||
return (_b = (_a = background.definition) === null || _a === void 0 ? void 0 : _a.skillProficienciesDescription) !== null && _b !== void 0 ? _b : null;
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param background
|
||||
*/
|
||||
export function getSkillProficienciesDescription(background) {
|
||||
return getDefinitionSkillProficienciesDescription(background);
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param background
|
||||
*/
|
||||
export function getDefinitionSnippet(background) {
|
||||
var _a, _b;
|
||||
return (_b = (_a = background.definition) === null || _a === void 0 ? void 0 : _a.snippet) !== null && _b !== void 0 ? _b : null;
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param background
|
||||
*/
|
||||
export function getSnippet(background) {
|
||||
return getDefinitionSnippet(background);
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param background
|
||||
*/
|
||||
export function getDefinitionSpellsPostDescription(background) {
|
||||
var _a, _b;
|
||||
return (_b = (_a = background.definition) === null || _a === void 0 ? void 0 : _a.spellsPostDescription) !== null && _b !== void 0 ? _b : null;
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param background
|
||||
*/
|
||||
export function getSpellsPostDescription(background) {
|
||||
return getDefinitionSpellsPostDescription(background);
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param background
|
||||
*/
|
||||
export function getDefinitionSpellsPreDescription(background) {
|
||||
var _a, _b;
|
||||
return (_b = (_a = background.definition) === null || _a === void 0 ? void 0 : _a.spellsPreDescription) !== null && _b !== void 0 ? _b : null;
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param background
|
||||
*/
|
||||
export function getSpellsPreDescription(background) {
|
||||
return getDefinitionSpellsPreDescription(background);
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param background
|
||||
*/
|
||||
export function getDefinitionSuggestedCharacteristicsDescription(background) {
|
||||
var _a, _b;
|
||||
return (_b = (_a = background.definition) === null || _a === void 0 ? void 0 : _a.suggestedCharacteristicsDescription) !== null && _b !== void 0 ? _b : null;
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param background
|
||||
*/
|
||||
export function getSuggestedCharacteristicsDescription(background) {
|
||||
return getDefinitionSuggestedCharacteristicsDescription(background);
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param background
|
||||
*/
|
||||
export function getDefinitionSuggestedLanguages(background) {
|
||||
var _a, _b;
|
||||
return (_b = (_a = background.definition) === null || _a === void 0 ? void 0 : _a.suggestedLanguages) !== null && _b !== void 0 ? _b : [];
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param background
|
||||
*/
|
||||
export function getSuggestedLanguages(background) {
|
||||
return getDefinitionSuggestedLanguages(background);
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param background
|
||||
*/
|
||||
export function getDefinitionSuggestedProficiencies(background) {
|
||||
var _a, _b;
|
||||
return (_b = (_a = background.definition) === null || _a === void 0 ? void 0 : _a.suggestedProficiencies) !== null && _b !== void 0 ? _b : [];
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param background
|
||||
*/
|
||||
export function getSuggestedProficiencies(background) {
|
||||
return getDefinitionSuggestedProficiencies(background);
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param background
|
||||
*/
|
||||
export function getDefinitionToolProficienciesDescription(background) {
|
||||
var _a, _b;
|
||||
return (_b = (_a = background.definition) === null || _a === void 0 ? void 0 : _a.toolProficienciesDescription) !== null && _b !== void 0 ? _b : null;
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param background
|
||||
*/
|
||||
export function getToolProficienciesDescription(background) {
|
||||
return getDefinitionToolProficienciesDescription(background);
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param background
|
||||
*/
|
||||
export function getDefinitionSources(background) {
|
||||
var _a, _b;
|
||||
return (_b = (_a = background.definition) === null || _a === void 0 ? void 0 : _a.sources) !== null && _b !== void 0 ? _b : [];
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param background
|
||||
*/
|
||||
export function getSources(background) {
|
||||
return getDefinitionSources(background);
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param background
|
||||
*/
|
||||
export function getDefinitionIsHomebrew(background) {
|
||||
var _a, _b;
|
||||
return (_b = (_a = background.definition) === null || _a === void 0 ? void 0 : _a.isHomebrew) !== null && _b !== void 0 ? _b : false;
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param background
|
||||
*/
|
||||
export function isHomebrew(background) {
|
||||
return getDefinitionIsHomebrew(background);
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param background
|
||||
*/
|
||||
export function getDefinitionSpellListIds(background) {
|
||||
var _a, _b;
|
||||
return (_b = (_a = background.definition) === null || _a === void 0 ? void 0 : _a.spellListIds) !== null && _b !== void 0 ? _b : [];
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param background
|
||||
*/
|
||||
export function getSpellListIds(background) {
|
||||
return getDefinitionSpellListIds(background);
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param background
|
||||
*/
|
||||
export function getCustomBackground(background) {
|
||||
return background.customBackground;
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param background
|
||||
*/
|
||||
export function getDefinitionId(background) {
|
||||
return background.definitionId;
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param background
|
||||
*/
|
||||
export function getHasCustomBackground(background) {
|
||||
return background.hasCustomBackground;
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param background
|
||||
*/
|
||||
export function getChoices(background) {
|
||||
return background.choices;
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param background
|
||||
*/
|
||||
export function getModifiers(background) {
|
||||
return background.modifiers;
|
||||
}
|
||||
export function getFeatListContracts(contract) {
|
||||
var _a, _b;
|
||||
return (_b = (_a = contract === null || contract === void 0 ? void 0 : contract.definition) === null || _a === void 0 ? void 0 : _a.grantedFeats) !== null && _b !== void 0 ? _b : [];
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
export var BackgroundModifierTypeEnum;
|
||||
(function (BackgroundModifierTypeEnum) {
|
||||
BackgroundModifierTypeEnum[BackgroundModifierTypeEnum["TWO_TOOLS"] = 1] = "TWO_TOOLS";
|
||||
BackgroundModifierTypeEnum[BackgroundModifierTypeEnum["TWO_LANGUAGES"] = 2] = "TWO_LANGUAGES";
|
||||
BackgroundModifierTypeEnum[BackgroundModifierTypeEnum["ONE_TOOL_ONE_LANGUAGE"] = 3] = "ONE_TOOL_ONE_LANGUAGE";
|
||||
})(BackgroundModifierTypeEnum || (BackgroundModifierTypeEnum = {}));
|
||||
@@ -0,0 +1,8 @@
|
||||
import { getEntityTypeId, getId } from './accessors';
|
||||
/**
|
||||
*
|
||||
* @param background
|
||||
*/
|
||||
export function deriveUniqueKey(background) {
|
||||
return [getId(background), getEntityTypeId(background)].join('-');
|
||||
}
|
||||
@@ -0,0 +1,116 @@
|
||||
import { ChoiceGenerators } from '../Choice';
|
||||
import { DataOriginDataInfoKeyEnum, DataOriginTypeEnum } from '../DataOrigin';
|
||||
import { FeatList } from '../FeatList';
|
||||
import { ModifierGenerators } from '../Modifier';
|
||||
import { getCustomBackground, getEntityTypeId, getHasCustomBackground, getId, getModifiers, getSpellListIds, } from './accessors';
|
||||
import { deriveUniqueKey } from './derivers';
|
||||
/**
|
||||
*
|
||||
* @param background
|
||||
* @param modifierLookup
|
||||
* @param choiceLookup
|
||||
* @param choiceComponents
|
||||
* @param baseFeats
|
||||
*/
|
||||
export function generateBackground(background, modifierLookup, choiceLookup, choiceComponents, baseFeats) {
|
||||
var _a, _b;
|
||||
if (!background || (background && !getHasCustomBackground(background) && background.definition === null)) {
|
||||
return null;
|
||||
}
|
||||
let backgroundInfo;
|
||||
if (getHasCustomBackground(background) && background.customBackground) {
|
||||
const { featuresBackground, characteristicsBackground, name, description, id, entityTypeId } = background.customBackground;
|
||||
let featureName = '';
|
||||
let featureDescription = '';
|
||||
if (featuresBackground) {
|
||||
featureName = featuresBackground.featureName ? featuresBackground.featureName : '';
|
||||
featureDescription = featuresBackground.featureDescription ? featuresBackground.featureDescription : '';
|
||||
}
|
||||
let bonds = [];
|
||||
let flaws = [];
|
||||
let ideals = [];
|
||||
let personalityTraits = [];
|
||||
if (characteristicsBackground) {
|
||||
bonds = characteristicsBackground.bonds === null ? [] : characteristicsBackground.bonds;
|
||||
flaws = characteristicsBackground.flaws === null ? [] : characteristicsBackground.flaws;
|
||||
ideals = characteristicsBackground.ideals === null ? [] : characteristicsBackground.ideals;
|
||||
personalityTraits =
|
||||
characteristicsBackground.personalityTraits === null ? [] : characteristicsBackground.personalityTraits;
|
||||
}
|
||||
backgroundInfo = {
|
||||
hasCustomBackground: getHasCustomBackground(background),
|
||||
customBackground: getCustomBackground(background),
|
||||
definitionId: id,
|
||||
definition: {
|
||||
avatarUrl: '',
|
||||
largeAvatarUrl: '',
|
||||
organization: null,
|
||||
snippet: '',
|
||||
contractsDescription: null,
|
||||
equipmentDescription: '',
|
||||
languagesDescription: '',
|
||||
skillProficienciesDescription: '',
|
||||
spellsPreDescription: null,
|
||||
spellsPostDescription: null,
|
||||
toolProficienciesDescription: '',
|
||||
suggestedCharacteristicsDescription: '',
|
||||
suggestedLanguages: [],
|
||||
suggestedProficiencies: [],
|
||||
id,
|
||||
entityTypeId,
|
||||
name,
|
||||
description,
|
||||
shortDescription: description,
|
||||
featureName,
|
||||
featureDescription,
|
||||
bonds,
|
||||
flaws,
|
||||
ideals,
|
||||
personalityTraits,
|
||||
isHomebrew: false,
|
||||
sources: [],
|
||||
spellListIds: [],
|
||||
grantedFeats: [],
|
||||
},
|
||||
};
|
||||
}
|
||||
else {
|
||||
backgroundInfo = background;
|
||||
}
|
||||
const backgroundId = getId(backgroundInfo);
|
||||
const backgroundTypeId = getEntityTypeId(backgroundInfo);
|
||||
const choices = ChoiceGenerators.generateBaseChoices(backgroundId, backgroundTypeId, choiceLookup, DataOriginTypeEnum.BACKGROUND, backgroundInfo);
|
||||
const modifiers = ModifierGenerators.generateModifiers(backgroundId, backgroundTypeId, modifierLookup, DataOriginTypeEnum.BACKGROUND, backgroundInfo);
|
||||
const featLists = ((_b = (_a = backgroundInfo.definition) === null || _a === void 0 ? void 0 : _a.grantedFeats) === null || _b === void 0 ? void 0 : _b.map((featListContract) => new FeatList(featListContract, choiceComponents.definitionKeyNameMap, baseFeats))) || [];
|
||||
return Object.assign(Object.assign({}, backgroundInfo), { choices,
|
||||
modifiers,
|
||||
featLists });
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param background
|
||||
*/
|
||||
export function generateBackgroundModifiers(background) {
|
||||
return background ? getModifiers(background) : [];
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param background
|
||||
*/
|
||||
export function generateRefBackgroundData(background) {
|
||||
let data = {};
|
||||
if (background !== null) {
|
||||
data[deriveUniqueKey(background)] = {
|
||||
[DataOriginDataInfoKeyEnum.PRIMARY]: background,
|
||||
[DataOriginDataInfoKeyEnum.PARENT]: null,
|
||||
};
|
||||
}
|
||||
return data;
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param background
|
||||
*/
|
||||
export function generateGlobalSpellListIds(background) {
|
||||
return background ? getSpellListIds(background) : [];
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
import * as BackgroundAccessors from './accessors';
|
||||
import * as BackgroundConstants from './constants';
|
||||
import * as BackgroundDerivers from './derivers';
|
||||
import * as BackgroundGenerators from './generators';
|
||||
import * as BackgroundTypings from './typings';
|
||||
export * from './typings';
|
||||
export * from './constants';
|
||||
export { BackgroundAccessors, BackgroundDerivers, BackgroundGenerators };
|
||||
export default Object.assign(Object.assign(Object.assign(Object.assign(Object.assign({}, BackgroundAccessors), BackgroundConstants), BackgroundDerivers), BackgroundGenerators), BackgroundTypings);
|
||||
@@ -0,0 +1,105 @@
|
||||
import { PartyInventorySharingStateEnum } from './constants';
|
||||
/**
|
||||
*
|
||||
* @param campaign
|
||||
* @deprecated Use the new getCharacters
|
||||
*/
|
||||
export function getCharacter(campaign) {
|
||||
return campaign.characters;
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param campaign
|
||||
* @returns {Array<ShortCharacterContract>}
|
||||
*/
|
||||
export function getCharacters(campaign) {
|
||||
return campaign.characters;
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param campaign
|
||||
*/
|
||||
export function getDescription(campaign) {
|
||||
return campaign.description;
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param campaign
|
||||
*/
|
||||
export function getDmUserId(campaign) {
|
||||
return campaign.dmUserId;
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param campaign
|
||||
*/
|
||||
export function getId(campaign) {
|
||||
return campaign.id;
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param campaign
|
||||
*/
|
||||
export function getDmUsername(campaign) {
|
||||
return campaign.dmUsername;
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param campaign
|
||||
*/
|
||||
export function getLink(campaign) {
|
||||
return campaign.link;
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param campaign
|
||||
*/
|
||||
export function getName(campaign) {
|
||||
return campaign.name;
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param campaign
|
||||
*/
|
||||
export function getPublicNotes(campaign) {
|
||||
return campaign.publicNotes;
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param partyInfo
|
||||
* @returns {Array<BaseInventoryContract>}
|
||||
*/
|
||||
export function getPartyBaseInventoryContracts(partyInfo) {
|
||||
return partyInfo.partyInventory;
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param partyInfo
|
||||
*/
|
||||
export function getSharingState(partyInfo) {
|
||||
var _a;
|
||||
return (_a = partyInfo.sharingState) !== null && _a !== void 0 ? _a : PartyInventorySharingStateEnum.OFF;
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param partyInfo
|
||||
*/
|
||||
export function getItemSpells(partyInfo) {
|
||||
var _a, _b;
|
||||
return (_b = (_a = partyInfo.spells) === null || _a === void 0 ? void 0 : _a.item) !== null && _b !== void 0 ? _b : [];
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param partyInfo
|
||||
*/
|
||||
export function getItemModifiers(partyInfo) {
|
||||
var _a, _b;
|
||||
return (_b = (_a = partyInfo.modifiers) === null || _a === void 0 ? void 0 : _a.item) !== null && _b !== void 0 ? _b : [];
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param partyInfo
|
||||
*/
|
||||
export function getCoin(partyInfo) {
|
||||
return partyInfo.coin;
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
export var PartyInventorySharingStateEnum;
|
||||
(function (PartyInventorySharingStateEnum) {
|
||||
PartyInventorySharingStateEnum[PartyInventorySharingStateEnum["OFF"] = 0] = "OFF";
|
||||
PartyInventorySharingStateEnum[PartyInventorySharingStateEnum["ON"] = 1] = "ON";
|
||||
PartyInventorySharingStateEnum[PartyInventorySharingStateEnum["DELETE_ONLY"] = 2] = "DELETE_ONLY";
|
||||
})(PartyInventorySharingStateEnum || (PartyInventorySharingStateEnum = {}));
|
||||
@@ -0,0 +1,16 @@
|
||||
import { ItemGenerators } from '../Item';
|
||||
import { getPartyBaseInventoryContracts } from './accessors';
|
||||
/**
|
||||
*
|
||||
* @param partyInfo
|
||||
* @param modifierLookup
|
||||
* @param spellLookup
|
||||
* @param valueLookup
|
||||
* @param inventoryInfusionLookup
|
||||
* @param ruleData
|
||||
*/
|
||||
export function generateBasePartyInventory(partyInfo, modifierLookup, spellLookup, valueLookup, inventoryInfusionLookup, ruleData) {
|
||||
return partyInfo
|
||||
? ItemGenerators.generateBaseItems(getPartyBaseInventoryContracts(partyInfo), modifierLookup, spellLookup, valueLookup, inventoryInfusionLookup, ruleData)
|
||||
: [];
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
import * as CampaignAccessors from './accessors';
|
||||
import * as CampaignConstants from './constants';
|
||||
import * as CampaignGenerators from './generators';
|
||||
import * as CampaignTypings from './typings';
|
||||
import * as CampaignUtils from './utils';
|
||||
export * from './typings';
|
||||
export * from './constants';
|
||||
export { CampaignAccessors, CampaignGenerators, CampaignUtils };
|
||||
export default Object.assign(Object.assign(Object.assign(Object.assign(Object.assign({}, CampaignConstants), CampaignAccessors), CampaignGenerators), CampaignTypings), CampaignUtils);
|
||||
@@ -0,0 +1,51 @@
|
||||
import { getCharacters } from './accessors';
|
||||
import { PartyInventorySharingStateEnum } from './constants';
|
||||
/**
|
||||
*
|
||||
* @param sharingState
|
||||
* @returns {Boolean}
|
||||
* @description Returns true as long as the sharing state is not OFF. WARNING: DELETE_ONLY overlaps with the inactive sharing state
|
||||
*/
|
||||
export function isSharingStateActive(sharingState) {
|
||||
return sharingState !== PartyInventorySharingStateEnum.OFF;
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param sharingState
|
||||
* @returns {Boolean}
|
||||
* @description Returns true as long as the sharing state is not ON. WARNING: DELETE_ONLY overlaps with the active sharing state
|
||||
*/
|
||||
export function isSharingStateInactive(sharingState) {
|
||||
return sharingState !== PartyInventorySharingStateEnum.ON;
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param campaign
|
||||
* @param characterId
|
||||
* @returns {CampaignDataContract | null}
|
||||
*/
|
||||
export function getCharacterById(campaign, characterId) {
|
||||
var _a, _b;
|
||||
return (_b = (_a = getCharacters(campaign)) === null || _a === void 0 ? void 0 : _a.find((character) => character.characterId === characterId)) !== null && _b !== void 0 ? _b : null;
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param campaign
|
||||
* @param characterId
|
||||
* @returns {string}
|
||||
*/
|
||||
export function getCharacterName(campaign, characterId) {
|
||||
var _a, _b;
|
||||
return (_b = (_a = getCharacterById(campaign, characterId)) === null || _a === void 0 ? void 0 : _a.characterName) !== null && _b !== void 0 ? _b : '';
|
||||
}
|
||||
/**
|
||||
* @description Given a character id, this determines whether or not that character in the campaign is assigned
|
||||
* to a player.
|
||||
* @param campaign
|
||||
* @param characterId
|
||||
* @returns {boolean}
|
||||
*/
|
||||
export function isCharacterAssignedToAPlayer(campaign, characterId) {
|
||||
var _a;
|
||||
return !!((_a = getCharacterById(campaign, characterId)) === null || _a === void 0 ? void 0 : _a.isAssigned);
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
export function getEnabledSourceIds(campaignSetting) {
|
||||
return campaignSetting.enabledSourceIds;
|
||||
}
|
||||
export function getAvailableSourceIds(campaignSetting) {
|
||||
var _a;
|
||||
return (_a = campaignSetting === null || campaignSetting === void 0 ? void 0 : campaignSetting.availableSources) === null || _a === void 0 ? void 0 : _a.map((s) => s.sourceId);
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
import * as CampaignSettingAccessors from './accessors';
|
||||
export { CampaignSettingAccessors };
|
||||
export default Object.assign({}, CampaignSettingAccessors);
|
||||
@@ -0,0 +1,18 @@
|
||||
export var ArmorClassTypeEnum;
|
||||
(function (ArmorClassTypeEnum) {
|
||||
ArmorClassTypeEnum["ARMOR"] = "Armor";
|
||||
ArmorClassTypeEnum["SHIELD"] = "Shield";
|
||||
ArmorClassTypeEnum["DEX_BONUS"] = "Dexterity Bonus";
|
||||
ArmorClassTypeEnum["MAGIC_BONUS"] = "Magic Bonus";
|
||||
ArmorClassTypeEnum["MISC_BONUS"] = "Misc Bonus";
|
||||
ArmorClassTypeEnum["UNARMORED_BONUS"] = "Unarmored Bonus";
|
||||
ArmorClassTypeEnum["ARMORED_BONUS"] = "Armored Bonus";
|
||||
ArmorClassTypeEnum["OVERRIDE_BASE_ARMOR"] = "Base Armor + DEX (Override)";
|
||||
})(ArmorClassTypeEnum || (ArmorClassTypeEnum = {}));
|
||||
export var ArmorClassExtraTypeEnum;
|
||||
(function (ArmorClassExtraTypeEnum) {
|
||||
ArmorClassExtraTypeEnum["MODIFIER"] = "MODIFIER";
|
||||
ArmorClassExtraTypeEnum["ITEM"] = "ITEM";
|
||||
ArmorClassExtraTypeEnum["STRING"] = "STRING";
|
||||
ArmorClassExtraTypeEnum["NUMBER"] = "NUMBER";
|
||||
})(ArmorClassExtraTypeEnum || (ArmorClassExtraTypeEnum = {}));
|
||||
@@ -0,0 +1,7 @@
|
||||
export var AttackSourceTypeEnum;
|
||||
(function (AttackSourceTypeEnum) {
|
||||
AttackSourceTypeEnum["ACTION"] = "ACTION";
|
||||
AttackSourceTypeEnum["ITEM"] = "ITEM";
|
||||
AttackSourceTypeEnum["SPELL"] = "SPELL";
|
||||
AttackSourceTypeEnum["CUSTOM"] = "CUSTOM";
|
||||
})(AttackSourceTypeEnum || (AttackSourceTypeEnum = {}));
|
||||
@@ -0,0 +1,6 @@
|
||||
export var DeathCauseEnum;
|
||||
(function (DeathCauseEnum) {
|
||||
DeathCauseEnum["NONE"] = "NONE";
|
||||
DeathCauseEnum["DEATHSAVES"] = "DEATHSAVES";
|
||||
DeathCauseEnum["CONDITION"] = "CONDITION";
|
||||
})(DeathCauseEnum || (DeathCauseEnum = {}));
|
||||
@@ -0,0 +1,14 @@
|
||||
export var ProtectionSupplierTypeEnum;
|
||||
(function (ProtectionSupplierTypeEnum) {
|
||||
ProtectionSupplierTypeEnum["RACIAL_TRAIT"] = "RACIAL_TRAIT";
|
||||
ProtectionSupplierTypeEnum["CLASS_FEATURE"] = "CLASS_FEATURE";
|
||||
ProtectionSupplierTypeEnum["FEAT"] = "FEAT";
|
||||
ProtectionSupplierTypeEnum["ITEM"] = "ITEM";
|
||||
})(ProtectionSupplierTypeEnum || (ProtectionSupplierTypeEnum = {}));
|
||||
export var ProtectionAvailabilityStatusEnum;
|
||||
(function (ProtectionAvailabilityStatusEnum) {
|
||||
ProtectionAvailabilityStatusEnum["AVAILABLE"] = "AVAILABLE";
|
||||
ProtectionAvailabilityStatusEnum["NO_LIMITED_USE_REMAINING"] = "NO_LIMITED_USE_REMAINING";
|
||||
ProtectionAvailabilityStatusEnum["ITEM_NOT_EQUIPPED"] = "ITEM_NOT_EQUIPPED";
|
||||
ProtectionAvailabilityStatusEnum["ITEM_NOT_ATTUNED"] = "ITEM_NOT_ATTUNED";
|
||||
})(ProtectionAvailabilityStatusEnum || (ProtectionAvailabilityStatusEnum = {}));
|
||||
@@ -0,0 +1,42 @@
|
||||
import { ActionAccessors } from '../../Action';
|
||||
import { ActivationAccessors } from '../../Activation';
|
||||
import { ActivatableTypeEnum } from '../../Core';
|
||||
import { OptionAccessors } from '../../Option';
|
||||
/**
|
||||
*
|
||||
* @param options
|
||||
* @param parentEntity
|
||||
*/
|
||||
export function deriveActivatableOptions(options, parentEntity) {
|
||||
const activatables = [];
|
||||
options.forEach((option) => {
|
||||
const actions = OptionAccessors.getActions(option);
|
||||
if (actions.length) {
|
||||
activatables.push(...deriveActivatableActions(actions, parentEntity));
|
||||
}
|
||||
});
|
||||
return activatables;
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param actions
|
||||
* @param parentEntity
|
||||
*/
|
||||
export function deriveActivatableActions(actions, parentEntity) {
|
||||
const activatables = [];
|
||||
actions.forEach((action) => {
|
||||
const activation = ActionAccessors.getActivation(action);
|
||||
if (activation !== null && ActivationAccessors.getType(activation) !== null) {
|
||||
activatables.push({
|
||||
type: ActivatableTypeEnum.ACTION,
|
||||
sortText: ActionAccessors.getName(action),
|
||||
activation,
|
||||
key: ActionAccessors.getUniqueKey(action),
|
||||
limitedUse: ActionAccessors.getLimitedUse(action),
|
||||
entity: action,
|
||||
parentEntity,
|
||||
});
|
||||
}
|
||||
});
|
||||
return activatables;
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
/**
|
||||
*
|
||||
* @param armorClassSources
|
||||
* @param initialValue
|
||||
*/
|
||||
export function deriveArmorClassSupplierTotal(armorClassSources, initialValue = 0) {
|
||||
return armorClassSources.reduce((acc, armorClassSource) => {
|
||||
if (armorClassSource.amount) {
|
||||
acc += armorClassSource.amount;
|
||||
}
|
||||
return acc;
|
||||
}, initialValue);
|
||||
}
|
||||
@@ -0,0 +1,45 @@
|
||||
import { AbilityAccessors } from '../../Ability';
|
||||
import { ModifierDerivers, ModifierValidators } from '../../Modifier';
|
||||
/**
|
||||
*
|
||||
* @param proficiencyBonus
|
||||
* @param abilityModifier
|
||||
*/
|
||||
export function deriveAttackSaveValue(proficiencyBonus, abilityModifier) {
|
||||
return 8 + proficiencyBonus + abilityModifier;
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param proficiencyBonus
|
||||
* @param abilityModifier
|
||||
*/
|
||||
export function deriveAttackModifier(proficiencyBonus, abilityModifier) {
|
||||
return proficiencyBonus + abilityModifier;
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param availableAbilities
|
||||
* @param modifiers
|
||||
* @param proficiencyBonus
|
||||
* @param abilityLookup
|
||||
*/
|
||||
export function deriveAttackAbilityPossibilities(availableAbilities, modifiers, proficiencyBonus, abilityLookup) {
|
||||
return availableAbilities.map((abilityId) => {
|
||||
const ability = abilityLookup[abilityId];
|
||||
// get bonus stat attack modifiers
|
||||
const bonusStatToHitModifiers = modifiers.filter((modifier) => ModifierValidators.isValidBonusStatAttackModifier(modifier, abilityId));
|
||||
const bonusStatToHitModifierTotal = ModifierDerivers.sumModifiers(bonusStatToHitModifiers, abilityLookup);
|
||||
// get damage stat attack modifiers
|
||||
const damageStatAttackModifiers = modifiers.filter((modifier) => ModifierValidators.isValidDamageStatAttackModifier(modifier, abilityId));
|
||||
const damageStatAttackModifierTotal = ModifierDerivers.sumModifiers(damageStatAttackModifiers, abilityLookup);
|
||||
const abilityModifier = ability ? AbilityAccessors.getModifier(ability) : null;
|
||||
const modifier = abilityModifier ? abilityModifier : 0;
|
||||
const toHit = modifier + proficiencyBonus + bonusStatToHitModifierTotal;
|
||||
return {
|
||||
abilityId,
|
||||
toHit,
|
||||
modifier,
|
||||
damageBonus: damageStatAttackModifierTotal + modifier,
|
||||
};
|
||||
});
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
import { DiceAdjustmentTypeEnum } from '../../Dice';
|
||||
import { ModifierDerivers, ModifierValidators } from '../../Modifier';
|
||||
/**
|
||||
*
|
||||
* @param modifiers
|
||||
*/
|
||||
export function deriveAdvantageDeathSavesAdjustments(modifiers) {
|
||||
return modifiers
|
||||
.filter((modifier) => ModifierValidators.isAdvantageDeathSavesModifier(modifier))
|
||||
.map((modifier) => ModifierDerivers.deriveDiceAdjustment(modifier, DiceAdjustmentTypeEnum.ADVANTAGE));
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param modifiers
|
||||
*/
|
||||
export function deriveDisadvantageDeathSavesAdjustments(modifiers) {
|
||||
return modifiers
|
||||
.filter((modifier) => ModifierValidators.isDisadvantageDeathSavesModifier(modifier))
|
||||
.map((modifier) => ModifierDerivers.deriveDiceAdjustment(modifier, DiceAdjustmentTypeEnum.DISADVANTAGE));
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
import { DataOriginGenerators, DataOriginTypeEnum } from '../../DataOrigin';
|
||||
/**
|
||||
*
|
||||
* @param adjustment
|
||||
*/
|
||||
export function deriveCustomDefenseAdjustmentDataOrigin(adjustment) {
|
||||
return DataOriginGenerators.generateDataOrigin(DataOriginTypeEnum.CUSTOM, adjustment.source ? adjustment.source : 'Custom');
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param adjustment
|
||||
*/
|
||||
export function deriveCustomConditionDefenseAdjustmentDataOrigin(adjustment) {
|
||||
return DataOriginGenerators.generateDataOrigin(DataOriginTypeEnum.CUSTOM, adjustment.source ? adjustment.source : 'Custom');
|
||||
}
|
||||
@@ -0,0 +1,43 @@
|
||||
import { ItemAccessors, ItemValidators } from '../../Item';
|
||||
import { LimitedUseDerivers } from '../../LimitedUse';
|
||||
import { ModifierAccessors } from '../../Modifier';
|
||||
import { ProtectionAvailabilityStatusEnum } from '../constants';
|
||||
/**
|
||||
*
|
||||
* @param limitedUse
|
||||
* @param abilityLookup
|
||||
* @param ruleData
|
||||
* @param proficiencyBonus
|
||||
*/
|
||||
export function deriveProtectionSupplierAvailabilityStatus(limitedUse, abilityLookup, ruleData, proficiencyBonus) {
|
||||
let availabilityStatus = ProtectionAvailabilityStatusEnum.AVAILABLE;
|
||||
if (!LimitedUseDerivers.deriveHasUsesAvailable(limitedUse, abilityLookup, ruleData, proficiencyBonus)) {
|
||||
availabilityStatus = ProtectionAvailabilityStatusEnum.NO_LIMITED_USE_REMAINING;
|
||||
}
|
||||
return availabilityStatus;
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param item
|
||||
* @param modifier
|
||||
* @param limitedUse
|
||||
* @param abilityLookup
|
||||
* @param ruleData
|
||||
* @param proficiencyBonus
|
||||
* @param characterId
|
||||
*/
|
||||
export function deriveItemProtectionSupplierAvailabilityStatus(item, modifier, limitedUse, abilityLookup, ruleData, proficiencyBonus, characterId) {
|
||||
if (ItemAccessors.canEquip(item)) {
|
||||
const isEquippedToCurrentCharacter = ItemValidators.isEquippedToCurrentCharacter(item, characterId);
|
||||
if (!isEquippedToCurrentCharacter) {
|
||||
return ProtectionAvailabilityStatusEnum.ITEM_NOT_EQUIPPED;
|
||||
}
|
||||
if (ModifierAccessors.requiresAttunement(modifier) && !ItemAccessors.isAttuned(item)) {
|
||||
return ProtectionAvailabilityStatusEnum.ITEM_NOT_ATTUNED;
|
||||
}
|
||||
}
|
||||
if (!LimitedUseDerivers.deriveHasUsesAvailable(limitedUse, abilityLookup, ruleData, proficiencyBonus)) {
|
||||
return ProtectionAvailabilityStatusEnum.NO_LIMITED_USE_REMAINING;
|
||||
}
|
||||
return ProtectionAvailabilityStatusEnum.AVAILABLE;
|
||||
}
|
||||
@@ -0,0 +1,43 @@
|
||||
import { ProficiencyLevelEnum, ProficiencyRoundingEnum } from '../../Core';
|
||||
import { ModifierDerivers, ModifierValidators } from '../../Modifier';
|
||||
import { RuleDataUtils } from '../../RuleData';
|
||||
/**
|
||||
*
|
||||
* @param level
|
||||
* @param modifiers
|
||||
* @param ruleData
|
||||
*/
|
||||
export function deriveProficiencyBonus(level, modifiers, ruleData) {
|
||||
const levelBonus = RuleDataUtils.getLevelProficiencyBonus(level, ruleData);
|
||||
const bonusProficiencyBonusModifiers = modifiers.filter((modifier) => ModifierValidators.isBonusProficiencyBonusModifier(modifier));
|
||||
const modifierBonusTotal = ModifierDerivers.sumModifiers(bonusProficiencyBonusModifiers);
|
||||
return levelBonus + modifierBonusTotal;
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param proficiencyLevel
|
||||
* @param proficiencyBonus
|
||||
* @param proficiencyRounding
|
||||
*/
|
||||
export function deriveProficiencyBonusAmount(proficiencyLevel, proficiencyBonus, proficiencyRounding = ProficiencyRoundingEnum.DOWN) {
|
||||
let proficiencyBonusAmount = 0;
|
||||
switch (proficiencyLevel) {
|
||||
case ProficiencyLevelEnum.EXPERT:
|
||||
proficiencyBonusAmount = proficiencyBonus * 2;
|
||||
break;
|
||||
case ProficiencyLevelEnum.FULL:
|
||||
proficiencyBonusAmount = proficiencyBonus;
|
||||
break;
|
||||
case ProficiencyLevelEnum.HALF:
|
||||
if (proficiencyRounding === ProficiencyRoundingEnum.UP) {
|
||||
proficiencyBonusAmount = Math.ceil(proficiencyBonus / 2);
|
||||
}
|
||||
else {
|
||||
proficiencyBonusAmount = Math.floor(proficiencyBonus / 2);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
// not implemented
|
||||
}
|
||||
return proficiencyBonusAmount;
|
||||
}
|
||||
@@ -0,0 +1,48 @@
|
||||
import { RuleDataAccessors } from '../../RuleData';
|
||||
/**
|
||||
*
|
||||
* @param xp
|
||||
* @param ruleData
|
||||
*/
|
||||
export function deriveXpLevel(xp, ruleData) {
|
||||
let level = 0;
|
||||
if (xp === 0) {
|
||||
return 1;
|
||||
}
|
||||
if (xp >= deriveMaxXp(ruleData)) {
|
||||
return RuleDataAccessors.getMaxCharacterLevel(ruleData);
|
||||
}
|
||||
const levelExperiencePoints = RuleDataAccessors.getLevelExperiencePoints(ruleData);
|
||||
levelExperiencePoints.forEach((levelXpAmount, levelIdx) => {
|
||||
if (level === 0 && xp < levelXpAmount) {
|
||||
level = levelIdx;
|
||||
}
|
||||
});
|
||||
return level;
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param level
|
||||
* @param ruleData
|
||||
*/
|
||||
export function deriveCurrentLevelXp(level, ruleData) {
|
||||
const levelExperiencePoints = RuleDataAccessors.getLevelExperiencePoints(ruleData);
|
||||
return levelExperiencePoints[Math.max(0, level - 1)];
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param level
|
||||
* @param ruleData
|
||||
*/
|
||||
export function deriveNextLevelXp(level, ruleData) {
|
||||
const levelExperiencePoints = RuleDataAccessors.getLevelExperiencePoints(ruleData);
|
||||
return levelExperiencePoints[Math.min(levelExperiencePoints.length - 1, level)];
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param ruleData
|
||||
*/
|
||||
export function deriveMaxXp(ruleData) {
|
||||
const levelExperiencePoints = RuleDataAccessors.getLevelExperiencePoints(ruleData);
|
||||
return levelExperiencePoints[levelExperiencePoints.length - 1];
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
import { SaveTypeEnum } from '../../Core';
|
||||
/**
|
||||
*
|
||||
* @param type
|
||||
*/
|
||||
export function deriveSaveTypeName(type) {
|
||||
let name = '';
|
||||
switch (type) {
|
||||
case SaveTypeEnum.ADVANTAGE:
|
||||
name = 'Advantage';
|
||||
break;
|
||||
case SaveTypeEnum.DISADVANTAGE:
|
||||
name = 'Disadvantage';
|
||||
break;
|
||||
case SaveTypeEnum.BONUS:
|
||||
name = 'Bonus';
|
||||
break;
|
||||
default:
|
||||
//not implemented
|
||||
}
|
||||
return name;
|
||||
}
|
||||
@@ -0,0 +1,59 @@
|
||||
import { AbilitySkillEnum } from '../../Core';
|
||||
import { ModifierDerivers, ModifierValidators } from '../../Modifier';
|
||||
import { SkillAccessors } from '../../Skill';
|
||||
/**
|
||||
*
|
||||
* @param skillModifier
|
||||
* @param bonuses
|
||||
*/
|
||||
export function derivePassiveSkill(skillModifier, bonuses = 0) {
|
||||
return 10 + skillModifier + bonuses;
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param skills
|
||||
* @param modifiers
|
||||
* @param abilityLookup
|
||||
*/
|
||||
export function derivePassivePerception(skills, modifiers, abilityLookup) {
|
||||
const skill = skills.find((skill) => SkillAccessors.getId(skill) === AbilitySkillEnum.PERCEPTION);
|
||||
const skillModifier = skill ? SkillAccessors.getModifier(skill) : null;
|
||||
if (!skill || skillModifier === null) {
|
||||
return 0;
|
||||
}
|
||||
const bonusModifiers = modifiers.filter((modifier) => ModifierValidators.isBonusPassivePerceptionModifier(modifier));
|
||||
const bonusModifierTotal = ModifierDerivers.sumModifiers(bonusModifiers, abilityLookup);
|
||||
return derivePassiveSkill(skillModifier, bonusModifierTotal);
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param skills
|
||||
* @param modifiers
|
||||
* @param abilityLookup
|
||||
*/
|
||||
export function derivePassiveInvestigation(skills, modifiers, abilityLookup) {
|
||||
const skill = skills.find((skill) => SkillAccessors.getId(skill) === AbilitySkillEnum.INVESTIGATION);
|
||||
const skillModifier = skill ? SkillAccessors.getModifier(skill) : null;
|
||||
if (!skill || skillModifier === null) {
|
||||
return 0;
|
||||
}
|
||||
const bonusModifiers = modifiers.filter((modifier) => ModifierValidators.isBonusPassiveInvestigationModifier(modifier));
|
||||
const bonusModifierTotal = ModifierDerivers.sumModifiers(bonusModifiers, abilityLookup);
|
||||
return derivePassiveSkill(skillModifier, bonusModifierTotal);
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param skills
|
||||
* @param modifiers
|
||||
* @param abilityLookup
|
||||
*/
|
||||
export function derivePassiveInsight(skills, modifiers, abilityLookup) {
|
||||
const skill = skills.find((skill) => SkillAccessors.getId(skill) === AbilitySkillEnum.INSIGHT);
|
||||
const skillModifier = skill ? SkillAccessors.getModifier(skill) : null;
|
||||
if (!skill || skillModifier === null) {
|
||||
return 0;
|
||||
}
|
||||
const bonusModifiers = modifiers.filter((modifier) => ModifierValidators.isBonusPassiveInsightModifier(modifier));
|
||||
const bonusModifierTotal = ModifierDerivers.sumModifiers(bonusModifiers, abilityLookup);
|
||||
return derivePassiveSkill(skillModifier, bonusModifierTotal);
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
import { PreferenceEncumbranceTypeEnum, WeightSpeedTypeEnum } from '../../Core';
|
||||
import { getCarryCapacity, getEncumberedWeight, getHeavilyEncumberedWeight } from '../utils';
|
||||
/**
|
||||
*
|
||||
* @param currentWeight
|
||||
* @param strScore
|
||||
* @param size
|
||||
* @param preferences
|
||||
* @param modifiers
|
||||
*/
|
||||
export function deriveCurrentWeightSpeedType(currentWeight, strScore, size, preferences, modifiers) {
|
||||
if (preferences !== null) {
|
||||
if (preferences.encumbranceType === PreferenceEncumbranceTypeEnum.VARIANT) {
|
||||
if (currentWeight > getHeavilyEncumberedWeight(strScore, size, modifiers)) {
|
||||
return WeightSpeedTypeEnum.HEAVILY_ENCUMBERED;
|
||||
}
|
||||
else if (currentWeight > getEncumberedWeight(strScore, size, modifiers)) {
|
||||
return WeightSpeedTypeEnum.ENCUMBERED;
|
||||
}
|
||||
}
|
||||
else if (preferences.encumbranceType === PreferenceEncumbranceTypeEnum.ENCUMBRANCE) {
|
||||
if (currentWeight > getCarryCapacity(strScore, size, modifiers)) {
|
||||
return WeightSpeedTypeEnum.OVER_CARRYING_CAPACITY;
|
||||
}
|
||||
}
|
||||
}
|
||||
return WeightSpeedTypeEnum.NORMAL;
|
||||
}
|
||||
@@ -0,0 +1,122 @@
|
||||
import { orderBy } from 'lodash';
|
||||
import { ActionAccessors } from '../../Action';
|
||||
import { ActivationAccessors } from '../../Activation';
|
||||
import { ClassAccessors } from '../../Class';
|
||||
import { ClassFeatureAccessors } from '../../ClassFeature';
|
||||
import { ActivatableTypeEnum } from '../../Core';
|
||||
import { FeatAccessors } from '../../Feat';
|
||||
import { ItemAccessors, ItemValidators } from '../../Item';
|
||||
import { RaceAccessors } from '../../Race';
|
||||
import { RacialTraitAccessors } from '../../RacialTrait';
|
||||
import { SpellAccessors } from '../../Spell';
|
||||
import { deriveActivatableActions, deriveActivatableOptions } from '../derivers';
|
||||
/**
|
||||
*
|
||||
* @param characterSpells
|
||||
* @param classSpells
|
||||
* @param classes
|
||||
* @param race
|
||||
* @param feats
|
||||
* @param innateActions
|
||||
* @param customActions
|
||||
* @param equippedItems
|
||||
*/
|
||||
export function generateActivatables(characterSpells, classSpells, classes, race, feats, innateActions, // TODO might need to change to InnateAction
|
||||
customActions, // TODO might need to change to CustomAction
|
||||
equippedItems) {
|
||||
const activatables = [];
|
||||
characterSpells.forEach((spell) => {
|
||||
const activation = SpellAccessors.getActivation(spell);
|
||||
if (activation !== null && ActivationAccessors.getType(activation) !== null) {
|
||||
activatables.push({
|
||||
type: ActivatableTypeEnum.CHARACTER_SPELL,
|
||||
sortText: SpellAccessors.getName(spell),
|
||||
key: SpellAccessors.getUniqueKey(spell),
|
||||
activation,
|
||||
limitedUse: SpellAccessors.getLimitedUse(spell),
|
||||
entity: spell,
|
||||
parentEntity: null,
|
||||
});
|
||||
}
|
||||
});
|
||||
classSpells.forEach((spell) => {
|
||||
const activation = SpellAccessors.getActivation(spell);
|
||||
if (activation !== null && ActivationAccessors.getType(activation) !== null) {
|
||||
activatables.push({
|
||||
type: ActivatableTypeEnum.CLASS_SPELL,
|
||||
sortText: SpellAccessors.getName(spell),
|
||||
key: SpellAccessors.getUniqueKey(spell),
|
||||
activation,
|
||||
limitedUse: null,
|
||||
entity: spell,
|
||||
parentEntity: null,
|
||||
});
|
||||
}
|
||||
});
|
||||
classes.forEach((charClass) => {
|
||||
ClassAccessors.getUniqueClassFeatures(charClass).forEach((feature) => {
|
||||
const actions = ClassFeatureAccessors.getActions(feature);
|
||||
const options = ClassFeatureAccessors.getOptions(feature);
|
||||
if (actions.length) {
|
||||
activatables.push(...deriveActivatableActions(actions, charClass));
|
||||
}
|
||||
if (options.length) {
|
||||
activatables.push(...deriveActivatableOptions(options, charClass));
|
||||
}
|
||||
});
|
||||
});
|
||||
if (race) {
|
||||
RaceAccessors.getRacialTraits(race).forEach((racialTrait) => {
|
||||
const actions = RacialTraitAccessors.getActions(racialTrait);
|
||||
const options = RacialTraitAccessors.getOptions(racialTrait);
|
||||
if (actions.length) {
|
||||
activatables.push(...deriveActivatableActions(actions, race));
|
||||
}
|
||||
if (options.length) {
|
||||
activatables.push(...deriveActivatableOptions(options, race));
|
||||
}
|
||||
});
|
||||
}
|
||||
feats.forEach((feat) => {
|
||||
const actions = FeatAccessors.getActions(feat);
|
||||
const options = FeatAccessors.getOptions(feat);
|
||||
if (actions.length) {
|
||||
activatables.push(...deriveActivatableActions(actions, race));
|
||||
}
|
||||
if (options.length) {
|
||||
activatables.push(...deriveActivatableOptions(options, race));
|
||||
}
|
||||
});
|
||||
innateActions.forEach((action) => {
|
||||
const activation = ActionAccessors.getActivation(action);
|
||||
if (activation !== null) {
|
||||
activatables.push({
|
||||
type: ActivatableTypeEnum.ACTION,
|
||||
sortText: ActionAccessors.getName(action),
|
||||
activation,
|
||||
key: ActionAccessors.getUniqueKey(action),
|
||||
limitedUse: null,
|
||||
entity: action,
|
||||
parentEntity: null,
|
||||
});
|
||||
}
|
||||
});
|
||||
customActions.forEach((action) => {
|
||||
const activation = ActionAccessors.getActivation(action);
|
||||
if (activation !== null && ActivationAccessors.getType(activation) !== null) {
|
||||
activatables.push({
|
||||
type: ActivatableTypeEnum.ACTION,
|
||||
sortText: ActionAccessors.getName(action),
|
||||
activation,
|
||||
key: ActionAccessors.getUniqueKey(action),
|
||||
limitedUse: null,
|
||||
entity: action,
|
||||
parentEntity: null,
|
||||
});
|
||||
}
|
||||
});
|
||||
equippedItems.filter(ItemValidators.validateCanContributeActions).forEach((item) => {
|
||||
activatables.push(...deriveActivatableActions(ItemAccessors.getInfusionActions(item), item));
|
||||
});
|
||||
return orderBy(activatables, ['sortText']);
|
||||
}
|
||||
@@ -0,0 +1,294 @@
|
||||
import { forOwn, groupBy } from 'lodash';
|
||||
import { AbilityAccessors } from '../../Ability';
|
||||
import { AbilityStatEnum } from '../../Core';
|
||||
import { DataOriginTypeEnum } from '../../DataOrigin';
|
||||
import { HelperUtils } from '../../Helper';
|
||||
import { ArmorTypeEnum, ItemAccessors, ItemDerivers, ItemHacks, ItemValidators, } from '../../Item';
|
||||
import { ModifierAccessors, ModifierDerivers, ModifierGenerators, ModifierHacks, ModifierValidators, } from '../../Modifier';
|
||||
import { AdjustmentTypeEnum, ValueAccessors, ValueUtils } from '../../Value';
|
||||
import { ArmorClassExtraTypeEnum, ArmorClassTypeEnum } from '../constants';
|
||||
import { deriveArmorClassSupplierTotal } from '../derivers';
|
||||
/**
|
||||
*
|
||||
* @param type
|
||||
* @param amount
|
||||
* @param extra
|
||||
* @param extraType
|
||||
*/
|
||||
export function generateArmorClassSupplier(type, amount, extra = null, extraType = null) {
|
||||
return {
|
||||
type,
|
||||
amount,
|
||||
extra,
|
||||
extraType,
|
||||
};
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param armorItem
|
||||
* @param localModifiers
|
||||
* @param globalModifiers
|
||||
* @param abilityLookup
|
||||
* @param valueLookup
|
||||
* @param modifierData
|
||||
*/
|
||||
export function generateArmoredBaseArmorSuppliers(armorItem, localModifiers, globalModifiers, abilityLookup, valueLookup, modifierData) {
|
||||
const dexModifier = AbilityAccessors.getModifier(abilityLookup[AbilityStatEnum.DEXTERITY]);
|
||||
const baseArmorOverrideValue = ValueUtils.getKeyValue(valueLookup, AdjustmentTypeEnum.OVERRIDE_BASE_ARMOR);
|
||||
const suppliers = [];
|
||||
if (baseArmorOverrideValue === null) {
|
||||
suppliers.push(generateArmorClassSupplier(ArmorClassTypeEnum.ARMOR, armorItem.armorClass, armorItem.item, ArmorClassExtraTypeEnum.ITEM));
|
||||
suppliers.push(generateArmorClassSupplier(ArmorClassTypeEnum.DEX_BONUS, ItemDerivers.deriveArmorDexBonus(armorItem.item, dexModifier ? dexModifier : 0, globalModifiers, abilityLookup), ItemDerivers.deriveArmorDexBonusMax(armorItem.item, globalModifiers, abilityLookup), ArmorClassExtraTypeEnum.NUMBER));
|
||||
}
|
||||
const setArmoredModifiers = localModifiers.filter((modifier) => ModifierValidators.isSetArmoredArmorClassModifier(modifier));
|
||||
const setArmoredHighestModifier = ModifierDerivers.deriveHighestValueModifier(setArmoredModifiers, modifierData);
|
||||
if (setArmoredHighestModifier) {
|
||||
suppliers.push(generateArmorClassSupplier(ArmorClassTypeEnum.ARMORED_BONUS, ModifierDerivers.deriveValue(setArmoredHighestModifier, modifierData), setArmoredHighestModifier, ArmorClassExtraTypeEnum.MODIFIER));
|
||||
}
|
||||
const bonusArmoredModifiers = globalModifiers.filter((modifier) => ModifierValidators.isBonusArmoredArmorClassModifier(modifier));
|
||||
bonusArmoredModifiers.forEach((modifier) => {
|
||||
suppliers.push(generateArmorClassSupplier(ArmorClassTypeEnum.ARMORED_BONUS, ModifierDerivers.deriveValue(modifier, modifierData), modifier, ArmorClassExtraTypeEnum.MODIFIER));
|
||||
});
|
||||
return suppliers;
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param localModifiers
|
||||
* @param globalModifiers
|
||||
* @param abilityLookup
|
||||
* @param valueLookup
|
||||
* @param ruleData
|
||||
* @param modifierData
|
||||
*/
|
||||
export function generateUnarmoredBaseArmorSuppliers(localModifiers, globalModifiers, abilityLookup, valueLookup, ruleData, modifierData) {
|
||||
const baseArmorOverrideValue = ValueUtils.getKeyValue(valueLookup, AdjustmentTypeEnum.OVERRIDE_BASE_ARMOR);
|
||||
const suppliers = [];
|
||||
if (baseArmorOverrideValue === null) {
|
||||
suppliers.push(generateArmorClassSupplier(ArmorClassTypeEnum.ARMOR, ruleData.noArmorAcAmount, 'None', ArmorClassExtraTypeEnum.STRING));
|
||||
const unarmoredDexModifier = ItemDerivers.deriveUnarmoredDexBonus(localModifiers, globalModifiers, abilityLookup);
|
||||
if (unarmoredDexModifier !== 0) {
|
||||
suppliers.push(generateArmorClassSupplier(ArmorClassTypeEnum.DEX_BONUS, unarmoredDexModifier, ItemDerivers.deriveUnarmoredDexBonusMax(globalModifiers), ArmorClassExtraTypeEnum.NUMBER));
|
||||
}
|
||||
}
|
||||
const setUnarmoredModifiers = localModifiers.filter((modifier) => ModifierValidators.isSetUnarmoredArmorClassModifier(modifier));
|
||||
// TODO: Fix Dirty Hack for Integrated Protection
|
||||
const hasLightArmorProficiency = globalModifiers.filter((modifier) => ModifierHacks.hack__isProficiencyLightArmor(modifier)).length > 0;
|
||||
if (setUnarmoredModifiers.length) {
|
||||
// let setUnarmoredHighestModifier = ModifierUtils.getHighestValueModifier(setUnarmoredModifiers, modifierData);
|
||||
const setUnarmoredHighestModifier = HelperUtils.getLast(setUnarmoredModifiers, (modifier) => ItemHacks.hack__getSetUnarmoredModifierValue(modifier, modifierData, hasLightArmorProficiency));
|
||||
if (setUnarmoredHighestModifier) {
|
||||
suppliers.push(generateArmorClassSupplier(ArmorClassTypeEnum.UNARMORED_BONUS, ItemHacks.hack__getSetUnarmoredModifierValue(setUnarmoredHighestModifier, modifierData, hasLightArmorProficiency), setUnarmoredHighestModifier, ArmorClassExtraTypeEnum.MODIFIER));
|
||||
}
|
||||
}
|
||||
const bonusUnarmoredModifiers = globalModifiers.filter((modifier) => ModifierValidators.isBonusUnarmoredArmorClassModifier(modifier));
|
||||
bonusUnarmoredModifiers.forEach((modifier) => {
|
||||
suppliers.push(generateArmorClassSupplier(ArmorClassTypeEnum.UNARMORED_BONUS, ModifierDerivers.deriveValue(modifier, modifierData), modifier, ArmorClassExtraTypeEnum.MODIFIER));
|
||||
});
|
||||
return suppliers;
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param armorItem
|
||||
* @param modifiers
|
||||
* @param abilityLookup
|
||||
* @param valueLookup
|
||||
* @param ruleData
|
||||
* @param modifierData
|
||||
*/
|
||||
export function generateBaseArmorSuppliers(armorItem, modifiers, abilityLookup, valueLookup, ruleData, modifierData) {
|
||||
const branchPossibilities = [];
|
||||
const branchingModifiers = modifiers.filter((modifier) => ModifierValidators.isArmorBranchingModifier(modifier));
|
||||
const groupedBranchModifiers = groupBy(branchingModifiers, (modifier) => ModifierGenerators.generateDataOriginKey(modifier));
|
||||
forOwn(groupedBranchModifiers, (branchGroupModifiers) => {
|
||||
const ignoreUnarmoredWhileArmoredModifiers = branchGroupModifiers.filter((modifier) => ModifierValidators.isIgnoreUnarmoredWhileArmoredModifier(modifier));
|
||||
const ignoreUnarmoredWhileArmored = !!ignoreUnarmoredWhileArmoredModifiers.length;
|
||||
if (armorItem) {
|
||||
branchPossibilities.push(generateBaseArmorBranchPossibility(armorItem, branchGroupModifiers, modifiers, abilityLookup, valueLookup, ruleData, modifierData));
|
||||
if (!ignoreUnarmoredWhileArmored) {
|
||||
branchPossibilities.push(generateBaseArmorBranchPossibility(null, branchGroupModifiers, modifiers, abilityLookup, valueLookup, ruleData, modifierData));
|
||||
}
|
||||
}
|
||||
else {
|
||||
branchPossibilities.push(generateBaseArmorBranchPossibility(null, branchGroupModifiers, modifiers, abilityLookup, valueLookup, ruleData, modifierData));
|
||||
}
|
||||
});
|
||||
// innate armor calc
|
||||
branchPossibilities.push(generateBaseArmorBranchPossibility(armorItem, [], modifiers, abilityLookup, valueLookup, ruleData, modifierData));
|
||||
const bestBaseArmorBranchPossibility = HelperUtils.getLast(branchPossibilities, (possibility) => possibility.total);
|
||||
if (bestBaseArmorBranchPossibility === null) {
|
||||
return [];
|
||||
}
|
||||
return bestBaseArmorBranchPossibility.suppliers;
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param mainhandWeapons
|
||||
* @param offhandWeapons
|
||||
* @param modifiers
|
||||
* @param modifierData
|
||||
*/
|
||||
export function generateDualWieldArmorClassSuppliers(mainhandWeapons, offhandWeapons, modifiers, modifierData) {
|
||||
const armorClassSuppliers = [];
|
||||
const bonusDualWieldAcModifiers = modifiers.filter((modifier) => ModifierValidators.isBonusDualWieldAcModifier(modifier));
|
||||
if (bonusDualWieldAcModifiers.length && mainhandWeapons.length && offhandWeapons.length) {
|
||||
bonusDualWieldAcModifiers.forEach((modifier) => {
|
||||
armorClassSuppliers.push(generateArmorClassSupplier(ArmorClassTypeEnum.MISC_BONUS, ModifierDerivers.deriveValue(modifier, modifierData), modifier, ArmorClassExtraTypeEnum.MODIFIER));
|
||||
});
|
||||
}
|
||||
return armorClassSuppliers;
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param armorItem
|
||||
* @param shieldItem
|
||||
* @param modifiers
|
||||
* @param abilityLookup
|
||||
* @param equippedItems
|
||||
* @param valueLookup
|
||||
* @param ruleData
|
||||
* @param modifierData
|
||||
*/
|
||||
export function generateArmorClassSuppliers(armorItem, shieldItem, modifiers, abilityLookup, equippedItems, valueLookup, ruleData, modifierData) {
|
||||
const armorClassSuppliers = [];
|
||||
// base armor AC sources based on potential branching paths
|
||||
const baseArmorSuppliers = generateBaseArmorSuppliers(armorItem, modifiers, abilityLookup, valueLookup, ruleData, modifierData);
|
||||
armorClassSuppliers.push(...baseArmorSuppliers);
|
||||
// TODO part of dirty hack
|
||||
const isWearingHeavyArmor = armorItem
|
||||
? ItemAccessors.getArmorTypeId(armorItem.item) === ArmorTypeEnum.HEAVY_ARMOR
|
||||
: false;
|
||||
// general AC bonuses (for both unarmored and armored)
|
||||
const armorModifiers = modifiers.filter((modifier) => ModifierValidators.isBonusArmorModifier(modifier));
|
||||
armorModifiers.forEach((modifier) => {
|
||||
const dataOrigin = ModifierAccessors.getDataOrigin(modifier);
|
||||
const dataOriginType = ModifierAccessors.getDataOriginType(modifier);
|
||||
let type = ArmorClassTypeEnum.MISC_BONUS;
|
||||
if (dataOriginType === DataOriginTypeEnum.ITEM) {
|
||||
// TODO This may cause issues with magic infusions, but should be minor and can be fixed when we do overhaul of accessing DataOrigin entities
|
||||
type = ItemAccessors.getDefinitionMagic(dataOrigin.primary)
|
||||
? ArmorClassTypeEnum.MAGIC_BONUS
|
||||
: ArmorClassTypeEnum.MISC_BONUS;
|
||||
}
|
||||
// TODO part of dirty hack
|
||||
const value = ItemHacks.hack__deriveBonusArmorModifierValue(modifier, modifierData, isWearingHeavyArmor);
|
||||
armorClassSuppliers.push(generateArmorClassSupplier(type, value,
|
||||
// ModifierDerivers.deriveValue(modifier, modifierData),
|
||||
modifier, ArmorClassExtraTypeEnum.MODIFIER));
|
||||
});
|
||||
// misc overall bonuses
|
||||
const shieldArmorClass = shieldItem ? shieldItem.armorClass : 0;
|
||||
const mainhandWeapons = equippedItems.filter(ItemValidators.isEquippedMainhandWeapon);
|
||||
const offhandWeapons = equippedItems.filter(ItemValidators.isEquippedOffhandWeapon);
|
||||
const dualWieldArmorClassSuppliers = generateDualWieldArmorClassSuppliers(mainhandWeapons, offhandWeapons, modifiers, modifierData);
|
||||
const dualWieldArmorClassBonus = deriveArmorClassSupplierTotal(dualWieldArmorClassSuppliers);
|
||||
if (dualWieldArmorClassBonus > 0 && dualWieldArmorClassBonus > shieldArmorClass) {
|
||||
armorClassSuppliers.push(...dualWieldArmorClassSuppliers);
|
||||
}
|
||||
else {
|
||||
// best shield AC
|
||||
if (shieldItem) {
|
||||
armorClassSuppliers.push(generateArmorClassSupplier(ArmorClassTypeEnum.SHIELD, shieldItem.armorClass, shieldItem.item, ArmorClassExtraTypeEnum.ITEM));
|
||||
}
|
||||
}
|
||||
// overall magic bonus adjustment value
|
||||
const magicBonusAdjustment = ValueUtils.getData(valueLookup, AdjustmentTypeEnum.MAGIC_BONUS_AC);
|
||||
if (magicBonusAdjustment !== null) {
|
||||
armorClassSuppliers.push(generateArmorClassSupplier(ArmorClassTypeEnum.MAGIC_BONUS, ValueAccessors.getValue(magicBonusAdjustment), ValueAccessors.getNotes(magicBonusAdjustment), ArmorClassExtraTypeEnum.STRING));
|
||||
}
|
||||
// overall misc bonus adjustment value
|
||||
const miscBonusAdjustment = ValueUtils.getData(valueLookup, AdjustmentTypeEnum.MISC_BONUS_AC);
|
||||
if (miscBonusAdjustment !== null) {
|
||||
armorClassSuppliers.push(generateArmorClassSupplier(ArmorClassTypeEnum.MISC_BONUS, ValueAccessors.getValue(miscBonusAdjustment), ValueAccessors.getNotes(miscBonusAdjustment), ArmorClassExtraTypeEnum.STRING));
|
||||
}
|
||||
return armorClassSuppliers;
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param armorItem
|
||||
* @param localModifiers
|
||||
* @param globalModifiers
|
||||
* @param abilityLookup
|
||||
* @param valueLookup
|
||||
* @param ruleData
|
||||
* @param modifierData
|
||||
*/
|
||||
export function generateBaseArmorBranchPossibility(armorItem, localModifiers, globalModifiers, abilityLookup, valueLookup, ruleData, modifierData) {
|
||||
let suppliers = [];
|
||||
const baseArmorOverride = ValueUtils.getData(valueLookup, AdjustmentTypeEnum.OVERRIDE_BASE_ARMOR);
|
||||
if (baseArmorOverride !== null) {
|
||||
suppliers.push(generateArmorClassSupplier(ArmorClassTypeEnum.OVERRIDE_BASE_ARMOR, ValueAccessors.getValue(baseArmorOverride), ValueAccessors.getNotes(baseArmorOverride), ArmorClassExtraTypeEnum.STRING));
|
||||
}
|
||||
// basearmor + set highest + status bonuses
|
||||
// - set highest is all of the "set > (un)armored armor class" modifiers
|
||||
// - status bonuses are bonuses based on whether you are armored or unarmored
|
||||
if (armorItem) {
|
||||
suppliers.push(...generateArmoredBaseArmorSuppliers(armorItem, localModifiers, globalModifiers, abilityLookup, valueLookup, modifierData));
|
||||
}
|
||||
else {
|
||||
suppliers.push(...generateUnarmoredBaseArmorSuppliers(localModifiers, globalModifiers, abilityLookup, valueLookup, ruleData, modifierData));
|
||||
}
|
||||
const minimumBaseArmorModifiers = localModifiers.filter((modifier) => ModifierValidators.isSetMinimumBaseArmorModifier(modifier));
|
||||
if (minimumBaseArmorModifiers.length) {
|
||||
const minBaseArmorModifier = minimumBaseArmorModifiers[0];
|
||||
const setMinBaseArmorValue = ModifierDerivers.deriveValue(minBaseArmorModifier, modifierData);
|
||||
if (setMinBaseArmorValue > deriveArmorClassSupplierTotal(suppliers)) {
|
||||
suppliers = [
|
||||
generateArmorClassSupplier(ArmorClassTypeEnum.ARMOR, setMinBaseArmorValue, minBaseArmorModifier, ArmorClassExtraTypeEnum.MODIFIER),
|
||||
];
|
||||
}
|
||||
}
|
||||
return {
|
||||
total: deriveArmorClassSupplierTotal(suppliers),
|
||||
suppliers,
|
||||
};
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param equippedItems
|
||||
* @param dexModifier
|
||||
* @param modifiers
|
||||
* @param abilityLookup
|
||||
* @param ruleData
|
||||
*/
|
||||
export function generateHighestAcEquippedArmor(equippedItems, dexModifier, modifiers, abilityLookup, ruleData) {
|
||||
const equippedArmor = equippedItems.filter(ItemValidators.isEquippedNonShieldArmor);
|
||||
return ItemDerivers.deriveHighestArmorAcItem(equippedArmor, dexModifier, modifiers, abilityLookup, ruleData);
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param equippedItems
|
||||
* @param dexModifier
|
||||
* @param modifiers
|
||||
* @param abilityLookup
|
||||
* @param ruleData
|
||||
*/
|
||||
export function generateHighestAcEquippedShield(equippedItems, dexModifier, modifiers, abilityLookup, ruleData) {
|
||||
const equippedShields = equippedItems.filter(ItemValidators.isEquippedShield);
|
||||
return ItemDerivers.deriveHighestArmorAcItem(equippedShields, dexModifier, modifiers, abilityLookup, ruleData);
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param valueLookup
|
||||
*/
|
||||
export function generateArmorClassAdjustments(valueLookup) {
|
||||
return {
|
||||
overrideAc: ValueUtils.getData(valueLookup, AdjustmentTypeEnum.OVERRIDE_AC),
|
||||
overrideBaseArmor: ValueUtils.getData(valueLookup, AdjustmentTypeEnum.OVERRIDE_BASE_ARMOR),
|
||||
miscBonus: ValueUtils.getData(valueLookup, AdjustmentTypeEnum.MISC_BONUS_AC),
|
||||
magicBonus: ValueUtils.getData(valueLookup, AdjustmentTypeEnum.MAGIC_BONUS_AC),
|
||||
};
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param armorClassSuppliers
|
||||
* @param armorClassAdjustments
|
||||
*/
|
||||
export function generateArmorClassTotal(armorClassSuppliers, armorClassAdjustments) {
|
||||
if (armorClassAdjustments.overrideAc !== null) {
|
||||
const overrideAcValue = ValueUtils.getTypedCharacterValueValue(armorClassAdjustments.overrideAc);
|
||||
if (overrideAcValue !== null) {
|
||||
return overrideAcValue;
|
||||
}
|
||||
}
|
||||
return deriveArmorClassSupplierTotal(armorClassSuppliers);
|
||||
}
|
||||
@@ -0,0 +1,89 @@
|
||||
import { orderBy } from 'lodash';
|
||||
import { ActionAccessors } from '../../Action';
|
||||
import { ActivationAccessors, ActivationTypeEnum } from '../../Activation';
|
||||
import { ItemAccessors } from '../../Item';
|
||||
import { ModifierAccessors, ModifierValidators } from '../../Modifier';
|
||||
import { SpellAccessors } from '../../Spell';
|
||||
import { AttackSourceTypeEnum } from '../constants';
|
||||
/**
|
||||
*
|
||||
* @param actions
|
||||
* @param itemAttacks
|
||||
* @param spellAttackList
|
||||
* @param customAttacks
|
||||
*/
|
||||
export function generateAttacks(actions, itemAttacks, spellAttackList, customAttacks) {
|
||||
const attacks = [];
|
||||
itemAttacks.forEach((attack) => {
|
||||
let activation = ActivationTypeEnum.ACTION;
|
||||
if (ItemAccessors.isOffhand(attack)) {
|
||||
activation = ActivationTypeEnum.BONUS_ACTION;
|
||||
}
|
||||
attacks.push({
|
||||
type: AttackSourceTypeEnum.ITEM,
|
||||
key: `${AttackSourceTypeEnum.ITEM}-${attack.id}`,
|
||||
activation,
|
||||
data: attack,
|
||||
});
|
||||
});
|
||||
spellAttackList.forEach((attack) => {
|
||||
attacks.push({
|
||||
type: AttackSourceTypeEnum.SPELL,
|
||||
key: `${AttackSourceTypeEnum.SPELL}-${SpellAccessors.getUniqueKey(attack)}`,
|
||||
activation: SpellAccessors.getActivationType(attack),
|
||||
data: attack,
|
||||
});
|
||||
});
|
||||
actions.forEach((action, idx) => {
|
||||
if (!ActionAccessors.displayAsAttack(action)) {
|
||||
return;
|
||||
}
|
||||
attacks.push({
|
||||
type: AttackSourceTypeEnum.ACTION,
|
||||
key: `${AttackSourceTypeEnum.ACTION}-${idx}-${ActionAccessors.getUniqueKey(action)}`,
|
||||
activation: ActivationAccessors.getType(ActionAccessors.getActivation(action)),
|
||||
data: action,
|
||||
});
|
||||
});
|
||||
customAttacks.forEach((attack) => {
|
||||
if (!ActionAccessors.displayAsAttack(attack)) {
|
||||
return;
|
||||
}
|
||||
attacks.push({
|
||||
type: AttackSourceTypeEnum.CUSTOM,
|
||||
key: `${AttackSourceTypeEnum.CUSTOM}-${ActionAccessors.getUniqueKey(attack)}`,
|
||||
activation: ActivationAccessors.getType(ActionAccessors.getActivation(attack)),
|
||||
data: attack,
|
||||
});
|
||||
});
|
||||
return attacks;
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param modifiers
|
||||
*/
|
||||
export function generateAttacksPerActionInfo(modifiers) {
|
||||
const extraAttackModifiers = modifiers.filter((modifier) => ModifierValidators.isSetExtraAttacksModifier(modifier));
|
||||
const sortedExtraAttackModifiers = orderBy(extraAttackModifiers, [
|
||||
(modifier) => ModifierAccessors.getValue(modifier),
|
||||
(modifier) => {
|
||||
const restriction = ModifierAccessors.getRestriction(modifier);
|
||||
return restriction !== null && restriction.length;
|
||||
},
|
||||
], ['asc', 'desc']);
|
||||
const attacksPerActionBestModifier = sortedExtraAttackModifiers.pop();
|
||||
const defaultValue = 0;
|
||||
const defaultRestriction = '';
|
||||
let attackInfoValue = defaultValue;
|
||||
let attackInfoRestriction = defaultRestriction;
|
||||
if (attacksPerActionBestModifier) {
|
||||
const bestModiferValue = ModifierAccessors.getValue(attacksPerActionBestModifier);
|
||||
attackInfoValue = bestModiferValue ? bestModiferValue : defaultValue;
|
||||
const bestModifierRestriction = ModifierAccessors.getRestriction(attacksPerActionBestModifier);
|
||||
attackInfoRestriction = bestModifierRestriction ? bestModifierRestriction : defaultRestriction;
|
||||
}
|
||||
return {
|
||||
value: 1 + attackInfoValue,
|
||||
restriction: attackInfoRestriction,
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,69 @@
|
||||
import { HelperUtils } from '../../Helper';
|
||||
import { RaceAccessors } from '../../Race';
|
||||
import { RuleDataAccessors } from '../../RuleData';
|
||||
/**
|
||||
*
|
||||
* @param alignmentId
|
||||
* @param ruleData
|
||||
*/
|
||||
export function generateAlignment(alignmentId, ruleData) {
|
||||
if (alignmentId === null) {
|
||||
return null;
|
||||
}
|
||||
return HelperUtils.lookupDataOrFallback(RuleDataAccessors.getAlignmentLookup(ruleData), alignmentId);
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param lifeStyleId
|
||||
* @param ruleData
|
||||
*/
|
||||
export function generateLifestyle(lifeStyleId, ruleData) {
|
||||
if (lifeStyleId === null) {
|
||||
return null;
|
||||
}
|
||||
return HelperUtils.lookupDataOrFallback(RuleDataAccessors.getLifestyleLookup(ruleData), lifeStyleId);
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param race
|
||||
*/
|
||||
export function generateSize(race) {
|
||||
if (race === null) {
|
||||
return null;
|
||||
}
|
||||
return RaceAccessors.getSizeInfo(race);
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param traitsContract
|
||||
*/
|
||||
export function generateCharacterTraits(traitsContract) {
|
||||
if (traitsContract !== null) {
|
||||
return traitsContract;
|
||||
}
|
||||
return {
|
||||
appearance: null,
|
||||
bonds: null,
|
||||
flaws: null,
|
||||
ideals: null,
|
||||
personalityTraits: null,
|
||||
};
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param notesContract
|
||||
*/
|
||||
export function generateCharacterNotes(notesContract) {
|
||||
if (notesContract !== null) {
|
||||
return notesContract;
|
||||
}
|
||||
return {
|
||||
allies: null,
|
||||
backstory: null,
|
||||
enemies: null,
|
||||
organizations: null,
|
||||
otherHoldings: null,
|
||||
otherNotes: null,
|
||||
personalPossessions: null,
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,74 @@
|
||||
import { MovementTypeEnum, PreferenceAbilityScoreDisplayTypeEnum, PreferenceEncumbranceTypeEnum, PreferenceHitPointTypeEnum, PreferencePrivacyTypeEnum, PreferenceProgressionTypeEnum, PreferenceSharingTypeEnum, SenseTypeEnum, } from '../../Core';
|
||||
/**
|
||||
*
|
||||
* @param race
|
||||
* @param classes
|
||||
* @param stats
|
||||
* @param configuration
|
||||
*/
|
||||
export function generateIsCharacterSheetReady(race, classes, stats, configuration) {
|
||||
if (!race) {
|
||||
return false;
|
||||
}
|
||||
if (!classes.length) {
|
||||
return false;
|
||||
}
|
||||
let hasAllStats = true;
|
||||
if (configuration.abilityScoreType === null) {
|
||||
hasAllStats = false;
|
||||
}
|
||||
stats.forEach((stat) => {
|
||||
if (stat.value === null) {
|
||||
hasAllStats = false;
|
||||
}
|
||||
});
|
||||
if (!hasAllStats) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param preferencesContract
|
||||
*/
|
||||
export function generateCharacterPreferences(preferencesContract, featureFlagInfo) {
|
||||
if (preferencesContract !== null) {
|
||||
return preferencesContract;
|
||||
}
|
||||
return {
|
||||
abilityScoreDisplayType: PreferenceAbilityScoreDisplayTypeEnum.MODIFIERS_TOP,
|
||||
enableOptionalClassFeatures: false,
|
||||
enableOptionalOrigins: false,
|
||||
encumbranceType: PreferenceEncumbranceTypeEnum.ENCUMBRANCE,
|
||||
enforceFeatRules: true,
|
||||
enforceMulticlassRules: true,
|
||||
hitPointType: PreferenceHitPointTypeEnum.FIXED,
|
||||
ignoreCoinWeight: true,
|
||||
primaryMovement: MovementTypeEnum.WALK,
|
||||
primarySense: SenseTypeEnum.PASSIVE_PERCEPTION,
|
||||
privacyType: PreferencePrivacyTypeEnum.CAMPAIGN_ONLY,
|
||||
progressionType: PreferenceProgressionTypeEnum.MILESTONE,
|
||||
sharingType: PreferenceSharingTypeEnum.LIMITED,
|
||||
showCompanions: false,
|
||||
showScaledSpells: true,
|
||||
showUnarmedStrike: true,
|
||||
showWildShape: false,
|
||||
enableDarkMode: false,
|
||||
useHomebrewContent: true,
|
||||
enableContainerCurrency: false,
|
||||
};
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param configurationContract
|
||||
*/
|
||||
export function generateCharacterConfiguration(configurationContract) {
|
||||
if (configurationContract !== null) {
|
||||
return configurationContract;
|
||||
}
|
||||
return {
|
||||
abilityScoreType: null,
|
||||
showHelpText: false,
|
||||
startingEquipmentType: null,
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,41 @@
|
||||
import { ModifierValidators } from '../../Modifier';
|
||||
import { RuleDataAccessors } from '../../RuleData';
|
||||
import { DeathCauseEnum } from '../constants';
|
||||
import { deriveAdvantageDeathSavesAdjustments, deriveDisadvantageDeathSavesAdjustments } from '../derivers';
|
||||
/**
|
||||
*
|
||||
* @param deathSaves
|
||||
* @param modifiers
|
||||
* @param ruleData
|
||||
*/
|
||||
export function generateDeathCause(deathSaves, modifiers, ruleData) {
|
||||
const maxDeathsavesFail = RuleDataAccessors.getMaxDeathsavesFail(ruleData);
|
||||
if (deathSaves !== null && deathSaves.failCount !== null && deathSaves.failCount >= maxDeathsavesFail) {
|
||||
return DeathCauseEnum.DEATHSAVES;
|
||||
}
|
||||
if (modifiers.find((modifier) => ModifierValidators.isSetDeathModifier(modifier))) {
|
||||
return DeathCauseEnum.CONDITION;
|
||||
}
|
||||
return DeathCauseEnum.NONE;
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param deathCause
|
||||
*/
|
||||
export function generateIsDead(deathCause) {
|
||||
return deathCause !== DeathCauseEnum.NONE;
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param deathSaveContract
|
||||
* @param modifiers
|
||||
*/
|
||||
export function generateDeathSaveInfo(deathSaveContract, modifiers) {
|
||||
return {
|
||||
failCount: deathSaveContract !== null && deathSaveContract.failCount !== null ? deathSaveContract.failCount : 0,
|
||||
successCount: deathSaveContract !== null && deathSaveContract.successCount !== null ? deathSaveContract.successCount : 0,
|
||||
isStabilized: deathSaveContract === null ? false : deathSaveContract.isStabilized,
|
||||
advantageAdjustments: deriveAdvantageDeathSavesAdjustments(modifiers),
|
||||
disadvantageAdjustments: deriveDisadvantageDeathSavesAdjustments(modifiers),
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,221 @@
|
||||
import { TypeScriptUtils } from '../../../utils';
|
||||
import { ConditionAccessors } from '../../Condition';
|
||||
import { DamageAdjustmentTypeEnum, DefenseAdjustmentTypeEnum } from '../../Core';
|
||||
import { FormatUtils } from '../../Format';
|
||||
import { HelperUtils } from '../../Helper';
|
||||
import { ModifierAccessors } from '../../Modifier';
|
||||
import { RuleDataAccessors, RuleDataUtils } from '../../RuleData';
|
||||
import { deriveCustomConditionDefenseAdjustmentDataOrigin, deriveCustomDefenseAdjustmentDataOrigin } from '../derivers';
|
||||
import { isImmunityDamageAdjustment, isResistanceDamageAdjustment, isVulnerabilityDamageAdjustment, } from '../validators';
|
||||
/**
|
||||
*
|
||||
* @param customDamageAdjustments
|
||||
* @param modifiers
|
||||
* @param ruleData
|
||||
*/
|
||||
export function generateActiveResistances(customDamageAdjustments, modifiers, ruleData) {
|
||||
const damageAdjustments = [];
|
||||
customDamageAdjustments.forEach((adjustment) => {
|
||||
damageAdjustments.push({
|
||||
name: adjustment.name === null ? '' : adjustment.name,
|
||||
dataOrigin: deriveCustomDefenseAdjustmentDataOrigin(adjustment),
|
||||
isCustom: true,
|
||||
type: DefenseAdjustmentTypeEnum.DAMAGE_ADJUSTMENT,
|
||||
slug: FormatUtils.slugify(adjustment.name),
|
||||
});
|
||||
});
|
||||
modifiers.forEach((modifier) => {
|
||||
const damageAdjustment = RuleDataUtils.getDamageAdjustmentBySlug(ModifierAccessors.getSubType(modifier), DamageAdjustmentTypeEnum.RESISTANCE, ruleData);
|
||||
let name = '';
|
||||
if (damageAdjustment) {
|
||||
name = damageAdjustment.name === null ? '' : damageAdjustment.name;
|
||||
}
|
||||
else {
|
||||
const subtypeName = ModifierAccessors.getFriendlySubtypeName(modifier);
|
||||
name = subtypeName === null ? '' : subtypeName;
|
||||
}
|
||||
damageAdjustments.push({
|
||||
name,
|
||||
dataOrigin: ModifierAccessors.getDataOrigin(modifier),
|
||||
isCustom: false,
|
||||
type: DefenseAdjustmentTypeEnum.DAMAGE_ADJUSTMENT,
|
||||
slug: FormatUtils.slugify(name),
|
||||
});
|
||||
});
|
||||
return damageAdjustments;
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param customDamageAdjustments
|
||||
* @param customConditionAdjustments
|
||||
* @param modifiers
|
||||
* @param ruleData
|
||||
*/
|
||||
export function generateActiveImmunities(customDamageAdjustments, customConditionAdjustments, modifiers, ruleData) {
|
||||
const defenseAdjustments = [];
|
||||
customDamageAdjustments.forEach((adjustment) => {
|
||||
defenseAdjustments.push({
|
||||
name: adjustment.name === null ? '' : adjustment.name,
|
||||
dataOrigin: deriveCustomDefenseAdjustmentDataOrigin(adjustment),
|
||||
isCustom: true,
|
||||
type: DefenseAdjustmentTypeEnum.DAMAGE_ADJUSTMENT,
|
||||
slug: FormatUtils.slugify(adjustment.name),
|
||||
});
|
||||
});
|
||||
customConditionAdjustments.forEach((adjustment) => {
|
||||
defenseAdjustments.push({
|
||||
name: ConditionAccessors.getName(adjustment),
|
||||
dataOrigin: deriveCustomConditionDefenseAdjustmentDataOrigin(adjustment),
|
||||
isCustom: true,
|
||||
type: DefenseAdjustmentTypeEnum.CONDITION_ADJUSTMENT,
|
||||
slug: FormatUtils.slugify(ConditionAccessors.getName(adjustment)),
|
||||
});
|
||||
});
|
||||
modifiers.forEach((modifier) => {
|
||||
const damageAdjustment = RuleDataUtils.getDamageAdjustmentBySlug(ModifierAccessors.getSubType(modifier), DamageAdjustmentTypeEnum.IMMUNITY, ruleData);
|
||||
if (damageAdjustment) {
|
||||
defenseAdjustments.push({
|
||||
name: damageAdjustment.name === null ? '' : damageAdjustment.name,
|
||||
dataOrigin: ModifierAccessors.getDataOrigin(modifier),
|
||||
isCustom: false,
|
||||
type: DefenseAdjustmentTypeEnum.DAMAGE_ADJUSTMENT,
|
||||
slug: FormatUtils.slugify(damageAdjustment.name),
|
||||
});
|
||||
return;
|
||||
}
|
||||
const condition = RuleDataUtils.getConditionBySlug(ModifierAccessors.getSubType(modifier), ruleData);
|
||||
if (condition) {
|
||||
defenseAdjustments.push({
|
||||
name: ConditionAccessors.getName(condition),
|
||||
dataOrigin: ModifierAccessors.getDataOrigin(modifier),
|
||||
isCustom: false,
|
||||
type: DefenseAdjustmentTypeEnum.CONDITION_ADJUSTMENT,
|
||||
slug: ConditionAccessors.getSlug(condition),
|
||||
});
|
||||
return;
|
||||
}
|
||||
const subtypeName = ModifierAccessors.getFriendlySubtypeName(modifier);
|
||||
defenseAdjustments.push({
|
||||
name: subtypeName === null ? '' : subtypeName,
|
||||
dataOrigin: ModifierAccessors.getDataOrigin(modifier),
|
||||
isCustom: false,
|
||||
type: DefenseAdjustmentTypeEnum.DAMAGE_ADJUSTMENT,
|
||||
slug: FormatUtils.slugify(ModifierAccessors.getFriendlySubtypeName(modifier)),
|
||||
});
|
||||
});
|
||||
return defenseAdjustments;
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param customDamageAdjustments
|
||||
* @param modifiers
|
||||
* @param ruleData
|
||||
*/
|
||||
export function generateActiveVulnerabilities(customDamageAdjustments, modifiers, ruleData) {
|
||||
const damageAdjustments = [];
|
||||
customDamageAdjustments.forEach((adjustment) => {
|
||||
damageAdjustments.push({
|
||||
name: adjustment.name === null ? '' : adjustment.name,
|
||||
dataOrigin: deriveCustomDefenseAdjustmentDataOrigin(adjustment),
|
||||
isCustom: true,
|
||||
type: DefenseAdjustmentTypeEnum.DAMAGE_ADJUSTMENT,
|
||||
slug: FormatUtils.slugify(adjustment.name),
|
||||
});
|
||||
});
|
||||
modifiers.forEach((modifier) => {
|
||||
let name;
|
||||
const damageAdjustment = RuleDataUtils.getDamageAdjustmentBySlug(ModifierAccessors.getSubType(modifier), DamageAdjustmentTypeEnum.VULNERABILITY, ruleData);
|
||||
if (damageAdjustment) {
|
||||
name = damageAdjustment.name;
|
||||
}
|
||||
else {
|
||||
name = ModifierAccessors.getFriendlySubtypeName(modifier);
|
||||
}
|
||||
damageAdjustments.push({
|
||||
name,
|
||||
dataOrigin: ModifierAccessors.getDataOrigin(modifier),
|
||||
isCustom: false,
|
||||
type: DefenseAdjustmentTypeEnum.DAMAGE_ADJUSTMENT,
|
||||
slug: FormatUtils.slugify(name),
|
||||
});
|
||||
});
|
||||
return damageAdjustments;
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param ruleData
|
||||
*/
|
||||
export function generateResistanceData(ruleData) {
|
||||
return RuleDataAccessors.getDamageAdjustments(ruleData).filter(isResistanceDamageAdjustment);
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param ruleData
|
||||
*/
|
||||
export function generateVulnerabilityData(ruleData) {
|
||||
return RuleDataAccessors.getDamageAdjustments(ruleData).filter(isVulnerabilityDamageAdjustment);
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param ruleData
|
||||
*/
|
||||
export function generateImmunityData(ruleData) {
|
||||
return RuleDataAccessors.getDamageAdjustments(ruleData).filter(isImmunityDamageAdjustment);
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param customDamageAdjustments
|
||||
*/
|
||||
export function generateCustomResistanceDamageAdjustments(customDamageAdjustments) {
|
||||
return customDamageAdjustments.filter(isResistanceDamageAdjustment);
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param customDamageAdjustments
|
||||
*/
|
||||
export function generateCustomImmunityDamageAdjustments(customDamageAdjustments) {
|
||||
return customDamageAdjustments.filter(isImmunityDamageAdjustment);
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param customDamageAdjustments
|
||||
*/
|
||||
export function generateCustomVulnerabilityDamageAdjustments(customDamageAdjustments) {
|
||||
return customDamageAdjustments.filter(isVulnerabilityDamageAdjustment);
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param customDefenseAdjustments
|
||||
* @param ruleData
|
||||
*/
|
||||
export function generateCustomDamageAdjustments(customDefenseAdjustments, ruleData) {
|
||||
const damageAdjustmentLookup = RuleDataAccessors.getDamageAdjustmentsLookup(ruleData);
|
||||
return customDefenseAdjustments
|
||||
.filter((adjustment) => adjustment.type === DefenseAdjustmentTypeEnum.DAMAGE_ADJUSTMENT)
|
||||
.map((adjustment) => {
|
||||
const damageAdjustmentData = HelperUtils.lookupDataOrFallback(damageAdjustmentLookup, adjustment.adjustmentId);
|
||||
if (damageAdjustmentData !== null) {
|
||||
return Object.assign(Object.assign({}, damageAdjustmentData), { source: adjustment.source === null ? '' : adjustment.source });
|
||||
}
|
||||
return null;
|
||||
})
|
||||
.filter(TypeScriptUtils.isNotNullOrUndefined);
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param customDefenseAdjustments
|
||||
* @param ruleData
|
||||
*/
|
||||
export function generateCustomConditionAdjustments(customDefenseAdjustments, ruleData) {
|
||||
const conditionDataLookup = RuleDataAccessors.getConditionLookup(ruleData);
|
||||
return customDefenseAdjustments
|
||||
.filter((adjustment) => adjustment.type === DefenseAdjustmentTypeEnum.CONDITION_ADJUSTMENT)
|
||||
.map((adjustment) => {
|
||||
const conditionData = HelperUtils.lookupDataOrFallback(conditionDataLookup, adjustment.adjustmentId);
|
||||
if (conditionData !== null) {
|
||||
return Object.assign(Object.assign({}, conditionData), { source: adjustment.source === null ? '' : adjustment.source });
|
||||
}
|
||||
return null;
|
||||
})
|
||||
.filter(TypeScriptUtils.isNotNullOrUndefined);
|
||||
}
|
||||
@@ -0,0 +1,314 @@
|
||||
import { AbilityAccessors } from '../../Ability';
|
||||
import { ActionAccessors } from '../../Action';
|
||||
import { ClassAccessors } from '../../Class';
|
||||
import { ClassFeatureAccessors } from '../../ClassFeature';
|
||||
import { AbilityStatEnum, PreferenceHitPointTypeEnum } from '../../Core';
|
||||
import { DataOriginTypeEnum } from '../../DataOrigin';
|
||||
import { DiceUtils } from '../../Dice';
|
||||
import { EntityUtils } from '../../Entity';
|
||||
import { FeatAccessors } from '../../Feat';
|
||||
import { HelperUtils } from '../../Helper';
|
||||
import { ItemAccessors } from '../../Item';
|
||||
import { ModifierAccessors, ModifierDerivers, ModifierValidators } from '../../Modifier';
|
||||
import { RaceAccessors } from '../../Race';
|
||||
import { RacialTraitAccessors } from '../../RacialTrait';
|
||||
import { RuleDataAccessors } from '../../RuleData';
|
||||
import { ProtectionSupplierTypeEnum } from '../constants';
|
||||
import { deriveItemProtectionSupplierAvailabilityStatus, deriveProtectionSupplierAvailabilityStatus, } from '../derivers';
|
||||
/**
|
||||
*
|
||||
* @param hitPointParts
|
||||
* @param currentLevel
|
||||
* @param classes
|
||||
* @param abilityLookup
|
||||
* @param raceModifiers
|
||||
* @param classesModifiers
|
||||
* @param miscModifiers
|
||||
* @param globalModifiers
|
||||
* @param preferences
|
||||
* @param ruleData
|
||||
*/
|
||||
export function generateHitPointInfo(hitPointParts, currentLevel, classes, abilityLookup, raceModifiers, classesModifiers, miscModifiers, globalModifiers, preferences, ruleData) {
|
||||
return getHitPointInfo(hitPointParts.baseHp, hitPointParts.overrideHp, hitPointParts.bonusHp, hitPointParts.tempHp, hitPointParts.removedHp, currentLevel, classes, abilityLookup, raceModifiers, classesModifiers, miscModifiers, globalModifiers, preferences, ruleData);
|
||||
}
|
||||
/**
|
||||
* //TODO better naming that fits generator convention
|
||||
* @param baseHp
|
||||
* @param overrideHp
|
||||
* @param bonusHp
|
||||
* @param tempHp
|
||||
* @param removedHp
|
||||
* @param currentLevel
|
||||
* @param classes
|
||||
* @param abilityLookup
|
||||
* @param raceModifiers
|
||||
* @param classesModifiers
|
||||
* @param miscModifiers
|
||||
* @param globalModifiers
|
||||
* @param preferences
|
||||
* @param ruleData
|
||||
*/
|
||||
export function getHitPointInfo(baseHp, overrideHp, bonusHp, tempHp, removedHp, currentLevel, classes, abilityLookup, raceModifiers, classesModifiers, miscModifiers, globalModifiers, preferences, ruleData) {
|
||||
const classesHitDice = classes.map((charClass) => ({
|
||||
dice: {
|
||||
diceCount: ClassAccessors.getLevel(charClass),
|
||||
diceValue: ClassAccessors.getHitDiceType(charClass),
|
||||
diceMultiplier: null,
|
||||
diceString: null,
|
||||
fixedValue: null,
|
||||
},
|
||||
charClass,
|
||||
}));
|
||||
const hitPointSources = [];
|
||||
let conStat;
|
||||
let conStatModifier;
|
||||
if (Object.keys(abilityLookup).length) {
|
||||
conStat = abilityLookup[AbilityStatEnum.CONSTITUTION] || 0;
|
||||
conStatModifier = AbilityAccessors.getModifier(conStat);
|
||||
}
|
||||
if (conStatModifier) {
|
||||
const source = AbilityAccessors.getLabel(conStat);
|
||||
hitPointSources.push({
|
||||
amount: currentLevel * conStatModifier,
|
||||
source: source === null ? 'UNK' : source,
|
||||
});
|
||||
}
|
||||
const racialHpPerLevelModifiers = raceModifiers.filter((modifier) => ModifierValidators.isBonusHitPointsPerLevelModifier(modifier));
|
||||
const classesHpPerLevelModifiers = classesModifiers.filter((modifier) => ModifierValidators.isBonusHitPointsPerLevelModifier(modifier));
|
||||
const miscHpPerLevelModifiers = miscModifiers.filter((modifier) => ModifierValidators.isBonusHitPointsPerLevelModifier(modifier));
|
||||
if (racialHpPerLevelModifiers.length) {
|
||||
racialHpPerLevelModifiers.reduce((acc, modifier) => {
|
||||
const value = ModifierAccessors.getValue(modifier);
|
||||
if (value !== null) {
|
||||
acc.push({
|
||||
amount: currentLevel * value,
|
||||
source: EntityUtils.getDataOriginName(ModifierAccessors.getDataOrigin(modifier)),
|
||||
});
|
||||
}
|
||||
return acc;
|
||||
}, hitPointSources);
|
||||
}
|
||||
if (classesHpPerLevelModifiers.length) {
|
||||
classesHpPerLevelModifiers.reduce((acc, modifier) => {
|
||||
const value = ModifierAccessors.getValue(modifier);
|
||||
const dataOrigin = ModifierAccessors.getDataOrigin(modifier);
|
||||
const dataOriginType = ModifierAccessors.getDataOriginType(modifier);
|
||||
if (dataOriginType === DataOriginTypeEnum.CLASS_FEATURE && value !== null) {
|
||||
acc.push({
|
||||
amount: ClassAccessors.getLevel(dataOrigin.parent) * value,
|
||||
source: EntityUtils.getDataOriginName(ModifierAccessors.getDataOrigin(modifier)),
|
||||
});
|
||||
}
|
||||
return acc;
|
||||
}, hitPointSources);
|
||||
}
|
||||
if (miscHpPerLevelModifiers.length) {
|
||||
miscHpPerLevelModifiers.reduce((acc, modifier) => {
|
||||
const value = ModifierAccessors.getValue(modifier);
|
||||
if (value !== null) {
|
||||
acc.push({
|
||||
amount: currentLevel * value,
|
||||
source: EntityUtils.getDataOriginName(ModifierAccessors.getDataOrigin(modifier)),
|
||||
});
|
||||
}
|
||||
return acc;
|
||||
}, hitPointSources);
|
||||
}
|
||||
const globalBonusHpModifiers = globalModifiers.filter((modifier) => ModifierValidators.isBonusHitPointsModifier(modifier));
|
||||
if (globalBonusHpModifiers.length) {
|
||||
globalBonusHpModifiers.reduce((acc, modifier) => {
|
||||
const statId = ModifierAccessors.getStatId(modifier);
|
||||
if (statId !== null) {
|
||||
const stat = HelperUtils.lookupDataOrFallback(abilityLookup, statId);
|
||||
if (stat !== null) {
|
||||
const statModifier = AbilityAccessors.getModifier(stat);
|
||||
acc.push({
|
||||
amount: statModifier === null ? 0 : statModifier,
|
||||
source: EntityUtils.getDataOriginName(ModifierAccessors.getDataOrigin(modifier)),
|
||||
});
|
||||
}
|
||||
}
|
||||
else {
|
||||
const hpIncrease = ModifierAccessors.getValue(modifier);
|
||||
if (!!hpIncrease) {
|
||||
acc.push({
|
||||
amount: hpIncrease,
|
||||
source: EntityUtils.getDataOriginName(ModifierAccessors.getDataOrigin(modifier)),
|
||||
});
|
||||
}
|
||||
}
|
||||
return acc;
|
||||
}, hitPointSources);
|
||||
}
|
||||
const totalHitPointSources = hitPointSources.reduce((acc, hitPointSource) => (acc += hitPointSource.amount), 0);
|
||||
const totalAvgClassHitDie = classes.reduce((acc, charClass) => {
|
||||
const hitDiceType = ClassAccessors.getHitDiceType(charClass);
|
||||
const level = ClassAccessors.getLevel(charClass);
|
||||
if (ClassAccessors.isStartingClass(charClass)) {
|
||||
acc += hitDiceType;
|
||||
acc += Math.floor((level - 1) * DiceUtils.getAverageDieValue(hitDiceType));
|
||||
}
|
||||
else {
|
||||
acc += Math.floor(level * DiceUtils.getAverageDieValue(hitDiceType));
|
||||
}
|
||||
return acc;
|
||||
}, 0);
|
||||
const totalFixedClassHitDie = classes.reduce((acc, charClass) => {
|
||||
const hitDiceType = ClassAccessors.getHitDiceType(charClass);
|
||||
const level = ClassAccessors.getLevel(charClass);
|
||||
if (ClassAccessors.isStartingClass(charClass)) {
|
||||
acc += hitDiceType;
|
||||
acc += (level - 1) * DiceUtils.getFixedDieValue(hitDiceType);
|
||||
}
|
||||
else {
|
||||
acc += level * DiceUtils.getFixedDieValue(hitDiceType);
|
||||
}
|
||||
return acc;
|
||||
}, 0);
|
||||
const totalClassHitDieMax = classes.reduce((acc, charClass) => (acc += ClassAccessors.getLevel(charClass) * ClassAccessors.getHitDiceType(charClass)), 0);
|
||||
const totalFixedValueHp = totalFixedClassHitDie + totalHitPointSources;
|
||||
const totalAverageHp = totalAvgClassHitDie + totalHitPointSources;
|
||||
const possibleMaxHitPoints = totalClassHitDieMax + totalHitPointSources;
|
||||
let finalBaseHp = baseHp;
|
||||
if (preferences && preferences.hitPointType === PreferenceHitPointTypeEnum.FIXED) {
|
||||
finalBaseHp = totalFixedClassHitDie;
|
||||
}
|
||||
const baseTotalHp = finalBaseHp + totalHitPointSources;
|
||||
let totalHp = baseTotalHp + (bonusHp ? bonusHp : 0);
|
||||
if (overrideHp !== null) {
|
||||
totalHp = overrideHp;
|
||||
}
|
||||
const finalTotalHp = Math.max(totalHp, RuleDataAccessors.getMinimumHpTotal(ruleData));
|
||||
const finalRemovedHp = Math.min(finalTotalHp, removedHp);
|
||||
return {
|
||||
baseHp: finalBaseHp,
|
||||
baseTotalHp,
|
||||
bonusHp,
|
||||
classesHitDice,
|
||||
hitPointSources,
|
||||
overrideHp,
|
||||
possibleMaxHitPoints,
|
||||
remainingHp: finalTotalHp - finalRemovedHp,
|
||||
removedHp: finalRemovedHp,
|
||||
tempHp,
|
||||
totalAverageHp,
|
||||
totalFixedValueHp,
|
||||
totalHitPointSources,
|
||||
totalHp: finalTotalHp,
|
||||
};
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param classes
|
||||
* @param race
|
||||
* @param feats
|
||||
* @param items
|
||||
* @param modifierData
|
||||
* @param abilityLookup
|
||||
* @param ruleData
|
||||
* @param proficiencyBonus
|
||||
* @param characterId
|
||||
*/
|
||||
export function generateProtectionSuppliers(classes, race, feats, items, modifierData, abilityLookup, ruleData, proficiencyBonus, characterId) {
|
||||
let protectionSuppliers = [];
|
||||
if (race !== null) {
|
||||
RaceAccessors.getRacialTraits(race).forEach((racialTrait) => {
|
||||
const modifiers = RacialTraitAccessors.getModifiers(racialTrait);
|
||||
const foundProtectionModifier = modifiers.find(ModifierValidators.isProtectionZeroHpModifier);
|
||||
if (!foundProtectionModifier) {
|
||||
return;
|
||||
}
|
||||
const actions = RacialTraitAccessors.getActions(racialTrait);
|
||||
if (actions.length !== 1) {
|
||||
return;
|
||||
}
|
||||
const action = actions[0];
|
||||
const limitedUse = ActionAccessors.getLimitedUse(action);
|
||||
if (!limitedUse) {
|
||||
return;
|
||||
}
|
||||
protectionSuppliers.push({
|
||||
type: ProtectionSupplierTypeEnum.RACIAL_TRAIT,
|
||||
data: racialTrait,
|
||||
modifier: foundProtectionModifier,
|
||||
setHpValue: ModifierDerivers.deriveValue(foundProtectionModifier, modifierData),
|
||||
key: [ProtectionSupplierTypeEnum.RACIAL_TRAIT, RacialTraitAccessors.getUniqueKey(racialTrait)].join('-'),
|
||||
availabilityStatus: deriveProtectionSupplierAvailabilityStatus(limitedUse, abilityLookup, ruleData, proficiencyBonus),
|
||||
action,
|
||||
});
|
||||
});
|
||||
}
|
||||
classes.forEach((charClass) => {
|
||||
ClassAccessors.getClassFeatures(charClass).forEach((classFeature) => {
|
||||
const modifiers = ClassFeatureAccessors.getModifiers(classFeature);
|
||||
const foundProtectionModifier = modifiers.find(ModifierValidators.isProtectionZeroHpModifier);
|
||||
if (!foundProtectionModifier) {
|
||||
return;
|
||||
}
|
||||
const actions = ClassFeatureAccessors.getActions(classFeature);
|
||||
if (actions.length !== 1) {
|
||||
return;
|
||||
}
|
||||
const action = actions[0];
|
||||
const limitedUse = ActionAccessors.getLimitedUse(action);
|
||||
if (!limitedUse) {
|
||||
return;
|
||||
}
|
||||
protectionSuppliers.push({
|
||||
type: ProtectionSupplierTypeEnum.CLASS_FEATURE,
|
||||
data: classFeature,
|
||||
modifier: foundProtectionModifier,
|
||||
setHpValue: ModifierDerivers.deriveValue(foundProtectionModifier, modifierData),
|
||||
key: [ProtectionSupplierTypeEnum.CLASS_FEATURE, ClassFeatureAccessors.getUniqueKey(classFeature)].join('-'),
|
||||
availabilityStatus: deriveProtectionSupplierAvailabilityStatus(limitedUse, abilityLookup, ruleData, proficiencyBonus),
|
||||
action,
|
||||
});
|
||||
});
|
||||
});
|
||||
feats.forEach((feat) => {
|
||||
const modifiers = FeatAccessors.getModifiers(feat);
|
||||
const foundProtectionModifier = modifiers.find(ModifierValidators.isProtectionZeroHpModifier);
|
||||
if (!foundProtectionModifier) {
|
||||
return;
|
||||
}
|
||||
const actions = FeatAccessors.getActions(feat);
|
||||
if (actions.length !== 1) {
|
||||
return;
|
||||
}
|
||||
const action = actions[0];
|
||||
const limitedUse = ActionAccessors.getLimitedUse(action);
|
||||
if (!limitedUse) {
|
||||
return;
|
||||
}
|
||||
protectionSuppliers.push({
|
||||
type: ProtectionSupplierTypeEnum.FEAT,
|
||||
data: feat,
|
||||
modifier: foundProtectionModifier,
|
||||
setHpValue: ModifierDerivers.deriveValue(foundProtectionModifier, modifierData),
|
||||
key: [ProtectionSupplierTypeEnum.FEAT, FeatAccessors.getUniqueKey(feat)].join('-'),
|
||||
availabilityStatus: deriveProtectionSupplierAvailabilityStatus(limitedUse, abilityLookup, ruleData, proficiencyBonus),
|
||||
action,
|
||||
});
|
||||
});
|
||||
items.forEach((item) => {
|
||||
const modifiers = ItemAccessors.getModifiers(item);
|
||||
const foundProtectionModifier = modifiers.find(ModifierValidators.isProtectionZeroHpModifier);
|
||||
if (!foundProtectionModifier) {
|
||||
return;
|
||||
}
|
||||
const limitedUse = ItemAccessors.getLimitedUse(item);
|
||||
if (limitedUse === null) {
|
||||
return;
|
||||
}
|
||||
protectionSuppliers.push({
|
||||
type: ProtectionSupplierTypeEnum.ITEM,
|
||||
data: item,
|
||||
modifier: foundProtectionModifier,
|
||||
setHpValue: ModifierDerivers.deriveValue(foundProtectionModifier, modifierData),
|
||||
key: [ProtectionSupplierTypeEnum.ITEM, ItemAccessors.getUniqueKey(item)].join('-'),
|
||||
availabilityStatus: deriveItemProtectionSupplierAvailabilityStatus(item, foundProtectionModifier, limitedUse, abilityLookup, ruleData, proficiencyBonus, characterId),
|
||||
action: null,
|
||||
});
|
||||
});
|
||||
return protectionSuppliers;
|
||||
}
|
||||
@@ -0,0 +1,58 @@
|
||||
import { AbilityAccessors } from '../../Ability';
|
||||
import { AbilityStatEnum } from '../../Core';
|
||||
import { ModifierBonusTypeEnum, ModifierDerivers, ModifierUtils, ModifierValidators } from '../../Modifier';
|
||||
/**
|
||||
*
|
||||
* @param modifiers
|
||||
* @param abilityLookup
|
||||
* @param profBonus
|
||||
*/
|
||||
export function getInitiative(modifiers, abilityLookup, profBonus) {
|
||||
const bonusInitiativeModifiers = modifiers.filter((modifier) => ModifierValidators.isBonusInitiativeModifier(modifier));
|
||||
const bonusInitiativeModifierTotal = abilityLookup
|
||||
? ModifierDerivers.sumModifiers(bonusInitiativeModifiers, abilityLookup)
|
||||
: 0;
|
||||
const includeProficiencyBonus = ModifierUtils.countModifierBonusTypes(bonusInitiativeModifiers, ModifierBonusTypeEnum.PROFICIENCY_BONUS) > 0;
|
||||
let halfProficiency = false;
|
||||
if (modifiers.filter((modifier) => ModifierValidators.isHalfProficiencyInitiativeModifier(modifier)).length) {
|
||||
halfProficiency = true;
|
||||
}
|
||||
let halfProficiencyRoundUp = false;
|
||||
if (modifiers.filter((modifier) => ModifierValidators.isHalfProficiencyRoundUpInitiativeModifier(modifier)).length) {
|
||||
halfProficiencyRoundUp = true;
|
||||
}
|
||||
let modifierProficiencyBonus = 0;
|
||||
if (includeProficiencyBonus) {
|
||||
modifierProficiencyBonus = profBonus;
|
||||
}
|
||||
else if (halfProficiencyRoundUp) {
|
||||
modifierProficiencyBonus = Math.ceil(profBonus / 2);
|
||||
}
|
||||
else if (halfProficiency) {
|
||||
modifierProficiencyBonus = Math.floor(profBonus / 2);
|
||||
}
|
||||
let dexAbility;
|
||||
let dexAbilityModifier;
|
||||
if (Object.keys(abilityLookup).length) {
|
||||
dexAbility = abilityLookup[AbilityStatEnum.DEXTERITY];
|
||||
dexAbilityModifier = AbilityAccessors.getModifier(dexAbility) || 0;
|
||||
}
|
||||
return dexAbilityModifier + bonusInitiativeModifierTotal + modifierProficiencyBonus;
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param processedInitiative
|
||||
* @param initiativeScore
|
||||
*
|
||||
* @returns number
|
||||
*/
|
||||
export function getStaticInitiative(processedInitiative, initiativeScore) {
|
||||
return processedInitiative + initiativeScore.amount;
|
||||
}
|
||||
/**
|
||||
* //TODO use array.some prototype
|
||||
* @param modifiers
|
||||
*/
|
||||
export function generateHasInitiativeAdvantage(modifiers) {
|
||||
return modifiers.filter((modifier) => ModifierValidators.isAdvantageInitiativeModifier(modifier)).length > 0;
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
import { TypeScriptUtils } from '../../../utils';
|
||||
import { ModifierAccessors, ModifierValidators } from '../../Modifier';
|
||||
/**
|
||||
*
|
||||
* @param modifiers
|
||||
*/
|
||||
export function generateLanguages(modifiers) {
|
||||
return modifiers
|
||||
.filter((modifier) => ModifierValidators.isLanguageModifier(modifier))
|
||||
.map((modifier) => ModifierAccessors.getFriendlySubtypeName(modifier))
|
||||
.filter(TypeScriptUtils.isNotNullOrUndefined);
|
||||
}
|
||||
@@ -0,0 +1,169 @@
|
||||
import { orderBy } from 'lodash';
|
||||
import { EntityUtils } from '../../Entity';
|
||||
import { HelperUtils } from '../../Helper';
|
||||
import { ModifierAccessors, ModifierValidators } from '../../Modifier';
|
||||
import { RuleDataAccessors, RuleDataUtils } from '../../RuleData';
|
||||
import { AdjustmentTypeEnum, ProficiencyAdjustmentTypeEnum, ValueAccessors, ValueUtils, } from '../../Value';
|
||||
import { deriveProficiencyBonus } from '../derivers';
|
||||
import { isCustomSkillProficiency } from '../validators';
|
||||
/**
|
||||
*
|
||||
* @param typeValueLookup
|
||||
* @param modifiers
|
||||
*/
|
||||
export function generateProficiencyLookup(typeValueLookup, modifiers) {
|
||||
let proficiencyLookup = {};
|
||||
ProficiencyAdjustmentTypeEnum.forEach((typeId) => {
|
||||
const values = ValueUtils.getTypeData(typeValueLookup, typeId);
|
||||
values.forEach((value) => {
|
||||
proficiencyLookup = Object.assign(Object.assign({}, proficiencyLookup), { [ValueAccessors.getEntityKey(value)]: 1 });
|
||||
});
|
||||
});
|
||||
modifiers
|
||||
.filter((modifier) => ModifierValidators.isProficiencyModifier(modifier) && ModifierAccessors.getEntityId(modifier))
|
||||
.forEach((modifier) => {
|
||||
proficiencyLookup = Object.assign(Object.assign({}, proficiencyLookup), { [ModifierAccessors.getEntityKey(modifier)]: 1 });
|
||||
});
|
||||
return proficiencyLookup;
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param currentLevel
|
||||
* @param modifiers
|
||||
* @param ruleData
|
||||
*/
|
||||
export function generateProficiencyBonus(currentLevel, modifiers, ruleData) {
|
||||
return deriveProficiencyBonus(currentLevel, modifiers, ruleData);
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param customProficiencies
|
||||
* @param valueLookupByType
|
||||
* @param modifiers
|
||||
* @param ruleData
|
||||
*/
|
||||
export function generateProficiencyGroups(customProficiencies, valueLookupByType, modifiers, ruleData) {
|
||||
const decoratedProficiencyGroups = RuleDataAccessors.getProficiencyGroups(ruleData).map((group) => (Object.assign(Object.assign({}, group), { modifiers: [], custom: [], values: [] })));
|
||||
const proficiencyGroupLookup = {};
|
||||
const customProficiencyGroupLookup = {};
|
||||
const customAdjustmentGroupLookup = {};
|
||||
decoratedProficiencyGroups.forEach((group, groupIdx) => {
|
||||
if (group.entityTypeIds !== null) {
|
||||
group.entityTypeIds.forEach((entityTypeId) => {
|
||||
proficiencyGroupLookup[entityTypeId] = groupIdx;
|
||||
});
|
||||
}
|
||||
if (group.customAdjustments !== null) {
|
||||
group.customAdjustments.forEach((adjustmentTypeId) => {
|
||||
customAdjustmentGroupLookup[adjustmentTypeId] = groupIdx;
|
||||
});
|
||||
}
|
||||
customProficiencyGroupLookup[group.customProficiencyGroup] = groupIdx;
|
||||
});
|
||||
modifiers.forEach((modifier) => {
|
||||
const entityTypeId = ModifierAccessors.getEntityTypeId(modifier);
|
||||
const isMasteryModifier = ModifierValidators.isValidWeaponMasteryModifier(modifier);
|
||||
if (entityTypeId !== null && !isMasteryModifier) {
|
||||
const groupLookupIdx = proficiencyGroupLookup[entityTypeId];
|
||||
if (typeof groupLookupIdx !== 'undefined') {
|
||||
decoratedProficiencyGroups[groupLookupIdx].modifiers.push(modifier);
|
||||
}
|
||||
}
|
||||
});
|
||||
customProficiencies.forEach((proficiency) => {
|
||||
const groupLookupIdx = customProficiencyGroupLookup[proficiency.type];
|
||||
if (typeof groupLookupIdx !== 'undefined') {
|
||||
decoratedProficiencyGroups[groupLookupIdx].custom.push(proficiency);
|
||||
}
|
||||
});
|
||||
Object.keys(customAdjustmentGroupLookup).forEach((adjustmentTypeId) => {
|
||||
if (valueLookupByType.hasOwnProperty(adjustmentTypeId)) {
|
||||
const groupLookupIdx = customAdjustmentGroupLookup[adjustmentTypeId];
|
||||
decoratedProficiencyGroups[groupLookupIdx].values.push(...valueLookupByType[adjustmentTypeId]);
|
||||
}
|
||||
});
|
||||
const proficiencyGroups = decoratedProficiencyGroups.map((group) => {
|
||||
if (group.label === 'Weapons') {
|
||||
RuleDataAccessors.getWeaponCategories(ruleData).forEach((category) => {
|
||||
if (group.modifiers.find((modifier) => ModifierValidators.isValidProficiencyWeaponCategoryModifier(modifier, category))) {
|
||||
group.modifiers = group.modifiers.filter((modifier) => {
|
||||
const weapon = RuleDataUtils.getWeaponByEntityId(ModifierAccessors.getEntityId(modifier), ModifierAccessors.getEntityTypeId(modifier), ruleData);
|
||||
return !weapon || (weapon && weapon.categoryId !== category.id);
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
const uniqueProficiencyGroups = {};
|
||||
group.modifiers.forEach((modifier) => {
|
||||
const friendlySubTypeName = ModifierAccessors.getFriendlySubtypeName(modifier);
|
||||
if (friendlySubTypeName !== null) {
|
||||
if (!uniqueProficiencyGroups.hasOwnProperty(friendlySubTypeName)) {
|
||||
uniqueProficiencyGroups[friendlySubTypeName] = {
|
||||
label: friendlySubTypeName,
|
||||
sources: [],
|
||||
restriction: ModifierAccessors.getRestriction(modifier),
|
||||
};
|
||||
}
|
||||
uniqueProficiencyGroups[friendlySubTypeName].sources.push(EntityUtils.getDataOriginName(ModifierAccessors.getDataOrigin(modifier), undefined, true));
|
||||
}
|
||||
});
|
||||
group.custom.forEach((proficiency) => {
|
||||
const proficiencyName = proficiency.name;
|
||||
if (proficiencyName !== null) {
|
||||
if (!uniqueProficiencyGroups.hasOwnProperty(proficiencyName)) {
|
||||
uniqueProficiencyGroups[proficiencyName] = {
|
||||
label: proficiencyName,
|
||||
sources: [],
|
||||
};
|
||||
}
|
||||
if (proficiency.notes !== null) {
|
||||
uniqueProficiencyGroups[proficiencyName].sources.push(proficiency.notes);
|
||||
}
|
||||
}
|
||||
});
|
||||
const armorNameLookup = RuleDataUtils.getArmorNameLookup(ruleData);
|
||||
const weaponNameLookup = RuleDataUtils.getWeaponNameLookup(ruleData);
|
||||
const toolNameLookup = RuleDataUtils.getToolNameLookup(ruleData);
|
||||
group.values.forEach((charValue) => {
|
||||
let name = '';
|
||||
const valueId = ValueAccessors.getValueIntId(charValue);
|
||||
const notes = ValueAccessors.getNotes(charValue);
|
||||
if (valueId !== null) {
|
||||
switch (ValueAccessors.getTypeId(charValue)) {
|
||||
case AdjustmentTypeEnum.ARMOR_PROFICIENCY_LEVEL:
|
||||
name = armorNameLookup[valueId];
|
||||
break;
|
||||
case AdjustmentTypeEnum.WEAPON_PROFICIENCY_LEVEL:
|
||||
name = weaponNameLookup[valueId];
|
||||
break;
|
||||
case AdjustmentTypeEnum.TOOL_PROFICIENCY_LEVEL:
|
||||
name = toolNameLookup[valueId];
|
||||
break;
|
||||
case AdjustmentTypeEnum.LANGUAGE_PROFICIENCY_LEVEL:
|
||||
name = RuleDataUtils.getLanguageName(valueId, ruleData);
|
||||
break;
|
||||
default:
|
||||
// not implemented
|
||||
}
|
||||
}
|
||||
if (!uniqueProficiencyGroups.hasOwnProperty(name)) {
|
||||
uniqueProficiencyGroups[name] = {
|
||||
label: name,
|
||||
sources: [],
|
||||
};
|
||||
}
|
||||
uniqueProficiencyGroups[name].sources.push(notes ? notes : 'Custom');
|
||||
});
|
||||
return Object.assign(Object.assign({}, group), { modifierGroups: orderBy(HelperUtils.convertObjectToArray(uniqueProficiencyGroups), [
|
||||
(modifierGroup) => modifierGroup.label,
|
||||
]) });
|
||||
});
|
||||
return proficiencyGroups;
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param proficiencies
|
||||
*/
|
||||
export function generateCustomSkillProficiencies(proficiencies) {
|
||||
return proficiencies.filter(isCustomSkillProficiency);
|
||||
}
|
||||
@@ -0,0 +1,50 @@
|
||||
import { ClassAccessors } from '../../Class';
|
||||
import { ClassFeatureAccessors, ClassFeatureUtils } from '../../ClassFeature';
|
||||
import { PreferenceProgressionTypeEnum } from '../../Core';
|
||||
import { ItemUtils } from '../../Item';
|
||||
import { deriveCurrentLevelXp, deriveNextLevelXp, deriveXpLevel } from '../derivers';
|
||||
/**
|
||||
*
|
||||
* @param xp
|
||||
* @param preferences
|
||||
* @param totalClassLevel
|
||||
* @param ruleData
|
||||
*/
|
||||
export function generateCurrentLevel(xp, preferences, totalClassLevel, ruleData) {
|
||||
if (preferences !== null && preferences.progressionType === PreferenceProgressionTypeEnum.XP) {
|
||||
return deriveXpLevel(xp, ruleData);
|
||||
}
|
||||
return totalClassLevel;
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param classLevel
|
||||
* @param currentLevel
|
||||
* @param currentLevelXp
|
||||
* @param ruleData
|
||||
*/
|
||||
export function generateExperienceInfo(classLevel, currentLevel, currentLevelXp, ruleData) {
|
||||
return {
|
||||
classLevel,
|
||||
currentLevel,
|
||||
currentLevelXp,
|
||||
currentLevelStartingXp: deriveCurrentLevelXp(currentLevel, ruleData),
|
||||
nextLevelXp: deriveNextLevelXp(currentLevel, ruleData),
|
||||
};
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param classes
|
||||
* @param equippedItems
|
||||
*/
|
||||
export function generateMartialArtsLevelScale(classes, equippedItems) {
|
||||
if (equippedItems.filter(ItemUtils.isArmorContract).length) {
|
||||
return null;
|
||||
}
|
||||
const martialArtsClass = classes.find((charClass) => ClassAccessors.getClassFeatures(charClass).filter((feature) => ClassFeatureUtils.doesEnableMartialArts(feature)).length > 0);
|
||||
if (martialArtsClass) {
|
||||
const classFeature = ClassAccessors.getClassFeatures(martialArtsClass).find((feature) => ClassFeatureUtils.doesEnableMartialArts(feature));
|
||||
return classFeature ? ClassFeatureAccessors.getLevelScale(classFeature) : null;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
@@ -0,0 +1,102 @@
|
||||
import { groupBy } from 'lodash';
|
||||
import { AbilityStatEnum, SaveTypeEnum, SituationalBonusSavingThrowTypeEnum } from '../../Core';
|
||||
import { DiceAdjustmentRollTypeEnum, DiceAdjustmentTypeEnum, DiceDerivers } from '../../Dice';
|
||||
import { FormatUtils } from '../../Format';
|
||||
import { ModifierAccessors, ModifierDerivers, ModifierValidators } from '../../Modifier';
|
||||
import { RuleDataAccessors, RuleDataUtils } from '../../RuleData';
|
||||
import { deriveSaveTypeName } from '../derivers';
|
||||
/**
|
||||
*
|
||||
* @param highestShield
|
||||
* @param modifiers
|
||||
* @param ruleData
|
||||
*/
|
||||
export function generateSituationalBonusSavingThrows(highestShield, modifiers, ruleData) {
|
||||
const saves = [];
|
||||
RuleDataAccessors.getStats(ruleData).forEach((statData) => {
|
||||
if (statData.id === AbilityStatEnum.DEXTERITY) {
|
||||
const bonusShieldAcModifiers = modifiers.filter((modifier) => ModifierValidators.isBonusShieldAcOnDexSavesModifier(modifier));
|
||||
if (highestShield) {
|
||||
bonusShieldAcModifiers.forEach((modifier) => {
|
||||
saves.push({
|
||||
key: ModifierAccessors.getEntityKey(modifier),
|
||||
statId: statData.id,
|
||||
value: highestShield.armorClass,
|
||||
extra: modifier,
|
||||
type: SituationalBonusSavingThrowTypeEnum.MODIFIER,
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
return saves;
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param situationalBonusSavingThrows
|
||||
*/
|
||||
export function generateSituationalBonusSavingThrowsLookup(situationalBonusSavingThrows) {
|
||||
return groupBy(situationalBonusSavingThrows, 'statId');
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param type
|
||||
* @param modifier
|
||||
*/
|
||||
export function generateSavingThrowModifierSummary(type, modifier) {
|
||||
let tooltipParts = [];
|
||||
if (type === SaveTypeEnum.BONUS) {
|
||||
let valueTotal = ModifierAccessors.getValueTotal(modifier);
|
||||
if (valueTotal) {
|
||||
tooltipParts.push(FormatUtils.renderSignedNumber(valueTotal));
|
||||
}
|
||||
}
|
||||
tooltipParts.push(deriveSaveTypeName(type));
|
||||
let abilityName = ModifierDerivers.deriveSavingThrowModifierAbilityName(modifier);
|
||||
if (abilityName) {
|
||||
tooltipParts.push(`on ${abilityName}`);
|
||||
}
|
||||
else {
|
||||
if (!modifier.restriction) {
|
||||
tooltipParts.push('on saves');
|
||||
}
|
||||
}
|
||||
let restrictionText = ModifierAccessors.getRestriction(modifier);
|
||||
if (restrictionText) {
|
||||
tooltipParts.push(restrictionText);
|
||||
}
|
||||
return tooltipParts.join(' ');
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param adjustment
|
||||
* @param ruleData
|
||||
*/
|
||||
export function generateSavingThrowAdjustmentSummary(adjustment, ruleData) {
|
||||
let tooltipParts = [];
|
||||
if (adjustment.type === DiceAdjustmentTypeEnum.BONUS) {
|
||||
if (adjustment.amount) {
|
||||
tooltipParts.push(FormatUtils.renderSignedNumber(adjustment.amount));
|
||||
}
|
||||
}
|
||||
tooltipParts.push(DiceDerivers.deriveDiceAdjustmentTypeName(adjustment.type));
|
||||
let abilityName = null;
|
||||
if (adjustment.statId) {
|
||||
abilityName = RuleDataUtils.getStatNameById(adjustment.statId, ruleData);
|
||||
}
|
||||
if (abilityName) {
|
||||
tooltipParts.push(`on ${abilityName}`);
|
||||
}
|
||||
else if (adjustment.rollType === DiceAdjustmentRollTypeEnum.DEATH_SAVE) {
|
||||
tooltipParts.push('on death saves');
|
||||
}
|
||||
if (adjustment.restriction) {
|
||||
tooltipParts.push(adjustment.restriction);
|
||||
}
|
||||
else {
|
||||
if (adjustment.rollType === DiceAdjustmentRollTypeEnum.SAVE) {
|
||||
tooltipParts.push('on saves');
|
||||
}
|
||||
}
|
||||
return tooltipParts.join(' ');
|
||||
}
|
||||
@@ -0,0 +1,124 @@
|
||||
import { keyBy } from 'lodash';
|
||||
import { SenseTypeEnum } from '../../Core';
|
||||
import { ModifierDerivers, ModifierValidators } from '../../Modifier';
|
||||
import { RuleDataUtils } from '../../RuleData';
|
||||
import { derivePassiveInsight, derivePassiveInvestigation, derivePassivePerception } from '../derivers';
|
||||
/**
|
||||
*
|
||||
* @param senseKey
|
||||
* @param modifiers
|
||||
* @param abilityLookup
|
||||
* @param customSenseLookup
|
||||
*/
|
||||
export function getSenseDistanceByKeyBonusTakeHighest(senseKey, modifiers, abilityLookup, customSenseLookup) {
|
||||
const customSenseData = customSenseLookup[senseKey];
|
||||
if (customSenseData) {
|
||||
const customDistance = customSenseData.distance;
|
||||
if (customDistance !== null) {
|
||||
return customDistance;
|
||||
}
|
||||
}
|
||||
const typeModifierKey = RuleDataUtils.getSenseTypeModifierKey(senseKey);
|
||||
const setSenseModifiers = modifiers.filter((modifier) => ModifierValidators.isValidSetSenseModifier(modifier, typeModifierKey));
|
||||
if (setSenseModifiers.length) {
|
||||
return ModifierDerivers.deriveHighestModifierValue(setSenseModifiers, abilityLookup);
|
||||
}
|
||||
const baseSenseModifiers = modifiers.filter((modifier) => ModifierValidators.isValidSetBaseSenseModifier(modifier, typeModifierKey));
|
||||
const highestBaseSenseModifierValue = ModifierDerivers.deriveHighestModifierValue(baseSenseModifiers, abilityLookup);
|
||||
const bonusSenseModifiers = modifiers.filter((modifier) => ModifierValidators.isValidSenseModifier(modifier, typeModifierKey) ||
|
||||
ModifierValidators.isValidBonusSenseModifier(modifier, typeModifierKey));
|
||||
const highestBonusSenseModifierValue = ModifierDerivers.deriveHighestModifierValue(bonusSenseModifiers, abilityLookup);
|
||||
return highestBaseSenseModifierValue + highestBonusSenseModifierValue;
|
||||
}
|
||||
/**
|
||||
* @deprecated use getSenseDistanceByKeyBonusTakeHighest
|
||||
*/
|
||||
export const getSenseDistanceByKey = getSenseDistanceByKeyBonusTakeHighest;
|
||||
/**
|
||||
*
|
||||
* @param senseKey
|
||||
* @param modifiers
|
||||
* @param abilityLookup
|
||||
* @param customSenseLookup
|
||||
*/
|
||||
export function getSenseDistanceByKeyBonusTakeAll(senseKey, modifiers, abilityLookup, customSenseLookup) {
|
||||
const customSenseData = customSenseLookup[senseKey];
|
||||
if (customSenseData) {
|
||||
const customDistance = customSenseData.distance;
|
||||
if (customDistance !== null) {
|
||||
return customDistance;
|
||||
}
|
||||
}
|
||||
const typeModifierKey = RuleDataUtils.getSenseTypeModifierKey(senseKey);
|
||||
const setSenseModifiers = modifiers.filter((modifier) => ModifierValidators.isValidSetSenseModifier(modifier, typeModifierKey));
|
||||
if (setSenseModifiers.length) {
|
||||
return ModifierDerivers.deriveHighestModifierValue(setSenseModifiers, abilityLookup);
|
||||
}
|
||||
const baseSenseModifiers = modifiers.filter((modifier) => ModifierValidators.isValidSetBaseSenseModifier(modifier, typeModifierKey));
|
||||
const highestBaseSenseModifierValue = ModifierDerivers.deriveHighestModifierValue(baseSenseModifiers, abilityLookup);
|
||||
const bonusSenseModifiers = modifiers.filter((modifier) => ModifierValidators.isValidSenseModifier(modifier, typeModifierKey) ||
|
||||
ModifierValidators.isValidBonusSenseModifier(modifier, typeModifierKey));
|
||||
const totalBonusSenseModifierValue = bonusSenseModifiers.reduce((total, modifier) => total + ModifierDerivers.getModifierValue(modifier, abilityLookup), 0);
|
||||
return highestBaseSenseModifierValue + totalBonusSenseModifierValue;
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param modifiers
|
||||
* @param abilityLookup
|
||||
* @param customSenseLookup
|
||||
*/
|
||||
export function generateSenseInfo(modifiers, abilityLookup, customSenseLookup) {
|
||||
return {
|
||||
[SenseTypeEnum.BLINDSIGHT]: getSenseDistanceByKeyBonusTakeHighest(SenseTypeEnum.BLINDSIGHT, modifiers, abilityLookup, customSenseLookup),
|
||||
[SenseTypeEnum.DARKVISION]: getSenseDistanceByKeyBonusTakeAll(SenseTypeEnum.DARKVISION, modifiers, abilityLookup, customSenseLookup),
|
||||
[SenseTypeEnum.PASSIVE_PERCEPTION]: getSenseDistanceByKeyBonusTakeHighest(SenseTypeEnum.PASSIVE_PERCEPTION, modifiers, abilityLookup, customSenseLookup),
|
||||
[SenseTypeEnum.TREMORSENSE]: getSenseDistanceByKeyBonusTakeHighest(SenseTypeEnum.TREMORSENSE, modifiers, abilityLookup, customSenseLookup),
|
||||
[SenseTypeEnum.TRUESIGHT]: getSenseDistanceByKeyBonusTakeHighest(SenseTypeEnum.TRUESIGHT, modifiers, abilityLookup, customSenseLookup),
|
||||
};
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param skills
|
||||
* @param modifiers
|
||||
* @param abilityLookup
|
||||
* @param overrideValue
|
||||
*/
|
||||
export function generatePassivePerception(skills, modifiers, abilityLookup, overrideValue) {
|
||||
if (overrideValue !== null) {
|
||||
return overrideValue;
|
||||
}
|
||||
return derivePassivePerception(skills, modifiers, abilityLookup);
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param skills
|
||||
* @param modifiers
|
||||
* @param abilityLookup
|
||||
* @param overrideValue
|
||||
*/
|
||||
export function generatePassiveInvestigation(skills, modifiers, abilityLookup, overrideValue) {
|
||||
if (overrideValue !== null) {
|
||||
return overrideValue;
|
||||
}
|
||||
return derivePassiveInvestigation(skills, modifiers, abilityLookup);
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param skills
|
||||
* @param modifiers
|
||||
* @param abilityLookup
|
||||
* @param overrideValue
|
||||
*/
|
||||
export function generatePassiveInsight(skills, modifiers, abilityLookup, overrideValue) {
|
||||
if (overrideValue !== null) {
|
||||
return overrideValue;
|
||||
}
|
||||
return derivePassiveInsight(skills, modifiers, abilityLookup);
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param senses
|
||||
*/
|
||||
export function generateCustomSenseLookup(senses) {
|
||||
return keyBy(senses, 'senseId');
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
import { CampaignSettingAccessors } from '../../CampaignSetting';
|
||||
import { FeatureFlagEnum, FeatureFlagInfoUtils } from '../../FeatureFlagInfo';
|
||||
import { RuleDataAccessors } from '../../RuleData';
|
||||
/**
|
||||
*
|
||||
* @param activeSourceCategories
|
||||
* @param campaignSetting
|
||||
* @param ruleData
|
||||
*/
|
||||
export function generateActiveSources(activeSourceCategories, customCampaignSetting, campaignSetting, ruleData, featureFlagInfo) {
|
||||
// console.log('customCampaignSetting', customCampaignSetting);
|
||||
const isCampaignSettingsActive = FeatureFlagInfoUtils.getFeatureFlagInfoValue(FeatureFlagEnum.RELEASE_GATE_CAMPAIGN_SETTINGS, featureFlagInfo);
|
||||
const sourceData = RuleDataAccessors.getSourceData(ruleData);
|
||||
let campaignSettingSources = [];
|
||||
if (customCampaignSetting) {
|
||||
if (customCampaignSetting.campaignSettingId) {
|
||||
campaignSettingSources = CampaignSettingAccessors.getAvailableSourceIds(campaignSetting[0]);
|
||||
}
|
||||
else {
|
||||
campaignSettingSources = CampaignSettingAccessors.getEnabledSourceIds(customCampaignSetting);
|
||||
}
|
||||
}
|
||||
// Return the Campaign Setting sources if the feature is enabled and they have been set
|
||||
if (isCampaignSettingsActive && (campaignSettingSources === null || campaignSettingSources === void 0 ? void 0 : campaignSettingSources.length)) {
|
||||
return sourceData.filter((source) => campaignSettingSources === null || campaignSettingSources === void 0 ? void 0 : campaignSettingSources.includes(source.id));
|
||||
}
|
||||
// Otherwise return the sources mapped to the specified Source Category
|
||||
return sourceData.filter((source) => activeSourceCategories.includes(source.sourceCategoryId));
|
||||
}
|
||||
@@ -0,0 +1,138 @@
|
||||
import { keyBy } from 'lodash';
|
||||
import { SpeedMovementKeyEnum, WeightSpeedTypeEnum } from '../../Core';
|
||||
import { ModifierDerivers, ModifierValidators } from '../../Modifier';
|
||||
import { RaceAccessors } from '../../Race';
|
||||
import { RuleDataUtils } from '../../RuleData';
|
||||
/**
|
||||
*
|
||||
* @param speedMovementKey
|
||||
* @param baseWeightSpeedLookup
|
||||
* @param weightSpeedType
|
||||
* @param mirrorSpeed
|
||||
* @param armorSpeedAdjustment
|
||||
* @param modifiers
|
||||
* @param customSpeedLookup
|
||||
* @param equippedArmor
|
||||
*/
|
||||
export function generateSpeedInfoByKey(speedMovementKey, baseWeightSpeedLookup, weightSpeedType, mirrorSpeed, armorSpeedAdjustment, modifiers, customSpeedLookup, equippedArmor) {
|
||||
if (baseWeightSpeedLookup === null) {
|
||||
return null;
|
||||
}
|
||||
const speedReductionRemoveModifiers = modifiers.filter((modifier) => ModifierValidators.isSpeedReductionRemoveModifier(modifier));
|
||||
const hasSpeedReductionRemove = speedReductionRemoveModifiers.length > 0;
|
||||
// set up initial speed
|
||||
let finalSpeed = baseWeightSpeedLookup[speedMovementKey];
|
||||
// calc based on standard modifiers
|
||||
const setModifiers = modifiers.filter((modifier) => ModifierValidators.isValidSetSpeedModifier(modifier, speedMovementKey));
|
||||
if (setModifiers.length) {
|
||||
finalSpeed = ModifierDerivers.deriveHighestModifierValue(setModifiers);
|
||||
}
|
||||
else {
|
||||
const innateSetModifiers = modifiers.filter((modifier) => ModifierValidators.isValidSetInnateSpeedModifier(modifier, speedMovementKey));
|
||||
let baseMovementSpeed = baseWeightSpeedLookup[speedMovementKey];
|
||||
if (baseMovementSpeed === null) {
|
||||
baseMovementSpeed = 0;
|
||||
}
|
||||
const baseSpeed = Math.max(baseMovementSpeed, ModifierDerivers.deriveHighestModifierValue(innateSetModifiers));
|
||||
if (baseSpeed === 0) {
|
||||
finalSpeed = baseSpeed;
|
||||
}
|
||||
else {
|
||||
const speedAdjustmentModifiers = modifiers.filter((modifier) => ModifierValidators.isValidBonusSpeedModifier(modifier, speedMovementKey));
|
||||
const speedAdjustmentModifierTotal = ModifierDerivers.sumModifiers(speedAdjustmentModifiers);
|
||||
let unarmoredBonus = 0;
|
||||
if (!equippedArmor) {
|
||||
const unarmoredBonusModifiers = modifiers.filter((modifier) => ModifierValidators.isBonusUnarmoredMovementModifier(modifier));
|
||||
unarmoredBonus = ModifierDerivers.sumModifiers(unarmoredBonusModifiers);
|
||||
}
|
||||
finalSpeed = baseSpeed + speedAdjustmentModifierTotal + armorSpeedAdjustment + unarmoredBonus;
|
||||
}
|
||||
}
|
||||
// check if there are any speed reductions
|
||||
if (!hasSpeedReductionRemove && finalSpeed !== 0) {
|
||||
let speed = finalSpeed;
|
||||
if (weightSpeedType === WeightSpeedTypeEnum.ENCUMBERED) {
|
||||
speed -= 10;
|
||||
}
|
||||
else if (weightSpeedType === WeightSpeedTypeEnum.HEAVILY_ENCUMBERED) {
|
||||
speed -= 20;
|
||||
}
|
||||
finalSpeed = Math.max(0, speed);
|
||||
}
|
||||
// check for custom speed overrides
|
||||
const movementId = RuleDataUtils.getMovementTypeBySpeedMovementKey(speedMovementKey);
|
||||
if (movementId !== null) {
|
||||
const speed = customSpeedLookup[movementId];
|
||||
if (speed && speed.distance !== null) {
|
||||
finalSpeed = speed.distance;
|
||||
}
|
||||
}
|
||||
// Have to do another pass to check if any of the speed set modifiers are null, if so use the mirror speed (most likely walking)
|
||||
if (mirrorSpeed !== null) {
|
||||
const speedSetModifiers = modifiers.filter((modifier) => ModifierValidators.isValidSetInnateSpeedModifier(modifier, speedMovementKey));
|
||||
const nullSpeedSetModifiers = speedSetModifiers.filter((modifier) => ModifierDerivers.deriveFixedModifierValue(modifier, null) === null);
|
||||
if (nullSpeedSetModifiers.length) {
|
||||
finalSpeed = mirrorSpeed;
|
||||
}
|
||||
}
|
||||
return finalSpeed;
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param weightSpeeds
|
||||
* @param weightSpeedType
|
||||
* @param armorSpeedAdjustment
|
||||
* @param modifiers
|
||||
* @param customSpeedLookup
|
||||
* @param equippedArmor
|
||||
*/
|
||||
export function generateSpeedInfo(weightSpeeds, weightSpeedType, armorSpeedAdjustment, modifiers, customSpeedLookup, equippedArmor) {
|
||||
const baseWeightSpeedLookup = weightSpeeds ? weightSpeeds[WeightSpeedTypeEnum.NORMAL] : null;
|
||||
const walkingSpeed = generateSpeedInfoByKey(SpeedMovementKeyEnum.WALK, baseWeightSpeedLookup, weightSpeedType, null, armorSpeedAdjustment, modifiers, customSpeedLookup, equippedArmor);
|
||||
return {
|
||||
[SpeedMovementKeyEnum.WALK]: walkingSpeed,
|
||||
[SpeedMovementKeyEnum.FLY]: generateSpeedInfoByKey(SpeedMovementKeyEnum.FLY, baseWeightSpeedLookup, weightSpeedType, walkingSpeed, armorSpeedAdjustment, modifiers, customSpeedLookup, equippedArmor),
|
||||
[SpeedMovementKeyEnum.CLIMB]: generateSpeedInfoByKey(SpeedMovementKeyEnum.CLIMB, baseWeightSpeedLookup, weightSpeedType, walkingSpeed, armorSpeedAdjustment, modifiers, customSpeedLookup, equippedArmor),
|
||||
[SpeedMovementKeyEnum.BURROW]: generateSpeedInfoByKey(SpeedMovementKeyEnum.BURROW, baseWeightSpeedLookup, weightSpeedType, walkingSpeed, armorSpeedAdjustment, modifiers, customSpeedLookup, equippedArmor),
|
||||
[SpeedMovementKeyEnum.SWIM]: generateSpeedInfoByKey(SpeedMovementKeyEnum.SWIM, baseWeightSpeedLookup, weightSpeedType, walkingSpeed, armorSpeedAdjustment, modifiers, customSpeedLookup, equippedArmor),
|
||||
};
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param speedInfo
|
||||
* @param customSpeedLookup
|
||||
* @param ruleData
|
||||
*/
|
||||
export function generateSpeeds(speedInfo, customSpeedLookup, ruleData) {
|
||||
return Object.keys(speedInfo).map((movementKey, idx) => {
|
||||
const movementAmount = speedInfo[movementKey];
|
||||
let source = '';
|
||||
const movementType = RuleDataUtils.getMovementTypeBySpeedMovementKey(movementKey);
|
||||
if (movementType && customSpeedLookup[movementType]) {
|
||||
source = customSpeedLookup[movementType].source;
|
||||
}
|
||||
return {
|
||||
distance: movementAmount,
|
||||
type: movementType,
|
||||
source,
|
||||
name: RuleDataUtils.getMovementDescription(movementType, ruleData),
|
||||
};
|
||||
});
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param race
|
||||
*/
|
||||
export function generateWeightSpeeds(race) {
|
||||
if (race === null) {
|
||||
return null;
|
||||
}
|
||||
return RaceAccessors.getWeightSpeeds(race);
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param speeds
|
||||
*/
|
||||
export function generateCustomSpeedLookup(speeds) {
|
||||
return keyBy(speeds, 'movementId');
|
||||
}
|
||||
@@ -0,0 +1,118 @@
|
||||
import { AbilityAccessors } from '../../Ability';
|
||||
import { ClassAccessors } from '../../Class';
|
||||
import { ModifierDerivers, ModifierValidators } from '../../Modifier';
|
||||
/**
|
||||
*
|
||||
* @param modifiers
|
||||
* @param xpInfo
|
||||
* @param proficiencyBonus
|
||||
* @param abilityLookup
|
||||
* @param spellListDataOriginLookup
|
||||
*/
|
||||
export function generateOverallSpellInfo(modifiers, xpInfo, proficiencyBonus, abilityLookup, spellListDataOriginLookup) {
|
||||
const bonusCantripDamageModifiers = modifiers.filter((modifier) => ModifierValidators.isBonusCantripDamage(modifier));
|
||||
const bonusCantripDamageModifierTotal = ModifierDerivers.sumModifiers(bonusCantripDamageModifiers, abilityLookup);
|
||||
return {
|
||||
bonusCantripDamage: bonusCantripDamageModifierTotal,
|
||||
characterLevel: xpInfo.currentLevel,
|
||||
proficiencyBonus,
|
||||
abilityLookup,
|
||||
modifiers,
|
||||
spellListDataOriginLookup,
|
||||
};
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param classes
|
||||
* @param characterLevel
|
||||
* @param spellSlots
|
||||
* @param pactMagicSlots
|
||||
* @param castableSpellLevels
|
||||
* @param castablePactMagicLevels
|
||||
* @param availableSpellLevels
|
||||
* @param availablePactMagicLevels
|
||||
* @param maxLevel
|
||||
* @param abilityLookup
|
||||
* @param classSpellInfoLookup
|
||||
*/
|
||||
export function generateSpellCasterInfo(classes, characterLevel, spellSlots, pactMagicSlots, castableSpellLevels, castablePactMagicLevels, availableSpellLevels, availablePactMagicLevels, maxLevel, abilityLookup, classSpellInfoLookup) {
|
||||
var _a, _b, _c, _d;
|
||||
const castingInfo = {
|
||||
modifiers: [],
|
||||
spellAttacks: [],
|
||||
saveDcs: [],
|
||||
};
|
||||
for (let i = 0; i < classes.length; i++) {
|
||||
const charClass = classes[i];
|
||||
const spellRules = ClassAccessors.getSpellRules(charClass);
|
||||
if (spellRules === null) {
|
||||
continue;
|
||||
}
|
||||
let modifier = 0;
|
||||
if (spellRules.spellcastingAbilityStatId) {
|
||||
modifier = AbilityAccessors.getModifier(abilityLookup[spellRules.spellcastingAbilityStatId]);
|
||||
}
|
||||
const classSpellInfo = classSpellInfoLookup[ClassAccessors.getId(charClass)];
|
||||
const spellAttack = classSpellInfo.toHit;
|
||||
const saveDc = classSpellInfo.spellSaveDc;
|
||||
if (ClassAccessors.isSpellcastingActive(charClass) || ClassAccessors.isPactMagicActive(charClass)) {
|
||||
const existingModifierIndex = castingInfo.modifiers.findIndex((existingModifier) => existingModifier.value === modifier);
|
||||
if (existingModifierIndex > -1) {
|
||||
castingInfo.modifiers[existingModifierIndex].sources.push(charClass);
|
||||
}
|
||||
else {
|
||||
castingInfo.modifiers.push({
|
||||
value: modifier,
|
||||
sources: [charClass],
|
||||
});
|
||||
}
|
||||
const existingSpellAttackIndex = castingInfo.spellAttacks.findIndex((existingSpellAttack) => existingSpellAttack.value === spellAttack);
|
||||
if (existingSpellAttackIndex > -1) {
|
||||
castingInfo.spellAttacks[existingSpellAttackIndex].sources.push(charClass);
|
||||
}
|
||||
else {
|
||||
castingInfo.spellAttacks.push({
|
||||
value: spellAttack,
|
||||
sources: [charClass],
|
||||
});
|
||||
}
|
||||
const existingSaveDcIndex = castingInfo.saveDcs.findIndex((existingSaveDc) => existingSaveDc.value === saveDc);
|
||||
if (existingSaveDcIndex > -1) {
|
||||
castingInfo.saveDcs[existingSaveDcIndex].sources.push(charClass);
|
||||
}
|
||||
else {
|
||||
castingInfo.saveDcs.push({
|
||||
value: saveDc,
|
||||
sources: [charClass],
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
const firstAvailableSpellSlotLevel = (_a = availableSpellLevels.sort()[0]) !== null && _a !== void 0 ? _a : null;
|
||||
const firstAvailablePactMagicSlotLevel = (_b = availablePactMagicLevels.sort()[0]) !== null && _b !== void 0 ? _b : null;
|
||||
const lastAvailableSpellSlotLevel = (_c = availableSpellLevels.sort().reverse()[0]) !== null && _c !== void 0 ? _c : null;
|
||||
const lastAvailablePactMagicSlotLevel = (_d = availablePactMagicLevels.sort().reverse()[0]) !== null && _d !== void 0 ? _d : null;
|
||||
return {
|
||||
characterLevel,
|
||||
spellSlots,
|
||||
pactMagicSlots,
|
||||
castableSpellLevels,
|
||||
castablePactMagicLevels,
|
||||
availableSpellLevels,
|
||||
availablePactMagicLevels,
|
||||
firstAvailableSpellSlotLevel,
|
||||
firstAvailablePactMagicSlotLevel,
|
||||
lastAvailableSpellSlotLevel,
|
||||
lastAvailablePactMagicSlotLevel,
|
||||
maxLevel,
|
||||
castingInfo,
|
||||
};
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param classSpellLists
|
||||
* @param characterSpells
|
||||
*/
|
||||
export function generateHasSpells(classSpellLists, characterSpells) {
|
||||
return !!(classSpellLists.length || characterSpells.length);
|
||||
}
|
||||
@@ -0,0 +1,106 @@
|
||||
import { ContainerAccessors, ContainerTypeEnum } from '../../Container';
|
||||
import { ItemDerivers, ItemValidators } from '../../Item';
|
||||
import { RuleDataAccessors } from '../../RuleData';
|
||||
/**
|
||||
*
|
||||
* @param currencies
|
||||
* @param preferences
|
||||
* @param ruleData
|
||||
*/
|
||||
export function generateCoinWeight(currencies, preferences, ruleData) {
|
||||
let weight = 0;
|
||||
if (currencies === null) {
|
||||
return weight;
|
||||
}
|
||||
if (preferences !== null && !preferences.ignoreCoinWeight) {
|
||||
RuleDataAccessors.getCurrencyData(ruleData).forEach((currencyInfo) => {
|
||||
if (currencyInfo.name !== null) {
|
||||
const heldCurrencyAmount = currencies[currencyInfo.name.toLowerCase()];
|
||||
if (heldCurrencyAmount) {
|
||||
weight += currencyInfo.weight * heldCurrencyAmount;
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
return weight;
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param allItems
|
||||
* @param customItems
|
||||
* @returns {number}
|
||||
*/
|
||||
export function generateItemWeight(allItems, customItems) {
|
||||
return ItemDerivers.deriveItemsWeightTotal(allItems) + ItemDerivers.deriveItemsWeightTotal(customItems);
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param characterContainers
|
||||
* @param partyContainers
|
||||
* @param characterId
|
||||
* @returns {number}
|
||||
*/
|
||||
export function generateContainerItemWeight(characterContainers, partyContainers, characterId) {
|
||||
return [...characterContainers, ...partyContainers].reduce((acc, container) => {
|
||||
const type = ContainerAccessors.getContainerType(container);
|
||||
const isEquipped = ContainerAccessors.isEquipped(container);
|
||||
if (type === ContainerTypeEnum.ITEM && isEquipped) {
|
||||
// A container item
|
||||
const containerItem = ContainerAccessors.getItem(container);
|
||||
// Ignore containers equipped to someone else in the party inventory
|
||||
if (containerItem && ItemValidators.isEquippedToCurrentCharacter(containerItem, characterId)) {
|
||||
const appliedWeight = ContainerAccessors.getWeightInfo(container).itemApplied;
|
||||
acc += appliedWeight;
|
||||
}
|
||||
}
|
||||
if (type === ContainerTypeEnum.CHARACTER || type === ContainerTypeEnum.CAMPAIGN) {
|
||||
// Based on the generateContainerWeightInfo generator,
|
||||
// when looking at the top level party inventory,
|
||||
// applied weight only includes items that are equipped to you.
|
||||
const appliedWeight = ContainerAccessors.getWeightInfo(container).itemApplied;
|
||||
acc += appliedWeight;
|
||||
}
|
||||
return acc;
|
||||
}, 0);
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param characterContainers
|
||||
* @param partyContainers
|
||||
* @param characterId
|
||||
* @param preferences
|
||||
* @returns {number}
|
||||
*/
|
||||
export function generateCointainerCoinWeight(characterContainers, partyContainers, characterId, preferences) {
|
||||
// 0 when ignoring coin weight
|
||||
if (!preferences || preferences.ignoreCoinWeight) {
|
||||
return 0;
|
||||
}
|
||||
// Whether cointainers are enabled or not, the process is the same.
|
||||
// All the coins will be in the top level character container if cointainers are off.
|
||||
return [...characterContainers, ...partyContainers].reduce((acc, container) => {
|
||||
const type = ContainerAccessors.getContainerType(container);
|
||||
const isEquipped = ContainerAccessors.isEquipped(container);
|
||||
if (type === ContainerTypeEnum.ITEM && isEquipped) {
|
||||
const containerItem = ContainerAccessors.getItem(container);
|
||||
if (containerItem && ItemValidators.isEquippedToCurrentCharacter(containerItem, characterId)) {
|
||||
const appliedWeight = ContainerAccessors.getWeightInfo(container).coinApplied;
|
||||
acc += appliedWeight;
|
||||
}
|
||||
}
|
||||
if (type === ContainerTypeEnum.CHARACTER || type === ContainerTypeEnum.CAMPAIGN) {
|
||||
const appliedWeight = ContainerAccessors.getWeightInfo(container).coinApplied;
|
||||
acc += appliedWeight;
|
||||
}
|
||||
return acc;
|
||||
}, 0);
|
||||
}
|
||||
/**
|
||||
* //TODO could include suppliers data
|
||||
* @param itemWeight
|
||||
* @param coinWeight
|
||||
*/
|
||||
export function generateTotalWeight(itemWeight, coinWeight) {
|
||||
// When coin weight is ignored, coinWeight will be 0.
|
||||
return itemWeight + coinWeight;
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
/**
|
||||
*
|
||||
* @param baseHp
|
||||
* @param overrideHp
|
||||
* @param bonusHp
|
||||
* @param tempHp
|
||||
* @param removedHp
|
||||
* https://github.com/reduxjs/reselect/issues/378
|
||||
*/
|
||||
export function hack__generateHitPointParts(baseHp, overrideHp, bonusHp, tempHp, removedHp) {
|
||||
return {
|
||||
baseHp,
|
||||
overrideHp,
|
||||
bonusHp,
|
||||
tempHp,
|
||||
removedHp,
|
||||
};
|
||||
}
|
||||
export function hack__generateSpecialWeaponPropertiesEnabled(hexWeaponEnabled, pactWeaponEnabled, improvedPactWeaponEnabled, dedicatedWeaponEnabled) {
|
||||
return {
|
||||
hexWeaponEnabled,
|
||||
pactWeaponEnabled,
|
||||
improvedPactWeaponEnabled,
|
||||
dedicatedWeaponEnabled,
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
import * as CharacterConstants from './constants';
|
||||
import * as CharacterDerivers from './derivers';
|
||||
import * as CharacterGenerators from './generators';
|
||||
import * as CharacterHacks from './hacks';
|
||||
import * as CharacterTypings from './typings';
|
||||
import * as CharacterUtils from './utils';
|
||||
import * as CharacterValidators from './validators';
|
||||
export * from './typings';
|
||||
export * from './constants';
|
||||
export { CharacterDerivers, CharacterValidators, CharacterGenerators, CharacterUtils, CharacterHacks };
|
||||
export default Object.assign(Object.assign(Object.assign(Object.assign(Object.assign(Object.assign(Object.assign({}, CharacterConstants), CharacterDerivers), CharacterValidators), CharacterGenerators), CharacterTypings), CharacterUtils), CharacterHacks);
|
||||
@@ -0,0 +1,51 @@
|
||||
/**
|
||||
*
|
||||
* @param preKey
|
||||
*/
|
||||
export function getPreferenceKey(preKey) {
|
||||
switch (preKey) {
|
||||
case 'abilityScoreDisplayType':
|
||||
return preKey;
|
||||
case 'enableDarkMode':
|
||||
return preKey;
|
||||
case 'enableContainerCurrency':
|
||||
return preKey;
|
||||
case 'enableOptionalClassFeatures':
|
||||
return preKey;
|
||||
case 'enableOptionalOrigins':
|
||||
return preKey;
|
||||
case 'encumbranceType':
|
||||
return preKey;
|
||||
case 'enforceFeatRules':
|
||||
return preKey;
|
||||
case 'enforceMulticlassRules':
|
||||
return preKey;
|
||||
case 'hitPointType':
|
||||
return preKey;
|
||||
case 'ignoreCoinWeight':
|
||||
return preKey;
|
||||
case 'primaryMovement':
|
||||
return preKey;
|
||||
case 'primarySense':
|
||||
return preKey;
|
||||
case 'privacyType':
|
||||
return preKey;
|
||||
case 'progressionType':
|
||||
return preKey;
|
||||
case 'sharingType':
|
||||
return preKey;
|
||||
case 'showCompanions':
|
||||
return preKey;
|
||||
case 'showScaledSpells':
|
||||
return preKey;
|
||||
case 'showUnarmedStrike':
|
||||
return preKey;
|
||||
case 'showWildShape':
|
||||
return preKey;
|
||||
case 'useHomebrewContent':
|
||||
return preKey;
|
||||
default:
|
||||
//not implemented
|
||||
}
|
||||
return null;
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
import { groupBy } from 'lodash';
|
||||
import { EntityUtils } from '../../Entity';
|
||||
/**
|
||||
*
|
||||
* @param defenseAdjustments
|
||||
*/
|
||||
export function groupDefenseAdjustments(defenseAdjustments) {
|
||||
const groupedDefenseAdjustments = [];
|
||||
const keyedGroupDefenseAdjustments = groupBy(defenseAdjustments, 'name');
|
||||
Object.keys(keyedGroupDefenseAdjustments).forEach((groupKey) => {
|
||||
const damageAdjustments = keyedGroupDefenseAdjustments[groupKey];
|
||||
groupedDefenseAdjustments.push({
|
||||
name: groupKey,
|
||||
sources: damageAdjustments
|
||||
.map((adjustment) => {
|
||||
return EntityUtils.getDataOriginName(adjustment.dataOrigin, undefined, true);
|
||||
})
|
||||
.sort(),
|
||||
hasCustom: !!damageAdjustments.find((adjustment) => adjustment.isCustom),
|
||||
damageAdjustments,
|
||||
});
|
||||
});
|
||||
return groupedDefenseAdjustments;
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
/**
|
||||
*
|
||||
* @param hitPointInfo
|
||||
* @param hpDiff
|
||||
*/
|
||||
export function calculateHitPoints(hitPointInfo, hpDiff) {
|
||||
let newTemp;
|
||||
let newHp;
|
||||
const hpTemp = hitPointInfo.tempHp ? hitPointInfo.tempHp : 0;
|
||||
if (hpDiff < 0) {
|
||||
newTemp = Math.max(hpTemp + hpDiff, 0);
|
||||
if (Math.abs(hpDiff) > hpTemp) {
|
||||
newHp = hitPointInfo.remainingHp + (hpTemp + hpDiff);
|
||||
}
|
||||
else {
|
||||
newHp = hitPointInfo.remainingHp;
|
||||
}
|
||||
}
|
||||
else {
|
||||
newTemp = hitPointInfo.tempHp;
|
||||
newHp = Math.min(hitPointInfo.remainingHp + hpDiff, hitPointInfo.totalHp);
|
||||
}
|
||||
newHp = Math.max(0, newHp);
|
||||
const newRemovedHp = hitPointInfo.totalHp - newHp;
|
||||
return {
|
||||
newTemp,
|
||||
newHp,
|
||||
newRemovedHp,
|
||||
startHp: hitPointInfo.remainingHp,
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,118 @@
|
||||
import { CreatureSizeEnum } from '../../Core';
|
||||
import { ModifierAccessors, ModifierDerivers, ModifierSubTypeEnum, ModifierValidators } from '../../Modifier';
|
||||
/**
|
||||
*
|
||||
* @param sizeId
|
||||
* @param modifiers
|
||||
*/
|
||||
export function getEncumbranceSize(sizeId, modifiers) {
|
||||
let encumbranceSize = sizeId;
|
||||
let isSmallerOverride = false;
|
||||
let isLargerOverride = false;
|
||||
const carryingCapacitySizeModifiers = modifiers.filter((modifier) => ModifierValidators.isCarryingCapacitySizeModifier(modifier));
|
||||
carryingCapacitySizeModifiers.forEach((modifier) => {
|
||||
switch (ModifierAccessors.getSubType(modifier)) {
|
||||
case ModifierSubTypeEnum.TINY:
|
||||
isSmallerOverride = true;
|
||||
break;
|
||||
case ModifierSubTypeEnum.LARGE:
|
||||
case ModifierSubTypeEnum.HUGE:
|
||||
case ModifierSubTypeEnum.GARGANTUAN:
|
||||
isLargerOverride = true;
|
||||
break;
|
||||
default:
|
||||
// not implemented
|
||||
}
|
||||
});
|
||||
if (isSmallerOverride) {
|
||||
encumbranceSize = CreatureSizeEnum.TINY;
|
||||
}
|
||||
if (isLargerOverride) {
|
||||
encumbranceSize = CreatureSizeEnum.LARGE;
|
||||
}
|
||||
return encumbranceSize;
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param value
|
||||
* @param encumbranceSizeId
|
||||
*/
|
||||
export function getEncumbranceSizeScaledValue(value, encumbranceSizeId) {
|
||||
switch (encumbranceSizeId) {
|
||||
case CreatureSizeEnum.TINY:
|
||||
return value / 2;
|
||||
case CreatureSizeEnum.LARGE:
|
||||
case CreatureSizeEnum.HUGE:
|
||||
case CreatureSizeEnum.GARGANTUAN:
|
||||
return value * 2;
|
||||
default:
|
||||
// not implemented
|
||||
}
|
||||
return value;
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param value
|
||||
* @param modifiers
|
||||
*/
|
||||
export function getCarryCapacityModifierScaledValue(value, modifiers) {
|
||||
// get weight multiplied by any multipliers, positive is times, negative is division (ex: 2 is times two, -3 is divide by 3)
|
||||
const carryingCapacityMultiplierModifiers = modifiers.filter((modifier) => ModifierValidators.isCarringCapacityMultiplierModifier(modifier));
|
||||
const highestCarryingCapacityMultiplier = ModifierDerivers.deriveHighestModifierValue(carryingCapacityMultiplierModifiers);
|
||||
if (highestCarryingCapacityMultiplier) {
|
||||
if (highestCarryingCapacityMultiplier < 0) {
|
||||
return (value /= Math.abs(highestCarryingCapacityMultiplier));
|
||||
}
|
||||
return (value *= highestCarryingCapacityMultiplier);
|
||||
}
|
||||
return value;
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param strengthScale
|
||||
* @param strScore
|
||||
* @param size
|
||||
* @param modifiers
|
||||
*/
|
||||
export function getStrengthScaledCarryCapacity(strengthScale, strScore, size, modifiers) {
|
||||
const sizeId = size ? size.id : null;
|
||||
const baseWeight = strScore * strengthScale;
|
||||
const encumbranceSize = getEncumbranceSize(sizeId, modifiers);
|
||||
let weight = getEncumbranceSizeScaledValue(baseWeight, encumbranceSize);
|
||||
weight = getCarryCapacityModifierScaledValue(weight, modifiers);
|
||||
return weight;
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param strScore
|
||||
* @param size
|
||||
* @param modifiers
|
||||
*/
|
||||
export function getCarryCapacity(strScore, size, modifiers) {
|
||||
return getStrengthScaledCarryCapacity(15, strScore, size, modifiers);
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param carryCapacity
|
||||
*/
|
||||
export function getPushDragLiftWeight(carryCapacity) {
|
||||
return carryCapacity * 2;
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param strScore
|
||||
* @param size
|
||||
* @param modifiers
|
||||
*/
|
||||
export function getEncumberedWeight(strScore, size, modifiers) {
|
||||
return getStrengthScaledCarryCapacity(5, strScore, size, modifiers);
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param strScore
|
||||
* @param size
|
||||
* @param modifiers
|
||||
*/
|
||||
export function getHeavilyEncumberedWeight(strScore, size, modifiers) {
|
||||
return getStrengthScaledCarryCapacity(10, strScore, size, modifiers);
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
import { DamageAdjustmentTypeEnum } from '../../Core';
|
||||
/**
|
||||
*
|
||||
* @param damageAdjustment
|
||||
*/
|
||||
export function isResistanceDamageAdjustment(damageAdjustment) {
|
||||
return damageAdjustment.type === DamageAdjustmentTypeEnum.RESISTANCE;
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param damageAdjustment
|
||||
*/
|
||||
export function isVulnerabilityDamageAdjustment(damageAdjustment) {
|
||||
return damageAdjustment.type === DamageAdjustmentTypeEnum.VULNERABILITY;
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param damageAdjustment
|
||||
*/
|
||||
export function isImmunityDamageAdjustment(damageAdjustment) {
|
||||
return damageAdjustment.type === DamageAdjustmentTypeEnum.IMMUNITY;
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
import { CustomProficiencyTypeEnum } from '../../Core';
|
||||
/**
|
||||
*
|
||||
* @param proficiency
|
||||
*/
|
||||
export function isCustomSkillProficiency(proficiency) {
|
||||
return proficiency.type === CustomProficiencyTypeEnum.SKILL;
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
import { SourceTypeEnum } from '../../Core';
|
||||
/**
|
||||
*
|
||||
* @param source
|
||||
*/
|
||||
export function isPrimarySource(source) {
|
||||
return source.sourceType === SourceTypeEnum.PRIMARY;
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param source
|
||||
*/
|
||||
export function isSecondarySource(source) {
|
||||
return source.sourceType === SourceTypeEnum.SECONDARY;
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param source
|
||||
*/
|
||||
export function isHiddenSource(source) {
|
||||
return source.sourceType === SourceTypeEnum.HIDDEN;
|
||||
}
|
||||
@@ -0,0 +1,123 @@
|
||||
/**
|
||||
*
|
||||
* @param choice
|
||||
*/
|
||||
export function getComponentId(choice) {
|
||||
return choice.componentId;
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param choice
|
||||
*/
|
||||
export function getComponentTypeId(choice) {
|
||||
return choice.componentTypeId;
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param choice
|
||||
*/
|
||||
export function getDefaultSubtypes(choice) {
|
||||
var _a;
|
||||
return (_a = choice.defaultSubtypes) !== null && _a !== void 0 ? _a : [];
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param choice
|
||||
*/
|
||||
export function getId(choice) {
|
||||
return choice.id;
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param choice
|
||||
*/
|
||||
export function isInfinite(choice) {
|
||||
return choice.isInfinite;
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param choice
|
||||
*/
|
||||
export function isOptional(choice) {
|
||||
return choice.isOptional;
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param choice
|
||||
*/
|
||||
export function getLabel(choice) {
|
||||
return choice.label;
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param choice
|
||||
*/
|
||||
export function getOptions(choice) {
|
||||
var _a;
|
||||
return (_a = choice.options) !== null && _a !== void 0 ? _a : [];
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param choice
|
||||
*/
|
||||
export function getOptionIds(choice) {
|
||||
var _a;
|
||||
return (_a = choice.optionIds) !== null && _a !== void 0 ? _a : [];
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param choice
|
||||
*/
|
||||
export function getDisplayOrder(choice) {
|
||||
return choice.displayOrder;
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param choice
|
||||
*/
|
||||
export function getOptionValue(choice) {
|
||||
return choice.optionValue;
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param choice
|
||||
*/
|
||||
export function getParentChoiceId(choice) {
|
||||
return choice.parentChoiceId;
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param choice
|
||||
*/
|
||||
export function getSubType(choice) {
|
||||
return choice.subType;
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param choice
|
||||
*/
|
||||
export function getType(choice) {
|
||||
return choice.type;
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param choice
|
||||
*/
|
||||
export function getDataOrigin(choice) {
|
||||
return choice.dataOrigin;
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param choice
|
||||
*/
|
||||
export function getUniqueKey(choice) {
|
||||
return getId(choice);
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param choice
|
||||
*/
|
||||
export function getTagConstraints(choice) {
|
||||
var _a;
|
||||
return (_a = choice.tagConstraints) !== null && _a !== void 0 ? _a : [];
|
||||
}
|
||||
@@ -0,0 +1,97 @@
|
||||
import { groupBy, orderBy } from 'lodash';
|
||||
import { DataOriginGenerators } from '../DataOrigin';
|
||||
import { HelperUtils } from '../Helper';
|
||||
import { getComponentId, getComponentTypeId, getDisplayOrder, getId, getLabel, getOptionIds, getParentChoiceId, getType, } from './accessors';
|
||||
/**
|
||||
*
|
||||
* @param choice
|
||||
*/
|
||||
export function generateDataOriginKey(choice) {
|
||||
return DataOriginGenerators.generateDataOriginKey(getComponentId(choice), getComponentTypeId(choice));
|
||||
}
|
||||
/**
|
||||
* @name generateChoiceComponentLookup
|
||||
* @param choices
|
||||
* @param choiceDefinitions
|
||||
* @description it takes choices and fills out the options via the optionIds and the choiceDefinitions and returns a lookup
|
||||
*/
|
||||
export function generateChoiceComponentLookup(choices, choiceDefinitions) {
|
||||
if (choiceDefinitions.length > 0) {
|
||||
choices.forEach((choice) => {
|
||||
var _a;
|
||||
// find the collection of choice definitions for this choice
|
||||
const options = ((_a = choiceDefinitions.find(({ id }) => id === `${getComponentTypeId(choice)}-${getType(choice)}`)) === null || _a === void 0 ? void 0 : _a.options) || null;
|
||||
const optionIds = getOptionIds(choice);
|
||||
if (options && optionIds.length) {
|
||||
// set existing list to empty array for phase 1 support
|
||||
choice.options = [];
|
||||
for (let i = 0; i < optionIds.length; i++) {
|
||||
const optionId = optionIds[i];
|
||||
// find the definition of the choice to add back to the list
|
||||
const option = options.find((c) => c.id === optionId);
|
||||
if (option) {
|
||||
choice.options.push(option);
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
return groupBy(choices, (choice) => generateDataOriginKey(choice));
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param proficiencyModifiers
|
||||
* @param expertiseModifiers
|
||||
* @param languageModifiers
|
||||
* @param kenseiModifiers
|
||||
* @param abilityLookup
|
||||
* @param classSpellLists
|
||||
*/
|
||||
export function generateChoiceData(proficiencyModifiers, expertiseModifiers, languageModifiers, kenseiModifiers, abilityLookup, classSpellLists) {
|
||||
return {
|
||||
proficiencyModifiers,
|
||||
expertiseModifiers,
|
||||
languageModifiers,
|
||||
kenseiModifiers,
|
||||
abilityLookup,
|
||||
classSpellLists,
|
||||
};
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param id
|
||||
* @param entityTypeId
|
||||
* @param choiceLookup
|
||||
* @param dataOriginType
|
||||
* @param primary
|
||||
* @param parent
|
||||
*/
|
||||
export function generateBaseChoices(id, entityTypeId, choiceLookup, dataOriginType, primary, parent = null) {
|
||||
const choices = HelperUtils.lookupDataOrFallback(choiceLookup, DataOriginGenerators.generateDataOriginKey(id, entityTypeId));
|
||||
if (!choices) {
|
||||
return [];
|
||||
}
|
||||
// create a sub choice lookup for later
|
||||
const subChoiceLookup = groupBy(choices.filter((choice) => getParentChoiceId(choice) !== null), (choice) => getParentChoiceId(choice));
|
||||
// get all choices that aren't children and sort them
|
||||
const orderedParentChoices = orderBy(choices.filter((choice) => getParentChoiceId(choice) === null), [getDisplayOrder, getType, (choice) => { var _a, _b; return (_b = (_a = getLabel(choice)) === null || _a === void 0 ? void 0 : _a.toLowerCase()) !== null && _b !== void 0 ? _b : null; }, getId]);
|
||||
// iterate over all non children choices, add choice, and then all ordered children after it into a flat array for parity
|
||||
const orderedChoices = [];
|
||||
orderedParentChoices.forEach((parentChoice) => {
|
||||
orderedChoices.push(parentChoice);
|
||||
const id = getId(parentChoice);
|
||||
if (id !== null) {
|
||||
let subChoices = HelperUtils.lookupDataOrFallback(subChoiceLookup, id);
|
||||
if (subChoices !== null) {
|
||||
let orderedSubChoices = orderBy(subChoices, [
|
||||
getDisplayOrder,
|
||||
getType,
|
||||
(choice) => { var _a, _b; return (_b = (_a = getLabel(choice)) === null || _a === void 0 ? void 0 : _a.toLowerCase()) !== null && _b !== void 0 ? _b : null; },
|
||||
getId,
|
||||
]);
|
||||
orderedChoices.push(...orderedSubChoices);
|
||||
}
|
||||
}
|
||||
});
|
||||
return orderedChoices.map((choice) => (Object.assign(Object.assign({}, choice), { dataOrigin: DataOriginGenerators.generateDataOrigin(dataOriginType, primary, parent) })));
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
import * as ChoiceAccessors from './accessors';
|
||||
import * as ChoiceGenerators from './generators';
|
||||
import * as ChoiceTypings from './typings';
|
||||
import * as ChoiceUtils from './utils';
|
||||
export * from './typings';
|
||||
export { ChoiceAccessors, ChoiceGenerators, ChoiceUtils };
|
||||
export default Object.assign(Object.assign(Object.assign(Object.assign({}, ChoiceAccessors), ChoiceGenerators), ChoiceTypings), ChoiceUtils);
|
||||
@@ -0,0 +1,211 @@
|
||||
import { orderBy } from 'lodash';
|
||||
import { TypeScriptUtils } from "../../utils";
|
||||
import { ClassAccessors } from '../Class';
|
||||
import { AbilityStatEnum, BuilderChoiceSubtypeEnum } from '../Core';
|
||||
import { DataOriginTypeEnum } from '../DataOrigin';
|
||||
import { EntityUtils } from '../Entity';
|
||||
import { HelperUtils } from '../Helper';
|
||||
import { ModifierAccessors } from '../Modifier';
|
||||
import { SourceUtils } from '../Source';
|
||||
import { SpellUtils } from '../Spell';
|
||||
import { getDefaultSubtypes, getOptions, getOptionValue, isOptional } from './accessors';
|
||||
export function isOnlyDefaultSelected(choice) {
|
||||
const defaultSubtypes = getDefaultSubtypes(choice);
|
||||
if (defaultSubtypes.length !== 1) {
|
||||
return false;
|
||||
}
|
||||
if (!getOptionValue(choice)) {
|
||||
return false;
|
||||
}
|
||||
const selectedOption = getSelectedOption(choice);
|
||||
if (selectedOption) {
|
||||
return selectedOption.label === defaultSubtypes[0];
|
||||
}
|
||||
return false;
|
||||
}
|
||||
export function getSelectedOption(choice) {
|
||||
return getOptions(choice).find((option) => option.id === getOptionValue(choice));
|
||||
}
|
||||
export function isOptionSelected(choice) {
|
||||
return !!getSelectedOption(choice);
|
||||
}
|
||||
export function isTodo(choice) {
|
||||
return !isOptional(choice) && getOptionValue(choice) === null;
|
||||
}
|
||||
// Given a Choice, return options for a select element that are potentially grouped by sourceCategory
|
||||
//used in DetailChoiceFeat.tsx for feat choices
|
||||
export function getSortedChoiceOptionsInfo(choice, ruleData, entityRestrictionData) {
|
||||
var _a;
|
||||
const options = getOptions(choice);
|
||||
let description;
|
||||
// If every option in the array has a null sourceId, ignore sorting by sourceId.
|
||||
// If any option has a non-null sourceId, sort by sourceId.
|
||||
const shouldSortBySourceId = options.some((option) => option.hasOwnProperty('sourceId') && option.sourceId !== null);
|
||||
let featChoiceOptions;
|
||||
//If the options have a sourceId, group them by Source Category (for now this should only be BuilderChoiceTypeEnum.ENTITY_SPELL_OPTION - we also have to do this in FeatureChoice for spell options)
|
||||
if (shouldSortBySourceId) {
|
||||
// Map over the options to mock parts of a DefinitionContract.
|
||||
const groupedOptions = SourceUtils.getSimpleSourcedDefinitionContracts(options);
|
||||
//If there is a chosen option, set detailChoiceDesc to its description.
|
||||
const chosenOption = options.find((option) => option.id === getOptionValue(choice));
|
||||
description = (_a = chosenOption === null || chosenOption === void 0 ? void 0 : chosenOption.description) !== null && _a !== void 0 ? _a : '';
|
||||
featChoiceOptions = SourceUtils.getGroupedOptionsBySourceCategory(groupedOptions, ruleData, chosenOption === null || chosenOption === void 0 ? void 0 : chosenOption.id, entityRestrictionData);
|
||||
}
|
||||
else {
|
||||
featChoiceOptions = options.map((option) => (Object.assign(Object.assign({}, option), { value: option.id })));
|
||||
featChoiceOptions = orderBy(featChoiceOptions, 'label');
|
||||
}
|
||||
return {
|
||||
options: featChoiceOptions,
|
||||
description,
|
||||
};
|
||||
}
|
||||
// filter Choice options based on modifiers and default subtypes that identify when a user has made a choice from another source. We filter those options out or we append the source data origin name next to the option label
|
||||
export function getRemainingOptions(options, modifiers, defaultSubtypes, showBackgroundProficiencyOptions, optionValue) {
|
||||
let remainingSubtypes = [];
|
||||
let selectedOption = options.find((option) => option.value === optionValue);
|
||||
//if there is a default option set, the default option is granted automatically.
|
||||
//defaultSubtypes would be an array of remaining options and we need to filter out anything that is already found in a modifier from another source
|
||||
if (defaultSubtypes) {
|
||||
if (defaultSubtypes.length > 1) {
|
||||
defaultSubtypes.forEach((defaultSubtype) => {
|
||||
if (!modifiers.find((modifier) => modifier.friendlySubtypeName === defaultSubtype) ||
|
||||
(selectedOption && selectedOption.label === defaultSubtype)) {
|
||||
remainingSubtypes.push(defaultSubtype);
|
||||
}
|
||||
});
|
||||
}
|
||||
else if (defaultSubtypes.length === 1 &&
|
||||
!modifiers.find((modifier) => modifier.friendlySubtypeName === defaultSubtypes[0])) {
|
||||
remainingSubtypes = [...defaultSubtypes];
|
||||
}
|
||||
}
|
||||
// If there are any remaining subtypes, only show those
|
||||
if (remainingSubtypes.length) {
|
||||
options = options.filter((option) => remainingSubtypes.includes(option.label ? option.label : '') || optionValue === option.value);
|
||||
}
|
||||
else {
|
||||
// If there aren't any remaining subtype defaults, just show the normal list of options
|
||||
if (modifiers.length) {
|
||||
options = options.reduce((acc, option) => {
|
||||
// Find any existing modifiers that are the current option
|
||||
let optionModifiers = modifiers.filter((modifier) => modifier.friendlySubtypeName === option.label);
|
||||
let backgroundOptionModifier = null;
|
||||
if (showBackgroundProficiencyOptions && optionModifiers.length) {
|
||||
// If there are any existing modifiers, find out if any of them are from a background
|
||||
const foundBackgroundOptionModifier = optionModifiers.find((modifier) => !ModifierAccessors.isGranted(modifier) &&
|
||||
ModifierAccessors.getDataOriginType(modifier) === DataOriginTypeEnum.BACKGROUND);
|
||||
if (foundBackgroundOptionModifier) {
|
||||
backgroundOptionModifier = foundBackgroundOptionModifier;
|
||||
}
|
||||
}
|
||||
if (!optionModifiers.length || backgroundOptionModifier || optionValue === option.value) {
|
||||
let value = typeof option.value === 'string' ? HelperUtils.parseInputInt(option.value) : option.value;
|
||||
//append the dataOrigin of the modifier (background) to the option label so the user knows where the option was selected
|
||||
if (value !== null) {
|
||||
acc.push(Object.assign(Object.assign({}, option), { value: value, label: backgroundOptionModifier
|
||||
? `${option.label} (${EntityUtils.getDataOriginName(ModifierAccessors.getDataOrigin(backgroundOptionModifier))})`
|
||||
: option.label }));
|
||||
}
|
||||
}
|
||||
return acc;
|
||||
}, []);
|
||||
}
|
||||
}
|
||||
return options;
|
||||
}
|
||||
//TODO this was abstracted from DetailChoice.tsx and needs to be broken down to smaller utils and simplified
|
||||
//TODO also need to remove the Array<any> type when gathering the renderOptions and fix the typing
|
||||
export function getSortedRenderOptions(options, classId, subType, entityRestrictionData, languages, ruleData, defaultSubtypes, showBackgroundProficiencyOptions, choiceInfo, optionValue) {
|
||||
const { classSpellLists, proficiencyModifiers, languageModifiers, expertiseModifiers, kenseiModifiers, abilityLookup, } = choiceInfo;
|
||||
// TODO need to get rid of this any and fix the typing
|
||||
// let renderOptions: Array<FeatureChoiceOption | HtmlSelectOptionGroup> = options;
|
||||
let renderOptions = options;
|
||||
switch (subType) {
|
||||
case BuilderChoiceSubtypeEnum.PROFICIENCY:
|
||||
renderOptions = getRemainingOptions(renderOptions, [...proficiencyModifiers, ...expertiseModifiers], defaultSubtypes, showBackgroundProficiencyOptions, optionValue);
|
||||
break;
|
||||
case BuilderChoiceSubtypeEnum.LANGUAGE:
|
||||
//handle languages based on other language choices made
|
||||
renderOptions = getRemainingOptions(renderOptions, languageModifiers, defaultSubtypes, showBackgroundProficiencyOptions, optionValue);
|
||||
//create lookup from ruledata - name: rpgSourceId
|
||||
const languageNameLookup = languages.reduce((acc, curr) => {
|
||||
var _a;
|
||||
return Object.assign(Object.assign({}, acc), { [(_a = curr.name) !== null && _a !== void 0 ? _a : '']: curr.rpgSourceId });
|
||||
}, {});
|
||||
//transform language options to choiceOptionContracts to attach sourceId for grouping by Source Category
|
||||
const choiceOptionContracts = renderOptions.map((option) => {
|
||||
return {
|
||||
label: option.label,
|
||||
id: option.id,
|
||||
description: option.description,
|
||||
sourceId: option.label ? HelperUtils.lookupDataOrFallback(languageNameLookup, option.label) : null,
|
||||
};
|
||||
});
|
||||
const groupedOptions = SourceUtils.getSimpleSourcedDefinitionContracts(choiceOptionContracts);
|
||||
//group languages by source category
|
||||
renderOptions = SourceUtils.getGroupedOptionsBySourceCategory(groupedOptions, ruleData, optionValue, entityRestrictionData, 'Other');
|
||||
break;
|
||||
case BuilderChoiceSubtypeEnum.KENSEI:
|
||||
renderOptions = getRemainingOptions(renderOptions, kenseiModifiers, defaultSubtypes, showBackgroundProficiencyOptions, optionValue);
|
||||
break;
|
||||
case BuilderChoiceSubtypeEnum.EXPERTISE:
|
||||
renderOptions = renderOptions.filter((option) => (proficiencyModifiers.find((modifier) => ModifierAccessors.getFriendlySubtypeName(modifier) === option.label) &&
|
||||
!expertiseModifiers.find((modifier) => ModifierAccessors.getFriendlySubtypeName(modifier) === option.label)) ||
|
||||
optionValue === option.value);
|
||||
break;
|
||||
case BuilderChoiceSubtypeEnum.EXPERTISE_NO_REQUIREMENT:
|
||||
renderOptions = renderOptions.filter((option) => !expertiseModifiers.find((modifier) => ModifierAccessors.getFriendlySubtypeName(modifier) === option.label) || optionValue === option.value);
|
||||
break;
|
||||
case BuilderChoiceSubtypeEnum.KNOWN_SPELLS:
|
||||
const spellList = classSpellLists.find((classSpellList) => ClassAccessors.getId(classSpellList.charClass) === classId);
|
||||
if (spellList) {
|
||||
renderOptions = renderOptions
|
||||
.map((topOption) => {
|
||||
if ('options' in topOption && topOption.options) {
|
||||
return Object.assign(Object.assign({}, topOption), { options: topOption.options.filter((option) => SpellUtils.isSpellKnown(spellList, Number(option.value)) ||
|
||||
optionValue === option.value) });
|
||||
}
|
||||
else {
|
||||
const singleOption = topOption;
|
||||
return SpellUtils.isSpellKnown(spellList, Number(singleOption.value)) ||
|
||||
optionValue === singleOption.value
|
||||
? singleOption
|
||||
: null;
|
||||
}
|
||||
})
|
||||
.filter(TypeScriptUtils.isNotNullOrUndefined);
|
||||
}
|
||||
break;
|
||||
case BuilderChoiceSubtypeEnum.ABILITY_SCORE: {
|
||||
renderOptions = renderOptions.filter((option) => {
|
||||
let abilityId = null;
|
||||
switch (option.label) {
|
||||
case 'Charisma Score':
|
||||
abilityId = AbilityStatEnum.CHARISMA;
|
||||
break;
|
||||
case 'Constitution Score':
|
||||
abilityId = AbilityStatEnum.CONSTITUTION;
|
||||
break;
|
||||
case 'Dexterity Score':
|
||||
abilityId = AbilityStatEnum.DEXTERITY;
|
||||
break;
|
||||
case 'Intelligence Score':
|
||||
abilityId = AbilityStatEnum.INTELLIGENCE;
|
||||
break;
|
||||
case 'Strength Score':
|
||||
abilityId = AbilityStatEnum.STRENGTH;
|
||||
break;
|
||||
case 'Wisdom Score':
|
||||
abilityId = AbilityStatEnum.WISDOM;
|
||||
break;
|
||||
}
|
||||
return !abilityId || (abilityId && !abilityLookup[abilityId].isMaxed) || optionValue === option.value;
|
||||
});
|
||||
break;
|
||||
}
|
||||
}
|
||||
return renderOptions.length > 0 && renderOptions[0].hasOwnProperty('optGroupLabel')
|
||||
? orderBy(renderOptions, 'sortOrder')
|
||||
: orderBy(renderOptions, 'label');
|
||||
}
|
||||
@@ -0,0 +1,535 @@
|
||||
/**
|
||||
*
|
||||
* @param charClass
|
||||
*/
|
||||
export function getDefinition(charClass) {
|
||||
return charClass.definition;
|
||||
}
|
||||
/**
|
||||
* @param charClass
|
||||
*/
|
||||
export function getName(charClass) {
|
||||
var _a, _b;
|
||||
return (_b = (_a = charClass.definition) === null || _a === void 0 ? void 0 : _a.name) !== null && _b !== void 0 ? _b : null;
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param charClass
|
||||
*/
|
||||
export function getId(charClass) {
|
||||
var _a, _b;
|
||||
return (_b = (_a = charClass.definition) === null || _a === void 0 ? void 0 : _a.id) !== null && _b !== void 0 ? _b : -1;
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param charClass
|
||||
*/
|
||||
export function getDefinitionHitDiceType(charClass) {
|
||||
var _a, _b;
|
||||
return (_b = (_a = charClass.definition) === null || _a === void 0 ? void 0 : _a.hitDice) !== null && _b !== void 0 ? _b : 0;
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param charClass
|
||||
*/
|
||||
export function getHitDiceType(charClass) {
|
||||
return getDefinitionHitDiceType(charClass);
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param charClass
|
||||
*/
|
||||
export function getDefinitionSpellcastingStatId(charClass) {
|
||||
var _a, _b;
|
||||
return (_b = (_a = charClass.definition) === null || _a === void 0 ? void 0 : _a.spellCastingAbilityId) !== null && _b !== void 0 ? _b : null;
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param charClass
|
||||
*/
|
||||
export function getDefinitionSpellContainerName(charClass) {
|
||||
var _a, _b;
|
||||
return (_b = (_a = charClass.definition) === null || _a === void 0 ? void 0 : _a.spellContainerName) !== null && _b !== void 0 ? _b : null;
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param charClass
|
||||
*/
|
||||
export function getSpellContainerName(charClass) {
|
||||
return getDefinitionSpellContainerName(charClass);
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param charClass
|
||||
*/
|
||||
export function getDefinitionKnowsAllSpells(charClass) {
|
||||
var _a, _b;
|
||||
return (_b = (_a = charClass.definition) === null || _a === void 0 ? void 0 : _a.knowsAllSpells) !== null && _b !== void 0 ? _b : null;
|
||||
}
|
||||
export function getKnowsAllSpells(charClass) {
|
||||
return getDefinitionKnowsAllSpells(charClass);
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param charClass
|
||||
*/
|
||||
export function getDefinitionSpellPrepareType(charClass) {
|
||||
var _a, _b;
|
||||
return (_b = (_a = charClass.definition) === null || _a === void 0 ? void 0 : _a.spellPrepareType) !== null && _b !== void 0 ? _b : null;
|
||||
}
|
||||
export function getSpellPrepareType(charClass) {
|
||||
return getDefinitionSpellPrepareType(charClass);
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param charClass
|
||||
*/
|
||||
export function getDefinitionSpellCastingLearningStyle(charClass) {
|
||||
var _a, _b;
|
||||
return (_b = (_a = charClass.definition) === null || _a === void 0 ? void 0 : _a.spellCastingLearningStyle) !== null && _b !== void 0 ? _b : null;
|
||||
}
|
||||
export function getSpellCastingLearningStyle(charClass) {
|
||||
return charClass.spellCastingLearningStyle;
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param charClass
|
||||
*/
|
||||
export function getPortraitUrl(charClass) {
|
||||
var _a, _b;
|
||||
return (_b = (_a = charClass.definition) === null || _a === void 0 ? void 0 : _a.portraitAvatarUrl) !== null && _b !== void 0 ? _b : '';
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param charClass
|
||||
*/
|
||||
export function getAvatarUrl(charClass) {
|
||||
var _a, _b;
|
||||
return (_b = (_a = charClass.definition) === null || _a === void 0 ? void 0 : _a.avatarUrl) !== null && _b !== void 0 ? _b : '';
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param charClass
|
||||
*/
|
||||
export function getLargeAvatarUrl(charClass) {
|
||||
var _a, _b;
|
||||
return (_b = (_a = charClass.definition) === null || _a === void 0 ? void 0 : _a.largeAvatarUrl) !== null && _b !== void 0 ? _b : '';
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param charClass
|
||||
*/
|
||||
export function isKnownSpellcaster(charClass) {
|
||||
const spellRules = getSpellRules(charClass);
|
||||
return spellRules.isKnownSpellcaster;
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param charClass
|
||||
*/
|
||||
export function isPreparedSpellcaster(charClass) {
|
||||
const spellRules = getSpellRules(charClass);
|
||||
return spellRules.isPreparedSpellcaster;
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param charClass
|
||||
*/
|
||||
export function isSpellbookSpellcaster(charClass) {
|
||||
const spellRules = getSpellRules(charClass);
|
||||
return spellRules.isSpellbookSpellcaster;
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param charClass
|
||||
*/
|
||||
export function isRitualSpellCaster(charClass) {
|
||||
const spellRules = getSpellRules(charClass);
|
||||
return spellRules.isRitualSpellCaster;
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param charClass
|
||||
*/
|
||||
export function getCanCastSpells(charClass) {
|
||||
getDefinitionCanCastSpells(charClass);
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param charClass
|
||||
*/
|
||||
export function getDefinitionCanCastSpells(charClass) {
|
||||
var _a, _b;
|
||||
return (_b = (_a = charClass.definition) === null || _a === void 0 ? void 0 : _a.canCastSpells) !== null && _b !== void 0 ? _b : null;
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param charClass
|
||||
*/
|
||||
export function getDefinitionDescription(charClass) {
|
||||
var _a, _b;
|
||||
return (_b = (_a = charClass.definition) === null || _a === void 0 ? void 0 : _a.description) !== null && _b !== void 0 ? _b : null;
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param charClass
|
||||
*/
|
||||
export function getDescription(charClass) {
|
||||
return getDefinitionDescription(charClass);
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param charClass
|
||||
*/
|
||||
export function getDefinitionEquipmentDescription(charClass) {
|
||||
var _a, _b;
|
||||
return (_b = (_a = charClass.definition) === null || _a === void 0 ? void 0 : _a.equipmentDescription) !== null && _b !== void 0 ? _b : null;
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param charClass
|
||||
*/
|
||||
export function getEquipmentDescription(charClass) {
|
||||
return getDefinitionEquipmentDescription(charClass);
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param charClass
|
||||
*/
|
||||
export function getMoreDetailsUrl(charClass) {
|
||||
return getDefinitionMoreDetailsUrl(charClass);
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param charClass
|
||||
*/
|
||||
export function getDefinitionMoreDetailsUrl(charClass) {
|
||||
var _a, _b;
|
||||
return (_b = (_a = charClass.definition) === null || _a === void 0 ? void 0 : _a.moreDetailsUrl) !== null && _b !== void 0 ? _b : null;
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param charClass
|
||||
*/
|
||||
export function getDefinitionParentClassId(charClass) {
|
||||
var _a, _b;
|
||||
return (_b = (_a = charClass.definition) === null || _a === void 0 ? void 0 : _a.parentClassId) !== null && _b !== void 0 ? _b : null;
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param charClass
|
||||
*/
|
||||
export function getParentClassId(charClass) {
|
||||
return getDefinitionParentClassId(charClass);
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param charClass
|
||||
*/
|
||||
export function getDefinitionSubclassDefinition(charClass) {
|
||||
var _a, _b;
|
||||
return (_b = (_a = charClass.definition) === null || _a === void 0 ? void 0 : _a.subclassDefinition) !== null && _b !== void 0 ? _b : null;
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param charClass
|
||||
*/
|
||||
export function getWealthDice(charClass) {
|
||||
return getDefinitionWealthDice(charClass);
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param charClass
|
||||
*/
|
||||
export function getDefinitionWealthDice(charClass) {
|
||||
var _a, _b;
|
||||
return (_b = (_a = charClass.definition) === null || _a === void 0 ? void 0 : _a.wealthDice) !== null && _b !== void 0 ? _b : null;
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param charClass
|
||||
*/
|
||||
export function getDefinitionClassFeatures(charClass) {
|
||||
var _a;
|
||||
return (_a = charClass.classFeatures) !== null && _a !== void 0 ? _a : [];
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param charClass
|
||||
*/
|
||||
export function getMappingEntityTypeId(charClass) {
|
||||
return charClass.entityTypeId;
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param charClass
|
||||
*/
|
||||
export function getHitDiceUsed(charClass) {
|
||||
return charClass.hitDiceUsed;
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param charClass
|
||||
*/
|
||||
export function getMappingId(charClass) {
|
||||
return charClass.id;
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param charClass
|
||||
*/
|
||||
export function isStartingClass(charClass) {
|
||||
return charClass.isStartingClass;
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param charClass
|
||||
*/
|
||||
export function getLevel(charClass) {
|
||||
return charClass.level;
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param charClass
|
||||
*/
|
||||
export function getSubclassName(charClass) {
|
||||
var _a, _b;
|
||||
return (_b = (_a = charClass.subclassDefinition) === null || _a === void 0 ? void 0 : _a.name) !== null && _b !== void 0 ? _b : null;
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param charClass
|
||||
*/
|
||||
export function getSubclass(charClass) {
|
||||
return charClass.subclassDefinition;
|
||||
}
|
||||
/**
|
||||
* this field will always return null until character service updates to populate it
|
||||
* @param charClass
|
||||
*/
|
||||
export function getSubclassDefinitionId(charClass) {
|
||||
return charClass.subclassDefinitionId;
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param charClass
|
||||
*/
|
||||
export function isPactMagicActive(charClass) {
|
||||
return charClass.isPactMagicActive;
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param charClass
|
||||
*/
|
||||
export function isSpellcastingActive(charClass) {
|
||||
return charClass.isSpellcastingActive;
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param charClass
|
||||
*/
|
||||
export function getSlug(charClass) {
|
||||
return charClass.slug;
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param charClass
|
||||
*/
|
||||
export function getSpellRules(charClass) {
|
||||
return charClass.spellRules;
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param charClass
|
||||
*/
|
||||
export function getActions(charClass) {
|
||||
return charClass.actions;
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param charClass
|
||||
*/
|
||||
export function getActiveClassFeatures(charClass) {
|
||||
return charClass.activeClassFeatures;
|
||||
}
|
||||
/**
|
||||
* @deprecated only used for typescript parody because of spells being in two different states within the same location
|
||||
* @param charClass
|
||||
*/
|
||||
export function getBaseClassSpells(charClass) {
|
||||
return charClass.spells;
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param charClass
|
||||
*/
|
||||
export function getClassFeatures(charClass) {
|
||||
var _a;
|
||||
return (_a = charClass.classFeatures) !== null && _a !== void 0 ? _a : [];
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param charClass
|
||||
*/
|
||||
export function getEnablesHexWeapon(charClass) {
|
||||
return charClass.enablesHexWeapon;
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param charClass
|
||||
*/
|
||||
export function getEnablesPactWeapon(charClass) {
|
||||
return charClass.enablesPactWeapon;
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param charClass
|
||||
*/
|
||||
export function getEnablesDedicatedWeapon(charClass) {
|
||||
return charClass.enablesDedicatedWeapon;
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param charClass
|
||||
*/
|
||||
export function getFeats(charClass) {
|
||||
return charClass.feats;
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param charClass
|
||||
*/
|
||||
export function getFeatureSpells(charClass) {
|
||||
return charClass.featureSpells;
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param charClass
|
||||
*/
|
||||
export function getModifiers(charClass) {
|
||||
return charClass.modifiers;
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param charClass
|
||||
*/
|
||||
export function getOrderedClassFeatures(charClass) {
|
||||
return charClass.orderedClassFeatures;
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param charClass
|
||||
*/
|
||||
export function getSpells(charClass) {
|
||||
return charClass.spells;
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param charClass
|
||||
*/
|
||||
export function getUniqueClassFeatures(charClass) {
|
||||
return charClass.uniqueClassFeatures;
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param charClass
|
||||
*/
|
||||
export function getVisibileClassFeatures(charClass) {
|
||||
return charClass.visibleClassFeatures;
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param charClass
|
||||
*/
|
||||
export function getActiveId(charClass) {
|
||||
return charClass.activeId;
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param charClass
|
||||
*/
|
||||
export function getDefinitionPrimaryAbilities(charClass) {
|
||||
var _a, _b;
|
||||
return (_b = (_a = charClass.definition) === null || _a === void 0 ? void 0 : _a.primaryAbilities) !== null && _b !== void 0 ? _b : [];
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param charClass
|
||||
*/
|
||||
export function getPrimaryAbilities(charClass) {
|
||||
return getDefinitionPrimaryAbilities(charClass);
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param charClass
|
||||
*/
|
||||
export function getDefinitionPrerequisites(charClass) {
|
||||
var _a, _b;
|
||||
return (_b = (_a = charClass.definition) === null || _a === void 0 ? void 0 : _a.prerequisites) !== null && _b !== void 0 ? _b : [];
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param charClass
|
||||
*/
|
||||
export function getPrerequisites(charClass) {
|
||||
return getDefinitionPrerequisites(charClass);
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param charClass
|
||||
*/
|
||||
export function getDefinitionSpellConfiguration(charClass) {
|
||||
var _a, _b;
|
||||
return (_b = (_a = charClass.definition) === null || _a === void 0 ? void 0 : _a.spellRules) !== null && _b !== void 0 ? _b : null;
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param charClass
|
||||
*/
|
||||
export function getSpellConfiguration(charClass) {
|
||||
return getDefinitionSpellConfiguration(charClass);
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param charClass
|
||||
*/
|
||||
export function getDefinitionSources(charClass) {
|
||||
var _a, _b;
|
||||
return (_b = (_a = charClass.definition) === null || _a === void 0 ? void 0 : _a.sources) !== null && _b !== void 0 ? _b : [];
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param charClass
|
||||
*/
|
||||
export function getSources(charClass) {
|
||||
return getDefinitionSources(charClass);
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param charClass
|
||||
*/
|
||||
export function getDefinitionIsHomebrew(charClass) {
|
||||
var _a, _b;
|
||||
return (_b = (_a = charClass.definition) === null || _a === void 0 ? void 0 : _a.isHomebrew) !== null && _b !== void 0 ? _b : false;
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param charClass
|
||||
*/
|
||||
export function isHomebrew(charClass) {
|
||||
return getDefinitionIsHomebrew(charClass);
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param charClass
|
||||
*/
|
||||
export function getSpellListIds(charClass) {
|
||||
return charClass.spellListIds;
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param charClass
|
||||
*/
|
||||
export function getOptionalClassFeatures(charClass) {
|
||||
return charClass.optionalClassFeatures;
|
||||
}
|
||||
@@ -0,0 +1,296 @@
|
||||
import { orderBy } from 'lodash';
|
||||
import { ChoiceUtils } from '../Choice';
|
||||
import { ClassFeatureAccessors, ClassFeatureUtils, ClassFeatureValidators } from '../ClassFeature';
|
||||
import { DB_STRING_BOOK_OF_ANCIENT_SECRETS, DB_STRING_INFUSE_ITEM, FeatureTypeEnum, } from '../Core';
|
||||
import { DataOriginGenerators } from '../DataOrigin';
|
||||
import { HelperUtils } from '../Helper';
|
||||
import { ModifierValidators } from '../Modifier';
|
||||
import { OptionalClassFeatureAccessors } from '../OptionalClassFeature';
|
||||
import { DefaultSpellCastingLearningStyle, SpellDerivers } from '../Spell';
|
||||
import { getActiveId, getDefinitionClassFeatures, getDefinitionSpellcastingStatId, getId, getLevel, getMappingId, getSubclass, getClassFeatures, getDefinitionSpellCastingLearningStyle, } from './accessors';
|
||||
/**
|
||||
*
|
||||
* @param charClass
|
||||
* @param subclassDefinition
|
||||
*/
|
||||
export function deriveSpellcastingStatId(charClass, subclassDefinition) {
|
||||
if (subclassDefinition && subclassDefinition.spellCastingAbilityId !== null) {
|
||||
return subclassDefinition.spellCastingAbilityId;
|
||||
}
|
||||
return getDefinitionSpellcastingStatId(charClass);
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param charClass
|
||||
* @param subclassDefinition
|
||||
*/
|
||||
export function deriveSpellCastingLearningStyle(charClass) {
|
||||
var _a;
|
||||
const subclassDefinition = getSubclass(charClass);
|
||||
if (subclassDefinition === null || subclassDefinition === void 0 ? void 0 : subclassDefinition.spellCastingLearningStyle) {
|
||||
return subclassDefinition.spellCastingLearningStyle;
|
||||
}
|
||||
return (_a = getDefinitionSpellCastingLearningStyle(charClass)) !== null && _a !== void 0 ? _a : DefaultSpellCastingLearningStyle;
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param classFeatures
|
||||
* @param classLevel
|
||||
*/
|
||||
export function deriveIsSpellcastingActive(classFeatures, classLevel) {
|
||||
const spellcastingFeature = classFeatures.find((feature) => ClassFeatureUtils.doesEnableSpellcasting(feature));
|
||||
return !!spellcastingFeature && ClassFeatureAccessors.getRequiredLevel(spellcastingFeature) <= classLevel;
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param classFeatures
|
||||
* @param classLevel
|
||||
*/
|
||||
export function deriveIsPactMagicActive(classFeatures, classLevel) {
|
||||
const pactMagicFeature = classFeatures.find((feature) => ClassFeatureUtils.doesEnablePactMagic(feature));
|
||||
return !!pactMagicFeature && ClassFeatureAccessors.getRequiredLevel(pactMagicFeature) <= classLevel;
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param charClass
|
||||
* @param allClassSpells
|
||||
* @param allClassAlwaysPreparedSpells
|
||||
* @param allClassAlwaysKnownSpells
|
||||
*/
|
||||
export function deriveSpells(charClass, allClassSpells, allClassAlwaysPreparedSpells, allClassAlwaysKnownSpells) {
|
||||
const classSpells = allClassSpells.find((classSpell) => classSpell.characterClassId === getMappingId(charClass));
|
||||
const spells = [];
|
||||
if (classSpells === null || classSpells === void 0 ? void 0 : classSpells.spells) {
|
||||
spells.push(...classSpells.spells);
|
||||
}
|
||||
let classSpellMappingLookup = {};
|
||||
const alwaysPreparedSpells = HelperUtils.lookupDataOrFallback(allClassAlwaysPreparedSpells, deriveActiveId(charClass));
|
||||
const alwaysKnownSpells = HelperUtils.lookupDataOrFallback(allClassAlwaysKnownSpells, deriveActiveId(charClass));
|
||||
// If we have any "always" spells, make a lookup of the existing class spell mappings
|
||||
if (alwaysKnownSpells !== null || alwaysPreparedSpells !== null) {
|
||||
if (classSpells === null || classSpells === void 0 ? void 0 : classSpells.spells) {
|
||||
classSpellMappingLookup = classSpells.spells.reduce((acc, spell) => {
|
||||
acc[SpellDerivers.deriveKnownKey(spell)] = true;
|
||||
return acc;
|
||||
}, {});
|
||||
}
|
||||
}
|
||||
// exclude always prepared spells that we are already sent in the class spell mappings
|
||||
if (alwaysPreparedSpells !== null) {
|
||||
alwaysPreparedSpells.forEach((spell) => {
|
||||
const knownKey = SpellDerivers.deriveKnownKey(spell);
|
||||
if (!HelperUtils.lookupDataOrFallback(classSpellMappingLookup, knownKey, false)) {
|
||||
spells.push(spell);
|
||||
classSpellMappingLookup[knownKey] = true;
|
||||
}
|
||||
});
|
||||
}
|
||||
// exclude always known spells that we are already sent in the class spell mappings
|
||||
if (alwaysKnownSpells !== null) {
|
||||
alwaysKnownSpells.forEach((spell) => {
|
||||
if (!HelperUtils.lookupDataOrFallback(classSpellMappingLookup, SpellDerivers.deriveKnownKey(spell), false)) {
|
||||
spells.push(spell);
|
||||
}
|
||||
});
|
||||
}
|
||||
return spells;
|
||||
}
|
||||
/**
|
||||
* The classFeatures being passed in here are updated during BaseCharClass generation and cannot be accessed off charClass
|
||||
* fix this to eventually not have class and class features from separate stages
|
||||
*
|
||||
* @param charClass
|
||||
* @param classFeatures
|
||||
* @param choiceLookup
|
||||
* @param ruleData
|
||||
*/
|
||||
export function deriveSpellRules(charClass, classFeatures, choiceLookup, ruleData) {
|
||||
const abilityId = deriveSpellcastingStatId(charClass, getSubclass(charClass));
|
||||
let enablesRitualCasting = false;
|
||||
classFeatures.forEach((feature) => {
|
||||
const id = ClassFeatureAccessors.getId(feature);
|
||||
const entityTypeId = ClassFeatureAccessors.getEntityTypeId(feature);
|
||||
const choicesFallback = [];
|
||||
const choices = HelperUtils.lookupDataOrFallback(choiceLookup, DataOriginGenerators.generateDataOriginKey(id, entityTypeId), choicesFallback);
|
||||
if (choices.length > 0) {
|
||||
choices.forEach((choice) => {
|
||||
const selectedOption = ChoiceUtils.getSelectedOption(choice);
|
||||
if (!enablesRitualCasting &&
|
||||
selectedOption &&
|
||||
selectedOption.label === DB_STRING_BOOK_OF_ANCIENT_SECRETS) {
|
||||
enablesRitualCasting = true;
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
return SpellDerivers.deriveClassSpellRules(charClass, abilityId, ruleData, enablesRitualCasting);
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param charClass
|
||||
* @param classFeatures
|
||||
* @param appContext
|
||||
*/
|
||||
export function deriveClassFeatureGroups(charClass, classFeatures, appContext) {
|
||||
const activeFeatures = classFeatures.filter((feature) => ClassFeatureAccessors.getRequiredLevel(feature) <= getLevel(charClass));
|
||||
const visibleFeatures = activeFeatures.filter((feature) => appContext === null || !ClassFeatureUtils.getHideInContext(feature, appContext));
|
||||
const orderedFeatures = deriveOrderedClassFeatures(visibleFeatures);
|
||||
const uniqueFeatures = orderedFeatures.reduce((acc, feature) => {
|
||||
const existingFeatureIdx = acc.findIndex((accFeature) => ClassFeatureAccessors.getName(accFeature) === ClassFeatureAccessors.getName(feature));
|
||||
if (existingFeatureIdx > 0) {
|
||||
acc[existingFeatureIdx] = feature;
|
||||
}
|
||||
else {
|
||||
acc.push(feature);
|
||||
}
|
||||
return acc;
|
||||
}, []);
|
||||
return {
|
||||
activeFeatures,
|
||||
visibleFeatures,
|
||||
orderedFeatures,
|
||||
uniqueFeatures,
|
||||
};
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param classFeatures
|
||||
*/
|
||||
export function deriveOrderedClassFeatures(classFeatures) {
|
||||
return orderBy(classFeatures, [
|
||||
(classFeature) => ClassFeatureAccessors.getRequiredLevel(classFeature),
|
||||
(classFeature) => ClassFeatureAccessors.getDisplayOrder(classFeature),
|
||||
(classFeature) => ClassFeatureAccessors.getName(classFeature),
|
||||
]);
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param classFeatures
|
||||
*/
|
||||
export function deriveDedicatedHexAndPactWeaponEnabled(classFeatures, classModifiers) {
|
||||
let enablesHexWeapon = false;
|
||||
let enablesPactWeapon = false;
|
||||
let enablesDedicatedWeapon = false;
|
||||
classModifiers.forEach((modifier) => {
|
||||
if (!enablesPactWeapon && ModifierValidators.isEnablePactWeaponModifier(modifier)) {
|
||||
enablesPactWeapon = true;
|
||||
return;
|
||||
}
|
||||
if (!enablesHexWeapon && ModifierValidators.isEnableHexWeaponModifier(modifier)) {
|
||||
enablesHexWeapon = true;
|
||||
return;
|
||||
}
|
||||
});
|
||||
//TODO remove this once we have dedicated weapon driven by modifiers
|
||||
classFeatures.forEach((feature) => {
|
||||
if (!enablesDedicatedWeapon && ClassFeatureUtils.doesEnableDedicatedWeapon(feature)) {
|
||||
enablesDedicatedWeapon = true;
|
||||
}
|
||||
});
|
||||
return {
|
||||
enablesHexWeapon,
|
||||
enablesPactWeapon,
|
||||
enablesDedicatedWeapon,
|
||||
};
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param charClass
|
||||
*/
|
||||
export function deriveActiveId(charClass) {
|
||||
const subclass = getSubclass(charClass);
|
||||
if (subclass === null) {
|
||||
return getId(charClass);
|
||||
}
|
||||
return subclass.id;
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param classes
|
||||
*/
|
||||
export function deriveIsMulticlassCharacter(classes) {
|
||||
return classes.length > 1;
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param charClass
|
||||
*/
|
||||
export function deriveUniqueKey(charClass) {
|
||||
return `class-${getActiveId(charClass)}`;
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param classFeatures
|
||||
* @param classLevel
|
||||
*/
|
||||
export function deriveSpellListIds(classFeatures, classLevel) {
|
||||
let spellLidsIds = [];
|
||||
classFeatures
|
||||
.filter((classFeature) => ClassFeatureAccessors.getRequiredLevel(classFeature) <= classLevel)
|
||||
.forEach((classFeature) => {
|
||||
spellLidsIds.push(...ClassFeatureAccessors.getSpellListIds(classFeature));
|
||||
});
|
||||
return spellLidsIds;
|
||||
}
|
||||
/**
|
||||
* has mirrored deriver RaceDerivers.deriveConsolidatedRacialTraits
|
||||
* - most likely update together
|
||||
*
|
||||
* @param charClass
|
||||
* @param optionalClassFeatures
|
||||
* @param enableOptionalClassFeatures
|
||||
*/
|
||||
export function deriveConsolidatedClassFeatures(charClass, optionalClassFeatures, enableOptionalClassFeatures) {
|
||||
//filtering because after generating CharClass, this function is used in getUpdateEnableOptionalClassFeaturesSpellListIdsToRemove
|
||||
// to determine updated look of race and we don't store original definition info for classes
|
||||
const originalDefinitionClassFeatures = getDefinitionClassFeatures(charClass).filter((feature) => ClassFeatureAccessors.getFeatureType(feature) === FeatureTypeEnum.GRANTED);
|
||||
if (!enableOptionalClassFeatures) {
|
||||
return originalDefinitionClassFeatures;
|
||||
}
|
||||
const additionalClassFeatures = [];
|
||||
const definitionKeysToRemove = new Set();
|
||||
optionalClassFeatures.forEach((optionalClassFeature) => {
|
||||
const classFeature = OptionalClassFeatureAccessors.getClassFeature(optionalClassFeature);
|
||||
if (classFeature === null) {
|
||||
return;
|
||||
}
|
||||
const featureType = ClassFeatureAccessors.getFeatureType(classFeature);
|
||||
switch (featureType) {
|
||||
case FeatureTypeEnum.REPLACEMENT: {
|
||||
const affectedDefinitionKey = OptionalClassFeatureAccessors.getAffectedClassFeatureDefinitionKey(optionalClassFeature);
|
||||
const affectedFeatureKeys = ClassFeatureAccessors.getAffectedFeatureDefinitionKeys(classFeature);
|
||||
//verify this is a valid replacement
|
||||
if (affectedDefinitionKey &&
|
||||
affectedFeatureKeys.includes(affectedDefinitionKey) &&
|
||||
ClassFeatureValidators.isValidClassClassFeature(charClass, classFeature)) {
|
||||
definitionKeysToRemove.add(affectedDefinitionKey);
|
||||
additionalClassFeatures.push(classFeature);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case FeatureTypeEnum.ADDITIONAL:
|
||||
case FeatureTypeEnum.GRANTED:
|
||||
default:
|
||||
if (ClassFeatureValidators.isValidClassClassFeature(charClass, classFeature)) {
|
||||
additionalClassFeatures.push(classFeature);
|
||||
}
|
||||
}
|
||||
});
|
||||
//remove definitionKeysToRemove
|
||||
const filteredDefinitionClassFeatures = originalDefinitionClassFeatures.filter((feature) => !definitionKeysToRemove.has(ClassFeatureAccessors.getDefinitionKey(feature)));
|
||||
return [...filteredDefinitionClassFeatures, ...additionalClassFeatures];
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param charClass
|
||||
*/
|
||||
export function deriveMaxInfusions(charClass) {
|
||||
var _a;
|
||||
const features = getClassFeatures(charClass);
|
||||
const infuseFeature = features.find((classFeature) => ClassFeatureAccessors.getName(classFeature) === DB_STRING_INFUSE_ITEM);
|
||||
if (infuseFeature) {
|
||||
const infusionLevelScale = ClassFeatureAccessors.getLevelScale(infuseFeature);
|
||||
return (_a = infusionLevelScale === null || infusionLevelScale === void 0 ? void 0 : infusionLevelScale.fixedValue) !== null && _a !== void 0 ? _a : 0;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
@@ -0,0 +1,385 @@
|
||||
import { keyBy, orderBy } from 'lodash';
|
||||
import { AbilityDerivers } from '../Ability';
|
||||
import { CharacterDerivers, } from '../Character';
|
||||
import { ClassFeatureAccessors, ClassFeatureGenerators } from '../ClassFeature';
|
||||
import { DB_STRING_IMPROVED_PACT_WEAPON } from '../Core';
|
||||
import { DataOriginDataInfoKeyEnum, DataOriginTypeEnum } from '../DataOrigin';
|
||||
import { FormatUtils } from '../Format';
|
||||
import { ModifierDerivers, ModifierValidators } from '../Modifier';
|
||||
import { OptionAccessors } from '../Option';
|
||||
import { SpellAccessors, SpellDerivers, SpellGenerators, } from '../Spell';
|
||||
import { getActiveId, getBaseClassSpells, getClassFeatures, getDefinitionClassFeatures, getEnablesDedicatedWeapon, getEnablesHexWeapon, getEnablesPactWeapon, getId, getLevel, getMappingId, getName, getSlug, getSpellPrepareType, getSpellRules, getSpells, getSubclass, isPactMagicActive, isSpellcastingActive, isStartingClass, } from './accessors';
|
||||
import { deriveActiveId, deriveClassFeatureGroups, deriveConsolidatedClassFeatures, deriveDedicatedHexAndPactWeaponEnabled, deriveIsPactMagicActive, deriveIsSpellcastingActive, deriveSpellCastingLearningStyle, deriveSpellListIds, deriveSpellRules, deriveSpells, deriveUniqueKey, } from './derivers';
|
||||
export function generateBaseCharClasses(charClasses, optionalClassFeatures, allClassSpells, allClassAlwaysPreparedSpells, allClassAlwaysKnownSpells, appContext, ruleData, classesLookupData, definitionPool, characterPreferences, characterId, choiceComponents, baseFeats) {
|
||||
const orderedClasses = orderBy(charClasses, [(charClass) => isStartingClass(charClass), (charClass) => getName(charClass)], ['desc', 'asc']);
|
||||
const hack__baseCharClasses = orderedClasses.map((charClass) => hack__generateHackBaseCharClass(charClass, optionalClassFeatures, ruleData, classesLookupData, characterPreferences.enableOptionalClassFeatures));
|
||||
return hack__baseCharClasses.map((charClass) => generateBaseCharClass(charClass, optionalClassFeatures, allClassSpells, allClassAlwaysPreparedSpells, allClassAlwaysKnownSpells, appContext, ruleData, classesLookupData, definitionPool, characterId, choiceComponents, baseFeats));
|
||||
}
|
||||
export function hack__generateHackBaseCharClass(charClass, optionalClassFeatures, ruleData, classesLookupData, enableOptionalClassFeatures) {
|
||||
const consolidatedClassFeatureDefinitions = deriveConsolidatedClassFeatures(charClass, optionalClassFeatures, enableOptionalClassFeatures);
|
||||
return Object.assign(Object.assign({}, charClass), { spellRules: deriveSpellRules(charClass, consolidatedClassFeatureDefinitions, classesLookupData.choiceLookup, ruleData), isSpellcastingActive: deriveIsSpellcastingActive(consolidatedClassFeatureDefinitions, getLevel(charClass)), isPactMagicActive: deriveIsPactMagicActive(consolidatedClassFeatureDefinitions, getLevel(charClass)), classFeatures: consolidatedClassFeatureDefinitions });
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param charClass
|
||||
* @param classSpells
|
||||
* @param classFeatures
|
||||
*/
|
||||
function updateClassFeatures(charClass, classSpells, classFeatures) {
|
||||
return classFeatures.map((classFeature) => {
|
||||
const spells = SpellGenerators.updateClassFeatureSpells(ClassFeatureAccessors.getSpells(classFeature), classSpells);
|
||||
const options = ClassFeatureAccessors.getOptions(classFeature).map((option) => {
|
||||
const spells = SpellGenerators.updateClassFeatureSpells(OptionAccessors.getSpells(option), classSpells);
|
||||
return Object.assign(Object.assign({}, option), { spells });
|
||||
});
|
||||
return Object.assign(Object.assign({}, classFeature), { spells,
|
||||
options });
|
||||
});
|
||||
}
|
||||
export function generateBaseCharClass(charClass, optionalClassFeatures, allClassSpells, allClassAlwaysPreparedSpells, allClassAlwaysKnownSpells, appContext, ruleData, classesLookupData, definitionPool, characterId, choiceComponents, baseFeats) {
|
||||
const classModifiers = [];
|
||||
const featureSpells = [];
|
||||
const feats = [];
|
||||
const actions = [];
|
||||
const generatedClassFeatures = getDefinitionClassFeatures(charClass).map((classFeature) => ClassFeatureGenerators.generateClassFeature(charClass, classFeature, ruleData, classesLookupData, definitionPool, characterId, choiceComponents, baseFeats));
|
||||
// update modifiers, feats and actions arrays based on classFeatures
|
||||
generatedClassFeatures.forEach((generatedClassFeature) => {
|
||||
classModifiers.push(...ClassFeatureAccessors.getModifiers(generatedClassFeature));
|
||||
feats.push(...ClassFeatureAccessors.getFeats(generatedClassFeature));
|
||||
actions.push(...ClassFeatureAccessors.getActions(generatedClassFeature));
|
||||
ClassFeatureAccessors.getOptions(generatedClassFeature).forEach((option) => {
|
||||
classModifiers.push(...OptionAccessors.getModifiers(option));
|
||||
feats.push(...OptionAccessors.getFeats(option));
|
||||
actions.push(...OptionAccessors.getActions(option));
|
||||
});
|
||||
});
|
||||
const classSpells = deriveSpells(charClass, allClassSpells, allClassAlwaysPreparedSpells, allClassAlwaysKnownSpells);
|
||||
const updatedFeatures = updateClassFeatures(charClass, classSpells, generatedClassFeatures);
|
||||
// update spells array base on updated classFeatures
|
||||
updatedFeatures.forEach((classFeature) => {
|
||||
featureSpells.push(...ClassFeatureAccessors.getSpells(classFeature));
|
||||
ClassFeatureAccessors.getOptions(classFeature).forEach((option) => {
|
||||
featureSpells.push(...OptionAccessors.getSpells(option));
|
||||
});
|
||||
});
|
||||
const { activeFeatures, visibleFeatures, orderedFeatures, uniqueFeatures } = deriveClassFeatureGroups(charClass, updatedFeatures, appContext);
|
||||
// do any class features or modifiers enable hex, pact or dedicated weapons
|
||||
//TODO eventually should just be able to use modifiers here and not have to check class feature names
|
||||
const { enablesHexWeapon, enablesPactWeapon, enablesDedicatedWeapon } = deriveDedicatedHexAndPactWeaponEnabled(updatedFeatures, classModifiers);
|
||||
return Object.assign(Object.assign({}, charClass), { activeId: deriveActiveId(charClass), spells: SpellGenerators.updateClassSpells(featureSpells, classSpells), modifiers: classModifiers, featureSpells, classFeatures: updatedFeatures, optionalClassFeatures, activeClassFeatures: activeFeatures, visibleClassFeatures: visibleFeatures, orderedClassFeatures: orderedFeatures, uniqueClassFeatures: uniqueFeatures, feats,
|
||||
actions,
|
||||
enablesDedicatedWeapon,
|
||||
enablesHexWeapon,
|
||||
enablesPactWeapon, slug: FormatUtils.cobaltSlugify(getName(charClass)), spellListIds: deriveSpellListIds(updatedFeatures, getLevel(charClass)), spellCastingLearningStyle: deriveSpellCastingLearningStyle(charClass) });
|
||||
}
|
||||
export function generateClassFeatureLookup(baseCharClasses) {
|
||||
const lookup = {};
|
||||
for (const baseCharClass of baseCharClasses) {
|
||||
for (const classFeature of baseCharClass.classFeatures) {
|
||||
if (classFeature.definition) {
|
||||
lookup[classFeature.definition.id] = classFeature;
|
||||
}
|
||||
}
|
||||
}
|
||||
return lookup;
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param classes
|
||||
*/
|
||||
export function generateTotalClassLevel(classes) {
|
||||
return classes.reduce((acc, charClass) => (acc += getLevel(charClass)), 0);
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param classes
|
||||
* @param ruleData
|
||||
* @param proficiencyBonus
|
||||
* @param modifiers
|
||||
* @param abilityLookup
|
||||
*/
|
||||
export function generateClassSpellInfoLookup(classes, ruleData, proficiencyBonus, modifiers, abilityLookup) {
|
||||
const lookup = {};
|
||||
classes.forEach((charClass) => {
|
||||
var _a;
|
||||
const classId = getId(charClass);
|
||||
const classSlug = getSlug(charClass);
|
||||
const classLevel = getLevel(charClass);
|
||||
const classSpellRules = getSpellRules(charClass);
|
||||
const spellPrepareType = getSpellPrepareType(charClass);
|
||||
const spellcastingModifier = AbilityDerivers.deriveStatModifier(classSpellRules.spellcastingAbilityStatId, abilityLookup);
|
||||
const knownCantripsMax = classSpellRules.levelCantripsKnownMaxes
|
||||
? classSpellRules.levelCantripsKnownMaxes[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 : SpellDerivers.deriveSpellPrepareMax(spellPrepareType, classLevel, spellcastingModifier);
|
||||
const baseToHitModifier = SpellDerivers.deriveSpellAttackModifier(proficiencyBonus, spellcastingModifier);
|
||||
const bonusSpellSaveDcModifiers = modifiers.filter((modifier) => ModifierValidators.isBonusSpellSaveDc(modifier));
|
||||
const bonusSpellSaveDcModifierTotal = ModifierDerivers.sumModifiers(bonusSpellSaveDcModifiers, abilityLookup);
|
||||
const bonusClassCantripDamageModifiers = modifiers.filter((modifier) => ModifierValidators.isValidBonusClassCantripDamageModifier(modifier, classSlug));
|
||||
const bonusClassCantripDamageModifierTotal = ModifierDerivers.sumModifiers(bonusClassCantripDamageModifiers, abilityLookup);
|
||||
const classSaveDcModifiers = modifiers.filter((modifier) => ModifierValidators.isValidBonusClassSpellSaveDcModifier(modifier, classSlug));
|
||||
const classSaveDcModifierTotal = ModifierDerivers.sumModifiers(classSaveDcModifiers, abilityLookup);
|
||||
const bonusSpellAttackModifiers = modifiers.filter((modifier) => ModifierValidators.isValidBonusSpellAttackModifier(modifier, null));
|
||||
const bonusSpellAttackModifierTotal = ModifierDerivers.sumModifiers(bonusSpellAttackModifiers, abilityLookup);
|
||||
const classSpellAttackModifiers = modifiers.filter((modifier) => ModifierValidators.isValidBonusClassSpellAttackModifier(modifier, classSlug));
|
||||
const classSpellAttackModifierTotal = ModifierDerivers.sumModifiers(classSpellAttackModifiers, abilityLookup);
|
||||
const classSpellDamageModifiers = modifiers.filter((modifier) => ModifierValidators.isValidDamageClassSpellAttackModifier(modifier, classSlug));
|
||||
const classSpellDamageModifierTotal = ModifierDerivers.sumModifiers(classSpellDamageModifiers, abilityLookup);
|
||||
const spellSaveDc = CharacterDerivers.deriveAttackSaveValue(proficiencyBonus, spellcastingModifier) +
|
||||
bonusSpellSaveDcModifierTotal +
|
||||
classSaveDcModifierTotal;
|
||||
const bonusSpellAttack = bonusSpellAttackModifierTotal + classSpellAttackModifierTotal;
|
||||
const toHit = baseToHitModifier + bonusSpellAttack;
|
||||
lookup[classId] = {
|
||||
spellcastingModifier,
|
||||
baseToHitModifier,
|
||||
bonusSpellAttack,
|
||||
spellDamage: classSpellDamageModifierTotal,
|
||||
bonusCantripDamage: bonusClassCantripDamageModifierTotal,
|
||||
spellSaveDc,
|
||||
toHit,
|
||||
knownCantripsMax,
|
||||
prepareMax,
|
||||
knowsAllSpells: classSpellRules.knowsAllSpells,
|
||||
};
|
||||
});
|
||||
return lookup;
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param charClasses
|
||||
* @param classSpellInfoLookup
|
||||
* @param overallSpellInfo
|
||||
* @param spellListDataOriginLookup
|
||||
* @param valueLookup
|
||||
* @param ruleData
|
||||
* @param modifierData
|
||||
*/
|
||||
export function generateCharClasses(charClasses, classSpellInfoLookup, overallSpellInfo, spellListDataOriginLookup, valueLookup, ruleData, modifierData) {
|
||||
return charClasses.map((charClass) => generateCharClass(charClass, classSpellInfoLookup, overallSpellInfo, spellListDataOriginLookup, valueLookup, ruleData, modifierData));
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param charClass
|
||||
* @param classSpellInfoLookup
|
||||
* @param overallSpellInfo
|
||||
* @param spellListDataOriginLookup
|
||||
* @param valueLookup
|
||||
* @param ruleData
|
||||
* @param modifierData
|
||||
*/
|
||||
export function generateCharClass(charClass, classSpellInfoLookup, overallSpellInfo, spellListDataOriginLookup, valueLookup, ruleData, modifierData) {
|
||||
const classSpellInfo = classSpellInfoLookup[getId(charClass)];
|
||||
const generatedSpells = getBaseClassSpells(charClass).map((spell) => {
|
||||
const dataOriginSpell = SpellGenerators.generateDataOriginSpell(spell, DataOriginTypeEnum.CLASS, charClass, null, spellListDataOriginLookup);
|
||||
return SpellGenerators.generateClassSpell(dataOriginSpell, classSpellInfo, overallSpellInfo, valueLookup, ruleData, modifierData);
|
||||
});
|
||||
return Object.assign(Object.assign({}, charClass), { spells: generatedSpells });
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param classes
|
||||
*/
|
||||
export function generateStartingClass(classes) {
|
||||
const startingClass = classes.find((charClass) => isStartingClass(charClass));
|
||||
return startingClass ? startingClass : null;
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param classes
|
||||
*/
|
||||
export function generateHexWeaponEnabled(classes) {
|
||||
let hexWeaponEnabled = false;
|
||||
classes.forEach((charClass) => {
|
||||
hexWeaponEnabled = getEnablesHexWeapon(charClass) || hexWeaponEnabled;
|
||||
});
|
||||
return hexWeaponEnabled;
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param classes
|
||||
*/
|
||||
export function generatePactWeaponEnabled(classes) {
|
||||
let pactWeaponEnabled = false;
|
||||
classes.forEach((charClass) => {
|
||||
pactWeaponEnabled = getEnablesPactWeapon(charClass) || pactWeaponEnabled;
|
||||
});
|
||||
return pactWeaponEnabled;
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param classes
|
||||
*/
|
||||
export function generateImprovedPactWeaponEnabled(classes) {
|
||||
let improvedPactWeaponEnabled = false;
|
||||
classes.forEach((charClass) => {
|
||||
if (improvedPactWeaponEnabled) {
|
||||
return;
|
||||
}
|
||||
const features = getClassFeatures(charClass);
|
||||
features.forEach((feature) => {
|
||||
if (improvedPactWeaponEnabled) {
|
||||
return;
|
||||
}
|
||||
const options = ClassFeatureAccessors.getOptions(feature);
|
||||
options.forEach((option) => {
|
||||
improvedPactWeaponEnabled =
|
||||
improvedPactWeaponEnabled || OptionAccessors.getName(option) === DB_STRING_IMPROVED_PACT_WEAPON;
|
||||
});
|
||||
});
|
||||
});
|
||||
return improvedPactWeaponEnabled;
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param classes
|
||||
*/
|
||||
export function generateDedicatedWeaponEnabled(classes) {
|
||||
let dedicatedWeaponEnabled = false;
|
||||
classes.forEach((charClass) => {
|
||||
dedicatedWeaponEnabled = getEnablesDedicatedWeapon(charClass) || dedicatedWeaponEnabled;
|
||||
});
|
||||
return dedicatedWeaponEnabled;
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param classes
|
||||
*/
|
||||
export function generateClassLevelLookup(classes) {
|
||||
return classes.reduce((acc, charClass) => {
|
||||
var _a, _b;
|
||||
acc[getId(charClass)] = getLevel(charClass);
|
||||
// add subclass level - this is used for Druid Circle of the Moon creature rules
|
||||
const subclassId = (_b = (_a = getSubclass(charClass)) === null || _a === void 0 ? void 0 : _a.id) !== null && _b !== void 0 ? _b : null;
|
||||
if (subclassId) {
|
||||
acc[subclassId] = getLevel(charClass);
|
||||
}
|
||||
return acc;
|
||||
}, {});
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param modifierLookup
|
||||
* @param spellLookup
|
||||
* @param actionLookup
|
||||
* @param choiceLookup
|
||||
* @param optionLookup
|
||||
* @param valueLookup
|
||||
* @param featLookup
|
||||
* @param infusionChoiceInfusionLookup
|
||||
* @param knownInfusionLookupByChoiceKey
|
||||
* @param spellListDataOriginLookup
|
||||
*/
|
||||
export function generateClassesLookupData(modifierLookup, spellLookup, actionLookup, choiceLookup, optionLookup, valueLookup, featLookup, infusionChoiceInfusionLookup, knownInfusionLookupByChoiceKey, spellListDataOriginLookup) {
|
||||
return {
|
||||
modifierLookup,
|
||||
spellLookup,
|
||||
actionLookup,
|
||||
choiceLookup,
|
||||
optionLookup,
|
||||
valueLookup,
|
||||
featLookup,
|
||||
infusionChoiceInfusionLookup,
|
||||
knownInfusionLookupByChoiceKey,
|
||||
spellListDataOriginLookup,
|
||||
};
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param classes
|
||||
*/
|
||||
export function generateSpellcastingClasses(classes) {
|
||||
return classes.filter(isSpellcastingActive);
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param classes
|
||||
*/
|
||||
export function generatePactMagicClasses(classes) {
|
||||
return classes.filter(isPactMagicActive);
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param spellcastingClasses
|
||||
* @param pactMagicClasses
|
||||
*/
|
||||
export function generateAggregatedSpellClasses(spellcastingClasses, pactMagicClasses) {
|
||||
return [...spellcastingClasses, ...pactMagicClasses];
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param classes
|
||||
*/
|
||||
export function generateClassMappingIdLookupByActiveId(classes) {
|
||||
return classes.reduce((acc, charClass) => {
|
||||
acc[getActiveId(charClass)] = getMappingId(charClass);
|
||||
return acc;
|
||||
}, {});
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param classes
|
||||
* @param isMulticlassCharacter
|
||||
*/
|
||||
export function generateClassesModifiers(classes, isMulticlassCharacter) {
|
||||
const modifiers = [];
|
||||
if (classes.length === 0) {
|
||||
return modifiers;
|
||||
}
|
||||
classes.forEach((charClass) => {
|
||||
getClassFeatures(charClass).forEach((classFeature) => {
|
||||
modifiers.push(...ClassFeatureAccessors.getModifiers(classFeature).filter((modifier) => ModifierValidators.isValidClassModifier(modifier, charClass, isMulticlassCharacter)));
|
||||
ClassFeatureAccessors.getOptions(classFeature).forEach((option) => {
|
||||
modifiers.push(...OptionAccessors.getModifiers(option).filter((modifier) => ModifierValidators.isValidClassModifier(modifier, charClass, isMulticlassCharacter)));
|
||||
});
|
||||
});
|
||||
});
|
||||
return modifiers;
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param classes
|
||||
*/
|
||||
export function generateRefClassData(classes) {
|
||||
let data = {};
|
||||
classes.forEach((charClass) => {
|
||||
data[deriveUniqueKey(charClass)] = {
|
||||
[DataOriginDataInfoKeyEnum.PRIMARY]: charClass,
|
||||
[DataOriginDataInfoKeyEnum.PARENT]: null,
|
||||
};
|
||||
});
|
||||
return data;
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param classes
|
||||
*/
|
||||
export function generateClassSpellListSpellsLookup(classes) {
|
||||
const lookup = {};
|
||||
classes.forEach((charClass) => {
|
||||
const spells = getSpells(charClass);
|
||||
spells.forEach((spell) => {
|
||||
const spellListId = SpellAccessors.getSpellListId(spell);
|
||||
if (spellListId !== null) {
|
||||
if (!lookup[spellListId]) {
|
||||
lookup[spellListId] = [];
|
||||
}
|
||||
lookup[spellListId].push({
|
||||
spell,
|
||||
charClass,
|
||||
});
|
||||
}
|
||||
});
|
||||
});
|
||||
return lookup;
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param classes
|
||||
*/
|
||||
export function generateBaseClassLookup(classes) {
|
||||
return keyBy(classes, (baseClass) => getMappingId(baseClass));
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
import * as ClassAccessors from './accessors';
|
||||
import * as ClassDerivers from './derivers';
|
||||
import * as ClassGenerators from './generators';
|
||||
import * as ClassTypings from './typings';
|
||||
import * as ClassUtils from './utils';
|
||||
import * as ClassValidators from './validators';
|
||||
export * from './typings';
|
||||
export { ClassAccessors, ClassGenerators, ClassDerivers, ClassValidators, ClassUtils };
|
||||
export default Object.assign(Object.assign(Object.assign(Object.assign(Object.assign(Object.assign({}, ClassAccessors), ClassGenerators), ClassTypings), ClassDerivers), ClassValidators), ClassUtils);
|
||||
@@ -0,0 +1,18 @@
|
||||
import { difference } from 'lodash';
|
||||
import { getLevel, getOptionalClassFeatures, getSpellListIds } from './accessors';
|
||||
import { deriveConsolidatedClassFeatures, deriveSpellListIds } from './derivers';
|
||||
/**
|
||||
*
|
||||
* @param classes
|
||||
* @param newEnableOptionalClassFeatures
|
||||
*/
|
||||
export function getUpdateEnableOptionalClassFeaturesSpellListIdsToRemove(classes, newEnableOptionalClassFeatures) {
|
||||
const spellListIdsToRemove = [];
|
||||
classes.forEach((charClass) => {
|
||||
const existingSpellListIds = getSpellListIds(charClass);
|
||||
const newClassFeatures = deriveConsolidatedClassFeatures(charClass, getOptionalClassFeatures(charClass), newEnableOptionalClassFeatures);
|
||||
const newSpellListIds = deriveSpellListIds(newClassFeatures, getLevel(charClass));
|
||||
spellListIdsToRemove.push(...difference(existingSpellListIds, newSpellListIds));
|
||||
});
|
||||
return spellListIdsToRemove;
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
import { getId, getSubclass } from './accessors';
|
||||
/**
|
||||
*
|
||||
* @param charClass
|
||||
* @param id
|
||||
*/
|
||||
export function isValidClassId(charClass, id) {
|
||||
var _a, _b;
|
||||
const subClassId = (_b = (_a = getSubclass(charClass)) === null || _a === void 0 ? void 0 : _a.id) !== null && _b !== void 0 ? _b : -1;
|
||||
return id === getId(charClass) || id === subClassId;
|
||||
}
|
||||
@@ -0,0 +1,429 @@
|
||||
import { ActivationAccessors } from '../Activation';
|
||||
import { FeatureTypeEnum } from '../Core';
|
||||
/**
|
||||
*
|
||||
* @param feature
|
||||
*/
|
||||
export function getDefinition(feature) {
|
||||
return feature.definition;
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param feature
|
||||
*/
|
||||
export function getDefinitionKey(feature) {
|
||||
var _a, _b;
|
||||
return (_b = (_a = getDefinition(feature)) === null || _a === void 0 ? void 0 : _a.definitionKey) !== null && _b !== void 0 ? _b : '';
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param feature
|
||||
*/
|
||||
export function getName(feature) {
|
||||
return getDefinitionName(feature);
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param feature
|
||||
*/
|
||||
export function getDefinitionName(feature) {
|
||||
var _a, _b;
|
||||
return (_b = (_a = getDefinition(feature)) === null || _a === void 0 ? void 0 : _a.name) !== null && _b !== void 0 ? _b : '';
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param feature
|
||||
*/
|
||||
export function getId(feature) {
|
||||
var _a, _b;
|
||||
return (_b = (_a = getDefinition(feature)) === null || _a === void 0 ? void 0 : _a.id) !== null && _b !== void 0 ? _b : -1;
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param feature
|
||||
*/
|
||||
export function getEntityTypeId(feature) {
|
||||
var _a, _b;
|
||||
return (_b = (_a = getDefinition(feature)) === null || _a === void 0 ? void 0 : _a.entityTypeId) !== null && _b !== void 0 ? _b : -1;
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param feature
|
||||
*/
|
||||
export function getUniqueKey(feature) {
|
||||
return `${getId(feature)}-${getEntityTypeId(feature)}`;
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param feature
|
||||
*/
|
||||
export function getDescription(feature) {
|
||||
return getDefinitionDescription(feature);
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param feature
|
||||
*/
|
||||
export function getDefinitionDescription(feature) {
|
||||
var _a, _b;
|
||||
return (_b = (_a = getDefinition(feature)) === null || _a === void 0 ? void 0 : _a.description) !== null && _b !== void 0 ? _b : null;
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param feature
|
||||
*/
|
||||
export function getSourceId(feature) {
|
||||
return getDefinitionSourceId(feature);
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param feature
|
||||
*/
|
||||
export function getDefinitionSourceId(feature) {
|
||||
var _a, _b;
|
||||
return (_b = (_a = getDefinition(feature)) === null || _a === void 0 ? void 0 : _a.sourceId) !== null && _b !== void 0 ? _b : null;
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param feature
|
||||
*/
|
||||
export function getSourcePage(feature) {
|
||||
return getDefinitionSourcePage(feature);
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param feature
|
||||
*/
|
||||
export function getDefinitionSourcePage(feature) {
|
||||
var _a, _b;
|
||||
return (_b = (_a = getDefinition(feature)) === null || _a === void 0 ? void 0 : _a.sourcePageNumber) !== null && _b !== void 0 ? _b : null;
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param feature
|
||||
*/
|
||||
export function getActivation(feature) {
|
||||
return getDefinitionActivation(feature);
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param feature
|
||||
*/
|
||||
export function getDefinitionActivation(feature) {
|
||||
var _a, _b;
|
||||
return (_b = (_a = getDefinition(feature)) === null || _a === void 0 ? void 0 : _a.activation) !== null && _b !== void 0 ? _b : null;
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param feature
|
||||
*/
|
||||
export function getActivationTime(feature) {
|
||||
return ActivationAccessors.getTime(getActivation(feature));
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param feature
|
||||
*/
|
||||
export function getActivationType(feature) {
|
||||
return ActivationAccessors.getType(getActivation(feature));
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param feature
|
||||
*/
|
||||
export function getDefinitionLevelScales(feature) {
|
||||
var _a, _b;
|
||||
return (_b = (_a = getDefinition(feature)) === null || _a === void 0 ? void 0 : _a.levelScales) !== null && _b !== void 0 ? _b : [];
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param feature
|
||||
*/
|
||||
export function getLevelScales(feature) {
|
||||
return getDefinitionLevelScales(feature);
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param feature
|
||||
*/
|
||||
export function getDefinitionLimitedUse(feature) {
|
||||
var _a, _b;
|
||||
return (_b = (_a = getDefinition(feature)) === null || _a === void 0 ? void 0 : _a.limitedUse) !== null && _b !== void 0 ? _b : [];
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param feature
|
||||
*/
|
||||
export function getLimitedUse(feature) {
|
||||
return getDefinitionLimitedUse(feature);
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param feature
|
||||
*/
|
||||
export function getMultiClassDescription(feature) {
|
||||
return getDefinitionMultiClassDescription(feature);
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param feature
|
||||
*/
|
||||
export function getDefinitionMultiClassDescription(feature) {
|
||||
var _a, _b;
|
||||
return (_b = (_a = getDefinition(feature)) === null || _a === void 0 ? void 0 : _a.multiClassDescription) !== null && _b !== void 0 ? _b : null;
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param feature
|
||||
*/
|
||||
export function getSnippet(feature) {
|
||||
return getDefinitionSnippet(feature);
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param feature
|
||||
*/
|
||||
export function getDefinitionSnippet(feature) {
|
||||
var _a, _b;
|
||||
return (_b = (_a = getDefinition(feature)) === null || _a === void 0 ? void 0 : _a.snippet) !== null && _b !== void 0 ? _b : null;
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param feature
|
||||
*/
|
||||
export function getDisplayOrder(feature) {
|
||||
return getDefinitionDisplayOrder(feature);
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param feature
|
||||
*/
|
||||
export function getDefinitionDisplayOrder(feature) {
|
||||
var _a, _b;
|
||||
return (_b = (_a = getDefinition(feature)) === null || _a === void 0 ? void 0 : _a.displayOrder) !== null && _b !== void 0 ? _b : null;
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param feature
|
||||
*/
|
||||
export function getHideInBuilder(feature) {
|
||||
return getDefinitionHideInBuilder(feature);
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param feature
|
||||
*/
|
||||
export function getDefinitionHideInBuilder(feature) {
|
||||
var _a, _b;
|
||||
return (_b = (_a = getDefinition(feature)) === null || _a === void 0 ? void 0 : _a.hideInBuilder) !== null && _b !== void 0 ? _b : false;
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param feature
|
||||
*/
|
||||
export function getHideInSheet(feature) {
|
||||
return getDefinitionHideInSheet(feature);
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param feature
|
||||
*/
|
||||
export function getDefinitionHideInSheet(feature) {
|
||||
var _a, _b;
|
||||
return (_b = (_a = getDefinition(feature)) === null || _a === void 0 ? void 0 : _a.hideInSheet) !== null && _b !== void 0 ? _b : false;
|
||||
}
|
||||
/**
|
||||
* @deprecated see getDefinitionIsSubClassFeature
|
||||
* @param feature
|
||||
*/
|
||||
export function getIsSubClassFeature(feature) {
|
||||
return getDefinitionIsSubClassFeature(feature);
|
||||
}
|
||||
/**
|
||||
* @deprecated we are switching to the property "classId" instead for more useful information
|
||||
* @param feature
|
||||
*/
|
||||
export function getDefinitionIsSubClassFeature(feature) {
|
||||
var _a, _b;
|
||||
return (_b = (_a = getDefinition(feature)) === null || _a === void 0 ? void 0 : _a.isSubClassFeature) !== null && _b !== void 0 ? _b : false;
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param feature
|
||||
*/
|
||||
export function getDefinitionClassId(feature) {
|
||||
var _a, _b;
|
||||
return (_b = (_a = getDefinition(feature)) === null || _a === void 0 ? void 0 : _a.classId) !== null && _b !== void 0 ? _b : -1;
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param feature
|
||||
*/
|
||||
export function getClassId(feature) {
|
||||
return getDefinitionClassId(feature);
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param feature
|
||||
*/
|
||||
export function getRequiredLevel(feature) {
|
||||
return getDefinitionRequiredLevel(feature);
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param feature
|
||||
*/
|
||||
export function getDefinitionRequiredLevel(feature) {
|
||||
var _a, _b;
|
||||
return (_b = (_a = getDefinition(feature)) === null || _a === void 0 ? void 0 : _a.requiredLevel) !== null && _b !== void 0 ? _b : -1;
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param feature
|
||||
*/
|
||||
export function getDefinitionCreatureRules(feature) {
|
||||
var _a, _b;
|
||||
return (_b = (_a = getDefinition(feature)) === null || _a === void 0 ? void 0 : _a.creatureRules) !== null && _b !== void 0 ? _b : [];
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param feature
|
||||
*/
|
||||
export function getCreatureRules(feature) {
|
||||
return getDefinitionCreatureRules(feature);
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param feature
|
||||
*/
|
||||
export function getDefinitionSpellListIds(feature) {
|
||||
var _a, _b;
|
||||
return (_b = (_a = getDefinition(feature)) === null || _a === void 0 ? void 0 : _a.spellListIds) !== null && _b !== void 0 ? _b : [];
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param feature
|
||||
*/
|
||||
export function getSpellListIds(feature) {
|
||||
return getDefinitionSpellListIds(feature);
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param feature
|
||||
*/
|
||||
export function getAffectedFeatureDefinitionKeys(feature) {
|
||||
return getDefinitionAffectedFeatureDefinitionKeys(feature);
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param feature
|
||||
*/
|
||||
export function getDefinitionAffectedFeatureDefinitionKeys(feature) {
|
||||
var _a, _b;
|
||||
return (_b = (_a = getDefinition(feature)) === null || _a === void 0 ? void 0 : _a.affectedFeatureDefinitionKeys) !== null && _b !== void 0 ? _b : [];
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param feature
|
||||
*/
|
||||
export function getSources(feature) {
|
||||
return getDefinitionSources(feature);
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param feature
|
||||
*/
|
||||
export function getDefinitionSources(feature) {
|
||||
var _a, _b;
|
||||
return (_b = (_a = getDefinition(feature)) === null || _a === void 0 ? void 0 : _a.sources) !== null && _b !== void 0 ? _b : [];
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param feature
|
||||
*/
|
||||
export function getFeatureType(feature) {
|
||||
return getDefinitionFeatureType(feature);
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param feature
|
||||
*/
|
||||
export function getDefinitionFeatureType(feature) {
|
||||
var _a, _b;
|
||||
return (_b = (_a = getDefinition(feature)) === null || _a === void 0 ? void 0 : _a.featureType) !== null && _b !== void 0 ? _b : FeatureTypeEnum.GRANTED;
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param feature
|
||||
*/
|
||||
export function getLevelScale(feature) {
|
||||
return feature.levelScale;
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param feature
|
||||
*/
|
||||
export function getOptions(feature) {
|
||||
return feature.options;
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param feature
|
||||
*/
|
||||
export function getActions(feature) {
|
||||
return feature.actions;
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param feature
|
||||
*/
|
||||
export function getChoices(feature) {
|
||||
return feature.choices;
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param feature
|
||||
*/
|
||||
export function getModifiers(feature) {
|
||||
return feature.modifiers;
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param feature
|
||||
*/
|
||||
export function getSpells(feature) {
|
||||
return feature.spells;
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param feature
|
||||
*/
|
||||
export function getFeats(feature) {
|
||||
return feature.feats;
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param feature
|
||||
*/
|
||||
export function getInfusionChoices(feature) {
|
||||
return feature.infusionChoices;
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param feature
|
||||
*/
|
||||
export function getInfusionRules(feature) {
|
||||
var _a, _b;
|
||||
return (_b = (_a = getDefinition(feature)) === null || _a === void 0 ? void 0 : _a.infusionRules) !== null && _b !== void 0 ? _b : [];
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param feature
|
||||
*/
|
||||
export function getAccessType(feature) {
|
||||
return feature.accessType;
|
||||
}
|
||||
export function getFeatListContracts(featureContract) {
|
||||
var _a, _b;
|
||||
return (_b = (_a = getDefinition(featureContract)) === null || _a === void 0 ? void 0 : _a.grantedFeats) !== null && _b !== void 0 ? _b : [];
|
||||
}
|
||||
@@ -0,0 +1,93 @@
|
||||
import { ActionGenerators } from '../Action';
|
||||
import { ChoiceGenerators } from '../Choice';
|
||||
import { ClassAccessors } from '../Class';
|
||||
import { CreatureRuleGenerators } from '../CreatureRule';
|
||||
import { DataOriginDataInfoKeyEnum, DataOriginGenerators, DataOriginTypeEnum, } from '../DataOrigin';
|
||||
import { DefinitionPoolUtils } from '../DefinitionPool';
|
||||
import { FeatGenerators } from '../Feat';
|
||||
import { FeatList } from '../FeatList';
|
||||
import { InfusionChoiceGenerators } from '../InfusionChoice';
|
||||
import { ModifierGenerators } from '../Modifier';
|
||||
import { OptionAccessors, OptionGenerators } from '../Option';
|
||||
import { SpellGenerators } from '../Spell';
|
||||
import { getCreatureRules, getDefinitionKey, getEntityTypeId, getFeatListContracts, getId, getInfusionRules, getOptions, getUniqueKey, } from './accessors';
|
||||
export function generateClassFeature(charClass, classFeature, ruleData, classesLookupData, definitionPool, characterId, choiceComponents, baseFeats) {
|
||||
const id = getId(classFeature);
|
||||
const entityTypeId = getEntityTypeId(classFeature);
|
||||
const { actionLookup, choiceLookup, modifierLookup, spellLookup, valueLookup, featLookup, optionLookup, infusionChoiceInfusionLookup, knownInfusionLookupByChoiceKey, spellListDataOriginLookup, } = classesLookupData;
|
||||
const actions = ActionGenerators.generateBaseActions(id, entityTypeId, actionLookup, valueLookup, DataOriginTypeEnum.CLASS_FEATURE, classFeature, charClass);
|
||||
const choices = ChoiceGenerators.generateBaseChoices(id, entityTypeId, choiceLookup, DataOriginTypeEnum.CLASS_FEATURE, classFeature, charClass);
|
||||
const modifiers = ModifierGenerators.generateModifiers(id, entityTypeId, modifierLookup, DataOriginTypeEnum.CLASS_FEATURE, classFeature, charClass);
|
||||
const spells = SpellGenerators.generateBaseSpells(id, entityTypeId, spellLookup, DataOriginTypeEnum.CLASS_FEATURE, classFeature, charClass, ruleData, spellListDataOriginLookup, valueLookup);
|
||||
const feats = FeatGenerators.generateDataOriginFeats(id, entityTypeId, featLookup, DataOriginTypeEnum.CLASS_FEATURE, classFeature, charClass);
|
||||
const options = generateClassFeatureOptions(classFeature, charClass, featLookup, actionLookup, spellLookup, optionLookup, modifierLookup, valueLookup, spellListDataOriginLookup, ruleData);
|
||||
const infusionChoices = InfusionChoiceGenerators.generateInfusionChoices(getInfusionRules(classFeature), DataOriginTypeEnum.CLASS_FEATURE, classFeature, charClass, infusionChoiceInfusionLookup, knownInfusionLookupByChoiceKey, characterId);
|
||||
const featLists = getFeatListContracts(classFeature).map((contract) => new FeatList(contract, choiceComponents.definitionKeyNameMap, baseFeats));
|
||||
return Object.assign(Object.assign({}, classFeature), { actions,
|
||||
choices,
|
||||
feats,
|
||||
modifiers,
|
||||
spells,
|
||||
options,
|
||||
infusionChoices, accessType: DefinitionPoolUtils.getDefinitionAccessType(getDefinitionKey(classFeature), definitionPool), featLists });
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param classFeature
|
||||
* @param charClass
|
||||
* @param featLookup
|
||||
* @param actionLookup
|
||||
* @param spellLookup
|
||||
* @param optionLookup
|
||||
* @param modifierLookup
|
||||
* @param valueLookup
|
||||
* @param spellListDataOriginLookup
|
||||
* @param ruleData
|
||||
*/
|
||||
export function generateClassFeatureOptions(classFeature, charClass, featLookup, actionLookup, spellLookup, optionLookup, modifierLookup, valueLookup, spellListDataOriginLookup, ruleData) {
|
||||
const baseOptions = OptionGenerators.generateDataOriginBaseOptions(getId(classFeature), getEntityTypeId(classFeature), optionLookup, DataOriginTypeEnum.CLASS_FEATURE, classFeature, charClass);
|
||||
return OptionGenerators.generateOptions(baseOptions, DataOriginTypeEnum.CLASS_FEATURE, featLookup, actionLookup, spellLookup, optionLookup, modifierLookup, valueLookup, spellListDataOriginLookup, ruleData, classFeature, charClass);
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param classes
|
||||
* @param xpInfo
|
||||
* @param ruleData
|
||||
*/
|
||||
export function generateClassCreatureRules(classes, xpInfo, ruleData) {
|
||||
const rules = [];
|
||||
classes.forEach((charClass) => {
|
||||
const features = ClassAccessors.getActiveClassFeatures(charClass);
|
||||
features.forEach((feature) => {
|
||||
const dataOrigin = DataOriginGenerators.generateDataOrigin(DataOriginTypeEnum.CLASS_FEATURE, feature, charClass);
|
||||
const featureRules = getCreatureRules(feature);
|
||||
featureRules.forEach((rule) => {
|
||||
rules.push(CreatureRuleGenerators.generateRule(rule, dataOrigin, xpInfo, ruleData));
|
||||
});
|
||||
const options = getOptions(feature);
|
||||
options.forEach((option) => {
|
||||
const optionRules = OptionAccessors.getCreatureRules(option);
|
||||
optionRules.forEach((rule) => {
|
||||
rules.push(CreatureRuleGenerators.generateRule(rule, dataOrigin, xpInfo, ruleData));
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
return rules;
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param classes
|
||||
*/
|
||||
export function generateRefClassFeatureData(classes) {
|
||||
let data = {};
|
||||
classes.forEach((charClass) => {
|
||||
ClassAccessors.getClassFeatures(charClass).forEach((classFeature) => {
|
||||
data[getUniqueKey(classFeature)] = {
|
||||
[DataOriginDataInfoKeyEnum.PRIMARY]: classFeature,
|
||||
[DataOriginDataInfoKeyEnum.PARENT]: charClass,
|
||||
};
|
||||
});
|
||||
});
|
||||
return data;
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
import * as ClassFeatureAccessors from './accessors';
|
||||
import * as ClassFeatureGenerators from './generators';
|
||||
import * as ClassFeatureSimulators from './simulators';
|
||||
import * as ClassFeatureTypings from './typings';
|
||||
import * as ClassFeatureUtils from './utils';
|
||||
import * as ClassFeatureValidators from './validators';
|
||||
export * from './typings';
|
||||
export { ClassFeatureAccessors, ClassFeatureGenerators, ClassFeatureSimulators, ClassFeatureUtils, ClassFeatureValidators, };
|
||||
export default Object.assign(Object.assign(Object.assign(Object.assign(Object.assign(Object.assign({}, ClassFeatureAccessors), ClassFeatureGenerators), ClassFeatureSimulators), ClassFeatureTypings), ClassFeatureUtils), ClassFeatureValidators);
|
||||
@@ -0,0 +1,42 @@
|
||||
import { ClassAccessors } from '../Class';
|
||||
import { DefinitionPoolUtils } from '../DefinitionPool';
|
||||
import { FeatList } from '../FeatList';
|
||||
import { getFeatListContracts } from './accessors';
|
||||
export function simulateClassFeature(definitionKey, definitionPool,
|
||||
// Optional args. Sometimes this method is called just to get an object that kind of looks like
|
||||
// a class feature, but is only used for a few properties.
|
||||
classes, choiceComponents, baseFeats) {
|
||||
var _a;
|
||||
const definition = DefinitionPoolUtils.getClassFeatureDefinition(definitionKey, definitionPool);
|
||||
if (definition === null) {
|
||||
return null;
|
||||
}
|
||||
let levelScale = null;
|
||||
if (definition === null || definition === void 0 ? void 0 : definition.levelScales) {
|
||||
// Find class that correlates to feature
|
||||
const classFeatureClass = classes === null || classes === void 0 ? void 0 : classes.find((classIterator) => ClassAccessors.getId(classIterator) === definition.classId);
|
||||
if (classFeatureClass) {
|
||||
// Find max level scale of appropriate level
|
||||
(_a = definition.levelScales) === null || _a === void 0 ? void 0 : _a.forEach((definitionLevelScale) => {
|
||||
if (definitionLevelScale.level <= classFeatureClass.level) {
|
||||
levelScale = definitionLevelScale;
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
const classFeatureMapping = simulateClassFeatureContract({
|
||||
definition,
|
||||
levelScale,
|
||||
});
|
||||
const featLists = choiceComponents && baseFeats
|
||||
? getFeatListContracts(classFeatureMapping).map((contract) => new FeatList(contract, choiceComponents.definitionKeyNameMap, baseFeats))
|
||||
: [];
|
||||
return Object.assign(Object.assign({}, classFeatureMapping), { actions: [], choices: [], feats: [], modifiers: [], options: [], spells: [], infusionChoices: [], accessType: DefinitionPoolUtils.getDefinitionAccessType(definitionKey, definitionPool), featLists });
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param classFeatureProps
|
||||
*/
|
||||
export function simulateClassFeatureContract(classFeatureProps) {
|
||||
return Object.assign({ levelScale: null, definition: null }, classFeatureProps);
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
import { ClassAccessors } from '../Class';
|
||||
import { AppContextTypeEnum, DB_STRING_MARTIAL_ARTS, DB_STRING_PACT_MAGIC, DB_STRING_SPELLCASTING, DB_STRING_DEDICATED_WEAPON, } from '../Core';
|
||||
import { getHideInBuilder, getHideInSheet, getLevelScale, getName } from './accessors';
|
||||
export function doesEnableSpellcasting(feature) {
|
||||
return getName(feature) === DB_STRING_SPELLCASTING;
|
||||
}
|
||||
export function doesEnablePactMagic(feature) {
|
||||
return getName(feature) === DB_STRING_PACT_MAGIC;
|
||||
}
|
||||
export function doesEnableDedicatedWeapon(feature) {
|
||||
return getName(feature) === DB_STRING_DEDICATED_WEAPON;
|
||||
}
|
||||
export function doesEnableMartialArts(feature) {
|
||||
return getName(feature).indexOf(DB_STRING_MARTIAL_ARTS) === 0;
|
||||
}
|
||||
export function getContextData(feature, charClass) {
|
||||
return {
|
||||
levelScale: getLevelScale(feature),
|
||||
classLevel: charClass ? ClassAccessors.getLevel(charClass) : null,
|
||||
};
|
||||
}
|
||||
export function getHideInContext(feature, context) {
|
||||
if (context === AppContextTypeEnum.SHEET) {
|
||||
return getHideInSheet(feature);
|
||||
}
|
||||
return getHideInBuilder(feature);
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
import { ClassValidators } from '../Class';
|
||||
import { getClassId } from './accessors';
|
||||
/**
|
||||
*
|
||||
* @param charClass
|
||||
* @param classFeature
|
||||
*/
|
||||
export function isValidClassClassFeature(charClass, classFeature) {
|
||||
return ClassValidators.isValidClassId(charClass, getClassId(classFeature));
|
||||
}
|
||||
@@ -0,0 +1,132 @@
|
||||
/**
|
||||
*
|
||||
* @param condition
|
||||
*/
|
||||
export function getUniqueKey(condition) {
|
||||
return `${getId(condition)}-${getEntityTypeId(condition)}`;
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param condition
|
||||
*/
|
||||
export function getContractId(condition) {
|
||||
return condition.id;
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param condition
|
||||
*/
|
||||
export function getContractLevel(condition) {
|
||||
return condition.level;
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param condition
|
||||
*/
|
||||
export function getDescription(condition) {
|
||||
return getDefinitionDescription(condition);
|
||||
}
|
||||
export function getDefinitionDescription(condition) {
|
||||
var _a, _b;
|
||||
return (_b = (_a = condition.definition) === null || _a === void 0 ? void 0 : _a.description) !== null && _b !== void 0 ? _b : null;
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param condition
|
||||
*/
|
||||
export function getEntityTypeId(condition) {
|
||||
return getDefinitionEntityTypeId(condition);
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param condition
|
||||
*/
|
||||
export function getDefinitionEntityTypeId(condition) {
|
||||
var _a, _b;
|
||||
return (_b = (_a = condition.definition) === null || _a === void 0 ? void 0 : _a.entityTypeId) !== null && _b !== void 0 ? _b : -1;
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param condition
|
||||
*/
|
||||
export function getId(condition) {
|
||||
return getDefinitionId(condition);
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param condition
|
||||
*/
|
||||
export function getDefinitionId(condition) {
|
||||
var _a, _b;
|
||||
return (_b = (_a = condition.definition) === null || _a === void 0 ? void 0 : _a.id) !== null && _b !== void 0 ? _b : -1;
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param condition
|
||||
*/
|
||||
export function getDefinitionLevels(condition) {
|
||||
var _a, _b;
|
||||
return (_b = (_a = condition.definition) === null || _a === void 0 ? void 0 : _a.levels) !== null && _b !== void 0 ? _b : [];
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param condition
|
||||
*/
|
||||
export function getName(condition) {
|
||||
return getDefinitionName(condition);
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param condition
|
||||
*/
|
||||
export function getDefinitionName(condition) {
|
||||
var _a, _b;
|
||||
return (_b = (_a = condition.definition) === null || _a === void 0 ? void 0 : _a.name) !== null && _b !== void 0 ? _b : '';
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param condition
|
||||
*/
|
||||
export function getSlug(condition) {
|
||||
return getDefinitionSlug(condition);
|
||||
}
|
||||
export function getDefinitionSlug(condition) {
|
||||
var _a, _b;
|
||||
return (_b = (_a = condition.definition) === null || _a === void 0 ? void 0 : _a.slug) !== null && _b !== void 0 ? _b : '';
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param condition
|
||||
*/
|
||||
export function getType(condition) {
|
||||
return getDefinitionType(condition);
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param condition
|
||||
*/
|
||||
export function getDefinitionType(condition) {
|
||||
var _a, _b;
|
||||
return (_b = (_a = condition.definition) === null || _a === void 0 ? void 0 : _a.type) !== null && _b !== void 0 ? _b : -1;
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param condition
|
||||
*/
|
||||
export function getLevels(condition) {
|
||||
return condition.levels;
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param condition
|
||||
*/
|
||||
export function getModifiers(condition) {
|
||||
return condition.modifiers;
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param condition
|
||||
*/
|
||||
export function getActiveLevel(condition) {
|
||||
return condition.level;
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
export var ConditionTypeEnum;
|
||||
(function (ConditionTypeEnum) {
|
||||
ConditionTypeEnum[ConditionTypeEnum["STANDARD"] = 1] = "STANDARD";
|
||||
ConditionTypeEnum[ConditionTypeEnum["SPECIAL"] = 2] = "SPECIAL";
|
||||
})(ConditionTypeEnum || (ConditionTypeEnum = {}));
|
||||
export var ConditionIdEnum;
|
||||
(function (ConditionIdEnum) {
|
||||
ConditionIdEnum[ConditionIdEnum["BLINDED"] = 1] = "BLINDED";
|
||||
ConditionIdEnum[ConditionIdEnum["CHARMED"] = 2] = "CHARMED";
|
||||
ConditionIdEnum[ConditionIdEnum["DEAFENED"] = 3] = "DEAFENED";
|
||||
ConditionIdEnum[ConditionIdEnum["EXHAUSTION"] = 4] = "EXHAUSTION";
|
||||
ConditionIdEnum[ConditionIdEnum["FRIGHTENED"] = 5] = "FRIGHTENED";
|
||||
ConditionIdEnum[ConditionIdEnum["GRAPPLED"] = 6] = "GRAPPLED";
|
||||
ConditionIdEnum[ConditionIdEnum["INCAPACITATED"] = 7] = "INCAPACITATED";
|
||||
ConditionIdEnum[ConditionIdEnum["INVISIBLE"] = 8] = "INVISIBLE";
|
||||
ConditionIdEnum[ConditionIdEnum["PARALYZED"] = 9] = "PARALYZED";
|
||||
ConditionIdEnum[ConditionIdEnum["PETRIFIED"] = 10] = "PETRIFIED";
|
||||
ConditionIdEnum[ConditionIdEnum["POISONED"] = 11] = "POISONED";
|
||||
ConditionIdEnum[ConditionIdEnum["PRONE"] = 12] = "PRONE";
|
||||
ConditionIdEnum[ConditionIdEnum["RESTRAINED"] = 13] = "RESTRAINED";
|
||||
ConditionIdEnum[ConditionIdEnum["STUNNED"] = 14] = "STUNNED";
|
||||
ConditionIdEnum[ConditionIdEnum["UNCONSCIOUS"] = 15] = "UNCONSCIOUS";
|
||||
})(ConditionIdEnum || (ConditionIdEnum = {}));
|
||||
@@ -0,0 +1,74 @@
|
||||
import { TypeScriptUtils } from '../../utils';
|
||||
import { ConditionLevelGenerators } from '../ConditionLevel';
|
||||
import { DataOriginDataInfoKeyEnum, DataOriginTypeEnum } from '../DataOrigin';
|
||||
import { ModifierGenerators } from '../Modifier';
|
||||
import { RuleDataUtils } from '../RuleData';
|
||||
import { getContractId, getContractLevel, getDefinitionLevels, getEntityTypeId, getId, getModifiers, getUniqueKey, } from './accessors';
|
||||
/**
|
||||
*
|
||||
* @param conditions
|
||||
* @param modifierLookup
|
||||
* @param ruleData
|
||||
*/
|
||||
export function generateConditions(conditions, modifierLookup, ruleData) {
|
||||
return conditions
|
||||
.map((characterCondition) => generateCondition(characterCondition, modifierLookup, ruleData))
|
||||
.filter(TypeScriptUtils.isNotNullOrUndefined);
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param condition
|
||||
* @param modifierLookup
|
||||
* @param ruleData
|
||||
*/
|
||||
export function generateCondition(condition, modifierLookup, ruleData) {
|
||||
const baseCondition = RuleDataUtils.getConditionInfo(getContractId(condition), ruleData);
|
||||
if (baseCondition === null) {
|
||||
return null;
|
||||
}
|
||||
const modifiers = ModifierGenerators.generateModifiers(getId(baseCondition), getEntityTypeId(baseCondition), modifierLookup, DataOriginTypeEnum.CONDITION, baseCondition);
|
||||
let allModifiers = [];
|
||||
let levels = [];
|
||||
if (baseCondition.definition) {
|
||||
const levelModifiers = [];
|
||||
const foundLevels = getDefinitionLevels(baseCondition).map((level) => {
|
||||
let conditionLevel = null;
|
||||
if (level) {
|
||||
conditionLevel = ConditionLevelGenerators.generateConditionLevel(level, baseCondition, modifierLookup);
|
||||
levelModifiers.push(...conditionLevel.modifiers);
|
||||
}
|
||||
return conditionLevel;
|
||||
});
|
||||
levels = foundLevels.filter(TypeScriptUtils.isNotNullOrUndefined);
|
||||
allModifiers = [...modifiers, ...levelModifiers];
|
||||
}
|
||||
return Object.assign(Object.assign({}, baseCondition), { level: getContractLevel(condition), modifiers: allModifiers, levels });
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param conditions
|
||||
*/
|
||||
export function generateConditionModifiers(conditions) {
|
||||
const modifiers = [];
|
||||
if (conditions.length === 0) {
|
||||
return modifiers;
|
||||
}
|
||||
conditions.forEach((condition) => {
|
||||
modifiers.push(...getModifiers(condition));
|
||||
});
|
||||
return modifiers;
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param conditions
|
||||
*/
|
||||
export function generateRefConditionData(conditions) {
|
||||
let data = {};
|
||||
conditions.forEach((condition) => {
|
||||
data[getUniqueKey(condition)] = {
|
||||
[DataOriginDataInfoKeyEnum.PRIMARY]: condition,
|
||||
[DataOriginDataInfoKeyEnum.PARENT]: null,
|
||||
};
|
||||
});
|
||||
return data;
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
import * as ConditionAccessors from './accessors';
|
||||
import * as ConditionConstants from './constants';
|
||||
import * as ConditionGenerators from './generators';
|
||||
import * as ConditionTypings from './typings';
|
||||
import * as ConditionUtils from './utils';
|
||||
export * from './typings';
|
||||
export * from './constants';
|
||||
export { ConditionAccessors, ConditionGenerators, ConditionUtils };
|
||||
export default Object.assign(Object.assign(Object.assign(Object.assign(Object.assign({}, ConditionAccessors), ConditionConstants), ConditionGenerators), ConditionTypings), ConditionUtils);
|
||||
@@ -0,0 +1,20 @@
|
||||
import { ConditionLevelAccessors } from '../ConditionLevel';
|
||||
import { getDefinitionLevels } from './accessors';
|
||||
/**
|
||||
*
|
||||
* @param condition
|
||||
*/
|
||||
export function getLevelEffectLookup(condition) {
|
||||
const levels = getDefinitionLevels(condition);
|
||||
if (levels.length === 0) {
|
||||
return null;
|
||||
}
|
||||
return levels.reduce((acc, levelData) => {
|
||||
const level = ConditionLevelAccessors.getLevel(levelData);
|
||||
const effect = ConditionLevelAccessors.getEffect(levelData);
|
||||
if (!acc[level] && effect !== null) {
|
||||
acc[level] = effect;
|
||||
}
|
||||
return acc;
|
||||
}, {});
|
||||
}
|
||||
@@ -0,0 +1,74 @@
|
||||
/**
|
||||
*
|
||||
* @param conditionLevel
|
||||
*/
|
||||
export function getUniqueKey(conditionLevel) {
|
||||
return `${getId(conditionLevel)}-${getEntityTypeId(conditionLevel)}`;
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param conditionLevel
|
||||
*/
|
||||
export function getEffect(conditionLevel) {
|
||||
return getDefinitionEffect(conditionLevel);
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param conditionLevel
|
||||
*/
|
||||
export function getDefinitionEffect(conditionLevel) {
|
||||
var _a, _b;
|
||||
return (_b = (_a = conditionLevel.definition) === null || _a === void 0 ? void 0 : _a.effect) !== null && _b !== void 0 ? _b : null;
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param conditionLevel
|
||||
*/
|
||||
export function getEntityTypeId(conditionLevel) {
|
||||
return getDefinitionEntityTypeId(conditionLevel);
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param conditionLevel
|
||||
*/
|
||||
export function getDefinitionEntityTypeId(conditionLevel) {
|
||||
var _a, _b;
|
||||
return (_b = (_a = conditionLevel.definition) === null || _a === void 0 ? void 0 : _a.entityTypeId) !== null && _b !== void 0 ? _b : -1;
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param conditionLevel
|
||||
*/
|
||||
export function getId(conditionLevel) {
|
||||
return getDefinitionId(conditionLevel);
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param conditionLevel
|
||||
*/
|
||||
export function getDefinitionId(conditionLevel) {
|
||||
var _a, _b;
|
||||
return (_b = (_a = conditionLevel.definition) === null || _a === void 0 ? void 0 : _a.id) !== null && _b !== void 0 ? _b : -1;
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param conditionLevel
|
||||
*/
|
||||
export function getLevel(conditionLevel) {
|
||||
return getDefinitionLevel(conditionLevel);
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param conditionLevel
|
||||
*/
|
||||
export function getDefinitionLevel(conditionLevel) {
|
||||
var _a, _b;
|
||||
return (_b = (_a = conditionLevel.definition) === null || _a === void 0 ? void 0 : _a.level) !== null && _b !== void 0 ? _b : -1;
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param conditionLevel
|
||||
*/
|
||||
export function getModifiers(conditionLevel) {
|
||||
return conditionLevel.modifiers;
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
import { DataOriginTypeEnum } from '../DataOrigin';
|
||||
import { ModifierGenerators } from '../Modifier';
|
||||
import { getEntityTypeId, getId } from './accessors';
|
||||
/**
|
||||
*
|
||||
* @param conditionLevel
|
||||
* @param condition
|
||||
* @param modifierLookup
|
||||
*/
|
||||
export function generateConditionLevel(conditionLevel, condition, modifierLookup) {
|
||||
const modifiers = ModifierGenerators.generateModifiers(getId(conditionLevel), getEntityTypeId(conditionLevel), modifierLookup, DataOriginTypeEnum.CONDITION, condition);
|
||||
return Object.assign(Object.assign({}, conditionLevel), { modifiers });
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
import * as ConditionLevelAccessors from './accessors';
|
||||
import * as ConditionLevelGenerators from './generators';
|
||||
import * as ConditionLevelTypings from './typings';
|
||||
export * from './typings';
|
||||
export { ConditionLevelAccessors, ConditionLevelGenerators };
|
||||
export default Object.assign(Object.assign(Object.assign({}, ConditionLevelAccessors), ConditionLevelGenerators), ConditionLevelTypings);
|
||||
@@ -0,0 +1,36 @@
|
||||
export function getName(container) {
|
||||
return container.name;
|
||||
}
|
||||
export function getMappingId(container) {
|
||||
return container.mappingId;
|
||||
}
|
||||
export function getDefinitionKey(container) {
|
||||
return container.definitionKey;
|
||||
}
|
||||
export function getItemMappingIds(container) {
|
||||
return container.itemMappingIds;
|
||||
}
|
||||
export function getInfusedItemMappingIds(container) {
|
||||
return container.infusedItemMappingIds;
|
||||
}
|
||||
export function hasInfusions(container) {
|
||||
return container.hasInfusions;
|
||||
}
|
||||
export function getContainerType(container) {
|
||||
return container.containerType;
|
||||
}
|
||||
export function isShared(container) {
|
||||
return container.isShared;
|
||||
}
|
||||
export function getWeightInfo(container) {
|
||||
return container.weightInfo;
|
||||
}
|
||||
export function isEquipped(container) {
|
||||
return container.isEquipped;
|
||||
}
|
||||
export function getCoin(container) {
|
||||
return container.coin;
|
||||
}
|
||||
export function getItem(container) {
|
||||
return container.item;
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
export var ContainerTypeEnum;
|
||||
(function (ContainerTypeEnum) {
|
||||
ContainerTypeEnum[ContainerTypeEnum["CHARACTER"] = 1581111423] = "CHARACTER";
|
||||
ContainerTypeEnum[ContainerTypeEnum["ITEM"] = 1439493548] = "ITEM";
|
||||
ContainerTypeEnum[ContainerTypeEnum["CAMPAIGN"] = 618115330] = "CAMPAIGN";
|
||||
ContainerTypeEnum[ContainerTypeEnum["SHOPPE"] = -1] = "SHOPPE";
|
||||
})(ContainerTypeEnum || (ContainerTypeEnum = {}));
|
||||
@@ -0,0 +1,171 @@
|
||||
import { keyBy, sortBy } from 'lodash';
|
||||
import { ConfigUtils } from '../../config';
|
||||
import { CampaignAccessors, CampaignUtils } from '../Campaign';
|
||||
import { generateCoinWeight } from '../Character/generators';
|
||||
import { DefinitionHacks } from '../Definition';
|
||||
import { FeatureFlagEnum, FeatureFlagInfoUtils } from '../FeatureFlagInfo';
|
||||
import { ItemAccessors, ItemDerivers, ItemValidators } from '../Item';
|
||||
import { getDefinitionKey, getName, isShared } from './accessors';
|
||||
import { ContainerTypeEnum } from './constants';
|
||||
function generateInitialCoins() {
|
||||
return {
|
||||
cp: 0,
|
||||
sp: 0,
|
||||
ep: 0,
|
||||
gp: 0,
|
||||
pp: 0,
|
||||
};
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param items
|
||||
* @param customItems
|
||||
* @param characterId
|
||||
* @param partyInfo
|
||||
* @param partyInventory
|
||||
* @param featureFlagInfo
|
||||
* @param characterCoin
|
||||
* @param preferences
|
||||
* @param ruleData
|
||||
*/
|
||||
export function generateContainers(items, customItems, characterId, partyInfo, partyInventory, featureFlagInfo, characterCoin, preferences, ruleData) {
|
||||
let sharingStateActive = false;
|
||||
if (partyInfo && CampaignUtils.isSharingStateActive(CampaignAccessors.getSharingState(partyInfo))) {
|
||||
sharingStateActive = true;
|
||||
}
|
||||
const partyInventoryActive = FeatureFlagInfoUtils.getFeatureFlagInfoValue(FeatureFlagEnum.RELEASE_GATE_IMS, featureFlagInfo) &&
|
||||
sharingStateActive;
|
||||
const rulesEngineConfig = ConfigUtils.getCurrentRulesEngineConfig();
|
||||
// Do we want to display Cointainers? You betcha!
|
||||
const canCointainer = (preferences === null || preferences === void 0 ? void 0 : preferences.enableContainerCurrency) && (rulesEngineConfig === null || rulesEngineConfig === void 0 ? void 0 : rulesEngineConfig.canUseCurrencyContainers);
|
||||
//if includeCustomItems on the config is true - customItems are added on the Inventory as Items
|
||||
//if includeCustomItems on the config is false/undefined (mobile until v5.1 support) - use the customItem contracts on the character JSON
|
||||
const { includeCustomItems } = ConfigUtils.getCurrentRulesEngineConfig();
|
||||
const includeCustomItemContractsInEquipment = !includeCustomItems;
|
||||
const equipmentContainer = generateContainer(characterId, ContainerTypeEnum.CHARACTER, 'Equipment',
|
||||
//TODO v5.1: All customItems mappings belong to character container for mobile until they can support customItems in containers
|
||||
includeCustomItemContractsInEquipment ? [...customItems, ...items] : items, false, null, characterCoin, characterId, preferences, ruleData);
|
||||
const itemContainers = items
|
||||
.filter(ItemAccessors.isContainer)
|
||||
.map((containerItem) => {
|
||||
var _a;
|
||||
return generateContainer(ItemAccessors.getMappingId(containerItem), ContainerTypeEnum.ITEM, ItemAccessors.getName(containerItem), items, false, containerItem, canCointainer ? (_a = ItemAccessors.getCurrency(containerItem)) !== null && _a !== void 0 ? _a : generateInitialCoins() : null, characterId, preferences, ruleData);
|
||||
});
|
||||
const campaignId = partyInfo ? CampaignAccessors.getId(partyInfo) : null;
|
||||
let partyEquipmentContainer = null;
|
||||
let partyContainers = [];
|
||||
if (partyInventoryActive && campaignId) {
|
||||
partyEquipmentContainer = generateContainer(campaignId, ContainerTypeEnum.CAMPAIGN, 'Party Equipment', partyInventory, true, null, partyInfo ? CampaignAccessors.getCoin(partyInfo) : null, characterId, preferences, ruleData);
|
||||
partyContainers = partyInventory
|
||||
.filter(ItemAccessors.isContainer)
|
||||
.map((containerItem) => {
|
||||
var _a;
|
||||
return generateContainer(ItemAccessors.getMappingId(containerItem), ContainerTypeEnum.ITEM, ItemAccessors.getName(containerItem), partyInventory, true, containerItem, canCointainer ? (_a = ItemAccessors.getCurrency(containerItem)) !== null && _a !== void 0 ? _a : generateInitialCoins() : null, characterId, preferences, ruleData);
|
||||
});
|
||||
}
|
||||
const playerContainers = sortBy(itemContainers, (container) => getName(container));
|
||||
return partyInventoryActive && partyEquipmentContainer
|
||||
? [equipmentContainer, ...playerContainers, partyEquipmentContainer, ...partyContainers]
|
||||
: [equipmentContainer, ...playerContainers];
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param mappingId
|
||||
* @param containerType
|
||||
* @param name
|
||||
* @param availableInventory
|
||||
* @param isShared
|
||||
* @param item
|
||||
* @param coin
|
||||
* @param characterId
|
||||
* @param preferences
|
||||
* @param ruleData
|
||||
*/
|
||||
export function generateContainer(mappingId, containerType, name, availableInventory, isShared, item, coin, characterId, preferences, ruleData) {
|
||||
let definitionKey = DefinitionHacks.hack__generateDefinitionKey(containerType, mappingId);
|
||||
const contents = availableInventory.filter((item) => ItemAccessors.getContainerDefinitionKey(item) === definitionKey && !ItemAccessors.isContainer(item));
|
||||
const infusedItems = contents.filter(ItemAccessors.getInfusion);
|
||||
return {
|
||||
containerType,
|
||||
coin,
|
||||
definitionKey,
|
||||
mappingId,
|
||||
name,
|
||||
hasInfusions: !!infusedItems.length,
|
||||
item,
|
||||
infusedItemMappingIds: infusedItems.map(ItemAccessors.getMappingId),
|
||||
itemMappingIds: contents.map(ItemAccessors.getMappingId),
|
||||
isEquipped: item ? ItemAccessors.isEquipped(item) : null,
|
||||
isShared,
|
||||
weightInfo: generateContainerWeightInfo(containerType, contents, item, characterId, coin, preferences, ruleData),
|
||||
};
|
||||
}
|
||||
export function generateContainerWeightInfo(type, containerInventory, item, characterId, coin, preferences, ruleData) {
|
||||
// Item total is the weight of all of the items in the container
|
||||
const itemTotal = ItemDerivers.deriveItemsWeightTotal(containerInventory);
|
||||
const coinTotal = generateCoinWeight(coin, preferences, ruleData);
|
||||
const total = itemTotal + coinTotal;
|
||||
// Default case is the character equipment container. All of its weight is applied.
|
||||
let capacity = 0;
|
||||
let itemApplied = itemTotal;
|
||||
let coinApplied = coinTotal;
|
||||
let applied = total;
|
||||
if (type === ContainerTypeEnum.ITEM && item) {
|
||||
// Case: It's a container, either in the character or party inventory.
|
||||
// The weight of the container itself (5lbs for a backpack, for example)
|
||||
// should be added in.
|
||||
// Some containers, such as bags of holding, have a weight multiplier to nullify
|
||||
// the weight of the contents.
|
||||
// The weight multiplier also affects coins.
|
||||
capacity = ItemAccessors.getCapacityWeight(item);
|
||||
const itemWeight = ItemAccessors.getWeight(item);
|
||||
const weightMultiplier = ItemAccessors.getWeightMultiplier(item);
|
||||
itemApplied = itemWeight + itemTotal * weightMultiplier;
|
||||
coinApplied = coinTotal * weightMultiplier;
|
||||
applied = itemApplied + coinApplied;
|
||||
}
|
||||
else if (type === ContainerTypeEnum.CAMPAIGN) {
|
||||
// Special case: This is the top level party inventory.
|
||||
// Go through the items. Only items equipped to the current character
|
||||
// are added to the applied weight.
|
||||
itemApplied = containerInventory.reduce((acc, containerItem) => {
|
||||
const itemEquippedToCharacter = ItemValidators.isEquippedToCurrentCharacter(containerItem, characterId);
|
||||
if (itemEquippedToCharacter) {
|
||||
return acc + ItemAccessors.getWeight(containerItem);
|
||||
}
|
||||
return acc;
|
||||
}, 0);
|
||||
coinApplied = 0; // never apply coin weight from the top level party inventory
|
||||
applied = itemApplied;
|
||||
}
|
||||
return {
|
||||
applied,
|
||||
capacity,
|
||||
total,
|
||||
itemTotal,
|
||||
coinTotal,
|
||||
itemApplied,
|
||||
coinApplied,
|
||||
};
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param containers
|
||||
*/
|
||||
export function generateCharacterContainers(containers) {
|
||||
return containers.filter((container) => !isShared(container));
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param containers
|
||||
*/
|
||||
export function generatePartyContainers(containers) {
|
||||
return containers.filter(isShared);
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param containers
|
||||
*/
|
||||
export function generateContainerLookup(containers) {
|
||||
return keyBy(containers, (container) => getDefinitionKey(container));
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user