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] SelectManager - update brings !forselected iteration and gives user new control to give selected tokens back to API-generated messages

1613591666

Edited 1614140284
timmaugh
Pro
API Scripter
SelectManager (New) FILES: Submitted to 1-click (until then, find it in my Repo ) SelectManager is a way to preserve the portions of a message that are present in a user-generated message but lost in an api-generated message (the selected tokens, who sent the message, and the playerid). The previous version of this script required the script developer to “opt-in” to use these features, but the new release (v0.0.5) also lets the user take control. With the new version, you can choose to “auto-insert” any or all of the properties into your downstream messages (those initiated by the API). EXAMPLE: You have a PowerCards macro that you build to launch a ChatSetAttr call. Because this is one script calling another, the ChatSetAttr message is generated by the API and the array of selected tokens is lost. Since ChatSetAttr works on the token currently selected, the call won’t work properly. Installing SelectManager, however, will make this situation work, even without a single change to your macro . !forselected Also in this version is a !forselected script handle that will take your existing call to another script and iterate over the selected tokens. So if you have a script that modifies a single token, or takes action based on the properties of a single token and you want to send that same call for multiple tokens at once, you would simply put forselected in front of the existing api handle. More on this, below. A Note on Timing SelectManager now uses the same 0-order trick as APILogic to shin-kick its way to the front of the line of scripts waiting to receive a message. This has been found to work with the vast majority of scripts currently available, but should you find a case where it doesn’t work you should remember that the best way to ensure SelectManager can get to the message-intended-for-another-script before that other script gets it (so that SelectManager can insert the necessary information) is to have it installed before other scripts in the game. !forselected - Iterate Over Selected Tokens Some scripts only process a single token at a time, forcing you to go through the process of selecting a new token, then re-issuing the command if you want to process more than one token in the same way. This can be tedious. With SelectManager installed, you can prepend that call to your other script with forselected and SelectManager will iterate over the selected tokens, sending the same call to the other script but cycling each selected token to hand only one off to each message. Just insert forselected (followed by a space) between the ! and the script handle of the downstream script. EXAMPLE: You want to use ChatSetAttr to set an attribute of a dozen tokens. The line might normally be: !set-attr --strmod|2 Using the forselected method, you would just insert the forselected text into the line: !forselected set-attr --strmod|2 If you have your dozen tokens selected, it will issue a dozen calls to ChatSetAttr, exactly the same except that the first call will see only the first token as selected, the second will see the second token selected, and so on. Special Constructions for Token or Character Sheet Info Anywhere you would use the @{selected|...} construction in a forselected command line, you can use at{selected|...} , instead. This is necessary since the Roll20 parser will eat an @{selected|token_id} structure and spit out the token ID of the first (but only first) selected token, for instance. To make sure these process for each selected token in turn, you should replace the @ version with the at version. SelectManager will detect these and retrieve the requested information for the current token in the cycle. See the Roll20 Wiki article on what information can be retrieved from a Token this way. Special Cases for token_id and token_name The most commonly utilized @{selected} requests are for the token_id and token_name, so to minimize how much you would have to alter your command line (beyond just inserting forselected at the start) to iterate over selected tokens, these two properties have been promoted to have special triggers. Use a + or a - immediately following the forselected to control whether to replace any reference to the result of an @{selected|token_id} call with the ID of the next token in the cycle. Use another + or - immediately following that to control whether to replace any result of the @{selected|token_name} call with the name of the next token in the cycle. These default to being “on,” meaning that references in the command line that match the token ID of the first selected token will be replaced with the token ID of the next in line. The same goes for the token name references. Therefore, you would typically use the handles to turn off this behavior. !forselected // replaces both (token ID and token name) !forselected+ // replaces both !forselected++ // replaces both !forselected- // token ID = OFF, token name = ON !forselected-+ // token ID = OFF, token name = ON !forselected+- // token ID = ON, token name = OFF !forselected-- // token ID = OFF, token name = OFF Use these in conjunction with the at{selected|...} formations to control what information is retrieved and when. For instance, if you have a character whose token ID should be referred to in one portion of the command line for every iteration of selected tokens (for instance, she is the “source” of some effect), but that character is also in your selected tokens, you don’t want to potentially automatically replace her ID in the command line: !somescript --source|-MZDKns0sna90an10 --target|@{selected|token_id} When you prepend that statement with forselected , you run the risk that the source character’s token ID will be replaced with every iteration (if she happened to be the FIRST token in the selected array). Instead, turn OFF the auto-replacement of the token ID, and use the at{selected} later in the line: !forselected- somescript --source|-MZDKns0sna90an10 --target|at{selected|token_id} User Opt-In (Auto-Insert) For macro/script calls other than forselected , SelectManager can auto-insert any or all of the three properties that are lost/changed when an API generates the message. Which of the properties SelectManager will auto-insert can be controlled from the chat interface and a few simple switches. Use the !smconfig script handle, followed by a space, and then a + (to turn on) or a - (to turn off) a given auto-insertion. !smconfig +selected // turns on selected auto-insertion !smconfig -who // turns off who auto-insertion !smconfig +playerid // turns on playerid auto-insertion These can be chained in a single line, handling any or all of them in one go: !smconfig +selected +who -playerid Once configured to auto-insert, these properties will be injected into any API-generated message with no other effort on your part. Run the simple command of  !smconfig  to see what you currently have configured for auto-insertion. SOMETHING TO BE AWARE OF:  As it comes, straight out of the box, SelectManager is only configured to auto-insert the selected tokens, and not the who or playerid properties. Before you enable the auto-insertion of the who and playerid properties of the message, think through the scripts in your game. There may be times another script needs to know that it was called by the API instead of a user. Certain scripts may trigger different activities based on who sent the message, and they may do different things if a user generates the call versus another script. For instance, if a script listens to events in the campaign and fires off a call to other scripts, those downstream scripts could very well be configured to know the difference and act accordingly. If you have a question whether a script behaves this way, ask the developer. Remember, even if you don’t tell SelectManager to auto-insert the properties of the message, the developer can still choose to opt-in and make use of SelectManager passively providing the information. Scripter Opt-In Whether or not the user has their installation configured to auto-insert stored pieces of the message, you can configure a script to get the information from SelectManager directly (typically we’re talking about a script’s author, though a user can update a manually-installed script, themselves, while they wait for the author to implement the SelectManager interface; for that sort of implementation, see Option 2: Use-If-Present Model ), below. Option 1: Make Your Script Dependent on SelectManager If you add SelectManager as a dependency to your script in the one-click, you can count on it being there when a user would utilize your script. In that case, you can access the library directly. Once your script has determined that the message should be received and handled by your script, assign whatever required properties to the various message objects. const handleInput = (msg) => { //... script tests for whether to pick up the message, then... if('API' === msg.playerid) { msg.selected = SelectManager.GetSelected(); msg.who = SelectManager.GetWho(); msg.playerid = SelectManager.GetPlayerID(); } //... script continues }; Alternately, instead of three lines, you could handle it with a single line, using deconstruction assignment: [msg.selected, msg.who, msg.playerid] = [SelectManager.GetSelected(), SelectManager.GetWho(), SelectManager.GetPlayerID();] Option 2: Use-If-Present Model If your script isn’t in the one-click or you’re unsure whether the SelectManager library will be installed, you can implement the script using just a few lines in your script’s definition. Note that if SelectManager is not installed for your user, then this method will not actually solve the problem of your script expecting, when called from the API, to be able to access the selected tokens (for example). However, this method allows your script to continue even if SelectManager is not installed, and if your user complains that the script breaks when they call it from another script, you can tell them the easy fix is to get SelectManager installed. The below example shows how to implement the GetSelected() function alone, though it can be expanded to include the others. Add the following two lines to the outer scope: let getSelected = () => {}; on('ready', () => { if(undefined !== typeof SelectManager) getSelected = () => SelectManager.GetSelected(); }); Next, locate the portion of the script that handles the on(‘chat:message’) event and include the following line immediately after the script tests the API handle to determine whether it should begin processing: if('API' === msg.playerid) msg.selected = getSelected(); (note that “msg” should be changed to match the name given to the message object in that procedure). The following example shows the same idea expanded to include all of the scripts: let getSelected = () => {}, getWho = () => {}, getPlayerID = () => {}; on('ready', () => { if(undefined !== typeof SelectManager) { getSelected = () => SelectManager.GetSelected(); getWho = () => SelectManager.GetWho(); getPlayerID = () => SelectManager.GetPlayerID(); } }); And then use those three functions ( getSelected() , getWho() , and getPlayerID() ) to access the data you need. Change Log v0.0.5 - Initial re-release, includes !forselected and 0-order interception allowing user control over auto-insert v0.0.6 ( link ) - Added multi-line downstream support for forselected (if the downstream command had line breaks, it would break, before); also added ability for api to call forselected, so that a third party script can launch a forselected iteration. v0.0.7 ( link ) - Added ability for forselected to work around a second exclamation point (such as: !forselected !set-attr...).
1613674033
David M.
Pro
API Scripter
Hey timmaugh, does SelectManager handle double bracket syntax for subordinate scripts? Doesn't seem to currently? !forselected {{!SomeScript ...a million cmds|args }} And before I get too far into the weeds, Is it true that if subordinate script "1" then called its own subordinate script "2", it would need to use forselected again? Or is this just folly and it would end up triggering the end of all creation? Without going into too many details, I was looking into having a Scriptcards macro fire off my Spawn script, both of which can have a pretty lengthy set of commands. The thought was to use forselected prior to the scriptcard, and then again for Spawn, all in a single ability. Not sure if that thought process would work. When I tried to just use forselected *within* scriptcards it didn't seem to work, even for simple examples. The guess is that the api had already eaten the selected info by the time forselected was called from within scriptcards.
1613677910
timmaugh
Pro
API Scripter
Hey, David... It doesn't handle the double-brackets natively (though it could be easily added), but I wonder if it needs to...? SelectManager just hands off everything downstream of the  forselected  handle to the iterative call... so I *think* all you need to do is to have the double-braces on the inside of the script that *would* parse them properly: !forselected SomeScript{{ ...a million cmds|args }} (You only need the initial exclamation point.) As for your suggested usage (ScriptCards launching a forselected), that's a great point that I will accommodate. Right now the script detects user-generated vs API generated, with the forselected test only happening on the user-generated side (so an api-generated call to forselected will just never be caught). But it's a pretty simple change to make it work (the stored selected, who, and playerid is obviously already available!)... I will break out the forselected test and subsequent code and let it be run from either the user- or api-gen side. On the api-gen side, it will just need to first restore those properties. Once I make that change, your usage case (ScriptCards calls forselected calls Spawn) *should* work. I should be able to get a new version out tonight, then you can give it a try!
1613682180
David M.
Pro
API Scripter
Thanks, Tim! Just tried a few variations using token-mod with very simple syntax with/without brackets. These all work !forselected token-mod --set statusmarkers|blue !forselected token-mod {{--set statusmarkers|blue}} !forselected token-mod {{ --set statusmarkers|blue }} This does not - seems like the line break is the culprit. !forselected token-mod {{ --set statusmarkers|blue }}  
1613682374
timmaugh
Pro
API Scripter
ok... I appreciate the leg work on that! I will add the parsing of the line breaks into the re-release asap.
1613712241

Edited 1613765465
timmaugh
Pro
API Scripter
Version 0.0.6 Released (Updated at Original Link and pending One-Click) Relase Date: Feb 19, 2021 Fixed : Double-braced command lines with line breaks will now work in forselected calls. Use the double-brace syntax within the sub-command forselected will iterate: !forselected token-mod {{ --lots of args --hoocha hoocha hoocha... lobster }} Fixed : API-generated calls to forselected should now be caught and executed appropriately. This addresses David's use case (above) of having ScriptCards issue a downstream command to forselected that would then issue a downstream command to Spawn. !scriptcard {{ --@forselected+|Spawn _name|imp _offset|1,0 --@forselected+|token-mod _set statusmarkers|blue|broken-shield }}
1613718108
keithcurtis
Forum Champion
Marketplace Creator
API Scripter
Very, very nice!
1613736337
David M.
Pro
API Scripter
Ahhhh. Works perfectly, thank you!!!
Man, I have got to start using this script!
1613743646
timmaugh
Pro
API Scripter
Excellent! Let me know if there is any issue. One thing I realized is that it would be good for SelectManager to detect a second exclamation point and handle it. That way, you could have a macro or ability with a particular script call, and easily reference it from chat: For instance, you create a macro named SpawnStuff stored as:  !spawn {{ --things --that go bump }} Chat entered command: !forselected #SpawnStuff Then what reaches the parser is: !forselected !spawn {{ ... I'll build in the ability to detect that second exclamation and work around it. The whole idea is to give you an easy way to iterate an existing command over many tokens! =D
1613765685
timmaugh
Pro
API Scripter
Version 0.0.7 Released (Updated at Original Link and pending One-Click) Relase Date: Feb 19, 2021 Added : Ability to detect and work around a second exclamation point (one that follows the forselected api-handle): !forselected !spawn --things This is necessary if you expand a macro as the source of the downstream, iterated command, and that macro comes in with an exclamation point of its own. (This had to be the absolute SMALLEST update I've ever had to push that wasn't a typo correction. This amounted to adding 2 characters to a regex statement to add this functionality.) =D
1613824585
David M.
Pro
API Scripter
Handy!
Oooh, this might make the Delay script work for me finally! I'm eager to test it out.
1615535662
Hi, I recently stumbled over that great script while playing with token-mod. But I can't get one thing running: I have a multi-sided token with 10 different tokens for trees. I place an amount of them on the map and want to give them a random side. Therefore I tried: !forselected token-mod --set currentside|[[1d10]] This doesn't work. It seems to get stuck somehow, at least nothing happens. If I use a fix number instead of [[1d10]] it works. So there seems to be some issue with the inline roll. Does anybody have an idea how to fix that? Do I have to add some escape characters somewhere? Thanks in advance!
1615556314
timmaugh
Pro
API Scripter
Hi, Bernd... there's a short answer and a slightly longer answer. =D SHORT ANSWER: The short answer is that you might need to install APILogic , too (have it in the order of scripts *after* SelectManager), and then use one of the methods in this post  to defer that inline roll. SLIGHTLY LONGER ANSWER: The slightly longer answer is that SelectManager can iterate over your tokens, but by the time it sees the message, Roll20 has already parsed that inline roll down to a roll marker ($[[0]]). SelectManager doesn't do anything with that roll marker (and the inline roll associated with it) other than pass it along to token-mod, and token-mod should be capable of unpacking that roll marker to get the value within... so when you say "stuck" I'm not sure if you are saying that it doesn't unpack that roll marker to get the value. If that is the issue, let me know and I can investigate if there is some way SelectManager is getting in the way of that. That said, what I think you really want is for every token to have its own individual roll (to have the random side of the token set). Even if token-mod were to parse the roll marker and extract the value of the roll, that value would be the same for all tokens you were iterating over and you would end up with every tree being the same. By using one of the methods in the message I linked (above), APILogic will defer that roll and have it be new for each token.
1615558209

Edited 1615558824
timmaugh said: Hi, Bernd... there's a short answer and a slightly longer answer. =D SHORT ANSWER: The short answer is that you might need to install APILogic , too (have it in the order of scripts *after* SelectManager), and then use one of the methods in this post  to defer that inline roll. SLIGHTLY LONGER ANSWER: The slightly longer answer is that SelectManager can iterate over your tokens, but by the time it sees the message, Roll20 has already parsed that inline roll down to a roll marker ($[[0]]). SelectManager doesn't do anything with that roll marker (and the inline roll associated with it) other than pass it along to token-mod, and token-mod should be capable of unpacking that roll marker to get the value within... so when you say "stuck" I'm not sure if you are saying that it doesn't unpack that roll marker to get the value. If that is the issue, let me know and I can investigate if there is some way SelectManager is getting in the way of that. That said, what I think you really want is for every token to have its own individual roll (to have the random side of the token set). Even if token-mod were to parse the roll marker and extract the value of the roll, that value would be the same for all tokens you were iterating over and you would end up with every tree being the same. By using one of the methods in the message I linked (above), APILogic will defer that roll and have it be new for each token. Thanks for the quick reply. I'll try that! I also tried to accomplish that by using the 'Bulk Macro' option in the VTT Enhancer Suite, which works fine for Initiative etc. But that didn't work either. But I will give it a try with APILogic! :-) UPDATE: oh my. I am really blind. So much easier! Just creating many of these multi-sided tokens, select them and choose 'Multi-sided -> Random Side' from the context menu. That does the trick. No macro-voodoo necessary! :-)
1615612525
David M.
Pro
API Scripter
Oh cool, I didn't realize the context menu worked on multiple selected tokens like that!
1616356239
Having issues getting this to work with ChatSetAttr - the below one-liner works for what I want to a chieve for a single token: !setattr --sel --HP||(@{selected|level}*((@{selected|hitdietype}/2)+@{selected|constitution_mod})+@{selected|constitution_base}) --nocreate --evaluate However, attempting to use forselected with this: !forselected setattr --sel --HP||(at{selected|level}*((at{selected|hitdietype}/2)+at{selected|constitution_mod})+at{selected|constitution_base}) --nocreate --evaluate results in an error: Something went wrong with --evaluate for the character Chuck Testtoken. You were warned. The error message was: SyntaxError: Unexpected token '*'. Attribute HP left unchanged. Replacing that asterisk with a + results in [...] The error message was: SyntaxError: Invalid regular expression: missing /. Attribute HP left unchanged. Likewis,e replacing the /2 with +2 results in [...] The error message was: SyntaxError: Unexpected token ')'. Attribute HP left unchanged. I have SelectManager installed before APILogic, and have tried various permutations based off of the token-mod thread you linked above involving adding various escaped double brackets. Interstingly, surrounding that HP equasion with [\[...]\] and adding the null eval suffix seems to cause the API sandbox to bork with the message: [...] "ŦŦ APILPlugins01 v0.0.1, 2021/3/8 ŦŦ -- offset continues from APILogic}" "Starting webworker script..." TypeError: Cannot set property 'version' of undefined "Starting webworker script..." TypeError: Cannot set property 'version' of undefined Which continued to be thrown on sandbox restart until I set the macro text back. So, any idea on how I can get these custom HP equation macros up and running with SelectManager? I'm needing 8 of them. (long term plan is to set up a chat template to determine which one to run for the selected group of tokens.)
1616359902
timmaugh
Pro
API Scripter
I think you're running up against the limitation of the initial release of SelectManager, that it was firstly only concerned with the token properties, and you're looking for represented-character properties. That is the next stage of release, and part of a planned "Meta Toolbox" release... hopefully early this week (in time to get in the one-click merge). The functionality you need is coming! =D
1616364817
Fantastic, thank you.
1618937652

Edited 1620074482
timmaugh
Pro
API Scripter
SelectManager (v1.0.0) FILE LOCATION:   META SCRIPT:  This script is a meta-script, and part of the ZeroFrame Meta Toolbox . It can be used on its own, or in conjunction with ZeroFrame and the other meta-toolbox scripts, to modify  other  scripts' API commands. ABSTRACT:  SelectManager helps API-generated messages remember what tokens are selected (they would otherwise not know), and lets you send commands to other scripts using the forselected handle. It also lets you "virtually" select tokens to ease interaction with the map. Introduction When a user sends a message to the API, the message contains an array of tokens that are selected. When the API sends a message to the API, those selected tokens are lost. Similarly, if a user includes an  @{target|...}  command, Roll20 doesn't include the selected tokens as a part of the message handed off to the API. This can be a problem for scripts built to expect at least one selected token in the message. SelectManager bridges this gap by remembering the tokens selected at the last point that a user message was selected, then restoring them to API-generated messages. This has been true in previous versions of SelectManager, and is still true, now. In fact, everything said about SelectManager in this thread is still true -- all of its existing functionality has been retained. This v1.0.0 release brings new functionality, including: The ability to plug into the ZeroFrame loop (if you have that script installed) The ability to virtually select (to replace) or inject (to add to) selected tokens. You can use this with Muler to create sets of selectable tokens you can easily add to a message without having to interact with the gameboard. A wider range of at(...) constructions to match Fetch retrievals for downstream token interaction, though #4 may obviate the need for this one... The ability to designate a custom escape character to defer downstream syntax detection (in other words, you tell SelectManager that for this forselected series of calls, SM should remove a particular character, which then allows syntax structures like a Fetch retrieval or a Muled variable retrieval, to be detected) Syntax Highlights No direct call interaction => SM can hand off tokens automatically !forselected spawn... => iterates a spawn script over the selected tokens !forselected !spawn... => same, including the exclamation point for downstream script !forselected(^) spawn @^(selected.token_id) => custom escape character for downstream script {& select Jax, Heretic} => replace selected tokens with comma-separated list (token ID, name, or near name) {& inject Jax} => Add Jax to the selected tokens, if not already included {& select get.TheParty} => Use a Muled variable "TheParty" to retrieve comma-separated list (requires Muler script) {& select get.?{Select...|Party,TheParty|Townies,TownNPCs|... => Utilize Roll20 query to choose the selected token set at run time (example requires Muler script) BONUS SYNTAX: !script --@forselected+|token-mod ... => forselected as downstream call, initiating downstream call (scriptcards calling forselected calling token-mod) Expanded forselected Options The forselected handle now accepts a custom escape character designation. The designated escape character is removed from the downstream call before it is sent to chat. Place the escape character in parentheses after the other options on the forselected handle: forselected(^) => use ^ as the escape character forselected-(\) => use \ as the escape character (the - is an auto-replacement setting, see previous post) forselected+-(=) => use = as the escape character (the + and - are auto-replacement settings, see previous post) With a command line like: !forselected(^) somescript --tgt|@^(selected.token_id) ...what is sent to chat by forselected will be: !somescript --tgt|@(selected.token_id) Which then resolves to the correct token id when it is received by the Fetch meta-script. (Note this won't work with the native Roll20 syntax  @{selected|token_id}  since that will try to resolve  before  SelectManager has the opportunity to restore the forgotten token to the message. You need the Fetch script to retrieve it, and you need to prioritize Fetch to run  after  SelectManager in the ZeroFrame loop. See the Meta Toolbox thread for more information.) Using select and inject With v1.0.0, you have the ability to select tokens virtually or to virtually add tokens to the selected set. Use either  {& select ...}  or  {& inject ...}  syntax structures, and include a comma-separated list of token IDs, token names, or approximate names of tokens to include. {& select -M1234567890abcdef, Haruk} {& inject Local Mookle, Biddy the Kill, Gorso} The difference between the two ( select  vs.  inject ) is that  select  replaces the selected tokens with those you designate, while  inject  adds the tokens to the selected token set (if they are unique). Using these tags can let you include a selected set of tokens even in a situation where you have used a targeting statement. The following statement would result in a message that did not have a selected array: !somescript --tgt|@{target|token_id} You can introduce selected tokens using either tag: !somescript --tgt|@{target|token_id} {& select Bargle} In fact, you can use a targeting statement as the source of the selected token: !somescript --tgt|@{target|token_id} {& select @{target|Use as selected...|token_id} Extend SelectManager Using Muler As mentioned in the Syntax Highlights, above, you can use Muler (another meta-scirpt) and a roll query to choose which token set to choose: !somescript arg1 arg2 {& select get.?{Tokens to select|The Party,theparty|Townies,townNPCs}}{& mule TokenSets} That would let you select which set of tokens you wanted to have replace the selected tokens of the message -- and it would happen at the time you run the message. This can save you from having to hunt up all of the party tokens on the board, or from having to deselect a mob of NPCs for a turn where you need the party selected, only to then have to reselect the mob.
1619327565

Edited 1619327588
timmaugh
Pro
API Scripter
Version 1.0.1 Released FIXED : bug where forselected escape character was not being properly removed FIXED : bug where forselected could read selected tokens twice
1619577105

Edited 1619577140
David M.
Pro
API Scripter
Did the latest version (1.0.1 installed) of SM lose the ability to use line breaks in the primary script call? Here's a simple example of what I was sure used to work. Obviously, there is no reason for this example to be using SM, but just wanted to make it easy for demonstration purposes :) !forselected Spawn {{   --name|imp   --offset|1,0 }} My script is returning the following error: (From SpawnAPI):  character "imp({& br})" not found The commands work when not using SM, i.e. !Spawn {{   --name|imp   --offset|1,0 }} Will also work if I use forselected but remove all the line breaks. I ran across this tonight as I was hoping to use SM to allow both a selected and target token in an upcoming revision of my Radar script (for easier determination of the center angle of a user-defined cone-shaped "radar" wavefront rather than the previous limitation to 360deg).
1619582133

Edited 1619582603
timmaugh
Pro
API Scripter
Hmm... two things around that... First, SelectManager did lose that -- and probably wrongly. Basically, SM was told to expect ZF to detect the line breaks and handle them appropriately. The problem is that you could have SM installed without ZF, in which case SM needs to be able to handle line-breaks on its own. So that ability actually needs to be in both scripts. I'll see if I can add that yet tonight. The second thing, though, is that your Spawn error report seems to show that you *do* have ZeroFrame installed, too. Basically, ZeroFrame is going to put the ({&br}) syntax token into the line in the place of a line break, so that later when it is done messing with the message and it is ready to release the message to the recipient script, it can replace that syntax with the line-breaks and the downstream script is never the wiser. I'm not sure why you would be seeing that unless your sandbox broke in mid-process... did you see an error in the console? EDIT : This same process was already built into SelectManager for the forselected side... so the syntax token could have come from from SM, alone. That said, the final point stands -- not sure why you would see that short of an error... but I'm digging.
1619585443

Edited 1619660175
timmaugh
Pro
API Scripter
Version 1.0.2 Released April 28, 2021 FIXED : Typo that prevented properly handling line-breaks in forselected calls ADDED : Ability to handle line-breaks independently, regardless of presence of ZeroFrame I also realized that even when you have an @{target} call, you can still do a formation like this anywhere in your line to get the selected token: {& select @{selected|token_id}} That will fill with the selected token's ID, and then SelectManager will restore the selected array and populate it with that token before the downstream script will get the message.
David M. said: . I ran across this tonight as I was hoping to use SM to allow both a selected and target token in an upcoming revision of my Radar script (for easier determination of the center angle of a user-defined cone-shaped "radar" wavefront rather than the previous limitation to 360deg). I'm listening.....
1619623990
David M.
Pro
API Scripter
I do have ZeroFrame installed (left over from our earlier troubleshooting). After updating to v1.0.2, the forselected with multi-line works, but only if I keep ZeroFrame enabled. When disabling ZeroFrame and running with v1.0.2, I'm now getting the following error: (From SpawnAPI):  character "imp({&br-sm})" not found For reference, the syntax tested is as follows: !forselected Spawn {{   --name|imp   --offset|1,0 }} Sandbox does not crash (no console errors). I have a big ol' try/catch in Spawn that spits errors out to chat. Issue seems to be that SM is passing "imp({&br-sm})" to the Spawn script when it is expecting just "imp". @Peacekeeper - haha, still working on it! Rolling the cone stuff into some other tricky revisions that I had already started, making the whole thing kind of a bear. Dead bugs litter my keyboard right now as new ones keep popping up! 
1619627416
David M.
Pro
API Scripter
Uh-oh, critical problem just popped up: With v1.0.2 of SM (and no ZeroFrame), it seems that multi-line script calls that don't use SM syntax no longer work. SM seems to still be active even when not being asked to. Gotta tell SM to stop mansplaining to my scripts, haha :) For example, the following gives me the same   (From SpawnAPI):  character "imp({&br-sm})" not found  error I was getting when I tried to use forselected, even though I am not referencing SM at all. If I disable SM, it begins working normally again. Similarly, if both SM & ZF enabled, the macro below works properly again.  !Spawn {{   --name|imp   --offset|1,0 }}
1619641907
timmaugh
Pro
API Scripter
OK... that's really the same problem as when you run forselected... SelectManager isn't cleaning up after itself. Let me get in there and see what is going on. *cue boilerplate sounds of wrenching, pounding, and metal objects tossed across the room*
1619660154
timmaugh
Pro
API Scripter
*bangs* *yanks wires* Got it. New version coming. Tested and working. (FYI, it helps, if you do a .replace() on a string, to store the changed string if -- and this is the important part -- IF you plan on needing the changed string.) Dropping pearls, right there, man. Just straight pearls. =D
1619660249

Edited 1620075799
timmaugh
Pro
API Scripter
Version 1.0.3 Released April 28, 2021 FIXED : Bug where SelectManager was not properly replacing all of its constructs if installed without ZeroFrame
1619660866
David M.
Pro
API Scripter
It's working, thanks!
1620076030

Edited 1620419989
timmaugh
Pro
API Scripter
Version 1.0.4 Released May 3, 2021 ADDED : You can now add virtually selected tokens using {&select...} or {&inject...} for API-generated messages Update Notes Previously, you could only use the above tags with a user-generated message. This change allows for the full expression of the tags' intended use: to be able to select tokens without having to click on them, and to have them available no matter the origin of the message (user or API). This change will coincide with changes to the !forselected script handle and Plugger script where those scripts gain an escape character to defer processing until the enclosed/embedded scriplet is evaluated. Since calls from these scripts will inherently be an API-generated message, it was important to allow individual selection of given tokens.
1620420050
timmaugh
Pro
API Scripter
Version 1.0.6 Released May 7, 2021 FIXED/ADDED : Tag buffering with parentheses of brace-enclosed tags, i.e.,  ({& mule... }) Update Notes This fix gives an option if the command line might result in a series of brace characters that would be inadvertently eaten by Roll20 parsers. In that case, you can enclose the syntax token in parentheses to break up that series of characters. This only matters for brace-enclosed tags: {& select Shulkor} or ({& select Shulkor})
1620743792
timmaugh
Pro
API Scripter
The new version of SelectManager is stable enough that I have submitted it to the one-click installer to replace the v0.0.7 that is currently available there. The latest version should be available with the next merge.
1621734004
@Tim - I use ScriptCards to build a menu of actions against NPCs and Characters (See below).  Most of my favorite API scripts include an option to send it a TokenID (TokenMod, GMNotes, ...), but there are a few that assume they are taking action on the selected token.  I would like to utilize their capabilities against non-selected tokens.  I've tried to use the {& select [&Token_Id]} syntax at the end of my API call, but it doesn't work.  As you may discern, I wish to call these API's with virtual/dynamic (unselected) TokenIds and use SelectManger to force them to be selected.  What am I missing?
1621821817
timmaugh
Pro
API Scripter
Hey, Will... SelectManager tracks a single set of selected tokens, playerid , and the who  of a message, updated every time you send a user-generated message. The {& select... } syntax overwrites that selected property, and since SelectManager works before ScriptCards, it overwrites the selected property for the whole of the ScriptCards macro. That might not matter. Other times, it might matter but you can work around it within ScriptCards (or whatever other receiving script you're working with). And still other times, you can work around it with Plugger. SelectManager will get a chance to run every time there is a new message. So if your ScriptCards macro fires off a sub call to another script, that should generate a new message giving SelectManager the opportunity to step in and handle the selected property. The trick is getting the {& select ...} syntax token to survive that long, because by then SelectManager will have examined the original message. Does ScriptCards give you a deferral character to prevent a too-early-parsing of downstream commands? For instance, if SC let you use the ^ character as a deferral character in downstream commands, you could break up the {& select ...} syntax so that it isn't detected when the initial macro is sent: {^& select ...} That way when the first message goes through, SelectManager doesn't see the construction. Eventually the message is handed off to ScriptCards, which, as it fires that sub call to TokenMod, removes the ^ character. A new message comes through, which SelectManager intercepts before TokenMod, and this message has a properly formed (and detectable) {& select... } syntax token. It assigns the tokens you feed it to that TokenMod message (and to the single top registry of selected tokens), and lets TokenMod run. Your top-level ScriptCards macro doesn't care that this happened, because by now it has already received its message and the selected tokens. Its selected token array doesn't change. However the next sub-call will care , because when that sub-call runs and a new message is sent through the API, SelectManager will step in, see that it is an API message, and restore the selected tokens. The set that it will restore are what you designated in your {& select ... } syntax. You can change this with another deferred {& select ... } structure in that sub-call, of course. Ideally, to make this work, you would have anything that required a limited subset of selected tokens be handled in its own "message" -- even if it meant that ScriptCards would call ScriptCards (can it do that?). And it would require, again, that ScriptCards give you a "deferral" character. If this won't work for you (or if SC doesn't have such a deferral character), we can look at doing it in Plugger (it does let you declare a deferral character)... since Plugger would run things as meta-script priority, the order might be a little different, but we could probably figure it out.
1621966897
I'll try to continue to play around with it.  ScriptCards has some syntax for calling itself, effectively re-executing with a "Reentry Button".  I might be able to use it in conjunction with SelectManager.  
1624021261
I have multiple characters with the same ability (~ToggleAuraTarget), so it seems like this construction should work: !forselected %(selected|~ToggleAuraTarget) The ability is: !pa toggle @{selected|token_id} @{target|token_id} Which, at least as I understand how SM works, gets shunted into the command line so that basically reads: !forselected !pa toggle @{selected|token_id} @{target|token_id} What's going wrong here?
1624035350

Edited 1624035381
timmaugh
Pro
API Scripter
This gets into the order of operations and how SelectManager is registered in the API queue. TL;DR: I need more information. See the bottom of this message. Meta scripts get in at the head of the queue for most of their work. SM actually registers for 3! different places in the queue, I think. Once to track and hand off the selected tokens (meta), once to handle the forselected command (delayed meta), and once to handle its own configuration commands (standard). Given that, it's important to remember the general order of operations for each message to make sure you get the return you want: Roll20 Parsing Meta Script Stack Standard Script Stack ... and then figure out what the command looks like at any point in the process, and when/if the command is spawning another command (to create a new instance of the above order of operations). Looking at your example: !forselected %(selected|~ToggleAuraTarget) I would expect the following processing: Command sent Command Line: !forselected %(selected|~ToggleAuraTarget) Roll 20 parsing - nothing detected Meta Script Stack   -- ZeroFrame (if installed) begins loop   -- SelectManager, seeing a user-generated message, tracks/stores all selected tokens   -- Fetch sees a construction, and goes to get the ~ToggleAuraTarget from the first token that is selected. Your command line now looks like:     !forselected !pa toggle @{selected|token_id} @{target|token_id}   -- ZeroFrame (if installed), detects that there was a change, so it unescapes the line (removing an instance of \ ), and sends the message to the Roll20 parsers again ------ NEW ORDER OF OPERATIONS STACK ESTABLISHED  ------ Command Line*: !forselected !pa toggle @{selected|token_id} @{target|token_id} Roll20 parsing   -- sees an @{selected...} construction, but this is an API-generated message, and SelectManager hasn't had time to restore the tokens, so this fails.   -- sees an @{target...} construction, but this is an API-generated message, and it doesn't know who to ask for the targeting info, so this fails Meta Script Stack   -- ZeroFrame (if installed) begins loop  -- No meta script sees anything to do as part of the loop   -- ZeroFrame (if installed) releases loop   -- SelectManager.forselected (not a part of the ZF loop), sees the forselected handle and sends the downstream command for each selected token ------ NEW ORDER OF OPERATIONS STACK ESTABLISHED  (once for each token tracked as a part of the initial message's selected token) ------ Command Line*: !pa toggle Roll20 parsing - nothing detected Meta Script Stack   -- ZeroFrame begins loop   -- No meta script sees anything to do as part of the loop   -- ZeroFrame releases message Standard Script Stack   -- Scripts, in order, see if they need to answer the !pa handle * - there is a ZeroFrame prepending code that helps it to track this message, but it doesn't matter to what you need to consider You can see where that lost the information you were looking for, and how the targeting statement won't work when it's buried in the ability (to be delivered to the chat via an API generated message). The way you get constructions to survive to the point where you WANT them to be processed (and to be individually processed) involves using the forselected's deferral handle -- which you can declare uniquely for each forselected call. !forselected(^)  <== be careful with this one if you use ScriptCards; ^ is the deferral character for ScriptCards spawning other API calls (like forselected) !forselected(=) !forselected(/) That will make those constructions undetectable until the forselected call process removes that character and exposes the construction to the iterated command. It still won't help with Roll20 parsing, since that happens before the Meta Scripts can get back in and restore what was lost, but that's where you can use Fetch in the downstream construction. Except for the targeting. So, there's a lot of moving parts there, and a lot of ways that it could be corrected depending on what you actually want to do with it. How many tokens do you have selected at once when you run this? Will all selected tokens target the same token, or would there be several? Describe your use-case, and I can help dial this in (or tell you if will even work)...
1624045371
I have a group of 4 paladins that I have selected at the same time, and they are all targeting the same token with the toggle. This command seems to have done what I wanted: !forselected pa toggle @(selected|token_id) @{target|token_id} {& select <various character names>} I just ran that directly in chat.
1624052317
timmaugh
Pro
API Scripter
Awesome! Yep, that was one of the scenarios that were a possible match for what you were looking for. Glad you got it working! For anyone keeping notes: The Roll20 targeting statement happens at the top level of the macro, as it needed to. The {& select...} also happens at the top, so now we've got a bank of "virtually" selected Paladin tokens for forselected to iterate over. The Fetch construction @(selected...) *also* happens at the top level, meaning that forselected  will see a single token ID in the command line that it sends... the token ID of the first character in the selected array. However, forselected comes defaulted to search the downstream command line for the token ID of the first character in the selected array... meaning that when it sees that ID in the command line, it figures it had better swap it out for the subsequent IDs as it iterates... replacing it with the ID of the second token when it sends that command... replacing it with the ID of the third, etc. In this case all of that means you get the outcome you were looking for. =D
1625400542
Ivo
Pro
I want to do something like this where I can call token-mod to update a number of tokens that are lights on the dynamic lighting layer, and update there light radius based on a value on the token, say bar3 for instance, with one call. !forselected token-mod {{   --set     light_radius|@{{& inject -MdkkPqDv2paJKc3cUWf -MdkkNvYMtGAh1gJjM-m -MdkkLVCIi8xmXn1ktSq -MdkiythYy8hXFg7hbVo -MdkhV1C6lNXDNfxyxSz -Mdkjbd3xW74g39Bg8YL}|bar3}     light_dimradius|  --on    light_otherplayers }}
1625444763
It sounds like you're wanting to have each token's light_radius set based on that token's bar3 value. I think the most straightforward method would be to use Fetch . With that installed, try: !forselected token-mod {{ {& select -MdkkPqDv2paJKc3cUWf -MdkkNvYMtGAh1gJjM-m -MdkkLVCIi8xmXn1ktSq -MdkiythYy8hXFg7hbVo -MdkhV1C6lNXDNfxyxSz -Mdkjbd3xW74g39Bg8YL}   --set     light_radius|@(selected|bar3)     light_dimradius|  --on    light_otherplayers }} Alternatively, just select the relevant tokens and skip the {& select ... } syntax altogether. Ivo said: I want to do something like this where I can call token-mod to update a number of tokens that are lights on the dynamic lighting layer, and update there light radius based on a value on the token, say bar3 for instance, with one call. !forselected token-mod {{   --set     light_radius|@{{& inject -MdkkPqDv2paJKc3cUWf -MdkkNvYMtGAh1gJjM-m -MdkkLVCIi8xmXn1ktSq -MdkiythYy8hXFg7hbVo -MdkhV1C6lNXDNfxyxSz -Mdkjbd3xW74g39Bg8YL}|bar3}     light_dimradius|  --on    light_otherplayers }}
1625445156

Edited 1625453098
Ivo
Pro
Thanks, I will giver that a try, I wouldnt be selecting them manually, so the & select seems the way to go, unless when I use -ids and add all of the token ids in i can somehow still reference the @{selected|bar3} and have "Selected" iterate through the ids Tried all manner of ways, still get this for all attempts , not sure if that's coming from token-mod or select manager I get this,  (From API): NO TOKENS No selected tokens to use for that command. Please select some tokens then try again. !forselected token-mod --ids {{ {& inject -MdkkPqDv2paJKc3cUWf -MdkkNvYMtGAh1gJjM-m -MdkkLVCIi8xmXn1ktSq -MdkiythYy8hXFg7hbVo -MdkhV1C6lNXDNfxyxSz -Mdkjbd3xW74g39Bg8YL}   --set     light_radius|@(selected.bar3_value)     light_dimradius|  --on    light_otherplayers }} This worked like a charm, thank you very much! !forselected token-mod --ids {{ {& inject Light}   --set     light_radius|@(selected.bar3_value)     light_dimradius|  --on    light_otherplayers }} And the above is even better, dont need to specify exact token id's Damn, thought it was working, I had a token selected!
1625493872

Edited 1625578011
timmaugh
Pro
API Scripter
Ivo said: I want to do something like this where I can call token-mod to update a number of tokens that are lights on the dynamic lighting layer, and update there light radius based on a value on the token, say bar3 for instance, with one call. Colin C. said: It sounds like you're wanting to have each token's light_radius set based on that token's bar3 value. I think the most straightforward method would be to use Fetch . With that installed, try: !forselected token-mod {{ {& select -MdkkPqDv2paJKc3cUWf -MdkkNvYMtGAh1gJjM-m -MdkkLVCIi8xmXn1ktSq -MdkiythYy8hXFg7hbVo -MdkhV1C6lNXDNfxyxSz -Mdkjbd3xW74g39Bg8YL}   --set     light_radius|@(selected|bar3)     light_dimradius|  --on    light_otherplayers }} Sorry I couldn't get to this message yesterday, but let me chime in now... TL;DR... Look for the code block, below, for the slight modification to make this work. First, the {&inject...} and {& select...} syntax requires the list of tokens to be separated by a comma. This is because you could put names in the list instead of IDs, and those names could have spaces. So when you provide a list of IDs that are separated by spaces, instead, it will look for a single token identified by that long string of information... and it will never find one. I think that's why you're ending up with "No token selected..." Second, I would do as Colin suggested and use {& select...} . That is going to build the list of selected tokens by starting over. If you have 10 NPC tokens selected, it is going to disregard them in order to select only the ones you feed into the syntax list. If you use {& inject...} , it is going to keep those 10 NPC tokens and add the list to the set of selected tokens (for the purposes and duration of this message). You won't want to always change the lighting of those other tokens, nor do you want to have to constantly deselect everything (clicking on the VTT board) to make sure you're starting from scratch to use {& inject...} and have only the light tokens. Just use {& select...} and provide the token id's as a comma-separated list. Third, the list of tokens-to-select won't be given to the --ids argument of TokenMod. In fact, the entire {& select...} structure will be eaten before TM sees the command line, so those IDs won't be there. But the bigger issue is that you want to reference an individual bar value for each of them. If you passed all of the tokens to the --ids argument of TM (which, again, is not what the {&select...} / {&inject...} syntax does), then when we fixed the iteration over the selected tokens, you would set the entire list to the bar value of the first token, then you would set the entire list to the bar value of the second token, etc. Last, Colin is right that Fetch is the way to go (possibly with ZeroFrame to make sure they play nicely together)... but we need one more element. As written, the Fetch construction @(selected|bar3) or @(selected.bar3) will resolve before the !forselected iteration begins. That means it will only be access one time... retrieving the bar3 value of the first token selected. That's not what you want. You want that Fetch construction to be discovered and processed for each token independently -- so it has to survive the first pass of the main message to be there in each of the iterated calls. To do this, declare a deferral character for the forselected process, and then use it anywhere you need to break up a syntax structure. In the example, below, I will use the ^ character for this. !forselected(^) token-mod {{ {& select -MdkkPqDv2paJKc3cUWf, -MdkkNvYMtGAh1gJjM-m, -MdkkLVCIi8xmXn1ktSq, -MdkiythYy8hXFg7hbVo, -MdkhV1C6lNXDNfxyxSz, -Mdkjbd3xW74g39Bg8YL}   --set     light_radius|@^(selected|bar3)     light_dimradius|  --on    light_otherplayers }} Other thoughts... I am planning on releasing a way to query for different data from the game, like the ability to return a list of tokens based on some shared feature (for instance, they all of the word "Lightsource" in their name). When that is ready, you could supply the tokens returned from that query to the select statement to retrieve the light tokens from the given layer, and adjust them accordingly. However, I have just been too busy of late to wrap that project up. In the meantime, if you didn't want to maintain the list of light-source tokens in the text of the macro, you could store it as a Muled variable. If you went that route, you could update the list in one location, and reference it from many different macros. If you're interested, I can post an example of how to change the above call to make it work.
1625531847

Edited 1625579507
Ivo
Pro
EDIT : OMG, it works fine for tokens on the token layer, but mine are all on the dynamic lighting layer, and forselected, deferals {& select etc don't seem to work on the Dynamic lighting layer!!! So this works as intended for tokens on the Object-Token layer or GM Layer !forselected(^) token-mod {{ {& select TLLight1, TLLight2}   --set     light_radius|@^(selected|bar3)     light_dimradius|  --on    light_otherplayers }} But move those same tokens to the Dynamic lighting layer or Map Layer and all you get is (From API): NO TOKENS No selected tokens to use for that command. Please select some tokens then try again. As a side note, I haven't been able to get to work using the & select as a way of selecting multiple tokens with a single name , ie TLLIght, maybe its not meant to work like a regexp etc. Thanks for your time. Still getting the same message, I did add commas to the select list as well. I've determined that the message is not coming from token-mod, but Selectmanager itself. Thinking about how token-mod works, wouldnt the {& select Light} be required before the token-mod reference, ive tried this to, same message. Ive used {&select Light} as all the token required have the word Light in the name, and the info on selectmanager says you an use a partial name etc. That said i also tried the same with fully resolved token_id. I have Selectmanager(installed as first script), fetch & zeroframe installed(last scripts). Maybe the priority has to change? Atm SM has priority over Fetch.
1625580284

Edited 1633532397
timmaugh
Pro
API Scripter
Thanks for catching the fact that after telling you to use commas, I forgot to use commas. *facepalm* I've edited the above post to fix that. About SM using partial names... it can use a partial name, but it will only find the first token that matches. That's where a query selector will come in handy ("give me all the tokens that start with 'light'"). For now, you have to provide an entry for each token -- either in the list or by maintaining a list (like in Muler). About the timing... it doesn't matter where the {&select...} statement comes in the line with relation to token-mod. The meta-scripts will all process before anything is handed to the normal scripts. SM will detect a construction it needs to grab and process; it will remove it from the command line and take the appropriate action (adding the tokens to the set of selected tokens). By the time token-mod gets it, it's like the {&select...} syntax was never there. In fact, it's getting down into the weeds a little bit, but !forselected is a part of SelectManager that registers as a normal script, so even by the time *that* part of the SM script sees the command line, the meta stuff is done. =D The one thing that can matter about where you put the {&select...} structure is whether it (or other meta-structures) will bump up against characters in the command line that cause Roll20 to take some action. For instance, bumping up against another opening brace -- { -- can make the parser think that the 2 braces should be treated as a template part. In those situations, most/all of the syntax structures that can suffer from this problem offer a second form where you would wrap the whole thing in parentheses: ({&select AGH Your leg, It's caught in a bear trap}) That could be another reason why it doesn't see that you have selected tokens -- because it hasn't detected/processed the {&select...} structure. Last, about not finding tokens on the DL layer... it's been a while since I've been elbow deep in the code, but I will have to see if there is some limitation that would prevent that. Because you ought to be able to do that... Let me see what I can find. EDIT: Thread Closed => New Thread This thread closed for inactivity. You can find the new thread at this link .