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

A script that calculates hypotenuses

Suppose I have two wizards flying through the air casting spells at one another, I've assigned them z-axes by putting a number within the blue bar of their tokens. Now, given these two numbers and the x and y coordinates of those tokens on the grid, is there a script that calculates the hypotenuse of the distance between them automatically that is compatable with pathfinder, 5e, Manhattan and euclidean measurement systems? It would speed my games 3.5 aerial combat immensely! Thanks!
1678695321

Edited 1678695379
GiGs
Pro
Sheet Author
API Scripter
You don't need a script. You can do this with a macro. This will give you a result rounded to hundredths. /roll round(((?{x|0}**2 + ?{y|0}**2)**0.5)*100)/100 If you want it rounded to nearest whole number, its a bit simpler: /roll round((?{x|0}**2 + ?{y|0}**2)**0.5) These will prompt for x and y; you can change those labels. using ** is the way to raise to a power in Roll20. I don't know what you need to do to make it compatible with those systems, since I don't play those systems - this is just the standard geometry.
1678716178
keithcurtis
Forum Champion
Marketplace Creator
API Scripter
Not sure about pathfinder, but the formula GiGs gave you is Euclidean. For 5e, it's super simple. 5e counts a diagonal as 1, same as an orthoganal. Just take the greatest of the three numbers and that's your range. In any case, no one formula will work for all geometry systems. They are mathematically incompatible.
1678725470
timmaugh
Pro
API Scripter
I've been meaning to write a metascript plugin that would calculate range for you (right in the command line of another script), however you can do it with existing metascript tools. The equation is a bit more than what GiGs shared, at least for Euclidean, since you'd first have to determine the distance along the ground between the tokens (solving one pythagorean formula), before you could use that and the difference in altitudes between the 2 tokens for a second pythagorean formula. Here's how to do that... You can get all the values you need using Fetch... like the blue markers: @(selected.status.blue?all) ...or the tops: @(selected.top) ...etc. Now, since we'll be figuring between two tokens, we'll probably need to target one of them, meaning that we won't have our typical array of "selected" tokens (a quirk of Roll20 message construction). So we'll use a ZeroFrame {&global} structure to just tag our selected and targeted token ids so that we can use them throughout the macro. Here is a proof of concept that will kick out a roll template with the information tagged and organized for you to see it working: !&{template:default}{{name=Range Test}}{{Lefts=@(seltoken.left) - @(tartoken.left) = [\][\]@(seltoken.left)-@(tartoken.left)\]\]}}{{Tops=@(seltoken.top) - @(tartoken.top) = [\][\]@(seltoken.top)-@(tartoken.top)\]\]}}{{Ground Distance=grdDistance}}{{Altitude Difference=altDiff}}{{Actual Distance=[\\][\\]round((grdDistance**2 + altDiff**2)**0.5)\\]\\]}}{&simple}{&global ([seltoken]@{selected|token_id})([tartoken]@{target|Target|token_id})}{\&global ([grdDistance] [\][\]round(((@(seltoken.left)-@(tartoken.left))**2 + (@(seltoken.top)-@(tartoken.top))**2)**0.5)\]\]) ([altDiff] [\][\]@(seltoken.status.blue?all[0])-@(tartoken.status.blue?all[0])\]\])} REQUIRED SCRIPTS:  ZeroFrame (pending 1-click release this week), Fetch (pending 1-click release this week) Now, if you only wanted the range as a number (rather than all the template information), that would be this: {&global ([seltoken]@{selected|token_id})([tartoken]@{target|Target|token_id})}{\\&global ([figuredRange] [\\][\\]round(([\][\]round(((@(seltoken.left)-@(tartoken.left))**2 + (@(seltoken.top)-@(tartoken.top))**2)**0.5)\]\].value**2 + [\][\]@(seltoken.status.blue?all[0])-@(tartoken.status.blue?all[0])\]\].value**2)**0.5)\\]\\].value)} That could be further simplified by not requiring the first {&global} , and just using @{selected|token_id} in the place of every seltoken in the second {&global} structure, and using @{target|Target|token_id} in the place of every tartoken . But I find this version more readable. The end result of this is that you have defined the term figuredRange to be equal to the range between 2 tokens where you are using the blue markers for altitude. Now you could drop that term in another script's command line. For instance, if you wanted to write the distance between two tokens into bar1 for your selected token... setting bar1 to a value would typically look like this: !token-mod --set bar1|figuredRange So now we make two changes. We add the above syntax for defining figuredRange (so that it is defined in this message), and then, since that will introduce a targeting statement and we won't have a selected token for TokenMod to act upon, we'll add either the TokenMod --ids argument, or a SelectManager {&select} statement... either one referencing the id of the selected token. Here is what that line becomes using the TokenMod argument: !token-mod --set bar1|figuredRange --ids|seltoken  {&global ([seltoken]@{selected|token_id})([tartoken]@{target|Target|token_id})}{\\&global ([figuredRange] [\\][\\]round(([\][\]round(((@(seltoken.left)-@(tartoken.left))**2 + (@(seltoken.top)-@(tartoken.top))**2)**0.5)\]\].value**2 + [\][\]@(seltoken.status.blue?all[0])-@(tartoken.status.blue?all[0])\]\].value**2)**0.5)\\]\\].value)} (If a player wants to run that command, TokenMod will need to be configured to have the players-can-ids option turned on.)
Here's the macro I use (it's pretty much the same as GiGs', but rounding to the tenth place, and with an output that shows the inputs: ?{Whisper|Yes,/w gm |No, }$[[0.computed]]² + $[[2.computed]]² = [[ round([[ [[[[?{A}]]**2]] + [[[[?{B}]]**2]] ]]**0.5*10)/10 ]]² For two creatures flying in the air, you can just use the Measure tool to get the distance in grid squares between them, and subtract their heights from each other and plug those numbers into the macro queries. The thing I also realized is that most of the time, when you're calculating the hypotenuse for these situations, rounding up the larger of two numbers is usually close enough for speeding up combat.  If the two numbers are close or equal, that's when the hypotenuse will be a bit larger, but if the two numbers are very different the hypotenuse is usually very close to the larger. As KeithCurtis says, D&D 5th Edition uses a simplified square geometry.  Pathfinder uses a 5/10 alternating diagonal geometry.  I'm not sure what 3.5E uses.  They're all different than a pure euclidian geometry, but in combat it's worthwhile to just use the method that is easiest and fastest for your table. 
1678730995
GiGs
Pro
Sheet Author
API Scripter
I like your approach, Jarren. I've noticed that about the hypotenuse - most times you can just approximate to the largest dimension. If absolute accuracy isn't important, you can use that. Tim's method looks great, but is probably a bit overkill because of this. But I'm sure there are games where it's the better approach.
1678854050
vÍnce
Pro
Sheet Author
Just sharing &{template:default}{{name=Distance to Target}}{{Height of Target:=[[?{Height of Target (ft)?|0}]]ft}}{{Distance to Target:=[[?{Horizontal Distance to Target (ft)?|0}]]ft}}{{Total Distance to Target:=[[round([[?{Height of Target (ft)?}*?{Height of Target (ft)?} + ?{Horizontal Distance to Target (ft)?}*?{Horizontal Distance to Target (ft)?}]]**0.5)]]ft}}
1678859366

Edited 1678859488
Thanks for all the tips and pointers everyone. I'll try each and see what works best in my circumstance. Thanks again! By the way, D&D 3.5's diagonals work like Pathfinders, at least according to the page settings in Roll20.