Grabbed dndbeyond's source code

```
~/go/bin/sourcemapper -output ddb -jsurl https://media.dndbeyond.com/character-app/static/js/main.90aa78c5.js
```
This commit is contained in:
2025-05-28 11:50:03 -07:00
commit 8df9031d27
3592 changed files with 319051 additions and 0 deletions
@@ -0,0 +1,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