diff --git a/CHANGELOG.md b/CHANGELOG.md index 2cb97d5f1..d20e70811 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,6 @@ # Next Up -- Simple Macros: Spell Refueling Ring infusion macro. +- Simple Macros: Spell Refueling Ring infusion, and Font of Magic macro. # 5.2.15 diff --git a/macros/feats/fontOfMagic.js b/macros/feats/fontOfMagic.js index 395801c4d..d326ba711 100644 --- a/macros/feats/fontOfMagic.js +++ b/macros/feats/fontOfMagic.js @@ -2,78 +2,6 @@ // required modules: midi-qol // number of points required to regain an nth level spell slot; {slot-level : point-cost}. -// midi changes to skip config dialog and not consume usage - -Hooks.once("dnd5e.preUseItem", (item, config, options) => { - options.configureDialog = false; - return true; -}); -Hooks.once("dnd5e.preItemUsageConsumption", (item, config, options) => { - config.consumeUsage = false; - return true; -}); -// End of midi changes to macro - -const conversion_map = { - "1": 2, - "2": 3, - "3": 5, - "4": 6, - "5": 7 -}; - -const style = ` - `; - -const sorceryPointsItem = actor.items.find((i) => i.name === "Sorcery Points"); -const { value: spvalue, max: spmax } = sorceryPointsItem.system.uses; -const spells = foundry.utils.duplicate(actor.system.spells); - -// array of spell levels for converting points to slots. -const valid_levels_with_spent_spell_slots = Object.entries(spells).filter(([key, { value, max }]) => { - const cost = conversion_map[key.at(-1)]; - if (!cost || cost > spvalue) return false; - return (max > 0 && value < max); -}); - // array of spell levels for converting slots to points. -const spell_levels_with_available_slots = Object.entries(spells).filter(([key, { value, max }]) => { - return (value > 0 && max > 0); -}); - -const is_missing_points = spvalue < spmax; -const is_missing_slots = valid_levels_with_spent_spell_slots.length > 0; - -// has unspent spell slots. -const has_available_spell_slots = spell_levels_with_available_slots.length > 0; -// has sp equal to or higher than the minimum required. -const has_available_sorcery_points = spvalue >= Math.min(...Object.values(conversion_map)); - -const can_convert_slot_to_points = has_available_spell_slots && is_missing_points; -const can_convert_points_to_slot = has_available_sorcery_points && is_missing_slots; -if (!can_convert_points_to_slot && !can_convert_slot_to_points) { - ui.notifications.warn("You have no options available."); - return; -} - -// set up available buttons. -const buttons = {}; -if (can_convert_slot_to_points) buttons["slot_to_point"] = { - icon: "
", - label: "Convert a spell slot to sorcery points", - callback: slot_to_points -}; -if (can_convert_points_to_slot) buttons["point_to_slot"] = { - icon: "
", - label: "Convert sorcery points to a spell slot", - callback: points_to_slot -}; -new Dialog({ title: "Font of Magic", buttons }).render(true); - // Convert spell slot to sorcery points. async function slot_to_points() { const level = await new Promise((resolve) => { @@ -81,7 +9,7 @@ async function slot_to_points() { const slot_to_points_buttons = Object.fromEntries(spell_levels_with_available_slots.map(([key, { value, max }]) => { const spell_level = key.at(-1); return [key, { callback: () => { - resolve(spell_level); + resolve(spell_level); }, label: `
${CONFIG.DND5E.spellLevels[spell_level]} (${value}/${max}) @@ -96,7 +24,7 @@ async function slot_to_points() {

Pick a spell slot level to convert one spell slot to sorcery points (${spvalue}/${spmax}). You regain a number of sorcery points equal to the level of the spell slot.

`, close: () => { - resolve(0); + resolve(0); } }, { classes: ["dialog", "font-of-magic"] @@ -124,7 +52,7 @@ async function points_to_slot() { const spell_level = key.at(-1); const cost = conversion_map[spell_level]; return [key, { callback: () => { - resolve(spell_level); + resolve(spell_level); }, label: `
${CONFIG.DND5E.spellLevels[spell_level]} (${value}/${max}) @@ -137,7 +65,7 @@ async function points_to_slot() { buttons: points_to_slot_buttons, content: style + `

Pick a spell slot level to regain from sorcery points (${spvalue}/${spmax}).

`, close: () => { - resolve(0); + resolve(0); } }, { classes: ["dialog", "font-of-magic"] @@ -154,3 +82,86 @@ async function points_to_slot() { }); } } + +const conversion_map = { + "1": 2, + "2": 3, + "3": 5, + "4": 6, + "5": 7 +}; + +const style = ` + `; + +const sorceryPointsItem = actor.items.find((i) => i.name === "Sorcery Points"); +const { value: spvalue, max: spmax } = sorceryPointsItem.system.uses; +const spells = foundry.utils.duplicate(actor.system.spells); + +// array of spell levels for converting points to slots. +const valid_levels_with_spent_spell_slots = Object.entries(spells).filter(([key, { value, max }]) => { + const cost = conversion_map[key.at(-1)]; + if (!cost || cost > spvalue) return false; + return (max > 0 && value < max); +}); + // array of spell levels for converting slots to points. +const spell_levels_with_available_slots = Object.entries(spells).filter(([key, { value, max }]) => { + return (value > 0 && max > 0); +}); + +const is_missing_points = spvalue < spmax; +const is_missing_slots = valid_levels_with_spent_spell_slots.length > 0; + +// has unspent spell slots. +const has_available_spell_slots = spell_levels_with_available_slots.length > 0; +// has sp equal to or higher than the minimum required. +const has_available_sorcery_points = spvalue >= Math.min(...Object.values(conversion_map)); + +const can_convert_slot_to_points = has_available_spell_slots && is_missing_points; +const can_convert_points_to_slot = has_available_sorcery_points && is_missing_slots; +if (!can_convert_points_to_slot && !can_convert_slot_to_points) { + ui.notifications.warn("You have no options available."); + return; +} + +// set up available buttons. +const buttons = {}; +if (can_convert_slot_to_points) buttons["slot_to_point"] = { + icon: "
", + label: "Convert a spell slot to sorcery points", + callback: slot_to_points +}; +if (can_convert_points_to_slot) buttons["point_to_slot"] = { + icon: "
", + label: "Convert sorcery points to a spell slot", + callback: points_to_slot +}; + + +if (scope && foundry.utils.getProperty(scope, "flags.ddb-importer.ddbMacroFunction")) { + if (!actor || ! item) { + logger.error("No actor or item passed to arcane recovery"); + return; + } + new Dialog({ title: "Font of Magic", buttons }).render(true); +} else if (args && args[0] === "on") { + // midi changes to skip config dialog and not consume usage + Hooks.once("dnd5e.preUseItem", (item, config, options) => { + options.configureDialog = false; + return true; + }); + Hooks.once("dnd5e.preItemUsageConsumption", (item, config, options) => { + config.consumeUsage = false; + return true; + }); + // End of midi changes to macro + + new Dialog({ title: "Font of Magic", buttons }).render(true); +} + + diff --git a/src/effects/DDBSimpleMacro.js b/src/effects/DDBSimpleMacro.js index 188a518d0..0f08955f2 100644 --- a/src/effects/DDBSimpleMacro.js +++ b/src/effects/DDBSimpleMacro.js @@ -17,6 +17,14 @@ export default class DDBSimpleMacro { name: "arcaneRecovery", label: "Arcane Recovery Macro" }, + "font-of-magic": { + name: "fontOfMagic", + label: "Font of Magic Macro", + }, + "convert-sorcery-points": { + name: "fontOfMagic", + label: "Font of Magic Macro", + }, }, "item": { "spell-refuleing-ring": {