Grabbed dndbeyond's source code
``` ~/go/bin/sourcemapper -output ddb -jsurl https://media.dndbeyond.com/character-app/static/js/main.90aa78c5.js ```
This commit is contained in:
@@ -0,0 +1,653 @@
|
||||
import { TypeScriptUtils } from '../../utils';
|
||||
import { AbilityAccessors, AbilityUtils } from '../Ability';
|
||||
import { CharacterDerivers } from '../Character';
|
||||
import { AbilitySkillEnum, AbilityStatEnum, ProficiencyLevelEnum, } from '../Core';
|
||||
import { HelperUtils } from '../Helper';
|
||||
import { InfusionAccessors } from '../Infusion';
|
||||
import { RuleDataAccessors, RuleDataUtils } from '../RuleData';
|
||||
import { SkillAccessors } from '../Skill';
|
||||
import { AdjustmentTypeEnum, ValueHacks, ValueUtils, ValueValidators } from '../Value';
|
||||
import { getAverageHitPoints, getChallengeProficiencyBonus, getChallengeRatingId, getDamageAdjustments, getDefinitionAlignmentId, getDefinitionArmorClass, getDefinitionConditionImmunities, getDefinitionDamageAdjustments, getDefinitionPassivePerception, getDefinitionSavingThrows, getDefinitionSizeId, getDefinitionSkills, getDefinitionStats, getDefinitionSubTypes, getDefinitionTypeId, getEnvironments, getId, getLairChallengeRatingId, getMappingEntityTypeId, getMappingId, getMovements, getRemoveHitPoints, getTemporaryHitPoints, getTypeId, } from './accessors';
|
||||
import { CREATURE_CUSTOMIZATION_ADJUSTMENT_TYPES, CreatureGroupFlagEnum } from './constants';
|
||||
import { getStatInfo, hasGroupFlag, shouldReplaceWithOwnerStat } from './utils';
|
||||
/**
|
||||
*
|
||||
* @param creature
|
||||
*/
|
||||
export function derivePreOwnerHitPointInfo(creature) {
|
||||
const finalTotalHp = Math.max(getAverageHitPoints(creature), 0);
|
||||
const finalBaseHp = finalTotalHp;
|
||||
const finalRemovedHp = Math.min(finalTotalHp, getRemoveHitPoints(creature));
|
||||
return {
|
||||
baseHp: finalBaseHp,
|
||||
tempHp: 0,
|
||||
removedHp: finalRemovedHp,
|
||||
bonusHp: 0,
|
||||
overrideHp: 0,
|
||||
totalHp: finalTotalHp,
|
||||
remainingHp: finalTotalHp - finalRemovedHp,
|
||||
};
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param creature
|
||||
* @param ownerData
|
||||
* @param valueLookup
|
||||
* @param ruleData
|
||||
*/
|
||||
export function deriveHitPointInfo(creature, ownerData, valueLookup, ruleData) {
|
||||
const flagLevelMultiplierHpPossibilities = [];
|
||||
if (hasGroupFlag(creature, CreatureGroupFlagEnum.MAX_HIT_POINTS_LEVEL_MULTIPLIER_OPTION)) {
|
||||
const flagInfo = RuleDataUtils.getCreatureGroupFlagInfo(CreatureGroupFlagEnum.MAX_HIT_POINTS_LEVEL_MULTIPLIER_OPTION, ruleData);
|
||||
if (flagInfo) {
|
||||
const contextClassLevel = flagInfo.valueContextId === null ? 0 : ownerData.classLevelLookup[flagInfo.valueContextId];
|
||||
const contextValue = flagInfo.value === null ? 1 : flagInfo.value;
|
||||
flagLevelMultiplierHpPossibilities.push((contextClassLevel ? contextClassLevel : 0) * contextValue);
|
||||
}
|
||||
}
|
||||
if (hasGroupFlag(creature, CreatureGroupFlagEnum.ARTIFICER_HP_MULTIPLIER)) {
|
||||
const flagInfo = RuleDataUtils.getCreatureGroupFlagInfo(CreatureGroupFlagEnum.ARTIFICER_HP_MULTIPLIER, ruleData);
|
||||
if (flagInfo) {
|
||||
const contextClassLevel = flagInfo.valueContextId === null ? 0 : ownerData.classLevelLookup[flagInfo.valueContextId];
|
||||
const contextValue = flagInfo.value === null ? 1 : flagInfo.value;
|
||||
flagLevelMultiplierHpPossibilities.push((contextClassLevel ? contextClassLevel : 0) * contextValue);
|
||||
}
|
||||
}
|
||||
const definitionTotalHp = getAverageHitPoints(creature);
|
||||
let finalTotalHp = Math.max(definitionTotalHp, ...flagLevelMultiplierHpPossibilities);
|
||||
if (hasGroupFlag(creature, CreatureGroupFlagEnum.MAX_HIT_POINTS_BASE_ARTIFICER_LEVEL)) {
|
||||
const flagInfo = RuleDataUtils.getCreatureGroupFlagInfo(CreatureGroupFlagEnum.MAX_HIT_POINTS_BASE_ARTIFICER_LEVEL, ruleData);
|
||||
if (flagInfo && flagInfo.valueContextId !== null) {
|
||||
finalTotalHp = HelperUtils.lookupDataOrFallback(ownerData.classLevelLookup, flagInfo.valueContextId, finalTotalHp);
|
||||
}
|
||||
}
|
||||
if (hasGroupFlag(creature, CreatureGroupFlagEnum.MAX_HIT_POINTS_ADD_INT_MODIFIER)) {
|
||||
const flagInfo = RuleDataUtils.getCreatureGroupFlagInfo(CreatureGroupFlagEnum.MAX_HIT_POINTS_ADD_INT_MODIFIER, ruleData);
|
||||
if (flagInfo) {
|
||||
const contextStatModifier = flagInfo.valueContextId === null ? null : ownerData.abilityLookup[flagInfo.valueContextId];
|
||||
let finalModifier = 0;
|
||||
if (contextStatModifier && contextStatModifier.modifier) {
|
||||
finalModifier = contextStatModifier.modifier;
|
||||
}
|
||||
finalTotalHp = HelperUtils.clampInt(finalTotalHp + finalModifier, RuleDataAccessors.getMinimumHpTotal(ruleData));
|
||||
}
|
||||
}
|
||||
if (hasGroupFlag(creature, CreatureGroupFlagEnum.MAX_HIT_POINTS_ADD_MONSTER_CON_MODIFIER)) {
|
||||
const flagInfo = RuleDataUtils.getCreatureGroupFlagInfo(CreatureGroupFlagEnum.MAX_HIT_POINTS_ADD_MONSTER_CON_MODIFIER, ruleData);
|
||||
if (flagInfo !== null && flagInfo.valueContextId) {
|
||||
let contextStatModifier = 0;
|
||||
const contextStatInfo = getStatInfo(creature, flagInfo.valueContextId);
|
||||
if (contextStatInfo !== null && contextStatInfo.modifier !== null) {
|
||||
contextStatModifier = contextStatInfo.modifier;
|
||||
}
|
||||
finalTotalHp = HelperUtils.clampInt(finalTotalHp + contextStatModifier, ruleData.minimumHpTotal);
|
||||
}
|
||||
}
|
||||
//if there is an override for the creature's hit points, use that instead
|
||||
const hpOverride = deriveOverridenValue(creature, AdjustmentTypeEnum.CREATURE_HIT_POINTS, null, valueLookup);
|
||||
if (hpOverride) {
|
||||
finalTotalHp = hpOverride;
|
||||
}
|
||||
const tempHp = getTemporaryHitPoints(creature);
|
||||
const finalRemovedHp = Math.min(finalTotalHp, getRemoveHitPoints(creature));
|
||||
return {
|
||||
baseHp: finalTotalHp,
|
||||
tempHp,
|
||||
removedHp: finalRemovedHp,
|
||||
bonusHp: 0,
|
||||
overrideHp: 0,
|
||||
totalHp: finalTotalHp,
|
||||
remainingHp: finalTotalHp - finalRemovedHp,
|
||||
};
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param creature
|
||||
* @param ownerData
|
||||
* @param ruleData
|
||||
*/
|
||||
export function deriveInitialTempHp(creature, ownerData, ruleData) {
|
||||
let initialTempHp = 0;
|
||||
if (hasGroupFlag(creature, CreatureGroupFlagEnum.TEMP_HIT_POINTS_BASE_DRUID_LEVEL)) {
|
||||
const flagInfo = RuleDataUtils.getCreatureGroupFlagInfo(CreatureGroupFlagEnum.TEMP_HIT_POINTS_BASE_DRUID_LEVEL, ruleData);
|
||||
if (flagInfo) {
|
||||
//find the level of the class or subclass id that matches the valueContextId and use it as the initial temp hp
|
||||
const contextClassLevel = flagInfo.valueContextId === null ? 0 : ownerData.classLevelLookup[flagInfo.valueContextId];
|
||||
initialTempHp = contextClassLevel;
|
||||
}
|
||||
}
|
||||
if (hasGroupFlag(creature, CreatureGroupFlagEnum.TEMP_HIT_POINTS_BASE_DRUID_LEVEL_MULTIPLIER)) {
|
||||
const flagInfo = RuleDataUtils.getCreatureGroupFlagInfo(CreatureGroupFlagEnum.TEMP_HIT_POINTS_BASE_DRUID_LEVEL_MULTIPLIER, ruleData);
|
||||
if (flagInfo) {
|
||||
//find the level of the class or subclass id that matches the valueContextId and multiply it by the contextValue
|
||||
const contextClassLevel = flagInfo.valueContextId === null ? 0 : ownerData.classLevelLookup[flagInfo.valueContextId];
|
||||
//only multiply the tempHp if the there is a contextClassLevel
|
||||
if (contextClassLevel > 0) {
|
||||
const contextValue = flagInfo.value === null ? 1 : flagInfo.value;
|
||||
initialTempHp = contextClassLevel * contextValue;
|
||||
}
|
||||
}
|
||||
}
|
||||
return initialTempHp;
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param creature
|
||||
*/
|
||||
export function deriveUseOwnerHp(creature) {
|
||||
//If this is true, the CreaturePane will use the player HP tracker instead of the Creature HP tracker and MaxHP override should be hidden from creature customization
|
||||
return hasGroupFlag(creature, CreatureGroupFlagEnum.USE_OWNER_MAX_HIT_POINTS);
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param creature
|
||||
* @param skill
|
||||
* @param ownerData
|
||||
* @param ruleData
|
||||
*/
|
||||
export function deriveOwnerSkillModifier(creature, skill, ownerData, ruleData) {
|
||||
var _a, _b, _c;
|
||||
const skillInfo = RuleDataUtils.getSkillInfo(skill.id, ruleData);
|
||||
let statModifier = 0;
|
||||
let proficiencyBonus = ownerData.proficiencyBonus;
|
||||
let otherBonuses = 0;
|
||||
if (skillInfo) {
|
||||
const statInfo = getStatInfo(creature, skillInfo.stat);
|
||||
const ownerSkill = HelperUtils.lookupDataOrFallback(ownerData.skillLookup, skill.id);
|
||||
statModifier = (_a = statInfo === null || statInfo === void 0 ? void 0 : statInfo.monster.modifier) !== null && _a !== void 0 ? _a : 0;
|
||||
if (ownerSkill !== null) {
|
||||
const ownerProficiencyLevel = SkillAccessors.getProficiencyLevel(ownerSkill);
|
||||
// Creature gives proficiency bonus if the owner doesn't have any
|
||||
let proficiencyLevel = ProficiencyLevelEnum.FULL;
|
||||
if (ownerProficiencyLevel !== ProficiencyLevelEnum.NONE) {
|
||||
proficiencyLevel = ownerProficiencyLevel;
|
||||
}
|
||||
proficiencyBonus = CharacterDerivers.deriveProficiencyBonusAmount(proficiencyLevel, ownerData.proficiencyBonus);
|
||||
if (shouldReplaceWithOwnerStat(creature, skillInfo.stat)) {
|
||||
if (SkillAccessors.getIsOverridden(ownerSkill)) {
|
||||
statModifier = (_b = SkillAccessors.getModifier(ownerSkill)) !== null && _b !== void 0 ? _b : 0;
|
||||
proficiencyBonus = 0;
|
||||
}
|
||||
else {
|
||||
statModifier = SkillAccessors.getStatModifier(ownerSkill);
|
||||
otherBonuses = SkillAccessors.getModifierBonuses(ownerSkill);
|
||||
}
|
||||
}
|
||||
else {
|
||||
const statInfo = getStatInfo(creature, skillInfo.stat);
|
||||
statModifier = (_c = statInfo === null || statInfo === void 0 ? void 0 : statInfo.monster.modifier) !== null && _c !== void 0 ? _c : 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
return statModifier + proficiencyBonus + otherBonuses;
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param creature
|
||||
* @param stat
|
||||
* @param ownerData
|
||||
*/
|
||||
export function deriveOwnerSaveModifier(creature, stat, ownerData) {
|
||||
var _a, _b, _c;
|
||||
const statInfo = getStatInfo(creature, stat.id);
|
||||
let statModifier = 0;
|
||||
let proficiencyBonus = ownerData.proficiencyBonus;
|
||||
let otherBonuses = 0;
|
||||
const ownerAbility = HelperUtils.lookupDataOrFallback(ownerData.abilityLookup, stat.id);
|
||||
if (ownerAbility !== null) {
|
||||
const ownerProficiencyLevel = AbilityAccessors.getProficiencyLevel(ownerAbility);
|
||||
// Creature gives proficiency bonus if the owner doesn't have any
|
||||
let proficiencyLevel = ProficiencyLevelEnum.FULL;
|
||||
if (ownerProficiencyLevel !== ProficiencyLevelEnum.NONE) {
|
||||
proficiencyLevel = ownerProficiencyLevel;
|
||||
}
|
||||
proficiencyBonus = CharacterDerivers.deriveProficiencyBonusAmount(proficiencyLevel, ownerData.proficiencyBonus);
|
||||
if (shouldReplaceWithOwnerStat(creature, stat.id)) {
|
||||
if (AbilityAccessors.getIsSaveOverridden(ownerAbility)) {
|
||||
statModifier = (_a = AbilityAccessors.getSave(ownerAbility)) !== null && _a !== void 0 ? _a : 0;
|
||||
proficiencyBonus = 0;
|
||||
}
|
||||
else {
|
||||
statModifier = (_b = AbilityAccessors.getModifier(ownerAbility)) !== null && _b !== void 0 ? _b : 0;
|
||||
otherBonuses = AbilityAccessors.getSaveBonuses(ownerAbility);
|
||||
}
|
||||
}
|
||||
else {
|
||||
statModifier = (_c = statInfo === null || statInfo === void 0 ? void 0 : statInfo.monster.modifier) !== null && _c !== void 0 ? _c : 0;
|
||||
}
|
||||
}
|
||||
return statModifier + proficiencyBonus + otherBonuses;
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param creature
|
||||
* @param skill
|
||||
* @param ruleData
|
||||
*/
|
||||
export function deriveCreatureSkillModifier(creature, skill, ruleData) {
|
||||
var _a, _b;
|
||||
const skillInfo = RuleDataUtils.getSkillInfo(skill.skillId, ruleData);
|
||||
let statModifier = 0;
|
||||
if (skillInfo) {
|
||||
const statInfo = getStatInfo(creature, skillInfo.stat);
|
||||
statModifier = (_a = statInfo === null || statInfo === void 0 ? void 0 : statInfo.monster.modifier) !== null && _a !== void 0 ? _a : 0;
|
||||
}
|
||||
const proficiencyBonus = getChallengeProficiencyBonus(creature);
|
||||
const otherBonuses = (_b = skill.additionalBonus) !== null && _b !== void 0 ? _b : 0;
|
||||
return statModifier + proficiencyBonus + otherBonuses;
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param creature
|
||||
* @param savingThrow
|
||||
*/
|
||||
export function deriveCreatureSaveModifier(creature, savingThrow) {
|
||||
var _a, _b;
|
||||
const statInfo = getStatInfo(creature, savingThrow.statId);
|
||||
const statModifier = (_a = statInfo === null || statInfo === void 0 ? void 0 : statInfo.monster.modifier) !== null && _a !== void 0 ? _a : 0;
|
||||
const proficiencyBonus = getChallengeProficiencyBonus(creature);
|
||||
const otherBonuses = (_b = savingThrow.bonusModifier) !== null && _b !== void 0 ? _b : 0;
|
||||
return statModifier + proficiencyBonus + otherBonuses;
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param creature
|
||||
* @param ownerData
|
||||
* @param ruleData
|
||||
*/
|
||||
export function deriveSkills(creature, ownerData, ruleData) {
|
||||
const skills = RuleDataAccessors.getAbilitySkills(ruleData);
|
||||
return skills
|
||||
.map((skillInfo) => {
|
||||
var _a;
|
||||
const statInfo = RuleDataUtils.getStatInfo(skillInfo.stat, ruleData);
|
||||
const creatureSkill = getDefinitionSkills(creature).find((skill) => skill.skillId === skillInfo.id);
|
||||
const isCreatureProficient = !!creatureSkill;
|
||||
const potentialModifiers = [];
|
||||
if (hasGroupFlag(creature, CreatureGroupFlagEnum.EVALUATE_OWNER_SKILL_PROFICIENCIES)) {
|
||||
const ownerSkill = HelperUtils.lookupDataOrFallback(ownerData.skillLookup, skillInfo.id);
|
||||
const isOwnerProficient = ownerSkill !== null && SkillAccessors.getProficiencyLevel(ownerSkill) !== ProficiencyLevelEnum.NONE;
|
||||
if (isCreatureProficient || isOwnerProficient) {
|
||||
potentialModifiers.push(deriveOwnerSkillModifier(creature, skillInfo, ownerData, ruleData));
|
||||
}
|
||||
// Can potentially use creatures modifier if the owner is "proficient"
|
||||
if (creatureSkill && isCreatureProficient && isOwnerProficient) {
|
||||
potentialModifiers.push(deriveCreatureSkillModifier(creature, creatureSkill, ruleData));
|
||||
}
|
||||
}
|
||||
else if (creatureSkill && isCreatureProficient) {
|
||||
potentialModifiers.push(deriveCreatureSkillModifier(creature, creatureSkill, ruleData));
|
||||
}
|
||||
// if we didn't generate any potential modifiers, exit early and null will be filtered out
|
||||
if (!potentialModifiers.length) {
|
||||
return null;
|
||||
}
|
||||
const modifier = Math.max(...potentialModifiers);
|
||||
let bonuses = 0;
|
||||
if (hasGroupFlag(creature, CreatureGroupFlagEnum.PROFICIENT_SKILLS_ADD_PROFICIENCY_BONUS)) {
|
||||
bonuses += ownerData.proficiencyBonus;
|
||||
}
|
||||
return {
|
||||
id: skillInfo.id,
|
||||
modifier: modifier + bonuses,
|
||||
statKey: (_a = statInfo === null || statInfo === void 0 ? void 0 : statInfo.key) !== null && _a !== void 0 ? _a : 'UNK',
|
||||
};
|
||||
})
|
||||
.filter(TypeScriptUtils.isNotNullOrUndefined);
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param creature
|
||||
* @param ownerData
|
||||
* @param ruleData
|
||||
*/
|
||||
export function deriveSavingThrows(creature, ownerData, ruleData) {
|
||||
const stats = RuleDataAccessors.getStats(ruleData);
|
||||
return stats
|
||||
.map((stat) => {
|
||||
var _a;
|
||||
const creatureSavingThrow = getDefinitionSavingThrows(creature).find((savingThrow) => savingThrow.statId === stat.id);
|
||||
const isCreatureProficient = !!creatureSavingThrow;
|
||||
const potentialModifiers = [];
|
||||
if (hasGroupFlag(creature, CreatureGroupFlagEnum.EVALUATE_OWNER_SAVE_PROFICIENCIES)) {
|
||||
const ownerAbility = HelperUtils.lookupDataOrFallback(ownerData.abilityLookup, stat.id);
|
||||
const isOwnerProficient = ownerAbility !== null &&
|
||||
AbilityAccessors.getProficiencyLevel(ownerAbility) !== ProficiencyLevelEnum.NONE;
|
||||
if (isCreatureProficient || isOwnerProficient) {
|
||||
potentialModifiers.push(deriveOwnerSaveModifier(creature, stat, ownerData));
|
||||
}
|
||||
// Can potentially use creatures modifier if the owner is "proficient"
|
||||
if (creatureSavingThrow && isCreatureProficient && isOwnerProficient) {
|
||||
potentialModifiers.push(deriveCreatureSaveModifier(creature, creatureSavingThrow));
|
||||
}
|
||||
}
|
||||
else if (creatureSavingThrow && isCreatureProficient) {
|
||||
potentialModifiers.push(deriveCreatureSaveModifier(creature, creatureSavingThrow));
|
||||
}
|
||||
// if we didn't generate any potential modifiers, exit early and null will be filtered out
|
||||
if (!potentialModifiers.length) {
|
||||
return null;
|
||||
}
|
||||
const modifier = Math.max(...potentialModifiers);
|
||||
let bonuses = 0;
|
||||
if (hasGroupFlag(creature, CreatureGroupFlagEnum.PROFICIENT_SAVING_THROWS_ADD_PROFICIENCY_BONUS)) {
|
||||
bonuses += ownerData.proficiencyBonus;
|
||||
}
|
||||
return {
|
||||
statId: stat.id,
|
||||
modifier: modifier + bonuses,
|
||||
statKey: (_a = stat.key) !== null && _a !== void 0 ? _a : '',
|
||||
};
|
||||
})
|
||||
.filter(TypeScriptUtils.isNotNullOrUndefined);
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param creature
|
||||
* @param ownerData
|
||||
* @param ruleData
|
||||
*/
|
||||
export function deriveStats(creature, ownerData, ruleData) {
|
||||
return getDefinitionStats(creature).map((stat) => {
|
||||
var _a;
|
||||
const originalScore = stat.value;
|
||||
let score = stat.value;
|
||||
if (shouldReplaceWithOwnerStat(creature, stat.statId)) {
|
||||
const ownerAbility = HelperUtils.lookupDataOrFallback(ownerData.abilityLookup, stat.statId);
|
||||
if (ownerAbility !== null) {
|
||||
score = AbilityAccessors.getScore(ownerAbility);
|
||||
}
|
||||
}
|
||||
const statInfo = RuleDataUtils.getStatInfo(stat.statId, ruleData);
|
||||
const statKey = (_a = statInfo === null || statInfo === void 0 ? void 0 : statInfo.key) !== null && _a !== void 0 ? _a : null;
|
||||
const modifier = score === null ? null : AbilityUtils.getStatScoreModifier(score, ruleData);
|
||||
const originalModifier = originalScore === null ? null : AbilityUtils.getStatScoreModifier(originalScore, ruleData);
|
||||
return {
|
||||
id: stat.statId,
|
||||
score,
|
||||
modifier,
|
||||
statKey,
|
||||
monster: {
|
||||
score: originalScore,
|
||||
modifier: originalModifier,
|
||||
},
|
||||
};
|
||||
});
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param creature
|
||||
* @param ruleData
|
||||
*/
|
||||
export function deriveDamageAdjustments(creature, ruleData) {
|
||||
return getDefinitionDamageAdjustments(creature)
|
||||
.map((damageAdjustmentId) => RuleDataUtils.getDamageAdjustmentInfo(damageAdjustmentId, ruleData))
|
||||
.filter(TypeScriptUtils.isNotNullOrUndefined);
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param creature
|
||||
* @param ruleData
|
||||
*/
|
||||
export function deriveConditionImmunities(creature, ruleData) {
|
||||
return getDefinitionConditionImmunities(creature)
|
||||
.map((conditionId) => RuleDataUtils.getConditionInfo(conditionId, ruleData))
|
||||
.filter(TypeScriptUtils.isNotNullOrUndefined);
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param damageAdjustmentType
|
||||
* @param creature
|
||||
*/
|
||||
export function deriveDamageAdjustmentType(damageAdjustmentType, creature) {
|
||||
return getDamageAdjustments(creature).filter((damageAdjustment) => damageAdjustment.type === damageAdjustmentType);
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param creature
|
||||
* @param ruleData
|
||||
*/
|
||||
export function deriveSubTypes(creature, ruleData) {
|
||||
const subTypes = getDefinitionSubTypes(creature);
|
||||
return subTypes
|
||||
.map((subTypeId) => RuleDataUtils.getMonsterSubTypeInfo(subTypeId, ruleData))
|
||||
.filter(TypeScriptUtils.isNotNullOrUndefined);
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param creature
|
||||
* @param ownerData
|
||||
* @param skillLookup
|
||||
* @param ruleData
|
||||
*/
|
||||
export function derivePassivePerception(creature, ownerData, skillLookup, ruleData) {
|
||||
if (!hasGroupFlag(creature, CreatureGroupFlagEnum.EVALUATE_UPDATED_PASSIVE_PERCEPTION)) {
|
||||
return getDefinitionPassivePerception(creature);
|
||||
}
|
||||
let skillModifier = 0;
|
||||
const perceptionInfo = skillLookup[AbilitySkillEnum.PERCEPTION];
|
||||
if (perceptionInfo) {
|
||||
skillModifier = perceptionInfo.modifier;
|
||||
}
|
||||
else {
|
||||
// fallback to perception's stat modifier if perception isn't called out
|
||||
const skillInfo = RuleDataUtils.getSkillInfo(AbilitySkillEnum.PERCEPTION, ruleData);
|
||||
if (skillInfo) {
|
||||
const statInfo = getStatInfo(creature, skillInfo.stat);
|
||||
skillModifier = statInfo && statInfo.modifier !== null ? statInfo.modifier : 0;
|
||||
}
|
||||
}
|
||||
const derivedPassivePerception = CharacterDerivers.derivePassiveSkill(skillModifier);
|
||||
const passivePerceptionPossibilities = [derivedPassivePerception];
|
||||
if (hasGroupFlag(creature, CreatureGroupFlagEnum.EVALUATE_OWNER_PASSIVE_PERCEPTION)) {
|
||||
if (ownerData.passivePerception !== null) {
|
||||
passivePerceptionPossibilities.push(ownerData.passivePerception);
|
||||
}
|
||||
}
|
||||
return Math.max(...passivePerceptionPossibilities);
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param creature
|
||||
* @param ruleData
|
||||
*/
|
||||
export function deriveEnvironmentTags(creature, ruleData) {
|
||||
const envs = getEnvironments(creature);
|
||||
return envs
|
||||
.map((envId) => {
|
||||
const envInfo = RuleDataUtils.getEnvironmentInfo(envId, ruleData);
|
||||
if (envInfo) {
|
||||
return envInfo.name;
|
||||
}
|
||||
return null;
|
||||
})
|
||||
.filter(TypeScriptUtils.isNotNullOrUndefined);
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param creature
|
||||
* @param ruleData
|
||||
*/
|
||||
export function deriveSubTypeTags(creature, ruleData) {
|
||||
const subTypes = getDefinitionSubTypes(creature);
|
||||
return subTypes
|
||||
.map((subTypeId) => {
|
||||
const info = RuleDataUtils.getMonsterSubTypeInfo(subTypeId, ruleData);
|
||||
if (info) {
|
||||
return info.name;
|
||||
}
|
||||
return null;
|
||||
})
|
||||
.filter(TypeScriptUtils.isNotNullOrUndefined);
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param creature
|
||||
* @param ruleData
|
||||
*/
|
||||
export function deriveTypeTag(creature, ruleData) {
|
||||
return RuleDataUtils.getMonsterTypeName(getTypeId(creature), ruleData, null);
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param creature
|
||||
*/
|
||||
export function deriveMovementIds(creature) {
|
||||
return getMovements(creature).map((movement) => movement.movementId);
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param creature
|
||||
* @param ruleData
|
||||
*/
|
||||
export function deriveMovementNames(creature, ruleData) {
|
||||
return getMovements(creature).map((movement) => RuleDataUtils.getMovementDescription(movement.movementId, ruleData));
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param creature
|
||||
* @param ownerData
|
||||
* @param valueLookup
|
||||
*/
|
||||
export function deriveArmorClass(creature, ownerData, valueLookup, ruleData) {
|
||||
var _a;
|
||||
const armorOverride = deriveOverridenValue(creature, AdjustmentTypeEnum.CREATURE_AC, null, valueLookup);
|
||||
if (armorOverride) {
|
||||
return armorOverride;
|
||||
}
|
||||
let bonuses = 0;
|
||||
if (hasGroupFlag(creature, CreatureGroupFlagEnum.ARMOR_ADD_PROFICIENCY_BONUS)) {
|
||||
bonuses += ownerData.proficiencyBonus;
|
||||
}
|
||||
let armorClass = getDefinitionArmorClass(creature);
|
||||
if (hasGroupFlag(creature, CreatureGroupFlagEnum.ARMOR_ADD_OWNER_WIS_PLUS_FIXED_VALUE)) {
|
||||
const flagInfo = RuleDataUtils.getCreatureGroupFlagInfo(CreatureGroupFlagEnum.ARMOR_ADD_OWNER_WIS_PLUS_FIXED_VALUE, ruleData);
|
||||
if (flagInfo) {
|
||||
const contextClassLevel = flagInfo.valueContextId === null ? 0 : ownerData.classLevelLookup[flagInfo.valueContextId];
|
||||
//Check if the owner has a matching class or subclass to the contextValueId
|
||||
if (contextClassLevel > 0) {
|
||||
const ownerWisdomModifier = (_a = ownerData.abilityLookup[AbilityStatEnum.WISDOM].modifier) !== null && _a !== void 0 ? _a : 0;
|
||||
const contextValue = flagInfo.value === null ? 0 : flagInfo.value;
|
||||
//AC will should be the highest value between the current AC and the owner's wisdom modifier + the context value
|
||||
armorClass = Math.max(armorClass, contextValue + ownerWisdomModifier);
|
||||
}
|
||||
}
|
||||
}
|
||||
//Add any final bonuses to the AC;
|
||||
return armorClass + bonuses;
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param creature
|
||||
* @param valueTypeId
|
||||
* @param fallback
|
||||
* @param valueLookup
|
||||
*/
|
||||
function deriveOverridenValue(creature, valueTypeId, fallback, valueLookup) {
|
||||
if (valueLookup) {
|
||||
const override = ValueUtils.getKeyValue(valueLookup, valueTypeId, ValueHacks.hack__toString(getMappingId(creature)), ValueHacks.hack__toString(getMappingEntityTypeId(creature)));
|
||||
if (override) {
|
||||
return override;
|
||||
}
|
||||
}
|
||||
return fallback;
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param creature
|
||||
* @param valueLookup
|
||||
*/
|
||||
export function deriveSizeId(creature, valueLookup) {
|
||||
return deriveOverridenValue(creature, AdjustmentTypeEnum.CREATURE_SIZE, getDefinitionSizeId(creature), valueLookup);
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param creature
|
||||
* @param valueLookup
|
||||
*/
|
||||
export function deriveTypeId(creature, valueLookup) {
|
||||
return deriveOverridenValue(creature, AdjustmentTypeEnum.CREATURE_TYPE_OVERRIDE, getDefinitionTypeId(creature), valueLookup);
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param creature
|
||||
* @param valueLookup
|
||||
*/
|
||||
export function deriveAlignmentId(creature, valueLookup) {
|
||||
return deriveOverridenValue(creature, AdjustmentTypeEnum.CREATURE_ALIGNMENT, getDefinitionAlignmentId(creature), valueLookup);
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param creature
|
||||
* @param valueLookup
|
||||
*/
|
||||
export function deriveNotes(creature, valueLookup) {
|
||||
return deriveOverridenValue(creature, AdjustmentTypeEnum.CREATURE_NOTES, null, valueLookup);
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param creature
|
||||
* @param ruleData
|
||||
*/
|
||||
export function deriveLevel(creature, ruleData) {
|
||||
if (hasGroupFlag(creature, CreatureGroupFlagEnum.USE_CHALLENGE_RATING_AS_LEVEL)) {
|
||||
const challengeInfo = RuleDataUtils.getChallengeInfo(getChallengeRatingId(creature), ruleData);
|
||||
const level = challengeInfo ? challengeInfo.value : 0;
|
||||
const maxCharLevel = RuleDataAccessors.getMaxCharacterLevel(ruleData);
|
||||
return HelperUtils.clampInt(level, 1, maxCharLevel);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param creature
|
||||
* @param ruleData
|
||||
*/
|
||||
export function deriveChallengeInfo(creature, ruleData) {
|
||||
if (hasGroupFlag(creature, CreatureGroupFlagEnum.USE_CHALLENGE_RATING_AS_LEVEL)) {
|
||||
return null;
|
||||
}
|
||||
return RuleDataUtils.getChallengeInfo(getChallengeRatingId(creature), ruleData);
|
||||
}
|
||||
export function deriveLairChallengeInfo(creature, ruleData) {
|
||||
if (hasGroupFlag(creature, CreatureGroupFlagEnum.USE_CHALLENGE_RATING_AS_LEVEL)) {
|
||||
return null;
|
||||
}
|
||||
return RuleDataUtils.getChallengeInfo(getLairChallengeRatingId(creature), ruleData);
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param creature
|
||||
* @param groupInfo
|
||||
* @param infusion
|
||||
*/
|
||||
export function deriveFlags(creature, groupInfo, infusion) {
|
||||
const flags = [];
|
||||
if (groupInfo && groupInfo.flags !== null) {
|
||||
flags.push(...groupInfo.flags);
|
||||
}
|
||||
if (infusion) {
|
||||
const creatureData = InfusionAccessors.getCreatureData(infusion);
|
||||
if (creatureData) {
|
||||
const foundCreatureData = creatureData.find((creatureDataEntry) => creatureDataEntry.monsterId === getId(creature));
|
||||
if (foundCreatureData && foundCreatureData.flags !== null) {
|
||||
flags.push(...foundCreatureData.flags);
|
||||
}
|
||||
}
|
||||
}
|
||||
return flags;
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param creature
|
||||
* @param valueLookup
|
||||
*/
|
||||
export function deriveIsCustomized(creature, valueLookup) {
|
||||
let isCustomized = ValueValidators.validateHasCustomization(CREATURE_CUSTOMIZATION_ADJUSTMENT_TYPES, valueLookup, ValueHacks.hack__toString(getMappingId(creature)), ValueHacks.hack__toString(getMappingEntityTypeId(creature)));
|
||||
if (!isCustomized) {
|
||||
if (creature.name !== null && creature.name !== '') {
|
||||
isCustomized = true;
|
||||
}
|
||||
}
|
||||
return isCustomized;
|
||||
}
|
||||
Reference in New Issue
Block a user