Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

BUG: Consumption doesnt seem to work if the actor has spell slots that arent Spell Slots or Pact slots #72

Open
Zanderaf opened this issue Mar 24, 2024 · 8 comments
Labels
bug Something isn't working

Comments

@Zanderaf
Copy link

Zanderaf commented Mar 24, 2024

With 3.1,0 DND5e, you now have the option to create custom spellcasting types, such as "Steve Magic" and "Steve Slots" which you can program to work in the same way as spell or pact slots. Attempting to use spell points while using any of these causes the module to break when determining what level you can cast the spells at.

Edit: Was talking about this in another server, and Zhell did have the following to say about it, not sure if it helps or now.

"They should be able to search through the full system.spells object and just read whether the values there have level and value."
"Having done a lot of generalization for spells this way in the system and elsewhere, I can assure you it is not hard"

image
image

@misthero misthero added the bug Something isn't working label Mar 25, 2024
@misthero
Copy link
Owner

may you show me how to create custom spellcasting types?

@Zanderaf
Copy link
Author

Zanderaf commented Mar 25, 2024

Sure! This was by Zhell from helping me set up my own custom spellcasting stuff, so credit to him. Its not a fully fleshed out progression, but it works for trying to figure out why it aint working I hope.

Hooks.once("init", function() {
  const {spellcastingTypes, spellProgression, spellPreparationModes} = CONFIG.DND5E;

  /* Basic configuration for each progression. */
  const configuration = {
    primal: {
      label: "Primal Magic",
      order: 0.75,
      upcast: true,
      cantrips: true
    },
    elemental: {
      label: "Four Elements",
      order: 0.85,
      upcast: true,
      cantrips: true
    }
  };

  /* Spell slot tables for the progressions. */
  const progressions = {
    primal: {
      2: {slots: 2, level: 1},
      17: {slots: 4, level: 5},
    },
    elemental: {
      2: {slots: 2, level: 1}
    }
  };

  /* Do these spellcasting progressions recover slots on short rests? */
  const rests = {
    primal: true,
    elemental: true
  };

  /* ------------------------------------------ */

  Object.entries(configuration).forEach(([k, v]) => {
    spellcastingTypes[k] = {label: v.label};
    spellProgression[k] = v.label;
    spellPreparationModes[k] = v;

    Hooks.on(`dnd5e.compute${k.capitalize()}Progression`, computeProgression.bind(k));
    Hooks.on(`dnd5e.prepare${k.capitalize()}Slots`, prepareSlots.bind(k));
  });

  Hooks.on("dnd5e.preRestCompleted", preRestCompleted);

  /**
   * @this k    Rebinding 'this' to be the key of the progression.
   */
  function computeProgression(progression, actor, cls, spellcasting, count) {
    progression[this] ??= 0;
    progression[this] += cls.system.levels;
  }

  /**
   * @this k    Rebinding 'this' to be the key of the progression.
   */
  function prepareSlots(spells, actor, progression) {
    let accumLevel = Math.clamped(progression[this], 0, CONFIG.DND5E.maxLevel);
    spells[this] ??= {};
    const override = Number.isNumeric(spells[this].override) ? parseInt(spells[this].override) : null;

    if ((accumLevel === 0) && (actor.type === "npc") && (override !== null)) {
      accumLevel = actor.system.details.spellLevel;
    }

    const [, configLevel] =
      Object.entries(progressions[this]).reverse().find(([l]) => Number(l) <= accumLevel) ?? [];
    if (configLevel) {
      spells[this].level = configLevel.level;
      if (override === null) spells[this].max = configLevel.slots;
      else spells[this].max = Math.max(override, 1);
      spells[this].value = Math.min(spells[this].value || 0, spells[this].max);
    } else {
      spells[this].max = override || 0;
      spells[this].level = (spells[this].max > 0) ? 1 : 0;
    }
  }

  /**
   * Recover slots on short rests.
   */
  function preRestCompleted(actor, result) {
    if (result.longRest) return;
    for (const [k, v] of Object.entries(rests)) {
      if (!v) return;
      const spells = actor.system.spells?.[k];
      if (!spells || !spells.max) return;
      result.updateData[`system.spells.${k}.value`] = spells.max;
    }
  }
});

@misthero
Copy link
Owner

thank you, may I also ask what is your use case? how do you use the custom slot progression and spellpoints? why do you need both? I'd like to know it to understand what can be done in your specific setup.

@Zanderaf
Copy link
Author

One thing I can think of is the whole "Warlocks using Spell Points" part of it, as the two listed here is basically pact magic but renamed and standalone, doing something along the lines of labeling all the spells as "Primal Magic" for example, and being able to upcast / cast them through spell points.

Taking "Primal Magic" (Basically Pact Magic renamed and standalone) as an example, from what I understand the module uses what spell slots a character has access to in order to determine to what level the spell can be cast at- but it looks like its only taking the "Basic" spell slots from upcasting, with Warlock spell points needing to be selected in the options to make it work for Pact Magic. (Though now I'm seeing you can only cast the spell at it's higher "Pact Magic" level with spell points,)

Ideally? It would recognize the level of the spell slot regardless of the name so it could be scaled properly in order to make use of the module but I'm still trying to figure out how it all works exactly

@misthero
Copy link
Owner

the "Warlocks using Spell Points" thing is there because officially dmg rules excludes warlocks from spellpoints system, what i fail to understand is if you are trying to get a custom number of spellpoints per level or what.
Pact magic always cast at a fixed level, no upcasting or downcasting, pact spell have a fixed level so the module knows that if the spellcasting is "pact" the level of the spell is in @spells.pact.level variable. other caster use the "Cast at level" selector to detect the level of the spell.

In your screenshot I cannot see the spellpoints enabled for that actor. Just slots. Am I wrong?
316345489-06d7aebf-8943-4e15-a3fc-cba4126bdbd8

it should be like this:
immagine

@Zanderaf
Copy link
Author

So, two screenshots:

  • First one is with just normal pact magic, only upscales to 3rd level as normal with spell points enabled
  • Second Image, spellcasting progression on the actor is switched to "Primal Magic" as shown in that section of World Script I sent, and no longer seems to work with spell points.
    image
    image

With the 2nd image, casting the spell to get into the Usage Configuration opens but errors out with the following:
image

@misthero
Copy link
Owner

does the second one works with spellpoints module disable and consume the right slots of the right level?

i tried the code you posted earlier to add primal magic and four elements, changed the casting type on the spells and the class but i get a strange behaviour, like a 5th level spell consuming first level slots or not being able to change the spell level

@Zanderaf
Copy link
Author

Zanderaf commented Mar 26, 2024

Seems to work, casting a spell with 3rd level Primal Magic slots only works with spells of 1st-3rd level, casting say, reincarnate at 5th level errors out and has no option for consumption because theres no spell slot of that level

  • Puts both of the spells at 3rd level correctly, but doesnt let me cast Reincarnate
    image
    image

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working
Projects
None yet
Development

No branches or pull requests

2 participants