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

!measure change help

Hi. I have been looking at !measure and was wondering if anyone could tell me how to change the code so the result of the !measure would result in a value that could be used in a macro or powercard. 
1654863624
The Aaron
Roll20 Production Team
API Scripter
You might be able to accomplish this with Tim's Metascripts. 
1654867239
timmaugh
Pro
API Scripter
Yep, we should be able to make that happen with some minor tweaks. Short of rewriting it as a full metascript, we can give it the right checks to tie it in to the Plugger mechanic where we can issue an embedded command to measure and have it return a value to the housing macro. Converting/building a script to work with Plugger is discussed at this link . Just to make sure we're talking about the same script, this is the one I'll be looking at: <a href="https://github.com/Roll20/roll20-api-scripts/tree/master/Measure" rel="nofollow">https://github.com/Roll20/roll20-api-scripts/tree/master/Measure</a> If that isn't correct, please point me at the correct code.
That is the correct script. timmaugh said: Yep, we should be able to make that happen with some minor tweaks. Short of rewriting it as a full metascript, we can give it the right checks to tie it in to the Plugger mechanic where we can issue an embedded command to measure and have it return a value to the housing macro. Converting/building a script to work with Plugger is discussed at this link . Just to make sure we're talking about the same script, this is the one I'll be looking at: <a href="https://github.com/Roll20/roll20-api-scripts/tree/master/Measure" rel="nofollow">https://github.com/Roll20/roll20-api-scripts/tree/master/Measure</a> If that isn't correct, please point me at the correct code.
1655226604
timmaugh
Pro
API Scripter
OK, it only took a total of 9 lines of code. And a few moments of me being an idiot. Here is the new version that will work as a Plugger plug-in to return a value from the script. I will leave it to Aaron whether or not he wants to incorporate this into his regular upkeep/re-release of the script. Note, to make this useful to you as a meta-return (getting information that you can use in another script), the script can only return 1 data point at a time. In effect, it returns the distance between the first 2 things it sees between the set of tokens selected and the token IDs included on the command line. If you have 2 things selected and 3 tokens in the command line, it will return only a single value -- not rows and rows. That means make sure you have explicit references to your tokens to make sure you're getting the correct data in return. To use this in its most basic form, you'd need Plugger, too. Then, to build/use your Plugger line... 1) wrap everything in {&amp;eval} &nbsp;and {&amp;/eval} tags 2) drop the exclamation point before measure 3) enclose all of measure's arguments in parentheses For example, with 2 tokens selected, you would only need: {&amp;eval}measure(){&amp;/eval} With one token selected you would have to explicitly reference one: {&amp;eval}measure(@{mook|token_id}){&amp;/eval} If you want to do targeting, you lose your selected tokens (a limitation of Roll20, not metascripts), so you either have to target start &amp; finish tokens, or include your selected token's id in the command: {&amp;eval}measure(@{selected|token_id} @{target|Target 1|token_id}){&amp;/eval} All of those are the same requirements of the script as originally existed; I just wanted to show how to translate them into the Plugger syntax. 4) put that statement in the macro command line for your OTHER script. The command line must start with an exclamation point to trigger the API. Make sure the Plugger statement is in the spot where the distance value should be returned. For instance: !AttackThat --range|{&amp;eval}measure(@{selected|token_id} @{target|Target 1|token_id}){&amp;/eval} By the time the AttackThat script sees the command line, Plugger will have returned a value, so the line will now read: !AttackThat --range|22 Other Metascript Interactions Simple Message with ZeroFrame Once you have the output of the distance, you can drop a normal chat message out with ZeroFrame, allowing you to build a template output: !&amp;{template:default}{{name=Distance from @{selected|token_name} to 2 Targets}}{{@{target|Target 1|token_name}={&amp;eval}measure(@{selected|token_id} @{target|Target 1|token_id}){&amp;/eval} }}{{@{target|Target 2|token_name}={&amp;eval}measure(@{selected|token_id} @{target|Target 2|token_id}){&amp;/eval} }}{&amp;simple} Yes, this begins to just return the same chat output of the script originally, but you can combine it with the methods, below, to do more with the returned numbers because you have them "in context" at the moment you're building your output. Deferred Inline Roll with ZeroFrame If you want the value returned to be used in an inline roll, you have to "hide" the inline roll. Roll20 will try to parse the inline roll the first time it sees it, but that's before the API (Plugger) has had a chance to return the value you need. To defer a roll, use ZeroFrame and include backslashes (and brackets) to denote "cycles" for deferring a roll. An inline roll deferred one pass (to allow Plugger to return a value) would look like: [\][\] ...roll equation here... \]\] In practice, this could be a to-hit number: [\][\]{1d20+@{selected|AttackSkill}}&gt;{&amp;eval}measure(@{selected|token_id} @{target|Target 1|token_id}){&amp;/eval} \]\] ...or some other math operation. Code // Github: <a href="https://github.com/shdwjk/Roll20API/blob/master/Measure/Measure.js" rel="nofollow">https://github.com/shdwjk/Roll20API/blob/master/Measure/Measure.js</a> // By: The Aaron, Arcane Scriptomancer // Contact: <a href="https://app.roll20.net/users/104025/the-aaron" rel="nofollow">https://app.roll20.net/users/104025/the-aaron</a> var Measure = Measure || (function () { 'use strict'; var version = '0.3.3', lastUpdate = 1530335089, checkInstall = function () { log('-=&gt; Measure v' + version + ' &lt;=- [' + (new Date(lastUpdate * 1000)) + ']'); }, handleInput = function (msg) { var args, pageid, page, measurements, whisper = false, who; if (msg.type !== "api") { return; } args = msg.content.split(/\s+/); switch (args.shift()) { case '!wmeasure': whisper = true; who = (getObj('player', msg.playerid) || { get: () =&gt; 'API' }).get('_displayname'); // break; // Intentional fall through case '!measure': measurements = _.chain(_.union(args, _.pluck(msg.selected, '_id'))) .uniq() .map(function (t) { return getObj('graphic', t); }) .reject(_.isUndefined) .map(function (t) { pageid = t.get('pageid'); return { name: t.get('name') || "Token @ " + Math.round(t.get('left') / 70) + ',' + Math.round(t.get('top') / 70), x: t.get('left'), y: t.get('top') }; }) .reduce(function (m, t, k, l) { _.each(_.rest(l, k + 1), function (t2) { m.push({ name1: t.name, name2: t2.name, distance: (Math.sqrt(Math.pow((t.x - t2.x), 2) + Math.pow((t.y - t2.y), 2)) / 70) }); }); return m; }, []) .value() ; page = getObj('page', pageid); if (page) { if (msg.eval) { return measurements.length ? Math.round(page.get('scale_number') * measurements[0].distance, 2) : 0; } _.chain(measurements) .reduce(function (m, e) { var d = Math.round(page.get('scale_number') * e.distance, 2); m.push("&lt;li&gt;" + e.name1 + " to " + e.name2 + ": &lt;b&gt;" + d + " " + page.get('scale_units') + "&lt;/b&gt;&lt;/li&gt;"); return m; }, []) .join('') .tap(function (o) { sendChat('Measure', (whisper ? '/w "' + who + '"' : '/direct') + ' &lt;div&gt;&lt;b&gt;Measurements:&lt;/b&gt;&lt;ul&gt;' + o + '&lt;/ul&gt;&lt;/div&gt;'); }); } break; } }, measure = function (m) { return handleInput(m); }, registerEventHandlers = function () { on('chat:message', handleInput); try { Plugger.RegisterRule(measure); } catch (error) { log(error); } }; return { CheckInstall: checkInstall, RegisterEventHandlers: registerEventHandlers, }; }()); on('ready', function () { 'use strict'; Measure.CheckInstall(); Measure.RegisterEventHandlers(); });