New source found from dndbeyond.com
This commit is contained in:
+4
@@ -20,6 +20,7 @@ import {
|
||||
DefinitionPool,
|
||||
DefinitionUtils,
|
||||
EntitledEntity,
|
||||
EntityRestrictionData,
|
||||
FeatDefinitionContract,
|
||||
FeatLookup,
|
||||
InfusionChoice,
|
||||
@@ -156,6 +157,7 @@ interface Props {
|
||||
optionalClassFeatureLookup: OptionalClassFeatureLookup;
|
||||
theme: CharacterTheme;
|
||||
inventoryManager: InventoryManager;
|
||||
entityRestrictionData: EntityRestrictionData;
|
||||
}
|
||||
interface State {
|
||||
showClassFeatures: boolean;
|
||||
@@ -407,6 +409,7 @@ export default class ClassManager extends React.PureComponent<Props, State> {
|
||||
optionalClassFeatureLookup,
|
||||
theme,
|
||||
activeSourceCategories,
|
||||
entityRestrictionData,
|
||||
} = this.props;
|
||||
|
||||
return (
|
||||
@@ -441,6 +444,7 @@ export default class ClassManager extends React.PureComponent<Props, State> {
|
||||
onChangeReplacementPromise={onChangeReplacementPromise}
|
||||
onRemoveSelectionPromise={onRemoveSelectionPromise}
|
||||
ruleData={ruleData}
|
||||
entityRestrictionData={entityRestrictionData}
|
||||
/>
|
||||
),
|
||||
id: "optional-features",
|
||||
|
||||
@@ -49,6 +49,7 @@ import {
|
||||
InventoryLookup,
|
||||
ItemUtils,
|
||||
InventoryManager,
|
||||
EntityRestrictionData,
|
||||
} from "@dndbeyond/character-rules-engine/es";
|
||||
|
||||
import { HpSummary } from "~/subApps/builder/components/HpSummary";
|
||||
@@ -125,6 +126,7 @@ interface Props extends DispatchProp {
|
||||
characterId: number;
|
||||
activeSourceCategories: Array<number>;
|
||||
createModal: (modalData: ModalData) => void;
|
||||
entityRestrictionData: EntityRestrictionData;
|
||||
}
|
||||
|
||||
class ClassesManage extends React.PureComponent<Props> {
|
||||
@@ -931,6 +933,7 @@ class ClassesManage extends React.PureComponent<Props> {
|
||||
theme,
|
||||
activeSourceCategories,
|
||||
inventoryManager,
|
||||
entityRestrictionData,
|
||||
} = this.props;
|
||||
|
||||
const levelsRemaining: number = Math.max(
|
||||
@@ -1010,6 +1013,7 @@ class ClassesManage extends React.PureComponent<Props> {
|
||||
classSpellListSpellsLookup={classSpellListSpellsLookup}
|
||||
activeSourceCategories={activeSourceCategories}
|
||||
inventoryManager={inventoryManager}
|
||||
entityRestrictionData={entityRestrictionData}
|
||||
/>
|
||||
))}
|
||||
{levelsRemaining !== 0 && (
|
||||
@@ -1086,6 +1090,8 @@ export default ConnectedBuilderPage(
|
||||
characterId: rulesEngineSelectors.getId(state),
|
||||
activeSourceCategories:
|
||||
rulesEngineSelectors.getActiveSourceCategories(state),
|
||||
entityRestrictionData:
|
||||
rulesEngineSelectors.getEntityRestrictionData(state),
|
||||
};
|
||||
}
|
||||
);
|
||||
|
||||
+41
-13
@@ -1,10 +1,7 @@
|
||||
import axios, { Canceler } from "axios";
|
||||
import React from "react";
|
||||
|
||||
import {
|
||||
MarketplaceCta,
|
||||
LoadingPlaceholder,
|
||||
} from "@dndbeyond/character-components/es";
|
||||
import { LoadingPlaceholder } from "@dndbeyond/character-components/es";
|
||||
import {
|
||||
ApiAdapterUtils,
|
||||
CharClass,
|
||||
@@ -20,6 +17,7 @@ import {
|
||||
ClassUtils,
|
||||
HelperUtils,
|
||||
RuleData,
|
||||
EntityRestrictionData,
|
||||
} from "@dndbeyond/character-rules-engine/es";
|
||||
|
||||
import { Link } from "~/components/Link";
|
||||
@@ -58,6 +56,7 @@ interface OptionalFeatureManagerProps {
|
||||
reject: () => void
|
||||
) => void;
|
||||
ruleData: RuleData;
|
||||
entityRestrictionData: EntityRestrictionData;
|
||||
}
|
||||
interface OptionalFeatureManagerState {
|
||||
loadingStatus: DataLoadingStatusEnum;
|
||||
@@ -180,6 +179,7 @@ export class OptionalFeatureManager extends React.PureComponent<
|
||||
onChangeReplacementPromise,
|
||||
onRemoveSelectionPromise,
|
||||
onSelection,
|
||||
entityRestrictionData,
|
||||
} = this.props;
|
||||
|
||||
let contentNode: React.ReactNode;
|
||||
@@ -234,13 +234,41 @@ export class OptionalFeatureManager extends React.PureComponent<
|
||||
const consolidatedOptionalOrigins = [
|
||||
...availableOptionalFeatures,
|
||||
...unEntitledOptionalClassFeatures,
|
||||
].filter(
|
||||
(feature) =>
|
||||
!ClassFeatureUtils.getHideInContext(
|
||||
feature,
|
||||
Constants.AppContextTypeEnum.BUILDER
|
||||
)
|
||||
);
|
||||
]
|
||||
.filter(
|
||||
(feature) =>
|
||||
!ClassFeatureUtils.getHideInContext(
|
||||
feature,
|
||||
Constants.AppContextTypeEnum.BUILDER
|
||||
)
|
||||
)
|
||||
.filter((feature) => {
|
||||
//check if the feature is already selectec
|
||||
const optionalFeatureMapping = HelperUtils.lookupDataOrFallback(
|
||||
optionalClassFeatureLookup,
|
||||
ClassFeatureUtils.getDefinitionKey(feature)
|
||||
);
|
||||
|
||||
//always return the feature if it is already selected
|
||||
if (optionalFeatureMapping) {
|
||||
return true;
|
||||
}
|
||||
|
||||
const sourceIds = ClassFeatureUtils.getSources(feature).map(
|
||||
(source) => source.sourceId
|
||||
);
|
||||
|
||||
// if there are no sources, we assume it is homebrew
|
||||
if (sourceIds.length === 0) {
|
||||
//return true if the user has homebrew content enabled
|
||||
return entityRestrictionData.preferences.useHomebrewContent;
|
||||
}
|
||||
|
||||
// filter out features that do not have any sources from the active sources lookup
|
||||
return sourceIds.some((sourceId) =>
|
||||
entityRestrictionData.activeSourceLookup.hasOwnProperty(sourceId)
|
||||
);
|
||||
});
|
||||
|
||||
if (!consolidatedOptionalOrigins.length) {
|
||||
contentNode = this.renderOptionalFeatureCta();
|
||||
@@ -294,7 +322,7 @@ export class OptionalFeatureManager extends React.PureComponent<
|
||||
affectedFeatureDefinitionKey={
|
||||
affectedFeatureDefinitionKey
|
||||
}
|
||||
isSelected={!!optionalFeatureMapping ?? false}
|
||||
isSelected={!!optionalFeatureMapping}
|
||||
onSelection={onSelection}
|
||||
onChangeReplacementPromise={onChangeReplacementPromise}
|
||||
onRemoveSelectionPromise={onRemoveSelectionPromise}
|
||||
@@ -338,7 +366,7 @@ export class OptionalFeatureManager extends React.PureComponent<
|
||||
affectedFeatureDefinitionKey={
|
||||
affectedFeatureDefinitionKey
|
||||
}
|
||||
isSelected={!!optionalFeatureMapping ?? false}
|
||||
isSelected={!!optionalFeatureMapping}
|
||||
onSelection={onSelection}
|
||||
onChangeReplacementPromise={onChangeReplacementPromise}
|
||||
onRemoveSelectionPromise={onRemoveSelectionPromise}
|
||||
|
||||
@@ -17,6 +17,7 @@ import {
|
||||
Constants,
|
||||
Container,
|
||||
ContainerUtils,
|
||||
CoreUtils,
|
||||
DataOrigin,
|
||||
DiceUtils,
|
||||
EntityValueLookup,
|
||||
@@ -135,6 +136,19 @@ export class ItemDetail extends React.PureComponent<Props> {
|
||||
}
|
||||
};
|
||||
|
||||
handleReplaceAbilityStatChange = (
|
||||
enabled: boolean,
|
||||
statId: Constants.AbilityStatEnum
|
||||
) => {
|
||||
const { onCustomDataUpdate } = this.props;
|
||||
|
||||
const adjustmentType = CoreUtils.getAdjustmentTypeByStatId(statId);
|
||||
|
||||
if (onCustomDataUpdate && adjustmentType) {
|
||||
onCustomDataUpdate(adjustmentType, enabled);
|
||||
}
|
||||
};
|
||||
|
||||
handleHexWeaponChange = (enabled) => {
|
||||
const { onCustomDataUpdate } = this.props;
|
||||
|
||||
@@ -319,7 +333,7 @@ export class ItemDetail extends React.PureComponent<Props> {
|
||||
};
|
||||
|
||||
renderClassCustomize = () => {
|
||||
const { item } = this.props;
|
||||
const { item, ruleData } = this.props;
|
||||
|
||||
const isHexWeapon = ItemUtils.isHexWeapon(item);
|
||||
const canHexWeapon = ItemUtils.canHexWeapon(item);
|
||||
@@ -327,8 +341,16 @@ export class ItemDetail extends React.PureComponent<Props> {
|
||||
const canPactWeapon = ItemUtils.canPactWeapon(item);
|
||||
const canBeDedicatedWeapon = ItemUtils.canBeDedicatedWeapon(item);
|
||||
const isDedicatedWeapon = ItemUtils.isDedicatedWeapon(item);
|
||||
const replacementWeaponStats = ItemUtils.getReplacementWeaponStats(item);
|
||||
const appliedWeaponReplacementStats =
|
||||
ItemUtils.getAppliedWeaponReplacementStats(item);
|
||||
|
||||
if (!canHexWeapon && !canPactWeapon && !canBeDedicatedWeapon) {
|
||||
if (
|
||||
!canHexWeapon &&
|
||||
!canPactWeapon &&
|
||||
!canBeDedicatedWeapon &&
|
||||
replacementWeaponStats.length === 0
|
||||
) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@@ -361,6 +383,21 @@ export class ItemDetail extends React.PureComponent<Props> {
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
{replacementWeaponStats.map((statId) => (
|
||||
<div className="ct-item-detail__class-customize-item" key={statId}>
|
||||
<Checkbox
|
||||
enabled={appliedWeaponReplacementStats.includes(statId)}
|
||||
onChange={(enabled) =>
|
||||
this.handleReplaceAbilityStatChange(enabled, statId)
|
||||
}
|
||||
label={`Use ${RuleDataUtils.getStatNameById(
|
||||
statId,
|
||||
ruleData,
|
||||
true
|
||||
)}`}
|
||||
/>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
+21
-3
@@ -1,4 +1,5 @@
|
||||
import * as React from "react";
|
||||
|
||||
import {
|
||||
AbilityLookup,
|
||||
Attack,
|
||||
@@ -21,15 +22,17 @@ import {
|
||||
} from "@dndbeyond/dice";
|
||||
import StarIcon from "@dndbeyond/fontawesome-cache/svgs/solid/star.svg";
|
||||
import { GameLogContext } from "@dndbeyond/game-log-components";
|
||||
|
||||
import { ItemName } from "~/components/ItemName";
|
||||
import { NumberDisplay } from "~/components/NumberDisplay";
|
||||
import Tooltip from "~/tools/js/commonComponents/Tooltip";
|
||||
|
||||
import Damage from "../../Damage";
|
||||
import { DigitalDiceWrapper } from "../../Dice";
|
||||
import { AttackTypeIcon } from "../../Icons";
|
||||
import NoteComponents from "../../NoteComponents";
|
||||
import { DiceComponentUtils } from "../../utils";
|
||||
import CombatAttack from "../CombatAttack";
|
||||
import { DigitalDiceWrapper } from "../../Dice";
|
||||
import Damage from "../../Damage";
|
||||
|
||||
interface Props {
|
||||
attack: Attack;
|
||||
@@ -130,6 +133,7 @@ class CombatItemAttack extends React.PureComponent<Props, State> {
|
||||
theme,
|
||||
rollContext,
|
||||
className,
|
||||
ruleData,
|
||||
} = this.props;
|
||||
|
||||
const [{ messageTargetOptions, defaultMessageTargetOption, userId }] =
|
||||
@@ -156,6 +160,8 @@ class CombatItemAttack extends React.PureComponent<Props, State> {
|
||||
const isPactWeapon = ItemUtils.isPactWeapon(item);
|
||||
const isDedicatedWeapon = ItemUtils.isDedicatedWeapon(item);
|
||||
const isLegacy = ItemUtils.isLegacy(item);
|
||||
const appliedWeaponReplacementStats =
|
||||
ItemUtils.getAppliedWeaponReplacementStats(item);
|
||||
|
||||
let combinedMetaItems: Array<string> = [];
|
||||
|
||||
@@ -165,7 +171,12 @@ class CombatItemAttack extends React.PureComponent<Props, State> {
|
||||
if (type === Constants.WeaponTypeEnum.AMMUNITION) {
|
||||
combinedMetaItems.push("Ammunition");
|
||||
} else {
|
||||
if (isHexWeapon || isPactWeapon || isDedicatedWeapon) {
|
||||
if (
|
||||
isHexWeapon ||
|
||||
isPactWeapon ||
|
||||
isDedicatedWeapon ||
|
||||
appliedWeaponReplacementStats.length > 0
|
||||
) {
|
||||
if (isHexWeapon) {
|
||||
combinedMetaItems.push("Hex Weapon");
|
||||
}
|
||||
@@ -175,6 +186,13 @@ class CombatItemAttack extends React.PureComponent<Props, State> {
|
||||
if (isDedicatedWeapon) {
|
||||
combinedMetaItems.push("Dedicated Weapon");
|
||||
}
|
||||
if (appliedWeaponReplacementStats.length > 0) {
|
||||
appliedWeaponReplacementStats.forEach((statId) => {
|
||||
combinedMetaItems.push(
|
||||
`Using ${RuleDataUtils.getStatNameById(statId, ruleData, true)}`
|
||||
);
|
||||
});
|
||||
}
|
||||
} else {
|
||||
combinedMetaItems.push(`${attackTypeName} Weapon`);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user