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...).