Roll20 uses cookies to improve your experience on our site. Cookies enable you to enjoy certain features, social sharing functionality, and tailor message and display ads to your interests on our site and others. They also help us understand how our site is being used. By continuing to use our site, you consent to our use of cookies. Update your cookie preferences .
×
Create a free account

Magic Missile Macro: Help!

1401816164

Edited 1401816394
The idea is to do the work up front to provide sleek macros that don't clutter the window with too much text (using inline boxes for popups for extra info) and that easily level up with the character. MM: each missile does 1d4+1 force dmg, 2 missiles at lvl 3, 3 at 5, 4 at 7, and 5 at 9. Character in question is currently lvl 6 ( goal =3d4+3 , not 3(1d4+1)) My attempts so far: [[1d4+1]] - gives us one missile [[ floor((@{level}+1)/2) ]] gives 3, the correct number of missiles. If I change the level anywhere between 1 and 9, it continues to give the correct number. Without using "floor" I get screwy numbers (+/-0.5) at even levels. [[ floor(( @{level}+1)/2)*(1d4+1) ]] gives me 3(1d4+1) which is close, but rolls one number for all missiles, and multiplies by three for a total. [[ floor(( @{level}+1)/2)d4+1 ]] give an error. [[1d4+floor(@{level}+1)/2]] gives 1d4+3, good, we want a +3 on the end. [[ floor(( @{level}+1)/2)*(1d4+floor(@{level}+1)/2) ]] gives 3*(1d4+3) [[ floor(( @{level}+1)/2)d4+floor(@{level}+1)/2 ]] gives an error: Could not determine result type of: [{"type":"M","expr":"floor((5+1)/2)"},{"type":"C","text":"d4+floor(5+1)/2"}] And that is where I'm stuck. I could always just do it the easy way: 1st [[1d4+1]] 2nd [[1d4+1]] 3rd [[1d4+1]], but I want to have a working template for spells that will automatically adjust as the @{level} attribute goes up. It would also be nice to have a function that caps the answer at 5 for the function that uses level to determine the number of missiles.
1401817320

Edited 1401817478
(floor((@{level} /2) +1)) The other problem I see you running into is targeting up to 5 targets, all needing to be with in 15ft of each other. Sounds like API work.
1401817786

Edited 1401818876
So if I try (floor((@{level} /2) +1))d4+(floor((@{level} /2) +1)), then I get "Could not determine result type of: [{"type":"M","expr":"(floor((5/2)+1))"},{"type":"C","text":"d4+(floor((5 /2) +1))"}]" Also - (floor((@{level} /2) +1)) is not giving the right numbers. A level 4 character is getting N=3, when it should be 2. My original: floor(( @{level}+1)/2), is giving the correct number all the time.
Also, I'm not worried about selecting different targets. That's work for later, and yes I realize not something for a macro alone.
I figured it out. I just had to break it apart into separate inline boxes. Here's what worked: /roll [[floor((@{level}+1)/2)]]d4+[[floor((@{level}+1)/2)]]
1401819316

Edited 1401819326
Lithl
Pro
Sheet Author
API Scripter
You can't really have a variable number of dice like this inline. However, if you're dealing with a finite number of possibilities, you do have another option. If your missiles are capping out at five (as they do in 3.5 RAW), you could do: [[{floor(@{level}/9),1}kl1*1d4 + {floor(@{level}/7),1}kl1*1d4 + {floor(@{level}/5),1}kl1*1d4 + {floor(@{level}/3),1}kl1*1d4 + 1d4 + floor((@{level}+1)/2)]] At level 6, the roll breaks down like this: [[{floor(6/9),1}kl1*1d4 + {floor(6/7),1}kl1*1d4 + {floor(6/5),1}kl1*1d4 + {floor(6/3),1}kl1*1d4 + 1d4 + floor((6+1)/2)]] [[{0,1}kl1*1d4 + {0,1}kl1*1d4 + {1,1}kl1*1d4 + {2,1}kl1*1d4 + 1d4 + 3]] [[0*1d4 + 0*1d4 + 1*1d4 + 1*1d4 + 1d4 + 3]] [[0 + 0 + 1d4 + 1d4 + 1d4 + 3]] [[3d4 + 3]] If you use the 3D dice, this solution will always roll 5d4 onto the tabletop, but two of them will be ignored in the final result at level 6.
So now I just need to figure out how to cap N at 5 in the equation Nd4+N.
Brian, it took me a few minutes, but I finally figured out what your macro does. I like it. Thank you!
The one issue is you still have floor((@{level}+1)/2 at the end. That means it will give the correct Nd4, and even cap at level 9, but the second N continues to increase after lvl 9. So close!
1401821496
Lithl
Pro
Sheet Author
API Scripter
{floor((@{level}+1)/2),5}kl1
1401823052

Edited 1401823512
I can't find info in the wiki about what the comma does (like the one you have just before the 5) **EDIT** nevermind, I figured it out by trying it out in roll20. It basically says choose between N and 5, keep the lowest and use that. With that I could rework the whole macro.
1401823596
Lithl
Pro
Sheet Author
API Scripter
{a,b,c,d} is a grouping; kl1 is "keep low: 1", which will keep the 1 lowest result from the group. With a grouping of { floor((@{level}+1)/2), 5 }, you'll either get the level+1/2 calculation, or 5, which ever is lower. At level 9 and 10, that ends up as 5 either way, but at level 11, the level calculation goes up to 6, while 5 remains... 5. 5 < 6, so kl1 picks the 5.
1401823620

Edited 1401823836
So I believe I should be able to shorten the whole thing to this: /roll [[ {floor((@{level}+1)/2),5}kl1 ]]d4+[[{floor((@{level}+1)/2),5}kl1]] **EDIT** Yes, testing confirms that it works. Thank you very much Brian for your insights and help.
1401823830
Lithl
Pro
Sheet Author
API Scripter
That should work, yes, although it's not fully inlined. You'd have to use something like my first post if you want the whole thing inline, just showing a single yellow box. The /roll [[...]]d4+... won't roll extra 3D dice, though, while my solution will, if you care about that. Also, you shouldn't need the inline brackets around the last part. /roll [[mumble]]d4+mumble should be fine.
Yes, your version would keep it fully inlined. I realize looking at it like that though that it is a bit of an eye full for a GM to try to figure out what's going on looking at the popup. Depends on the GM and how sleek you want the finished version looking
This is slightly off-topic, but, is there a way to animate or use particle effects for magic. There is an effects section in GM mode, but its all fire effects, and I don't know if these can be manipulated in the API.
1401845924
Lithl
Pro
Sheet Author
API Scripter
I don't believe you can utilize the FX system from the API. However, you could create particle effects with graphics and JavaScript timers. (setInterval, setTimeout, and clearInterval)
How do you do "animation" though? Is there a way to get the XY of token and have the api plot a course too the coordinates from the caster? I don't need fancy and flashy effects, but doing a lightbolt or magic missiles going across the screen would be neat.
1401894935
Lithl
Pro
Sheet Author
API Scripter
Sure; token.get('top') and token.get('left') will give you a token's position. You can also use token.set('rotation', ...) to make sure your bolt is facing the right direction. I know someone has previously written a script to launch arrows from one token to another. Aki J also recently posted a script to make tokens bleed.
Ah nice.
This is highly off topic, and therefore I won't post more on this matter here. If this discussion spawns a thread of its own, please direct me there :) Michael P. & Brian || animating movement of a token: Something like this? It's pseudo-ish code written in stream of thought manner, so don't just copy-paste it, though! There most probably is a sign error and/or a phase error there. If you ( any you) make a working move-function, let me know. I may have use for one :) /** * Call this to make a token move towards a given target point with a desired velocity. * Velocity is given as pixels per second, and updateInterval is given as milliseconds. * WARNING! Choose as high updateInterval as you can, because this function utilizes expensive Math functions, such as atan2 and sqrt. Give the poor CPU a breather, won't ya! */ function startMovingTokenTowardsPoint(tokenId, targetTop, targetLeft, velocity, updateInterval) { var top, left, token = getObj("graphic", tokenId), angle, distance, distanceToTravel, shouldStop = false; top = token.get("top"); left = token.get("left"); angle = Math.atan2(targetTop - top, targetLeft - left); distance = Math.sqrt(Math.pow(targetTop - top,2) + Math.pow(targetLeft - left,2)); distanceToTravel = velocity * updateInterval / 1000; if(distanceToTravel >= distance) { shouldStop = true; distanceToTravel = distance; } token.set({ top: top + distanceToTravel * Math.sin(angle), left: left + distanceToTravel * Math.cos(angle), angle: angle * 180 / Math.PI }); if(!shouldStop) { setTimeOut(function() { startMovingTokenTowardsPoint(tokenId, targetTop, targetLeft, velocity, updateInterval); }, updateInterval); } }