import React from "react"; import { AbilityLookup, CharacterTheme, Constants, DataOriginRefData, ExperienceInfo, RuleData, ScaledSpell, Spell, SpellCasterInfo, SpellSlotContract, SpellUtils, } from "@dndbeyond/character-rules-engine/es"; import { IRollContext } from "@dndbeyond/dice"; import SpellsSpell from "../SpellsSpell"; interface Props { spells: Array; level: number; spellCasterInfo: SpellCasterInfo; ruleData: RuleData; abilityLookup: AbilityLookup; xpInfo: ExperienceInfo; onSpellClick?: (spell: Spell, castLevel: number) => void; onSpellSlotChange?: (castLevel: number, changeAmount: number) => void; onPactSlotChange?: (castLevel: number, changeAmount: number) => void; onSpellLimitedUseSet?: ( mappingId: number, mappingTypeId: number, uses: number, dataOriginType: Constants.DataOriginTypeEnum ) => void; onItemLimitedUseSet?: ( mappingId: number, mappingTypeId: number, uses: number ) => void; showNotes: boolean; isInteractive: boolean; diceEnabled: boolean; theme: CharacterTheme; dataOriginRefData: DataOriginRefData; proficiencyBonus: number; rollContext: IRollContext; } export default class SpellsLevel extends React.PureComponent { static defaultProps = { showNotes: true, diceEnabled: false, }; handleSpellSlotChange = (changeAmount: number): void => { const { onSpellSlotChange, level } = this.props; if (onSpellSlotChange) { onSpellSlotChange(level, changeAmount); } }; handlePactSlotChange = (changeAmount: number): void => { const { onPactSlotChange, level } = this.props; if (onPactSlotChange) { onPactSlotChange(level, changeAmount); } }; handleSpellClick = (spell: Spell, castLevel: number): void => { const { onSpellClick } = this.props; if (onSpellClick) { onSpellClick(spell, castLevel); } }; handleSpellUse = ( useSpellSlot: boolean, usePactMagicSlot: boolean, dataOriginType: Constants.DataOriginTypeEnum, uses: number | null, mappingId: number | null, mappingTypeId: number | null ): void => { const { onSpellLimitedUseSet, onItemLimitedUseSet } = this.props; if (useSpellSlot) { this.handleSpellSlotChange(1); } if (usePactMagicSlot) { this.handlePactSlotChange(1); } if (uses !== null && mappingId !== null && mappingTypeId !== null) { switch (dataOriginType) { case Constants.DataOriginTypeEnum.ITEM: if (onItemLimitedUseSet) { onItemLimitedUseSet(mappingId, mappingTypeId, uses); } break; default: if (onSpellLimitedUseSet) { onSpellLimitedUseSet( mappingId, mappingTypeId, uses, dataOriginType ); } } } }; getSpellSlotInfo = (): SpellSlotContract | null => { const { spellCasterInfo, level } = this.props; const { spellSlots } = spellCasterInfo; let spellSlotInfo = spellSlots.find( (spellSlotGroup) => spellSlotGroup.level === level ); return spellSlotInfo ? spellSlotInfo : null; }; getPactSlotInfo = (): SpellSlotContract | null => { const { spellCasterInfo, level } = this.props; const { pactMagicSlots } = spellCasterInfo; let spellSlotInfo = pactMagicSlots.find( (pactSlotGroup) => pactSlotGroup.level === level ); return spellSlotInfo ? spellSlotInfo : null; }; renderSpell = (spell: ScaledSpell): React.ReactNode => { const { ruleData, abilityLookup, xpInfo, level, showNotes, isInteractive, diceEnabled, theme, dataOriginRefData, proficiencyBonus, rollContext, } = this.props; let spellSlotLevel = this.getSpellSlotInfo(); let pactMagicLevel = this.getPactSlotInfo(); let doesSpellSlotExist: boolean = !!spellSlotLevel && spellSlotLevel.available > 0; let doesPactSlotExist: boolean = !!pactMagicLevel && pactMagicLevel.available > 0; let isSpellSlotAvailable: boolean = false; if (doesSpellSlotExist && spellSlotLevel) { isSpellSlotAvailable = spellSlotLevel.used < spellSlotLevel.available; } let isPactSlotAvailable: boolean = false; if (doesPactSlotExist && pactMagicLevel) { isPactSlotAvailable = pactMagicLevel.used < pactMagicLevel.available; } return ( ); }; render() { const { spells, showNotes, theme } = this.props; return (
Name
Time
Range
Hit / DC
Effect
{showNotes && (
Notes
)}
{spells.length ? ( spells.map((spell) => this.renderSpell(spell)) ) : (
No Spells Match the Current Filter
)}
); } }