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 .
×
Advertisement Create a free account

[Script] APILogic - Gives If/ElseIf/Else Processing to Other Scripts

1612407840

Edited 1615298981
timmaugh
Pro
API Scripter
APILogic File Location:   APILogic.js  (submitted to the one-click, but until then, find it in my personal repo) Script Dependency:   libInline.js  (also submitted to the one-click) Wiki Article: APILogic APILogic introduces logical structures (things like IF, ELSEIF, and ELSE) as well as real-time inline math operations, and variable muling to Roll20 command lines. It can test sets of conditions and, depending on the result, include or exclude parts of the command line that actually reaches the chat processor. For example, given the statement: !somescript {& if a = a} true stuff {& else} default stuff {& end} …results in the following reaching the chat: !somescript true stuff APILogic exploits a peculiarity of the way many of the scripts reach the chat interface (a peculiarity first discovered by – who else? – The Aaron) to give it the ability to intercept the chat message  before  it reaches other scripts, no matter if it is installed before or after them in the script library. It also uses a separate bit of script magic to let it retain ownership of the message even when otherwise asynchronous chat calls would be going. That means you can use IF structures to conditionally include or exclude parts of your command line, you can use MATH structures to perform real-time math operations on your data, you can store and recall variables for this or later calls, and all of this shaping the command line BEFORE the other script ever sees it. Caveat:  The method APILogic utilizes has been tested and shown to work with a large number of scripts. If you find that it doesn’t, you should be reminded that the most foolproof way to ensure proper timing of script execution is to load APILogic in your script library before the other script. But hopefully you’ll find that you don’t need to do that!) Also, although it requires the API, it is not only for API messages. You can use these logic structures with basic chat messages, too. This document will show you how. Credits:  Many thanks to The Aaron for lending his expertise on questions I had, and to the other members of the House of Mod for sounding out and working through ideas. Instructions for Use (Wiki Article) Though it is easy to use APILogic, the sheer scope of what you can do with it has necessitated that the instructions are stored on the wiki for easy reference. I will keep this article updated as new features are released. Development Path: Numeric Ranges as Mule Variable Names (i.e., 1-10) Including token items as conditions SWITCH/CASE tag MAX/MIN tag - Levenshtein Distance for approximate names Other special tests for sheet items - EVAL tag Change Log: Version 1.0.0 - Initial Release Version 1.0.1 ( link ) - minor bug fix related to inline table resolution Version 1.1.0 ( link ) - changed special tests for sheet items to be int and max instead of i and m ; changed DEFINE tags to evaluate sheet items; added the ability to return the name of a sheet item Version 1.1.1 ( link ) - Minor bug fix, added rowname and row returns for repeating items Version 1.1.2 ( link ) - Bug fix in the logic engine where numeric conditions were not always properly detected Version 1.1.3 ( link ) - Bug fix where inline rolls in a condition were not accessed correctly Version 1.2.0 ( link ) - added EVAL tag; added rule registration for scriptlet plugins; added row and rowname as retrievable things for repeating sheet items; added MATH tag for inline math calculations; added MULE tag (and get/set language) to handle variable storage
1612417496

Edited 1612417580
Well you'd been quiet for a while, I figured you were cooking something interesting up. Very cool. Are those blank errors at the start and end a new thing? That's a fiendishly clever idea (I'm assuming this offset gives you an accurate line number for errors... or does it do other stuff too?)  edit - this also vaguely translates as "I'm stealing that idea"
1612417615
Victor B.
Pro
Sheet Author
API Scripter
This is in a char sheet/roll template?  Changes the game.  Only limitation is requires Pro user, but yes otherwise.  
1612444691

Edited 1612444729
Amazing - a whole bunch of fundamental limitations just went away! I especially like that it is retrofittable to existing content where we've had to live with such limitations for so long... Congratulations and thank you.
1612447806

Edited 1612448040
timmaugh
Pro
API Scripter
Oosh said: Well you'd been quiet for a while, I figured you were cooking something interesting up. Very cool. I've had my hands full, for sure! It was definitely a snowsuit-sort of programming problem: you know, where a kid takes so long getting dressed to go out into the snow that by the time they have their snowsuit on they have to use the restroom? I found the reverse was true: once I had donned all my programming layers and really reacclimated to where this project stood, it was difficult to imagine taking all of that off again and tackling something on the forum. Sorry! Oosh  said: Are those blank errors at the start and end a new thing? That's a fiendishly clever idea (I'm assuming this offset gives you an accurate line number for errors... or does it do other stuff too?)  edit - this also vaguely translates as "I'm stealing that idea" Please do! But, really, I stole it from Aaron, so by the Transitory Property of Intellectual Absconsion I'm pretty sure you're in the clear over any guilt (or maybe I am because you re-steal it?). Heck, courts in at least 2 Canadian provinces would call it your original work. On a serious note, yes, those render line numbers for troubleshooting. In the first line, you have to subtract the line number of where the empty error is thrown to arrive at the right offset (I subtract 13 because it's on line 13). I also report that value in my "ready" statement so I know where to find it. I think Aaron has a way to float the actual line number up at the time an actual error would be encountered in a script, but I haven't managed to steal that bit, yet. =D Me, when Aaron notices I've done something cool in code: @Victor - I haven't done anything in a character sheet, but a roll template would work. You just have to defer the detection of the roll template until you are ready for it to be parsed (for instance, confirming some conditions are met).
1612448235
Victor B.
Pro
Sheet Author
API Scripter
If you can copy and actually understand TheAaron's code, then I shall title thee Grand Absconsionist and announce a holiday in your name.    
1612448918

Edited 1612448936
The Aaron
Forum Champion
API Scripter
HAHAHAHAHAHA.&nbsp; That API_Meta stuff is something I've started adding to my scripts.&nbsp; It basically consists of 3 parts: Header /* 3 lines omitted */ var API_Meta = API_Meta||{}; API_Meta.NAME={offset:Number.MAX_SAFE_INTEGER,lineCount:-1}; {try{throw new Error('');}catch(e){API_Meta.NAME.offset=(parseInt(e.stack.split(/\n/)[1].replace(/^.*:(\d+):.*$/,'$1'),10)-6);}} Body /* somewhere in the script, storing useful data */ API_Meta.NAME.version = version; Footer /* last line of the file */ {try{throw new Error('');}catch(e){API_Meta.NAME.lineCount=(parseInt(e.stack.split(/\n/)[1].replace(/^.*:(\d+):.*$/,'$1'),10)-API_Meta.NAME.offset);}} As Tim explains, in the header I grab the line number from the callstack in the thrown/caught exception and subtract the known line offset to get exactly the start of the script.&nbsp; In the footer, I do the same and subtract the start offset to get the length of the script.&nbsp; In the body, I collect some useful things, like version number.&nbsp; It stores in a global variable named API_Meta, which can then be accessed by everyone to try and track down where errors are in a callstack: { "AaronDebug": { "offset": 0, "lineCount": 864, "version": "0.1.1" }, "APIVariables": { "offset": 864, "lineCount": 273 }, "TokenMod": { "offset": 1137, "lineCount": 3614, "version": "0.8.63" }, "UniversalVTTImporter": { "offset": 5989, "lineCount": 675, "version": "0.1.5" }, "UDLWindows": { "offset": 7639, "lineCount": 304, "version": "0.1.1" }, "libTokenMarkers": { "offset": 16730, "lineCount": 175, "version": "0.1.1" }, "FateDots": { "offset": 16905, "lineCount": 227, "version": "0.2.2" }, "InitiativeAssistant": { "offset": 17132, "lineCount": 353, "version": "0.1.5" }, "Emas": { "offset": 17485, "lineCount": 217, "version": "0.8.4" }, "BounceTokens": { "offset": 17702, "lineCount": 210, "version": "0.1.3" } } This is actually a refinement on what I've been using in TokenMod for quite a while.&nbsp; If you've used TokenMod and gotten a box in chat asking you to send me a message, here's the code that's generating that: } catch (e) { let who=(getObj('player',msg_orig.playerid)||{get:()=&gt;'API'}).get('_displayname'); sendChat('TokenMod',`/w "${who}" `+ `&lt;div style="border:1px solid black; background-color: #ffeeee; padding: .2em; border-radius:.4em;" &gt;`+ `&lt;div&gt;There was an error while trying to run your command:&lt;/div&gt;`+ `&lt;div style="margin: .1em 1em 1em 1em;"&gt;&lt;code&gt;${msg_orig.content}&lt;/code&gt;&lt;/div&gt;`+ `&lt;div&gt;Please &lt;a class="showtip tipsy" title="The Aaron's profile on Roll20." style="color:blue; text-decoration: underline;" href="<a href="https://app.roll20.net/users/104025/the-aaron&quot;&gt;send" rel="nofollow">https://app.roll20.net/users/104025/the-aaron"&gt;send</a> me this information&lt;/a&gt; so I can make sure this doesn't happen again (triple click for easy select in most browsers.):&lt;/div&gt;`+ `&lt;div style="font-size: .6em; line-height: 1em;margin:.1em .1em .1em 1em; padding: .1em .3em; color: #666666; border: 1px solid #999999; border-radius: .2em; background-color: white;"&gt;`+ JSON.stringify({msg: msg_orig, version:version, stack: e.stack, API_Meta})+ `&lt;/div&gt;`+ `&lt;/div&gt;` ); } And you can see it passing the API_Meta object as something to encode.&nbsp; At some point, I might write a callstack analyzer that would use API_Meta to decode a callstack automatically, but even before doing that it's pretty useful. Here's my current new script template, with those lines in it: // Github: <a href="https://github.com/shdwjk/Roll20API/blob/master/NAME/NAME.js" rel="nofollow">https://github.com/shdwjk/Roll20API/blob/master/NAME/NAME.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 API_Meta = API_Meta||{}; API_Meta.NAME={offset:Number.MAX_SAFE_INTEGER,lineCount:-1}; {try{throw new Error('');}catch(e){API_Meta.NAME.offset=(parseInt(e.stack.split(/\n/)[1].replace(/^.*:(\d+):.*$/,'$1'),10)-6);}} const NAME = (() =&gt; { // eslint-disable-line no-unused-vars const scriptName = 'NAME'; const version = '0.1.0'; API_Meta.NAME.version = version; const lastUpdate = 1609291956; const schemaVersion = 0.1; const checkInstall = () =&gt; { log(`-=&gt; ${scriptName} v${version} &lt;=- [${new Date(lastUpdate*1000)}]`); if( ! state.hasOwnProperty(scriptName) || state[scriptName].version !== schemaVersion) { log(` &gt; Updating Schema to v${schemaVersion} &lt;`); switch(state[scriptName] &amp;&amp; state[scriptName].version) { case 0.1: /* break; // intentional dropthrough */ /* falls through */ case 'UpdateSchemaVersion': state[scriptName].version = schemaVersion; break; default: state[scriptName] = { version: schemaVersion }; break; } } }; const handleInput = (msg) =&gt; { if (msg.type !== "api") { return; } let args = msg.content.split(/\s+/); switch(args[0]) { case '!NAME': break; } }; const registerEventHandlers = () =&gt; { on('chat:message', handleInput); }; on('ready', () =&gt; { checkInstall(); registerEventHandlers(); }); return { // Public interface here }; })(); {try{throw new Error('');}catch(e){API_Meta.NAME.lineCount=(parseInt(e.stack.split(/\n/)[1].replace(/^.*:(\d+):.*$/,'$1'),10)-API_Meta.NAME.offset);}}
1612449412
David M.
Pro
API Scripter
Pretty sure the "Advanced Usage and Tricks" label needs to be moved to the top of the post ;)&nbsp;&nbsp;
1612453688

Edited 1613711408
timmaugh
Pro
API Scripter
Version 1.0.1 Released (Updated at Original Link and pending One-Click) Relase Date: Feb 4, 2021 Fixed : Previously, resolution of table rolls in an IF condition (i.e., turning $[[0]] into 'This is the table entry') had not been updated to use the libInline parsed result. Instead, it pulled the total from the inlineroll object, which for a table roll was always 0. Now it retrieves the parsed value from the roll, which is whatever would hit chat if that roll were sent independently. Changed : Consistent with Aaron's note of versioning being tracked in APIMeta, I replaced local housing of the version (scoped to the script) to the APIMeta object. User will see no change.
1612799050
timmaugh
Pro
API Scripter
Version 1.1.0 Released (Updated at Original Link and pending One-Click) Relase Date: Feb 8, 2021 CHANGED : Definitions will now evaluate a sheet item using APILogic syntax so that the retrieved value will be used elsewhere. So if you want to define "arrowsleft" as the number of arrows a character has, you could use: {&amp; define ([arrowsleft] *|Bob the Slayer|resources|[resource_name="arrows"]|resource_quantity) } You can use this to return the name of the sheet item by using the&nbsp; name &nbsp;request, which would let you use it elsewhere in your command line. For instance, if you had to feed the resource_quantity of the arrows resource to another argument in your larger script (ChatSetAttr, PowerCards, ScriptCards, InsertArg, AmmoTracker, etc.), you would want to know what the name was of that item on a character's sheet. Returning the name in a definition block will insert that defined name anywhere the term is encountered: {&amp; define ([arrowsleftattr] *name|Bob the Slayer|resources|[resource_name="arrows"]|resource_quantity) } Drop that somewhere in the housing script command line, and it will replace all instances of "arrowsleftattr" with the actual name of the attribute as it sits on the Bob the Slayer sheet. CHANGED: Special tests for integer and number are now&nbsp; int &nbsp;and&nbsp; max &nbsp;respectively. This allows for a broader set of tests or requests to be included in this space with fewer name collisions.
1612902161

Edited 1612903200
That is awesome! Does it matter where I put that tag in a command? For example, the Ammo script currently only accepts either an attribute name or a repeating row ID/index to be altered, like this !ammo @{character_id} repeating_items-readied_$0_readied_quantity -1 @{readied_item} where the command arguments are !ammo &lt;charid&gt; &lt;attr&gt; &lt;change&gt; &lt;resource name as shown in chat output&gt; I'd like to be able to alter the value based on the name of the repeating section entry ( readied_item in the example above) so would I rebuild the command like this? !ammo @{character_id} ammunition -1 @{readied_item} {&amp; define ([ ammunition ] *name|@{character_name}|items-readied|[readied_item="@{readied_item}"]|readied_quantity) } EDIT: Testing it out, the command seems to be ignoring 'ammunition' altogether and is treating '-1' as the attr argument rather than the change argument, so it's giving this error:
1612920196
timmaugh
Pro
API Scripter
Hey, Persephone! You look to be doing it right, with one potential problem I'll get to at the end. Couple of tests you can run to make sure. This one, will output the defined term for you to make sure you're getting the correct piece of data: !{&amp; define ([ ammunition ] *name|@{character_name}|items-readied|[readied_item="@{readied_item}"]|readied_quantity) }The piece of data you requested was ammunition{&amp;simple} That should retrieve the name of that field, drop it in place of the later "ammunition", and then drop the whole thing to a simple chat message. Make sure you're getting a real return from the attribute... and, if&nbsp; you're not, use Xray to figure out what you should be using. The second test is to make sure that APILogic is hitting before ammo gets the script. To do that, drop a {&amp; simple} in your call to ammo. If APILogic is catching the message first, it should flatten the message to a simple chat output of your command line before ammo ever gets a chance to know that the original call was intended for it. Come to think of it, this second test really runs the first test, too, because it shows you how `ammunition` was evaluated in the definition tag. Now, the potential problem is that the above syntax will give you something like: repeating_items-readied_-M1234567890abcdefg_readied_quantity If the ammo script requires the $0 version of that syntax, instead, this won't work. That would a good feature to add, though. I've got more changes nearly ready to push out. I'll add a $0-nomenclature output to my to-do list and let you know when it is ready to try out. In the meantime, try the above and see if it will work for you.
1612926171

Edited 1612926370
EDIT: I restarted the sandbox and got the chat output working, and then discovered that the reason the command wasn't working before was because the readied_quantity field hadn't been manually adjusted since importing the character. So it's all working great now! Okay, I tried entering each of the following to chat and got no chat output from either one: !{&amp; define ([ ammunition ] *name|@{selected|character_name}|items-readied|[readied_item="@{selected|readied_item}"]|readied_quantity) }The piece of data you requested was ammunition{&amp;simple} !ammo @{selected|character_id} ammunition -1 @{selected|readied_item} {&amp; define ([ ammunition ] *name|@{selected|character_name}|items-readied|[readied_item="@{selected|readied_item}"]|readied_quantity) }{&amp;simple} Ammo can use the row ID or the row index, so the following version of the command works: !ammo -M6aAfQSBiZ8j3JdMSrz repeating_items-readied_-M7LoKTIBEpYrUAPppF0_readied_quantity -1 @{selected|readied_item}
1612939390

Edited 1612942983
Question about the bolded part of the following command: [Spend Spell Slot (@{uses}/@{uses|max})](!ammo @{character_id} spellslot -1 preparation of level @{current_level} &amp;ast;@{name}&amp;ast; {&amp;amp; define ([spellslot] &amp;ast;name|@{character_name}|normalspells| [name=&amp;quot;@{name}&amp;quot;] |uses&amp;rpar; }) Can more than one of these arguments be made in the same define tag? Like [name="Heal"][current_level="3"], so if there are multiple rows with the name "Heal" but with different levels, and multiple rows with level "3" but different names, then this would only refer to the one row named Heal that is also level 3? Also, just noticed that if the quantity attribute (like "uses") is changed to 0 by either Ammo or ChatSetAttr, and is still 0 at the time of running another command, the define tag substitutes in 0 instead of the full repeating_normalspells_-MIljWVlPYyIXBtMtr7T_uses . So if I reduce the uses to 0 using the command above, then when I click this one [Prepare](!setattr --charid @{character_id} --spellslot|&amp;quest;{Uses prepared&amp;vert;1}|&amp;quest;{Uses prepared} {&amp;amp; define ([spellslot] &amp;ast;name|@{character_name}|normalspells|[name=&amp;quot;@{name}&amp;quot;]|uses&amp;rpar; }) it gets turned into this !setattr --charid -MIdzBjQlxL6pgJaBzc2 --0|1|1 It works just fine if the value is above or below 0, or was manually set to 0.
1612963718

Edited 1612963749
timmaugh
Pro
API Scripter
So glad you got the script working, P! Now, about your issue... Persephone said: Question about the bolded part of the following command: [Spend Spell Slot (@{uses}/@{uses|max})](!ammo @{character_id} spellslot -1 preparation of level @{current_level} &amp;ast;@{name}&amp;ast; {&amp;amp; define ([spellslot] &amp;ast;name|@{character_name}|normalspells| [name=&amp;quot;@{name}&amp;quot;] |uses&amp;rpar; }) Can more than one of these arguments be made in the same define tag? Like [name="Heal"][current_level="3"], so if there are multiple rows with the name "Heal" but with different levels, and multiple rows with level "3" but different names, then this would only refer to the one row named Heal that is also level 3? Yes! All of those requirements go in the same pattern definition, though: [name=Heal current_level=3] (You only need the quotation marks if the data has a space in it.) Basically, put all of the identifying requirements in this portion of the sheet item, all within the one set of closing brackets. APILogic will find all of the items that match that pattern, and then return the first out of that set. As for the other issue (an API-set 0 making a request for the name of a repeating sheet item instead return 0)... I haven't seen that particular interaction. I wonder if it isn't finding the attribute and therefore is subbing in a 0...? I thought I had it subbing in a zero-length string if it didn't find the requested sheet item. I will have to dig into that one, and see how ChatSetAttr and Ammo are setting that field that could create this interaction. Can you tell me what&nbsp; @{name} &nbsp;resolves to, in that command? Where you have a pattern of: [name=&amp;quot;@{name}&amp;quot;]
1612981621

Edited 1612981845
Thanks for the clarification! Let me know if you need any other info or help testing regarding the API-set 0 issue. I had set up commands for refilling those values, but this is causing them to not work in most cases. And @{name} in that example is the attr for the spell name (those buttons are placed in the spell description so it pulls from the same repeating row). So it works the same as @{repeating_normalspells_-MIljWVlPYyIXBtMtr7T_name} , if the spells name is ray of enfeeblement that is what @{name} resolves as.
1613069650
timmaugh
Pro
API Scripter
Version 1.1.1 Released (Updated at Original Link and pending One-Click) Release Date: Feb 11, 2021 FIXED : Terms defined to be simple text (i.e., not a sheet item) are now properly detected. ADDED : Special returns have been added for repeating sheet items&nbsp; (in addition to the&nbsp; name &nbsp;return available for all sheet items). Below is the full set of special returns available. ----------------------------------------------------------------------------------------------------------------------------- TERM&nbsp;&nbsp;&nbsp;&nbsp;| EXAMPLE&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;| EXAMPLE RETURN --------|------------------------------------------------------------|------------------------------------------------------- name&nbsp;&nbsp;&nbsp;&nbsp;| *name|Bob|skills|[skill_name=Bowling]|skill_roll_target&nbsp;&nbsp;&nbsp;&nbsp;| repeating_skills_-M1234567890abcdef_skill_roll_target row&nbsp;&nbsp;&nbsp;&nbsp; | *row|Bob|skills|[skill_name=Bowling]|skill_roll_target&nbsp;&nbsp;&nbsp;&nbsp; | $2 rowname | *rowname|Bob|skills|[skill_name=Bowling]|skill_roll_target&nbsp;| repeating_skills_$2_skill_roll_target
1613404150
I tried to run this ![&amp; if @|Bob the Slayer|slogan]@\{Bob the Slayer|slogan}[&amp; end] For tomorrow we dine in hell.[&amp; simple] I didn't get any chat result.&nbsp; I had added the character and a slogan field into that characters name as well as hurray.&nbsp; From reading the description of behavior I thought it would result in Bob the Slayer Hurray.&nbsp;&nbsp;&nbsp; I had tried this under 1.1.1 that is in the github and prior to that 1.1 under one click. I thought I could use what you have here for the old role master critical hit charts where I could use a number and compare that number to a result that would then present that critical result.&nbsp; Does that sound like the right fit for this api and am I doing something wrong with just trying to get orientated with it from the example that you have written? Looking forward to your reply.&nbsp;
1613414887
timmaugh
Pro
API Scripter
Hi, John... good to run into another rolemaster... um... er. Rolemaster-er. =D I think your problem is that you are using the square brackets for your tags rather than the curly braces. The script had initially been written in that form, but I had to change it do to a parsing bug in the Roll20 parser. I *thought* I had caught all previous references to the square bracket formation, but apparently I missed some. I will try to get it updated... did you find that example in the readme in the git repo? For now, try this, instead: !{&amp; if @|Bob the Slayer|slogan}@\{Bob the Slayer|slogan}{&amp; end} For tomorrow we dine in hell.{&amp; simple} Also, yes, you're in the right neighborhood for the resolution of a critical using APILogic... but I know, too, from having played Rolemaster that you're talking about a lot of different results, on potentially a lot of different charts. The beta version of this script (soon to be released) includes a way to "plugin" more script functionality. One such plugin is going to be a "variable mule" to allow you store variables between macros. I could see a plugin answering this specific requirement, letting you input the rolemaster chart and then plug a number into it. I will add that to my list to build!
1613420348
Great that did as described.&nbsp; Thank you so much.&nbsp; I had grabbed that from your post way above.
1613427077
timmaugh
Pro
API Scripter
Great to hear that it worked for you... and I have that example corrected. Thanks for the heads up!
1613584867

Edited 1613584924
Say I'm getting inconsistent and unexpected results in my call that I'm running. This is an exhaustion formula where I have set the bar1 to track that resource until they start feeling tired and getting negative results.&nbsp; My thought flow is that the value is the old value when it hits my logic so everything is sort of one off from what I want it to be but that seemed to work. Now I'm getting different sections triggered and its showing the those logic tags as well.&nbsp; The below example is a value going from 29 to 28.&nbsp; Results don't always repeat for the same value changes and api output has a tag of unexpected token at 99. !token-mod --set bar1_value|-1 /desc @{selected|token_name} ... !{&amp;if @{selected|bar1} &gt; 30 } they still have reserves. @{selected|bar1} {&amp; simple} {&amp; end} !{&amp;if @{selected|bar1} &lt; 31 &amp;&amp; @{selected|bar1} &gt; 20} -5 penalty. They feel all of their exertion. @{selected|bar1} {&amp; simple} {&amp; end} !{&amp;if @{selected|bar1} &lt; 21 &amp;&amp; @{selected|bar1} &gt; 11} -10 penalty. They could use a rest. @{selected|bar1} {&amp; simple} {&amp; end} !{&amp;if @{selected|bar1} &lt; 12 &amp;&amp; @{selected|bar1} &gt; 5} -30 penalty. They are exhausted. @{selected|bar1} {&amp; simple} {&amp; end} !{&amp;if @{selected|bar1} &lt; 6 &amp;&amp; @{selected|bar1} &gt; 2} -60 penalty. They are totally exhausted. @{selected|bar1} {&amp; simple} {&amp; end} !{&amp;if @{selected|bar1} &lt; 3} -100 penalty. They are wiped out.. @{selected|bar1} {&amp; simple} {&amp; end} API output "!APILogic-MTl6kPaWwzLDAablAHx{&amp;if 34 &lt; 6 &amp;&amp; 34 &gt; 2} -60 penalty. They are totally exhausted. 34 " "Unexpected token at 99." "!APILogic-MTl6kvRYlbT4BS_ElfV{&amp;if 32 &lt; 6 &amp;&amp; 32 &gt; 2} -60 penalty. They are totally exhausted. 32 " "Unexpected token at 99." "!APILogic-MTl6l6Xy3zJ9ryJn5Q4{&amp;if 31 &lt; 6 &amp;&amp; 31 &gt; 2} -60 penalty. They are totally exhausted. 31 " "Unexpected token at 99." "!APILogic-MTl6lHcF4MwNGEi2Q29{&amp;if 30 &lt; 6 &amp;&amp; 30 &gt; 2} -60 penalty. They are totally exhausted. 30 " "Unexpected token at 99." "!APILogic-MTl6lT141iej86Ux1Hb{&amp;if 29 &lt; 6 &amp;&amp; 29 &gt; 2} -60 penalty. They are totally exhausted. 29 "
1613589084

Edited 1613589150
timmaugh
Pro
API Scripter
It looks like that is a line break issue. If I try your single line for "totally exhausted", I get the same output, but it's because the {&amp; simple} and {&amp; end} tags are being sent in a follow-on message. If I delete the line-break and bring them into a single line, I don't get the error. I get the appropriate output. APILogic doesn't do anything with line-breaks specifically -- it just treats the line-break characters as other text to include/exclude -- but it has to see all of the appropriate tags in one message as it reaches the chat parser. The actual ability to break lines in a macro is a function of tricking the Roll20 parser into thinking it has a roll template (by using '{{' and '}}'). The housing script (in this case, token-mod) has to be ready to parse out the braces and the line-break characters, but in that case all of the text (across all line breaks between the double braces) is sent at once to the chat parser. Someone with more experience on token-mod will have to correct me, but I think you need something like: !token-mod {{ --set|bar1_value|-1 ...other stuff... }}
1613597333
The token mod is working as expected.&nbsp; Thanks did not intend to have a line break on there and hard to see in the macro regarding the {&amp; simple} {&amp; end}. Each line on the macro is its own message is my understanding.&nbsp; So each line should run on its own accord. So I"m seeing things getting triggered in the message that isn't making sense unless I'm goofing on the use of the &amp;&amp; for and to achieve a range. All of this came out of the message for the value of 27 but it should be mutually exclusive and so -60 and -100 should not have happened. -5 penalty. They feel all of their exertion. 27&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; expected -60 penalty. They are totally exhausted. 27&nbsp; unexpected -100 penalty. They are wiped out.. 27 unexpected
1613613785

Edited 1613616820
timmaugh
Pro
API Scripter
OK, I have replicated that issue, and I think I know what the problem is. Let me run a few tests to make sure I have it licked and I will post updated code. EDIT: Yep, that got it. New release should have you covered!
1613616578

Edited 1614045596
timmaugh
Pro
API Scripter
Version 1.1.2 Released (Updated at Original Link and pending One-Click) Release Date: Feb 17, 2021 FIXED : Comparisons of &lt;, &lt;=, &gt;, &gt;= were not properly detecting and coercing number values when necessary. Fixed version will compare text values alphabetically and numeric values numerically.
1613660830
Thanks Tim.I started from the top of my number test and started to subtract it and something that is occurring without errors is nothing is getting triggered.&nbsp; I was using values between 38 to 30 and counting down and occasionally&nbsp; "they still have reserves" above 30 logic would not show.&nbsp; This behavior is not repeating on any specific number but just occasionally the logic isn't finding the true case.&nbsp; As I was writing this I quick did a bunch more cases to identify if it was just my first logic test which is just a greater than versus the use of the and and it is happening with irregularity on all bands.
1613673983
timmaugh
Pro
API Scripter
I ran a bunch of tests with a similar ability structure (just APIL, no token-mod), and I am getting consistent results: !{&amp; if @{selected|bar1} &gt; 50}Value is over 50. @{selected|bar1}{&amp;simple}{&amp;end} !{&amp; if @{selected|bar1} &gt; 40 &amp;&amp; @{selected|bar1} &lt;=50}Value is between 40 and 50. @{selected|bar1}{&amp;simple}{&amp;end} !{&amp; if @{selected|bar1} &gt; 30 &amp;&amp; @{selected|bar1} &lt;=40}Value is between 30 and 40. @{selected|bar1}{&amp;simple}{&amp;end} !{&amp; if @{selected|bar1} &gt; 20 &amp;&amp; @{selected|bar1} &lt;=30}Value is between 20 and 30. @{selected|bar1}{&amp;simple}{&amp;end} !{&amp; if @{selected|bar1} &gt; 10 &amp;&amp; @{selected|bar1} &lt;=20}Value is between 10 and 20. @{selected|bar1}{&amp;simple}{&amp;end} !{&amp; if @{selected|bar1} &lt;=10}Value is less than 10. @{selected|bar1}{&amp;simple}{&amp;end} I changed the bar manually and ran that a bunch of times, getting consistent/correct results each time: That was with a bar that was *not* backed by an attribute, so I'll try with an attribute-backed bar to see what I get. I'm wondering, too what the condition is actually seeing on your end when the command reaches the parser... so could you add a&nbsp; {&amp; log} &nbsp;tag to each of your APIL calls in that macro? There will be quite a bit of information posted to the console. Can you copy/paste your full macro text and the output of that logging to a new message?
1613695374
From my macro button. Appreciate that your taking the time.&nbsp; !token-mod --set bar1_value|-1 /desc @{selected|token_name} ... !{&amp;if @{selected|bar1} &gt; 30 } they still have reserves. @{selected|bar1} {&amp; simple} {&amp; end} {&amp; log} !{&amp;if @{selected|bar1} &lt; 31 &amp;&amp; @{selected|bar1} &gt; 20} -5 penalty. They feel all of their exertion. @{selected|bar1} {&amp; simple} {&amp; end} {&amp; log} !{&amp;if @{selected|bar1} &lt; 21 &amp;&amp; @{selected|bar1} &gt; 11} -10 penalty. They could use a rest. @{selected|bar1} {&amp; simple} {&amp; end} {&amp; log} !{&amp;if @{selected|bar1} &lt; 12 &amp;&amp; @{selected|bar1} &gt; 5} -30 penalty. They are exhausted. @{selected|bar1} {&amp; simple} {&amp; end} {&amp; log} !{&amp;if @{selected|bar1} &lt; 6 &amp;&amp; @{selected|bar1} &gt; 2} -60 penalty. They are totally exhausted. @{selected|bar1} {&amp; simple} {&amp; end} {&amp; log} !{&amp;if @{selected|bar1} &lt; 3} -100 penalty. They are wiped out.. @{selected|bar1} {&amp; simple} {&amp; end} {&amp; log} A few iterations of the series of macros.&nbsp; Last iteration came up with no result though it had a value of 17 and should have appeared.&nbsp; I changed my macro button to remove the token mod that is decrementing the bar to see if that was conflicting but similar result occurred.&nbsp; Output onto the console. "ŦŦ APILogic v1.1.2, 2021/2/18 ŦŦ -- offset 11958" "DEFVAL BEGINS" "==TEXT INPUT: !APILogic-MTrhlecXRgrtXOVrofk{&amp;if 20 &gt; 30 } they still have reserves. 20 {&amp; simple} {&amp; end} " "==TEXT KEEPS: !APILogic-MTrhlecXRgrtXOVrofk{&amp;if 20 &gt; 30 } they still have reserves. 20 {&amp; simple} {&amp; end} " "DEFVAL ENDS" "VAL BEGINS" "==TEXT INPUT: !APILogic-MTrhlecXRgrtXOVrofk{&amp;if 20 &gt; 30 } they still have reserves. 20 {&amp; simple} {&amp; end} " "==TEXT KEEPS: !APILogic-MTrhlecXRgrtXOVrofk" "==IF INPUT: {&amp;if 20 &gt; 30 } they still have reserves. 20 {&amp; simple} {&amp; end} " "====GETCONDITIONS BEGINS" "======CONDITION INPUT: 20 &gt; 30 } they still have reserves. 20 {&amp; simple} {&amp; end} " "======CONDITION OUTPUT: {\"type\":\"&gt;\",\"contents\":[[\"20 \",\"\",\"\",\"20\"],[\"30 \",\"\",\"\",\"30\"]],\"next\":\"\",\"negate\":false}" "====GETCONDITIONS ENDS" "====BUILDING CONTENT: they still have reserves. 20 {&amp; simple} {&amp; end} " "======VAL BEGINS" "========TEXT INPUT: they still have reserves. 20 {&amp; simple} {&amp; end} " "========TEXT KEEPS: they still have reserves. 20 {&amp; simple} " "======VAL ENDS" "====ENDING CONTENT: {&amp; end} " "==IF OUTPUT: {\"type\":\"if\",\"conditions\":[{\"type\":\"&gt;\",\"contents\":[[\"20 \",\"\",\"\",\"20\"],[\"30 \",\"\",\"\",\"30\"]],\"next\":\"\",\"negate\":false}],\"contents\":[{\"type\":\"text\",\"value\":\" they still have reserves. 20 {&amp; simple} \"}],\"else\":{}}" "==TEXT INPUT: " "==TEXT KEEPS: " "VAL ENDS" "DEFVAL BEGINS" "==TEXT INPUT: !APILogic-MTrhlelM92vZWywBiSC{&amp;if 20 &lt; 31 &amp;&amp; 20 &gt; 20} -5 penalty. They feel all of their exertion. 20 {&amp; simple} {&amp; end} " "==TEXT KEEPS: !APILogic-MTrhlelM92vZWywBiSC{&amp;if 20 &lt; 31 &amp;&amp; 20 &gt; 20} -5 penalty. They feel all of their exertion. 20 {&amp; simple} {&amp; end} " "DEFVAL ENDS" "VAL BEGINS" "==TEXT INPUT: !APILogic-MTrhlelM92vZWywBiSC{&amp;if 20 &lt; 31 &amp;&amp; 20 &gt; 20} -5 penalty. They feel all of their exertion. 20 {&amp; simple} {&amp; end} " "==TEXT KEEPS: !APILogic-MTrhlelM92vZWywBiSC" "==IF INPUT: {&amp;if 20 &lt; 31 &amp;&amp; 20 &gt; 20} -5 penalty. They feel all of their exertion. 20 {&amp; simple} {&amp; end} " "====GETCONDITIONS BEGINS" "======CONDITION INPUT: 20 &lt; 31 &amp;&amp; 20 &gt; 20} -5 penalty. They feel all of their exertion. 20 {&amp; simple} {&amp; end} " "======CONDITION OUTPUT: {\"type\":\"&lt;\",\"contents\":[[\"20 \",\"\",\"\",\"20\"],[\"31 \",\"\",\"\",\"31\"]],\"next\":\"&amp;&amp;\",\"negate\":false}" "======CONDITION INPUT: 20 &gt; 20} -5 penalty. They feel all of their exertion. 20 {&amp; simple} {&amp; end} " "======CONDITION OUTPUT: {\"type\":\"&gt;\",\"contents\":[[\"20 \",\"\",\"\",\"20\"],[\"20\",\"\",\"\",\"20\"]],\"next\":\"\",\"negate\":false}" "====GETCONDITIONS ENDS" "====BUILDING CONTENT: -5 penalty. They feel all of their exertion. 20 {&amp; simple} {&amp; end} " "======VAL BEGINS" "========TEXT INPUT: -5 penalty. They feel all of their exertion. 20 {&amp; simple} {&amp; end} " "========TEXT KEEPS: -5 penalty. They feel all of their exertion. 20 {&amp; simple} " "======VAL ENDS" "====ENDING CONTENT: {&amp; end} " "==IF OUTPUT: {\"type\":\"if\",\"conditions\":[{\"type\":\"&lt;\",\"contents\":[[\"20 \",\"\",\"\",\"20\"],[\"31 \",\"\",\"\",\"31\"]],\"next\":\"&amp;&amp;\",\"negate\":false},{\"type\":\"&gt;\",\"contents\":[[\"20 \",\"\",\"\",\"20\"],[\"20\",\"\",\"\",\"20\"]],\"next\":\"\",\"negate\":false}],\"contents\":[{\"type\":\"text\",\"value\":\" -5 penalty. They feel all of their exertion. 20 {&amp; simple} \"}],\"else\":{}}" "==TEXT INPUT: " "==TEXT KEEPS: " "VAL ENDS" "DEFVAL BEGINS" "==TEXT INPUT: !APILogic-MTrhlf-VgPaoXC5I8z_{&amp;if 20 &lt; 21 &amp;&amp; 20 &gt; 11} -10 penalty. They could use a rest. 20 {&amp; simple} {&amp; end} " "==TEXT KEEPS: !APILogic-MTrhlf-VgPaoXC5I8z_{&amp;if 20 &lt; 21 &amp;&amp; 20 &gt; 11} -10 penalty. They could use a rest. 20 {&amp; simple} {&amp; end} " "DEFVAL ENDS" "VAL BEGINS" "==TEXT INPUT: !APILogic-MTrhlf-VgPaoXC5I8z_{&amp;if 20 &lt; 21 &amp;&amp; 20 &gt; 11} -10 penalty. They could use a rest. 20 {&amp; simple} {&amp; end} " "==TEXT KEEPS: !APILogic-MTrhlf-VgPaoXC5I8z_" "==IF INPUT: {&amp;if 20 &lt; 21 &amp;&amp; 20 &gt; 11} -10 penalty. They could use a rest. 20 {&amp; simple} {&amp; end} " "====GETCONDITIONS BEGINS" "======CONDITION INPUT: 20 &lt; 21 &amp;&amp; 20 &gt; 11} -10 penalty. They could use a rest. 20 {&amp; simple} {&amp; end} " "======CONDITION OUTPUT: {\"type\":\"&lt;\",\"contents\":[[\"20 \",\"\",\"\",\"20\"],[\"21 \",\"\",\"\",\"21\"]],\"next\":\"&amp;&amp;\",\"negate\":false}" "======CONDITION INPUT: 20 &gt; 11} -10 penalty. They could use a rest. 20 {&amp; simple} {&amp; end} " "======CONDITION OUTPUT: {\"type\":\"&gt;\",\"contents\":[[\"20 \",\"\",\"\",\"20\"],[\"11\",\"\",\"\",\"11\"]],\"next\":\"\",\"negate\":false}" "====GETCONDITIONS ENDS" "====BUILDING CONTENT: -10 penalty. They could use a rest. 20 {&amp; simple} {&amp; end} " "======VAL BEGINS" "========TEXT INPUT: -10 penalty. They could use a rest. 20 {&amp; simple} {&amp; end} " "========TEXT KEEPS: -10 penalty. They could use a rest. 20 {&amp; simple} " "======VAL ENDS" "====ENDING CONTENT: {&amp; end} " "==IF OUTPUT: {\"type\":\"if\",\"conditions\":[{\"type\":\"&lt;\",\"contents\":[[\"20 \",\"\",\"\",\"20\"],[\"21 \",\"\",\"\",\"21\"]],\"next\":\"&amp;&amp;\",\"negate\":false},{\"type\":\"&gt;\",\"contents\":[[\"20 \",\"\",\"\",\"20\"],[\"11\",\"\",\"\",\"11\"]],\"next\":\"\",\"negate\":false}],\"contents\":[{\"type\":\"text\",\"value\":\" -10 penalty. They could use a rest. 20 {&amp; simple} \"}],\"else\":{}}" "==TEXT INPUT: " "==TEXT KEEPS: " "VAL ENDS" "DEFVAL BEGINS" "==TEXT INPUT: !APILogic-MTrhlfI05_oh5Vhol8M{&amp;if 20 &lt; 6 &amp;&amp; 20 &gt; 2} -60 penalty. They are totally exhausted. 20 {&amp; simple} {&amp; end} " "==TEXT KEEPS: !APILogic-MTrhlfI05_oh5Vhol8M{&amp;if 20 &lt; 6 &amp;&amp; 20 &gt; 2} -60 penalty. They are totally exhausted. 20 {&amp; simple} {&amp; end} " "DEFVAL ENDS" "VAL BEGINS" "==TEXT INPUT: !APILogic-MTrhlfI05_oh5Vhol8M{&amp;if 20 &lt; 6 &amp;&amp; 20 &gt; 2} -60 penalty. They are totally exhausted. 20 {&amp; simple} {&amp; end} " "==TEXT KEEPS: !APILogic-MTrhlfI05_oh5Vhol8M" "==IF INPUT: {&amp;if 20 &lt; 6 &amp;&amp; 20 &gt; 2} -60 penalty. They are totally exhausted. 20 {&amp; simple} {&amp; end} " "====GETCONDITIONS BEGINS" "======CONDITION INPUT: 20 &lt; 6 &amp;&amp; 20 &gt; 2} -60 penalty. They are totally exhausted. 20 {&amp; simple} {&amp; end} " "======CONDITION OUTPUT: {\"type\":\"&lt;\",\"contents\":[[\"20 \",\"\",\"\",\"20\"],[\"6 \",\"\",\"\",\"6\"]],\"next\":\"&amp;&amp;\",\"negate\":false}" "======CONDITION INPUT: 20 &gt; 2} -60 penalty. They are totally exhausted. 20 {&amp; simple} {&amp; end} " "======CONDITION OUTPUT: {\"type\":\"&gt;\",\"contents\":[[\"20 \",\"\",\"\",\"20\"],[\"2\",\"\",\"\",\"2\"]],\"next\":\"\",\"negate\":false}" "====GETCONDITIONS ENDS" "====BUILDING CONTENT: -60 penalty. They are totally exhausted. 20 {&amp; simple} {&amp; end} " "======VAL BEGINS" "========TEXT INPUT: -60 penalty. They are totally exhausted. 20 {&amp; simple} {&amp; end} " "========TEXT KEEPS: -60 penalty. They are totally exhausted. 20 {&amp; simple} " "======VAL ENDS" "====ENDING CONTENT: {&amp; end} " "==IF OUTPUT: {\"type\":\"if\",\"conditions\":[{\"type\":\"&lt;\",\"contents\":[[\"20 \",\"\",\"\",\"20\"],[\"6 \",\"\",\"\",\"6\"]],\"next\":\"&amp;&amp;\",\"negate\":false},{\"type\":\"&gt;\",\"contents\":[[\"20 \",\"\",\"\",\"20\"],[\"2\",\"\",\"\",\"2\"]],\"next\":\"\",\"negate\":false}],\"contents\":[{\"type\":\"text\",\"value\":\" -60 penalty. They are totally exhausted. 20 {&amp; simple} \"}],\"else\":{}}" "==TEXT INPUT: " "==TEXT KEEPS: " "VAL ENDS" "DEFVAL BEGINS" "==TEXT INPUT: !APILogic-MTrhnb4Ar8eZYv_6XhG{&amp;if 19 &gt; 30 } they still have reserves. 19 {&amp; simple} {&amp; end} " "==TEXT KEEPS: !APILogic-MTrhnb4Ar8eZYv_6XhG{&amp;if 19 &gt; 30 } they still have reserves. 19 {&amp; simple} {&amp; end} " "DEFVAL ENDS" "VAL BEGINS" "==TEXT INPUT: !APILogic-MTrhnb4Ar8eZYv_6XhG{&amp;if 19 &gt; 30 } they still have reserves. 19 {&amp; simple} {&amp; end} " "==TEXT KEEPS: !APILogic-MTrhnb4Ar8eZYv_6XhG" "==IF INPUT: {&amp;if 19 &gt; 30 } they still have reserves. 19 {&amp; simple} {&amp; end} " "====GETCONDITIONS BEGINS" "======CONDITION INPUT: 19 &gt; 30 } they still have reserves. 19 {&amp; simple} {&amp; end} " "======CONDITION OUTPUT: {\"type\":\"&gt;\",\"contents\":[[\"19 \",\"\",\"\",\"19\"],[\"30 \",\"\",\"\",\"30\"]],\"next\":\"\",\"negate\":false}" "====GETCONDITIONS ENDS" "====BUILDING CONTENT: they still have reserves. 19 {&amp; simple} {&amp; end} " "======VAL BEGINS" "========TEXT INPUT: they still have reserves. 19 {&amp; simple} {&amp; end} " "========TEXT KEEPS: they still have reserves. 19 {&amp; simple} " "======VAL ENDS" "====ENDING CONTENT: {&amp; end} " "==IF OUTPUT: {\"type\":\"if\",\"conditions\":[{\"type\":\"&gt;\",\"contents\":[[\"19 \",\"\",\"\",\"19\"],[\"30 \",\"\",\"\",\"30\"]],\"next\":\"\",\"negate\":false}],\"contents\":[{\"type\":\"text\",\"value\":\" they still have reserves. 19 {&amp; simple} \"}],\"else\":{}}" "==TEXT INPUT: " "==TEXT KEEPS: " "VAL ENDS" "DEFVAL BEGINS" "==TEXT INPUT: !APILogic-MTrhnbI8CI9Y8W5Bd2O{&amp;if 19 &lt; 31 &amp;&amp; 19 &gt; 20} -5 penalty. They feel all of their exertion. 19 {&amp; simple} {&amp; end} " "==TEXT KEEPS: !APILogic-MTrhnbI8CI9Y8W5Bd2O{&amp;if 19 &lt; 31 &amp;&amp; 19 &gt; 20} -5 penalty. They feel all of their exertion. 19 {&amp; simple} {&amp; end} " "DEFVAL ENDS" "VAL BEGINS" "==TEXT INPUT: !APILogic-MTrhnbI8CI9Y8W5Bd2O{&amp;if 19 &lt; 31 &amp;&amp; 19 &gt; 20} -5 penalty. They feel all of their exertion. 19 {&amp; simple} {&amp; end} " "==TEXT KEEPS: !APILogic-MTrhnbI8CI9Y8W5Bd2O" "==IF INPUT: {&amp;if 19 &lt; 31 &amp;&amp; 19 &gt; 20} -5 penalty. They feel all of their exertion. 19 {&amp; simple} {&amp; end} " "====GETCONDITIONS BEGINS" "======CONDITION INPUT: 19 &lt; 31 &amp;&amp; 19 &gt; 20} -5 penalty. They feel all of their exertion. 19 {&amp; simple} {&amp; end} " "======CONDITION OUTPUT: {\"type\":\"&lt;\",\"contents\":[[\"19 \",\"\",\"\",\"19\"],[\"31 \",\"\",\"\",\"31\"]],\"next\":\"&amp;&amp;\",\"negate\":false}" "======CONDITION INPUT: 19 &gt; 20} -5 penalty. They feel all of their exertion. 19 {&amp; simple} {&amp; end} " "======CONDITION OUTPUT: {\"type\":\"&gt;\",\"contents\":[[\"19 \",\"\",\"\",\"19\"],[\"20\",\"\",\"\",\"20\"]],\"next\":\"\",\"negate\":false}" "====GETCONDITIONS ENDS" "====BUILDING CONTENT: -5 penalty. They feel all of their exertion. 19 {&amp; simple} {&amp; end} " "======VAL BEGINS" "========TEXT INPUT: -5 penalty. They feel all of their exertion. 19 {&amp; simple} {&amp; end} " "========TEXT KEEPS: -5 penalty. They feel all of their exertion. 19 {&amp; simple} " "======VAL ENDS" "====ENDING CONTENT: {&amp; end} " "==IF OUTPUT: {\"type\":\"if\",\"conditions\":[{\"type\":\"&lt;\",\"contents\":[[\"19 \",\"\",\"\",\"19\"],[\"31 \",\"\",\"\",\"31\"]],\"next\":\"&amp;&amp;\",\"negate\":false},{\"type\":\"&gt;\",\"contents\":[[\"19 \",\"\",\"\",\"19\"],[\"20\",\"\",\"\",\"20\"]],\"next\":\"\",\"negate\":false}],\"contents\":[{\"type\":\"text\",\"value\":\" -5 penalty. They feel all of their exertion. 19 {&amp; simple} \"}],\"else\":{}}" "==TEXT INPUT: " "==TEXT KEEPS: " "VAL ENDS" "DEFVAL BEGINS" "==TEXT INPUT: !APILogic-MTrhnbTP30mdszPCQln{&amp;if 19 &lt; 21 &amp;&amp; 19 &gt; 11} -10 penalty. They could use a rest. 19 {&amp; simple} {&amp; end} " "==TEXT KEEPS: !APILogic-MTrhnbTP30mdszPCQln{&amp;if 19 &lt; 21 &amp;&amp; 19 &gt; 11} -10 penalty. They could use a rest. 19 {&amp; simple} {&amp; end} " "DEFVAL ENDS" "VAL BEGINS" "==TEXT INPUT: !APILogic-MTrhnbTP30mdszPCQln{&amp;if 19 &lt; 21 &amp;&amp; 19 &gt; 11} -10 penalty. They could use a rest. 19 {&amp; simple} {&amp; end} " "==TEXT KEEPS: !APILogic-MTrhnbTP30mdszPCQln" "==IF INPUT: {&amp;if 19 &lt; 21 &amp;&amp; 19 &gt; 11} -10 penalty. They could use a rest. 19 {&amp; simple} {&amp; end} " "====GETCONDITIONS BEGINS" "======CONDITION INPUT: 19 &lt; 21 &amp;&amp; 19 &gt; 11} -10 penalty. They could use a rest. 19 {&amp; simple} {&amp; end} " "======CONDITION OUTPUT: {\"type\":\"&lt;\",\"contents\":[[\"19 \",\"\",\"\",\"19\"],[\"21 \",\"\",\"\",\"21\"]],\"next\":\"&amp;&amp;\",\"negate\":false}" "======CONDITION INPUT: 19 &gt; 11} -10 penalty. They could use a rest. 19 {&amp; simple} {&amp; end} " "======CONDITION OUTPUT: {\"type\":\"&gt;\",\"contents\":[[\"19 \",\"\",\"\",\"19\"],[\"11\",\"\",\"\",\"11\"]],\"next\":\"\",\"negate\":false}" "====GETCONDITIONS ENDS" "====BUILDING CONTENT: -10 penalty. They could use a rest. 19 {&amp; simple} {&amp; end} " "======VAL BEGINS" "========TEXT INPUT: -10 penalty. They could use a rest. 19 {&amp; simple} {&amp; end} " "========TEXT KEEPS: -10 penalty. They could use a rest. 19 {&amp; simple} " "======VAL ENDS" "====ENDING CONTENT: {&amp; end} " "==IF OUTPUT: {\"type\":\"if\",\"conditions\":[{\"type\":\"&lt;\",\"contents\":[[\"19 \",\"\",\"\",\"19\"],[\"21 \",\"\",\"\",\"21\"]],\"next\":\"&amp;&amp;\",\"negate\":false},{\"type\":\"&gt;\",\"contents\":[[\"19 \",\"\",\"\",\"19\"],[\"11\",\"\",\"\",\"11\"]],\"next\":\"\",\"negate\":false}],\"contents\":[{\"type\":\"text\",\"value\":\" -10 penalty. They could use a rest. 19 {&amp; simple} \"}],\"else\":{}}" "==TEXT INPUT: " "==TEXT KEEPS: " "VAL ENDS" "DEFVAL BEGINS" "==TEXT INPUT: !APILogic-MTrhnbabheF2df_g1XP{&amp;if 19 &lt; 12 &amp;&amp; 19 &gt; 5} -30 penalty. They are exhausted. 19 {&amp; simple} {&amp; end} " "==TEXT KEEPS: !APILogic-MTrhnbabheF2df_g1XP{&amp;if 19 &lt; 12 &amp;&amp; 19 &gt; 5} -30 penalty. They are exhausted. 19 {&amp; simple} {&amp; end} " "DEFVAL ENDS" "VAL BEGINS" "==TEXT INPUT: !APILogic-MTrhnbabheF2df_g1XP{&amp;if 19 &lt; 12 &amp;&amp; 19 &gt; 5} -30 penalty. They are exhausted. 19 {&amp; simple} {&amp; end} " "==TEXT KEEPS: !APILogic-MTrhnbabheF2df_g1XP" "==IF INPUT: {&amp;if 19 &lt; 12 &amp;&amp; 19 &gt; 5} -30 penalty. They are exhausted. 19 {&amp; simple} {&amp; end} " "====GETCONDITIONS BEGINS" "======CONDITION INPUT: 19 &lt; 12 &amp;&amp; 19 &gt; 5} -30 penalty. They are exhausted. 19 {&amp; simple} {&amp; end} " "======CONDITION OUTPUT: {\"type\":\"&lt;\",\"contents\":[[\"19 \",\"\",\"\",\"19\"],[\"12 \",\"\",\"\",\"12\"]],\"next\":\"&amp;&amp;\",\"negate\":false}" "======CONDITION INPUT: 19 &gt; 5} -30 penalty. They are exhausted. 19 {&amp; simple} {&amp; end} " "======CONDITION OUTPUT: {\"type\":\"&gt;\",\"contents\":[[\"19 \",\"\",\"\",\"19\"],[\"5\",\"\",\"\",\"5\"]],\"next\":\"\",\"negate\":false}" "====GETCONDITIONS ENDS" "====BUILDING CONTENT: -30 penalty. They are exhausted. 19 {&amp; simple} {&amp; end} " "======VAL BEGINS" "========TEXT INPUT: -30 penalty. They are exhausted. 19 {&amp; simple} {&amp; end} " "========TEXT KEEPS: -30 penalty. They are exhausted. 19 {&amp; simple} " "======VAL ENDS" "====ENDING CONTENT: {&amp; end} " "==IF OUTPUT: {\"type\":\"if\",\"conditions\":[{\"type\":\"&lt;\",\"contents\":[[\"19 \",\"\",\"\",\"19\"],[\"12 \",\"\",\"\",\"12\"]],\"next\":\"&amp;&amp;\",\"negate\":false},{\"type\":\"&gt;\",\"contents\":[[\"19 \",\"\",\"\",\"19\"],[\"5\",\"\",\"\",\"5\"]],\"next\":\"\",\"negate\":false}],\"contents\":[{\"type\":\"text\",\"value\":\" -30 penalty. They are exhausted. 19 {&amp; simple} \"}],\"else\":{}}" "==TEXT INPUT: " "==TEXT KEEPS: " "VAL ENDS" "DEFVAL BEGINS" "==TEXT INPUT: !APILogic-MTrhns4OS9BwTT--SZF{&amp;if 18 &gt; 30 } they still have reserves. 18 {&amp; simple} {&amp; end} " "==TEXT KEEPS: !APILogic-MTrhns4OS9BwTT--SZF{&amp;if 18 &gt; 30 } they still have reserves. 18 {&amp; simple} {&amp; end} " "DEFVAL ENDS" "VAL BEGINS" "==TEXT INPUT: !APILogic-MTrhns4OS9BwTT--SZF{&amp;if 18 &gt; 30 } they still have reserves. 18 {&amp; simple} {&amp; end} " "==TEXT KEEPS: !APILogic-MTrhns4OS9BwTT--SZF" "==IF INPUT: {&amp;if 18 &gt; 30 } they still have reserves. 18 {&amp; simple} {&amp; end} " "====GETCONDITIONS BEGINS" "======CONDITION INPUT: 18 &gt; 30 } they still have reserves. 18 {&amp; simple} {&amp; end} " "======CONDITION OUTPUT: {\"type\":\"&gt;\",\"contents\":[[\"18 \",\"\",\"\",\"18\"],[\"30 \",\"\",\"\",\"30\"]],\"next\":\"\",\"negate\":false}" "====GETCONDITIONS ENDS" "====BUILDING CONTENT: they still have reserves. 18 {&amp; simple} {&amp; end} " "======VAL BEGINS" "========TEXT INPUT: they still have reserves. 18 {&amp; simple} {&amp; end} " "========TEXT KEEPS: they still have reserves. 18 {&amp; simple} " "======VAL ENDS" "====ENDING CONTENT: {&amp; end} " "==IF OUTPUT: {\"type\":\"if\",\"conditions\":[{\"type\":\"&gt;\",\"contents\":[[\"18 \",\"\",\"\",\"18\"],[\"30 \",\"\",\"\",\"30\"]],\"next\":\"\",\"negate\":false}],\"contents\":[{\"type\":\"text\",\"value\":\" they still have reserves. 18 {&amp; simple} \"}],\"else\":{}}" "==TEXT INPUT: " "==TEXT KEEPS: " "VAL ENDS" "DEFVAL BEGINS" "==TEXT INPUT: !APILogic-MTrhnsEenNh5HpWeTgZ{&amp;if 18 &lt; 31 &amp;&amp; 18 &gt; 20} -5 penalty. They feel all of their exertion. 18 {&amp; simple} {&amp; end} " "==TEXT KEEPS: !APILogic-MTrhnsEenNh5HpWeTgZ{&amp;if 18 &lt; 31 &amp;&amp; 18 &gt; 20} -5 penalty. They feel all of their exertion. 18 {&amp; simple} {&amp; end} " "DEFVAL ENDS" "VAL BEGINS" "==TEXT INPUT: !APILogic-MTrhnsEenNh5HpWeTgZ{&amp;if 18 &lt; 31 &amp;&amp; 18 &gt; 20} -5 penalty. They feel all of their exertion. 18 {&amp; simple} {&amp; end} " "==TEXT KEEPS: !APILogic-MTrhnsEenNh5HpWeTgZ" "==IF INPUT: {&amp;if 18 &lt; 31 &amp;&amp; 18 &gt; 20} -5 penalty. They feel all of their exertion. 18 {&amp; simple} {&amp; end} " "====GETCONDITIONS BEGINS" "======CONDITION INPUT: 18 &lt; 31 &amp;&amp; 18 &gt; 20} -5 penalty. They feel all of their exertion. 18 {&amp; simple} {&amp; end} " "======CONDITION OUTPUT: {\"type\":\"&lt;\",\"contents\":[[\"18 \",\"\",\"\",\"18\"],[\"31 \",\"\",\"\",\"31\"]],\"next\":\"&amp;&amp;\",\"negate\":false}" "======CONDITION INPUT: 18 &gt; 20} -5 penalty. They feel all of their exertion. 18 {&amp; simple} {&amp; end} " "======CONDITION OUTPUT: {\"type\":\"&gt;\",\"contents\":[[\"18 \",\"\",\"\",\"18\"],[\"20\",\"\",\"\",\"20\"]],\"next\":\"\",\"negate\":false}" "====GETCONDITIONS ENDS" "====BUILDING CONTENT: -5 penalty. They feel all of their exertion. 18 {&amp; simple} {&amp; end} " "======VAL BEGINS" "========TEXT INPUT: -5 penalty. They feel all of their exertion. 18 {&amp; simple} {&amp; end} " "========TEXT KEEPS: -5 penalty. They feel all of their exertion. 18 {&amp; simple} " "======VAL ENDS" "====ENDING CONTENT: {&amp; end} " "==IF OUTPUT: {\"type\":\"if\",\"conditions\":[{\"type\":\"&lt;\",\"contents\":[[\"18 \",\"\",\"\",\"18\"],[\"31 \",\"\",\"\",\"31\"]],\"next\":\"&amp;&amp;\",\"negate\":false},{\"type\":\"&gt;\",\"contents\":[[\"18 \",\"\",\"\",\"18\"],[\"20\",\"\",\"\",\"20\"]],\"next\":\"\",\"negate\":false}],\"contents\":[{\"type\":\"text\",\"value\":\" -5 penalty. They feel all of their exertion. 18 {&amp; simple} \"}],\"else\":{}}" "==TEXT INPUT: " "==TEXT KEEPS: " "VAL ENDS" "DEFVAL BEGINS" "==TEXT INPUT: !APILogic-MTrhnsRxjUjQqjD05l9{&amp;if 18 &lt; 21 &amp;&amp; 18 &gt; 11} -10 penalty. They could use a rest. 18 {&amp; simple} {&amp; end} " "==TEXT KEEPS: !APILogic-MTrhnsRxjUjQqjD05l9{&amp;if 18 &lt; 21 &amp;&amp; 18 &gt; 11} -10 penalty. They could use a rest. 18 {&amp; simple} {&amp; end} " "DEFVAL ENDS" "VAL BEGINS" "==TEXT INPUT: !APILogic-MTrhnsRxjUjQqjD05l9{&amp;if 18 &lt; 21 &amp;&amp; 18 &gt; 11} -10 penalty. They could use a rest. 18 {&amp; simple} {&amp; end} " "==TEXT KEEPS: !APILogic-MTrhnsRxjUjQqjD05l9" "==IF INPUT: {&amp;if 18 &lt; 21 &amp;&amp; 18 &gt; 11} -10 penalty. They could use a rest. 18 {&amp; simple} {&amp; end} " "====GETCONDITIONS BEGINS" "======CONDITION INPUT: 18 &lt; 21 &amp;&amp; 18 &gt; 11} -10 penalty. They could use a rest. 18 {&amp; simple} {&amp; end} " "======CONDITION OUTPUT: {\"type\":\"&lt;\",\"contents\":[[\"18 \",\"\",\"\",\"18\"],[\"21 \",\"\",\"\",\"21\"]],\"next\":\"&amp;&amp;\",\"negate\":false}" "======CONDITION INPUT: 18 &gt; 11} -10 penalty. They could use a rest. 18 {&amp; simple} {&amp; end} " "======CONDITION OUTPUT: {\"type\":\"&gt;\",\"contents\":[[\"18 \",\"\",\"\",\"18\"],[\"11\",\"\",\"\",\"11\"]],\"next\":\"\",\"negate\":false}" "====GETCONDITIONS ENDS" "====BUILDING CONTENT: -10 penalty. They could use a rest. 18 {&amp; simple} {&amp; end} " "======VAL BEGINS" "========TEXT INPUT: -10 penalty. They could use a rest. 18 {&amp; simple} {&amp; end} " "========TEXT KEEPS: -10 penalty. They could use a rest. 18 {&amp; simple} " "======VAL ENDS" "====ENDING CONTENT: {&amp; end} " "==IF OUTPUT: {\"type\":\"if\",\"conditions\":[{\"type\":\"&lt;\",\"contents\":[[\"18 \",\"\",\"\",\"18\"],[\"21 \",\"\",\"\",\"21\"]],\"next\":\"&amp;&amp;\",\"negate\":false},{\"type\":\"&gt;\",\"contents\":[[\"18 \",\"\",\"\",\"18\"],[\"11\",\"\",\"\",\"11\"]],\"next\":\"\",\"negate\":false}],\"contents\":[{\"type\":\"text\",\"value\":\" -10 penalty. They could use a rest. 18 {&amp; simple} \"}],\"else\":{}}" "==TEXT INPUT: " "==TEXT KEEPS: " "VAL ENDS" "DEFVAL BEGINS" "==TEXT INPUT: !APILogic-MTrhoS52k6gmIA_7hFS{&amp;if 17 &gt; 30 } they still have reserves. 17 {&amp; simple} {&amp; end} " "==TEXT KEEPS: !APILogic-MTrhoS52k6gmIA_7hFS{&amp;if 17 &gt; 30 } they still have reserves. 17 {&amp; simple} {&amp; end} " "DEFVAL ENDS" "VAL BEGINS" "==TEXT INPUT: !APILogic-MTrhoS52k6gmIA_7hFS{&amp;if 17 &gt; 30 } they still have reserves. 17 {&amp; simple} {&amp; end} " "==TEXT KEEPS: !APILogic-MTrhoS52k6gmIA_7hFS" "==IF INPUT: {&amp;if 17 &gt; 30 } they still have reserves. 17 {&amp; simple} {&amp; end} " "====GETCONDITIONS BEGINS" "======CONDITION INPUT: 17 &gt; 30 } they still have reserves. 17 {&amp; simple} {&amp; end} " "======CONDITION OUTPUT: {\"type\":\"&gt;\",\"contents\":[[\"17 \",\"\",\"\",\"17\"],[\"30 \",\"\",\"\",\"30\"]],\"next\":\"\",\"negate\":false}" "====GETCONDITIONS ENDS" "====BUILDING CONTENT: they still have reserves. 17 {&amp; simple} {&amp; end} " "======VAL BEGINS" "========TEXT INPUT: they still have reserves. 17 {&amp; simple} {&amp; end} " "========TEXT KEEPS: they still have reserves. 17 {&amp; simple} " "======VAL ENDS" "====ENDING CONTENT: {&amp; end} " "==IF OUTPUT: {\"type\":\"if\",\"conditions\":[{\"type\":\"&gt;\",\"contents\":[[\"17 \",\"\",\"\",\"17\"],[\"30 \",\"\",\"\",\"30\"]],\"next\":\"\",\"negate\":false}],\"contents\":[{\"type\":\"text\",\"value\":\" they still have reserves. 17 {&amp; simple} \"}],\"else\":{}}" "==TEXT INPUT: " "==TEXT KEEPS: " "VAL ENDS" "DEFVAL BEGINS" "==TEXT INPUT: !APILogic-MTrhoSDx8mpwBVI_-ZT{&amp;if 17 &lt; 31 &amp;&amp; 17 &gt; 20} -5 penalty. They feel all of their exertion. 17 {&amp; simple} {&amp; end} " "==TEXT KEEPS: !APILogic-MTrhoSDx8mpwBVI_-ZT{&amp;if 17 &lt; 31 &amp;&amp; 17 &gt; 20} -5 penalty. They feel all of their exertion. 17 {&amp; simple} {&amp; end} " "DEFVAL ENDS" "VAL BEGINS" "==TEXT INPUT: !APILogic-MTrhoSDx8mpwBVI_-ZT{&amp;if 17 &lt; 31 &amp;&amp; 17 &gt; 20} -5 penalty. They feel all of their exertion. 17 {&amp; simple} {&amp; end} " "==TEXT KEEPS: !APILogic-MTrhoSDx8mpwBVI_-ZT" "==IF INPUT: {&amp;if 17 &lt; 31 &amp;&amp; 17 &gt; 20} -5 penalty. They feel all of their exertion. 17 {&amp; simple} {&amp; end} " "====GETCONDITIONS BEGINS" "======CONDITION INPUT: 17 &lt; 31 &amp;&amp; 17 &gt; 20} -5 penalty. They feel all of their exertion. 17 {&amp; simple} {&amp; end} " "======CONDITION OUTPUT: {\"type\":\"&lt;\",\"contents\":[[\"17 \",\"\",\"\",\"17\"],[\"31 \",\"\",\"\",\"31\"]],\"next\":\"&amp;&amp;\",\"negate\":false}" "======CONDITION INPUT: 17 &gt; 20} -5 penalty. They feel all of their exertion. 17 {&amp; simple} {&amp; end} " "======CONDITION OUTPUT: {\"type\":\"&gt;\",\"contents\":[[\"17 \",\"\",\"\",\"17\"],[\"20\",\"\",\"\",\"20\"]],\"next\":\"\",\"negate\":false}" "====GETCONDITIONS ENDS" "====BUILDING CONTENT: -5 penalty. They feel all of their exertion. 17 {&amp; simple} {&amp; end} " "======VAL BEGINS" "========TEXT INPUT: -5 penalty. They feel all of their exertion. 17 {&amp; simple} {&amp; end} " "========TEXT KEEPS: -5 penalty. They feel all of their exertion. 17 {&amp; simple} " "======VAL ENDS" "====ENDING CONTENT: {&amp; end} " "==IF OUTPUT: {\"type\":\"if\",\"conditions\":[{\"type\":\"&lt;\",\"contents\":[[\"17 \",\"\",\"\",\"17\"],[\"31 \",\"\",\"\",\"31\"]],\"next\":\"&amp;&amp;\",\"negate\":false},{\"type\":\"&gt;\",\"contents\":[[\"17 \",\"\",\"\",\"17\"],[\"20\",\"\",\"\",\"20\"]],\"next\":\"\",\"negate\":false}],\"contents\":[{\"type\":\"text\",\"value\":\" -5 penalty. They feel all of their exertion. 17 {&amp; simple} \"}],\"else\":{}}" "==TEXT INPUT: " "==TEXT KEEPS: " "VAL ENDS" "DEFVAL BEGINS" "==TEXT INPUT: !APILogic-MTrhoSQcMa38oATh9Fg{&amp;if 17 &lt; 12 &amp;&amp; 17 &gt; 5} -30 penalty. They are exhausted. 17 {&amp; simple} {&amp; end} " "==TEXT KEEPS: !APILogic-MTrhoSQcMa38oATh9Fg{&amp;if 17 &lt; 12 &amp;&amp; 17 &gt; 5} -30 penalty. They are exhausted. 17 {&amp; simple} {&amp; end} " "DEFVAL ENDS" "VAL BEGINS" "==TEXT INPUT: !APILogic-MTrhoSQcMa38oATh9Fg{&amp;if 17 &lt; 12 &amp;&amp; 17 &gt; 5} -30 penalty. They are exhausted. 17 {&amp; simple} {&amp; end} " "==TEXT KEEPS: !APILogic-MTrhoSQcMa38oATh9Fg" "==IF INPUT: {&amp;if 17 &lt; 12 &amp;&amp; 17 &gt; 5} -30 penalty. They are exhausted. 17 {&amp; simple} {&amp; end} " "====GETCONDITIONS BEGINS" "======CONDITION INPUT: 17 &lt; 12 &amp;&amp; 17 &gt; 5} -30 penalty. They are exhausted. 17 {&amp; simple} {&amp; end} " "======CONDITION OUTPUT: {\"type\":\"&lt;\",\"contents\":[[\"17 \",\"\",\"\",\"17\"],[\"12 \",\"\",\"\",\"12\"]],\"next\":\"&amp;&amp;\",\"negate\":false}" "======CONDITION INPUT: 17 &gt; 5} -30 penalty. They are exhausted. 17 {&amp; simple} {&amp; end} " "======CONDITION OUTPUT: {\"type\":\"&gt;\",\"contents\":[[\"17 \",\"\",\"\",\"17\"],[\"5\",\"\",\"\",\"5\"]],\"next\":\"\",\"negate\":false}" "====GETCONDITIONS ENDS" "====BUILDING CONTENT: -30 penalty. They are exhausted. 17 {&amp; simple} {&amp; end} " "======VAL BEGINS" "========TEXT INPUT: -30 penalty. They are exhausted. 17 {&amp; simple} {&amp; end} " "========TEXT KEEPS: -30 penalty. They are exhausted. 17 {&amp; simple} " "======VAL ENDS" "====ENDING CONTENT: {&amp; end} " "==IF OUTPUT: {\"type\":\"if\",\"conditions\":[{\"type\":\"&lt;\",\"contents\":[[\"17 \",\"\",\"\",\"17\"],[\"12 \",\"\",\"\",\"12\"]],\"next\":\"&amp;&amp;\",\"negate\":false},{\"type\":\"&gt;\",\"contents\":[[\"17 \",\"\",\"\",\"17\"],[\"5\",\"\",\"\",\"5\"]],\"next\":\"\",\"negate\":false}],\"contents\":[{\"type\":\"text\",\"value\":\" -30 penalty. They are exhausted. 17 {&amp; simple} \"}],\"else\":{}}" "==TEXT INPUT: " "==TEXT KEEPS: " "VAL ENDS" "DEFVAL BEGINS" "==TEXT INPUT: !APILogic-MTrhoSdZXpjg8Ldd8IJ{&amp;if 17 &lt; 3} -100 penalty. They are wiped out.. 17 {&amp; simple} {&amp; end} " "==TEXT KEEPS: !APILogic-MTrhoSdZXpjg8Ldd8IJ{&amp;if 17 &lt; 3} -100 penalty. They are wiped out.. 17 {&amp; simple} {&amp; end} " "DEFVAL ENDS" "VAL BEGINS" "==TEXT INPUT: !APILogic-MTrhoSdZXpjg8Ldd8IJ{&amp;if 17 &lt; 3} -100 penalty. They are wiped out.. 17 {&amp; simple} {&amp; end} " "==TEXT KEEPS: !APILogic-MTrhoSdZXpjg8Ldd8IJ" "==IF INPUT: {&amp;if 17 &lt; 3} -100 penalty. They are wiped out.. 17 {&amp; simple} {&amp; end} " "====GETCONDITIONS BEGINS" "======CONDITION INPUT: 17 &lt; 3} -100 penalty. They are wiped out.. 17 {&amp; simple} {&amp; end} " "======CONDITION OUTPUT: {\"type\":\"&lt;\",\"contents\":[[\"17 \",\"\",\"\",\"17\"],[\"3\",\"\",\"\",\"3\"]],\"next\":\"\",\"negate\":false}" "====GETCONDITIONS ENDS" "====BUILDING CONTENT: -100 penalty. They are wiped out.. 17 {&amp; simple} {&amp; end} " "======VAL BEGINS" "========TEXT INPUT: -100 penalty. They are wiped out.. 17 {&amp; simple} {&amp; end} " "========TEXT KEEPS: -100 penalty. They are wiped out.. 17 {&amp; simple} " "======VAL ENDS" "====ENDING CONTENT: {&amp; end} " "==IF OUTPUT: {\"type\":\"if\",\"conditions\":[{\"type\":\"&lt;\",\"contents\":[[\"17 \",\"\",\"\",\"17\"],[\"3\",\"\",\"\",\"3\"]],\"next\":\"\",\"negate\":false}],\"contents\":[{\"type\":\"text\",\"value\":\" -100 penalty. They are wiped out.. 17 {&amp; simple} \"}],\"else\":{}}" "==TEXT INPUT: " "==TEXT KEEPS: " "VAL ENDS"
1613762909

Edited 1613837096
timmaugh
Pro
API Scripter
Sorry, John... R20 went a little sideways last night and limited my ability to test this issue. That log looks right, and this morning I did confirm that even with the bar linked to an attribute, I am getting consistent results. I do occasionally got absolutely no return with your macro, but I think that is Roll20 burping on so many chat messages being sent so rapidly (meaning, I never got wrong results, I just got no results at all). I changed your macro to give each IF statement an ELSE as well, just to report that the value wasn't in the specified range. That should have given me a chat message return for each line, with all but one of them being of the "Not in this range" sort: !{&amp;if @{selected|bar1} &gt; 30 } they still have reserves.{&amp; else}This wasn't over 30.{&amp; end} @{selected|bar1}{&amp; simple} !{&amp;if @{selected|bar1} &lt; 31 &amp;&amp; @{selected|bar1} &gt; 20} -5 penalty. They feel all of their exertion.{&amp; else}This wasn't between 21 and 30.{&amp; end} @{selected|bar1}{&amp; simple} !{&amp;if @{selected|bar1} &lt; 21 &amp;&amp; @{selected|bar1} &gt; 11} -10 penalty. They could use a rest.{&amp; else}This wasn't between 12 and 20.{&amp; end} @{selected|bar1}{&amp; simple} !{&amp;if @{selected|bar1} &lt; 12 &amp;&amp; @{selected|bar1} &gt; 5} -30 penalty. They are exhausted.{&amp; else}This wasn't between 6 and 11.{&amp; end} @{selected|bar1}{&amp; simple} !{&amp;if @{selected|bar1} &lt; 6 &amp;&amp; @{selected|bar1} &gt; 2} -60 penalty. They are totally exhausted.{&amp; else}This was not between 3 and 5.{&amp; end} @{selected|bar1}{&amp; simple} !{&amp;if @{selected|bar1} &lt; 3} -100 penalty. They are wiped out.{&amp; else}This was not under 3.{&amp; end} @{selected|bar1}{&amp; simple} Doing that, I sometimes got 6 statements output to chat, and other times less. The input was the same, and APIL was handling it the same, but R20 was eating some of the outputs. I will look what exactly is happening there. For now, I suggest you change your macro to be this single IF statement with branched ELSEIF portions: !{&amp;if @{selected|bar1} &gt; 30 } they still have reserves.{&amp; elseif&nbsp; @{selected|bar1} &lt; 31 &amp;&amp;&nbsp; @{selected|bar1} &gt; 20} -5 penalty. They feel all of their exertion.{&amp; elseif&nbsp; @{selected|bar1} &lt; 21 &amp;&amp;&nbsp; @{selected|bar1} &gt; 11} -10 penalty. They could use a rest.{&amp; elseif&nbsp; @{selected|bar1} &lt; 12 &amp;&amp;&nbsp; @{selected|bar1} &gt; 5} -30 penalty. They are exhausted.{&amp; elseif&nbsp; @{selected|bar1} &lt; 6 &amp;&amp;&nbsp; @{selected|bar1} &gt; 2} -60 penalty. They are totally exhausted.{&amp; elseif @{selected|bar1} &lt; 3} -100 penalty. They are wiped out.{&amp; else}This was not under 3.{&amp; end} @{selected|bar1}{&amp; simple} With that, I never got a non-return. I am also working on an update to APIL that is in beta, right now. I will incorporate anything I can learn about how to stop Roll20 stepping on some of these outputs... but I will also implement the ability to have multiline structures, so that you could instead have a nice-looking macro, like: !{{ &nbsp;&nbsp;&nbsp;&nbsp;{&amp;if @{selected|bar1} &gt; 30 } they still have reserves. &nbsp;&nbsp;&nbsp;&nbsp;{&amp; elseif&nbsp; @{selected|bar1} &lt; 31 &amp;&amp;&nbsp; @{selected|bar1} &gt; 20} -5 penalty. They feel all of their exertion. &nbsp;&nbsp;&nbsp;&nbsp;{&amp; elseif&nbsp; @{selected|bar1} &lt; 21 &amp;&amp;&nbsp; @{selected|bar1} &gt; 11} -10 penalty. They could use a rest. &nbsp;&nbsp;&nbsp;&nbsp;{&amp; elseif&nbsp; @{selected|bar1} &lt; 12 &amp;&amp;&nbsp; @{selected|bar1} &gt; 5} -30 penalty. They are exhausted. &nbsp;&nbsp;&nbsp;&nbsp;{&amp; elseif&nbsp; @{selected|bar1} &lt; 6 &amp;&amp;&nbsp; @{selected|bar1} &gt; 2} -60 penalty. They are totally exhausted. &nbsp;&nbsp;&nbsp;&nbsp;{&amp; elseif @{selected|bar1} &lt; 3} -100 penalty. They are wiped out. &nbsp;&nbsp;&nbsp;&nbsp;{&amp; else}This was not under 3. &nbsp;&nbsp;&nbsp;&nbsp;{&amp; end} @{selected|bar1}{&amp; simple} }} (note, something like this won't work, yet)
1613933194
Yeah I was doing it separate as you had concluded to make it easier to read.&nbsp; Easy to miss a thing for those chained if statements.&nbsp; I'll be paying attention for an update and try your suggested changes.&nbsp; Thank you..
1614037681
I found this in the script library (and was super excited! this is awesome) but that version didn't seem to be working. On restart the API output console said it was failing to load APIlogic and Libline.&nbsp; Pasting in the version from your repo works fine, but the script library dropdown version is producing these failures: Failed to load libInline No such file or directory @ rb_sysopen - /home/symbly/www/d20-app/apiscripts/libInline/1.0.0/libInline.js Failed to load APILogic No such file or directory @ rb_sysopen - /home/symbly/www/d20-app/apiscripts/APILogic/1.0.0/APILogic.js
1614038124
timmaugh
Pro
API Scripter
Happy to hear a script fills a need for someone! But, sadly, yep... there was a problem with that version, and no merge of the R20 Git Repo last week that would get the corrected version in place... so we're still waiting on this week's merge to happen before the 1-click should work. Also, there's a newer version in beta currently which should be released probably with next week's merge, so there will be more functionality coming with that!
1614042329
It is deeply cool. Perfect for my current project. I'm having some issues where inline rolls, like [[1d20]] are causing the sandbox to crash. It seems to crash with any double bracket. (even simple math like [[@{mod} -1]] or [[2-1]]. For instance my test macro: !{&amp; if [[1d6]] &gt; 1 } Yes {&amp;else} No&nbsp; {&amp; end} {&amp; simple} Yields these errors in the console: ReferenceError: preserved is not defined ReferenceError: preserved is not defined at apiscript.js:1271:138 at String.replace (&lt;anonymous&gt;) at apiscript.js:1271:67 at Array.forEach (&lt;anonymous&gt;) at resolveCondition (apiscript.js:1267:24) at c.tokens.reduce.value (apiscript.js:1324:29) at Array.reduce (&lt;anonymous&gt;) at areConditionsTruthy (apiscript.js:1309:30) at apiscript.js:1349:49 at Array.reduce (&lt;anonymous&gt;) Only apilogic and libline are enabled.&nbsp;
1614045574
timmaugh
Pro
API Scripter
My apologies, but thanks for catching that. I have updated it at my repo and in the pending 1-click merge. The problem was that at one point I had gone from using a single, script-scoped object to track the building message, to using a locally scoped object for the message and a script-scoped library of message objects from which the local one would draw information. This particular error was one place I had not caught where the old style of reference was still in use. I have tested your line, though, and it works for me. Again, apologies!
1614045683
timmaugh
Pro
API Scripter
Version 1.1.3 Released (Updated at Original Link and pending One-Click) Release Date: Feb 22, 2021 FIXED : Bug where text conditions with inline rolls were not properly accessing the parsed inline roll data (see Austin's error, just above). This is corrected, now.
1614087063

Edited 1614089499
timmaugh
Pro
API Scripter
@John B... Aaron and I did a bunch of testing last night, and we determined that there is a Roll20 bug dealing with chat commands with many individual commands in it. Though it sometimes sends all the commands in the chat message, Roll20 is consistently dropping a non-zero number of those individual commands. (This seems to be something fairly recent, since Aaron has a popular Walls script which would have you copy and paste in a hundred or more individual calls in the same message, and people would have let him know if something was going wrong.) I will get the multi-line ability added in to the APIL beta (planning to release that next week) which would let you have nicely formatted, more readable macros... but for now (or at least until Roll20 gets the bug tracked down), the best option is to write your multi-condition APIL test as a single line. Aaron has notified the devs of the bug. I'm going to open a thread on the bug forum for the benefit of other people to know that this issue might be going on, and might be the cause of why a part of their macro doesn't work properly. That thread will have a small repro script, if you want to see it for yourself.
1614094034
Oh that sounds great.&nbsp; Sounds like one heck of a challenging bug to nail down.&nbsp; Greatly Appetited @timmaugh&nbsp;
1614094511
The Aaron
Forum Champion
API Scripter
On the bright side, it's very easy to reproduce. =D
1615298329

Edited 1615299074
timmaugh
Pro
API Scripter
Version 1.2.0 Released (Updated at original link and pending one-click) Date: 3/9/2021 Added: MULE tag allows for variable getting and setting, storing data between calls. Added: MATH tag allows for real-time, inline math processing using sheet items, variables, math constants, functions, and basic operations (+,-,/,*,%) Added: EVAL and EVAL- tags allow for 3rd party scripters to plugin functionality to ride the APILogic train and retrieve data formatted to be in the command line. Added: APILogic will now work with multiline macros (the sort housed in {{ }} ) This is a huge update, with a lot of new features. The larger write-up of the instructions is over at the APILogic wiki article , but let me highlight a bit of the new things you can do -- and all in other scripts! Using the MULE Tag (get/set variables) Mules are abilities on a character sheet that can help you track information across rolls, game sessions, or even, since they are stored on the sheet, campaigns. This could be an inventory, a series of condition mods, roll history, or even tables from a game system. You can have as many mules as you want on any character, and you can access any mule on any character you control. You can create a mule ability yourself, though if APILogic detects that the mule you have created doesn’t exist, it will try to create it. Mules are formatted as lines of&nbsp; variable=value : initMod=4 FavTeamMember=Mo the Raging LeastFavoriteTeamMember=Lizzie PurePants Any lines that do not follow this format are not included in the set of parsed variables, so you if you wanted to add add in headers or grouping, you can: === MODS === initMod=4 === TEAM DYNAMICS === FavTeamMember=Mo the Raging LeastFavoriteTeamMember=Lizzie PurePants But be aware that if a variable does not exist, APILogic will create it, and it will create it at the bottom of the list. You can move it later without causing a problem, or you can leave it there. In fact, maybe you want an&nbsp; === UNCATEGORIZED === &nbsp;section. It’s up to you. Naming Obviously, since a Mule is a character sheet ability, it cannot contain a space in the name. Variable names may not contain spaces or an equals, though the value of the variable is free to be whatever you can fit on one line. Later, you will see how APILogic uses dot-notation to refer to&nbsp; character.mule.variable . You can continue this notation within your mule if you wanted to store similarly-named variables in the same mule but differentiate them from each other. For instance, if you wanted a table of EncumbranceMods (with the Encumbrance a character is carrying related as 0, 1, 2, etc.) in the same Mule as you wanted to store a table of FatigueMods (also in 0, 1, 2, etc.), you might use dot-notation in the names: EncMods.0=0 EncMods.1=0 EncMods.2=-1 EncMods3=-1.5 ...etc. FtgMods.0=1 FtgMods.1=1 FtgMods.2=1.1 ...etc. Though it might make more sense to store this information in separate Mules. Loading a Mule Use the&nbsp; {&amp; mule ... } &nbsp;tag to load Mules and make their variables available for you in your command line. Mule retrieval happens before variable retrieval, so it doesn’t matter where in your line you put your Mule statement. !somescript --stuff {&amp; mule ModMule} --tacos You can load multiple Mules in the same statement just by separating them with a space. Also, APILogic uses a “least common reference” (LCR) to identify the Mules to load… meaning that if you control two characters who each have a Mule named “ModMule”,&nbsp; both &nbsp;will be loaded by the above statement (see below how to reference their variables independently). To load a “ModMule” Mule from only one character, use the dot notation: {&amp; mule Viper.ModMule} Getting a Variable Once you have one or more Mules loaded, you can use a&nbsp; get.varname &nbsp;to retrieve it in your command: !somescript --mod|get.initMod {&amp; mule Viper.ModMule} The&nbsp; get &nbsp;statement can take these forms: get.varname get.mulename.varname get.character.mulename.varname When a variable is loaded from a Mule, it takes over the location for that variable name, that mule.variable name, and that character.mule.variable name. That means that the least specific reference ( get.varname ) will always be filled with the&nbsp; last &nbsp;variable of that name to be found, and the&nbsp; get.mulename.varname &nbsp;version will always be filled with that variable from the last mule of that name to be found. EXAMPLE: Naming Precedence You load the Mule “MyLittleMule” using the statement: {&amp; mule MyLittleMule} However, you have two characters, Viper and Jester, who each have a MyLittleMule attribute. Viper’s looks like this: initMod=4 EncMod=5 motto=There's no time to think! bestrecent=20 Jester’s looks like this: initMod=3 EncMod=3 Motto=Where'd who go? If Viper loads before Jester, the map of variable reference would look like this: VARIABLE REFERENCE | CHAR | VALUE -----------------------------------|--------|----------------------------- get.initMod | Jester | 3 get.EncMod | Jester | 3 get.motto | Viper | There's no time to think! get.Motto | Jester | Where'd who go? get.bestrecent | Viper | 20 get.MyLittleMule.initMod | Jester | 3 get.MyLittleMule.EncMod | Jester | 3 get.MyLittleMule.motto | Viper | There's no time to think! get.MyLittleMule.Motto | Jester | Where'd who go? get.MyLittleMule.bestrecent | Viper | 20 get.Jester.MyLittleMule.initMod | Jester | 3 get.Jester.MyLittleMule.EncMod | Jester | 3 get.Jester.MyLittleMule.Motto | Jester | Where'd who go? get.Viper.MyLittleMule.initMod | Viper | 4 get.Viper.MyLittleMule.EncMod | Viper | 5 get.Viper.MyLittleMule.motto | Viper | There's no time to think! get.Viper.MyLittleMule.bestrecent | Viper | 20 Note that the variables are case-sensitive (“motto” vs “Motto”), and that it is only when you arrive at a unique piece of identifying data (in this case, the character name) that you are able to differentiate between the similarly named (and/or similarly-muled) variables. The point is, you should use the LCR guaranteed to get you the variable you intend to retrieve, but if you have only one Mule, you can use the simplest form for every variable. Setting a Variable’s Value Set a variable’s value using the text formation&nbsp; set.varname = value /set . The implication of the LCR during setting is that all less-specific references to the variable are set, across all Mules, and among the available ways of referencing that variable. In the above example (Jester and Viper having similarly named Mules), the following statement: set.initMod = 8 …will set the initMod variable in both Mules to be the same value, 8. In fact, using the Mule name in the set statement would still result in both Mules being updated, since the name is shared between them. The only way to set only one of the variables would be to fully qualify the name with the character’s name: set.Viper.MyLittleMule.initMod = 8 In setting that value, the less specific ways of referring to the variable ( get.initMod &nbsp;and&nbsp; get.MyLittleMule.initMod ) are also set, so that further references to these during this cycle of APILogic evaluating the command line will retrieve the new value. Although setting variables comes at the end of the cycle of operations, remember that the APILogic process is a loop, so there can be further references when the whole thing starts again (see both&nbsp; Escaping Text (Deferring Processing) &nbsp;and&nbsp; Order of Operations ). Using the MATH Tag Using the MATH tag, you can drop real-time, inline math calculations into your macro command to have the value rendered before the message is handed off to the intended script. The MATH tag is denoted by the&nbsp; {&amp; math ... } &nbsp;formation, where the equation to evaluate follows the tag name: {&amp; math (2+3)/4} The above would output 1.25. You can use numbers, parentheses, known constants, mule variables, inline rolls or roll markers, and math functions as operands in + , - , * , / , and&nbsp;% (modulo) operations (exponentiation is handled in a function): {&amp; math round(sin(90) * pi, 2) / randb(0,4) } The above rounds (to 2 decimal places), the sine of 90 multiplied by pi, then divides that by a random number between 0 and 4. Mule Variables All variables from all loaded mules are made available to the math processor directly, without the need of using the&nbsp; get &nbsp;statement. Of course, since mules are loaded (and variables retrieved) before equations are handed off to the math processor, using the&nbsp; get &nbsp;statement will still work. You just don’t have to use it in a MATH tag’s equation. If you have a variable named 'ArmorMod, then the following are functionally equivalent: {&amp; math ArmorMod + 4} {&amp; math get.ArmorMod + 4} Functions Most of the javascript Math functions are exposed for you, as well as some that were added to answer common requirements. These include things like round (with a decimal places argument), ceiling, floor, min, max, random, random between, random among, absolute value, square root, cube root, and more. To use them, include the specified name followed by an open parentheses and any arguments as necessary before supplying a closing parentheses. Functions are nestable. For a full list of functions included in the math processor, see&nbsp; APPENDIX III . Constants The following constants are available as part of the math processor: e &nbsp;- Euler’s number (javascript: Math.E) pi &nbsp;- Pi (javascript: Math.PI) lntwo &nbsp;- Natural log of 2 (javascript: Math.LN2) lnten &nbsp;- Natural log of 10 (javascript: Math.LN10) logtwoe &nbsp;- Base 2 log of e (javascript: Math. LOG2E) logtene &nbsp;- Base 10 log of e (javascript: Math.LOG10E) Constants take priority over Mule variables of the same name, therefore if you have reason to store a variable under the name ‘pi’, for instance, you can only reach it within the math processor by a more specific LCR – including the Mule or Character.Mule information. Using the EVAL and EVAL- Tags EVAL tags are new to version 1.2.0, and represent a way to plug more processing power into the inline parsing engine of APILogic. EVAL tags can run plugin scriptlets (or even other scripts) from your existing command line. The advantage of plugging the scriptlet into APILogic is that it can sub the returned data into your command line in real time! Although APILogic includes a library with a few built-in functions, the real strength of the EVAL tag is that 3rd-party scripters (or even you) can write plugable scriptlets to allow this real-time return of game data to your command line. Need a PageID? Write a script and plug it in. Need the closest X number of tokens to a given token? Or all of the tokens within some given range? Write a script! (Or buy your local scripter a coffee and have them write it for you!) EVAL tags are represented by&nbsp; {&amp; eval} ... {&amp; /eval} , while EVAL- tags are represented by&nbsp; {&amp; eval-} ... {&amp; /eval-} . The difference between them is only one of timing: the EVAL tag runs after MULE tags but before DEFINE tags, while the EVAL- tag runs after the DEFINE tags but before the IF tags (see&nbsp; Order of Operations , below, for a fuller discussion of the order of parsing). A full EVAL block would be structured like this: {&amp; eval} scriptname(arguments for script){&amp; /eval} OR {&amp; eval} scriptname arguments for script{&amp; /eval} OR {&amp; eval}&nbsp;!scriptname arguments for script{&amp; /eval} The&nbsp; scriptname &nbsp;can represent one of the library of plugin scriptlets, or it could be another script in the game. Everything between the parentheses is passed to that script as arguments. Use the first form when you want to access a plug-in designed to return information to the line. Plug-ins are built very similarly to normal scripts, and in fact a fully-fledged script can be co-opted to return a value, if the developer wishes. More on building plugins is in&nbsp; APPENDIX I . The last two forms are functionally the same as each other (the third line simply includes the leading exclamation point), but they differ from the first form in that they do not return anything to the command line. These forms are intended solely for launching other scripts (not plugins) that have nothing to do with returning a value to the command line. The EVAL tag will launch the other script and consume itself, leaving a zero-length footprint behind. EXAMPLE: All tokens in range Your character has an attack spell that affects anyone within some given range. Your scripter friend writes a script that returns the IDs of all tokens within that range, telling you that to use it, you would use a command syntax of: !withinrange range source delimiter So a typical call might be: !withinrange 3 -M1234567890abcdef , …returning a comma-separated list of tokens within 3 units of the given source token. Your scripter friend also tells you that they have built it as a plug-in for APILogic, so now you can use the same scriptlet in-line with another command to substitute in that comma-separated list: !some-other-script --targets|{&amp; eval}withinrange(3 -M1234567890abcdef ,){&amp; /eval} --damage|tons By the time&nbsp; some-other-script &nbsp;picks up the message, the EVAL tag has been evaluated and now contains the comma-separated list of tokens within the given 3 unit range. Nest-able EVAL tags are nest-able, and are processed from inside-out, allowing you to use one EVAL tag to return a piece of data that would be used as an argument in an enclosing EVAL tag: {&amp; eval}withinrange({&amp; eval}getsheetitem(*|Bob the Slayer|spells|[spell_name=Supernova]|spell_lvl){&amp; /eval} -M1234567890abcdef ,{&amp; /eval} In that example, the&nbsp; spell_lvl &nbsp;of the Supernova spell is the range. The inner EVAL tag block retrieves the data by use of the built-in&nbsp; getsheetitem &nbsp;scriptlet, and passes it to the outer EVAL block’s&nbsp; withinrange &nbsp;scriptlet. Available Built-In Scriptlet Functions At the time of writing this, there are two built-in functions, with more coming: getDiceByVal() &nbsp;will retrieve dice from an inline roll that match a given set of value parameters (i.e., 2|5-6|&gt;=10). Output options are a count of the dice, a total of the dice, or a list separated by a delimiter of your choice. More info on the syntax is in Appendix II . getDiceByPos() &nbsp;will retrieve dice from an inline roll based on the position of the dice based on a set of position parameters (i.e., 2|5-6|&gt;=10). Output options are a count of the dice, a total of the dice, or a list separated by a delimiter of your choice. More info on the syntax is in&nbsp; APPENDIX II . Installing 3rd Party Scriptlets If you or your local scripter has written a scriptlet to plug into APILogic (which is easy enough to do – see&nbsp; APPENDIX I , below), you only need to install it as you would any other script. Provided the script author implemented the syntax to register that scriptlet with APILogic, it will be available to you as soon as your sandbox restarts.
1615327825
timmaugh
Pro
API Scripter
Version 1.2.1 Released (Updated at original link and pending one-click) Date: 3/9/2021 Fixed: Bug that presented on sandbox reboot after install; bug owed to a late combination of the code, rolling in the plugins library and the logic engine into a single file.
Hey timmaugh, I noticed yesterday that {&amp; define} doesn't seem to be working properly anymore. Idk if it's a side effect of the recent sheet updates, but all the commands I'd set up using that function now return the defined string as nothing. So when used with ChatSetAttr, for example, instead of changing a value in a repeating row, it creates a nameless attribute on the sheet with the new value. Here's an example command button: [Prepare](!setattr --charid @{character_id} --spellslot|&amp;quest;{Set as&amp;vert;prepared,1&amp;vert;unprepared,0}&nbsp;--fb-header --fb-from @{character_name} {&amp;amp; define ([spellslot] &amp;ast;name|@{character_name}|cantrip|[name=&amp;quot;@{name}&amp;quot; current_level=@{current_level}]|uses&amp;rpar; }) When clicked, it should give a message like "Setting repeating_cantrip_-[row id]_uses to 1 for character Slashy" and is instead giving "Setting to 1 for character Slashy". These were all working fine a couple weeks ago, and I've been using v1.2.1 of your script since then. Just wondering if you've experienced this in your own uses and/or if you have any idea for a workaround?
1618322628
timmaugh
Pro
API Scripter
Hmm... I installed v1.2.1 and the define tag still seems to work for me: !{&amp; define ([theattr] *name|Heretic|skills|[skill_name~Elder]|skill_name)}The name of the attr is theattr.{&amp;simple} That outputs this to the chat interface: The name of the attr is repeating_skills_-M5sYfPs0x3LgGSdmXC1_skill_name. If you run a similar/simple test with your construction, do you get the proper attribute name? Also, in the pending Meta Toolbox I keep trying to button up to release, the sheet-item-retrieval portion of APILogic has been broken off into its own script (which really doesn't matter when we're talking about meta scripts) called Fetch. It has also been expanded to allow more options (like normally non-retrievable token properties), more references (like "speaker" instead of a character's name or "selected"), and the use of a default value if the thing isn't found. All of that might give you a better ability to zero-in on the item you want if we can't figure out what is going on with v.1.2.1. But first, try breaking off the definition like I did, and make sure you're getting what you should. =D
1618355477

Edited 1618504670
Okay, I've tested that for multiple repeating attributes on multiple characters and I'm getting this each time: The name of the attr is .
Did more testing in other games, even made new games with different sheets. It turns out something about the Pathfinder Second Edition by Roll20 sheet is messing up the script, but I can't figure out what. It had an update recently, and that must be when {&amp;define} stopped working on it...
1618576352
timmaugh
Pro
API Scripter
Well, that's good (and bad) to hear... at least we have a place to start. You could try to XRay the sheet to see if it's just a matter of the nomenclature having changed. I have heard that sheet is a little... different... in a couple of ways, but I've never used it, myself. I will try to set up a game using that sheet, too. Or, if you try to XRay and it looks like what you're doing should really be retrieving the piece of data, you can invite/promote me and I'll check it out in situ. FYI, APILogic is about to get an update (hopefully yet today, if I can get the documentation finished)... where this sheet-retrieval piece will be broken off to its own meta-script. Definitions stay a part of APIL... but that's ok because it all works together. Also as a part of that update the sheet-retrieval gets a few more bells, a skosh of whistles... so those might have an effect, too. =D
XRay seems to be picking up all the attributes in repeating sections just fine! Still no luck with {&amp;define}
1618938039
timmaugh
Pro
API Scripter
APILogic 2.0.0 Released as Meta-Toolbox Script (ZeroFrame) Version 2.0 of the script has been rebuilt to break off certain functionalities and give you more control over the execution order. It is now part of the Meta-Toolbox, meaning it can be used on its own or with the ZeroFrame script. Updated instructions are in the wiki link .