#Custom Wild Magic Surge

1 messages ยท Page 1 of 1 (latest)

misty valley
#

@burnt shoal this thread shows the development of a surge handler

burnt shoal
#

My game is tonight, so I can't do it right now, but I'll check it out during the week end !

misty valley
#

@unreal portal

#

Just fyi

burnt shoal
#

Hm, how do I check that a WM was triggered ? Is just checking the result of the handler with .table enough ?

misty valley
#

Yea, I still haven't fixed the return info

#

But a table does indicate a surge occured

burnt shoal
#

Wait no, I need a post run, actually, since I'm defining the handler.

misty valley
#

You can call the base handler for most of the work

#

Just change the target or roll value

#

In the script above, you see this exact process

burnt shoal
#

Oh yeah.

#

How do you think I should store the information of the current threshold for an actor ? Directly in the actor ?

misty valley
#

Yea, a flag or resource pool would work

#

You can send back actor updates to apply

burnt shoal
#

Resource pool could be used by something else.

misty valley
#

That set property call above is doing that

#

Yea, a flag would be easy too

#

You can set it yourself or include it in the actor update field of the surge data

burnt shoal
#

I'm unfamiliar with flag conventions. Should I scope the flag with the module name ?

misty valley
#

If it's your own flag not from a module, use the world scope

#

'world' that is

burnt shoal
#
/* surges on 1d20 <= X + 1, where X is the number of spells without surge since the last surge */
  static async buildupHandler(actor, surgeData) {
    const targetRoll = actor.getFlag(MODULE.data.name, 'wildMagicBuildupThreshold') ?? 1;

    let surgeResult = await WildMagic.templates.handler(actor, surgeData, `${targetRoll}`);
    actor.setFlag(MODULE.data.name, 'wildMagicBuildupThreshold', surgeResult.table ? 1 : targetRoll + 1);

    return surgeResult;
}

Something like this maybe ?

#

Oh, really ? ok, world it is.

misty valley
#

You won't have access to the MODULE namespace anyway

burnt shoal
#

I added an import :p

#

but ok, I'll change it.

misty valley
#

Hehehe

#

It's best to stay out of other module flag scopes

burnt shoal
#

Isn't 'world' the global scope, though ?

misty valley
#

Which a world script falls into ๐Ÿ™‚

burnt shoal
#

I mean, I am writing a pr to your module. My question was how to scope the flag then ^^

misty valley
#

Ohhhh

#

Hmmm

#

Yea, using the module scope is correct

#

Sorry, forgot you were doing a PR

#

Import MODULE like you did initially, ๐Ÿ˜…

burnt shoal
#

Ill make the PR tomorrow or on Sunday, I don't really want to mess with modules rn when I have session 1 in 1 hour x)

misty valley
#

Hehehe, that's a smart move

#

I'll keep an eye out for it. Hopefully getting some dev time in this weekend with working AC!

burnt shoal
#

Also, grats on having a well made API. Adding a homebrew in 5 lines of code is not something I'm used to.

misty valley
#

That's wonderful to hear! I was pretty happy with being able to implement the stock handlers with as little top level code as it was

burnt shoal
#

Flags seem to be broken on master btw. Tried to go back a couple of commits and it didnt fix itself.

burnt shoal
misty valley
#

a new homebrew surge rule in a handful of lines is pretty neat

#

so happy this api is working out!

misty valley
#

@modern crypt Ah, there you are ๐Ÿ™‚ here is the WMS API thread that has two examples in it (over many many messages, hehe)

misty valley
#

@severe nacelle

#

actually, incremental checks where implemented just above

#

but dont let me distract you, i'll just leave this here ๐Ÿ™‚

severe nacelle
#

does it have auto-surge if tides is expended? I think that was the main one

misty valley
#

not built in, but it would be an easy add

severe nacelle
#

how easy would it be to trigger that macro Zhell made for me, instead of rolling a table?

#

cos if I can have the macro trigger, and the auto-surge, then I can do everything in helpers without needing outside stuff

misty valley
#

It should be quite easy. Will take a world script to add the handler, but if you look in the scripts/plugins folder on the repo, you will see examples of the core handlers

#

Which are built using the exact same tools you are provided with

#

Full control over anything that causes the actor to be modified

severe nacelle
#

I may need help doing it. I actually already use dnd5e helpers for a few other things (like the better diagonals, and I may start using the actions logging) so doing wild magic too would mean I could actually -reduce- my total modules!

#

from like... 109

#

to 108

#

I'm just looking through the plugin/scripts stuff now

misty valley
severe nacelle
#

so that seems to be what I wanted (mostly?) in that it is adding to the rolls if tides is discharged. Which may be enough... though I do think it may be worth just adding a tickbox for the whole wild magic options list that is 'auto surge if tides discharged' that would then work no matter what surge rules you were using. Just a thought. As a lot of DMs seem to use the rule where a surge always happens if tides is empty (or so it seems)

#

but how would I set up triggering a macro, instead of rolling on the table? That doesn't seem to be in that document (that I'm seeing)

misty valley
#

after the v10 upgrade i can revisit things like that ๐Ÿ‘

misty valley
severe nacelle
misty valley
#

just set surgeresult.surge to true if tides is charged

#

shouldnt even need the surge roll handler in that case

severe nacelle
misty valley
#

you would breakpoint in that function, im not sure how well that ret value is documented...1 sec

#

that's the ret val

severe nacelle
#

is the table in another js file? This one seems to return a value for surgeresult

misty valley
#

the table is a table ID or UUID

severe nacelle
#

oh no I meant the table field I needed to edit / delete / perform some kind of black magic upon

misty valley
#

surgeResults.table = null

severe nacelle
#
results.table = {
        uuid: table?.uuid
      }

This part, ok

misty valley
#

not in the helpers code

#

in your plugin code

#

but yea, that's where i create the field on my side

severe nacelle
#

oh, thats what confused me, cos the handler the other person did didn't have a results.table section

misty valley
#

right, yea, they just let the default behavior go

#

simply modified the target based on the flag

severe nacelle
#

yeh, while I'm happy with the default roll options, but want to add auto-surge and change the table-roll to a macro. So I'm :confused business dog at keyboard:

severe nacelle
#
 if (surgeResult.table) {
        setProperty(surgeResult, 'actorUpdates.data.resources.secondary.value', 0)
      } else {
        const newValue = actor.data.data.resources.secondary.value + surgeData.spellLevel
        setProperty(surgeResult, 'actorUpdates.data.resources.secondary.value', newValue)
      }

Is there anything in this section that is actually necessary for my purposes? As far as I can see, its all related to adding or resetting their secondary resource (which I believe was where they stored their incremental tally)

misty valley
#

that looks about right, log out the final surgeResult before returning, to double check

severe nacelle
#

let surgeResult =
what value should this be to force a surge? I can't figure it out from the example

#
class WildMagicSurge {

    static init() {
  
      /* When called on by the WildMagic utility, register our surge handlers and pre checks */
      Hooks.on('wmsRegister', () => {
        /* use our modified inputs for the homebrew variants */
        WildMagic.registerHandler('Soul Music', WildMagicSurge.soulHandler);
        ui.notifications.notify("Hear the Music!");
      });
    }
  


    /* surges on 1d20 <= spell level*/
    static async soulHandler(actor, surgeData) {
  
      /* increase the spell level by resource factor */
      const targetRoll = `${surgeData.spellLevel}`
      const surgeRoll = `1d20`
      const tidesCharged = WildMagic.isTidesCharged(actor);

      if (tidesCharged = true) {
        let surgeResult = await WildMagic.templates.handler(actor, surgeData, targetRoll, surgeRoll);
      }
      else {
        let surgeResult = 
      }
      
     
     
/*      if (surgeResult.table) {
        setProperty(surgeResult, 'actorUpdates.data.resources.secondary.value', 0)
      } else {
        const newValue = actor.data.data.resources.secondary.value + surgeData.spellLevel
        setProperty(surgeResult, 'actorUpdates.data.resources.secondary.value', newValue)
      }  */

      return surgeResult
  
    }
  }
  
  /* When the WildMagic utility is ready, we can use its helpers
   * and register ourselves */
  Hooks.on('helpersReady', WildMagicSurge.init)

About as far as I could figure out lol. I don't even know if tidesCharged returns as true/false or something else entirely

#

Ha, I didn't know you could format discord as js. TIL

misty valley
#

if (tidesCharged = true) { -> use two ==

#

but looking good

severe nacelle
#

but what does surgeResult need to be to force a surge? I haven't been able to figure that out

misty valley
#

surgeResult.surge = true, iirc

#

generate chat data could be useful too

severe nacelle
#

I'll take another look at it tomorrow ๐Ÿ™‚

severe nacelle
#

On another subject (as I'm currently working my way through my v10 compatibility list) I'm sure you get this all the time, but I was just curious if Squadron v10 was in the works? I only just installed it, but it's so good I already am not sure I would update to v10 without it lol

misty valley
#

yes, but its still going to be a couple weeks

severe nacelle
#

No rush, I probably won't update until Drag Ruler and Item Piles gets updated too anyway. I don't see how people play foundry without drag ruler !

misty valley
#

(easily, hehe)

severe nacelle
#

Needing a keyboard to move isn't great, at least not for my players who usually play while lounging on the sofa with their mouse

#

I dunno if core changed the controls since I last tried it though. I installed drag early on and never looked back

misty valley
#

shrug couldnt say ๐Ÿ™‚

misty valley
#

@copper mortar unlocked now?

copper mortar
misty valley
#

which custom class?

copper mortar
#

the handler class

misty valley
#

oh, world script

copper mortar
#

right, what does adding a class look like? I know what catching a hook looks like. would i just add this to the world script?

static async myCustomHandler(actor, surgeData) {
    // doing stuff
    return surgeResult;
}
misty valley
#

i implemented the helpers wild magic surge with its own API to serve as an example ๐Ÿ™‚ everything but that top import {MODULE}

copper mortar
#

oh sorry, I misread that. The class is WildMagicSurge , the handler is a function, my b.
So could i just add this to my world script and it'll add my custom handler to the class?


class WildMagicSurge {
  static async myCustomHandler(actor, surgeData) {
    // doing stuff
    return surgeResult;
  }
}

adding the stuff to the hook to register I understand, just unsure about what adding a function looks like

misty valley
#

it would look like line 22, for example

#

WildMagic is the global namespace available after the helpersReady hook

copper mortar
#

yeah, thats the registering of the handler. I get that bit. how am I adding my custom function?

misty valley
#

๐Ÿค” hmm, im not following

#

by registering the handler, the system takes it from there

copper mortar
#

lemme send a screenshot of my worldscript to give beter context

#

50-54 are registering the handler, 56-61 is where the code for that handler goes?

misty valley
#

the myCustomHandler function is where all your logic goes, yea

#

making as much use of the WildMagic.templates functions as you can

copper mortar
#

yeah, it will likely be very similar to the existing buildup handler, I just wanted to make sure the syntax for that function is correct in the worldscript. Just seems odd to me for some reason that I'm writing a function to a class that already exists by adding the class itself to the worldscript

misty valley
#

oh, WildMagicSurge is just a local symbol in that plugin file I linked

#

you could call your class anything

#

the WildMagic symbol, however, is a global symbol provided by helpers to access its API

copper mortar
#

OHH, so I'm just writing a function inside a nothing class thats getting called by the wildmagicsurge handler? Do I even need the Class bit then? could I just write an orphan function?

misty valley
#

you very much could write it as a free function, yep

#

my implementation had a bit more to it, so i opted for a slightly stricter organization

copper mortar
#

Ohh, so do world scripts just append all this code into the source? the implementation of it is new to me. You'd think I mightve been taught these things while studying computer science, but i guess scripting is just really different from OOP

misty valley
#

world scripts are loaded akin to modules -- they are just world-specific

#

loaded into memory and executed

copper mortar
#

Ok yeah, just dont have a ton of experience with app building, so learning a lot here. thanks ๐Ÿ™‚ I'll come back if I have any questions implementing this

misty valley
#

looks like you got a pretty good start, good luck!

copper mortar
misty valley
#

Yea, pretty sure they are async aware

copper mortar
#

okay i definitely dont know how to do this bit, I wrote code that should work in theory, but I dont know how to put my dialog box callback at the front of the queue to prevent the rest of the handler from running until i get a response

#

it basically, properly pulling up the dialog, but by the time the dialog has loaded, the code moves on and i'm getting errors because the variables I want to set with the dialog box aren't set yet

#

basically I dont know where to put "await" when it comes to dialog boxes

misty valley
#

ooo, that one is much much easier in v10. Search #macro-polo for Dialog.prompt, Dialog.confirm, or Dialog.wait

#

@copper mortar

copper mortar
#

yeah, figured it out, ty

bleak quarry
#

I was not expecting there to be a thread for the specific macro I wanted to make

#

nice

misty valley
#

the topic has come up a few times and having this thread is handy reference ๐Ÿ™‚

#

several examples right here

bleak quarry
#

so for example if I had the module and wanted a macro that just rolls on a custom wild magic table, I'd use surge([whatever the alias is for currently selected actor]) in it and change the settings of the module to target a different roll table I've made?

misty valley
#

if i were to rephrase: you want a specific actor to use an alternate surge table rather than the one defined in the module options?

bleak quarry
bleak quarry
#

the contacts lists the makers discord tag as JB#2780, but there doesn't seem to be anyone with that account name here

#

found them

turbid barn
#

And I don't think it is working. I tested the my-script.js file as far as I could in the console. When I load the edited world and my-script files I still see character casting via Tides of Chaos in the console window, and none of the console log stuff nor chatmessage stuff shows up. I suspect that my lack of knowledge is a root cause. The my-script.js file is saved in same folder as the world.json. I have attached the world.json and my-script.js files. Have now verified that the world.json is not the issue. Help Please!

misty valley
#

im not really at a place i can dig through this too much, but the world manifest looks right, i do see a potential error when you are registering the handler:

WildMagic.registerHandler('BrokenSurges', WildMagicSurge.BrokenSurges);

I think you want that to just be BrokenSurges, which is the name of your function, below

#

mmmm

#

or im confused and read the indents wrong

#

you can remove all of that class wrapping you are doing

#

define your init function and your BrokenSurges functions individually

#

and pass the init function to the helper init hook like you are doing currently

#

that will at least simplify things

#

OH

#

yea, unwrapping would have helped, so i recommend doing that

turbid barn
#

Trying that now.

misty valley
#

'ready' fires well after helpersReady

#

just have your init called from helpersReady

#

.....unless indentation got me AGAIN lolol, sorry

turbid barn
#

Its all good. I tried removing the wrapper. Still doesn't seem to work. But I also can't very well ask you to troubleshoot when you are busy. If I can't beat in to shape I will follow up tomorrow.

#

I have noticed that under special traits on character sheet I can't assign my wildmagicsurge variant which could be part of the problem.

misty valley
#

go ahead and post the updated version when you get a chance, and you are 100% correct that the absence of your entry means something high level didnt quite work

#

i'll try to take a look at it over coffee tomorrow morning ๐Ÿ™‚ its been a while since ive used this code, personally, so I could be missing something

#

return values from the handlers could be one thing, just offhand ๐Ÿคทโ€โ™‚๏ธ

turbid barn
#

Apparently store already closed. Guess I am making backup plan leftovers for dinner. ๐Ÿคฃ Also realized image I pasted was wrong folder.

turbid barn
#

And giving up for the night. Only changes are to the my-script.js function. Uploading current version and doing something non code until brian fog clears.

misty valley
#

here we go, this is one issue

Hooks.on('helpersReady', WildMagicSurge.init)
#

i was likely reading from the wrong source code (old v9 helper's version)

#

the hook name is simbulsReady

#

@turbid barn

turbid barn
#

Still does not seem to be working.

#

In that It does not get as far as giving option for custom wild surge variant.

misty valley
#

oh

#

there is another small one

#

that same line

#

WildMagicSurge.init, you are calling the core init function (already called). You want to call your init function, which is just init

#

and remove the static declarations from your functions

#

replace with function or async function

turbid barn
#

Also changed line 10 and it now loads and gives broken surges as an option. However it does not like the for loops I am using starting in line 40 for list comparison. Gives error variable ar is not defined. I assume I need to fix syntax on the for loops, or there may be a more efficient way to do list matching in this environment.

misty valley
#

JS needs its variables declared, so similar to your outer for loop, for (const variable of list)

#

or for...in in this specific case

turbid barn
#

On it!

#

Worked in console for some reason, will have to edit the .js real quick.

misty valley
#

console is a bit different w.r.t declaring variables

#

or...is more "tolerant"

turbid barn
#

Gotcha. And I am used to python which would have a different form entirely for most of my commands. Looks like javascript prefers while statements for parsing lists.

#

Lets see if this fixes it.

misty valley
#

mmmm, no no, i mean, a for loop is fine

#

one thing, change those var declarations to let if mutable, or const if read-only

#

and comparing objects directly is not usually what you wanna do

turbid barn
#

Fair. I just looked at some quick .js tutorials on list parsing. However it looks my declaration for casting mod is still an issue in that it parses it as a string?it is a string rather than an int?

misty valley
#

for example:

        for (ar in arcaneClass) {

            /* breaks if there is no subclass
            if (testClass == arcaneClass[i] || subClass == arcaneClass[i])
            */
            if (testClass == arcaneClass[ar]) {
                multiplier = 2;
                console.log("matched arcane");
            }
        }

is better written

const hasArcane = arcaneClass.some( name => name == testClass)
#

nevermind, testClass was a string, not an object

misty valley
#

there is no ability with ID == testClass

#

abilities are 'str', 'dex', etc

turbid barn
#

That may be a more elegant /compact solution. I am going with the assumption that a given character could have multiple classes to parse. Ideally I would like to parse subclasses as well but am unsure how to handle cases where character is too low a level to have subclasses. The ideal flow for it is 1)generate list of subclass /class (probably only test subclass if length of list >0), 2) set multiplier based on list matches (lowest mult will be retained), 3)determine casting mod based on lowest multiplier classes stat, 4) roll vs DC and pass off for calculation.

misty valley
#

i would use Array#filter to extract class and subclass items from the actor's items list

#

then convert those to class identifier strings via Array#map

#

the class identifiers are probably what you want to pay attention to

#

it would also help if you defined your arcane class names by the identifiers, rather than the item's name

turbid barn
#

I will Google a tutorial on that when I get home. I am not familiar with array#filter or Reay#map. When you say identifiers, what do you mean? The only way I could find to search was using tbr actor object. In a perfect world this function would know which classes spell slot uas used to cast but I suspect that would involve a lot more under the hood.

misty valley
#

identifier is a property of a class item that defines the "key" for this class

#

subclasses link to their main class via this identifier

#

e.g. the "Wizard" class item in the srd has an identifier of wizard

turbid barn
#

Is there a simple way to query for an existing list of class keys from the console? It would be less cumbersome than building an npc of each class and testing manually.

misty valley
#

the identifiers are 100% arbitrary

#

as in, you can change them to be whatever, even the SRD classes

#

so you would instead define your arcane classes based on the class identifiers you are using

turbid barn
#

That would simplify. And then just use filter to see if key is in list.

turbid barn
misty valley
#

so that means somewhere in your code, you are accessing the system property of an undefined object (likely actor)

#

log out any variables using that system property and check for nulls

#

backtrack to figure out why its null

#

or do something like if (someVariable == undefined) console.log('Foo')

#

oh, there it is

  let testClass = (charClasses[key].name);
        /*if class in question grants spellcasting 
        and if we have a multiplier of >2 
        see if we have arcane caster*/ 
        if (testClass.system.spellcasting.prog
#

testClass is a string

#

strings dont have a system property

turbid barn
#

Heh. Just ran into that one and was waitingg for a foundry reload before posting as root cause (for fear that it isn't).

#

and found the problem, but not the solution. the only way I have found to query for character classes is actor._classes. when I try to do a .keys() on it I get an error. Is there another way to extract the class names/subclass data?

misty valley
#

dont dig into underscore variables

#

you can either filter the items collection, or maybe actor.itemTypes.class, maybe

#

here is some examples of item filtering

#

and a lot of the examples on that wiki use filter, map, reduce etc

turbid barn
#

so => is the command to search for items matching a type?

misty valley
#

No, that is syntax for arrow functions

#

Filter is the array function to use

#

You send it a function to evaluate against

turbid barn
#

May need to do a lot more tutorials to get fluent in this. I don't think arrows exist as a concept in python. ๐Ÿคฃ On upside I now have it at the point where I think I am one line of understanding short of it working.

#

Works fine until it passes final string to handler to evaluate...then things get a bit wonky.

misty valley
#

Making progress!!

#

But yeah, arrow functions are just shorthand for the more explicit async function etc etc. They have a few additional properties but are very handy. Highly recommend reading the MDN article on it

turbid barn
#

Getting 'logger.js:14 simbuls-wild-surges | ERROR | TypeError: roll.evaluate is not a function
at convertEval (DnDWildMagic.js:490:20)
at Object.commonSurgeHandler [as handler] (DnDWildMagic.js:497:32)
at async BrokenSurges (my-script.js:97:23)
at async DnDWildMagic._runHandler (DnDWildMagic.js:328:23)'

#

I suspect it is from passing it 1d20 +3 +2 in the form of j'''

#

let targetRoll = 10 + ${surgeData.spellLevel} * multiplier
/set up a surge roll/
let surgeRoll = 1d20 +${castingMod} +${prof}
console.log(prof);
console.log(castingMod)
console.log(targetRoll);
console.log(surgeRoll)
await ChatMessage.create({ content: ${surgeRoll} vs ${targetRoll} DC to cast spell});
let surgeResult = await WildMagic.templates.handler(actor, surgeData, targetRoll, surgeRoll)
return (surgeResult)

misty valley
#

I need to step away for a bit, but you can place break points in your code by opening up the dev tools in your browser. I would put a breakpoint right at the top of the function that's breaking and just stepping through it. Looking at each variable as you go. That should both help find the problem quickly. And give you a lot of context

turbid barn
#

Here is most recent version with breakpoints dropped in starting at line 94. I suspect the formatting for either targetRoll or surgeRoll is what is breaking it. Code for my matching is a bit fugly but that is a tomorrow problem.

misty valley
#

there it is, the console shows us, we just need to see what its saying

#

you see that TargetRoll output? and the SurgeRoll output?

#

TargetRoll is a number

#

not a string

#

look in your code where you are creating target roll and compare it to surgeroll

turbid barn
#

๐Ÿค” I was trying to figure out how to force SurgeRoll to be a nubmer as that is what I thought the module wanted. Ooops. It now runs.

#

Next step I figure out how to cancel spells and roll on wild magic table when surges occur.

#

Think I got a solution from past mesages in this gorup

misty valley
#

depends on how you want to cancel, but rolling on a given table is handled by a return value from one of the handlers

#

results.table

#

since you are using the template handler, you can modify its return value as well if you dont want to generate the whole thing yourself

turbid barn
#

Will have to take a look at this tomorrow or later tonight. Time to start a grill.

turbid barn
#

Thai style dish kind of night you know?

misty valley
#

gib

turbid barn
misty valley
#

shakes head i dont think that's needed

#

just take its normal return value and modify it to suit your needs

#

i.e. replacing the table uuid to indicate a table roll is needed

turbid barn
#

Ie I can put the uuid into the helper function directly?

misty valley
#

call the handler like you are, capture its return value, modify its return value

#

and return that

turbid barn
#

so something like if(surgeResult.surge)==true{ // update chat content to fit my needs}

misty valley
#

yea! thats the correct direction -- if you havent already, log out the return value from the template handler

#

it contains a bunch of information about what happened, and then you can inspect and modify as needed

turbid barn
#

already logged. Have a crude version working, just trying to streamline the chat .

misty valley
#

but lets fix that syntax if (!!surgeResult.surge)

#

just a little more compact and expressive

#

"if we have a non false result from surging"

turbid barn
#

Ah. So that is the js convention. And presumably for true if (surgeResult.surge)

misty valley
#

alskdjfopiasdjfopaisjdfas

#

weeeeeeeeeeeeeeeeeee

turbid barn
#

oops. meant if false (!surgeResult.surge)

#

Well that is done. Tomorrow I add reloads and potential misfires to firearms and finish off custom rule automation for the game world (at least for now)

misty valley
#

i hope you found the exercise worthwhile

#

was a pretty hard crash course in JS ๐Ÿ˜…

turbid barn
#

Definitely. Prior to this I had zero javascript experience. I still expect that most of what I do will focus more on Python, but never know when a new skill will prove useful at work.

misty valley
#

100% -- im finding nodejs scripts to be as easy...if not easier than throwing together a python script....

#

the package management environment alone is almost worth it

#

(npm)

proper crown
#

Hi everyone. What is the situation with Wild Magic Surge? Can somebody please tell me what works well for you?
Meanwhile, I send a PR with fix for Wild Magic Surge 5e.
Does anyone know how to reach JB#2780?

misty valley
proper crown
#

Oh. My bad. How well it works? What is the difference?

misty valley
# proper crown Oh. My bad. How well it works? What is the difference?

i dont have a ton of insight as to its current state (i wrote the original module and plugin system) with dnd5e 4.x, but i think the 2014 stock version of wild magic surge (no interaction with Tides of Chaos) should still mostly work -- but im sure there are issues here and there

#

so far so good, now define your targetRoll

#

i.e. what the d20 is compared against

#

it may just be spellLevel from the surgeData

hexed merlin
#

It is!

#

So just `const targetRoll = `${surgeData.spellLevel}`

misty valley
#

yep

#

good to go

#

almost done

#

so now, we have all the info that the stock handler needs (and you are basically doing a normal surge, just modified targets)

#

so next line is to call the stock handler:

let surgeResult = await WildMagic.templates.handler(actor, surgeData, targetRoll, surgeRoll);
hexed merlin
#

(I don't know how to do the formatting for coding on discord)

misty valley
#

```js
//code
```

#

yep, so far so good

hexed merlin
#
  /* surges on 1d20 <= spell level, reduced by number of charges */
  static async faeHandler(actor, surgeData) {

    /* increase the spell level by resource factor */
    const targetRoll = `${surgeData.spellLevel}`
    const surgeRoll = `1d20 - ${actor.data.data.resources.secondary.value}`
let surgeResult = await WildMagic.templates.handler(actor, surgeData, targetRoll, surgeRoll);
misty valley
#

missed a closing backtick on targetRoll

#
  /* surges on 1d20 <= spell level, reduced by number of charges */
  static async faeHandler(actor, surgeData) {

    /* increase the spell level by resource factor */
    const targetRoll = `${surgeData.spellLevel}`
    const surgeRoll = `1d20 - ${actor.data.data.resources.secondary.value}`
let surgeResult = await WildMagic.templates.handler(actor, surgeData, targetRoll, surgeRoll);
hexed merlin
#

Aye

misty valley
#

just checking the core code

hexed merlin
#

So input this into the world file and edit the special traits under the character?

misty valley
#

make sure its inside the "MyCoolClassName" class

#

but, last thing to do...

#

surgeResult.chatData.surgeOccured indicates if it surged

#

so check that result, and if true, we need to reset the resource counter

hexed merlin
#

And if false, add surgeData to resource counter

misty valley
#

precisely

#

surgeResult.actorUpdate is an update object that will be applied to the actor

#

so all you need to do is add in your update to that object for the resource

#

something like
setProperty(surgeResult.actorUpdate, 'data.resources.secondary.value', newValue)

#

then just return that surge result object and party!

hexed merlin
#

Where would that go? Sorry I'm a little lost

misty valley
#

after you call the template.handler function

hexed merlin
#

After return, then?

misty valley
#

if (surgeResult.chatData.surgeOccured)

#

not after return, we need to modify that surgeResult data before returning it

#
let surgeResult = ...
if (surgeResult.chatData.surgeOccured) {
 //
} else {
 //
}
return surgeResult
hexed merlin
#

newValue would be surgeData?

misty valley
#

newValue is whatever the new value for the secondary resource is now

#

you are telling the wild magic system what to change on the actor for this surge

hexed merlin
#

So data.resources.secondary.value + surgeData?

#

Adding the spell level to the pre-existing value?

misty valley
#

surgeData is an object

#

surgeData.spellLevel however, is a number ๐Ÿ™‚

#

you need to grab the previous value first

#

i.e. compute the full value, then use setProperty

hexed merlin
#

You're... speaking eldritch now, sorry

#

Like, I understand what I must do, but I have no idea how

misty valley
#

const newValue = actor.data.data.resources.secondary.value + surgeData.spellLevel

hexed merlin
#
  let surgeResult = await WildMagic.templates.handler(actor, surgeData, targetRoll, surgeRoll);
     if (surgeResult.chatData.surgeOccured) {
    //
    
    } else 
     const newValue = actor.data.data.resources.secondary.value + surgeData.spellLevel
     {setProperty(surgeResult.actorUpdate, 'data.resources.secondary.value', newValue)

       //
      }
      return surgeResult
   
  
  
  
  
    return WildMagic.templates.handler(actor, surgeData, targetRoll);
misty valley
#

the syntax there isnt quite right and you are returning twice ๐Ÿคฃ one sec

#
 let surgeResult = await WildMagic.templates.handler(actor, surgeData, targetRoll, surgeRoll);
 if (surgeResult.chatData.surgeOccured) {
    setProperty(surgeResult.actorUpdate, 'data.resources.secondary.value', 0)
 } else {
    const newValue = actor.data.data.resources.secondary.value + surgeData.spellLevel
    setProperty(surgeResult.actorUpdate, 'data.resources.secondary.value', newValue)
 }
 return surgeResult
#

forgive the formatting

hexed merlin
#

Bold of you to assume I can tell that it's bad

#

return surgeResult
I can include this in the final return together with the other properties (actor, surgeData, etc), right?

misty valley
#

you just need to return surgeResult from your handler

#

nothing else

hexed merlin
#
    /* surges on 1d20 <= spell level, reduced by number of charges */
    static async faeHandler(actor, surgeData) {
  
      /* increase the spell level by resource factor */
      const targetRoll = `${surgeData.spellLevel}`
      const surgeRoll = `1d20 - ${actor.data.data.resources.secondary.value}`
      let surgeResult = await WildMagic.templates.handler(actor, surgeData, targetRoll, surgeRoll);
      if (surgeResult.chatData.surgeOccured) {
     setProperty(surgeResult.actorUpdate, 'data.resources.secondary.value', 0)
     } else {
 const newValue = actor.data.data.resources.secondary.value + surgeData.spellLevel
 setProperty(surgeResult.actorUpdate, 'data.resources.secondary.value', newValue)
       }
       return surgeResult
misty valley
#

that looks right!

hexed merlin
#

Let's spin those wheels then

misty valley
#

now, only thing you need to do is substitute that in the register call

#

can you show me the register call you have now?

#

or just the whole script, actually

hexed merlin
#

I've co-opted the script you sent earlier so

misty valley
#

yep, just to make sure im looking at the right thing with all the changes

hexed merlin
#

It's tiny but it's too many words for my humble discordness

misty valley
#

delete the other 2 handler functions in there

#

and delete all the other registerHandler calls except yours

hexed merlin
#

Doney

misty valley
#

lets have a final look-see

hexed merlin
#
// This example greets players with an on-screen notification once Foundry
// has finished its initial loading
Hooks.on("ready", () => ui.notifications.notify("Welcome to the World!"));
class WildMagicSurge {


    static init() {
  
      /* When called on by the WildMagic utility, register our surge handlers and pre checks */
      Hooks.on('wmsRegister', () => {
  
        /* Using the core "is slot expended?" preCheck for all variants (default, 3rd argument) */
  
        /* use the core, default implementation for the PHB surge 1d20 == 1 */
        WildMagic.registerHandler(game.i18n.localize("option.wmOptions.standard"), WildMagic.templates.handler);
  
        /* use our modified inputs for the homebrew variants */
        WildMagic.registerHandler(game.i18n.localize("option.wmOptions.fae"), WildMagicSurge.faeHandler);
  
      });
    }
  
    /* surges on 1d20 <= spell level, reduced by number of charges */
    static async faeHandler(actor, surgeData) {
  
      /* increase the spell level by resource factor */
      const targetRoll = `${surgeData.spellLevel}`
      const surgeRoll = `1d20 - ${actor.data.data.resources.secondary.value}`
      let surgeResult = await WildMagic.templates.handler(actor, surgeData, targetRoll, surgeRoll);
      if (surgeResult.chatData.surgeOccured) {
     setProperty(surgeResult.actorUpdate, 'data.resources.secondary.value', 0)
     } else {
 const newValue = actor.data.data.resources.secondary.value + surgeData.spellLevel
 setProperty(surgeResult.actorUpdate, 'data.resources.secondary.value', newValue)
       }
       return surgeResult
 
   
  
  
  
  
    }
  }
  
  /* When the WildMagic utility is ready, we can use its helpers
   * and register ourselves */
  Hooks.on('helpersReady', WildMagicSurge.init)
#

Fits here now

misty valley
#

remove the standard register handler

#

and give this an actual string - game.i18n.localize("option.wmOptions.fae")

hexed merlin
#

Very clean of you

misty valley
#

because i dont have a translation string for that key

hexed merlin
#

What does giving a string mean

misty valley
#

that is the name of the handler that will show up in the special traits

#

so call it whatever it should be named like 'Fae Surges' or something

hexed merlin
#

WildMagic.registerHandler('My Handler', WildMagic.templates.handler);

#

So this

misty valley
#

that would call my template handler ๐Ÿ˜‰

#
      Hooks.on('wmsRegister', () => {
  
        /* Using the core "is slot expended?" preCheck for all variants (default, 3rd argument) */
        /* use our modified inputs for the homebrew variants */
        WildMagic.registerHandler('Fae Surges', WildMagicSurge.faeHandler);
  
      });
hexed merlin
#

Yes but adapted

#

Yeah!

misty valley
#

boom

#

save, reload world, watch console for errors and check out the special traits and cast a spell!

#

๐Ÿคž

hexed merlin
#

Nope, it do be borked

misty valley
#

fuuuu

#

can you copy the full script in here? i'll test it out

hexed merlin
misty valley
#

oh hmm

hexed merlin
#
// This example greets players with an on-screen notification once Foundry
// has finished its initial loading
Hooks.on("ready", () => ui.notifications.notify("Welcome to the World!"));
class WildMagicSurge {


    static init() {
  
      /* When called on by the WildMagic utility, register our surge handlers and pre checks */
      Hooks.on('wmsRegister', () => {
        /* use our modified inputs for the homebrew variants */
        WildMagic.registerHandler('Fae Surges', WildMagicSurge.faeHandler);

  
      });
    }
  
    /* surges on 1d20 <= spell level, reduced by number of charges */
    static async faeHandler(actor, surgeData) {
  
      /* increase the spell level by resource factor */
      const targetRoll = `${surgeData.spellLevel}`
      const surgeRoll = `1d20 - ${actor.data.data.resources.secondary.value}`
      let surgeResult = await WildMagic.templates.handler(actor, surgeData, targetRoll, surgeRoll);
      if (surgeResult.chatData.surgeOccured) {
     setProperty(surgeResult.actorUpdate, 'data.resources.secondary.value', 0)
     } else {
 const newValue = actor.data.data.resources.secondary.value + surgeData.spellLevel
 setProperty(surgeResult.actorUpdate, 'data.resources.secondary.value', newValue)
       }
       return surgeResult
 
   
  
  
  
  
    }
  }
  
  /* When the WildMagic utility is ready, we can use its helpers
   * and register ourselves */
  Hooks.on('helpersReady', WildMagicSurge.init)```
#

It's definitely the script, I think, because the other surges are working

misty valley
#

yea, its how we are setting the resource update

#

one moment

#

lets try this instead

#
      if (surgeResult.chatData.surgeOccured) {
     setProperty(surgeResult, 'actorUpdate.data.resources.secondary.value', 0)
     } else {
 const newValue = actor.data.data.resources.secondary.value + surgeData.spellLevel
 setProperty(surgeResult, 'actorUpdate.data.resources.secondary.value', newValue)
       }
#

moving the actorUpdate object into the set property field

#

(which is an oversight on my side, not providing an empty actorUpdate field)

hexed merlin
#

It's working for the roll itself

#

But not updating the resource field

#

It's not returning any errors though!

#

So to be entirely honest I don't wanna take up more of your time

misty valley
#

ok, lemme put this in on my side and see what's up, im sure the update isn't quite right

hexed merlin
#

As it is is way more than enough from what I thought I could achieve

misty valley
#

no no, im glad you are doing this -- ive been needing an example of use like this!

#

can you re-paste the full script you have?

hexed merlin
#
// This example greets players with an on-screen notification once Foundry
// has finished its initial loading
Hooks.on("ready", () => ui.notifications.notify("Welcome to the World!"));
class WildMagicSurge {


    static init() {
  
      /* When called on by the WildMagic utility, register our surge handlers and pre checks */
      Hooks.on('wmsRegister', () => {
        /* use our modified inputs for the homebrew variants */
        WildMagic.registerHandler('Fae Surges', WildMagicSurge.faeHandler);

  
      });
    }
  
    /* surges on 1d20 <= spell level, reduced by number of charges */
    static async faeHandler(actor, surgeData) {
  
      /* increase the spell level by resource factor */
      const targetRoll = `${surgeData.spellLevel}`
      const surgeRoll = `1d20 - ${actor.data.data.resources.secondary.value}`
      let surgeResult = await WildMagic.templates.handler(actor, surgeData, targetRoll, surgeRoll);
      if (surgeResult.chatData.surgeOccured) {
        setProperty(surgeResult, 'actorUpdate.data.resources.secondary.value', 0)
        } else {
    const newValue = actor.data.data.resources.secondary.value + surgeData.spellLevel
    setProperty(surgeResult, 'actorUpdate.data.resources.secondary.value', newValue)
          }
       return surgeResult
 
   
  
  
  
  
    }
  }
  
  /* When the WildMagic utility is ready, we can use its helpers
   * and register ourselves */
  Hooks.on('helpersReady', WildMagicSurge.init)
#

I think I found it

#

let surgeResult = await WildMagic.templates.handler(actor, surgeData, targetRoll, surgeRoll);

#

Should be WildMagicSurge.faeHandler

#

Right?

misty valley
#

shakes head

#

no, we are wrapping the core handler

#

im digging in, its stuff on my side

hexed merlin
#

The actorUpdate fields are missing a .data from the actual resource values?

misty valley
#

nah, they are intended for update, which sits inside the first data

#

its the "surgeOccured" field

#

looks like I dont....actually send that back, which is a bug on my side

#

i'll file an issue and get that fixed, but in the mean-time, we can be a bit tricky

hexed merlin
#

It's alright, the way it's working right now is well enough

#

And session is in 15 minutes >:D

#

So absolutely let me know when you figure that out though

misty valley
#
class WildMagicSurge {

  static init() {

    /* When called on by the WildMagic utility, register our surge handlers and pre checks */
    Hooks.on('wmsRegister', () => {
      /* use our modified inputs for the homebrew variants */
      WildMagic.registerHandler('Fae Surges', WildMagicSurge.faeHandler);
      ui.notifications.notify("Fae Surges Loaded!");
    });
  }

  /* surges on 1d20 <= spell level, reduced by number of charges */
  static async faeHandler(actor, surgeData) {

    /* increase the spell level by resource factor */
    const targetRoll = `${surgeData.spellLevel}`
    const surgeRoll = `1d20 - ${actor.data.data.resources.secondary.value}`
    let surgeResult = await WildMagic.templates.handler(actor, surgeData, targetRoll, surgeRoll);
    if (surgeResult.table) {
      setProperty(surgeResult, 'actorUpdates.data.resources.secondary.value', 0)
    } else {
      const newValue = actor.data.data.resources.secondary.value + surgeData.spellLevel
      setProperty(surgeResult, 'actorUpdates.data.resources.secondary.value', newValue)
    }
    return surgeResult

  }
}

/* When the WildMagic utility is ready, we can use its helpers
 * and register ourselves */
Hooks.on('helpersReady', WildMagicSurge.init)
#

there we go

#

all fixed up and working ๐Ÿ‘

#

this has given me a couple areas of improvement as well, so I appreciate the willingness to try this out โค๏ธ

hexed merlin
#

shocjked gasp

misty valley
#

33 lines for a custom surge implementation isn't too shabby ๐Ÿ˜Ž

hexed merlin
#

Fuck yes it's working perfectly

#

Thank you so much

#

๐Ÿ˜ญ

misty valley
#

๐Ÿฅณ