``` ~/go/bin/sourcemapper -output ddb -jsurl https://media.dndbeyond.com/character-app/static/js/main.90aa78c5.js ```
303 lines
9.0 KiB
TypeScript
303 lines
9.0 KiB
TypeScript
import * as React from "react";
|
|
import { Tooltip } from "@dndbeyond/character-common-components/es";
|
|
import {
|
|
ConditionUtils,
|
|
DiceUtils,
|
|
HigherLevelContract,
|
|
HigherLevelEntryContract,
|
|
ModifierUtils,
|
|
RuleData,
|
|
RuleDataUtils,
|
|
Spell,
|
|
SpellConditionContract,
|
|
SpellModifierContract,
|
|
SpellUtils,
|
|
CharacterTheme,
|
|
} from "@dndbeyond/character-rules-engine/es";
|
|
import { RollType, RollKind, IRollContext } from "@dndbeyond/dice";
|
|
import { GameLogContext } from "@dndbeyond/game-log-components";
|
|
import { HealingIcon } from "../Icons";
|
|
import { DiceComponentUtils } from "../utils";
|
|
import { DigitalDiceWrapper } from "../Dice";
|
|
import Damage from "../Damage";
|
|
|
|
interface Props {
|
|
spell: Spell;
|
|
castLevel: number;
|
|
characterLevel: number;
|
|
ruleData: RuleData;
|
|
diceEnabled: boolean;
|
|
theme: CharacterTheme;
|
|
isCriticalHit?: boolean;
|
|
rollContext: IRollContext;
|
|
}
|
|
class SpellDamageEffect extends React.PureComponent<Props> {
|
|
static defaultProps = {
|
|
diceEnabled: false,
|
|
};
|
|
|
|
getPoints = (
|
|
atHigherLevels: HigherLevelContract | null
|
|
): Array<HigherLevelEntryContract> => {
|
|
let points: Array<HigherLevelEntryContract> = [];
|
|
if (atHigherLevels && atHigherLevels.points !== null) {
|
|
points = atHigherLevels.points;
|
|
}
|
|
return points;
|
|
};
|
|
|
|
render() {
|
|
const {
|
|
spell,
|
|
castLevel,
|
|
characterLevel,
|
|
ruleData,
|
|
diceEnabled,
|
|
theme,
|
|
isCriticalHit,
|
|
rollContext,
|
|
} = this.props;
|
|
|
|
const [{ messageTargetOptions, defaultMessageTargetOption, userId }] =
|
|
this.context;
|
|
|
|
let isScaled: boolean = false;
|
|
const modifiers = SpellUtils.getModifiers(spell);
|
|
const tags = SpellUtils.getTags(spell);
|
|
const conditions = SpellUtils.getConditions(spell);
|
|
|
|
let displayNode: React.ReactNode;
|
|
let damageModifiers = modifiers.filter((modifier) =>
|
|
ModifierUtils.isSpellDamageModifier(modifier)
|
|
);
|
|
if (damageModifiers.length) {
|
|
let modifier: SpellModifierContract = damageModifiers[0];
|
|
const friendlySubtypeName =
|
|
ModifierUtils.getFriendlySubtypeName(modifier);
|
|
const atHigherLevels = ModifierUtils.getAtHigherLevels(modifier);
|
|
let scaleType = SpellUtils.getScaleType(spell);
|
|
let points = this.getPoints(atHigherLevels);
|
|
let atHigherDamage = SpellUtils.getSpellScaledAtHigher(
|
|
spell,
|
|
scaleType,
|
|
points,
|
|
characterLevel,
|
|
castLevel
|
|
);
|
|
let scaledDamageDie = SpellUtils.getSpellFinalScaledDie(
|
|
spell,
|
|
modifier,
|
|
atHigherDamage
|
|
);
|
|
isScaled =
|
|
isScaled ||
|
|
SpellUtils.isSpellScaledByCastLevel(
|
|
spell,
|
|
scaleType,
|
|
points,
|
|
castLevel
|
|
);
|
|
|
|
displayNode = (
|
|
<span className="ddbc-spell-damage-effect__damages">
|
|
<DigitalDiceWrapper
|
|
diceNotation={DiceUtils.renderDice(scaledDamageDie)}
|
|
rollType={RollType.Damage}
|
|
rollAction={SpellUtils.getName(spell)}
|
|
rollKind={isCriticalHit ? RollKind.CriticalHit : RollKind.None}
|
|
diceEnabled={diceEnabled}
|
|
themeColor={theme.themeColor}
|
|
rollContext={rollContext}
|
|
rollTargetOptions={
|
|
messageTargetOptions
|
|
? Object.values(messageTargetOptions?.entities)
|
|
: undefined
|
|
}
|
|
rollTargetDefault={defaultMessageTargetOption}
|
|
userId={userId}
|
|
>
|
|
<Damage
|
|
damage={DiceComponentUtils.getDamageDiceNotation(
|
|
scaledDamageDie,
|
|
isCriticalHit
|
|
)}
|
|
type={friendlySubtypeName || ""}
|
|
showInfoTooltip={false}
|
|
theme={theme}
|
|
/>
|
|
</DigitalDiceWrapper>
|
|
</span>
|
|
);
|
|
}
|
|
|
|
let hitPointHealingModifiers = modifiers.filter((modifier) =>
|
|
ModifierUtils.isSpellHealingHitPointsModifier(modifier)
|
|
);
|
|
if (!displayNode && hitPointHealingModifiers.length) {
|
|
let modifier: SpellModifierContract = hitPointHealingModifiers[0];
|
|
const atHigherLevels = ModifierUtils.getAtHigherLevels(modifier);
|
|
let scaleType = SpellUtils.getScaleType(spell);
|
|
let points = this.getPoints(atHigherLevels);
|
|
let atHigherHealing = SpellUtils.getSpellScaledAtHigher(
|
|
spell,
|
|
scaleType,
|
|
points,
|
|
characterLevel,
|
|
castLevel
|
|
);
|
|
let scaledHealingDie = SpellUtils.getSpellFinalScaledDie(
|
|
spell,
|
|
modifier,
|
|
atHigherHealing,
|
|
castLevel
|
|
);
|
|
isScaled =
|
|
isScaled ||
|
|
SpellUtils.isSpellScaledByCastLevel(
|
|
spell,
|
|
scaleType,
|
|
points,
|
|
castLevel
|
|
);
|
|
|
|
displayNode = (
|
|
<span className="ddbc-spell-damage-effect__healing ddbc-spell-damage-effect__healing--hp">
|
|
<DigitalDiceWrapper
|
|
useAdvancedMenu={false}
|
|
diceNotation={DiceUtils.renderDice(scaledHealingDie)}
|
|
rollType={RollType.Heal}
|
|
rollAction={SpellUtils.getName(spell)}
|
|
diceEnabled={diceEnabled}
|
|
rollContext={rollContext}
|
|
rollTargetOptions={
|
|
messageTargetOptions
|
|
? Object.values(messageTargetOptions?.entities)
|
|
: undefined
|
|
}
|
|
rollTargetDefault={defaultMessageTargetOption}
|
|
userId={userId}
|
|
>
|
|
{DiceUtils.renderDice(scaledHealingDie)}{" "}
|
|
<HealingIcon theme={theme} isHp={true} />
|
|
</DigitalDiceWrapper>
|
|
</span>
|
|
);
|
|
}
|
|
|
|
const tempHitPointHealingModifiers = modifiers.filter((modifier) =>
|
|
ModifierUtils.isSpellHealingTempHitPointsModifier(modifier)
|
|
);
|
|
if (!displayNode && tempHitPointHealingModifiers.length) {
|
|
let modifier = tempHitPointHealingModifiers[0];
|
|
const atHigherLevels = ModifierUtils.getAtHigherLevels(modifier);
|
|
let scaleType = SpellUtils.getScaleType(spell);
|
|
let points = this.getPoints(atHigherLevels);
|
|
let atHigherHealing = SpellUtils.getSpellScaledAtHigher(
|
|
spell,
|
|
scaleType,
|
|
points,
|
|
characterLevel,
|
|
castLevel
|
|
);
|
|
let scaledHealingDie = SpellUtils.getSpellFinalScaledDie(
|
|
spell,
|
|
modifier,
|
|
atHigherHealing,
|
|
castLevel
|
|
);
|
|
isScaled =
|
|
isScaled ||
|
|
SpellUtils.isSpellScaledByCastLevel(
|
|
spell,
|
|
scaleType,
|
|
points,
|
|
castLevel
|
|
);
|
|
|
|
displayNode = (
|
|
<span className="ddbc-spell-damage-effect__healing ddbc-spell-damage-effect__healing--temp">
|
|
<DigitalDiceWrapper
|
|
useAdvancedMenu={false}
|
|
diceNotation={DiceUtils.renderDice(scaledHealingDie)}
|
|
rollType={RollType.Heal}
|
|
rollAction={SpellUtils.getName(spell)}
|
|
diceEnabled={diceEnabled}
|
|
rollContext={rollContext}
|
|
rollTargetOptions={
|
|
messageTargetOptions
|
|
? Object.values(messageTargetOptions?.entities)
|
|
: undefined
|
|
}
|
|
rollTargetDefault={defaultMessageTargetOption}
|
|
userId={userId}
|
|
>
|
|
{DiceUtils.renderDice(scaledHealingDie)}{" "}
|
|
<HealingIcon theme={theme} isTemp={true} />
|
|
</DigitalDiceWrapper>
|
|
</span>
|
|
);
|
|
}
|
|
|
|
if (!displayNode && conditions.length) {
|
|
let spellCondition: SpellConditionContract = conditions[0];
|
|
let condition = RuleDataUtils.getCondition(
|
|
spellCondition.conditionId,
|
|
ruleData
|
|
);
|
|
let name: string =
|
|
condition === null ? "" : ConditionUtils.getName(condition);
|
|
displayNode = (
|
|
<span
|
|
className={`ddbc-spell-damage-effect__conditions ${
|
|
theme.isDarkMode
|
|
? "ddbc-spell-damage-effect__conditions--dark-mode"
|
|
: ""
|
|
}`}
|
|
>
|
|
<Tooltip
|
|
isDarkMode={theme.isDarkMode}
|
|
title={`${name}${
|
|
spellCondition.exception ? `, ${spellCondition.exception}` : ""
|
|
}`}
|
|
>
|
|
{name}
|
|
</Tooltip>
|
|
</span>
|
|
);
|
|
}
|
|
|
|
if (!displayNode && tags.length) {
|
|
displayNode = (
|
|
<span
|
|
className={`ddbc-spell-damage-effect__tags ${
|
|
theme.isDarkMode ? "ddbc-spell-damage-effect__tags--dark-mode" : ""
|
|
}`}
|
|
>
|
|
{tags[0]}
|
|
</span>
|
|
);
|
|
}
|
|
|
|
let hasMore: boolean = damageModifiers.length > 1;
|
|
hasMore = hasMore || hitPointHealingModifiers.length > 1;
|
|
hasMore = hasMore || tempHitPointHealingModifiers.length > 1;
|
|
hasMore = hasMore || conditions.length > 1;
|
|
hasMore = hasMore || tags.length > 1;
|
|
|
|
return (
|
|
<div
|
|
className={`ddbc-spell-damage-effect ${
|
|
isScaled ? "ddbc-spell-damage-effect--scaled" : ""
|
|
} ${theme.isDarkMode ? "ddbc-spell-damage-effect--dark-mode" : ""}`}
|
|
>
|
|
{displayNode}
|
|
{hasMore ? "*" : ""}
|
|
</div>
|
|
);
|
|
}
|
|
}
|
|
|
|
SpellDamageEffect.contextType = GameLogContext;
|
|
|
|
export default SpellDamageEffect;
|